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 <utilities/array_size.h>
34 #include <ctkclient.h>
35 #include <libaks_acl_cf_keys.h>
37 #if TKTOKEN_CLIENT_INTERFACE_VERSION <= 1
38 #define kTKTokenCreateAttributeAuxParams "auxParams"
42 #include "SecRSAKey.h"
43 #include "SecCTKKeyPriv.h"
45 const CFStringRef kSecUseToken
= CFSTR("u_Token");
46 const CFStringRef kSecUseTokenObjectID
= CFSTR("u_TokenOID");
52 SecCFDictionaryCOW auth_params
;
53 SecCFDictionaryCOW attributes
;
54 CFMutableDictionaryRef params
;
57 static void SecCTKKeyDestroy(SecKeyRef key
) {
58 SecCTKKeyData
*kd
= key
->key
;
59 CFReleaseSafe(kd
->token
);
60 CFReleaseSafe(kd
->token_id
);
61 CFReleaseSafe(kd
->objectID
);
62 CFReleaseSafe(kd
->auth_params
.mutable_dictionary
);
63 CFReleaseSafe(kd
->attributes
.mutable_dictionary
);
64 CFReleaseSafe(kd
->params
);
67 static CFIndex
SecCTKGetAlgorithmID(SecKeyRef key
) {
68 SecCTKKeyData
*kd
= key
->key
;
69 CFTypeRef type
= CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrKeyType
);
71 if (CFGetTypeID(type
) == CFNumberGetTypeID()) {
73 if (CFNumberGetValue(type
, kCFNumberCFIndexType
, &keyType
) && keyType
== 73 /* kSecAttrKeyTypeEC */)
74 return kSecECDSAAlgorithmID
;
75 } else if (CFGetTypeID(type
) == CFStringGetTypeID() && CFEqual(type
, kSecAttrKeyTypeEC
)) {
76 return kSecECDSAAlgorithmID
;
79 return kSecRSAAlgorithmID
;
82 static SecItemAuthResult
SecCTKProcessError(CFStringRef operation
, TKTokenRef token
, CFDataRef object_id
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
83 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
84 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
85 CFDataRef access_control
= TKTokenCopyObjectAccessControl(token
, object_id
, error
);
86 if (access_control
!= NULL
) {
87 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
88 CFAssignRetained(*ac_pairs
, CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
));
90 CFReleaseNull(*error
);
92 CFRelease(access_control
);
93 return kSecItemAuthResultNeedAuth
;
96 return kSecItemAuthResultError
;
99 static const CFTypeRef
*aclOperations
[] = {
100 [kSecKeyOperationTypeSign
] = &kAKSKeyOpSign
,
101 [kSecKeyOperationTypeDecrypt
] = &kAKSKeyOpDecrypt
,
102 [kSecKeyOperationTypeKeyExchange
] = &kAKSKeyOpComputeKey
,
105 static CFTypeRef
SecCTKKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
106 CFArrayRef algorithms
, SecKeyOperationMode mode
,
107 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
108 SecCTKKeyData
*kd
= key
->key
;
109 __block SecCFDictionaryCOW auth_params
= { kd
->auth_params
.dictionary
};
110 __block TKTokenRef token
= CFRetainSafe(kd
->token
);
111 __block CFTypeRef result
= kCFNull
;
113 CFErrorRef localError
= NULL
;
114 SecItemAuthDo(&auth_params
, &localError
, ^SecItemAuthResult(CFDictionaryRef ap
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
115 if (auth_params
.mutable_dictionary
!= NULL
|| token
== NULL
|| kd
->params
!= NULL
) {
116 // token was not connected yet or auth_params were modified, so reconnect the token in order to update the attributes.
117 SecCFDictionaryCOW attributes
= { ap
};
118 if (kd
->params
&& CFDictionaryGetCount(kd
->params
) > 0) {
119 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attributes
), CFSTR(kTKTokenCreateAttributeAuxParams
), kd
->params
);
121 CFAssignRetained(token
, SecTokenCreate(kd
->token_id
, attributes
.dictionary
, error
));
122 CFReleaseSafe(attributes
.mutable_dictionary
);
124 return kSecItemAuthResultError
;
128 #if TKTOKEN_CLIENT_INTERFACE_VERSION >= 1
129 result
= TKTokenCopyOperationResult(token
, kd
->objectID
, operation
, algorithms
, mode
, in1
, in2
, error
);
131 result
= TKTokenCopyCryptoResult(token
, kd
->objectID
, operation
, (CFIndex
)algorithm
, in1
, in2
, error
);
133 return (result
!= NULL
) ? kSecItemAuthResultOK
: SecCTKProcessError(*aclOperations
[operation
], token
,
134 kd
->objectID
, ac_pairs
, error
);
137 CFErrorPropagate(localError
, error
);
138 CFReleaseSafe(auth_params
.mutable_dictionary
);
139 CFReleaseSafe(token
);
143 static size_t SecCTKKeyBlockSize(SecKeyRef key
) {
144 SecCTKKeyData
*kd
= key
->key
;
145 CFTypeRef keySize
= CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrKeySizeInBits
);
146 if (CFGetTypeID(keySize
) == CFNumberGetTypeID()) {
148 if (CFNumberGetValue(keySize
, kCFNumberCFIndexType
, &bitSize
))
149 return (bitSize
+ 7) / 8;
155 static OSStatus
SecCTKKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*data
) {
156 OSStatus status
= errSecSuccess
;
157 CFErrorRef error
= NULL
;
158 CFDataRef publicData
= NULL
;
160 SecCTKKeyData
*kd
= key
->key
;
161 require_action_quiet(publicData
= TKTokenCopyPublicKeyData(kd
->token
, kd
->objectID
, &error
), out
,
162 status
= SecErrorGetOSStatus(error
));
166 CFReleaseSafe(error
);
170 static CFStringRef
SecCTKKeyCopyKeyDescription(SecKeyRef key
) {
171 SecCTKKeyData
*kd
= key
->key
;
172 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecKeyRef:('%@') %p>"),
173 CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrTokenID
), key
);
176 // Attributes allowed to be exported from all internal key attributes.
177 static const CFStringRef
*kSecExportableCTKKeyAttributes
[] = {
181 &kSecAttrIsPermanent
,
183 &kSecAttrIsModifiable
,
185 &kSecAttrKeySizeInBits
,
186 &kSecAttrEffectiveKeySize
,
187 &kSecAttrIsSensitive
,
188 &kSecAttrWasAlwaysSensitive
,
189 &kSecAttrIsExtractable
,
190 &kSecAttrWasNeverExtractable
,
196 &kSecAttrCanSignRecover
,
197 &kSecAttrCanVerifyRecover
,
203 static CFDictionaryRef
SecCTKKeyCopyAttributeDictionary(SecKeyRef key
) {
204 CFMutableDictionaryRef attrs
= NULL
;
205 CFErrorRef error
= NULL
;
206 CFDataRef publicData
= NULL
, digest
= NULL
;
207 SecCTKKeyData
*kd
= key
->key
;
209 // Encode ApplicationLabel as SHA1 digest of public key bytes.
210 require_quiet(publicData
= TKTokenCopyPublicKeyData(kd
->token
, kd
->objectID
, &error
), out
);
212 /* Calculate the digest of the public key. */
213 require(digest
= SecSHA1DigestCreate(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
)), out
);
214 attrs
= CFDictionaryCreateMutableForCFTypes(CFGetAllocator(key
));
215 CFDictionarySetValue(attrs
, kSecAttrApplicationLabel
, digest
);
217 for (const CFStringRef
**attrKey
= &kSecExportableCTKKeyAttributes
[0]; *attrKey
!= NULL
; attrKey
++) {
218 CFTypeRef value
= CFDictionaryGetValue(kd
->attributes
.dictionary
, **attrKey
);
220 CFDictionarySetValue(attrs
, **attrKey
, value
);
225 CFReleaseSafe(error
);
226 CFReleaseSafe(publicData
);
227 CFReleaseSafe(digest
);
231 static SecKeyRef
SecCTKKeyCreateDuplicate(SecKeyRef key
);
233 static SecKeyDescriptor kSecCTKKeyDescriptor
= {
234 .version
= kSecKeyDescriptorVersion
,
236 .extraBytes
= sizeof(SecCTKKeyData
),
238 .destroy
= SecCTKKeyDestroy
,
239 .blockSize
= SecCTKKeyBlockSize
,
240 .copyDictionary
= SecCTKKeyCopyAttributeDictionary
,
241 .describe
= SecCTKKeyCopyKeyDescription
,
242 .getAlgorithmID
= SecCTKGetAlgorithmID
,
243 .copyPublic
= SecCTKKeyCopyPublicOctets
,
244 .copyOperationResult
= SecCTKKeyCopyOperationResult
,
245 .createDuplicate
= SecCTKKeyCreateDuplicate
,
248 static SecKeyRef
SecCTKKeyCreateDuplicate(SecKeyRef key
) {
249 SecKeyRef result
= SecKeyCreate(CFGetAllocator(key
), &kSecCTKKeyDescriptor
, 0, 0, 0);
250 SecCTKKeyData
*kd
= key
->key
, *rd
= result
->key
;
251 rd
->token
= CFRetainSafe(kd
->token
);
252 rd
->objectID
= CFRetainSafe(kd
->objectID
);
253 rd
->token_id
= CFRetainSafe(kd
->token_id
);
254 if (kd
->attributes
.dictionary
!= NULL
) {
255 rd
->attributes
.dictionary
= kd
->attributes
.dictionary
;
256 SecCFDictionaryCOWGetMutable(&rd
->attributes
);
258 if (kd
->auth_params
.dictionary
!= NULL
) {
259 rd
->auth_params
.dictionary
= kd
->auth_params
.dictionary
;
260 SecCFDictionaryCOWGetMutable(&rd
->auth_params
);
265 SecKeyRef
SecKeyCreateCTKKey(CFAllocatorRef allocator
, CFDictionaryRef refAttributes
, CFErrorRef
*error
) {
266 SecKeyRef key
= SecKeyCreate(allocator
, &kSecCTKKeyDescriptor
, 0, 0, 0);
267 SecCTKKeyData
*kd
= key
->key
;
268 kd
->token
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseToken
));
269 kd
->objectID
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseTokenObjectID
));
270 kd
->token_id
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecAttrTokenID
));
271 kd
->attributes
.dictionary
= refAttributes
;
272 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseToken
);
273 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseTokenObjectID
);
274 SecItemAuthCopyParams(&kd
->auth_params
, &kd
->attributes
);
275 if (CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrIsPrivate
) == NULL
) {
276 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecAttrIsPrivate
, kCFBooleanTrue
);
281 OSStatus
SecCTKKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
283 CFMutableDictionaryRef attrs
= NULL
;
284 CFDictionaryRef keyAttrs
= NULL
;
285 CFDataRef publicData
= NULL
;
287 require_action_quiet(publicKey
!= NULL
, out
, status
= errSecParam
);
288 require_action_quiet(privateKey
!= NULL
, out
, status
= errSecParam
);
290 // Simply adding key on the token without value will cause the token to generate the key and automatically
291 // add it to the keychain. Prepare dictionary specifying item to add.
292 keyAttrs
= CFDictionaryGetValue(parameters
, kSecPrivateKeyAttrs
);
293 attrs
= (keyAttrs
== NULL
) ? CFDictionaryCreateMutableForCFTypes(NULL
) : CFDictionaryCreateMutableCopy(NULL
, 0, keyAttrs
);
295 CFDictionaryForEach(parameters
, ^(const void *key
, const void *value
) {
296 if (!CFEqual(key
, kSecPrivateKeyAttrs
) && !CFEqual(key
, kSecPublicKeyAttrs
)) {
297 CFDictionarySetValue(attrs
, key
, value
);
300 CFDictionaryRemoveValue(attrs
, kSecValueData
);
301 CFDictionarySetValue(attrs
, kSecClass
, kSecClassKey
);
302 CFDictionarySetValue(attrs
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
303 CFDictionarySetValue(attrs
, kSecReturnRef
, kCFBooleanTrue
);
305 // Add key from given attributes to the token (having no data will cause the token to actually generate the key).
306 require_noerr_quiet(status
= SecItemAdd(attrs
, (CFTypeRef
*)privateKey
), out
);
308 // Create non-token public key.
309 require_noerr_quiet(status
= SecCTKKeyCopyPublicOctets(*privateKey
, &publicData
), out
);
310 if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeEC
)) {
311 *publicKey
= SecKeyCreateECPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
312 kSecKeyEncodingBytes
);
313 } else if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeRSA
)) {
314 *publicKey
= SecKeyCreateRSAPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
315 kSecKeyEncodingBytes
);
318 if (*publicKey
!= NULL
) {
319 status
= errSecSuccess
;
321 status
= errSecInvalidKey
;
322 CFReleaseNull(*privateKey
);
326 CFReleaseSafe(attrs
);
327 CFReleaseSafe(publicData
);
331 SecKeyRef
SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType
, CFErrorRef
*error
) {
332 if (keyType
!= kSecKeyAttestationKeyTypeSIK
&& keyType
!= kSecKeyAttestationKeyTypeGID
) {
333 SecError(errSecParam
, error
, CFSTR("unexpected attestation key type %u"), (unsigned)keyType
);
337 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.sik" dataUsingEncoding:NSUTF8StringEncoding]];
338 static const uint8_t sikObjectIDBytes
[] = {
339 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
340 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
341 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
342 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
343 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
344 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
345 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x73, 0x69, 0x6b, 0x80, 0x02, 0xd2,
346 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
347 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
348 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
349 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
350 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
351 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
352 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
357 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.gid" dataUsingEncoding:NSUTF8StringEncoding]];
358 static const uint8_t gidObjectIDBytes
[] = {
359 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
360 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
361 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
362 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
363 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
364 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
365 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x67, 0x69, 0x64, 0x80, 0x02, 0xd2,
366 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
367 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
368 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
369 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
370 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
371 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
372 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
373 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
374 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
377 CFDataRef objectID
= (keyType
== kSecKeyAttestationKeyTypeSIK
) ?
378 CFDataCreate(kCFAllocatorDefault
, sikObjectIDBytes
, sizeof(sikObjectIDBytes
)) :
379 CFDataCreate(kCFAllocatorDefault
, gidObjectIDBytes
, sizeof(gidObjectIDBytes
)) ;
381 const void *keys
[] = { kSecUseToken
, kSecUseTokenObjectID
, kSecAttrTokenID
};
382 const void *values
[] = { kCFNull
, objectID
, CFSTR("com.apple.setoken.attest") };
384 CFDictionaryRef attributes
= CFDictionaryCreate(kCFAllocatorDefault
,
385 keys
, values
, sizeof(keys
) / sizeof(*keys
),
386 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
388 return SecKeyCreateCTKKey(kCFAllocatorDefault
, attributes
, error
);
391 CFDataRef
SecKeyCreateAttestation(SecKeyRef key
, SecKeyRef keyToAttest
, CFErrorRef
*error
) {
392 if (!key
|| !keyToAttest
) {
393 SecError(errSecParam
, error
, CFSTR("attestation key(s) is NULL"));
397 SecCTKKeyData
*attestingKeyData
= key
->key
;
398 SecCTKKeyData
*keyToAttestData
= keyToAttest
->key
;
400 if (key
->key_class
!= &kSecCTKKeyDescriptor
) {
401 SecError(errSecUnsupportedOperation
, error
, CFSTR("attestation not supported by key %@"), key
);
404 if (keyToAttest
->key_class
!= &kSecCTKKeyDescriptor
|| CFEqual(keyToAttestData
->token
, kCFNull
)) {
405 SecError(errSecUnsupportedOperation
, error
, CFSTR("attestation not supported for key %@"), keyToAttest
);
409 const void *keys
[] = {
410 CFSTR(kTKTokenControlAttribAttestingKey
),
411 CFSTR(kTKTokenControlAttribKeyToAttest
),
413 const void *values
[] = {
414 attestingKeyData
->objectID
,
415 keyToAttestData
->objectID
418 CFDictionaryRef attributes
= NULL
;
419 __block CFDictionaryRef outputAttributes
= NULL
;
420 CFDataRef attestationData
= NULL
;
421 __block SecCFDictionaryCOW sign_auth_params
= { keyToAttestData
->auth_params
.dictionary
};
423 attributes
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
) / sizeof(*keys
),
424 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
426 SecItemAuthDo(&sign_auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
427 outputAttributes
= TKTokenControl(keyToAttestData
->token
, attributes
, error
);
428 return outputAttributes
? kSecItemAuthResultOK
: SecCTKProcessError(kAKSKeyOpAttest
, keyToAttestData
->token
, keyToAttestData
->objectID
, ac_pairs
, error
);
430 require(outputAttributes
, out
);
432 attestationData
= CFDictionaryGetValue(outputAttributes
, CFSTR(kTKTokenControlAttribAttestationData
));
433 require_action(attestationData
, out
, SecError(errSecInternal
, error
, CFSTR("could not get attestation data")));
435 if (CFGetTypeID(attestationData
) != CFDataGetTypeID()) {
436 SecError(errSecInternal
, error
, CFSTR("unexpected attestation object type"));
437 attestationData
= NULL
;
440 CFRetainSafe(attestationData
);
443 CFReleaseSafe(attributes
);
444 CFReleaseSafe(outputAttributes
);
445 return attestationData
;
448 Boolean
SecKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
449 CFTypeRef acm_reference
= NULL
;
450 require_action_quiet(key
->key_class
== &kSecCTKKeyDescriptor
, out
,
451 SecError(errSecUnimplemented
, error
, CFSTR("SecKeySetParameter() not supported for key %@"), key
));
452 SecCTKKeyData
*kd
= key
->key
;
454 static const CFStringRef
*const knownUseFlags
[] = {
455 &kSecUseOperationPrompt
,
456 &kSecUseAuthenticationContext
,
457 &kSecUseAuthenticationUI
,
459 &kSecUseCredentialReference
,
462 // Check, whether name is part of known use flags.
463 bool isUseFlag
= false;
464 for (size_t i
= 0; i
< array_size(knownUseFlags
); i
++) {
465 if (CFEqual(*knownUseFlags
[i
], name
)) {
471 if (CFEqual(name
, kSecUseAuthenticationContext
)) {
472 // Preprocess LAContext to ACMRef value.
474 require_quiet(acm_reference
= SecItemAttributesCopyPreparedAuthContext(value
, error
), out
);
475 value
= acm_reference
;
477 name
= kSecUseCredentialReference
;
481 // Release existing token connection to enforce creation of new connection with new auth params.
482 CFReleaseNull(kd
->token
);
484 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd
->auth_params
), name
, value
);
486 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->auth_params
), name
);
489 if (kd
->params
== NULL
) {
490 kd
->params
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
493 CFDictionarySetValue(kd
->params
, name
, value
);
495 CFDictionaryRemoveValue(kd
->params
, name
);
500 CFReleaseSafe(acm_reference
);