Skip to content

Commit 5dd512e

Browse files
authored
Merge pull request #167
[fix] Removed TDES as default assumption for PivSession.PinOnly
2 parents baa3db0 + 4e5a685 commit 5dd512e

File tree

10 files changed

+93
-117
lines changed

10 files changed

+93
-117
lines changed

Yubico.YubiKey/src/Yubico/YubiKey/Piv/Commands/InitializeAuthenticateManagementKeyCommand.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using System;
1516
using Yubico.Core.Iso7816;
1617

1718
namespace Yubico.YubiKey.Piv.Commands
@@ -306,18 +307,25 @@ public sealed class InitializeAuthenticateManagementKeyCommand : IYubiKeyCommand
306307
/// </value>
307308
public YubiKeyApplication Application => YubiKeyApplication.Piv;
308309

310+
311+
[Obsolete("This constructor is deprecated. Users must specify management key algorithm type, as it cannot be assumed.")]
312+
public InitializeAuthenticateManagementKeyCommand()
313+
: this(true)
314+
{
315+
}
316+
309317
/// <summary>
310318
/// Initializes a new instance of the InitializeAuthenticateManagementKeyCommand class for
311-
/// Mutual Authentication, and a Triple-DES management key.
319+
/// Mutual Authentication.
312320
/// </summary>
313321
/// <remarks>
314322
/// Using this constructor is equivalent to
315323
/// <code language="csharp">
316-
/// new InitializeAuthenticateManagementKeyCommand(true);
324+
/// new InitializeAuthenticateManagementKeyCommand(true, PivAlgorithm.AES192);
317325
/// </code>
318326
/// </remarks>
319-
public InitializeAuthenticateManagementKeyCommand()
320-
: this(true)
327+
public InitializeAuthenticateManagementKeyCommand(PivAlgorithm algorithm)
328+
: this(true, algorithm)
321329
{
322330
}
323331

@@ -335,6 +343,7 @@ public InitializeAuthenticateManagementKeyCommand()
335343
/// <param name="mutualAuthentication">
336344
/// <c>True</c> for mutual authentication, <c>false</c> for single.
337345
/// </param>
346+
[Obsolete("This constructor is deprecated. Users must specify management key algorithm type, as it cannot be assumed.")]
338347
public InitializeAuthenticateManagementKeyCommand(bool mutualAuthentication)
339348
: this(mutualAuthentication, PivAlgorithm.TripleDes)
340349
{

Yubico.YubiKey/src/Yubico/YubiKey/Piv/Commands/InitializeAuthenticateManagementKeyResponse.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,7 @@ public sealed class InitializeAuthenticateManagementKeyResponse : PivResponse, I
6161
// ResponseApdu.Data. It will be 8 bytes.
6262
private readonly byte[]? _clientAuthenticationChallenge;
6363

64-
/// <summary>
65-
/// Constructs an InitializeAuthenticateManagementKeyResponse based on a ResponseApdu
66-
/// received from the YubiKey for the Triple-DES algorithm.
67-
/// </summary>
68-
/// <param name="responseApdu">
69-
/// The object containing the Response APDU<br/>returned by the YubiKey.
70-
/// </param>
71-
/// <exception cref="MalformedYubiKeyResponseException">
72-
/// Thrown when the data provided does not meet the expectations, and cannot be parsed.
73-
/// </exception>
64+
[Obsolete("This constructor is deprecated. Users must specify management key algorithm type, as it cannot be assumed.")]
7465
public InitializeAuthenticateManagementKeyResponse(ResponseApdu responseApdu)
7566
: this(responseApdu, PivAlgorithm.TripleDes)
7667
{
@@ -90,8 +81,8 @@ public InitializeAuthenticateManagementKeyResponse(ResponseApdu responseApdu)
9081
/// <exception cref="MalformedYubiKeyResponseException">
9182
/// Thrown when the data provided does not meet the expectations, and cannot be parsed.
9283
/// </exception>
93-
public InitializeAuthenticateManagementKeyResponse(ResponseApdu responseApdu, PivAlgorithm algorithm) :
94-
base(responseApdu)
84+
public InitializeAuthenticateManagementKeyResponse(ResponseApdu responseApdu, PivAlgorithm algorithm)
85+
: base(responseApdu)
9586
{
9687
Algorithm = algorithm;
9788

Yubico.YubiKey/src/Yubico/YubiKey/Piv/Commands/SetManagementKeyCommand.cs

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@ private SetManagementKeyCommand()
159159
throw new NotImplementedException();
160160
}
161161

162+
[Obsolete("This constructor is deprecated. Users must specify management key algorithm type, as it cannot be assumed.")]
163+
public SetManagementKeyCommand(ReadOnlyMemory<byte> newKey)
164+
: this(newKey, PivTouchPolicy.Default, PivAlgorithm.TripleDes)
165+
{
166+
}
167+
162168
/// <summary>
163169
/// Initializes a new instance of the <c>SetManagementKeyCommand</c> class.
164170
/// This command takes the new management key as input and will set the
@@ -176,11 +182,9 @@ private SetManagementKeyCommand()
176182
/// };
177183
/// </code>
178184
/// <para>
179-
/// The default algorithm is <c>TripleDes</c>. If you do not set the
180-
/// <c>Algorithm</c> property after instantiating with this constructor,
181-
/// the SDK will expect the key to be TripleDES. Valid algorithms are
182-
/// <c>PivAlgorithm.TripleDes</c>, <c>PivAlgorithm.Aes128</c>,
183-
/// <c>PivAlgorithm.Aes192</c>, and <c>PivAlgorithm.Aes256</c>.
185+
/// Valid algorithms are <c>PivAlgorithm.TripleDes</c>,
186+
/// <c>PivAlgorithm.Aes128</c>, <c>PivAlgorithm.Aes192</c>, and
187+
/// <c>PivAlgorithm.Aes256</c>. FIPS YubiKeys versions 5.7 and greater require <c>PivAlgorithm.Aes192</c>.
184188
/// </para>
185189
/// <para>
186190
/// Note that you need to authenticate the current PIV management key before
@@ -190,36 +194,15 @@ private SetManagementKeyCommand()
190194
/// <param name="newKey">
191195
/// The bytes that make up the new management key.
192196
/// </param>
193-
public SetManagementKeyCommand(ReadOnlyMemory<byte> newKey)
194-
: this(newKey, PivTouchPolicy.Default, PivAlgorithm.TripleDes)
197+
/// <param name="algorithm">
198+
/// The algorithm of the new management key.
199+
/// </param>
200+
public SetManagementKeyCommand(ReadOnlyMemory<byte> newKey, PivAlgorithm algorithm)
201+
: this(newKey, PivTouchPolicy.Default, algorithm)
195202
{
196203
}
197204

198-
/// <summary>
199-
/// Initializes a new instance of the SetManagementKeyCommand class. This
200-
/// command takes the new management key and the touch policy as input.
201-
/// </summary>
202-
/// <remarks>
203-
/// Note that a <c>touchPolicy</c> of <c>PivTouchPolicy.Default</c> or
204-
/// <c>None</c> is equivalent to <c>Never</c>.
205-
/// <para>
206-
/// The default algorithm is <c>TripleDes</c>. If you do not set the
207-
/// <c>Algorithm</c> property after instantiating with this constructor,
208-
/// the SDK will expect the key to be TripleDES. Valid algorithms are
209-
/// <c>PivAlgorithm.TripleDes</c>, <c>PivAlgorithm.Aes128</c>,
210-
/// <c>PivAlgorithm.Aes192</c>, and <c>PivAlgorithm.Aes256</c>.
211-
/// </para>
212-
/// <para>
213-
/// Note also that you need to authenticate the current PIV management
214-
/// key before setting it to a new value with this command.
215-
/// </para>
216-
/// </remarks>
217-
/// <param name="newKey">
218-
/// The bytes that make up the new management key.
219-
/// </param>
220-
/// <param name="touchPolicy">
221-
/// The touch policy for the management key.
222-
/// </param>
205+
[Obsolete("This constructor is deprecated. Users must specify management key algorithm type, as it cannot be assumed.")]
223206
public SetManagementKeyCommand(ReadOnlyMemory<byte> newKey, PivTouchPolicy touchPolicy)
224207
: this(newKey, touchPolicy, PivAlgorithm.TripleDes)
225208
{
@@ -236,7 +219,7 @@ public SetManagementKeyCommand(ReadOnlyMemory<byte> newKey, PivTouchPolicy touch
236219
/// <para>
237220
/// Valid algorithms are <c>PivAlgorithm.TripleDes</c>,
238221
/// <c>PivAlgorithm.Aes128</c>, <c>PivAlgorithm.Aes192</c>, and
239-
/// <c>PivAlgorithm.Aes256</c>,
222+
/// <c>PivAlgorithm.Aes256</c>. FIPS YubiKeys versions 5.7 and greater require <c>PivAlgorithm.Aes192</c>.
240223
/// </para>
241224
/// <para>
242225
/// Note also that you need to authenticate the current PIV management

Yubico.YubiKey/src/Yubico/YubiKey/Piv/PivSession.Pinonly.cs

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ public PivPinOnlyMode TryRecoverPinOnlyMode()
267267
// If we can authenticate the mgmt key, then set ADMIN DATA and
268268
// PRINTED.
269269
var userKeyCollector = KeyCollector;
270-
using var specialKeyCollector = new SpecialKeyCollector();
270+
using var specialKeyCollector = new SpecialKeyCollector(DefaultManagementKeyAlgorithm);
271271

272272
try
273273
{
@@ -349,7 +349,7 @@ private PivPinOnlyMode TryAuthenticatePinOnly(bool trustAdminData)
349349
}
350350

351351
var userKeyCollector = KeyCollector;
352-
using var specialKeyCollector = new SpecialKeyCollector();
352+
using var specialKeyCollector = new SpecialKeyCollector(DefaultManagementKeyAlgorithm);
353353

354354
try
355355
{
@@ -513,7 +513,7 @@ private PivPinOnlyMode GetPinDerivedStatus(
513513

514514
/// <summary>
515515
/// Set the YubiKey's PIV application to be PIN-only with a PIN-derived
516-
/// and/or PIN-Protected Triple-DES management key. This sets the
516+
/// and/or PIN-Protected management key (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.). This sets the
517517
/// YubiKey to either
518518
/// <code>
519519
/// PivPinOnlyMode.PinProtected
@@ -544,7 +544,7 @@ private PivPinOnlyMode GetPinDerivedStatus(
544544
/// </para>
545545
/// <para>
546546
/// Note also that this will make sure that the management key algorithm
547-
/// will be Triple-DES, even if the current management key is a different
547+
/// will be default management key algorithm (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.), even if the current management key is a different
548548
/// algorithm. This behavior matches how this method operated in previous
549549
/// versions of the SDK.
550550
/// </para>
@@ -554,7 +554,7 @@ private PivPinOnlyMode GetPinDerivedStatus(
554554
/// </param>
555555
/// <exception cref="InvalidOperationException">
556556
/// There is no <c>KeyCollector</c> loaded, one of the keys provided was
557-
/// not a valid Triple-DES key, the data stored on the YubiKey is
557+
/// not of a valid key algorithm type (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.), the data stored on the YubiKey is
558558
/// incompatible with PIN-only, or the YubiKey had some other error, such
559559
/// as unreliable connection.
560560
/// </exception>
@@ -566,7 +566,7 @@ private PivPinOnlyMode GetPinDerivedStatus(
566566
/// authenticated, or the remaining retries count indicates the PIN is
567567
/// blocked.
568568
/// </exception>
569-
public void SetPinOnlyMode(PivPinOnlyMode pinOnlyMode) => SetPinOnlyMode(pinOnlyMode, PivAlgorithm.TripleDes);
569+
public void SetPinOnlyMode(PivPinOnlyMode pinOnlyMode) => SetPinOnlyMode(pinOnlyMode, DefaultManagementKeyAlgorithm);
570570

571571
/// <summary>
572572
/// Set the YubiKey's PIV application to be PIN-only with a PIN-derived
@@ -604,13 +604,13 @@ private PivPinOnlyMode GetPinDerivedStatus(
604604
/// The management key derived and/or stored in PRINTED will be for the
605605
/// specified algorithm. For all YubiKeys, <c>TripleDes</c> is a valid
606606
/// algorithm. For YubiKeys 5.4.2 and later, it is possible to set the
607-
/// management key to an AES key. Before setting the
608-
/// <c>mgmtKeyAlgorithm</c> arg to an AES algorithm, make sure it is
607+
/// management key to an AES key. For YubiKeys 5.7 and later, AES192 is the default.
608+
/// Before setting the <c>mgmtKeyAlgorithm</c> arg to an AES algorithm, make sure it is
609609
/// allowed on the YubiKey. You can use the <c>HasFeature</c> call. For
610610
/// example,
611611
/// <code language="csharp">
612612
/// PivAlgorithm mgmtKeyAlgorithm = yubiKey.HasFeature(YubiKeyFeature.PivAesManagementKey) ?
613-
/// PivAlgorithm.Aes128 : PivAlgorithm.TripleDes;
613+
/// PivAlgorithm.Aes192 : PivAlgorithm.TripleDes;
614614
/// pivSession.SetPinOnlyMode(PivPinOnlyMode.PinProtected, mgmtKeyAlgorithm);
615615
/// </code>
616616
/// If the algorithm is not supported by the YubiKey, this method will
@@ -641,16 +641,11 @@ private PivPinOnlyMode GetPinDerivedStatus(
641641
/// currently set to PIN-only (and neither PinProtected nor PinDerived is
642642
/// Unavailable), this method will remove the contents of the storage
643643
/// locations ADMIN DATA and PRINTED, and reset the management key to the
644-
/// default:
645-
/// <code>
646-
/// Triple-DES
647-
/// 0x01 02 03 04 05 06 07 08
648-
/// 01 02 03 04 05 06 07 08
649-
/// 01 02 03 04 05 06 07 08
650-
/// </code>
644+
/// default management key.
651645
/// In this case, the <c>mgmtKeyAlgorithm</c> arg will be ignored, the
652646
/// management key's algorithm after removing PIN-only status will be
653-
/// Triple-DES. The touch policy of the management key will also be set
647+
/// the default management key algorithm (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.).
648+
/// The touch policy of the management key will also be set
654649
/// to the default (Never). Note that the management key must be
655650
/// authenticated and the PIN verified in order to perform this task.
656651
/// This method will authenticate the management key using the PIN-only
@@ -732,7 +727,7 @@ private PivPinOnlyMode GetPinDerivedStatus(
732727
/// </param>
733728
/// <exception cref="InvalidOperationException">
734729
/// There is no <c>KeyCollector</c> loaded, one of the keys provided was
735-
/// not a valid Triple-DES key, the data stored on the YubiKey is
730+
/// not of a valid key algorithm type (Firmware 5.7.x and later: AES-192. Firmware 5.6.x and earlier: TDES.), the data stored on the YubiKey is
736731
/// incompatible with PIN-only, or the YubiKey had some other error, such
737732
/// as unreliable connection.
738733
/// </exception>
@@ -751,7 +746,7 @@ public void SetPinOnlyMode(PivPinOnlyMode pinOnlyMode, PivAlgorithm mgmtKeyAlgor
751746
pinOnlyMode.ToString(), mgmtKeyAlgorithm.ToString());
752747

753748
var userKeyCollector = KeyCollector;
754-
using var specialKeyCollector = new SpecialKeyCollector();
749+
using var specialKeyCollector = new SpecialKeyCollector(DefaultManagementKeyAlgorithm);
755750

756751
try
757752
{
@@ -777,7 +772,7 @@ private void SetPinOnlyMode(ReadOnlyMemory<byte> pin, PivPinOnlyMode pinOnlyMode
777772
}
778773

779774
var userKeyCollector = KeyCollector;
780-
using var specialKeyCollector = new SpecialKeyCollector();
775+
using var specialKeyCollector = new SpecialKeyCollector(DefaultManagementKeyAlgorithm);
781776

782777
try
783778
{
@@ -835,7 +830,7 @@ private void SetPinOnlyMode(
835830
// Or some other reason.
836831
var newPinOnlyMode = PivPinOnlyMode.None;
837832
var currentPinOnlyMode = GetPrintedPinProtectedStatus(specialKeyCollector, userKeyCollector);
838-
833+
839834
var pinOnlyCheck = CheckPinOnlyStatus(
840835
currentPinOnlyMode, pinOnlyMode, PivPinOnlyMode.PinProtected, PivPinOnlyMode.PinProtectedUnavailable,
841836
newAlgorithm, ref newPinOnlyMode);
@@ -1028,11 +1023,12 @@ private void ClearPinOnly(PivPinOnlyMode currentMode, SpecialKeyCollector specia
10281023
PutEmptyData(AdminDataDataTag);
10291024
}
10301025

1026+
var managementKeyAlgorithm = DefaultManagementKeyAlgorithm;
10311027
specialKeyCollector.SetKeyData(
10321028
SpecialKeyCollector.SetKeyDataDefault, ReadOnlyMemory<byte>.Empty, isNewKey: true,
1033-
PivAlgorithm.TripleDes);
1029+
managementKeyAlgorithm);
10341030

1035-
specialKeyCollector.ChangeManagementKey(this, PivAlgorithm.TripleDes);
1031+
specialKeyCollector.ChangeManagementKey(this, managementKeyAlgorithm);
10361032
}
10371033

10381034
private void PutEmptyData(int dataTag)
@@ -1087,7 +1083,7 @@ private void SetYubiKeyPinDerived(
10871083
// because this method will update the current key with the new key.
10881084
specialKeyCollector.ChangeManagementKey(this, mgmtKeyAlgorithm);
10891085
_ = BlockPinOrPuk(PivSlot.Puk);
1090-
1086+
10911087
adminData.SetSalt(saltBytes);
10921088
adminData.PukBlocked = true;
10931089
}
@@ -1150,7 +1146,7 @@ private bool TryGetChangePinMode(ReadOnlyMemory<byte> pin, out PivPinOnlyMode mo
11501146
mode = PivPinOnlyMode.None;
11511147

11521148
var userKeyCollectorFunc = KeyCollector;
1153-
using var specialKeyCollector = new SpecialKeyCollector();
1149+
using var specialKeyCollector = new SpecialKeyCollector(DefaultManagementKeyAlgorithm);
11541150

11551151
bool isValid = TryReadObject(out AdminData adminData);
11561152

@@ -1179,17 +1175,18 @@ private bool TryGetChangePinMode(ReadOnlyMemory<byte> pin, out PivPinOnlyMode mo
11791175

11801176
_ = specialKeyCollector.DeriveKeyData(salt, ManagementKeyAlgorithm, isNewKey: false);
11811177

1178+
var managementKeyAlgorithm = DefaultManagementKeyAlgorithm;
11821179
specialKeyCollector.SetKeyData(
11831180
SpecialKeyCollector.SetKeyDataDefault, ReadOnlyMemory<byte>.Empty, isNewKey: true,
1184-
PivAlgorithm.TripleDes);
1181+
managementKeyAlgorithm);
11851182

11861183
// If this fails, then the mgmt key is not PIN-derived from the
11871184
// PIN and salt, so we'll say it is not PIN-derived.
11881185
if (!TryForcedChangeManagementKey(
11891186
specialKeyCollector.GetCurrentMgmtKey(),
11901187
specialKeyCollector.GetNewMgmtKey(),
11911188
PivTouchPolicy.Never,
1192-
PivAlgorithm.TripleDes))
1189+
managementKeyAlgorithm))
11931190
{
11941191
return true;
11951192
}
@@ -1405,13 +1402,14 @@ private sealed class SpecialKeyCollector : IDisposable
14051402
private readonly MgmtKeyHolder _currentKey;
14061403
private readonly Memory<byte> _defaultKey;
14071404
private readonly MgmtKeyHolder _newKey;
1405+
private readonly PivAlgorithm _defaultManagementKeyAlgorithm;
14081406
private readonly byte[] _pinData = new byte[MaxPinLength];
14091407
private readonly Memory<byte> _pinMemory;
14101408

14111409
private bool _disposed;
14121410
private int _pinLength;
14131411

1414-
public SpecialKeyCollector()
1412+
public SpecialKeyCollector(PivAlgorithm defaultManagemenyKeyAlgorithm)
14151413
{
14161414
_defaultKey = new Memory<byte>(
14171415
new byte[]
@@ -1425,7 +1423,8 @@ public SpecialKeyCollector()
14251423
_newKey = new MgmtKeyHolder();
14261424

14271425
// Make sure the current key is init to the default.
1428-
_currentKey.SetKeyData(_defaultKey, PivAlgorithm.TripleDes);
1426+
_defaultManagementKeyAlgorithm = defaultManagemenyKeyAlgorithm;
1427+
_currentKey.SetKeyData(_defaultKey, _defaultManagementKeyAlgorithm);
14291428

14301429
PinCollected = false;
14311430
_pinMemory = new Memory<byte>(_pinData);
@@ -1494,7 +1493,7 @@ public void SetKeyData(int setFlag, ReadOnlyMemory<byte> keyData, bool isNewKey,
14941493
return;
14951494
}
14961495

1497-
destinationKeyHolder.SetKeyData(_defaultKey, PivAlgorithm.TripleDes);
1496+
destinationKeyHolder.SetKeyData(_defaultKey, _defaultManagementKeyAlgorithm);
14981497
}
14991498

15001499
// Derive the mgmt key from the PIN in this object, along with the

0 commit comments

Comments
 (0)