2 * Copyright (c) 2015 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 <AssertMacros.h>
25 #include <Security/SecFramework.h>
26 #include <Security/SecKeyPriv.h>
27 #include <Security/SecItem.h>
28 #include <Security/SecItemPriv.h>
29 #include <Security/SecItemInternal.h>
30 #include <Security/SecBasePriv.h>
31 #include <utilities/SecCFError.h>
32 #include <utilities/SecCFWrappers.h>
33 #include <ctkclient.h>
34 #include <libaks_acl_cf_keys.h>
37 #include "SecRSAKey.h"
38 #include "SecCTKKeyPriv.h"
40 const CFStringRef kSecUseToken
= CFSTR("u_Token");
41 const CFStringRef kSecUseTokenObjectID
= CFSTR("u_TokenOID");
47 SecCFDictionaryCOW auth_params
;
48 SecCFDictionaryCOW attributes
;
51 static void SecCTKKeyDestroy(SecKeyRef key
) {
52 SecCTKKeyData
*kd
= key
->key
;
53 CFReleaseSafe(kd
->token
);
54 CFReleaseSafe(kd
->token_id
);
55 CFReleaseSafe(kd
->objectID
);
56 CFReleaseSafe(kd
->auth_params
.mutable_dictionary
);
57 CFReleaseSafe(kd
->attributes
.mutable_dictionary
);
60 static CFIndex
SecCTKGetAlgorithmID(SecKeyRef key
) {
61 SecCTKKeyData
*kd
= key
->key
;
62 if (CFEqualSafe(CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrKeyType
), kSecAttrKeyTypeEC
))
63 return kSecECDSAAlgorithmID
;
65 return kSecRSAAlgorithmID
;
68 static SecItemAuthResult
SecCTKProcessError(CFStringRef operation
, TKTokenRef token
, CFDataRef object_id
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
69 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
70 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
71 CFDataRef access_control
= TKTokenCopyObjectAccessControl(token
, object_id
, error
);
72 if (access_control
!= NULL
) {
73 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
74 CFAssignRetained(*ac_pairs
, CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
));
76 CFReleaseNull(*error
);
78 CFRelease(access_control
);
79 return kSecItemAuthResultNeedAuth
;
82 return kSecItemAuthResultError
;
85 static OSStatus
SecCTKKeyRawSign(SecKeyRef key
, SecPadding padding
,
86 const uint8_t *dataToSign
, size_t dataToSignLen
,
87 uint8_t *sig
, size_t *sigLen
) {
88 OSStatus status
= errSecSuccess
;
89 CFDataRef digest
= CFDataCreateWithBytesNoCopy(NULL
, dataToSign
, dataToSignLen
, kCFAllocatorNull
);
91 SecCTKKeyData
*kd
= key
->key
;
92 __block SecCFDictionaryCOW sign_auth_params
= { kd
->auth_params
.dictionary
};
93 __block TKTokenRef token
= CFRetainSafe(kd
->token
);
95 status
= SecOSStatusWith(^bool(CFErrorRef
*error
) {
96 return SecItemAuthDo(&sign_auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
97 CFDataRef signature
= NULL
;
98 SecItemAuthResult auth_result
= kSecItemAuthResultOK
;
100 if (sign_auth_params
.mutable_dictionary
!= NULL
) {
101 // auth_params were modified, so reconnect the token in order to update the attributes.
102 TKTokenRef new_token
= NULL
;
103 require_quiet(new_token
= SecTokenCreate(kd
->token_id
, auth_params
, error
), out
);
104 CFAssignRetained(token
, new_token
);
107 require_action_quiet(signature
= TKTokenCopySignature(token
, kd
->objectID
, padding
, digest
, error
), out
,
108 auth_result
= SecCTKProcessError(kAKSKeyOpSign
, token
, kd
->objectID
, ac_pairs
, error
));
109 require_action_quiet((CFIndex
)*sigLen
>= CFDataGetLength(signature
), out
,
110 SecError(errSecParam
, error
, CFSTR("signature buffer too small (%ulb required)"),
111 (unsigned long)CFDataGetLength(signature
)));
112 *sigLen
= CFDataGetLength(signature
);
113 CFDataGetBytes(signature
, CFRangeMake(0, *sigLen
), sig
);
114 *sigLen
= CFDataGetLength(signature
);
117 CFReleaseSafe(signature
);
122 CFReleaseSafe(sign_auth_params
.mutable_dictionary
);
123 CFReleaseSafe(digest
);
124 CFReleaseSafe(token
);
128 static size_t SecCTKKeyBlockSize(SecKeyRef key
) {
129 SecCTKKeyData
*kd
= key
->key
;
130 CFTypeRef keySize
= CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrKeySizeInBits
);
131 if (CFGetTypeID(keySize
) == CFNumberGetTypeID()) {
133 if (CFNumberGetValue(keySize
, kCFNumberCFIndexType
, &bitSize
))
134 return (bitSize
+ 7) / 8;
140 static OSStatus
SecCTKKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*data
) {
141 OSStatus status
= errSecSuccess
;
142 CFErrorRef error
= NULL
;
143 CFDataRef publicData
= NULL
;
145 SecCTKKeyData
*kd
= key
->key
;
146 require_action_quiet(publicData
= TKTokenCopyPublicKeyData(kd
->token
, kd
->objectID
, &error
), out
,
147 status
= SecErrorGetOSStatus(error
));
151 CFReleaseSafe(error
);
155 static CFStringRef
SecCTKKeyCopyKeyDescription(SecKeyRef key
) {
156 SecCTKKeyData
*kd
= key
->key
;
157 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecKeyRef:('%@') %p>"),
158 CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrTokenID
), key
);
161 // Attributes allowed to be exported from all internal key attributes.
162 static const CFStringRef
*kSecExportableCTKKeyAttributes
[] = {
166 &kSecAttrIsPermanent
,
168 &kSecAttrIsModifiable
,
170 &kSecAttrKeySizeInBits
,
171 &kSecAttrEffectiveKeySize
,
172 &kSecAttrIsSensitive
,
173 &kSecAttrWasAlwaysSensitive
,
174 &kSecAttrIsExtractable
,
175 &kSecAttrWasNeverExtractable
,
181 &kSecAttrCanSignRecover
,
182 &kSecAttrCanVerifyRecover
,
188 static CFDictionaryRef
SecCTKKeyCopyAttributeDictionary(SecKeyRef key
) {
189 CFMutableDictionaryRef attrs
= NULL
;
190 CFErrorRef error
= NULL
;
191 CFDataRef publicData
= NULL
, digest
= NULL
;
192 SecCTKKeyData
*kd
= key
->key
;
194 // Encode ApplicationLabel as SHA1 digest of public key bytes.
195 require_quiet(publicData
= TKTokenCopyPublicKeyData(kd
->token
, kd
->objectID
, &error
), out
);
197 /* Calculate the digest of the public key. */
198 require(digest
= SecSHA1DigestCreate(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
)), out
);
199 attrs
= CFDictionaryCreateMutableForCFTypes(CFGetAllocator(key
));
200 CFDictionarySetValue(attrs
, kSecAttrApplicationLabel
, digest
);
202 for (const CFStringRef
**attrKey
= &kSecExportableCTKKeyAttributes
[0]; *attrKey
!= NULL
; attrKey
++) {
203 CFTypeRef value
= CFDictionaryGetValue(kd
->attributes
.dictionary
, **attrKey
);
205 CFDictionarySetValue(attrs
, **attrKey
, value
);
210 CFReleaseSafe(error
);
211 CFReleaseSafe(publicData
);
212 CFReleaseSafe(digest
);
216 SecKeyDescriptor kSecCTKKeyDescriptor
= {
217 kSecKeyDescriptorVersion
,
219 sizeof(SecCTKKeyData
),
223 NULL
, // SecKeyRawVerifyMethod
224 NULL
, // SecKeyEncryptMethod
225 NULL
, // SecKeyRawDecrypt
226 NULL
, // SecKeyComputeMethod
228 SecCTKKeyCopyAttributeDictionary
,
229 SecCTKKeyCopyKeyDescription
,
230 SecCTKGetAlgorithmID
,
231 SecCTKKeyCopyPublicOctets
,
232 NULL
, // SecKeyCopyWrapKey
233 NULL
, // SecKeyCopyUnwrapKey
236 SecKeyRef
SecKeyCreateCTKKey(CFAllocatorRef allocator
, CFDictionaryRef refAttributes
) {
237 SecKeyRef key
= SecKeyCreate(allocator
, &kSecCTKKeyDescriptor
, 0, 0, 0);
238 SecCTKKeyData
*kd
= key
->key
;
239 kd
->token
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseToken
));
240 kd
->objectID
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseTokenObjectID
));
241 kd
->token_id
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecAttrTokenID
));
242 kd
->attributes
.dictionary
= refAttributes
;
243 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseToken
);
244 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseTokenObjectID
);
245 SecItemAuthCopyParams(&kd
->auth_params
, &kd
->attributes
);
249 OSStatus
SecCTKKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
251 CFMutableDictionaryRef attrs
= NULL
;
252 CFDictionaryRef keyAttrs
= NULL
;
253 CFDataRef publicData
= NULL
;
255 require_action_quiet(publicKey
!= NULL
, out
, status
= errSecParam
);
256 require_action_quiet(privateKey
!= NULL
, out
, status
= errSecParam
);
258 // Simply adding key on the token without value will cause the token to generate the key and automatically
259 // add it to the keychain. Prepare dictionary specifying item to add.
260 keyAttrs
= CFDictionaryGetValue(parameters
, kSecPrivateKeyAttrs
);
261 attrs
= (keyAttrs
== NULL
) ? CFDictionaryCreateMutableForCFTypes(NULL
) : CFDictionaryCreateMutableCopy(NULL
, 0, keyAttrs
);
263 CFDictionaryForEach(parameters
, ^(const void *key
, const void *value
) {
264 if (!CFEqual(key
, kSecPrivateKeyAttrs
) && !CFEqual(key
, kSecPublicKeyAttrs
)) {
265 CFDictionarySetValue(attrs
, key
, value
);
268 CFDictionaryRemoveValue(attrs
, kSecValueData
);
269 CFDictionarySetValue(attrs
, kSecClass
, kSecClassKey
);
270 CFDictionarySetValue(attrs
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
271 CFDictionarySetValue(attrs
, kSecReturnRef
, kCFBooleanTrue
);
273 // Add key from given attributes to the token (having no data will cause the token to actually generate the key).
274 require_noerr_quiet(status
= SecItemAdd(attrs
, (CFTypeRef
*)privateKey
), out
);
276 // Create non-token public key.
277 require_noerr_quiet(status
= SecCTKKeyCopyPublicOctets(*privateKey
, &publicData
), out
);
278 if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeEC
)) {
279 *publicKey
= SecKeyCreateECPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
280 kSecKeyEncodingBytes
);
281 } else if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeRSA
)) {
282 *publicKey
= SecKeyCreateRSAPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
283 kSecKeyEncodingBytes
);
286 if (*publicKey
!= NULL
) {
287 status
= errSecSuccess
;
289 status
= errSecInvalidKey
;
290 CFReleaseNull(*privateKey
);
294 CFReleaseSafe(attrs
);
295 CFReleaseSafe(publicData
);