diff --git a/Docs/Commands/Assert-YubikeyPIV.md b/Docs/Commands/Assert-YubikeyPIV.md index d0f485e..50d54fa 100644 --- a/Docs/Commands/Assert-YubikeyPIV.md +++ b/Docs/Commands/Assert-YubikeyPIV.md @@ -1,10 +1,11 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml -HelpUri: +HelpUri: '' +Locale: en-US Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 +title: Assert-YubiKeyPIV --- # Assert-YubiKeyPIV diff --git a/Docs/Commands/Block-YubikeyPIV.md b/Docs/Commands/Block-YubikeyPIV.md index eeff554..ee99878 100644 --- a/Docs/Commands/Block-YubikeyPIV.md +++ b/Docs/Commands/Block-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Build-YubiKeyPIVCertificateSigningRequest.md b/Docs/Commands/Build-YubiKeyPIVCertificateSigningRequest.md index f41aced..000fb17 100644 --- a/Docs/Commands/Build-YubiKeyPIVCertificateSigningRequest.md +++ b/Docs/Commands/Build-YubiKeyPIVCertificateSigningRequest.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Build-YubikeyPIVSignCertificate.md b/Docs/Commands/Build-YubikeyPIVSignCertificate.md index a397522..de02750 100644 --- a/Docs/Commands/Build-YubikeyPIVSignCertificate.md +++ b/Docs/Commands/Build-YubikeyPIVSignCertificate.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Clear-YubiKeyFIDO2Blob.md b/Docs/Commands/Clear-YubiKeyFIDO2Blob.md new file mode 100644 index 0000000..74704f6 --- /dev/null +++ b/Docs/Commands/Clear-YubiKeyFIDO2Blob.md @@ -0,0 +1,105 @@ +--- +document type: cmdlet +external help file: powershellYK.dll-Help.xml +HelpUri: '' +Locale: en-SE +Module Name: powershellYK +PlatyPS schema version: 2024-05-01 +title: Clear-YubiKeyFIDO2Blob +--- + +# Clear-YubiKeyFIDO2Blob + +## SYNOPSIS + +Removes all BLOBs from the YubiKey FIDO2 application. + +## SYNTAX + +### __AllParameterSets + +``` +Clear-YubiKeyFIDO2Blob [-WhatIf] [-Confirm] [] +``` + +## ALIASES + +## DESCRIPTION + +Removes all BLOBs from the YubiKey FIDO2 application. This cmdlet will prompt for confirmation before proceeding with the deletion of all BLOBs. + +## EXAMPLES + +### Example 1 + +{{ Add example description here }} + +## PARAMETERS + +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: System.Management.Automation.SwitchParameter +DefaultValue: '' +SupportsWildcards: false +Aliases: +- cf +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + +### -WhatIf + +Runs the command in a mode that only reports what would happen without performing the actions. + +```yaml +Type: System.Management.Automation.SwitchParameter +DefaultValue: '' +SupportsWildcards: false +Aliases: +- wi +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + +### CommonParameters + +This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, +-InformationAction, -InformationVariable, -OutBuffer, -OutVariable, -PipelineVariable, +-ProgressAction, -Verbose, -WarningAction, and -WarningVariable. For more information, see +[about_CommonParameters](https://go.microsoft.com/fwlink/?LinkID=113216). + +## INPUTS + +## OUTPUTS + +### System.Object + +{{ Fill in the Description }} + +## NOTES + +{{ Fill in the Notes }} + +## RELATED LINKS + +{{ Fill in the related links here }} + diff --git a/Docs/Commands/Confirm-YubiKeyFIDO2Attestation.md b/Docs/Commands/Confirm-YubiKeyFIDO2Attestation.md index e7b4671..6c42766 100644 --- a/Docs/Commands/Confirm-YubiKeyFIDO2Attestation.md +++ b/Docs/Commands/Confirm-YubiKeyFIDO2Attestation.md @@ -4,7 +4,6 @@ external help file: powershellYK.dll-Help.xml HelpUri: '' Locale: en-SE Module Name: powershellYK -ms.date: 03-26-2026 PlatyPS schema version: 2024-05-01 title: Confirm-YubiKeyFIDO2Attestation --- @@ -13,7 +12,7 @@ title: Confirm-YubiKeyFIDO2Attestation ## SYNOPSIS -{{ Fill in the Synopsis }} +Confirm YubiKey FIDO2 Attestation. ## SYNTAX @@ -25,9 +24,6 @@ Confirm-YubiKeyFIDO2Attestation -AttestationObject [ [] ### Password (Default) ``` -Connect-YubiKeyOATH -Password [] +Connect-YubiKeyOATH [-Password ] [] ``` ## ALIASES @@ -57,7 +56,7 @@ Aliases: [] ParameterSets: - Name: Password Position: Named - IsRequired: true + IsRequired: false ValueFromPipeline: false ValueFromPipelineByPropertyName: false ValueFromRemainingArguments: false diff --git a/Docs/Commands/Connect-YubikeyPIV.md b/Docs/Commands/Connect-YubikeyPIV.md index f3f504b..23b78d0 100644 --- a/Docs/Commands/Connect-YubikeyPIV.md +++ b/Docs/Commands/Connect-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/ConvertTo-AltSecurity.md b/Docs/Commands/ConvertTo-AltSecurity.md index e20d0f8..c630c00 100644 --- a/Docs/Commands/ConvertTo-AltSecurity.md +++ b/Docs/Commands/ConvertTo-AltSecurity.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Disconnect-Yubikey.md b/Docs/Commands/Disconnect-Yubikey.md index fef9550..c49462f 100644 --- a/Docs/Commands/Disconnect-Yubikey.md +++ b/Docs/Commands/Disconnect-Yubikey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Enable-YubikeyFIDO2EnterpriseAttestation.md b/Docs/Commands/Enable-YubikeyFIDO2EnterpriseAttestation.md index 64f320f..c920183 100644 --- a/Docs/Commands/Enable-YubikeyFIDO2EnterpriseAttestation.md +++ b/Docs/Commands/Enable-YubikeyFIDO2EnterpriseAttestation.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Enable-powershellYKSDKLogging.md b/Docs/Commands/Enable-powershellYKSDKLogging.md index d40a529..5938453 100644 --- a/Docs/Commands/Enable-powershellYKSDKLogging.md +++ b/Docs/Commands/Enable-powershellYKSDKLogging.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Export-YubiKeyFIDO2Blob.md b/Docs/Commands/Export-YubiKeyFIDO2Blob.md index dfefd9a..21d752f 100644 --- a/Docs/Commands/Export-YubiKeyFIDO2Blob.md +++ b/Docs/Commands/Export-YubiKeyFIDO2Blob.md @@ -4,7 +4,6 @@ external help file: powershellYK.dll-Help.xml HelpUri: '' Locale: en-SE Module Name: powershellYK -ms.date: 03-20-2026 PlatyPS schema version: 2024-05-01 title: Export-YubiKeyFIDO2Blob --- @@ -29,6 +28,12 @@ Export-YubiKeyFIDO2Blob -CredentialId -OutFile [ -OutFile [] ``` +### AutoLookup (Default) + +``` +Export-YubiKeyFIDO2Blob -OutFile [] +``` + ## ALIASES ## DESCRIPTION @@ -79,6 +84,12 @@ DefaultValue: '' SupportsWildcards: false Aliases: [] ParameterSets: +- Name: AutoLookup + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false - Name: Export LargeBlob Position: Named IsRequired: true @@ -140,5 +151,4 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## RELATED LINKS -[FIDO2 large blobs ("largeBlobs" option)](https://docs.yubico.com/yesdk/users-manual/application-fido2/large-blobs.html) - +- [FIDO2 large blobs ("largeBlobs" option)](https://docs.yubico.com/yesdk/users-manual/application-fido2/large-blobs.html) diff --git a/Docs/Commands/Export-YubikeyPIVCertificate.md b/Docs/Commands/Export-YubikeyPIVCertificate.md index 79ded40..8ed7628 100644 --- a/Docs/Commands/Export-YubikeyPIVCertificate.md +++ b/Docs/Commands/Export-YubikeyPIVCertificate.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Find-Yubikey.md b/Docs/Commands/Find-Yubikey.md index 6322719..77dc00e 100644 --- a/Docs/Commands/Find-Yubikey.md +++ b/Docs/Commands/Find-Yubikey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-Yubikey.md b/Docs/Commands/Get-Yubikey.md index 801c5bb..1c551c7 100644 --- a/Docs/Commands/Get-Yubikey.md +++ b/Docs/Commands/Get-Yubikey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-YubikeyBIOFingerprint.md b/Docs/Commands/Get-YubikeyBIOFingerprint.md index 0d9af24..2f10a76 100644 --- a/Docs/Commands/Get-YubikeyBIOFingerprint.md +++ b/Docs/Commands/Get-YubikeyBIOFingerprint.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-YubikeyFIDO2.md b/Docs/Commands/Get-YubikeyFIDO2.md index fdecd0c..1858f61 100644 --- a/Docs/Commands/Get-YubikeyFIDO2.md +++ b/Docs/Commands/Get-YubikeyFIDO2.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-YubikeyFIDO2Credential.md b/Docs/Commands/Get-YubikeyFIDO2Credential.md index fe36595..d28ff81 100644 --- a/Docs/Commands/Get-YubikeyFIDO2Credential.md +++ b/Docs/Commands/Get-YubikeyFIDO2Credential.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- @@ -33,6 +32,12 @@ Get-YubiKeyFIDO2Credential -CredentialID [] Get-YubiKeyFIDO2Credential -CredentialIdBase64Url [] ``` +### List-RelyingPartyID + +``` +Get-YubiKeyFIDO2Credential -RelyingPartyID [] +``` + ## ALIASES ## DESCRIPTION @@ -118,6 +123,29 @@ AcceptedValues: [] HelpMessage: '' ``` +### -RelyingPartyID + +Filter credentials by relying party ID + +```yaml +Type: System.String +DefaultValue: '' +SupportsWildcards: false +Aliases: +- RP +- Origin +ParameterSets: +- Name: List-RelyingPartyID + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, diff --git a/Docs/Commands/Get-YubikeyOATH.md b/Docs/Commands/Get-YubikeyOATH.md index 7cd1d7b..05412e3 100644 --- a/Docs/Commands/Get-YubikeyOATH.md +++ b/Docs/Commands/Get-YubikeyOATH.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-YubikeyOATHAccount.md b/Docs/Commands/Get-YubikeyOATHAccount.md index 06a2c7d..1c4ce7c 100644 --- a/Docs/Commands/Get-YubikeyOATHAccount.md +++ b/Docs/Commands/Get-YubikeyOATHAccount.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-YubikeyOTP.md b/Docs/Commands/Get-YubikeyOTP.md index a766eab..e5979be 100644 --- a/Docs/Commands/Get-YubikeyOTP.md +++ b/Docs/Commands/Get-YubikeyOTP.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-YubikeyPIV.md b/Docs/Commands/Get-YubikeyPIV.md index 2c78f21..a62a9de 100644 --- a/Docs/Commands/Get-YubikeyPIV.md +++ b/Docs/Commands/Get-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Get-powershellYKInfo.md b/Docs/Commands/Get-powershellYKInfo.md index 24d703a..5003fc2 100644 --- a/Docs/Commands/Get-powershellYKInfo.md +++ b/Docs/Commands/Get-powershellYKInfo.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Import-YubiKeyFIDO2Blob.md b/Docs/Commands/Import-YubiKeyFIDO2Blob.md index b5c60a2..5fbf9cf 100644 --- a/Docs/Commands/Import-YubiKeyFIDO2Blob.md +++ b/Docs/Commands/Import-YubiKeyFIDO2Blob.md @@ -4,7 +4,6 @@ external help file: powershellYK.dll-Help.xml HelpUri: '' Locale: en-SE Module Name: powershellYK -ms.date: 03-20-2026 PlatyPS schema version: 2024-05-01 title: Import-YubiKeyFIDO2Blob --- @@ -20,20 +19,24 @@ Imports large blob to YubiKey FIDO2 by Credential ID or Relying Party ID (Origin ### Set LargeBlob ``` -Import-YubiKeyFIDO2Blob -LargeBlob -CredentialId [-Force] +Import-YubiKeyFIDO2Blob -Path -CredentialId [-Force] [-WhatIf] [-Confirm] [] ``` ### Set LargeBlob by RelyingPartyID ``` -Import-YubiKeyFIDO2Blob -LargeBlob -RelyingPartyID [-Force] [] +Import-YubiKeyFIDO2Blob -Path -RelyingPartyID [-Force] [-WhatIf] [-Confirm] + [] ``` -## ALIASES +### AutoCreate (Default) + +``` +Import-YubiKeyFIDO2Blob -Path [-Force] [-WhatIf] [-Confirm] [] +``` -This cmdlet has the following aliases, - {{Insert list of aliases}} +## ALIASES ## DESCRIPTION @@ -52,6 +55,28 @@ Imports the large blob from the specified file for the credential with the speci ## PARAMETERS +### -Confirm + +Prompts you for confirmation before running the cmdlet. + +```yaml +Type: System.Management.Automation.SwitchParameter +DefaultValue: '' +SupportsWildcards: false +Aliases: +- cf +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + ### -CredentialId Credential ID (hex or base64url string) to associate with the large blob array. @@ -76,6 +101,7 @@ HelpMessage: '' ### -Force Overwrite existing large blob entry for this credential without prompting. +Suppress confirmation prompts (credential creation and blob overwrite). ```yaml Type: System.Management.Automation.SwitchParameter @@ -83,6 +109,12 @@ DefaultValue: '' SupportsWildcards: false Aliases: [] ParameterSets: +- Name: AutoCreate + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false - Name: Set LargeBlob Position: Named IsRequired: false @@ -127,6 +159,41 @@ AcceptedValues: [] HelpMessage: '' ``` +### -Path + +File to import as large blob + +```yaml +Type: System.IO.FileInfo +DefaultValue: '' +SupportsWildcards: false +Aliases: +- LargeBlob +- File +ParameterSets: +- Name: AutoCreate + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +- Name: Set LargeBlob + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +- Name: Set LargeBlob by RelyingPartyID + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + ### -RelyingPartyID Relying party ID, or relying party display name if unique, to associate with the large blob. @@ -150,6 +217,28 @@ AcceptedValues: [] HelpMessage: '' ``` +### -WhatIf + +Runs the command in a mode that only reports what would happen without performing the actions. + +```yaml +Type: System.Management.Automation.SwitchParameter +DefaultValue: '' +SupportsWildcards: false +Aliases: +- wi +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + ### CommonParameters This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, @@ -171,4 +260,4 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## RELATED LINKS -[FIDO2 large blobs ("largeBlobs" option)](https://docs.yubico.com/yesdk/users-manual/application-fido2/large-blobs.html) \ No newline at end of file +- [FIDO2 large blobs ("largeBlobs" option)](https://docs.yubico.com/yesdk/users-manual/application-fido2/large-blobs.html) diff --git a/Docs/Commands/Import-YubikeyPIV.md b/Docs/Commands/Import-YubikeyPIV.md index cc5517e..18665b2 100644 --- a/Docs/Commands/Import-YubikeyPIV.md +++ b/Docs/Commands/Import-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Lock-Yubikey.md b/Docs/Commands/Lock-Yubikey.md index 56eaa10..48082d9 100644 --- a/Docs/Commands/Lock-Yubikey.md +++ b/Docs/Commands/Lock-Yubikey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Move-YubikeyPIV.md b/Docs/Commands/Move-YubikeyPIV.md index d6297d9..c33680c 100644 --- a/Docs/Commands/Move-YubikeyPIV.md +++ b/Docs/Commands/Move-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/New-Challenge.md b/Docs/Commands/New-Challenge.md index 8eda0b5..89e3a4d 100644 --- a/Docs/Commands/New-Challenge.md +++ b/Docs/Commands/New-Challenge.md @@ -4,7 +4,6 @@ external help file: powershellYK.dll-Help.xml HelpUri: '' Locale: en-SE Module Name: powershellYK -ms.date: 03-26-2026 PlatyPS schema version: 2024-05-01 title: New-Challenge --- @@ -20,7 +19,7 @@ Creates a pseudo random challenge to support FIDO2 attestation output (among oth ### __AllParameterSets ``` -New-Challenge -OutFile [-Length ] [-Force] [] +New-Challenge [-Length ] -OutFile [-Force] [] ``` ## ALIASES diff --git a/Docs/Commands/New-YubiKeyFIDO2Credential.md b/Docs/Commands/New-YubiKeyFIDO2Credential.md index a898c9b..00dd496 100644 --- a/Docs/Commands/New-YubiKeyFIDO2Credential.md +++ b/Docs/Commands/New-YubiKeyFIDO2Credential.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- @@ -49,6 +48,14 @@ New-YubiKeyFIDO2Credential -RelyingParty -Challenge [-RequestedAlgorithms ] [-WhatIf] [-Confirm] [] ``` +### Synthetic + +``` +New-YubiKeyFIDO2Credential -RelyingPartyID -Username [-RelyingPartyName ] + [-UserDisplayName ] [-Discoverable ] + [-RequestedAlgorithms ] [-WhatIf] [-Confirm] [] +``` + ## ALIASES ## DESCRIPTION @@ -70,6 +77,7 @@ PS C:\> {{ Add example code here }} ### -Challenge Challange. +Challenge for credential registration. ```yaml Type: powershellYK.FIDO2.Challenge @@ -77,7 +85,25 @@ DefaultValue: None SupportsWildcards: false Aliases: [] ParameterSets: -- Name: (All) +- Name: UserData-HostData + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +- Name: UserData-RelyingParty + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +- Name: UserEntity-HostData + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +- Name: UserEntity-RelyingParty Position: Named IsRequired: true ValueFromPipeline: false @@ -180,6 +206,12 @@ ParameterSets: ValueFromPipeline: false ValueFromPipelineByPropertyName: false ValueFromRemainingArguments: false +- Name: Synthetic + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false DontShow: false AcceptedValues: [] HelpMessage: '' @@ -207,6 +239,12 @@ ParameterSets: ValueFromPipeline: false ValueFromPipelineByPropertyName: false ValueFromRemainingArguments: false +- Name: Synthetic + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false DontShow: false AcceptedValues: [] HelpMessage: '' @@ -262,6 +300,12 @@ ParameterSets: ValueFromPipeline: false ValueFromPipelineByPropertyName: false ValueFromRemainingArguments: false +- Name: Synthetic + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false DontShow: false AcceptedValues: [] HelpMessage: '' @@ -343,6 +387,12 @@ ParameterSets: ValueFromPipeline: false ValueFromPipelineByPropertyName: false ValueFromRemainingArguments: false +- Name: Synthetic + Position: Named + IsRequired: true + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false DontShow: false AcceptedValues: [] HelpMessage: '' diff --git a/Docs/Commands/New-YubikeyOATHAccount.md b/Docs/Commands/New-YubikeyOATHAccount.md index 51f7a5f..1ce3f67 100644 --- a/Docs/Commands/New-YubikeyOATHAccount.md +++ b/Docs/Commands/New-YubikeyOATHAccount.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/New-YubikeyPIVKey.md b/Docs/Commands/New-YubikeyPIVKey.md index c9b963a..dbf41d4 100644 --- a/Docs/Commands/New-YubikeyPIVKey.md +++ b/Docs/Commands/New-YubikeyPIVKey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/New-YubikeyPIVSelfSign.md b/Docs/Commands/New-YubikeyPIVSelfSign.md index a2bd62d..1077017 100644 --- a/Docs/Commands/New-YubikeyPIVSelfSign.md +++ b/Docs/Commands/New-YubikeyPIVSelfSign.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Protect-YubiKeyFIDO2File.md b/Docs/Commands/Protect-YubiKeyFIDO2File.md index 6aeedc8..19b908b 100644 --- a/Docs/Commands/Protect-YubiKeyFIDO2File.md +++ b/Docs/Commands/Protect-YubiKeyFIDO2File.md @@ -4,7 +4,6 @@ external help file: powershellYK.dll-Help.xml HelpUri: '' Locale: en-SE Module Name: powershellYK -ms.date: 03-26-2026 PlatyPS schema version: 2024-05-01 title: Protect-YubiKeyFIDO2File --- @@ -17,31 +16,35 @@ Encrypts a file using FIDO2 PRF (hmac-secret) extension on a YubiKey. ## SYNTAX -### WithCredential (Default) +### WithCredential ``` -Protect-YubiKeyFIDO2File -Path -Credential [-OutFile ] [-WhatIf] - [-Confirm] [] +Protect-YubiKeyFIDO2File -Path -Credential [-OutFile ] [-Force] + [-WhatIf] [-Confirm] [] ``` ### WithCredentialID ``` Protect-YubiKeyFIDO2File -Path -CredentialID -RelyingPartyID - [-OutFile ] [-WhatIf] [-Confirm] [] + [-OutFile ] [-Force] [-WhatIf] [-Confirm] [] ``` ### ByRelyingPartyID ``` -Protect-YubiKeyFIDO2File -Path -RelyingPartyID [-OutFile ] [-WhatIf] - [-Confirm] [] +Protect-YubiKeyFIDO2File -Path -RelyingPartyID [-OutFile ] [-Force] + [-WhatIf] [-Confirm] [] ``` -## ALIASES +### AutoCreate (Default) + +``` +Protect-YubiKeyFIDO2File -Path [-OutFile ] [-Force] [-WhatIf] [-Confirm] + [] +``` -This cmdlet has the following aliases, - {{Insert list of aliases}} +## ALIASES ## DESCRIPTION @@ -139,6 +142,27 @@ AcceptedValues: [] HelpMessage: '' ``` +### -Force + +Suppress the confirmation prompt when auto-creating a credential. + +```yaml +Type: System.Management.Automation.SwitchParameter +DefaultValue: '' +SupportsWildcards: false +Aliases: [] +ParameterSets: +- Name: (All) + Position: Named + IsRequired: false + ValueFromPipeline: false + ValueFromPipelineByPropertyName: false + ValueFromRemainingArguments: false +DontShow: false +AcceptedValues: [] +HelpMessage: '' +``` + ### -OutFile Output file path. Defaults to input path with .enc extension. diff --git a/Docs/Commands/Protect-YubikeyOATH.md b/Docs/Commands/Protect-YubikeyOATH.md index 11284ce..f556535 100644 --- a/Docs/Commands/Protect-YubikeyOATH.md +++ b/Docs/Commands/Protect-YubikeyOATH.md @@ -1,4 +1,4 @@ ---- +--- external help file: powershellYK.dll-Help.xml Module Name: powershellYK online version: diff --git a/Docs/Commands/Register-YubikeyBIOFingerprint.md b/Docs/Commands/Register-YubikeyBIOFingerprint.md index 6e2ebe0..54f00f5 100644 --- a/Docs/Commands/Register-YubikeyBIOFingerprint.md +++ b/Docs/Commands/Register-YubikeyBIOFingerprint.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Remove-YubiKeyBIOFingerprint.md b/Docs/Commands/Remove-YubiKeyBIOFingerprint.md index a316350..5a9cb4a 100644 --- a/Docs/Commands/Remove-YubiKeyBIOFingerprint.md +++ b/Docs/Commands/Remove-YubiKeyBIOFingerprint.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Remove-YubikeyFIDO2Credential.md b/Docs/Commands/Remove-YubikeyFIDO2Credential.md index 9c5c40c..e734449 100644 --- a/Docs/Commands/Remove-YubikeyFIDO2Credential.md +++ b/Docs/Commands/Remove-YubikeyFIDO2Credential.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Remove-YubikeyOATHAccount.md b/Docs/Commands/Remove-YubikeyOATHAccount.md index 47059f3..99c65f0 100644 --- a/Docs/Commands/Remove-YubikeyOATHAccount.md +++ b/Docs/Commands/Remove-YubikeyOATHAccount.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Remove-YubikeyOTP.md b/Docs/Commands/Remove-YubikeyOTP.md index 63f22f2..ebc4ed3 100644 --- a/Docs/Commands/Remove-YubikeyOTP.md +++ b/Docs/Commands/Remove-YubikeyOTP.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Remove-YubikeyPIVKey.md b/Docs/Commands/Remove-YubikeyPIVKey.md index 5ae183a..16d924d 100644 --- a/Docs/Commands/Remove-YubikeyPIVKey.md +++ b/Docs/Commands/Remove-YubikeyPIVKey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Rename-YubikeyBIOFingerprint.md b/Docs/Commands/Rename-YubikeyBIOFingerprint.md index b01fce9..b734beb 100644 --- a/Docs/Commands/Rename-YubikeyBIOFingerprint.md +++ b/Docs/Commands/Rename-YubikeyBIOFingerprint.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Rename-YubikeyOATHAccount.md b/Docs/Commands/Rename-YubikeyOATHAccount.md index 8f29722..5bd2fb0 100644 --- a/Docs/Commands/Rename-YubikeyOATHAccount.md +++ b/Docs/Commands/Rename-YubikeyOATHAccount.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Request-YubikeyOATHCode.md b/Docs/Commands/Request-YubikeyOATHCode.md index ede9c39..5a6332c 100644 --- a/Docs/Commands/Request-YubikeyOATHCode.md +++ b/Docs/Commands/Request-YubikeyOATHCode.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Request-YubikeyOTPChallange.md b/Docs/Commands/Request-YubikeyOTPChallange.md index 20d9fd2..02aabfc 100644 --- a/Docs/Commands/Request-YubikeyOTPChallange.md +++ b/Docs/Commands/Request-YubikeyOTPChallange.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Reset-YubiKeyBioMPE.md b/Docs/Commands/Reset-YubiKeyBioMPE.md index 1d852f3..4d97f19 100644 --- a/Docs/Commands/Reset-YubiKeyBioMPE.md +++ b/Docs/Commands/Reset-YubiKeyBioMPE.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Reset-YubikeyFIDO2.md b/Docs/Commands/Reset-YubikeyFIDO2.md index e2f6499..88f0b65 100644 --- a/Docs/Commands/Reset-YubikeyFIDO2.md +++ b/Docs/Commands/Reset-YubikeyFIDO2.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Reset-YubikeyOATH.md b/Docs/Commands/Reset-YubikeyOATH.md index e066cec..b935094 100644 --- a/Docs/Commands/Reset-YubikeyOATH.md +++ b/Docs/Commands/Reset-YubikeyOATH.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Reset-YubikeyPIV.md b/Docs/Commands/Reset-YubikeyPIV.md index de83a87..2fb5d15 100644 --- a/Docs/Commands/Reset-YubikeyPIV.md +++ b/Docs/Commands/Reset-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Set-YubiKeyOATHPassword.md b/Docs/Commands/Set-YubiKeyOATHPassword.md index 3ffb5c9..39307c4 100644 --- a/Docs/Commands/Set-YubiKeyOATHPassword.md +++ b/Docs/Commands/Set-YubiKeyOATHPassword.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Set-YubiKeyOTPSlotAccessCode.md b/Docs/Commands/Set-YubiKeyOTPSlotAccessCode.md index fa856aa..9c04a9a 100644 --- a/Docs/Commands/Set-YubiKeyOTPSlotAccessCode.md +++ b/Docs/Commands/Set-YubiKeyOTPSlotAccessCode.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Set-Yubikey.md b/Docs/Commands/Set-Yubikey.md index b2c8a08..0f4ff1f 100644 --- a/Docs/Commands/Set-Yubikey.md +++ b/Docs/Commands/Set-Yubikey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Set-YubikeyFIDO2.md b/Docs/Commands/Set-YubikeyFIDO2.md index 309f1bd..da48d95 100644 --- a/Docs/Commands/Set-YubikeyFIDO2.md +++ b/Docs/Commands/Set-YubikeyFIDO2.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Set-YubikeyFIDO2PIN.md b/Docs/Commands/Set-YubikeyFIDO2PIN.md index edf20cb..915ca4b 100644 --- a/Docs/Commands/Set-YubikeyFIDO2PIN.md +++ b/Docs/Commands/Set-YubikeyFIDO2PIN.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Set-YubikeyOTP.md b/Docs/Commands/Set-YubikeyOTP.md index 921e69c..5e39e64 100644 --- a/Docs/Commands/Set-YubikeyOTP.md +++ b/Docs/Commands/Set-YubikeyOTP.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Set-YubikeyPIV.md b/Docs/Commands/Set-YubikeyPIV.md index e1052b2..165d023 100644 --- a/Docs/Commands/Set-YubikeyPIV.md +++ b/Docs/Commands/Set-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Switch-YubikeyOTP.md b/Docs/Commands/Switch-YubikeyOTP.md index 9520b14..e13b15e 100644 --- a/Docs/Commands/Switch-YubikeyOTP.md +++ b/Docs/Commands/Switch-YubikeyOTP.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Unblock-YubikeyPIV.md b/Docs/Commands/Unblock-YubikeyPIV.md index 377675b..8d85df9 100644 --- a/Docs/Commands/Unblock-YubikeyPIV.md +++ b/Docs/Commands/Unblock-YubikeyPIV.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Unlock-Yubikey.md b/Docs/Commands/Unlock-Yubikey.md index 006b654..fb6cb54 100644 --- a/Docs/Commands/Unlock-Yubikey.md +++ b/Docs/Commands/Unlock-Yubikey.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/Unprotect-YubiKeyFIDO2File.md b/Docs/Commands/Unprotect-YubiKeyFIDO2File.md index 045812f..1e23d15 100644 --- a/Docs/Commands/Unprotect-YubiKeyFIDO2File.md +++ b/Docs/Commands/Unprotect-YubiKeyFIDO2File.md @@ -4,7 +4,6 @@ external help file: powershellYK.dll-Help.xml HelpUri: '' Locale: en-SE Module Name: powershellYK -ms.date: 03-26-2026 PlatyPS schema version: 2024-05-01 title: Unprotect-YubiKeyFIDO2File --- @@ -26,9 +25,6 @@ Unprotect-YubiKeyFIDO2File -Path [-OutFile ] [-WhatIf] [-Co ## ALIASES -This cmdlet has the following aliases, - {{Insert list of aliases}} - ## DESCRIPTION Decrypts a file previously encrypted with Protect-YubiKeyFIDO2. diff --git a/Docs/Commands/Unprotect-YubikeyOATH.md b/Docs/Commands/Unprotect-YubikeyOATH.md index 7184d50..a638c37 100644 --- a/Docs/Commands/Unprotect-YubikeyOATH.md +++ b/Docs/Commands/Unprotect-YubikeyOATH.md @@ -1,9 +1,8 @@ ---- +--- document type: cmdlet external help file: powershellYK.dll-Help.xml HelpUri: Module Name: powershellYK -ms.date: 03-19-2026 PlatyPS schema version: 2024-05-01 --- diff --git a/Docs/Commands/powershellYK.md b/Docs/Commands/powershellYK.md index dce173b..9d0b386 100644 --- a/Docs/Commands/powershellYK.md +++ b/Docs/Commands/powershellYK.md @@ -5,7 +5,6 @@ HelpInfoUri: '' Locale: en-US Module Guid: d947dd9b-87eb-49ea-a373-b91c7acc0917 Module Name: powershellYK -ms.date: 03-27-2026 PlatyPS schema version: 2024-05-01 System.Collections.Generic.Dictionary`2[System.Object,System.Object]: '' --- @@ -34,9 +33,13 @@ Creates a CSR for a slot in the YubiKey. Sign a certificate request with a YubiKey. +### [Clear-YubiKeyFIDO2Blob](Clear-YubiKeyFIDO2Blob.md) + +Removes all BLOBs from the YubiKey FIDO2 application. + ### [Confirm-YubiKeyFIDO2Attestation](Confirm-YubiKeyFIDO2Attestation.md) -{{ Fill in the Synopsis }} +Confirm YubiKey FIDO2 Attestation. ### [Confirm-YubiKeyPIVAttestation](Confirm-YubiKeyPIVAttestation.md) @@ -163,10 +166,6 @@ Create a self signed certificate Encrypts a file using FIDO2 PRF (hmac-secret) extension on a YubiKey. -### [Protect-YubiKeyOATH](Protect-YubiKeyOATH.md) - -Set password - ### [Register-YubikeyBIOFingerprint](Register-YubikeyBIOFingerprint.md) Register a new fingerprint on a YubiKey Bio _or_ a YubiKey Bio Multi-Protocol Edition (MPE). diff --git a/Module/Cmdlets/FIDO2/Clear-YubiKeyFIDO2Blob.cs b/Module/Cmdlets/FIDO2/Clear-YubiKeyFIDO2Blob.cs new file mode 100644 index 0000000..ee610ed --- /dev/null +++ b/Module/Cmdlets/FIDO2/Clear-YubiKeyFIDO2Blob.cs @@ -0,0 +1,96 @@ +/// +/// Allows uploading of large blobs to the YubiKey FIDO2 applet, associated with a specific credential ID or relying party. +/// Requires a YubiKey with FIDO2 support and administrator privileges on Windows. +/// +/// .EXAMPLE +/// Import-YubiKeyFIDO2Blob -LargeBlob test.txt -RelyingPartyID "demo.yubico.com" +/// Imports a file as a large blob when there is no more than one credential for the Relying Party on the YubiKey. +/// +/// .EXAMPLE +/// Import-YubiKeyFIDO2Blob -LargeBlob test.txt -CredentialId "19448fe...67ab9207071e" +/// Imports a file as a large blob for a specified FIDO2 credential by ID (use when the RP has multiple credentials). +/// +/// .EXAMPLE +/// Import-YubiKeyFIDO2Blob -LargeBlob test.txt -CredentialId "19448fe...67ab9207071e" -Force +/// Imports a file as a large blob and overwrites any existing blob entry for that credential without prompting. +/// + +using Microsoft.VisualBasic; +using Newtonsoft.Json; +using powershellYK.FIDO2; +using powershellYK.support; +using powershellYK.support.transform; +using powershellYK.support.validators; +using System.Management.Automation; // Windows PowerShell namespace. +using System.Security; +using System.Security.Cryptography; +using Yubico.YubiKey; +using Yubico.YubiKey.Cryptography; +using Yubico.YubiKey.Fido2; + +namespace powershellYK.Cmdlets.Fido +{ + [Cmdlet(VerbsCommon.Clear, "YubiKeyFIDO2Blob", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)] + public class ClearYubikeyFIDO2BlobCmdlet : PSCmdlet + { + // Initialize processing and verify requirements + protected override void BeginProcessing() + { + // Check if running as Administrator + if (Windows.IsRunningAsAdministrator() == false) + { + throw new Exception("FIDO access on Windows requires running as Administrator."); + } + + // 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) + { + throw new Exception("Connect-YubikeyFIDO2 failed to connect to the FIDO2 applet!"); + } + } + } + + // Process the main cmdlet logic + protected override void ProcessRecord() + { + using (var fido2Session = new Fido2Session((YubiKeyDevice)YubiKeyModule._yubikey!)) + { + fido2Session.KeyCollector = YubiKeyModule._KeyCollector.YKKeyCollectorDelegate; + + if (fido2Session.AuthenticatorInfo.MaximumSerializedLargeBlobArray is null) + { + throw new NotSupportedException("This YubiKey does not support FIDO2 large blobs."); + } + + // Get the current serialized Large Blob array from the authenticator + var blobArray = fido2Session.GetSerializedLargeBlobArray(); + WriteDebug($"Step 6: Current large blob array loaded! {blobArray.Entries.Count} entries"); + + for (int i = (blobArray.Entries.Count - 1); i >= 0; i--) + { + blobArray.RemoveEntry(i); + } + + if (ShouldProcess("This will delete stored FIDO2 blobs, Proceed?", "This will delete stored FIDO2 blobs, Proceed?", "WARNING!")) + { + WriteDebug($"Step 8: Writing updated large blob array ({blobArray.Encode().Length}) bytes to YubiKey..."); + // Write the updated Large Blob array back to the authenticator + fido2Session.SetSerializedLargeBlobArray(blobArray); + + WriteInformation( + $"All FIDO2 large blob entries removed.", + new[] { "FIDO2" }); + } + } + } + } +} diff --git a/Module/Cmdlets/FIDO2/ConfirmYubiKeyFIDO2Attestation.cs b/Module/Cmdlets/FIDO2/ConfirmYubiKeyFIDO2Attestation.cs index eb59486..50eb6a0 100644 --- a/Module/Cmdlets/FIDO2/ConfirmYubiKeyFIDO2Attestation.cs +++ b/Module/Cmdlets/FIDO2/ConfirmYubiKeyFIDO2Attestation.cs @@ -170,7 +170,11 @@ private static X509Certificate2 ParseSshSkAttestation(byte[] data) try { +#if NET9_0_OR_GREATER + return X509CertificateLoader.LoadCertificate(certDer); +#else return new X509Certificate2(certDer); +#endif } catch { diff --git a/Module/Cmdlets/FIDO2/Import-YubiKeyFIDO2Blob.cs b/Module/Cmdlets/FIDO2/Import-YubiKeyFIDO2Blob.cs index ba868d2..2edd57d 100644 --- a/Module/Cmdlets/FIDO2/Import-YubiKeyFIDO2Blob.cs +++ b/Module/Cmdlets/FIDO2/Import-YubiKeyFIDO2Blob.cs @@ -63,8 +63,9 @@ public class ImportYubikeyFIDO2BlobCmdlet : PSCmdlet HelpMessage = "File to import as large blob" )] [TransformPath] + [Alias("LargeBlob", "File")] [ValidatePath(fileMustExist: true, fileMustNotExist: false)] - public required System.IO.FileInfo LargeBlob { get; set; } + public required System.IO.FileInfo Path { get; set; } [Parameter( Mandatory = true, @@ -136,22 +137,22 @@ protected override void BeginProcessing() // Process the main cmdlet logic protected override void ProcessRecord() { - if (LargeBlob is null) + if (Path is null) { - throw new ArgumentException("You must enter a valid file path.", nameof(LargeBlob)); + throw new ArgumentException("You must enter a valid file path.", nameof(Path)); } // Resolve and read the input file - string resolvedPath = GetUnresolvedProviderPathFromPSPath(LargeBlob.FullName); + string resolvedPath = GetUnresolvedProviderPathFromPSPath(Path.FullName); byte[] blobData; try { blobData = System.IO.File.ReadAllBytes(resolvedPath); - WriteDebug($"Step 1: Input file loaded from '{LargeBlob.FullName}' ({blobData.Length} bytes)."); + WriteDebug($"Step 1: Input file loaded from '{Path.FullName}' ({blobData.Length} bytes)."); } catch (Exception ex) { - throw new IOException($"Failed to read large blob data from file '{LargeBlob}'.", ex); + throw new IOException($"Failed to read large blob data from file '{Path}'.", ex); } // ── Phase 1: Resolve credential ID and RP in isolated sessions ── diff --git a/Module/powershellYK.csproj b/Module/powershellYK.csproj index 7b6e84d..d862175 100644 --- a/Module/powershellYK.csproj +++ b/Module/powershellYK.csproj @@ -56,14 +56,20 @@ - - + + - - + + + + + + + + diff --git a/Module/powershellYK.psd1 b/Module/powershellYK.psd1 index 46c43d3..7d0db3f 100644 --- a/Module/powershellYK.psd1 +++ b/Module/powershellYK.psd1 @@ -81,6 +81,7 @@ CmdletsToExport = @( 'Set-YubiKey', 'Reset-YubiKeyBioMPE', 'Unlock-YubiKey', + 'Clear-YubiKeyFIDO2Blob', 'Connect-YubiKeyFIDO2', 'Confirm-YubiKeyFIDO2Attestation', 'Enable-YubiKeyFIDO2EnterpriseAttestation', diff --git a/Module/support/Yubico/KeyConverter.Asymmetric.cs b/Module/support/Yubico/KeyConverter.Asymmetric.cs new file mode 100644 index 0000000..2734ed8 --- /dev/null +++ b/Module/support/Yubico/KeyConverter.Asymmetric.cs @@ -0,0 +1,131 @@ +// Copyright 2021 Yubico AB +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Globalization; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using Yubico.YubiKey.Cryptography; +using Yubico.YubiKey.Piv; + +namespace Yubico.YubiKey.Sample.PivSampleCode +{ + // This file contains methods related to converting from a PivPublicKey into + // an AsymmetricAlgorithm, and converting from AsymmetricAlgorithm + // (the C# classes RSA and ECDsa) into PivPublicKey and PivPrivateKey. + public static partial class KeyConverter + { + // Build a PublicKey object from an AsymmetricAlgorithm object. + public static Cryptography.PublicKey GetPublicKeyFromDotNet(AsymmetricAlgorithm dotNetObject) + { + if (dotNetObject is null) + { + throw new ArgumentNullException(nameof(dotNetObject)); + } + + // Look at the SignatureAlgorithm property. If it is "RSA", we can + // cast the input to RSA. + if (string.Equals(dotNetObject.SignatureAlgorithm, AlgorithmRsa, StringComparison.Ordinal)) + { + var rsaParams = ((RSA)dotNetObject).ExportParameters(false); + // This constructor will validate the modulus and exponent. + var rsaPubKey = RSAPublicKey.CreateFromParameters(rsaParams); + return rsaPubKey; + } + var eccParams = new ECParameters(); + + // If the SignatureAlgorithm is "ECDsa", we can cast to ECDsa. + if (string.Equals(dotNetObject.SignatureAlgorithm, AlgorithmEcdsa, StringComparison.Ordinal)) + { + eccParams = ((ECDsa)dotNetObject).ExportParameters(false); + } + else if (string.Equals(dotNetObject.KeyExchangeAlgorithm, AlgorithmEcdh, StringComparison.Ordinal)) + { + eccParams = ((ECDiffieHellman)dotNetObject).ExportParameters(false); + } + + if (ValidateEccParameters(eccParams)) + { + var eccPubKey = ECPublicKey.CreateFromParameters(eccParams); + return eccPubKey; + } + + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, InvalidKeyDataMessage)); + + } + + // Build an AsymmetricAlgorithm object (either RSA or ECDsa) from a + // PublicKey. + public static AsymmetricAlgorithm GetDotNetFromPublicKey(IPublicKey publicKey) + { + ArgumentNullException.ThrowIfNull(publicKey); + if (publicKey.KeyType.IsRSA()) + { + var rsaPublicKey = (RSAPublicKey)publicKey; + return RSA.Create(rsaPublicKey.Parameters); + } + var ecPublicKey = (ECPublicKey)publicKey; + return ECDsa.Create(ecPublicKey.Parameters); + } + // Build a PrivateKey object from an AsymmetricAlgorithm object that + // contains a private key. + public static PrivateKey GetPrivateKeyFromDotNet(AsymmetricAlgorithm dotNetObject) + { + if (dotNetObject is null) + { + throw new ArgumentNullException(nameof(dotNetObject)); + } + + var rsaParams = new RSAParameters(); + var eccParams = new ECParameters(); + + try + { + // Look at the SignatureAlgorithm property. If it is "RSA", we can + // cast the input to RSA. + if (string.Equals(dotNetObject.SignatureAlgorithm, AlgorithmRsa, StringComparison.Ordinal)) + { + rsaParams = ((RSA)dotNetObject).ExportParameters(true); + + return RSAPrivateKey.CreateFromParameters(rsaParams); + } + + // If the SignatureAlgorithm is "ECDsa", we can cast to ECDsa. + if (string.Equals(dotNetObject.SignatureAlgorithm, AlgorithmEcdsa, StringComparison.Ordinal)) + { + eccParams = ((ECDsa)dotNetObject).ExportParameters(true); + } + else if (string.Equals(dotNetObject.KeyExchangeAlgorithm, AlgorithmEcdh, StringComparison.Ordinal)) + { + eccParams = ((ECDiffieHellman)dotNetObject).ExportParameters(true); + } + + if (ValidateEccParameters(eccParams)) + { + return ECPrivateKey.CreateFromParameters(eccParams); + } + } + finally + { + ClearRsaParameters(rsaParams); + ClearEccParameters(eccParams); + } + + throw new InvalidOperationException( + string.Format( + CultureInfo.CurrentCulture, + InvalidKeyDataMessage)); + } + } +} \ No newline at end of file diff --git a/Module/support/Yubico/KeyConverter.Pem.cs b/Module/support/Yubico/KeyConverter.Pem.cs new file mode 100644 index 0000000..e8632b4 --- /dev/null +++ b/Module/support/Yubico/KeyConverter.Pem.cs @@ -0,0 +1,483 @@ +// Copyright 2021 Yubico AB +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Globalization; +using System.Security.Cryptography; +using Yubico.YubiKey.Cryptography; +using Yubico.YubiKey.Piv; + + +namespace Yubico.YubiKey.Sample.PivSampleCode +{ + // This file contains methods related to converting into and out of PEM + // constructions. + public static partial class KeyConverter + { + // Build a new PublicKey object from a PEM key string. + // This method expects the buffer to contain one key only. It can be of + // either form + // -----BEGIN PUBLIC KEY----- + // + // -----END PUBLIC KEY----- + // + // -----BEGIN PRIVATE KEY----- + // + // -----END PRIVATE KEY----- + + + public static PublicKey GetPublicKeyFromPem(char[] pemKeyString) + { + byte[] encodedKey = GetEncodedKey(pemKeyString, false, out int algorithmFlag); + + try + { + // algorithmFlag is used as a bitfield. AlgorithmFlagPrivate has value 1 + // and other algorithm flags are distinct powers-of-two. Use bitwise + // checks instead of integer equality to avoid confusion about "+1". + bool isCurve25519 = (algorithmFlag & AlgorithmFlagCurve25519) != 0; + + if (isCurve25519) + { + // For a PUBLIC KEY PEM, encodedKey is a SubjectPublicKeyInfo and + // we can decode it directly. + return Curve25519PublicKey.CreateFromSubjectPublicKeyInfo(encodedKey); + } + + // For all other cases (including non-private curve25519 or + // RSA/ECDSA), fall back to the existing DotNet path. + using var dotNetObject = GetDotNetFromPem(pemKeyString, false); + return GetPublicKeyFromDotNet(dotNetObject); + } + finally + { + OverwriteBytes(encodedKey); + } + } + + // Build the PEM string from a PublicKey. + // This method will build the following PEM format. + // -----BEGIN PUBLIC KEY----- + // + // -----END PUBLIC KEY----- + + + public static char[] GetPemFromPublicKey(IPublicKey publicKey) + { + return PemOperations.BuildPem(PublicKeyTitle, publicKey.ExportSubjectPublicKeyInfo()); + } + + // Build a new PrivateKey object from a PEM key string. + // This method expects the PEM key to be of the form + // -----BEGIN PRIVATE KEY----- + // + // -----END PRIVATE KEY----- + + + public static PrivateKey GetPrivateKeyFromPem(char[] pemKeyString) + { + byte[] encodedKey = GetEncodedKey(pemKeyString, true, out int algorithmFlag); + + try + { + // algorithmFlag is used as a bitfield. AlgorithmFlagPrivate has value 1 + // and other algorithm flags are distinct powers-of-two. Use bitwise checks + bool isCurve25519 = (algorithmFlag & AlgorithmFlagCurve25519) != 0; + + if (isCurve25519) + { + // For Curve25519, decode the PKCS#8 format directly. + return Curve25519PrivateKey.CreateFromPkcs8(encodedKey); + } + + // For all other cases (including non-private curve25519 or + // RSA/ECDSA), fall back to the existing DotNet path. + using var dotNetObject = GetDotNetFromPem(pemKeyString, true); + return GetPrivateKeyFromDotNet(dotNetObject); + } + finally + { + OverwriteBytes(encodedKey); + } + } + + // Build an AsymmetricAlgorithm object from a PEM key. + // If the isPrivate arg is true, this method expects the PEM key to be of + // the form + // -----BEGIN PRIVATE KEY----- + // + // -----END PRIVATE KEY----- + // If not, the method will throw an exception. + // + // If the isPrivate arg is false, the method will accept the PEM private + // key format or + // -----BEGIN PUBLIC KEY----- + // + // -----END PUBLIC KEY----- + // Regardless of the format, the method will build an AsymmetricAlgorithm + // object that contains only the public key. + // If the key is ECC, this method will build an ECDsa object. If you need + // it as ECDiffieHellman, you can build a new ECDH object from the params + // of the ECDsa object. + public static AsymmetricAlgorithm GetDotNetFromPem(char[] pemKeyString, bool isPrivate) + { + byte[] encodedKey = Array.Empty(); + var rsaParams = new RSAParameters(); + var eccParams = new ECParameters(); + + try + { + encodedKey = GetEncodedKey(pemKeyString, isPrivate, out int algorithmFlag); + + switch (algorithmFlag) + { + default: + throw new InvalidOperationException( + string.Format( + CultureInfo.CurrentCulture, + InvalidKeyDataMessage)); + + case AlgorithmFlagRsa: + var rsaObject = RSA.Create(); + rsaObject.ImportSubjectPublicKeyInfo(encodedKey, out _); + return rsaObject; + + case AlgorithmFlagRsa | AlgorithmFlagPrivate: + using (var rsaPrivateObject = RSA.Create()) + { + rsaPrivateObject.ImportPkcs8PrivateKey(encodedKey, out _); + if (isPrivate) + { + rsaParams = rsaPrivateObject.ExportParameters(true); + } + else + { + // We have a private DotNet object, but the caller wanted + // a public. Get the public params out and build a new + // object. + rsaParams = rsaPrivateObject.ExportParameters(false); + } + return RSA.Create(rsaParams); + } + + case AlgorithmFlagEcdsa: + var eccObject = ECDsa.Create(); + eccObject.ImportSubjectPublicKeyInfo(encodedKey, out _); + return eccObject; + + case AlgorithmFlagEcdsa | AlgorithmFlagPrivate: + using (var eccPrivateObject = ECDsa.Create()) + { + eccPrivateObject.ImportPkcs8PrivateKey(encodedKey, out _); + if (isPrivate) + { + eccParams = eccPrivateObject.ExportParameters(true); + } + else + { + // We have a private DotNet object, but the caller wanted + // a public. Get the public params out and build a new + // object. + eccParams = eccPrivateObject.ExportParameters(false); + } + return ECDsa.Create(eccParams); + } + } + } + finally + { + OverwriteBytes(encodedKey); + ClearRsaParameters(rsaParams); + ClearEccParameters(eccParams); + } + } + + // Build a PEM key string. This method will build either + // -----BEGIN PUBLIC KEY----- + // + // -----END PUBLIC KEY----- + // or + // -----BEGIN PRIVATE KEY----- + // + // -----END PRIVATE KEY----- + // If the isPrivate arg is true, the method will extract the PKCS 8 + // PrivateKeyInfo from the dotNetObject and build the PRIVATE KEY. + // If the isPrivate arg is false, the method will extract the + // SubjectPublicKeyInfo and build the PUBLIC KEY. It will do so even if + // the dotNetObject contains the private key. + // If isPrivate is true and the dotNetObject does not contain the private + // key, this method will throw an exception. + public static char[] GetPemFromDotNet(AsymmetricAlgorithm dotNetObject, bool isPrivate) + { + if (dotNetObject is null) + { + throw new ArgumentNullException(nameof(dotNetObject)); + } + + byte[] encodedKey = Array.Empty(); + string title; + + try + { + if (isPrivate) + { + encodedKey = dotNetObject.ExportPkcs8PrivateKey(); + title = PrivateKeyTitle; + } + else + { + encodedKey = dotNetObject.ExportSubjectPublicKeyInfo(); + title = PublicKeyTitle; + } + + return PemOperations.BuildPem(title, encodedKey); + } + finally + { + OverwriteBytes(encodedKey); + } + } + + // Base64 decode the PEM key and return a new byte array containing the + // result. Return an empty array on error. + // If the isPrivate arg is true, the key must be private. If not, return + // an empty encodedKey. + // If the isPrivate arg is false, the key can be private or public. Go + // ahead and return the encoded key. + // Set the algorithmFlag to the algorithm (See AlgorithmFlag const + // values). If there's an error set it to AlgorithmFlagNone. + // This works for only PUBLIC KEY (SubjectPublicKeyInfo) and PRIVATE KEY + // (PrivateKeyInfo). + // Determine the algorithm based on the OID in the algorithm identifier. + // For both pub and pri, read tags until reaching 06. For private, there + // is an INTEGER in there, but all other tags will be SEQUENCE until + // hitting the OID. + private static byte[] GetEncodedKey(char[] pemKeyString, bool isPrivate, out int algorithmFlag) + { + algorithmFlag = AlgorithmFlagNone; + byte[] encodedKey = Array.Empty(); + + try + { + encodedKey = PemOperations.GetEncodingFromPem(pemKeyString, out string title); + + bool isPemPrivate = true; + if (!string.Equals(PrivateKeyTitle, title, StringComparison.Ordinal)) + { + isPemPrivate = false; + if (!string.Equals(PublicKeyTitle, title, StringComparison.Ordinal)) + { + return Array.Empty(); + } + } + + // If the caller wanted the private key, and this is the public + // key, return an empty array. + if (isPrivate && !isPemPrivate) + { + return Array.Empty(); + } + + // There is an OID inside the Pkcs8PrivateKey and the + // SubjectPublicKeyInfo that tells us whether this is RSA or ECC. + // However, C# does not have any publicly available way to read + // DER encoded data (it does but is only available in .NET 5.0). + // For now, we'll write our own code to find the OID. + // The DER encoding will be either + // 30 len 02 len value 30 len 06 len OID + // or + // 30 len 30 len 06 len OID + // So for this sample, we'll use a local method that reads TL or + // TLV and returns the offset to the next tag. Read until we hit + // the 06 (the OID tag). + int offset = 0; + do + { + offset = GetNextTagOffset(encodedKey, offset); + if (offset < 0) + { + return Array.Empty(); + } + } while (encodedKey[offset] != 6); + + // encodedKey[offset] is where the OID begins. + // RSA: 06 09 + // 2A 86 48 86 F7 0D 01 01 01 + // ECC: 06 07 + // 2A 86 48 CE 3D 02 01 + // Read the OID length and value bytes in a robust, ASN.1-aware way + // encodedKey[offset] is the OID tag (0x06). The length byte(s) + // follow at offset+1, and the value bytes follow the length field. + int oidLenIndex = offset + 1; + if (oidLenIndex >= encodedKey.Length) + { + return Array.Empty(); + } + + int firstLen = encodedKey[oidLenIndex] & 0xFF; + int oidLen; + int oidValueStart; + + if (firstLen <= 0x7F) + { + oidLen = firstLen; + oidValueStart = oidLenIndex + 1; + } + else + { + // Long-form length. Support up to 3 length bytes as in GetNextTagOffset. + if (firstLen == 0x80 || firstLen > 0x83) + { + return Array.Empty(); + } + + int count = firstLen & 0x0F; + if (encodedKey.Length < oidLenIndex + 1 + count) + { + return Array.Empty(); + } + + oidLen = 0; + for (int i = 0; i < count; i++) + { + oidLen = (oidLen << 8) + (encodedKey[oidLenIndex + 1 + i] & 0xFF); + } + + oidValueStart = oidLenIndex + 1 + count; + } + + if (oidValueStart + oidLen > encodedKey.Length) + { + return Array.Empty(); + } + + // Known OID value byte sequences (DER encoded value bytes): + // RSA: 1.2.840.113549.1.1.1 -> 2A 86 48 86 F7 0D 01 01 01 + // ECDSA: 1.2.840.10045.2.1 -> 2A 86 48 CE 3D 02 01 + // Ed25519: 1.3.101.112 -> 2B 65 70 + // X25519: 1.3.101.110 -> 2B 65 6E + byte[] oidRsa = new byte[] { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }; + byte[] oidEcdsa = new byte[] { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }; + byte[] oidEd25519 = new byte[] { 0x2B, 0x65, 0x70 }; + byte[] oidX25519 = new byte[] { 0x2B, 0x65, 0x6E }; + + bool Matches(byte[] candidate) + { + if (candidate.Length != oidLen) + { + return false; + } + + for (int i = 0; i < candidate.Length; i++) + { + if (encodedKey[oidValueStart + i] != candidate[i]) + { + return false; + } + } + + return true; + } + + if (Matches(oidRsa)) + { + algorithmFlag = AlgorithmFlagRsa; + } + else if (Matches(oidEcdsa)) + { + algorithmFlag = AlgorithmFlagEcdsa; + } + else if (Matches(oidEd25519) || Matches(oidX25519)) + { + algorithmFlag = AlgorithmFlagCurve25519; + } + else + { + return Array.Empty(); + } + + if (isPemPrivate) + { + algorithmFlag |= AlgorithmFlagPrivate; + } + + return encodedKey; + } + finally + { + if (algorithmFlag == AlgorithmFlagNone) + { + OverwriteBytes(encodedKey); + } + } + } + + // Return the offset to the next tag. If there's an error, return -1. + // Read the current tag and length at buffer[offset]. If the current tag + // is 30, just return the offset beyond the TL. If the current tag is not + // 30, return the offset beyond the TLV. + private static int GetNextTagOffset(byte[] buffer, int offset) + { + // Make sure there are enough bytes to read. + if (offset < 0 || buffer.Length < offset + 2) + { + return -1; + } + + // Read the value (the V of TLV) only if the current tag is not 30. + bool readValue = buffer[offset] != 0x30; + + // Look at the first length octet. + // If the length is 0x7F or less, the length is one octet. + // If the length octet is 0x80, that's BER and we shouldn't see it. + // Otherwise the length octet should be 81, 82, or 83 (technically it + // could be 84 or higher, but this method does not support anything + // beyond 83). This says the length is the next 1, 2, or 3 octets. + int length = buffer[offset + 1]; + int increment = 2; + if (length == 0x80 || length > 0x83) + { + return -1; + } + if (length > 0x80) + { + int count = length & 0xf; + if (buffer.Length < offset + increment + count) + { + return -1; + } + increment += count; + length = 0; + while (count > 0) + { + length <<= 8; + length += (int)buffer[offset + increment - count] & 0xFF; + count--; + } + } + + if (readValue) + { + if (buffer.Length < offset + increment + length) + { + return -1; + } + + increment += length; + } + + return offset + increment; + } + } +} \ No newline at end of file diff --git a/Module/support/Yubico/KeyConverter.cs b/Module/support/Yubico/KeyConverter.cs new file mode 100644 index 0000000..4483ad5 --- /dev/null +++ b/Module/support/Yubico/KeyConverter.cs @@ -0,0 +1,194 @@ +// Copyright 2021 Yubico AB +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Security.Cryptography; + +namespace Yubico.YubiKey.Sample.PivSampleCode +{ + // This class contains methods that convert between key formats. + // + // PEM string (PRIVATE KEY or PUBLIC KEY) + // PivPublicKey + // PivPrivateKey + // System.Security.Cryptography.RSA + // System.Security.Cryptography.ECDsa + // System.Security.Cryptography.ECDiffieHellman + // + // Each method will be "GetFrom", such as + // "GetPemFromPivPublicKey" or "GetPivPrivateKeyFromDotNet". + // + // For example, if you have a PEM key: + // + // -----BEGIN PRIVATE KEY----- + // + // -----END PRIVATE KEY----- + // or + // -----BEGIN PUBLIC KEY----- + // + // -----END PUBLIC KEY----- + // + // call the relevant "FromPem" method to get that key data returned as a + // PivPublicKey, PivPrivateKey, or an AsymmetricAlgorithm object. Note that + // this class uses the term "DotNet" as one of the formats. That denotes the + // input object or result returned will be from the .NET Base Class Libraries + // (BCL), namely the AsymmetricAlgorithm object. + // + // When converting to DotNet, the AsymmetricAlgorithm object returned will be + // an instance of System.Security.Cryptography.AsymmetricAlgorithm. That is + // an abstract base class, the actual object will be an instance of either + // RSA or ECDsa. Check the SignatureAlgorithm property to see what the + // algorithm is. If the object returned is ECDsa, but you need it as + // ECDiffieHellman, you can build a new ECDH object from the params of the + // ECDsa object. + // + // When converting from DotNet, the AsymmetricAlgorithm can be an instance of + // either RSA, ECDsa, or ECDiffieHellman. + // + // These are the following conversions in this class. + // + // From: To: + // + // PEM PivPublicKey + // PivPrivateKey + // DotNet + // + // PivPublicKey PEM + // DotNet + // + // PivPrivateKey --none-- + // + // DotNet PEM + // PivPublicKey + // PivPrivateKey + // + // A DotNet (AsymmetricAlgorithm) object contains either the public key only + // or the public and private key. If an object contains only the public key, + // then of course you will not be able to build a PivPrivateKey or a PEM + // private key. But if the object contains a private key, then you will be + // able to build a PivPublicKey or a PEM public key from that object. + // + // A PEM private key also contains a public key. If you want to get the + // PivPublicKey out of that PEM construction, you will have to build a + // DotNet (AsymmetricAlgorithm) object and and then convert from DotNet to + // PivPublicKey or PEM. + // + // For all From PEM methods, the key data must be of the form + // -----BEGIN PRIVATE KEY----- + // + // -----END PRIVATE KEY----- + // or + // -----BEGIN PUBLIC KEY----- + // + // -----END PUBLIC KEY----- + // If there are any "stray" characters at the beginning or end (even new + // line or other whitespace), the method will throw an exception. + // Note that there can be new line characters after the BEGIN line and + // before the END line, just make sure there is nothing immediately in + // front of the BEGIN line and nothing immediately after the END line. + // + // All PEM methods (To and From) use a char array. This is so that you can + // overwrite sensitive data if you want. The string class is immutable, so if + // you have a private key in PEM format, you cannot overwrite it when it's no + // longer needed. But if you have your private key as a char[], you can + // overwrite it when you're done with it (Array.Fill). + // If you want to deal with strings, and are not concerned with + // overwriting buffers, you can still use strings, just use the + // ToCharArray method if your PEM data is a string, and if you have + // output from this class as a char[], use the String constructor that + // takes in a char[]. + // + // This class accepts keys that are either + // RSA 1024, with public exponent of F4 (0x01 00 01 = decimal 65,537) + // RSA 2048, with public exponent of F4 + // ECC from the NIST curve P256 + // ECC from the NIST curve P384 + // If it encounters any other keys it will throw an exception. + // For example, if a PEM key to convert is DSA, or it is RSA 2048 with public + // exponent 3, the method will throw an exception. + public static partial class KeyConverter + { + private const string InvalidKeyDataMessage = "The input key data was not recognized."; + + // Bit field. Rsa and Private set, it is an RSA private key. If only the + // Rsa bit is set, it is RSA public. Same for Ecdsa. + private const int AlgorithmFlagNone = 0; + private const int AlgorithmFlagPrivate = 1; + private const int AlgorithmFlagRsa = 2; + private const int AlgorithmFlagEcdsa = 4; + private const int AlgorithmFlagCurve25519 = 8; + + private const string AlgorithmRsa = "RSA"; + private const string AlgorithmEcdsa = "ECDsa"; + private const string AlgorithmEcdh = "ECDiffieHellman"; + private const string PrivateKeyTitle = "PRIVATE KEY"; + private const string PublicKeyTitle = "PUBLIC KEY"; + + private const string OidP256 = "1.2.840.10045.3.1.7"; + private const string OidP384 = "1.3.132.0.34"; + + // Make sure the params are P256 or P384. + private static bool ValidateEccParameters(ECParameters eccParams) + { + if (!string.Equals(eccParams.Curve.Oid.Value, OidP256, StringComparison.Ordinal) && + !string.Equals(eccParams.Curve.Oid.Value, OidP384, StringComparison.Ordinal)) + { + return false; + } + + return true; + } + + public static void ClearRsaParameters(RSAParameters rsaParams) + { + OverwriteBytes(rsaParams.P); + OverwriteBytes(rsaParams.Q); + OverwriteBytes(rsaParams.DP); + OverwriteBytes(rsaParams.DQ); + OverwriteBytes(rsaParams.InverseQ); + OverwriteBytes(rsaParams.D); + + rsaParams.D = null; + rsaParams.DP = null; + rsaParams.DQ = null; + rsaParams.Exponent = null; + rsaParams.InverseQ = null; + rsaParams.Modulus = null; + rsaParams.P = null; + rsaParams.Q = null; + } + + private static void ClearEccParameters(ECParameters eccParams) + { + OverwriteBytes(eccParams.D); + eccParams.D = null; + } + + public static void OverwriteBytes(byte[] buffer) + { + if (!(buffer is null)) + { + Array.Fill(buffer, 0); + } + } + + public static void OverwriteChars(char[] buffer) + { + if (!(buffer is null)) + { + Array.Fill(buffer, '0'); + } + } + } +} \ No newline at end of file diff --git a/Module/support/Yubico/MessageDigestOperations.cs b/Module/support/Yubico/MessageDigestOperations.cs new file mode 100644 index 0000000..9b2dd31 --- /dev/null +++ b/Module/support/Yubico/MessageDigestOperations.cs @@ -0,0 +1,61 @@ +// Copyright 2021 Yubico AB +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Security.Cryptography; +using Yubico.YubiKey.Cryptography; + +namespace Yubico.YubiKey.Sample.PivSampleCode +{ + // This class demonstrates how to perform some hash (message digest) + // operations using the .NET Base Class Library. + // This sample demonstrates operations that are not part of PIV or the SDK. + // It is only presented as a convenience to Yubico's customers. + public static class MessageDigestOperations + { + // Create the message digest (hash) of the inputData. + // This method digests all the bytes in dataToDigest, using the specified + // hashAlgorithm. + public static byte[] ComputeMessageDigest(byte[] dataToDigest, HashAlgorithmName hashAlgorithm) + { + if (dataToDigest is null) + { + throw new ArgumentNullException(nameof(dataToDigest)); + } + + // The CryptographyProviders class is in + // Yubico.Authenticators.Cryptography. It is used to provide various + // crypto objects. By default, this class returns instances of the + // default .NET BCL classes. It is possible to change the + // CryptographyProviders class to return instances of different + // classes, so long as they are subclasses of the appropriate .NET + // classes. + using HashAlgorithm digester = hashAlgorithm.Name switch + { + "SHA1" => CryptographyProviders.Sha1Creator(), + "SHA256" => CryptographyProviders.Sha256Creator(), + "SHA384" => CryptographyProviders.Sha384Creator(), + "SHA512" => CryptographyProviders.Sha512Creator(), + _ => throw new ArgumentException("Unsupported by sample code"), + }; + + byte[] digest = new byte[digester.HashSize / 8]; + + _ = digester.TransformFinalBlock(dataToDigest, 0, dataToDigest.Length); + Array.Copy(digester.Hash, 0, digest, 0, digest.Length); + + return digest; + } + } +} \ No newline at end of file diff --git a/Module/support/Yubico/PemOperations.cs b/Module/support/Yubico/PemOperations.cs new file mode 100644 index 0000000..6aefeaf --- /dev/null +++ b/Module/support/Yubico/PemOperations.cs @@ -0,0 +1,215 @@ +// Copyright 2021 Yubico AB +// +// Licensed under the Apache License, Version 2.0 (the "License"). +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Globalization; + +namespace Yubico.YubiKey.Sample.PivSampleCode +{ + // This class contains methods that build and parse PEM constructions. + public static class PemOperations + { + private const string InvalidPemDataMessage = "The input PEM data was not recognized."; + + private const string Part1 = "-----BEGIN "; + private const string Part2And4 = "-----"; + private const string Part3 = "-----END "; + private const string NewLine = "\r\n"; + private const int Part1Length = 11; + private const int Part2And4Length = 5; + private const int Part3Length = 9; + + // Build a PEM construction using the given title and encoding. + // This method will build + // + // -----BEGIN title----- + // base64 of encoding + // -----END title----- + // + // For example, provide the encoding of a SubjectPublicKeyInfo and the + // tile of "PUBLIC KEY", and this method will build + // + // -----BEGIN PUBLIC KEY----- + // base64 of SubjectPublicKeyInfo + // -----END PUBLIC KEY----- + // + // That is a PEM public key. + // Note that this method will place a space between the "BEGIN" and the + // title provided. Hence, the title should be + // "PUBLIC KEY" + // not " PUBLIC KEY" + // not "PUBLIC KEY " + // Note that this method will "blindly" put the title into the result and + // will "blindly" base64 encode the input encoding. It does not check to + // see if the title is a valid PEM title (it does not even check if all + // the letters are upper case), nor does it check the encoding. + public static char[] BuildPem(string title, byte[] encoding) + { + if (encoding is null) + { + throw new ArgumentNullException(nameof(encoding)); + } + + char[] temp = Array.Empty(); + + string header = Part1 + title + Part2And4 + NewLine; + string footer = NewLine + Part3 + title + Part2And4; + char[] prefix = header.ToCharArray(); + char[] suffix = footer.ToCharArray(); + + try + { + // The length of the char array will be the lengths of the prefix and + // suffix, along with the length of the Base64 data, and new line + // characters. Create an upper bound. + int blockCount = (encoding.Length + 2) / 3; + int totalLength = blockCount * 4; + int lineCount = (totalLength + 75) / 76; + totalLength += lineCount * 4; + totalLength += prefix.Length; + totalLength += suffix.Length; + + temp = new char[totalLength]; + Array.Copy(prefix, 0, temp, 0, prefix.Length); + int count = Convert.ToBase64CharArray( + encoding, 0, encoding.Length, + temp, prefix.Length, + Base64FormattingOptions.InsertLineBreaks); + Array.Copy(suffix, 0, temp, prefix.Length + count, suffix.Length); + totalLength = prefix.Length + suffix.Length + count; + char[] returnValue = new char[totalLength]; + Array.Copy(temp, 0, returnValue, 0, totalLength); + + return returnValue; + } + finally + { + KeyConverter.OverwriteChars(temp); + } + } + + // Base64 decode the PEM contents and return a new byte array containing + // the result. Set the output argument title to the PEM header title. + // The title will be something like "PRIVATE KEY" or + // "CERTIFICATE REQUEST". + // A PEM structure will be + // -----BEGIN something----- + // Base64 encoded data + // -----END something----- + // This method will find the base64 data and decode it. The result will + // be the encoded data. For example, if the header is + // -----BEGIN PUBLIC KEY----- + // then the data will be the DER encoding of SubjectPublicKeyInfo. + // The method will isolate the title, it is the "something" after the + // BEGIN and END in the header and footer. + // The method will also check to verify the header and footer match. + public static byte[] GetEncodingFromPem(char[] pemString, out string title) + { + if (pemString is null) + { + throw new ArgumentNullException(nameof(pemString)); + } + + bool isValid = false; + title = ""; + int titleLength = 0; + + // Find the title and verify the header and footer match. + if (CompareToTarget(pemString, 0, Part1.ToCharArray())) + { + int indexStart = Part1Length; + int indexEnd = Array.FindIndex(pemString, indexStart, x => x == '-'); + if (indexEnd > 0) + { + titleLength = indexEnd - indexStart; + char[] titleChars = new char[titleLength]; + Array.Copy(pemString, indexStart, titleChars, 0, titleLength); + title = new string(titleChars); + isValid = VerifyPemHeaderAndFooter(pemString, title); + } + } + + if (isValid) + { + int prefixLength = Part1Length + titleLength + Part2And4Length; + int suffixLength = Part3Length + titleLength + Part2And4Length; + + // Base64 decode everything between the labels. + return Convert.FromBase64CharArray( + pemString, + prefixLength, + pemString.Length - (prefixLength + suffixLength)); + } + + throw new InvalidOperationException( + string.Format( + CultureInfo.CurrentCulture, + InvalidPemDataMessage)); + } + + // This is the same as the other GetEncodingFromPem, except this takes in + // an expected title rather than returning the one found. + // Call this with the expected title. If it is the one in the PEM + // construction, the method will return the encoding. If it is not, the + // method will throw an exception. + public static byte[] GetEncodingFromPem(char[] pemString, string expectedTitle) + { + byte[] encoding = GetEncodingFromPem(pemString, out string title); + if (string.Equals(title, expectedTitle, StringComparison.Ordinal)) + { + return encoding; + } + + KeyConverter.OverwriteBytes(encoding); + throw new InvalidOperationException( + string.Format( + CultureInfo.CurrentCulture, + InvalidPemDataMessage)); + } + + // Verify that the given string begins with the targetStart and ends with + // the targetEnd. + private static bool VerifyPemHeaderAndFooter(char[] pemKeyString, string title) + { + char[] targetStart = (Part1 + title + Part2And4).ToCharArray(); + char[] targetEnd = (Part3 + title + Part2And4).ToCharArray(); + bool returnValue = false; + if (pemKeyString.Length > targetStart.Length + targetEnd.Length) + { + if (CompareToTarget(pemKeyString, 0, targetStart)) + { + returnValue = CompareToTarget(pemKeyString, pemKeyString.Length - targetEnd.Length, targetEnd); + } + } + + return returnValue; + } + + // Compare the chars in buffer beginning at offset with the chars in + // target. + private static bool CompareToTarget(char[] buffer, int offset, char[] target) + { + int index = 0; + for (; index < target.Length; index++) + { + if (buffer[index + offset] != target[index]) + { + break; + } + } + + return index >= target.Length; + } + } +} \ No newline at end of file diff --git a/Module/support/Yubico/YubiKeySignatureGenerator.cs b/Module/support/Yubico/YubiKeySignatureGenerator.cs index 2d7f2b0..be324a8 100644 --- a/Module/support/Yubico/YubiKeySignatureGenerator.cs +++ b/Module/support/Yubico/YubiKeySignatureGenerator.cs @@ -35,7 +35,7 @@ public sealed partial class YubiKeySignatureGenerator : X509SignatureGenerator private readonly PivSession _pivSession; private readonly byte _slotNumber; - private readonly IPublicKey _publicKey; + private readonly KeyType _algorithm; private readonly RSASignaturePaddingMode _rsaPaddingMode; private readonly X509SignatureGenerator _defaultGenerator; @@ -50,17 +50,13 @@ public sealed partial class YubiKeySignatureGenerator : X509SignatureGenerator public YubiKeySignatureGenerator( PivSession pivSession, byte slotNumber, - IPublicKey pivPublicKey, + IPublicKey publicKey, RSASignaturePaddingMode rsaPaddingMode = RSASignaturePaddingMode.Pss) { - if (pivSession is null) - { - throw new ArgumentNullException(nameof(pivSession)); - } - if (pivPublicKey is null) - { - throw new ArgumentNullException(nameof(pivPublicKey)); - } + + ArgumentNullException.ThrowIfNull(pivSession); + ArgumentNullException.ThrowIfNull(publicKey); + if (!PivSlot.IsValidSlotNumberForSigning(slotNumber)) { throw new ArgumentException( @@ -71,28 +67,20 @@ public YubiKeySignatureGenerator( _pivSession = pivSession; _slotNumber = slotNumber; - _publicKey = pivPublicKey; + _algorithm = publicKey.KeyType; _rsaPaddingMode = rsaPaddingMode; - if (_publicKey is RSAPublicKey) + using var dotNetPublicKey = KeyConverter.GetDotNetFromPublicKey(publicKey); + + if (_algorithm.IsRSA()) { var paddingScheme = rsaPaddingMode == RSASignaturePaddingMode.Pss ? RSASignaturePadding.Pss : RSASignaturePadding.Pkcs1; - - using (RSA rsa = RSA.Create()) - { - rsa.ImportSubjectPublicKeyInfo(_publicKey.ExportSubjectPublicKeyInfo(), out _); - _defaultGenerator = X509SignatureGenerator.CreateForRSA(rsa, paddingScheme); - } + _defaultGenerator = X509SignatureGenerator.CreateForRSA((RSA)dotNetPublicKey, paddingScheme); } - else if (_publicKey is ECPublicKey) + else if (_algorithm.IsEllipticCurve()) { - using (ECDsa ecc = ECDsa.Create()) - { - ecc.ImportSubjectPublicKeyInfo(_publicKey.ExportSubjectPublicKeyInfo(), out _); - _defaultGenerator = X509SignatureGenerator.CreateForECDsa(ecc); - } - + _defaultGenerator = X509SignatureGenerator.CreateForECDsa((ECDsa)dotNetPublicKey); } else { @@ -130,7 +118,7 @@ public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) byte[] dataToSign = DigestData(data, hashAlgorithm); - if (_publicKey is RSAPublicKey) + if (_algorithm.IsRSA()) { dataToSign = PadRsa(dataToSign, hashAlgorithm); } @@ -139,36 +127,28 @@ public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) } // Compute the message digest of the data using the given hashAlgorithm. - private byte[] DigestData(byte[] data, HashAlgorithmName hashAlgorithm) + // For RSA keys, returns the raw digest (PadRsa handles signature padding). + // For ECC keys, pads the digest to key size with leading zeros if needed. + public byte[] DigestData(byte[] data, HashAlgorithmName hashAlgorithm) { - using HashAlgorithm digester = hashAlgorithm.Name switch - { - "SHA1" => CryptographyProviders.Sha1Creator(), - "SHA256" => CryptographyProviders.Sha256Creator(), - "SHA384" => CryptographyProviders.Sha384Creator(), - "SHA512" => CryptographyProviders.Sha512Creator(), - _ => throw new ArgumentException( - string.Format( - CultureInfo.CurrentCulture, - InvalidAlgorithmMessage)), - }; + byte[] digest = MessageDigestOperations.ComputeMessageDigest(data, hashAlgorithm); - // If the algorithm is P-256, then make sure the digest is exactly 32 - // bytes. If it's P-384, the digest must be exactly 48 bytes. - // We'll prepend 00 bytes if necessary. - int bufferSize = _publicKey.KeyType switch + // For RSA, return the raw digest - PadRsa handles the signature padding + if (_algorithm.IsRSA()) { - KeyType.ECP256 => 32, - KeyType.ECP384 => 48, - KeyType.ECP521 => 65, - _ => digester.HashSize / 8, - }; + return digest; + } - byte[] digest = new byte[bufferSize]; - int offset = bufferSize - (digester.HashSize / 8); + // For ECC, the digest must match the key size (e.g., 32 bytes for P-256) + // Pad with leading zeros if necessary + int keySizeBytes = _algorithm.GetKeySizeBytes(); - // If offset < 0, that means the digest is too big. - if (offset < 0) + if (digest.Length == keySizeBytes) + { + return digest; + } + + if (digest.Length > keySizeBytes) { throw new ArgumentException( string.Format( @@ -176,10 +156,12 @@ private byte[] DigestData(byte[] data, HashAlgorithmName hashAlgorithm) InvalidAlgorithmMessage)); } - _ = digester.TransformFinalBlock(data, 0, data.Length); - Array.Copy(digester.Hash!, 0, digest, offset, digester.Hash.Length); + // Pad with leading zeros + byte[] paddedDigest = new byte[keySizeBytes]; + int offset = keySizeBytes - digest.Length; + Array.Copy(digest, 0, paddedDigest, offset, digest.Length); - return digest; + return paddedDigest; } // Create a block of data that is the data to sign padded following the @@ -199,11 +181,10 @@ private byte[] PadRsa(byte[] digest, HashAlgorithmName hashAlgorithm) if (_rsaPaddingMode == RSASignaturePaddingMode.Pss) { - return RsaFormat.FormatPkcs1Pss(digest, digestAlgorithm, ((RSAPublicKey)_publicKey).KeyType.GetKeySizeBits()); + return RsaFormat.FormatPkcs1Pss(digest, digestAlgorithm, _algorithm.GetKeySizeBits()); } - return RsaFormat.FormatPkcs1Sign(digest, digestAlgorithm, ((RSAPublicKey)_publicKey).KeyType.GetKeySizeBits()); - + return RsaFormat.FormatPkcs1Sign(digest, digestAlgorithm, _algorithm.GetKeySizeBits()); } } } \ No newline at end of file diff --git a/Pester/120-Yubikey-Generic.tests.ps1 b/Pester/120-Yubikey-Generic.tests.ps1 index e5b70fc..2d44339 100644 --- a/Pester/120-Yubikey-Generic.tests.ps1 +++ b/Pester/120-Yubikey-Generic.tests.ps1 @@ -3,6 +3,6 @@ Describe "Test Yubikey parts" { {Find-Yubikey -Serialnumber 123} | Should -Throw # Try to connect to non existing Yubikey } It "outputs 'Verify that connect works'" { - Get-Yubikey|Select-Object -ExpandProperty SerialNumber | Should -Be 19661687 + Get-Yubikey|Select-Object -ExpandProperty SerialNumber | Should-BeGreaterThanOrEqual 10000 } } diff --git a/Pester/310-FIDO2.tests.ps1 b/Pester/310-FIDO2.tests.ps1 index 848e4ff..07f9ab0 100644 --- a/Pester/310-FIDO2.tests.ps1 +++ b/Pester/310-FIDO2.tests.ps1 @@ -21,16 +21,25 @@ Describe "FIDO2 Tests" -Tag @("FIDO2") { } It -Name "Clear all credentials" -Test { {Get-YubiKeyFIDO2Credential|%{Remove-YubikeyFIDO2Credential -CredentialId $_.CredentialID -Confirm:$false}} | Should -Not -Throw - (Get-YubiKeyFIDO2Credential).Count | Should -Be 0 + Get-YubiKeyFIDO2Credential -WarningAction SilentlyContinue | Should -BeNullOrEmpty + #[array](Get-YubiKeyFIDO2Credential -WarningAction SilentlyContinue)).Count | Should -Be 0 # Make sure that the warning message does not trip Pester + } + It -Name "Create single fake credential" -Test { {New-YubiKeyFIDO2Credential -RelyingPartyID 'powershellYK' -Challenge ([powershellYK.FIDO2.Challenge]::FakeChallange("powershellYK")) -Discoverable:$true -Username 'powershellYKUser' -UserID 0x01} | Should -Not -Throw - (Get-YubiKeyFIDO2Credential).Count | Should -Be 1 + Get-YubiKeyFIDO2Credential | Should -HaveCount 1 (Get-YubiKeyFIDO2Credential).UserName | Should -Be "powershellYKUser" (Get-YubiKeyFIDO2Credential).RPId | Should -Be "powershellYK" - (Get-YubiKeyFIDO2Credential).Count | Should -Be 1 + } + It -Name "Add another credential" -Test { {New-YubiKeyFIDO2Credential -RelyingPartyID 'powershellYK' -Challenge ([powershellYK.FIDO2.Challenge]::FakeChallange("powershellYK")) -Discoverable:$true -Username 'powershellYK' -UserID 0x02} | Should -Not -Throw (Get-YubiKeyFIDO2Credential).Count | Should -Be 2 - {Get-YubiKeyFIDO2Credential|%{Remove-YubikeyFIDO2Credential -CredentialId $_.CredentialID -Confirm:$false}} | Should -Not -Throw - (Get-YubiKeyFIDO2Credential).Count | Should -Be 0 + } + It -Name "Clear all credentials one after another total 2" -Test { + & {Get-YubiKeyFIDO2Credential|%{Remove-YubikeyFIDO2Credential -CredentialId $_.CredentialID -Confirm:$false}} + Get-YubiKeyFIDO2Credential -WarningAction SilentlyContinue | Should-BeFalsy + } + + It -Name "Create credential and remove using CredentialID" -Test { {New-YubiKeyFIDO2Credential -RelyingPartyID 'powershellYK' -Challenge ([powershellYK.FIDO2.Challenge]::FakeChallange("powershellYK")) -Discoverable:$true -Username 'powershellYK' -UserID 0x03} | Should -Not -Throw $credentialString = (Get-YubiKeyFIDO2Credential|Select-Object -ExpandProperty CredentialID).ToString() {Remove-YubikeyFIDO2Credential -CredentialId $credentialString -Confirm:$false} | Should -Not -Throw diff --git a/Pester/320-FIDO2Blob.tests.ps1 b/Pester/320-FIDO2Blob.tests.ps1 index 642a556..7a122ac 100644 --- a/Pester/320-FIDO2Blob.tests.ps1 +++ b/Pester/320-FIDO2Blob.tests.ps1 @@ -1,13 +1,15 @@ Describe "FIDO2 Blob Tests" -Tag @("FIDO2",'FIDO2Blob') { BeforeAll { - { Connect-YubiKey } | Should -Not -Throw - { Connect-YubiKeyFIDO2 -PIN (ConvertTo-SecureString -String '123456' -AsPlainText -Force) } | Should -Not -Throw - { New-YubiKeyFIDO2Credential -RelyingPartyID 'powershellYK-FIDO2-BLOB' -Challenge ([powershellYK.FIDO2.Challenge]::FakeChallange("powershellYK")) -Discoverable:$true -Username 'powershellYKUser' -UserID 0x01 } | Should -Not -Throw + Connect-YubiKey + Connect-YubiKeyFIDO2 -PIN (ConvertTo-SecureString -String '123456' -AsPlainText -Force) + New-YubiKeyFIDO2Credential -RelyingPartyID 'powershellYK-FIDO2-BLOB' -Challenge ([powershellYK.FIDO2.Challenge]::FakeChallange("powershellYK")) -Discoverable:$true -Username 'powershellYKUser' -UserID 0x01 + Clear-YubiKeyFIDO2Blob -Confirm:$False } AfterAll { - Remove-YubikeyFIDO2Credential -RelayingParty 'powershellYK-FIDO2-BLOB' -Username powershellYKUser + Remove-YubikeyFIDO2Credential -RelayingParty 'powershellYK-FIDO2-BLOB' -Username powershellYKUser -Confirm:$False + Clear-YubiKeyFIDO2Blob -Confirm:$False } It -Name "Store file in FIDO2 Blob" -Test { - { Import-YubiKeyFIDO2Blob -RelyingPartyID 'powershellYK-FIDO2-BLOB' -LargeBlob ".\Pester\TestData\piv_attestion_5_4_3_9a_request.req" } | Should -Not -Throw + Import-YubiKeyFIDO2Blob -RelyingPartyID 'powershellYK-FIDO2-BLOB' -Path "./Pester/TestData/piv_attestion_5_4_3_9a_request.req" } } \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 1dbcef5..03b513b 100644 --- a/build.ps1 +++ b/build.ps1 @@ -4,18 +4,10 @@ if (Test-Path 'release') { $Directory = New-Item -Type Directory 'release' dotnet publish module --nologo --framework 'net8.0' --output "$($Directory.fullname)" -#Copy-Item "$($Directory.fullname)\loader\powershellYK_loader.pdb" "$($Directory.fullname)\module" -#Move-Item "$($Directory.fullname)\module\powershellYK.psd1" "$($Directory.fullname)" -#Move-Item "$($Directory.fullname)\module\powershellYK.format.ps1xml" "$($Directory.fullname)" - -#Remove-Item -Recurse "$($Directory.fullname)\module\runtimes\linux*" -#Remove-Item -Recurse "$($Directory.fullname)\module\runtimes\osx*" -#Remove-Item -Recurse "$($Directory.fullname)\module\runtimes\unix*" - # Only Windows Powershell use format.ps1xml #& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\signtool.exe" sign /sha1 "8079DD82969461B1B7A8769B26262726AA0F6D89" /fd SHA256 /t http://timestamp.sectigo.com "$($Directory.fullname)\powershellYK.format.ps1xml" -& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\signtool.exe" sign /sha1 "A502DF63C4109BE4BCAD42D8AFF43932709FB0C4" /fd SHA256 /t http://timestamp.sectigo.com "$($Directory.fullname)\powershellYK.dll" +#& "C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x86\signtool.exe" sign /sha1 "A502DF63C4109BE4BCAD42D8AFF43932709FB0C4" /fd SHA256 /t http://timestamp.sectigo.com "$($Directory.fullname)\powershellYK.dll" Read-Host -Prompt "Press Enter to continue" @@ -46,6 +38,14 @@ Measure-PlatyPSMarkdown -Path ./docs/Commands/*.md | Move-Item "$($Directory.fullname)\powershellYK\powershellYK.dll-help.xml" "$($Directory.fullname)\en-US\powershellYK.dll-help.xml" Remove-Item "$($Directory.fullname)\powershellYK" +#Remove ms.date from all files.. + +Get-ChildItem "Docs\Commands" -Recurse -File | + ForEach-Object { + (Get-Content $_.FullName) | + Where-Object { $_ -notmatch '^ms\.date:' } | + Set-Content $_.FullName + } Import-Module Pester