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/ctkclient.h>
39 #include <coreauthd_spi.h>
42 static os_log_t
TOKEN_LOG_DEFAULT() {
43 static dispatch_once_t once
;
45 dispatch_once(&once
, ^{ log
= os_log_create("com.apple.security", "tokenlogin"); });
48 #define TL_LOG TOKEN_LOG_DEFAULT()
50 #define kSecTokenLoginDomain CFSTR("com.apple.security.tokenlogin")
52 static CFStringRef CF_RETURNS_RETAINED
cfDataToHex(CFDataRef bin
)
54 size_t len
= CFDataGetLength(bin
) * 2;
55 CFMutableStringRef str
= CFStringCreateMutable(NULL
, len
);
57 static const char* digits
[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
59 const uint8_t* data
= CFDataGetBytePtr(bin
);
60 for (size_t i
= 0; i
< CFDataGetLength(bin
); i
++) {
61 CFStringAppendCString(str
, digits
[data
[i
] >> 4], 1);
62 CFStringAppendCString(str
, digits
[data
[i
] & 0xf], 1);
67 static CFStringRef
getPin(CFDictionaryRef context
)
73 CFStringRef pin
= (CFStringRef
)CFDictionaryGetValue(context
, kSecAttrService
);
74 if (!pin
|| CFGetTypeID(pin
) != CFStringGetTypeID()) {
80 static CFStringRef
getTokenId(CFDictionaryRef context
)
86 CFStringRef tokenId
= (CFStringRef
)CFDictionaryGetValue(context
, kSecAttrTokenID
);
87 if (!tokenId
|| CFGetTypeID(tokenId
) != CFStringGetTypeID()) {
88 os_log_debug(TL_LOG
, "Invalid tokenId");
94 static CFDataRef
getPubKeyHash(CFDictionaryRef context
)
100 CFDataRef pubKeyHash
= (CFDataRef
)CFDictionaryGetValue(context
, kSecAttrPublicKeyHash
);
101 if (!pubKeyHash
|| CFGetTypeID(pubKeyHash
) != CFDataGetTypeID()) {
102 os_log_debug(TL_LOG
, "Invalid pubkeyhash");
108 static CFDataRef
getPubKeyHashWrap(CFDictionaryRef context
)
114 CFDataRef pubKeyHashWrap
= (CFDataRef
)CFDictionaryGetValue(context
, kSecAttrAccount
);
115 if (!pubKeyHashWrap
|| CFGetTypeID(pubKeyHashWrap
) != CFDataGetTypeID()) {
116 os_log_debug(TL_LOG
, "Invalid pubkeyhashwrap");
119 return pubKeyHashWrap
;
122 static OSStatus
privKeyForPubKeyHashWrap(CFDictionaryRef context
, SecKeyRef
*privKey
, CFTypeRef
*laCtx
)
125 os_log_error(TL_LOG
, "private key for pubkeyhash wrong params");
129 CFRef
<CFMutableDictionaryRef
> tokenAttributes
= makeCFMutableDictionary(1, kSecAttrTokenID
, getTokenId(context
));
130 CFRef
<CFErrorRef
> error
;
132 CFStringRef pin
= getPin(context
);
134 CFRef
<CFTypeRef
> LAContext
= LACreateNewContextWithACMContext(NULL
, error
.take());
136 os_log_error(TL_LOG
, "Failed to LA Context: %{public}@", error
.get());
140 *laCtx
= (CFTypeRef
)CFRetain(LAContext
);
141 CFRef
<CFDataRef
> externalizedContext
= LACopyACMContext(LAContext
, error
.take());
142 if (!externalizedContext
) {
143 os_log_error(TL_LOG
, "Failed to get externalized context: %{public}@", error
.get());
146 CFDictionarySetValue(tokenAttributes
, kSecUseCredentialReference
, externalizedContext
.get());
147 CFDictionarySetValue(tokenAttributes
, CFSTR("PIN"), pin
);
150 CFRef
<TKTokenRef
> token
= TKTokenCreate(tokenAttributes
, error
.take());
152 os_log_error(TL_LOG
, "Failed to create token: %{public}@", error
.get());
156 CFRef
<CFArrayRef
> identities
= TKTokenCopyIdentities(token
, TKTokenKeyUsageAny
, error
.take());
157 if (!identities
|| !CFArrayGetCount(identities
)) {
158 os_log_error(TL_LOG
, "No identities found for token: %{public}@", error
.get());
162 CFDataRef desiredHash
= getPubKeyHashWrap(context
);
164 os_log_error(TL_LOG
, "No wrap key in context");
168 CFIndex idx
, count
= CFArrayGetCount(identities
);
169 for (idx
= 0; idx
< count
; ++idx
) {
170 SecIdentityRef identity
= (SecIdentityRef
)CFArrayGetValueAtIndex(identities
, idx
);
171 CFRef
<SecCertificateRef
> certificate
;
172 OSStatus result
= SecIdentityCopyCertificate(identity
, certificate
.take());
173 if (result
!= errSecSuccess
) {
174 os_log_error(TL_LOG
, "Failed to get certificate for identity: %d", (int) result
);
178 CFRef
<CFDataRef
> identityHash
= SecCertificateCopyPublicKeySHA1Digest(certificate
);
179 if (identityHash
&& CFEqual(desiredHash
, identityHash
)) {
180 result
= SecIdentityCopyPrivateKey(identity
, privKey
);
181 if (result
!= errSecSuccess
) {
182 os_log_error(TL_LOG
, "Failed to get identity private key: %d", (int) result
);
191 OSStatus
TokenLoginGetContext(const void *base64TokenLoginData
, UInt32 base64TokenLoginDataLength
, CFDictionaryRef
*context
)
193 if (!base64TokenLoginData
|| !context
) {
194 os_log_error(TL_LOG
, "Get login context - wrong params");
198 // Token data are base64 encoded in password.
199 size_t dataLen
= SecBase64Decode((const char *)base64TokenLoginData
, base64TokenLoginDataLength
, NULL
, 0);
201 os_log_debug(TL_LOG
, "Invalid base64 encoded token data");
205 CFRef
<CFMutableDataRef
> data
= CFDataCreateMutable(kCFAllocatorDefault
, dataLen
);
206 dataLen
= SecBase64Decode((const char *)base64TokenLoginData
, base64TokenLoginDataLength
, CFDataGetMutableBytePtr(data
), dataLen
);
208 os_log_error(TL_LOG
, "Invalid base64 encoded token data");
211 CFDataSetLength(data
, dataLen
);
213 // Content of the password consists of a serialized dictionary containing token ID, PIN, wrap key hash etc.
214 CFRef
<CFErrorRef
> error
;
215 *context
= (CFDictionaryRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
217 kCFPropertyListImmutable
,
220 if (!*context
|| CFGetTypeID(*context
) != CFDictionaryGetTypeID()) {
221 os_log_error(TL_LOG
, "Invalid token login data property list, %{public}@", error
.get());
225 if (!getPin(*context
) || !getTokenId(*context
) || !getPubKeyHash(*context
) || !getPubKeyHashWrap(*context
)) {
226 os_log_error(TL_LOG
, "Invalid token login data context, %{public}@", error
.get());
230 return errSecSuccess
;
233 OSStatus
TokenLoginGetUnlockKey(CFDictionaryRef context
, CFDataRef
*unlockKey
)
235 if (!context
|| !unlockKey
) {
236 os_log_error(TL_LOG
, "Get unlock key - wrong params");
240 CFRef
<CFDictionaryRef
> loginData
;
241 OSStatus result
= TokenLoginGetLoginData(context
, loginData
.take());
242 if (result
!= errSecSuccess
) {
243 os_log_error(TL_LOG
, "Failed to get login data: %d", (int)result
);
247 CFDataRef wrappedUnlockKey
= (CFDataRef
)CFDictionaryGetValue(loginData
, kSecValueData
);
248 if (!wrappedUnlockKey
) {
249 os_log_error(TL_LOG
, "Wrapped unlock key not found in unlock key data");
252 SecKeyAlgorithm algorithm
= (SecKeyAlgorithm
)CFDictionaryGetValue(loginData
, kSecAttrService
);
254 os_log_error(TL_LOG
, "Algorithm not found in unlock key data");
257 CFDataRef pubKeyHashWrapFromPlist
= (CFDataRef
)CFDictionaryGetValue(loginData
, kSecAttrPublicKeyHash
);
258 if (pubKeyHashWrapFromPlist
== NULL
) {
259 os_log_error(TL_LOG
, "Failed to get wrapkey for unlock key data");
260 return errSecInternal
;
263 CFRef
<CFDictionaryRef
> ctx
= makeCFDictionary(3,
264 kSecAttrTokenID
, getTokenId(context
),
265 kSecAttrService
, getPin(context
),
266 kSecAttrAccount
, pubKeyHashWrapFromPlist
269 CFRef
<SecKeyRef
> privKey
;
270 CFRef
<CFTypeRef
> LAContext
;
271 result
= privKeyForPubKeyHashWrap(ctx
, privKey
.take(), LAContext
.take());
272 if (result
!= errSecSuccess
) {
273 os_log_error(TL_LOG
, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrapFromPlist
, (int)result
);
277 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
279 os_log_error(TL_LOG
, "Failed to get public key from private key");
282 CFRef
<CFErrorRef
> error
;
283 *unlockKey
= SecKeyCreateDecryptedData(privKey
,
288 os_log_error(TL_LOG
, "Failed to unwrap unlock key: %{public}@", error
.get());
292 // we need to re-wrap already unwrapped data to avoid capturing and reusing communication with the smartcard
293 CFRef
<CFDataRef
> reWrappedUnlockKey
= SecKeyCreateEncryptedData(pubKey
, algorithm
, *unlockKey
, error
.take());
294 if (!reWrappedUnlockKey
) {
295 os_log_error(TL_LOG
, "Failed to rewrap unlock key: %{public}@", error
.get());
296 TokenLoginDeleteUnlockData(getPubKeyHash(context
));
300 CFRef
<CFMutableDictionaryRef
> newDict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 4, loginData
);
302 CFDictionarySetValue(newDict
, kSecValueData
, reWrappedUnlockKey
);
303 TokenLoginStoreUnlockData(context
, newDict
);
306 return errSecSuccess
;
309 OSStatus
TokenLoginGetLoginData(CFDictionaryRef context
, CFDictionaryRef
*loginData
)
311 if (!loginData
|| !context
) {
312 os_log_error(TL_LOG
, "Get login data - wrong params");
316 CFRef
<CFStringRef
> pubKeyHashHex
= cfDataToHex(getPubKeyHash(context
));
318 CFPreferencesSynchronize(kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
319 CFRef
<CFDataRef
> storedData
= (CFDataRef
)CFPreferencesCopyValue(pubKeyHashHex
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
321 // this is not an error, might be a normal situation if the value does not exist
322 os_log_debug(TL_LOG
, "Failed to read token login plist");
326 CFRef
<CFErrorRef
> error
;
327 *loginData
= (CFDictionaryRef
)CFPropertyListCreateWithData(kCFAllocatorDefault
,
329 kCFPropertyListImmutable
,
332 if (!*loginData
|| CFGetTypeID(*loginData
) != CFDictionaryGetTypeID()) {
333 os_log_error(TL_LOG
, "Failed to deserialize unlock key data: %{public}@", error
.get());
337 return errSecSuccess
;
340 OSStatus
TokenLoginGetPin(CFDictionaryRef context
, CFStringRef
*pin
)
342 if (!pin
|| !context
) {
345 *pin
= getPin(context
);
347 return errSecSuccess
;
350 OSStatus
TokenLoginUpdateUnlockData(CFDictionaryRef context
, CFStringRef password
)
353 os_log_error(TL_LOG
, "Updating unlock data - wrong params");
357 CFRef
<SecKeychainRef
> loginKeychain
;
358 OSStatus result
= SecKeychainCopyLogin(loginKeychain
.take());
359 if (result
!= errSecSuccess
) {
360 os_log_error(TL_LOG
, "Failed to get user keychain: %d", (int) result
);
364 return SecKeychainStoreUnlockKeyWithPubKeyHash(getPubKeyHash(context
), getTokenId(context
), getPubKeyHashWrap(context
), loginKeychain
, password
);
367 OSStatus
TokenLoginCreateLoginData(CFStringRef tokenId
, CFDataRef pubKeyHash
, CFDataRef pubKeyHashWrap
, CFDataRef unlockKey
, CFDataRef scBlob
)
369 if (!tokenId
|| !pubKeyHash
|| !pubKeyHashWrap
|| !unlockKey
|| !scBlob
) {
370 os_log_error(TL_LOG
, "Create login data - wrong params");
374 CFRef
<CFDictionaryRef
> ctx
= makeCFDictionary(3,
375 kSecAttrTokenID
, tokenId
,
376 kSecAttrPublicKeyHash
, pubKeyHash
,
377 kSecAttrAccount
, pubKeyHashWrap
379 CFRef
<SecKeyRef
> privKey
;
380 OSStatus result
= privKeyForPubKeyHashWrap(ctx
, privKey
.take(), NULL
);
381 if (result
!= errSecSuccess
) {
382 os_log_error(TL_LOG
, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrap
, (int)result
);
386 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
388 os_log_error(TL_LOG
, "Failed to get public key from private key");
392 SecKeyAlgorithm algorithms
[] = {
393 kSecKeyAlgorithmECIESEncryptionStandardX963SHA512AESGCM
,
394 kSecKeyAlgorithmECIESEncryptionStandardX963SHA384AESGCM
,
395 kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM
,
396 kSecKeyAlgorithmECIESEncryptionStandardX963SHA224AESGCM
,
397 kSecKeyAlgorithmECIESEncryptionStandardX963SHA1AESGCM
,
398 kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM
,
399 kSecKeyAlgorithmRSAEncryptionOAEPSHA384AESGCM
,
400 kSecKeyAlgorithmRSAEncryptionOAEPSHA256AESGCM
,
401 kSecKeyAlgorithmRSAEncryptionOAEPSHA224AESGCM
,
402 kSecKeyAlgorithmRSAEncryptionOAEPSHA1AESGCM
405 SecKeyAlgorithm algorithm
= NULL
;
406 for (size_t i
= 0; i
< sizeof(algorithms
) / sizeof(*algorithms
); i
++) {
407 if (SecKeyIsAlgorithmSupported(pubKey
, kSecKeyOperationTypeEncrypt
, algorithms
[i
])
408 && SecKeyIsAlgorithmSupported(privKey
, kSecKeyOperationTypeDecrypt
, algorithms
[i
])) {
409 algorithm
= algorithms
[i
];
413 if (algorithm
== NULL
) {
414 os_log_error(TL_LOG
, "Failed to find supported wrap algorithm");
418 CFRef
<CFErrorRef
> error
;
419 CFRef
<CFDataRef
> wrappedUnlockKey
= SecKeyCreateEncryptedData(pubKey
, algorithm
, unlockKey
, error
.take());
420 if (!wrappedUnlockKey
) {
421 os_log_error(TL_LOG
, "Failed to wrap unlock key: %{public}@", error
.get());
425 CFRef
<CFDictionaryRef
> loginData
= makeCFDictionary(4,
426 kSecAttrService
, algorithm
,
427 kSecAttrPublicKeyHash
, pubKeyHashWrap
,
428 kSecValueData
, wrappedUnlockKey
.get(),
431 return TokenLoginStoreUnlockData(ctx
, loginData
);
434 OSStatus
TokenLoginStoreUnlockData(CFDictionaryRef context
, CFDictionaryRef loginData
)
436 os_log_debug(TL_LOG
, "Storing unlock data");
438 CFRef
<CFErrorRef
> error
;
439 CFRef
<CFDataRef
> data
= CFPropertyListCreateData(kCFAllocatorDefault
,
441 kCFPropertyListBinaryFormat_v1_0
,
445 os_log_error(TL_LOG
, "Failed to create unlock data: %{public}@", error
.get());
446 return errSecInternal
;
448 CFRef
<CFStringRef
> pubKeyHashHex
= cfDataToHex(getPubKeyHash(context
));
449 os_log_debug(TL_LOG
, "Pubkeyhash %@", pubKeyHashHex
.get());
451 CFPreferencesSetValue(pubKeyHashHex
, data
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
452 os_log_debug(TL_LOG
, "Pubkeyhash %@", pubKeyHashHex
.get());
454 CFPreferencesSynchronize(kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
455 CFRef
<CFDataRef
> storedData
= (CFDataRef
)CFPreferencesCopyValue(pubKeyHashHex
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
456 os_log_debug(TL_LOG
, "Stored data %@", storedData
.get());
458 if (!storedData
|| !CFEqual(storedData
, data
)) {
459 os_log_error(TL_LOG
, "Failed to write token login plist");
462 os_log_debug(TL_LOG
, "Original data %@. Everything is OK", data
.get());
464 return errSecSuccess
;
467 OSStatus
TokenLoginDeleteUnlockData(CFDataRef pubKeyHash
)
469 CFRef
<CFStringRef
> pubKeyHashHex
= cfDataToHex(pubKeyHash
);
470 CFPreferencesSetValue(pubKeyHashHex
, NULL
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
471 CFPreferencesSynchronize(kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
472 CFRef
<CFDataRef
> storedData
= (CFDataRef
)CFPreferencesCopyValue(pubKeyHashHex
, kSecTokenLoginDomain
, kCFPreferencesCurrentUser
, kCFPreferencesAnyHost
);
475 os_log_error(TL_LOG
, "Failed to remove unlock data");
479 return errSecSuccess
;
482 OSStatus
TokenLoginGetScBlob(CFDataRef pubKeyHashWrap
, CFStringRef tokenId
, CFStringRef password
, CFDataRef
*scBlob
)
484 if (scBlob
== NULL
|| password
== NULL
|| pubKeyHashWrap
== NULL
|| tokenId
== NULL
) {
485 os_log_error(TL_LOG
, "TokenLoginGetScBlob wrong params");
489 CFRef
<CFDictionaryRef
> ctx
= makeCFDictionary(2,
490 kSecAttrTokenID
, tokenId
,
491 kSecAttrAccount
, pubKeyHashWrap
494 CFRef
<SecKeyRef
> privKey
;
495 OSStatus retval
= privKeyForPubKeyHashWrap(ctx
, privKey
.take(), NULL
);
496 if (retval
!= errSecSuccess
) {
497 os_log_error(TL_LOG
, "TokenLoginGetScBlob failed to get private key for public key hash %{public}@: %d", pubKeyHashWrap
, (int)retval
);
501 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
503 os_log_error(TL_LOG
, "TokenLoginGetScBlob no pubkey");
504 return errSecInternal
;
507 CFRef
<CFDictionaryRef
> attributes
= SecKeyCopyAttributes(pubKey
);
509 os_log_error(TL_LOG
, "TokenLoginGetScBlob no attributes");
510 return errSecInternal
;
513 aks_smartcard_mode_t mode
;
514 CFRef
<CFStringRef
> type
= (CFStringRef
)CFDictionaryGetValue(attributes
, kSecAttrKeyType
);
515 if (CFEqual(type
, kSecAttrKeyTypeRSA
))
516 mode
= AKS_SMARTCARD_MODE_RSA
;
517 else if (CFEqual(type
, kSecAttrKeyTypeEC
))
518 mode
= AKS_SMARTCARD_MODE_ECDH
;
520 os_log_error(TL_LOG
, "TokenLoginGetScBlob bad type");
521 return errSecNotAvailable
;
524 CFRef
<CFDataRef
> publicBytes
= SecKeyCopyExternalRepresentation(pubKey
, NULL
);
526 os_log_error(TL_LOG
, "TokenLoginGetScBlob cannot get public bytes");
530 CFIndex maxLength
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(password
), kCFStringEncodingUTF8
) + 1;
531 char* buf
= (char*)malloc(maxLength
);
533 os_log_error(TL_LOG
, "TokenLoginGetScBlob no mem for buffer");
537 if (CFStringGetCString(password
, buf
, maxLength
, kCFStringEncodingUTF8
) == FALSE
) {
538 os_log_error(TL_LOG
, "TokenLoginGetScBlob no pwd cstr");
543 void *sc_blob
= NULL
;
545 aks_smartcard_unregister(session_keybag_handle
); // just to be sure no previous registration exist
546 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
);
548 os_log_debug(TL_LOG
, "TokenLoginGetScBlob register result %d", aks_retval
);
551 *scBlob
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)sc_blob
, (CFIndex
)sc_len
);
557 // context = data wrapped in password variable, loginData = dictionary from stored plist
558 OSStatus
TokenLoginUnlockKeybag(CFDictionaryRef context
, CFDictionaryRef loginData
)
560 if (!loginData
|| !context
) {
564 CFDataRef scBlob
= (CFDataRef
)CFDictionaryGetValue(loginData
, kSecClassKey
);
565 if (scBlob
== NULL
) {
566 os_log_error(TL_LOG
, "Failed to get scblob");
567 return errSecInternal
;
570 CFDataRef pubKeyHashWrapFromPlist
= (CFDataRef
)CFDictionaryGetValue(loginData
, kSecAttrPublicKeyHash
);
571 if (pubKeyHashWrapFromPlist
== NULL
) {
572 os_log_error(TL_LOG
, "Failed to get wrapkey");
573 return errSecInternal
;
576 CFRef
<CFDictionaryRef
> ctx
= makeCFDictionary(3,
577 kSecAttrTokenID
, getTokenId(context
),
578 kSecAttrService
, getPin(context
),
579 kSecAttrAccount
, pubKeyHashWrapFromPlist
582 CFRef
<CFErrorRef
> error
;
583 CFRef
<SecKeyRef
> privKey
;
584 CFRef
<CFTypeRef
> LAContext
;
585 OSStatus retval
= privKeyForPubKeyHashWrap(ctx
, privKey
.take(), LAContext
.take());
586 if (retval
!= errSecSuccess
) {
587 os_log_error(TL_LOG
, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrapFromPlist
, (int)retval
);
591 CFRef
<SecKeyRef
> pubKey
= SecKeyCopyPublicKey(privKey
);
593 os_log_error(TL_LOG
, "Failed to get pubkey");
597 CFRef
<CFDictionaryRef
> attributes
= SecKeyCopyAttributes(pubKey
);
599 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag no attributes");
600 return errSecInternal
;
603 aks_smartcard_mode_t mode
;
604 CFStringRef type
= (CFStringRef
)CFDictionaryGetValue(attributes
, kSecAttrKeyType
);
605 if (CFEqual(type
, kSecAttrKeyTypeRSA
))
606 mode
= AKS_SMARTCARD_MODE_RSA
;
607 else if (CFEqual(type
, kSecAttrKeyTypeEC
))
608 mode
= AKS_SMARTCARD_MODE_ECDH
;
610 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag bad type");
611 return errSecNotAvailable
;
614 void *scChallenge
= NULL
;
615 size_t scChallengeLen
= 0;
616 int res
= aks_smartcard_request_unlock(session_keybag_handle
, (uint8_t *)CFDataGetBytePtr(scBlob
), (size_t)CFDataGetLength(scBlob
), &scChallenge
, &scChallengeLen
);
618 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag cannot request unlock: %x", res
);
619 return errSecInternal
;
621 const void *scUsk
= NULL
;
623 res
= aks_smartcard_get_sc_usk(scChallenge
, scChallengeLen
, &scUsk
, &scUskLen
);
625 if (res
!= 0 || scUsk
== NULL
) {
627 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag cannot get usk: %x", res
);
628 return errSecInternal
;
631 CFRef
<CFTypeRef
> wrappedUsk
;
632 if (mode
== AKS_SMARTCARD_MODE_ECDH
) {
633 const void *ecPub
= NULL
;
635 res
= aks_smartcard_get_ec_pub(scChallenge
, scChallengeLen
, &ecPub
, &ecPubLen
);
636 if (res
!= 0 || ecPub
== NULL
) {
638 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag cannot get ecpub: %x", res
);
639 return errSecInternal
;
641 wrappedUsk
= CFDataCreateMutable(kCFAllocatorDefault
, ecPubLen
+ scUskLen
);
644 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag no mem for ecpubusk");
645 return errSecInternal
;
647 CFDataAppendBytes((CFMutableDataRef
)wrappedUsk
.get(), (const UInt8
*)ecPub
, (CFIndex
)ecPubLen
);
648 CFDataAppendBytes((CFMutableDataRef
)wrappedUsk
.get(), (const UInt8
*)scUsk
, (CFIndex
)scUskLen
);
650 wrappedUsk
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)scUsk
, (CFIndex
)scUskLen
);
653 // decrypt Usk with SC
654 CFRef
<CFDataRef
> unwrappedUsk
= SecKeyCreateDecryptedData(privKey
,
655 mode
== AKS_SMARTCARD_MODE_RSA
? kSecKeyAlgorithmRSAEncryptionOAEPSHA256
: kSecKeyAlgorithmECIESEncryptionAKSSmartCard
,
656 (CFDataRef
)wrappedUsk
.get(),
659 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag failed to unwrap blob: %{public}@", error
.get());
660 return errSecInternal
;
663 void *scNewBlob
= NULL
;
665 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
);
667 CFRef
<CFDataRef
> newBlobData
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)scNewBlob
, (CFIndex
)scNewLen
);
669 CFRef
<CFMutableDictionaryRef
> newDict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 4, loginData
);
671 CFDictionarySetValue(newDict
, kSecClassKey
, newBlobData
.get());
672 TokenLoginStoreUnlockData(context
, newDict
);
675 os_log_error(TL_LOG
, "TokenLoginUnlockKeybag no new scblob received: %d", res
);