58
58
NSString * const YKFFIDO2OptionUV = @" uv" ;
59
59
NSString * const YKFFIDO2OptionUP = @" up" ;
60
60
61
+ @interface NSData (NSData_PinProtocols)
62
+
63
+ - (NSData *)ykf_authenticateDataWithKey : (NSData *)data pinProtocol : (YKFFIDOPinProtocol)pinProtocol ;
64
+ - (NSData *)ykf_encryptDataWithKey : (NSData *)data pinProtocol : (YKFFIDOPinProtocol)pinProtocol ;
65
+ - (NSData *)ykf_decryptDataWithKey : (NSData *)data pinProtocol : (YKFFIDOPinProtocol)pinProtocol ;
66
+
67
+ @end
68
+
61
69
#pragma mark - Private Response Blocks
62
70
63
71
typedef void (^YKFFIDO2SessionResultCompletionBlock)
@@ -80,6 +88,8 @@ @interface YKFFIDO2Session()
80
88
// Keeps the state of the application selection to avoid reselecting the application.
81
89
@property BOOL applicationSelected;
82
90
91
+ @property (nonatomic , readwrite ) YKFFIDOPinProtocol pinProtocol;
92
+
83
93
@end
84
94
85
95
@implementation YKFFIDO2Session
@@ -97,8 +107,18 @@ + (void)sessionWithConnectionController:(nonnull id<YKFConnectionControllerProto
97
107
if (error) {
98
108
completion (nil , error);
99
109
} else {
100
- [session updateKeyState: YKFFIDO2SessionKeyStateIdle];
101
- completion (session, nil );
110
+ [session getInfoWithCompletion: ^(YKFFIDO2GetInfoResponse * _Nullable response, NSError * _Nullable error) {
111
+ if ([response.pinProtocols containsObject: @2 ]) {
112
+ session.pinProtocol = YKFFIDOPinProtocolV2;
113
+ } else if ([response.pinProtocols containsObject: @1 ]) {
114
+ session.pinProtocol = YKFFIDOPinProtocolV1;
115
+ } else {
116
+ completion (nil , [YKFFIDO2Error errorWithCode: YKFFIDO2ErrorCodeOTHER]);
117
+ return ;
118
+ }
119
+ completion (session, nil );
120
+ [session updateKeyState: YKFFIDO2SessionKeyStateIdle];
121
+ }];
102
122
}
103
123
}];
104
124
}
@@ -189,13 +209,13 @@ - (void)verifyPin:(NSString *)pin completion:(YKFFIDO2SessionGenericCompletionBl
189
209
190
210
// Get the authenticator pinToken
191
211
YKFFIDO2ClientPinRequest *clientPinGetPinTokenRequest = [[YKFFIDO2ClientPinRequest alloc ] init ];
192
- clientPinGetPinTokenRequest.pinProtocol = 1 ;
212
+ clientPinGetPinTokenRequest.pinProtocol = self. pinProtocol ;
193
213
clientPinGetPinTokenRequest.subCommand = YKFFIDO2ClientPinRequestSubCommandGetPINToken;
194
214
clientPinGetPinTokenRequest.keyAgreement = cosePlatformPublicKey;
195
215
196
216
NSData *pinData = [pin dataUsingEncoding: NSUTF8StringEncoding];
197
217
NSData *pinHash = [[pinData ykf_SHA256 ] subdataWithRange: NSMakeRange (0 , 16 )];
198
- clientPinGetPinTokenRequest.pinHashEnc = [pinHash ykf_aes256EncryptedDataWithKey : sharedSecret];
218
+ clientPinGetPinTokenRequest.pinHashEnc = [pinHash ykf_encryptDataWithKey : sharedSecret pinProtocol: self .pinProtocol ];
199
219
200
220
[strongSelf executeClientPinRequest: clientPinGetPinTokenRequest completion: ^(YKFFIDO2ClientPinResponse *response, NSError *error) {
201
221
if (error) {
@@ -209,7 +229,7 @@ - (void)verifyPin:(NSString *)pin completion:(YKFFIDO2SessionGenericCompletionBl
209
229
}
210
230
211
231
// Cache the pinToken
212
- strongSelf.pinToken = [response.pinToken ykf_aes256DecryptedDataWithKey : sharedSecret];
232
+ strongSelf.pinToken = [encryptedPinToken ykf_decryptDataWithKey : sharedSecret pinProtocol: self .pinProtocol ];
213
233
214
234
if (!strongSelf.pinToken ) {
215
235
completion ([YKFFIDO2Error errorWithCode: YKFFIDO2ErrorCodeINVALID_CBOR]);
@@ -299,13 +319,12 @@ - (void)setPin:(nonnull NSString *)pin completion:(nonnull YKFFIDO2SessionGeneri
299
319
300
320
// Set the new PIN
301
321
YKFFIDO2ClientPinRequest *setPinRequest = [[YKFFIDO2ClientPinRequest alloc ] init ];
302
- setPinRequest.pinProtocol = 1 ;
322
+ setPinRequest.pinProtocol = self. pinProtocol ;
303
323
setPinRequest.subCommand = YKFFIDO2ClientPinRequestSubCommandSetPIN;
304
324
setPinRequest.keyAgreement = cosePlatformPublicKey;
305
325
306
-
307
- setPinRequest.pinEnc = [pinData ykf_aes256EncryptedDataWithKey: sharedSecret];
308
- setPinRequest.pinAuth = [[setPinRequest.pinEnc ykf_fido2HMACWithKey: sharedSecret] subdataWithRange: NSMakeRange (0 , 16 )];
326
+ setPinRequest.pinEnc = [pinData ykf_encryptDataWithKey: sharedSecret pinProtocol: self .pinProtocol];
327
+ setPinRequest.pinAuth = [setPinRequest.pinEnc ykf_authenticateDataWithKey: sharedSecret pinProtocol: self .pinProtocol];
309
328
310
329
[strongSelf executeClientPinRequest: setPinRequest completion: ^(YKFFIDO2ClientPinResponse *response, NSError *error) {
311
330
if (error) {
@@ -351,9 +370,8 @@ - (void)makeCredentialWithClientDataHash:(NSData *)clientDataHash
351
370
NSUInteger pinProtocol = 0 ;
352
371
if (self.pinToken ) {
353
372
YKFParameterAssertReturn (clientDataHash);
354
- pinProtocol = 1 ;
355
- NSData *hmac = [clientDataHash ykf_fido2HMACWithKey: self .pinToken];
356
- pinAuth = [hmac subdataWithRange: NSMakeRange (0 , 16 )];
373
+ pinProtocol = self.pinProtocol ;
374
+ pinAuth = [clientDataHash ykf_authenticateDataWithKey: self .pinToken pinProtocol: self .pinProtocol];
357
375
if (!pinAuth) {
358
376
completion (nil , [YKFFIDO2Error errorWithCode: YKFFIDO2ErrorCodeOTHER]);
359
377
}
@@ -400,9 +418,8 @@ - (void)getAssertionWithClientDataHash:(NSData *)clientDataHash
400
418
NSUInteger pinProtocol = 0 ;
401
419
if (self.pinToken ) {
402
420
YKFParameterAssertReturn (clientDataHash);
403
- pinProtocol = 1 ;
404
- NSData *hmac = [clientDataHash ykf_fido2HMACWithKey: self .pinToken];
405
- pinAuth = [hmac subdataWithRange: NSMakeRange (0 , 16 )];
421
+ pinProtocol = self.pinProtocol ;
422
+ pinAuth = [clientDataHash ykf_authenticateDataWithKey: self .pinToken pinProtocol: self .pinProtocol];
406
423
if (!pinAuth) {
407
424
completion (nil , [YKFFIDO2Error errorWithCode: YKFFIDO2ErrorCodeOTHER]);
408
425
}
@@ -537,7 +554,7 @@ - (void)executeGetSharedSecretWithCompletion:(YKFFIDO2SessionClientPinSharedSecr
537
554
538
555
// Get the authenticator public key.
539
556
YKFFIDO2ClientPinRequest *clientPinKeyAgreementRequest = [[YKFFIDO2ClientPinRequest alloc ] init ];
540
- clientPinKeyAgreementRequest.pinProtocol = 1 ;
557
+ clientPinKeyAgreementRequest.pinProtocol = self. pinProtocol ;
541
558
clientPinKeyAgreementRequest.subCommand = YKFFIDO2ClientPinRequestSubCommandGetKeyAgreement;
542
559
clientPinKeyAgreementRequest.keyAgreement = cosePlatformPublicKey;
543
560
@@ -563,7 +580,20 @@ - (void)executeGetSharedSecretWithCompletion:(YKFFIDO2SessionClientPinSharedSecr
563
580
completion (nil , nil , [YKFFIDO2Error errorWithCode: YKFFIDO2ErrorCodeOTHER]);
564
581
return ;
565
582
}
566
- sharedSecret = [sharedSecret ykf_SHA256 ];
583
+
584
+ switch (_pinProtocol) {
585
+ case YKFFIDOPinProtocolV1:
586
+ sharedSecret = [sharedSecret ykf_SHA256 ];
587
+ break ;
588
+ case YKFFIDOPinProtocolV2: {
589
+ NSData *hmacKey = [sharedSecret ykf_deriveHKDFWithSalt: [NSMutableData dataWithLength: 32 ] info: [@" CTAP2 HMAC key" dataUsingEncoding: NSUTF8StringEncoding]];
590
+ NSData *aesKey = [sharedSecret ykf_deriveHKDFWithSalt: [NSMutableData dataWithLength: 32 ] info: [@" CTAP2 AES key" dataUsingEncoding: NSUTF8StringEncoding]];
591
+ NSMutableData *result = [hmacKey mutableCopy ];
592
+ [result appendData: aesKey];
593
+ sharedSecret = result;
594
+ break ;
595
+ }
596
+ }
567
597
568
598
// Success
569
599
completion (sharedSecret, cosePlatformPublicKey, nil );
@@ -641,3 +671,50 @@ - (void)handleTouchRequired:(YKFAPDU *)apdu retryCount:(int)retryCount completi
641
671
}
642
672
643
673
@end
674
+
675
+
676
+ #pragma mark - INT conversion
677
+
678
+ @implementation NSData (NSData_PinProtocols)
679
+
680
+ - (NSData *)ykf_authenticateDataWithKey : (NSData *)key pinProtocol : (YKFFIDOPinProtocol)pinProtocol {
681
+ switch (pinProtocol) {
682
+ case YKFFIDOPinProtocolV1:
683
+ return [[self ykf_fido2HMACWithKey: key] subdataWithRange: NSMakeRange (0 , 16 )];
684
+ case YKFFIDOPinProtocolV2:
685
+ return [self ykf_fido2HMACWithKey: [key subdataWithRange: NSMakeRange (0 , 32 )]];
686
+ }
687
+ return [NSData new ];
688
+ }
689
+
690
+ - (NSData *)ykf_encryptDataWithKey : (NSData *)key pinProtocol : (YKFFIDOPinProtocol)pinProtocol {
691
+ switch (pinProtocol) {
692
+ case YKFFIDOPinProtocolV1:
693
+ return [self ykf_aes256Operation: kCCEncrypt withKey: key];
694
+ case YKFFIDOPinProtocolV2: {
695
+ NSData *aesKey = [key subdataWithRange: NSMakeRange (32 , key.length-32 )];
696
+ NSData *iv = [NSData ykf_randomDataOfSize: 16 ];
697
+ NSData *cipher = [self ykf_cryptOperation: kCCEncrypt algorithm: kCCAlgorithmAES mode: kCCModeCBC key: aesKey iv: iv];
698
+ NSMutableData *result = [iv mutableCopy ];
699
+ [result appendData: cipher];
700
+ return result;
701
+ }
702
+ }
703
+ return [NSData new ];
704
+ }
705
+
706
+ - (NSData *)ykf_decryptDataWithKey : (NSData *)key pinProtocol : (YKFFIDOPinProtocol)pinProtocol {
707
+ switch (pinProtocol) {
708
+ case YKFFIDOPinProtocolV1:
709
+ return [self ykf_aes256Operation: kCCDecrypt withKey: key];
710
+ case YKFFIDOPinProtocolV2: {
711
+ NSData *aesKey = [key subdataWithRange: NSMakeRange (32 , key.length-32 )];
712
+ NSData *iv = [self subdataWithRange: NSMakeRange (0 , 16 )];
713
+ NSData *cipher = [self subdataWithRange: NSMakeRange (16 , self .length-16 )];
714
+ return [cipher ykf_cryptOperation: kCCDecrypt algorithm: kCCAlgorithmAES mode: kCCModeCBC key: aesKey iv: iv];
715
+ }
716
+ }
717
+ return [NSData new ];
718
+ }
719
+
720
+ @end
0 commit comments