Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 53 additions & 15 deletions Module/Cmdlets/FIDO2/ExportYubiKeyFIDO2Blob.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/// <summary>
/// Allows the return of a large blob associated with a FIDO2 credential, which may contain additional metadata or state information for that credential.
/// Requires a YubiKey with FIDO2 support and administrator privileges on Windows.
/// When no credential or relying party is provided, the cmdlet automatically looks up the "blob-storage" credential.
///
/// .EXAMPLE
/// Export-YubiKeyFIDO2Blob -OutFile fileName.txt
/// Exports the large blob stored under the "blob-storage" credential.
///
/// .EXAMPLE
/// Export-YubiKeyFIDO2Blob -RelyingPartyID "demo.yubico.com" -OutFile fileName.txt
Expand All @@ -25,7 +30,7 @@

namespace powershellYK.Cmdlets.Fido
{
[Cmdlet(VerbsData.Export, "YubiKeyFIDO2Blob")]
[Cmdlet(VerbsData.Export, "YubiKeyFIDO2Blob", DefaultParameterSetName = "AutoLookup")]
public class ExportYubikeyFIDO2BlobCmdlet : PSCmdlet
{
[Parameter(
Expand All @@ -46,6 +51,12 @@ public class ExportYubikeyFIDO2BlobCmdlet : PSCmdlet
[ValidateNotNullOrEmpty]
public string? RelyingPartyID { get; set; }

[Parameter(
Mandatory = true,
ParameterSetName = "AutoLookup",
ValueFromPipeline = false,
HelpMessage = "Output file path for the exported large blob"
)]
[Parameter(
Mandatory = true,
ParameterSetName = "Export LargeBlob",
Expand All @@ -62,6 +73,8 @@ public class ExportYubikeyFIDO2BlobCmdlet : PSCmdlet
[ValidatePath(fileMustExist: false, fileMustNotExist: true)]
public required System.IO.FileInfo OutFile { get; set; }

private const string AutoCreateRpId = "blob-storage";

// Initialize processing and verify requirements
protected override void BeginProcessing()
{
Expand All @@ -84,22 +97,19 @@ protected override void BeginProcessing()
WriteDebug($"Successfully connected");
}

// Connect to FIDO2 if exporting large blob
if (ParameterSetName == "Export LargeBlob" || ParameterSetName == "Export LargeBlob by RelyingPartyID")
// Connect to FIDO2 if not already authenticated
if (YubiKeyModule._fido2PIN is null)
{
WriteDebug("No FIDO2 session has been authenticated, calling Connect-YubikeyFIDO2...");
var myPowersShellInstance = PowerShell.Create(RunspaceMode.CurrentRunspace).AddCommand("Connect-YubikeyFIDO2");
if (this.MyInvocation.BoundParameters.ContainsKey("InformationAction"))
{
myPowersShellInstance = myPowersShellInstance.AddParameter("InformationAction", this.MyInvocation.BoundParameters["InformationAction"]);
}
myPowersShellInstance.Invoke();
if (YubiKeyModule._fido2PIN is null)
{
WriteDebug("No FIDO2 session has been authenticated, calling Connect-YubikeyFIDO2...");
var myPowersShellInstance = PowerShell.Create(RunspaceMode.CurrentRunspace).AddCommand("Connect-YubikeyFIDO2");
if (this.MyInvocation.BoundParameters.ContainsKey("InformationAction"))
{
myPowersShellInstance = myPowersShellInstance.AddParameter("InformationAction", this.MyInvocation.BoundParameters["InformationAction"]);
}
myPowersShellInstance.Invoke();
if (YubiKeyModule._fido2PIN is null)
{
throw new Exception("Connect-YubikeyFIDO2 failed to connect to the FIDO2 applet!");
}
throw new Exception("Connect-YubikeyFIDO2 failed to connect to the FIDO2 applet!");
}
}
}
Expand All @@ -122,7 +132,35 @@ protected override void ProcessRecord()
RelyingParty? credentialRelyingParty = null;
var relyingParties = fido2Session.EnumerateRelyingParties();
powershellYK.FIDO2.CredentialID selectedCredentialId;
if (ParameterSetName == "Export LargeBlob by RelyingPartyID")
if (ParameterSetName == "AutoLookup")
{
var match = relyingParties.FirstOrDefault(rp =>
string.Equals(rp.Id, AutoCreateRpId, StringComparison.OrdinalIgnoreCase));
if (match is null)
{
throw new InvalidOperationException(
$"No '{AutoCreateRpId}' credential found on this YubiKey. " +
"Use Import-YubiKeyFIDO2Blob to store a blob first, or specify -CredentialId / -RelyingPartyID.");
}

try
{
var creds = fido2Session.EnumerateCredentialsForRelyingParty(match);
if (creds.Count == 0)
{
throw new InvalidOperationException(
$"No credentials found for relying party '{match.Id}'.");
}
credentialRelyingParty = match;
selectedCredentialId = (powershellYK.FIDO2.CredentialID)creds[0].CredentialId;
}
catch (NotSupportedException)
{
throw new InvalidOperationException(
$"Unable to enumerate credentials for relying party '{match.Id}' due to unsupported algorithm.");
}
}
else if (ParameterSetName == "Export LargeBlob by RelyingPartyID")
{
if (string.IsNullOrWhiteSpace(RelyingPartyID))
{
Expand Down
Loading
Loading