|
36 | 36 | #import "YKFFIDO2ResetAPDU.h"
|
37 | 37 |
|
38 | 38 | #import "YKFFIDO2GetInfoResponse+Private.h"
|
| 39 | +#import "YKFFIDO2MakeCredentialResponse.h" |
39 | 40 | #import "YKFFIDO2MakeCredentialResponse+Private.h"
|
40 | 41 | #import "YKFFIDO2GetAssertionResponse+Private.h"
|
41 | 42 |
|
@@ -335,33 +336,88 @@ - (void)makeCredentialWithClientDataHash:(NSData *)clientDataHash
|
335 | 336 | NSData *hmac = [clientDataHash ykf_fido2HMACWithKey:self.pinToken];
|
336 | 337 | pinAuth = [hmac subdataWithRange:NSMakeRange(0, 16)];
|
337 | 338 | if (!pinAuth) {
|
338 |
| - completion(nil, [YKFFIDO2Error errorWithCode:YKFFIDO2ErrorCodeOTHER]); |
| 339 | + completion(nil, nil, [YKFFIDO2Error errorWithCode:YKFFIDO2ErrorCodeOTHER]); |
339 | 340 | }
|
340 | 341 | }
|
341 | 342 |
|
342 |
| - YKFAPDU *apdu = [[YKFFIDO2MakeCredentialAPDU alloc] initWithClientDataHash:clientDataHash rp:rp user:user pubKeyCredParams:pubKeyCredParams excludeList:excludeList pinAuth:pinAuth pinProtocol:pinProtocol options:options extensions:extensions]; |
| 343 | + |
| 344 | + // Extensions, client authentictor input |
| 345 | + NSMutableDictionary *authenticatorInputs = [NSMutableDictionary new]; |
| 346 | + // Sign |
| 347 | + if (extensions && extensions[@"sign"] && extensions[@"sign"][@"generateKey"]) { |
| 348 | + NSDictionary *generateKeyDict = (NSDictionary *) extensions[@"sign"][@"generateKey"]; |
| 349 | + NSMutableDictionary *signExtensionDict = [NSMutableDictionary new]; |
| 350 | + // Flags hard coded for now. More information here: |
| 351 | + // https://github.com/Yubico/python-fido2/blob/8722a8925509d3320f8cb6d8a22c76e2af08fb20/fido2/ctap2/extensions.py#L493 |
| 352 | + int flags = 0b101; |
| 353 | + |
| 354 | + NSMutableArray *algorithms = [NSMutableArray array]; |
| 355 | + [(NSArray *)generateKeyDict[@"algorithms"] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { |
| 356 | + NSInteger intValue = [(NSNumber *)obj integerValue]; |
| 357 | + [algorithms addObject:YKFCBORInteger(intValue)]; |
| 358 | + }]; |
| 359 | + signExtensionDict[YKFCBORInteger(3)] = YKFCBORArray(algorithms); |
| 360 | + signExtensionDict[YKFCBORInteger(4)] = YKFCBORInteger(flags); |
| 361 | + |
| 362 | + if (generateKeyDict[@"phData"]) { |
| 363 | + NSString * phData = generateKeyDict[@"phData"]; |
| 364 | + NSData *phDataBase64Encoded = [[NSData alloc] initWithBase64EncodedString:phData options:0]; |
| 365 | + signExtensionDict[YKFCBORInteger(0)] = YKFCBORByteString(phDataBase64Encoded); |
| 366 | + } |
| 367 | + authenticatorInputs[YKFCBORTextString(@"sign")] = YKFCBORMap(signExtensionDict); |
| 368 | + } |
| 369 | + |
| 370 | + // Extensions large blob |
| 371 | + if (extensions && extensions[@"largeBlobKey"] && [extensions[@"largeBlobKey"][@"support"] isEqual: @"required"]) { |
| 372 | + authenticatorInputs[YKFCBORTextString(@"largeBlobKey")] = YKFCBORBool(true); |
| 373 | + } |
| 374 | + |
| 375 | + // Extensions hmac-secret |
| 376 | + if (extensions && extensions[@"prf"]) { |
| 377 | + authenticatorInputs[YKFCBORTextString(@"hmac-secret")] = YKFCBORBool(true); |
| 378 | + } |
| 379 | + |
| 380 | + YKFAPDU *apdu = [[YKFFIDO2MakeCredentialAPDU alloc] initWithClientDataHash:clientDataHash rp:rp user:user pubKeyCredParams:pubKeyCredParams excludeList:excludeList pinAuth:pinAuth pinProtocol:pinProtocol options:options extensions:authenticatorInputs]; |
343 | 381 |
|
344 | 382 | if (!apdu) {
|
345 | 383 | YKFSessionError *error = [YKFFIDO2Error errorWithCode:YKFFIDO2ErrorCodeOTHER];
|
346 |
| - completion(nil, error); |
| 384 | + completion(nil, nil, error); |
347 | 385 | return;
|
348 | 386 | }
|
349 | 387 |
|
350 | 388 | ykf_weak_self();
|
351 | 389 | [self executeFIDO2Command:apdu retryCount:0 completion:^(NSData *data, NSError *error) {
|
352 | 390 | ykf_safe_strong_self();
|
353 | 391 | if (error) {
|
354 |
| - completion(nil, error); |
| 392 | + completion(nil, nil, error); |
355 | 393 | return;
|
356 | 394 | }
|
357 | 395 |
|
358 | 396 | NSData *cborData = [strongSelf cborFromKeyResponseData:data];
|
359 | 397 | YKFFIDO2MakeCredentialResponse *makeCredentialResponse = [[YKFFIDO2MakeCredentialResponse alloc] initWithCBORData:cborData];
|
360 | 398 |
|
| 399 | + // Extensions, authenticator output |
| 400 | + NSMutableDictionary *extensionsClientOutput = [NSMutableDictionary new]; |
| 401 | + if (authenticatorInputs[YKFCBORTextString(@"hmac-secret")]) { |
| 402 | + YKFCBORBool *cborBool = makeCredentialResponse.authenticatorData.extensions.value[YKFCBORTextString(@"hmac-secret")]; |
| 403 | + if (cborBool && cborBool.value) { |
| 404 | + extensionsClientOutput[@"prf"] = @{@"enabled" : @YES}; |
| 405 | + } else { |
| 406 | + extensionsClientOutput[@"prf"] = @{@"enabled" : @NO}; |
| 407 | + } |
| 408 | +// |
| 409 | +// NSError *error; |
| 410 | +// NSData *jsonData = [NSJSONSerialization dataWithJSONObject:extensionsClientOutput |
| 411 | +// options:NSJSONWritingPrettyPrinted |
| 412 | +// error:&error]; |
| 413 | +// NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; |
| 414 | +// NSLog(@"%@", jsonString); |
| 415 | + } |
| 416 | + |
361 | 417 | if (makeCredentialResponse) {
|
362 |
| - completion(makeCredentialResponse, nil); |
| 418 | + completion(makeCredentialResponse, extensionsClientOutput, nil); |
363 | 419 | } else {
|
364 |
| - completion(nil, [YKFFIDO2Error errorWithCode:YKFFIDO2ErrorCodeINVALID_CBOR]); |
| 420 | + completion(nil, nil, [YKFFIDO2Error errorWithCode:YKFFIDO2ErrorCodeINVALID_CBOR]); |
365 | 421 | }
|
366 | 422 | }];
|
367 | 423 | }
|
|
0 commit comments