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 Boolean
SecCTKKeySetParameter(SecKeyRef key
, CFStringRef name
, CFPropertyListRef value
, CFErrorRef
*error
) {
234 SecCTKKeyData
*kd
= key
->key
;
235 CFTypeRef acm_reference
= NULL
;
237 static const CFStringRef
*const knownUseFlags
[] = {
238 &kSecUseOperationPrompt
,
239 &kSecUseAuthenticationContext
,
240 &kSecUseAuthenticationUI
,
242 &kSecUseCredentialReference
,
245 // Check, whether name is part of known use flags.
246 bool isUseFlag
= false;
247 for (size_t i
= 0; i
< array_size(knownUseFlags
); i
++) {
248 if (CFEqual(*knownUseFlags
[i
], name
)) {
254 if (CFEqual(name
, kSecUseAuthenticationContext
)) {
255 // Preprocess LAContext to ACMRef value.
257 require_quiet(acm_reference
= SecItemAttributesCopyPreparedAuthContext(value
, error
), out
);
258 value
= acm_reference
;
260 name
= kSecUseCredentialReference
;
264 // Release existing token connection to enforce creation of new connection with new auth params.
265 CFReleaseNull(kd
->token
);
267 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd
->auth_params
), name
, value
);
269 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->auth_params
), name
);
272 if (kd
->params
== NULL
) {
273 kd
->params
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
276 CFDictionarySetValue(kd
->params
, name
, value
);
278 CFDictionaryRemoveValue(kd
->params
, name
);
283 CFReleaseSafe(acm_reference
);
287 static SecKeyDescriptor kSecCTKKeyDescriptor
= {
288 .version
= kSecKeyDescriptorVersion
,
290 .extraBytes
= sizeof(SecCTKKeyData
),
292 .destroy
= SecCTKKeyDestroy
,
293 .blockSize
= SecCTKKeyBlockSize
,
294 .copyDictionary
= SecCTKKeyCopyAttributeDictionary
,
295 .describe
= SecCTKKeyCopyKeyDescription
,
296 .getAlgorithmID
= SecCTKGetAlgorithmID
,
297 .copyPublic
= SecCTKKeyCopyPublicOctets
,
298 .copyOperationResult
= SecCTKKeyCopyOperationResult
,
299 .createDuplicate
= SecCTKKeyCreateDuplicate
,
300 .setParameter
= SecCTKKeySetParameter
,
303 static SecKeyRef
SecCTKKeyCreateDuplicate(SecKeyRef key
) {
304 SecKeyRef result
= SecKeyCreate(CFGetAllocator(key
), &kSecCTKKeyDescriptor
, 0, 0, 0);
305 SecCTKKeyData
*kd
= key
->key
, *rd
= result
->key
;
306 rd
->token
= CFRetainSafe(kd
->token
);
307 rd
->objectID
= CFRetainSafe(kd
->objectID
);
308 rd
->token_id
= CFRetainSafe(kd
->token_id
);
309 if (kd
->attributes
.dictionary
!= NULL
) {
310 rd
->attributes
.dictionary
= kd
->attributes
.dictionary
;
311 SecCFDictionaryCOWGetMutable(&rd
->attributes
);
313 if (kd
->auth_params
.dictionary
!= NULL
) {
314 rd
->auth_params
.dictionary
= kd
->auth_params
.dictionary
;
315 SecCFDictionaryCOWGetMutable(&rd
->auth_params
);
320 SecKeyRef
SecKeyCreateCTKKey(CFAllocatorRef allocator
, CFDictionaryRef refAttributes
, CFErrorRef
*error
) {
321 SecKeyRef key
= SecKeyCreate(allocator
, &kSecCTKKeyDescriptor
, 0, 0, 0);
322 SecCTKKeyData
*kd
= key
->key
;
323 kd
->token
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseToken
));
324 kd
->objectID
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecUseTokenObjectID
));
325 kd
->token_id
= CFRetainSafe(CFDictionaryGetValue(refAttributes
, kSecAttrTokenID
));
326 kd
->attributes
.dictionary
= refAttributes
;
327 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseToken
);
328 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecUseTokenObjectID
);
329 SecItemAuthCopyParams(&kd
->auth_params
, &kd
->attributes
);
330 if (CFDictionaryGetValue(kd
->attributes
.dictionary
, kSecAttrIsPrivate
) == NULL
) {
331 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd
->attributes
), kSecAttrIsPrivate
, kCFBooleanTrue
);
336 OSStatus
SecCTKKeyGeneratePair(CFDictionaryRef parameters
, SecKeyRef
*publicKey
, SecKeyRef
*privateKey
) {
338 CFMutableDictionaryRef attrs
= NULL
;
339 CFDictionaryRef keyAttrs
= NULL
;
340 CFDataRef publicData
= NULL
;
342 require_action_quiet(publicKey
!= NULL
, out
, status
= errSecParam
);
343 require_action_quiet(privateKey
!= NULL
, out
, status
= errSecParam
);
345 // Simply adding key on the token without value will cause the token to generate the key and automatically
346 // add it to the keychain. Prepare dictionary specifying item to add.
347 keyAttrs
= CFDictionaryGetValue(parameters
, kSecPrivateKeyAttrs
);
348 attrs
= (keyAttrs
== NULL
) ? CFDictionaryCreateMutableForCFTypes(NULL
) : CFDictionaryCreateMutableCopy(NULL
, 0, keyAttrs
);
350 CFDictionaryForEach(parameters
, ^(const void *key
, const void *value
) {
351 if (!CFEqual(key
, kSecPrivateKeyAttrs
) && !CFEqual(key
, kSecPublicKeyAttrs
)) {
352 CFDictionarySetValue(attrs
, key
, value
);
355 CFDictionaryRemoveValue(attrs
, kSecValueData
);
356 CFDictionarySetValue(attrs
, kSecClass
, kSecClassKey
);
357 CFDictionarySetValue(attrs
, kSecAttrKeyClass
, kSecAttrKeyClassPrivate
);
358 CFDictionarySetValue(attrs
, kSecReturnRef
, kCFBooleanTrue
);
360 // Add key from given attributes to the token (having no data will cause the token to actually generate the key).
361 require_noerr_quiet(status
= SecItemAdd(attrs
, (CFTypeRef
*)privateKey
), out
);
363 // Create non-token public key.
364 require_noerr_quiet(status
= SecCTKKeyCopyPublicOctets(*privateKey
, &publicData
), out
);
365 if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeEC
)) {
366 *publicKey
= SecKeyCreateECPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
367 kSecKeyEncodingBytes
);
368 } else if (CFEqualSafe(CFDictionaryGetValue(parameters
, kSecAttrKeyType
), kSecAttrKeyTypeRSA
)) {
369 *publicKey
= SecKeyCreateRSAPublicKey(NULL
, CFDataGetBytePtr(publicData
), CFDataGetLength(publicData
),
370 kSecKeyEncodingBytes
);
373 if (*publicKey
!= NULL
) {
374 status
= errSecSuccess
;
376 status
= errSecInvalidKey
;
377 CFReleaseNull(*privateKey
);
381 CFReleaseSafe(attrs
);
382 CFReleaseSafe(publicData
);
386 SecKeyRef
SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType
, CFErrorRef
*error
) {
387 if (keyType
!= kSecKeyAttestationKeyTypeSIK
&& keyType
!= kSecKeyAttestationKeyTypeGID
) {
388 SecError(errSecParam
, error
, CFSTR("unexpected attestation key type %u"), (unsigned)keyType
);
392 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.sik" dataUsingEncoding:NSUTF8StringEncoding]];
393 static const uint8_t sikObjectIDBytes
[] = {
394 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
395 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
396 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
397 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
398 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
399 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
400 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x73, 0x69, 0x6b, 0x80, 0x02, 0xd2,
401 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
402 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
403 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
404 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
405 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
406 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
407 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
408 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
412 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.gid" dataUsingEncoding:NSUTF8StringEncoding]];
413 static const uint8_t gidObjectIDBytes
[] = {
414 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
415 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
416 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
417 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
418 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
419 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
420 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x67, 0x69, 0x64, 0x80, 0x02, 0xd2,
421 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
422 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
423 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
424 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
425 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
426 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
427 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
428 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
432 CFDataRef objectID
= (keyType
== kSecKeyAttestationKeyTypeSIK
) ?
433 CFDataCreate(kCFAllocatorDefault
, sikObjectIDBytes
, sizeof(sikObjectIDBytes
)) :
434 CFDataCreate(kCFAllocatorDefault
, gidObjectIDBytes
, sizeof(gidObjectIDBytes
)) ;
436 const void *keys
[] = { kSecUseToken
, kSecUseTokenObjectID
, kSecAttrTokenID
};
437 const void *values
[] = { kCFNull
, objectID
, CFSTR("com.apple.setoken.attest") };
439 CFDictionaryRef attributes
= CFDictionaryCreate(kCFAllocatorDefault
,
440 keys
, values
, sizeof(keys
) / sizeof(*keys
),
441 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
443 return SecKeyCreateCTKKey(kCFAllocatorDefault
, attributes
, error
);
446 CFDataRef
SecKeyCreateAttestation(SecKeyRef key
, SecKeyRef keyToAttest
, CFErrorRef
*error
) {
447 if (!key
|| !keyToAttest
) {
448 SecError(errSecParam
, error
, CFSTR("attestation key(s) is NULL"));
452 SecCTKKeyData
*attestingKeyData
= key
->key
;
453 SecCTKKeyData
*keyToAttestData
= keyToAttest
->key
;
455 if (key
->key_class
!= &kSecCTKKeyDescriptor
) {
456 SecError(errSecUnsupportedOperation
, error
, CFSTR("attestation not supported by key %@"), key
);
459 if (keyToAttest
->key_class
!= &kSecCTKKeyDescriptor
|| CFEqual(keyToAttestData
->token
, kCFNull
)) {
460 SecError(errSecUnsupportedOperation
, error
, CFSTR("attestation not supported for key %@"), keyToAttest
);
464 const void *keys
[] = {
465 CFSTR(kTKTokenControlAttribAttestingKey
),
466 CFSTR(kTKTokenControlAttribKeyToAttest
),
468 const void *values
[] = {
469 attestingKeyData
->objectID
,
470 keyToAttestData
->objectID
473 CFDictionaryRef attributes
= NULL
;
474 __block CFDictionaryRef outputAttributes
= NULL
;
475 CFDataRef attestationData
= NULL
;
476 __block SecCFDictionaryCOW sign_auth_params
= { keyToAttestData
->auth_params
.dictionary
};
478 attributes
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
) / sizeof(*keys
),
479 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
481 SecItemAuthDo(&sign_auth_params
, error
, ^SecItemAuthResult(CFDictionaryRef auth_params
, CFArrayRef
*ac_pairs
, CFErrorRef
*error
) {
482 outputAttributes
= TKTokenControl(keyToAttestData
->token
, attributes
, error
);
483 return outputAttributes
? kSecItemAuthResultOK
: SecCTKProcessError(kAKSKeyOpAttest
, keyToAttestData
->token
, keyToAttestData
->objectID
, ac_pairs
, error
);
485 require(outputAttributes
, out
);
487 attestationData
= CFDictionaryGetValue(outputAttributes
, CFSTR(kTKTokenControlAttribAttestationData
));
488 require_action(attestationData
, out
, SecError(errSecInternal
, error
, CFSTR("could not get attestation data")));
490 if (CFGetTypeID(attestationData
) != CFDataGetTypeID()) {
491 SecError(errSecInternal
, error
, CFSTR("unexpected attestation object type"));
492 attestationData
= NULL
;
495 CFRetainSafe(attestationData
);
498 CFReleaseSafe(attributes
);
499 CFReleaseSafe(outputAttributes
);
500 return attestationData
;