Skip to content

Commit

Permalink
FIDO2 Updates (#17)
Browse files Browse the repository at this point in the history
* Allow Set-YubikeyFIDO -SetPIN to request OldPIN
Update YKKeyCollector to throw if wrong oldPIN is set
Force Reset-YubikeyFIDO2 to confirm and update info

* Add DOCS

* Update Microsoft Management.Information
Update powershellYK version
  • Loading branch information
virot authored Nov 17, 2024
1 parent 92a9acf commit 756f65a
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 30 deletions.
34 changes: 32 additions & 2 deletions Docs/Commands/Reset-YubikeyFIDO2.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
---
external help file: powershellYK.dll-Help.xml
Module Name: powershellYK
online version:
Expand All @@ -13,7 +13,7 @@ Reset a Yubikey FIDO2 device to factory settings.
## SYNTAX

```
Reset-YubikeyFIDO2 [<CommonParameters>]
Reset-YubikeyFIDO2 [-WhatIf] [-Confirm] [<CommonParameters>]
```

## DESCRIPTION
Expand All @@ -31,6 +31,36 @@ Resets the Yubikey FIDO2 device to factory settings.

## PARAMETERS

### -Confirm
Prompts you for confirmation before running the cmdlet.

```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases: cf

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -WhatIf
Shows what would happen if the cmdlet runs. The cmdlet is not run.
```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases: wi

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
Expand Down
33 changes: 24 additions & 9 deletions Docs/Commands/Set-YubikeyFIDO2.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
---
external help file: powershellYK.dll-Help.xml
Module Name: powershellYK
online version:
Expand All @@ -12,11 +12,6 @@ Allows settings FIDO2 options.

## SYNTAX

### Set new PIN
```
Set-YubikeyFIDO2 -NewPIN <SecureString> [-SetPIN] [<CommonParameters>]
```

### Set PIN minimum length
```
Set-YubikeyFIDO2 -MinimumPINLength <Int32> [<CommonParameters>]
Expand All @@ -27,8 +22,13 @@ Set-YubikeyFIDO2 -MinimumPINLength <Int32> [<CommonParameters>]
Set-YubikeyFIDO2 -MinimumPINRelyingParty <String> [<CommonParameters>]
```

### Set PIN
```
Set-YubikeyFIDO2 [-SetPIN] [-OldPIN <SecureString>] -NewPIN <SecureString> [<CommonParameters>]
```

## DESCRIPTION
{{ Fill in the Description }}
Allows the setting of PIN code and minimum PIN length.

## EXAMPLES

Expand Down Expand Up @@ -99,7 +99,7 @@ New PIN
```yaml
Type: SecureString
Parameter Sets: Set new PIN
Parameter Sets: Set PIN
Aliases:

Required: True
Expand All @@ -109,12 +109,27 @@ Accept pipeline input: False
Accept wildcard characters: False
```
### -OldPIN
Old PIN, required to change the PIN code.
```yaml
Type: SecureString
Parameter Sets: Set PIN
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```
### -SetPIN
Easy access to Set new PIN
```yaml
Type: SwitchParameter
Parameter Sets: Set new PIN
Parameter Sets: Set PIN
Aliases:

Required: False
Expand Down
29 changes: 23 additions & 6 deletions Module/Cmdlets/Fido/ResetYubikeyFIDO2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
using powershellYK.FIDO2;
using powershellYK.support;
using Yubico.YubiKey.Fido2.Commands;
using powershellYK.Exceptions;

namespace powershellYK.Cmdlets.Fido
{
[Cmdlet(VerbsCommon.Reset, "YubikeyFIDO2")]
[Cmdlet(VerbsCommon.Reset, "YubikeyFIDO2", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]

public class ResetYubikeyFIDO2Cmdlet : Cmdlet
{
Expand All @@ -30,13 +31,29 @@ protected override void BeginProcessing()

protected override void ProcessRecord()
{
using (var fido2Session = new Fido2Session((YubiKeyDevice)YubiKeyModule._yubikey!))
if (ShouldProcess("Yubikey FIDO2", "Reset"))
{
ResetCommand resetCommand = new Yubico.YubiKey.Fido2.Commands.ResetCommand();
ResetResponse reply = fido2Session.Connection.SendCommand(resetCommand);
if (reply.Status != ResponseStatus.Success)
using (var fido2Session = new Fido2Session((YubiKeyDevice)YubiKeyModule._yubikey!))
{
WriteWarning($"Failed to reset FIDO2 credentials: {reply.Status}, Yubikey needs to be inserted within the last 5 seconds.");
ResetCommand resetCommand = new Yubico.YubiKey.Fido2.Commands.ResetCommand();
WriteWarning("Please touch the Yubikey to allow the reset.");
ResetResponse reply = fido2Session.Connection.SendCommand(resetCommand);
switch (reply.Status)
{
default:
throw new Exception("Unknown status. (Update ResetYubikeyFIDO2Cmdlet)");

case ResponseStatus.Failed:
throw new Exception("Please touch the Yubikey to allow the reset.");

case ResponseStatus.ConditionsNotSatisfied:
throw new Exception($"Failed to reset, Yubikey needs to be inserted within the last 5 seconds.");

case ResponseStatus.Success:
break;
}
WriteWarning("Restart FIDO2 Application by removing and reinserting the Yubikey.");
YubiKeyModule._fido2PIN = null;
}
}
}
Expand Down
74 changes: 66 additions & 8 deletions Module/Cmdlets/Fido/SetYubikeyFIDO2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,77 @@
using powershellYK.support;
using System.Security;
using powershellYK.support.validators;
using System.Collections.ObjectModel;
using Yubico.YubiKey.Piv;
using Microsoft.VisualBasic;


namespace powershellYK.Cmdlets.Fido
{
[Cmdlet(VerbsCommon.Set, "YubikeyFIDO2")]

public class SetYubikeyFIDO2Cmdlet : PSCmdlet
public class SetYubikeyFIDO2Cmdlet : PSCmdlet, IDynamicParameters
{
[Parameter(Mandatory = false, ParameterSetName = "Set new PIN", ValueFromPipeline = false, HelpMessage = "Easy access to Set new PIN")]
[Parameter(Mandatory = false, ParameterSetName = "Set PIN", ValueFromPipeline = false, HelpMessage = "Easy access to Set new PIN")]
public SwitchParameter SetPIN;
[ValidateYubikeyPIN(4,8)]
[Parameter(Mandatory = true, ParameterSetName = "Set new PIN", ValueFromPipeline = false, HelpMessage = "New PIN")]
public SecureString NewPIN { get; set; } = new SecureString();

[ValidateRange(4, 63)]
[Parameter(Mandatory = true, ParameterSetName = "Set PIN minimum length", ValueFromPipeline = false, HelpMessage = "Set the minimum length of the PIN")]
public int? MinimumPINLength { get; set; }
[ValidateLength(4, 63)]
[Parameter(Mandatory = true, ParameterSetName = "Send MinimumPIN to RelyingParty", ValueFromPipeline = false, HelpMessage = "To which RelyingParty should minimum PIN be sent")]
public string? MinimumPINRelyingParty { get; set; }

public object GetDynamicParameters()
{
try { YubiKeyModule.ConnectYubikey(); } catch { }

Collection<Attribute> oldPIN, newPIN;
if (YubiKeyModule._yubikey is not null)
{
using (var fido2Session = new Fido2Session((YubiKeyDevice)YubiKeyModule._yubikey!))
{
// if no minimum pin length is set, then set it to 63.
int minPinLength = fido2Session.AuthenticatorInfo.MinimumPinLength ?? 4;
// Verify that the yubikey FIDO2 has a PIN already set. If there is a PIN set then make sure we get the old PIN.
if (fido2Session.AuthenticatorInfo.Options!.Any(x => x.Key == AuthenticatorOptions.clientPin && x.Value == true) && (YubiKeyModule._fido2PIN is null)) {
oldPIN = new Collection<Attribute>() {
new ParameterAttribute() { Mandatory = true, HelpMessage = "Old PIN, required to change the PIN code.", ParameterSetName = "Set PIN", ValueFromPipeline = false},
new ValidateYubikeyPIN(4, 63)
};
}
else
{
oldPIN = new Collection<Attribute>() {
new ParameterAttribute() { Mandatory = false, HelpMessage = "Old PIN, required to change the PIN code.", ParameterSetName = "Set PIN", ValueFromPipeline = false},
new ValidateYubikeyPIN(4, 63)
};
}

newPIN = new Collection<Attribute>() {
new ParameterAttribute() { Mandatory = true, HelpMessage = "New PIN code to set for the FIDO2 module.", ParameterSetName = "Set PIN", ValueFromPipeline = false},
new ValidateYubikeyPIN(minPinLength, 63)
};
}
}
else
{
oldPIN = new Collection<Attribute>() {
new ParameterAttribute() { Mandatory = false, HelpMessage = "Old PIN, required to change the PIN code.", ParameterSetName = "Set PIN", ValueFromPipeline = false},
new ValidateYubikeyPIN(4, 63)
};
newPIN = new Collection<Attribute>() {
new ParameterAttribute() { Mandatory = true, HelpMessage = "New PIN code to set for the FIDO2 module.", ParameterSetName = "Set PIN", ValueFromPipeline = false},
new ValidateYubikeyPIN(4, 63)
};
}
var runtimeDefinedParameterDictionary = new RuntimeDefinedParameterDictionary();
var runtimeDefinedOldPIN = new RuntimeDefinedParameter("OldPIN", typeof(SecureString), oldPIN);
var runtimeDefinedNewPIN = new RuntimeDefinedParameter("NewPIN", typeof(SecureString), newPIN);
runtimeDefinedParameterDictionary.Add("OldPIN", runtimeDefinedOldPIN);
runtimeDefinedParameterDictionary.Add("NewPIN", runtimeDefinedNewPIN);
return runtimeDefinedParameterDictionary;
}

protected override void BeginProcessing()
{
Expand Down Expand Up @@ -68,8 +119,14 @@ protected override void ProcessRecord()
throw new Exception("Changing minimum PIN not possible with this yubikey hardware.");
}
break;
case "Set new PIN":
YubiKeyModule._fido2PINNew = NewPIN;
case "Set PIN":

if (this.MyInvocation.BoundParameters.ContainsKey("OldPIN"))
{
YubiKeyModule._fido2PIN = (SecureString)this.MyInvocation.BoundParameters["OldPIN"];
}

YubiKeyModule._fido2PINNew = (SecureString)this.MyInvocation.BoundParameters["NewPIN"];
try
{
if (fido2Session.AuthenticatorInfo.GetOptionValue(AuthenticatorOptions.clientPin) == OptionValue.False)
Expand All @@ -85,13 +142,14 @@ protected override void ProcessRecord()
}
catch (Exception e)
{
YubiKeyModule._fido2PIN = null;
throw new Exception(e.Message, e);
}
finally
{
YubiKeyModule._fido2PINNew = null;
}
YubiKeyModule._fido2PIN = NewPIN;
YubiKeyModule._fido2PIN = (SecureString)this.MyInvocation.BoundParameters["NewPIN"];
break;
case "Send MinimumPIN to RelyingParty":
var rpidList = new List<string>(1);
Expand Down
4 changes: 2 additions & 2 deletions Module/powershellYK.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<AssemblyVersion>0.0.15.4</AssemblyVersion>
<AssemblyVersion>0.0.16.0</AssemblyVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
Expand Down Expand Up @@ -36,7 +36,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Management.Automation" Version="7.4.5" />
<PackageReference Include="System.Management.Automation" Version="7.4.6" />
<PackageReference Include="Yubico.YubiKey" Version="1.11.0" />
</ItemGroup>

Expand Down
8 changes: 5 additions & 3 deletions Module/support/YKKeyCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,17 @@ public bool YKKeyCollectorDelegate(KeyEntryData keyEntryData)
switch (keyEntryData.Request)
{
default:
throw new Exception("Unknown request.");
//return false;
throw new Exception("Unknown request. (Update YKKeyCollector)");

case KeyEntryRequest.AuthenticatePivManagementKey:
throw new Exception("Incorrect Management Key.");
//return false;

case KeyEntryRequest.VerifyOathPassword:
throw new Exception("Incorrect Password.");

case KeyEntryRequest.ChangeFido2Pin:
throw new Exception("Failed to change FIDO2 PIN.");

case KeyEntryRequest.VerifyFido2Pin:
case KeyEntryRequest.VerifyPivPin:
if (!(keyEntryData.RetriesRemaining is null))
Expand Down

0 comments on commit 756f65a

Please sign in to comment.