2 * Copyright (c) 2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "TokenLogin.h"
26 #include <Security/SecItem.h>
27 #include <Security/SecItemPriv.h>
28 #include <Security/SecKeyPriv.h>
29 #include "SecBase64P.h"
30 #include <Security/SecIdentity.h>
31 #include <Security/SecCertificatePriv.h>
32 #include <Security/SecKeychainPriv.h>
33 #include <security_utilities/cfutilities.h>
35 #include <libaks_smartcard.h>
38 #include <ctkclient.h>
39 #include <coreauthd_spi.h>
42 #define kSecTokenLoginDomain CFSTR("com.apple.security.tokenlogin")
44 static CFStringRef
cfDataToHex(CFDataRef bin
)
46 size_t len
= CFDataGetLength(bin
) * 2;
47 CFMutableStringRef str
= CFStringCreateMutable(NULL
, len
);
49 static const char* digits
[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
51 const uint8_t* data
= CFDataGetBytePtr(bin
);
52 for (size_t i
= 0; i
< CFDataGetLength(bin
); i
++) {
53 CFStringAppendCString(str
, digits
[data
[i
] >> 4], 1);
54 CFStringAppendCString(str
, digits
[data
[i
] & 0xf], 1);
59 static CFStringRef
getPin(CFDictionaryRef context
)
65 CFStringRef pin
= (CFStringRef
)CFDictionaryGetValue(context
, kSecAttrService
);
66 if (!pin
|| CFGetTypeID(pin
) != CFStringGetTypeID()) {
72 static CFStringRef
getTokenId(CFDictionaryRef context
)
78 CFStringRef tokenId
= (CFStringRef
)CFDictionaryGetValue(context
, kSecAttrTokenID
);
79 if (!tokenId
|| CFGetTypeID(tokenId
) != CFStringGetTypeID()) {
80 secinfo("TokenLogin", "Invalid tokenId");
86 static CFDataRef
getPubKeyHash(CFDictionaryRef context
)
92 CFDataRef pubKeyHash
= (CFDataRef
)CFDictionaryGetValue(context
, kSecAttrPublicKeyHash
);
93 if (!pubKeyHash
|| CFGetTypeID(pubKeyHash
) != CFDataGetTypeID()) {
94 secinfo("TokenLogin", "Invalid pubkeyhash");
100 static CFDataRef
getPubKeyHashWrap(CFDictionaryRef context
)
106 CFDataRef pubKeyHashWrap
= (CFDataRef
)CFDictionaryGetValue(context
, kSecAttrAccount
);
107 if (!pubKeyHashWrap
|| CFGetTypeID(pubKeyHashWrap
) != CFDataGetTypeID()) {
108 secinfo("TokenLogin", "Invalid pubkeyhashwrap");
111 return pubKeyHashWrap
;
114 static OSStatus
privKeyForPubKeyHash(CFDictionaryRef context
, SecKeyRef
*privKey
, CFTypeRef
*laCtx
)
120 CFRef
<CFMutableDictionaryRef
> tokenAttributes
= makeCFMutableDictionary(1, kSecAttrTokenID
, getTokenId(context
));
121 CFRef
<CFErrorRef
> error
;
123 CFStringRef pin
= getPin(context
);
125 CFRef
<CFDictionaryRef
> LAParams
= makeCFDictionary(1, CFSTR("useDaemon"), kCFBooleanFalse
);
126 CFRef
<CFTypeRef
> LAContext
= LACreateNewContextWithACMContext(LAParams
.as
<CFDataRef
>(), error
.take());
128 secinfo("TokenLogin", "Failed to LA Context: %@", error
.get());
132 *laCtx
= (CFTypeRef
)CFRetain(LAContext
);
133 CFRef
<CFDataRef
> externalizedContext
= LACopyACMContext(LAContext
, error
.take());
134 if (!externalizedContext
) {
135 secinfo("TokenLogin", "Failed to get externalized context: %@", error
.get());
138 CFDictionarySetValue(tokenAttributes
, kSecUseCredentialReference
, externalizedContext
.get());
139 CFDictionarySetValue(tokenAttributes
, CFSTR("PIN"), pin
);
142 CFRef
<TKTokenRef
> token
= TKTokenCreate(tokenAttributes
, error
.take());
144 secinfo("TokenLogin", "Failed to create token: %@", error
.get());
148 CFRef
<CFArrayRef
> identities
= TKTokenCopyIdentities(token
, TKTokenKeyUsageAny
, error
.take());
149 if (!identities
|| !CFArrayGetCount(identities
)) {
150 secinfo("TokenLogin", "No identities found for token: %@", error
.get());
154 CFDataRef desiredHash
= getPubKeyHashWrap(context
);
155 CFIndex idx
, count
= CFArrayGetCount(identities
);
156 for (idx
= 0; idx
< count
; ++idx
) {
157 SecIdentityRef identity
= (SecIdentityRef
)CFArrayGetValueAtIndex(identities
, idx
);
158 CFRef
<SecCertificateRef
> certificate
;
159 OSStatus result
= SecIdentityCopyCertificate(identity
, certificate
.take());
160 if (result
!= errSecSuccess
) {
161 secinfo("TokenLogin", "Failed to get certificate for identity: %d", (int) result
);
165 CFRef
<CFDataRef
> identityHash
= SecCertificateCopyPublicKeySHA1Digest(certificate
);
166 if (identityHash
&& CFEqual(desiredHash
, identityHash
)) {
167 result
= SecIdentityCopyPrivateKey(identity
, privKey
);
168 if (result
!= errSecSuccess
) {
169 secinfo("TokenLogin", "Failed to get identity private key: %d", (int) result
);
178 OSStatus
TokenLoginGetContext(const void *base64TokenLoginData
, UInt32 base64TokenLoginDataLength
, CFDictionaryRef
*context
)
180 if (!base64TokenLoginData
|| !context
) {
184 // Token data are base64 encoded in password.
185 size_t dataLen
= SecBase64Decode((const char *)base64TokenLoginData
, base64TokenLoginDataLength
, NULL
, 0);
187 secinfo("TokenLogin", "Invalid base64 encoded token data");
191 CFRef
<CFMutableDataRef
> data
= CFDataCreateMutable(kCFAllocatorDefault
, dataLen
);
192 dataLen
= SecBase64Decode((const char *)base64TokenLoginData
, base64TokenLoginDataLength
, CFDataGetMutableBytePtr(data
), dataLen
);
194 secinfo("TokenLogin", "Invalid base64 encoded token data");
197 CFDataSetLength(data
, dataLen
);
199 // Content of the password consists of a serialized dictionary containing token ID, PIN, wrap key hash etc.
200 CFRef
<CFErrorRef
> error
;
201 *context
= (CFDictionaryRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
203 kCFPropertyListImmutable
,
206 if (!*context
|| CFGetTypeID(*context
) != CFDictionaryGetTypeID()) {
207 secinfo("TokenLogin", "Invalid token login data property list, %@", error
.get());
211 if (!getPin(*context
) || !getTokenId(*context
) || !getPubKeyHash(*context
) || !getPubKeyHashWrap(*context
)) {
212 secinfo("TokenLogin", "Invalid token login data context, %@", error
.get());
216 return errSecSuccess
;
219 OSStatus
TokenLoginGetUnlockKey(CFDictionaryRef context
, CFDataRef
*unlockKey
)
221 if (!context
|| !unlockKey
) {
225 CFRef
<CFDictionaryRef
> loginData
;
226 OSStatus result
= TokenLoginGetLoginData(context
, loginData
.take());
227 if (result
!= errSecSuccess
) {
228 secinfo("TokenLogin", "Failed to get login data: %d", (int)result
);
232 CFDataRef wrappedUnlockKey
= (CFDataRef
)CFDictionaryGetValue(loginData
, kSecValueData
);
233 if (!wrappedUnlockKey
) {
234 secinfo("TokenLogin", "Wrapped unlock key not found in unlock key data");
237 SecKeyAlgorithm algorithm
= (SecKeyAlgorithm
)CFDictionaryGetValue(loginData
, kSecAttrService
);
239 secinfo("TokenLogin", "Algorithm not found in unlock key data");
243 CFRef
<SecKeyRef
> privKey
;
244 CFRef
<CFTypeRef
> LAContext
;
245 result
= privKeyForPubKeyHash(context
, privKey
.take(), LAContext
.take());
246 if (result
!= errSecSuccess
) {
247 secinfo("TokenLogin", "Failed to get private key for public key hash: %d", (int)result
);
251 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
253 secinfo("TokenLogin", "Failed to get public key from private key");
256 CFRef
<CFErrorRef
> error
;
257 *unlockKey
= SecKeyCreateDecryptedData(privKey
,
262 secinfo("TokenLogin", "Failed to unwrap unlock key: %@", error
.get());
266 // we need to re-wrap already unwrapped data to avoid capturing and reusing communication with the smartcard
267 CFRef
<CFDataRef
> reWrappedUnlockKey
= SecKeyCreateEncryptedData(pubKey
, algorithm
, *unlockKey
, error
.take());
268 if (!reWrappedUnlockKey
) {
269 secinfo("TokenLogin", "Failed to rewrap unlock key: %@", error
.get());
270 TokenLoginDeleteUnlockData(getPubKeyHash(context
));
274 CFRef
<CFMutableDictionaryRef
> newDict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 4, loginData
);
276 CFDictionarySetValue(newDict
, kSecValueData
, reWrappedUnlockKey
);
277 TokenLoginStoreUnlockData(context
, newDict
);
280 return errSecSuccess
;
283 OSStatus
TokenLoginGetLoginData(CFDictionaryRef context
, CFDictionaryRef
*loginData
)
285 if (!loginData
|| !context
) {
289 CFRef
<CFStringRef
> pubKeyHashHex
= cfDataToHex(getPubKeyHash(context
));
290 CFPreferencesSynchronize(kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
291 CFRef
<CFDataRef
> storedData
= (CFDataRef
)CFPreferencesCopyValue(pubKeyHashHex
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
293 secinfo("TokenLogin", "Failed to read token login plist");
297 CFRef
<CFErrorRef
> error
;
298 *loginData
= (CFDictionaryRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
300 kCFPropertyListImmutable
,
303 if (!*loginData
|| CFGetTypeID(*loginData
) != CFDictionaryGetTypeID()) {
304 secinfo("TokenLogin", "Failed to deserialize unlock key data: %@", error
.get());
308 return errSecSuccess
;
311 OSStatus
TokenLoginGetPin(CFDictionaryRef context
, CFStringRef
*pin
)
313 if (!pin
|| !context
) {
316 *pin
= getPin(context
);
318 return errSecSuccess
;
321 OSStatus
TokenLoginUpdateUnlockData(CFDictionaryRef context
, CFStringRef password
)
327 CFRef
<SecKeychainRef
> loginKeychain
;
328 OSStatus result
= SecKeychainCopyLogin(loginKeychain
.take());
329 if (result
!= errSecSuccess
) {
330 secinfo("TokenLogin", "Failed to get user keychain: %d", (int) result
);
334 return SecKeychainStoreUnlockKeyWithPubKeyHash(getPubKeyHash(context
), getTokenId(context
), getPubKeyHashWrap(context
), loginKeychain
, password
);
337 OSStatus
TokenLoginCreateLoginData(CFStringRef tokenId
, CFDataRef pubKeyHash
, CFDataRef pubKeyHashWrap
, CFDataRef unlockKey
, CFDataRef scBlob
)
339 if (!tokenId
|| !pubKeyHash
|| !pubKeyHashWrap
|| !unlockKey
|| !scBlob
)
342 CFRef
<CFDictionaryRef
> ctx
= makeCFDictionary(3,
343 kSecAttrTokenID
, tokenId
,
344 kSecAttrPublicKeyHash
, pubKeyHash
,
345 kSecAttrAccount
, pubKeyHashWrap
347 CFRef
<SecKeyRef
> privKey
;
348 OSStatus result
= privKeyForPubKeyHash(ctx
, privKey
.take(), NULL
);
349 if (result
!= errSecSuccess
) {
350 secinfo("TokenLogin", "Failed to get private key for public key hash: %d", (int) result
);
354 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
356 secinfo("TokenLogin", "Failed to get public key from private key");
360 SecKeyAlgorithm algorithms
[] = {
361 kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM
,
362 kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM
,
363 kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM
,
364 kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM
,
365 kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM
,
366 kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM
,
367 kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM
,
368 kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM
,
369 kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM
,
370 kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM
373 SecKeyAlgorithm algorithm
= NULL
;
374 for (size_t i
= 0; i
< sizeof(algorithms
) / sizeof(*algorithms
); i
++) {
375 if (SecKeyIsAlgorithmSupported(pubKey
, kSecKeyOperationTypeEncrypt
, algorithms
[i
])
376 && SecKeyIsAlgorithmSupported(privKey
, kSecKeyOperationTypeDecrypt
, algorithms
[i
])) {
377 algorithm
= algorithms
[i
];
381 if (algorithm
== NULL
) {
382 secinfo("SecKeychain", "Failed to find supported wrap algorithm");
386 CFRef
<CFErrorRef
> error
;
387 CFRef
<CFDataRef
> wrappedUnlockKey
= SecKeyCreateEncryptedData(pubKey
, algorithm
, unlockKey
, error
.take());
388 if (!wrappedUnlockKey
) {
389 secinfo("TokenLogin", "Failed to wrap unlock key: %@", error
.get());
393 CFRef
<CFDictionaryRef
> loginData
= makeCFDictionary(4,
394 kSecAttrService
, algorithm
,
395 kSecAttrPublicKeyHash
, pubKeyHashWrap
,
396 kSecValueData
, wrappedUnlockKey
.get(),
399 return TokenLoginStoreUnlockData(ctx
, loginData
);
402 OSStatus
TokenLoginStoreUnlockData(CFDictionaryRef context
, CFDictionaryRef loginData
)
405 CFRef
<CFErrorRef
> error
;
406 CFRef
<CFDataRef
> data
= CFPropertyListCreateData(kCFAllocatorDefault
,
408 kCFPropertyListBinaryFormat_v1_0
,
412 secdebug("TokenLogin", "Failed to create unlock data: %@", error
.get());
413 return errSecInternal
;
415 CFRef
<CFStringRef
> pubKeyHashHex
= cfDataToHex(getPubKeyHash(context
));
416 CFPreferencesSetValue(pubKeyHashHex
, data
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
417 CFPreferencesSynchronize(kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
418 CFRef
<CFDataRef
> storedData
= (CFDataRef
)CFPreferencesCopyValue(pubKeyHashHex
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
420 if (!storedData
|| !CFEqual(storedData
, data
)) {
421 secinfo("TokenLogin", "Failed to write token login plist");
425 return errSecSuccess
;
428 OSStatus
TokenLoginDeleteUnlockData(CFDataRef pubKeyHash
)
430 CFRef
<CFStringRef
> pubKeyHashHex
= cfDataToHex(pubKeyHash
);
431 CFPreferencesSetValue(pubKeyHashHex
, NULL
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
432 CFPreferencesSynchronize(kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
433 CFRef
<CFDataRef
> storedData
= (CFDataRef
)CFPreferencesCopyValue(pubKeyHashHex
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
436 secinfo("TokenLogin", "Failed to remove unlock data");
440 return errSecSuccess
;
443 OSStatus
TokenLoginGetScBlob(CFDataRef pubKeyHashWrap
, CFStringRef tokenId
, CFStringRef password
, CFDataRef
*scBlob
)
445 if (scBlob
== NULL
|| password
== NULL
|| pubKeyHashWrap
== NULL
|| tokenId
== NULL
) {
446 secinfo("TokenLogin", "TokenLoginGetScBlob wrong params");
450 CFRef
<CFDictionaryRef
> ctx
= makeCFDictionary(2,
451 kSecAttrTokenID
, tokenId
,
452 kSecAttrAccount
, pubKeyHashWrap
455 CFRef
<SecKeyRef
> privKey
;
456 OSStatus retval
= privKeyForPubKeyHash(ctx
, privKey
.take(), NULL
);
457 if (retval
!= errSecSuccess
) {
458 secinfo("TokenLogin", "TokenLoginGetScBlob failed to get private key for public key hash: %d", (int) retval
);
462 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
464 secinfo("TokenLogin", "TokenLoginGetScBlob no pubkey");
465 return errSecInternal
;
468 CFRef
<CFDictionaryRef
> attributes
= SecKeyCopyAttributes(pubKey
);
470 secinfo("TokenLogin", "TokenLoginGetScBlob no attributes");
471 return errSecInternal
;
474 aks_smartcard_mode_t mode
;
475 CFRef
<CFStringRef
> type
= (CFStringRef
)CFDictionaryGetValue(attributes
, kSecAttrKeyType
);
476 if (CFEqual(type
, kSecAttrKeyTypeRSA
))
477 mode
= AKS_SMARTCARD_MODE_RSA
;
478 else if (CFEqual(type
, kSecAttrKeyTypeEC
))
479 mode
= AKS_SMARTCARD_MODE_ECDH
;
481 secinfo("TokenLogin", "TokenLoginGetScBlob bad type");
482 return errSecNotAvailable
;
485 CFRef
<CFDataRef
> publicBytes
= SecKeyCopyExternalRepresentation(pubKey
, NULL
);
487 secinfo("TokenLogin", "TokenLoginGetScBlob cannot get public bytes");
491 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
492 char* buf
= (char*)malloc(maxLength
);
494 secinfo("TokenLogin", "TokenLoginGetScBlob no mem for buffer");
498 if (CFStringGetCString(password
, buf
, maxLength
, kCFStringEncodingUTF8
) == FALSE
) {
499 secinfo("TokenLogin", "TokenLoginGetScBlob no pwd cstr");
504 void *sc_blob
= NULL
;
506 aks_smartcard_unregister(session_keybag_handle
); // just to be sure no previous registration exist
507 kern_return_t aks_retval
= aks_smartcard_register(session_keybag_handle
, (uint8_t *)buf
, strlen(buf
), mode
, (uint8_t *)CFDataGetBytePtr(publicBytes
), (size_t)CFDataGetLength(publicBytes
), &sc_blob
, &sc_len
);
509 secinfo("TokenLogin", "TokenLoginGetScBlob register result %d", aks_retval
);
512 *scBlob
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)sc_blob
, (CFIndex
)sc_len
);
518 OSStatus
TokenLoginUnlockKeybag(CFDictionaryRef context
, CFDictionaryRef loginData
)
520 if (!loginData
|| !context
) {
524 CFDataRef scBlob
= (CFDataRef
)CFDictionaryGetValue(loginData
, kSecClassKey
);
525 if (scBlob
== NULL
) {
526 secinfo("TokenLogin", "Failed to get scblob");
527 return errSecInternal
;
530 CFRef
<CFErrorRef
> error
;
531 CFRef
<SecKeyRef
> privKey
;
532 CFRef
<CFTypeRef
> LAContext
;
533 OSStatus retval
= privKeyForPubKeyHash(context
, privKey
.take(), LAContext
.take());
534 if (retval
!= errSecSuccess
) {
535 secinfo("TokenLogin", "Failed to get private key for public key hash: %d", (int) retval
);
539 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
541 secinfo("TokenLogin", "Failed to get pubkey");
545 CFRef
<CFDictionaryRef
> attributes
= SecKeyCopyAttributes(pubKey
);
547 secinfo("TokenLogin", "TokenLoginUnlockKeybag no attributes");
548 return errSecInternal
;
551 aks_smartcard_mode_t mode
;
552 CFStringRef type
= (CFStringRef
)CFDictionaryGetValue(attributes
, kSecAttrKeyType
);
553 if (CFEqual(type
, kSecAttrKeyTypeRSA
))
554 mode
= AKS_SMARTCARD_MODE_RSA
;
555 else if (CFEqual(type
, kSecAttrKeyTypeEC
))
556 mode
= AKS_SMARTCARD_MODE_ECDH
;
558 secinfo("TokenLogin", "TokenLoginUnlockKeybag bad type");
559 return errSecNotAvailable
;
562 void *scChallenge
= NULL
;
563 size_t scChallengeLen
= 0;
564 int res
= aks_smartcard_request_unlock(session_keybag_handle
, (uint8_t *)CFDataGetBytePtr(scBlob
), (size_t)CFDataGetLength(scBlob
), &scChallenge
, &scChallengeLen
);
566 secinfo("TokenLogin", "TokenLoginUnlockKeybag cannot request unlock: %x", res
);
567 return errSecInternal
;
569 const void *scUsk
= NULL
;
571 res
= aks_smartcard_get_sc_usk(scChallenge
, scChallengeLen
, &scUsk
, &scUskLen
);
573 if (res
!= 0 || scUsk
== NULL
) {
575 secinfo("TokenLogin", "TokenLoginUnlockKeybag cannot get usk: %x", res
);
576 return errSecInternal
;
579 CFRef
<CFTypeRef
> wrappedUsk
;
580 if (mode
== AKS_SMARTCARD_MODE_ECDH
) {
581 const void *ecPub
= NULL
;
583 res
= aks_smartcard_get_ec_pub(scChallenge
, scChallengeLen
, &ecPub
, &ecPubLen
);
584 if (res
!= 0 || ecPub
== NULL
) {
586 secinfo("TokenLogin", "TokenLoginUnlockKeybag cannot get ecpub: %x", res
);
587 return errSecInternal
;
589 wrappedUsk
= CFDataCreateMutable(kCFAllocatorDefault
, ecPubLen
+ scUskLen
);
592 secinfo("TokenLogin", "TokenLoginUnlockKeybag no mem for ecpubusk");
593 return errSecInternal
;
595 CFDataAppendBytes((CFMutableDataRef
)wrappedUsk
.get(), (const UInt8
*)ecPub
, (CFIndex
)ecPubLen
);
596 CFDataAppendBytes((CFMutableDataRef
)wrappedUsk
.get(), (const UInt8
*)scUsk
, (CFIndex
)scUskLen
);
598 wrappedUsk
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)scUsk
, (CFIndex
)scUskLen
);
601 // decrypt Usk with SC
602 CFRef
<CFDataRef
> unwrappedUsk
= SecKeyCreateDecryptedData(privKey
,
603 mode
== AKS_SMARTCARD_MODE_RSA
? kSecKeyAlgorithmRSAEncryptionOAEPSHA256
: kSecKeyAlgorithmECIESEncryptionAKSSmartCard
,
604 (CFDataRef
)wrappedUsk
.get(),
607 secinfo("TokenLogin", "TokenLoginUnlockKeybag failed to unwrap blob: %@", error
.get());
608 return errSecInternal
;
611 void *scNewBlob
= NULL
;
613 res
= aks_smartcard_unlock(session_keybag_handle
, (uint8_t *)CFDataGetBytePtr(scBlob
), (size_t)CFDataGetLength(scBlob
), (uint8_t *)CFDataGetBytePtr(unwrappedUsk
), (size_t)CFDataGetLength(unwrappedUsk
), &scNewBlob
, &scNewLen
);
615 CFRef
<CFDataRef
> newBlobData
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)scNewBlob
, (CFIndex
)scNewLen
);
617 CFRef
<CFMutableDictionaryRef
> newDict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 4, loginData
);
619 CFDictionarySetValue(newDict
, kSecClassKey
, newBlobData
.get());
620 TokenLoginStoreUnlockData(context
, newDict
);