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>
36 #if TKTOKEN_CLIENT_INTERFACE_VERSION <= 1
37 #define kTKTokenCreateAttributeAuxParams "auxParams"
41 #include "SecRSAKey.h"
42 #include "SecCTKKeyPriv.h"
44 const CFStringRef kSecUseToken
= CFSTR("u_Token");
45 const CFStringRef kSecUseTokenObjectID
= CFSTR("u_TokenOID");
51 SecCFDictionaryCOW auth_params
;
52 SecCFDictionaryCOW attributes
;
53 CFMutableDictionaryRef params
;
56 static void SecCTKKeyDestroy(SecKeyRef key
) {
57 SecCTKKeyData
*kd
= key
->key
;
58 CFReleaseSafe(kd
->token
);
59 CFReleaseSafe(kd
->token_id
);
60 CFReleaseSafe(kd
->objectID
);
61 CFReleaseSafe(kd
->auth_params
.mutable_dictionary
);
62 CFReleaseSafe(kd
->attributes
.mutable_dictionary
);
63 CFReleaseSafe(kd
->params
);
66 static CFIndex
SecCTKGetAlgorithmID(SecKeyRef key
) {
67 SecCTKKeyData
*kd
= key
->key
;
68 CFTypeRef type
= CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrKeyType
);
70 if (CFGetTypeID(type
) == CFNumberGetTypeID()) {
72 if (CFNumberGetValue(type
, kCFNumberCFIndexType
, &keyType
) && keyType
== 73 /* kSecAttrKeyTypeEC */)
73 return kSecECDSAAlgorithmID
;
74 } else if (CFGetTypeID(type
) == CFStringGetTypeID() && CFEqual(type
, kSecAttrKeyTypeEC
)) {
75 return kSecECDSAAlgorithmID
;
78 return kSecRSAAlgorithmID
;
81 static SecItemAuthResult
SecCTKProcessError(CFStringRef operation
, TKTokenRef token
, CFDataRef object_id
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
82 if (CFEqualSafe(CFErrorGetDomain(*error
), CFSTR(kTKErrorDomain
)) &&
83 CFErrorGetCode(*error
) == kTKErrorCodeAuthenticationFailed
) {
84 CFDataRef access_control
= TKTokenCopyObjectAccessControl(token
, object_id
, error
);
85 if (access_control
!= NULL
) {
86 CFArrayRef ac_pair
= CFArrayCreateForCFTypes(NULL
, access_control
, operation
, NULL
);
87 CFAssignRetained(*ac_pairs
, CFArrayCreateForCFTypes(NULL
, ac_pair
, NULL
));
89 CFReleaseNull(*error
);
91 CFRelease(access_control
);
92 return kSecItemAuthResultNeedAuth
;
95 return kSecItemAuthResultError
;
98 static const CFTypeRef
*aclOperations
[] = {
99 [kSecKeyOperationTypeSign
] = &kAKSKeyOpSign
,
100 [kSecKeyOperationTypeDecrypt
] = &kAKSKeyOpDecrypt
,
101 [kSecKeyOperationTypeKeyExchange
] = &kAKSKeyOpComputeKey
,
104 static CFTypeRef
SecCTKKeyCopyOperationResult(SecKeyRef key
, SecKeyOperationType operation
, SecKeyAlgorithm algorithm
,
105 CFArrayRef algorithms
, SecKeyOperationMode mode
,
106 CFTypeRef in1
, CFTypeRef in2
, CFErrorRef
*error
) {
107 SecCTKKeyData
*kd
= key
->key
;
108 __block SecCFDictionaryCOW auth_params
= { kd
->auth_params
.dictionary
};
109 __block TKTokenRef token
= CFRetainSafe(kd
->token
);
110 __block CFTypeRef result
= kCFNull
;
112 CFErrorRef localError
= NULL
;
113 SecItemAuthDo(&auth_params
, &localError
, ^SecItemAuthResult(CFDictionaryRef ap
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
114 if (auth_params
.mutable_dictionary
!= NULL
|| token
== NULL
|| kd
->params
!= NULL
) {
115 // token was not connected yet or auth_params were modified, so reconnect the token in order to update the attributes.
116 SecCFDictionaryCOW attributes
= { ap
};
117 if (kd
->params
&& CFDictionaryGetCount(kd
->params
) > 0) {
118 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attributes
), CFSTR(kTKTokenCreateAttributeAuxParams
), kd
->params
);
120 CFAssignRetained(token
, SecTokenCreate(kd
->token_id
, attributes
.dictionary
, error
));
121 CFReleaseSafe(attributes
.mutable_dictionary
);
123 return kSecItemAuthResultError
;
127 #if TKTOKEN_CLIENT_INTERFACE_VERSION >= 1
128 result
= TKTokenCopyOperationResult(token
, kd
->objectID
, operation
, algorithms
, mode
, in1
, in2
, error
);
130 result
= TKTokenCopyCryptoResult(token
, kd
->objectID
, operation
, (CFIndex
)algorithm
, in1
, in2
, error
);
132 return (result
!= NULL
) ? kSecItemAuthResultOK
: SecCTKProcessError(*aclOperations
[operation
], token
,
133 kd
->objectID
, ac_pairs
, error
);
136 CFErrorPropagate(localError
, error
);
137 CFReleaseSafe(auth_params
.mutable_dictionary
);
138 CFReleaseSafe(token
);
142 static size_t SecCTKKeyBlockSize(SecKeyRef key
) {
143 SecCTKKeyData
*kd
= key
->key
;
144 CFTypeRef keySize
= CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrKeySizeInBits
);
145 if (CFGetTypeID(keySize
) == CFNumberGetTypeID()) {
147 if (CFNumberGetValue(keySize
, kCFNumberCFIndexType
, &bitSize
))
148 return (bitSize
+ 7) / 8;
154 static OSStatus
SecCTKKeyCopyPublicOctets(SecKeyRef key
, CFDataRef
*data
) {
155 OSStatus status
= errSecSuccess
;
156 CFErrorRef error
= NULL
;
157 CFDataRef publicData
= NULL
;
159 SecCTKKeyData
*kd
= key
->key
;
160 require_action_quiet(publicData
= TKTokenCopyPublicKeyData(kd
->token
, kd
->objectID
, &error
), out
,
161 status
= SecErrorGetOSStatus(error
));
165 CFReleaseSafe(error
);
169 static CFStringRef
SecCTKKeyCopyKeyDescription(SecKeyRef key
) {
170 SecCTKKeyData
*kd
= key
->key
;
171 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<SecKeyRef:('%@') %p>"),
172 CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrTokenID
), key
);
175 // Attributes allowed to be exported from all internal key attributes.
176 static const CFStringRef
*kSecExportableCTKKeyAttributes
[] = {
180 &kSecAttrIsPermanent
,
182 &kSecAttrIsModifiable
,
184 &kSecAttrKeySizeInBits
,
185 &kSecAttrEffectiveKeySize
,
186 &kSecAttrIsSensitive
,
187 &kSecAttrWasAlwaysSensitive
,
188 &kSecAttrIsExtractable
,
189 &kSecAttrWasNeverExtractable
,
195 &kSecAttrCanSignRecover
,
196 &kSecAttrCanVerifyRecover
,
202 static CFDictionaryRef
SecCTKKeyCopyAttributeDictionary(SecKeyRef key
) {
203 CFMutableDictionaryRef attrs
= NULL
;
204 CFErrorRef error
= NULL
;
205 CFDataRef publicData
= NULL
, digest
= NULL
;
206 SecCTKKeyData
*kd
= key
->key
;
208 // Encode ApplicationLabel as SHA1 digest of public key bytes.
209 require_quiet(publicData
= TKTokenCopyPublicKeyData(kd
->token
, kd
->objectID
, &error
), out
);
211 /* Calculate the digest of the public key. */
212 require(digest
= SecSHA1DigestCreate(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
)), out
);
213 attrs
= CFDictionaryCreateMutableForCFTypes(CFGetAllocator(key
));
214 CFDictionarySetValue(attrs
, kSecAttrApplicationLabel
, digest
);
216 for (const CFStringRef
**attrKey
= &kSecExportableCTKKeyAttributes
[0]; *attrKey
!= NULL
; attrKey
++) {
217 CFTypeRef value
= CFDictionaryGetValue(kd
->attributes
.dictionary
, **attrKey
);
219 CFDictionarySetValue(attrs
, **attrKey
, value
);
224 CFReleaseSafe(error
);
225 CFReleaseSafe(publicData
);
226 CFReleaseSafe(digest
);
230 static SecKeyDescriptor kSecCTKKeyDescriptor
= {
231 .version
= kSecKeyDescriptorVersion
,
233 .extraBytes
= sizeof(SecCTKKeyData
),
235 .destroy
= SecCTKKeyDestroy
,
236 .blockSize
= SecCTKKeyBlockSize
,
237 .copyDictionary
= SecCTKKeyCopyAttributeDictionary
,
238 .describe
= SecCTKKeyCopyKeyDescription
,
239 .getAlgorithmID
= SecCTKGetAlgorithmID
,
240 .copyPublic
= SecCTKKeyCopyPublicOctets
,
241 .copyOperationResult
= SecCTKKeyCopyOperationResult
,
244 SecKeyRef
SecKeyCreateCTKKey(CFAllocatorRef allocator
, CFDictionaryRef refAttributes
, CFErrorRef
*error
) {
245 SecKeyRef key
= SecKeyCreate(allocator
, &kSecCTKKeyDescriptor
, 0, 0, 0);
246 SecCTKKeyData
*kd
= key
->key
;
247 kd
->token
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseToken
));
248 kd
->objectID
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseTokenObjectID
));
249 kd
->token_id
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecAttrTokenID
));
250 kd
->attributes
.dictionary
= refAttributes
;
251 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseToken
);
252 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseTokenObjectID
);
253 SecItemAuthCopyParams(&kd
->auth_params
, &kd
->attributes
);
254 if (CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrIsPrivate
) == NULL
) {
255 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecAttrIsPrivate
, kCFBooleanTrue
);
260 OSStatus
SecCTKKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
262 CFMutableDictionaryRef attrs
= NULL
;
263 CFDictionaryRef keyAttrs
= NULL
;
264 CFDataRef publicData
= NULL
;
266 require_action_quiet(publicKey
!= NULL
, out
, status
= errSecParam
);
267 require_action_quiet(privateKey
!= NULL
, out
, status
= errSecParam
);
269 // Simply adding key on the token without value will cause the token to generate the key and automatically
270 // add it to the keychain. Prepare dictionary specifying item to add.
271 keyAttrs
= CFDictionaryGetValue(parameters
, kSecPrivateKeyAttrs
);
272 attrs
= (keyAttrs
== NULL
) ? CFDictionaryCreateMutableForCFTypes(NULL
) : CFDictionaryCreateMutableCopy(NULL
, 0, keyAttrs
);
274 CFDictionaryForEach(parameters
, ^(const void *key
, const void *value
) {
275 if (!CFEqual(key
, kSecPrivateKeyAttrs
) && !CFEqual(key
, kSecPublicKeyAttrs
)) {
276 CFDictionarySetValue(attrs
, key
, value
);
279 CFDictionaryRemoveValue(attrs
, kSecValueData
);
280 CFDictionarySetValue(attrs
, kSecClass
, kSecClassKey
);
281 CFDictionarySetValue(attrs
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
282 CFDictionarySetValue(attrs
, kSecReturnRef
, kCFBooleanTrue
);
284 // Add key from given attributes to the token (having no data will cause the token to actually generate the key).
285 require_noerr_quiet(status
= SecItemAdd(attrs
, (CFTypeRef
*)privateKey
), out
);
287 // Create non-token public key.
288 require_noerr_quiet(status
= SecCTKKeyCopyPublicOctets(*privateKey
, &publicData
), out
);
289 if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeEC
)) {
290 *publicKey
= SecKeyCreateECPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
291 kSecKeyEncodingBytes
);
292 } else if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeRSA
)) {
293 *publicKey
= SecKeyCreateRSAPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
294 kSecKeyEncodingBytes
);
297 if (*publicKey
!= NULL
) {
298 status
= errSecSuccess
;
300 status
= errSecInvalidKey
;
301 CFReleaseNull(*privateKey
);
305 CFReleaseSafe(attrs
);
306 CFReleaseSafe(publicData
);
310 SecKeyRef
SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType
, CFErrorRef
*error
) {
311 if (keyType
!= kSecKeyAttestationKeyTypeSIK
&& keyType
!= kSecKeyAttestationKeyTypeGID
) {
312 SecError(errSecParam
, error
, CFSTR("unexpected attestation key type %u"), (unsigned)keyType
);
316 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.sik" dataUsingEncoding:NSUTF8StringEncoding]];
317 static const uint8_t sikObjectIDBytes
[] = {
318 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
319 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
320 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
321 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
322 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
323 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
324 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x73, 0x69, 0x6b, 0x80, 0x02, 0xd2,
325 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
326 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
327 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
328 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
329 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
330 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
331 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
332 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
333 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
336 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.gid" dataUsingEncoding:NSUTF8StringEncoding]];
337 static const uint8_t gidObjectIDBytes
[] = {
338 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
339 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
340 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
341 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
342 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
343 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
344 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x67, 0x69, 0x64, 0x80, 0x02, 0xd2,
345 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
346 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
347 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
348 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
349 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
350 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
351 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
352 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
356 CFDataRef objectID
= (keyType
== kSecKeyAttestationKeyTypeSIK
) ?
357 CFDataCreate(kCFAllocatorDefault
, sikObjectIDBytes
, sizeof(sikObjectIDBytes
)) :
358 CFDataCreate(kCFAllocatorDefault
, gidObjectIDBytes
, sizeof(gidObjectIDBytes
)) ;
360 const void *keys
[] = { kSecUseToken
, kSecUseTokenObjectID
, kSecAttrTokenID
};
361 const void *values
[] = { kCFNull
, objectID
, CFSTR("com.apple.setoken.attest") };
363 CFDictionaryRef attributes
= CFDictionaryCreate(kCFAllocatorDefault
,
364 keys
, values
, sizeof(keys
) / sizeof(*keys
),
365 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
367 return SecKeyCreateCTKKey(kCFAllocatorDefault
, attributes
, error
);
370 CFDataRef
SecKeyCreateAttestation(SecKeyRef key
, SecKeyRef keyToAttest
, CFErrorRef
*error
) {
371 if (!key
|| !keyToAttest
) {
372 SecError(errSecParam
, error
, CFSTR("attestation key(s) is NULL"));
376 SecCTKKeyData
*attestingKeyData
= key
->key
;
377 SecCTKKeyData
*keyToAttestData
= keyToAttest
->key
;
379 if (key
->key_class
!= &kSecCTKKeyDescriptor
) {
380 SecError(errSecUnsupportedOperation
, error
, CFSTR("attestation not supported by key %@"), key
);
383 if (keyToAttest
->key_class
!= &kSecCTKKeyDescriptor
|| CFEqual(keyToAttestData
->token
, kCFNull
)) {
384 SecError(errSecUnsupportedOperation
, error
, CFSTR("attestation not supported for key %@"), keyToAttest
);
388 const void *keys
[] = {
389 CFSTR(kTKTokenControlAttribAttestingKey
),
390 CFSTR(kTKTokenControlAttribKeyToAttest
),
392 const void *values
[] = {
393 attestingKeyData
->objectID
,
394 keyToAttestData
->objectID
397 CFDictionaryRef attributes
= NULL
;
398 __block CFDictionaryRef outputAttributes
= NULL
;
399 CFDataRef attestationData
= NULL
;
400 __block SecCFDictionaryCOW sign_auth_params
= { keyToAttestData
->auth_params
.dictionary
};
402 attributes
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
) / sizeof(*keys
),
403 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
405 SecItemAuthDo(&sign_auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
406 outputAttributes
= TKTokenControl(keyToAttestData
->token
, attributes
, error
);
407 return outputAttributes
? kSecItemAuthResultOK
: SecCTKProcessError(kAKSKeyOpAttest
, keyToAttestData
->token
, keyToAttestData
->objectID
, ac_pairs
, error
);
409 require(outputAttributes
, out
);
411 attestationData
= CFDictionaryGetValue(outputAttributes
, CFSTR(kTKTokenControlAttribAttestationData
));
412 require_action(attestationData
, out
, SecError(errSecInternal
, error
, CFSTR("could not get attestation data")));
414 if (CFGetTypeID(attestationData
) != CFDataGetTypeID()) {
415 SecError(errSecInternal
, error
, CFSTR("unexpected attestation object type"));
416 attestationData
= NULL
;
419 CFRetainSafe(attestationData
);
422 CFReleaseSafe(attributes
);
423 CFReleaseSafe(outputAttributes
);
424 return attestationData
;
427 Boolean
SecKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
428 require_action_quiet(key
->key_class
== &kSecCTKKeyDescriptor
, out
,
429 SecError(errSecUnimplemented
, error
, CFSTR("SecKeySetParameter() not supported for key %@"), key
));
430 SecCTKKeyData
*kd
= key
->key
;
431 if (kd
->params
== NULL
) {
432 kd
->params
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
435 CFDictionarySetValue(kd
->params
, name
, value
);
437 CFDictionaryRemoveValue(kd
->params
, name
);