22
22
23
23
namespace Yubico . YubiKey . Piv
24
24
{
25
- // All these tests will reset the PIV application, run, then reset the PIV
26
- // application again.
27
25
// All these tests will also use a random number generator with a specified
28
26
// set of bytes, followed by 2048 random bytes. If you want to get only
29
27
// random bytes, skip the first SpecifiedStart bytes (get a random object and
@@ -33,20 +31,51 @@ public class PinOnlyWithResetTests : PivSessionIntegrationTestBase
33
31
{
34
32
private const int SpecifiedStart = 72 ;
35
33
private const int RandomTrailingCount = 2048 ;
36
- readonly RandomObjectUtility replacement ;
37
- readonly private byte [ ] specifiedBytes ;
34
+ readonly RandomObjectUtility _partiallyRandomGenerator ;
35
+
36
+ private Span < byte > GetTripleDesKey_Strong_PrecomputedRandomBytes ( ) => new byte [ ]
37
+ {
38
+ 0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B ,
39
+ 0x05 , 0x01 , 0xC9 , 0x5E , 0x72 , 0xAB , 0x58 , 0x9E ,
40
+ 0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B ,
41
+ } ;
42
+
43
+ private Span < byte > GetTripleDesKey_Weak_PrecomputedRandomBytes ( ) => new byte [ ]
44
+ {
45
+ 0x05 , 0x01 , 0xC9 , 0x5E , 0x72 , 0xAB , 0x58 , 0x9E ,
46
+ 0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B ,
47
+ 0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B
48
+ } ;
49
+
50
+ // 3DES key that is derived using a PIN of "123456" and a salt of the first 16 bytes.
51
+ private Span < byte > Get_DerivedKey_PrecomputedRandomBytes ( ) => new byte [ ]
52
+ {
53
+ 0xc9 , 0xf4 , 0x20 , 0x5a , 0x29 , 0x38 , 0x1b , 0xb8 ,
54
+ 0x60 , 0x6b , 0xd4 , 0xde , 0x18 , 0xef , 0xf4 , 0x3d ,
55
+ 0x43 , 0x24 , 0x87 , 0x3e , 0x5e , 0xd2 , 0xc1 , 0xed
56
+ } ;
57
+
58
+ // Same as the weak 3DES key, but since it's AES it is allowed and not considered weak
59
+ private Span < byte > GetAesKey_PrecomputedRandomBytes ( ) => new byte [ ]
60
+ {
61
+ 0x05 , 0x01 , 0xC9 , 0x5E , 0x72 , 0xAB , 0x58 , 0x9E ,
62
+ 0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B ,
63
+ 0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B
64
+ } ;
65
+
66
+ private Span < byte > GetSalt_PrecomputedRandomBytes ( ) => new byte [ ]
67
+ {
68
+ 0x05 , 0x01 , 0xC9 , 0x5E , 0x72 , 0xAB , 0x58 , 0x9E ,
69
+ 0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B
70
+ } ;
38
71
39
72
public PinOnlyWithResetTests ( )
40
73
{
74
+ // The data in this array correspond to the getter fields above (Span<byte> Get_XXX_PrecomputedRandomBytes).
41
75
// This buffer will hold the random bytes to return.
42
- // The first 24 will be a weak 3DES key
43
- // The first 16 can also be a salt.
44
- // The second 24 will be a non-weak 3DES key.
45
- // The third 24 bytes is the 3DES key that is derived using a PIN of
46
- // "123456" and a salt of the first 16 bytes.
47
76
// Then there will be 2048 random bytes.
48
- specifiedBytes =
49
- [
77
+ byte [ ] predefinedPrefixedBytes =
78
+ [
50
79
0x05 , 0x01 , 0xC9 , 0x5E , 0x72 , 0xAB , 0x58 , 0x9E ,
51
80
0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B ,
52
81
0x6D , 0x82 , 0x95 , 0xA3 , 0x74 , 0xB7 , 0x69 , 0x2B ,
@@ -59,11 +88,12 @@ public PinOnlyWithResetTests()
59
88
] ;
60
89
61
90
var randomBytes = new byte [ SpecifiedStart + RandomTrailingCount ] ;
62
- using var random = RandomObjectUtility . GetRandomObject ( null ) ;
91
+ using var random = RandomNumberGenerator . Create ( ) ;
63
92
random . GetBytes ( randomBytes ) ;
64
93
65
- Array . Copy ( specifiedBytes , 0 , randomBytes , 0 , specifiedBytes . Length ) ;
66
- replacement = RandomObjectUtility . SetRandomProviderFixedBytes ( randomBytes ) ;
94
+ // Set the first 72 bytes with the predefined prefixed bytes so that we can anticipate the values in the tests.
95
+ predefinedPrefixedBytes . CopyTo ( randomBytes . AsSpan ( ) ) ;
96
+ _partiallyRandomGenerator = RandomObjectUtility . SetRandomProviderFixedBytes ( randomBytes ) ;
67
97
}
68
98
69
99
[ Fact ]
@@ -120,7 +150,7 @@ public void Run_SetPinDerived_UsesSalt()
120
150
var adminData = Session . ReadObject < AdminData > ( ) ;
121
151
Assert . NotNull ( adminData . Salt ) ;
122
152
123
- var expected = GetSpecifiedSpan ( 0 , 16 ) ;
153
+ var expected = GetSalt_PrecomputedRandomBytes ( ) ;
124
154
var result = ( ReadOnlyMemory < byte > ) adminData . Salt ;
125
155
var isValid = expected . SequenceEqual ( result . Span ) ;
126
156
Assert . True ( isValid ) ;
@@ -196,34 +226,36 @@ public void SetProtectThenDerive_GetMode_ReturnsCorrect()
196
226
[ Fact ]
197
227
public void SetProtectThenDerive_CorrectMgmtKey ( )
198
228
{
199
- var expected1 = GetSpecifiedSpan ( 24 , 24 ) ;
200
- var expected2 = GetSpecifiedSpan ( 48 , 24 ) ;
229
+ var expectedManagementKey = DefaultManagementKeyType == KeyType . AES192
230
+ ? GetAesKey_PrecomputedRandomBytes ( )
231
+ : GetTripleDesKey_Strong_PrecomputedRandomBytes ( ) ;
232
+
233
+ var expectedRandomDerivedKey = Get_DerivedKey_PrecomputedRandomBytes ( ) ;
201
234
using ( var pivSession = GetSession ( ) )
202
235
{
203
236
// Act
204
237
pivSession . SetPinOnlyMode ( PivPinOnlyMode . PinProtected ) ;
205
238
239
+ // Assert
206
240
var pinProtect = pivSession . ReadObject < PinProtectedData > ( ) ;
207
- Assert . False ( pinProtect . IsEmpty ) ;
208
241
Assert . NotNull ( pinProtect . ManagementKey ) ;
209
- var result = ( ReadOnlyMemory < byte > ) pinProtect . ManagementKey ;
210
- var isValid = expected1 . SequenceEqual ( result . Span ) ;
242
+ var isValid = expectedManagementKey . SequenceEqual ( pinProtect . ManagementKey . Value . Span ) ;
211
243
Assert . True ( isValid ) ;
212
244
}
213
245
214
246
using ( var pivSession = GetSession ( ) )
215
247
{
216
248
// Act
217
- pivSession . SetPinOnlyMode ( PivPinOnlyMode . PinDerived ) ;
218
-
249
+ pivSession . SetPinOnlyMode ( PivPinOnlyMode
250
+ . PinDerived ) ;
219
251
var mode = pivSession . GetPinOnlyMode ( ) ;
220
252
Assert . Equal ( PivPinOnlyMode . PinProtected | PivPinOnlyMode . PinDerived , mode ) ;
221
253
222
254
var pinProtect = pivSession . ReadObject < PinProtectedData > ( ) ;
223
255
Assert . False ( pinProtect . IsEmpty ) ;
224
256
Assert . NotNull ( pinProtect . ManagementKey ) ;
225
- var result = ( ReadOnlyMemory < byte > ) pinProtect . ManagementKey ;
226
- var isValid = expected2 . SequenceEqual ( result . Span ) ;
257
+ var result = pinProtect . ManagementKey ;
258
+ var isValid = expectedRandomDerivedKey . SequenceEqual ( result . Value ! . Span ) ;
227
259
Assert . True ( isValid ) ;
228
260
}
229
261
}
@@ -232,7 +264,9 @@ public void SetProtectThenDerive_CorrectMgmtKey()
232
264
public void SetProtect_ThenNone_CorrectMode ( )
233
265
{
234
266
// Arrange
235
- var mgmtKey = GetSpecifiedSpan ( 24 , 24 ) ;
267
+ var expectedManagementKey = DefaultManagementKeyType == KeyType . AES192
268
+ ? GetAesKey_PrecomputedRandomBytes ( )
269
+ : GetTripleDesKey_Strong_PrecomputedRandomBytes ( ) ;
236
270
using ( var pivSession = GetSession ( ) )
237
271
{
238
272
// Act
@@ -242,8 +276,8 @@ public void SetProtect_ThenNone_CorrectMode()
242
276
var pinProtect = pivSession . ReadObject < PinProtectedData > ( ) ;
243
277
Assert . False ( pinProtect . IsEmpty ) ;
244
278
Assert . NotNull ( pinProtect . ManagementKey ) ;
245
- // var isValid = mgmtKey .SequenceEqual(pinProtect.ManagementKey.Value.Span);
246
- // Assert.True(isValid);
279
+ var isValid = expectedManagementKey . SequenceEqual ( pinProtect . ManagementKey . Value . Span ) ;
280
+ Assert . True ( isValid ) ;
247
281
}
248
282
249
283
var isBlocked = IsPukBlocked ( ) ;
@@ -273,7 +307,7 @@ public void SetProtect_ThenNone_CorrectMode()
273
307
var specifiedCollector = new SpecifiedKeyCollector (
274
308
DefaultPin ,
275
309
DefaultPuk ,
276
- mgmtKey . ToArray ( ) ) ;
310
+ expectedManagementKey . ToArray ( ) ) ;
277
311
pivSession . KeyCollector = specifiedCollector . SpecifiedKeyCollectorDelegate ;
278
312
279
313
var mode = pivSession . GetPinOnlyMode ( ) ;
@@ -541,11 +575,6 @@ public void SetPinOnly_ThenNone_Success(
541
575
}
542
576
}
543
577
544
- private Span < byte > GetSpecifiedSpan (
545
- int offset ,
546
- int length ) =>
547
- specifiedBytes . AsSpan ( offset , length ) ;
548
-
549
578
// If the PUK is blocked, return true.
550
579
// If the PUK is not blocked, return false.
551
580
// If there is any other error, throw an exception.
@@ -576,7 +605,7 @@ protected override void Dispose(
576
605
{
577
606
if ( disposing )
578
607
{
579
- replacement . RestoreRandomProvider ( ) ;
608
+ _partiallyRandomGenerator . RestoreRandomProvider ( ) ;
580
609
}
581
610
582
611
base . Dispose ( disposing ) ;
0 commit comments