]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCTKKey.c
Security-57740.31.2.tar.gz
[apple/security.git] / OSX / sec / Security / SecCTKKey.c
1 /*
2 * Copyright (c) 2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
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>
36
37 #if TKTOKEN_CLIENT_INTERFACE_VERSION <= 1
38 #define kTKTokenCreateAttributeAuxParams "auxParams"
39 #endif
40
41 #include "SecECKey.h"
42 #include "SecRSAKey.h"
43 #include "SecCTKKeyPriv.h"
44
45 const CFStringRef kSecUseToken = CFSTR("u_Token");
46 const CFStringRef kSecUseTokenObjectID = CFSTR("u_TokenOID");
47
48 typedef struct {
49 TKTokenRef token;
50 CFStringRef token_id;
51 CFDataRef objectID;
52 SecCFDictionaryCOW auth_params;
53 SecCFDictionaryCOW attributes;
54 CFMutableDictionaryRef params;
55 } SecCTKKeyData;
56
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);
65 }
66
67 static CFIndex SecCTKGetAlgorithmID(SecKeyRef key) {
68 SecCTKKeyData *kd = key->key;
69 CFTypeRef type = CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType);
70 if (type != NULL) {
71 if (CFGetTypeID(type) == CFNumberGetTypeID()) {
72 CFIndex keyType;
73 if (CFNumberGetValue(type, kCFNumberCFIndexType, &keyType) && keyType == 73 /* kSecAttrKeyTypeEC */)
74 return kSecECDSAAlgorithmID;
75 } else if (CFGetTypeID(type) == CFStringGetTypeID() && CFEqual(type, kSecAttrKeyTypeEC)) {
76 return kSecECDSAAlgorithmID;
77 }
78 }
79 return kSecRSAAlgorithmID;
80 }
81
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));
89
90 CFReleaseNull(*error);
91 CFRelease(ac_pair);
92 CFRelease(access_control);
93 return kSecItemAuthResultNeedAuth;
94 }
95 }
96 return kSecItemAuthResultError;
97 }
98
99 static const CFTypeRef *aclOperations[] = {
100 [kSecKeyOperationTypeSign] = &kAKSKeyOpSign,
101 [kSecKeyOperationTypeDecrypt] = &kAKSKeyOpDecrypt,
102 [kSecKeyOperationTypeKeyExchange] = &kAKSKeyOpComputeKey,
103 };
104
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;
112
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);
120 }
121 CFAssignRetained(token, SecTokenCreate(kd->token_id, attributes.dictionary, error));
122 CFReleaseSafe(attributes.mutable_dictionary);
123 if (token == NULL) {
124 return kSecItemAuthResultError;
125 }
126 }
127
128 #if TKTOKEN_CLIENT_INTERFACE_VERSION >= 1
129 result = TKTokenCopyOperationResult(token, kd->objectID, operation, algorithms, mode, in1, in2, error);
130 #else
131 result = TKTokenCopyCryptoResult(token, kd->objectID, operation, (CFIndex)algorithm, in1, in2, error);
132 #endif
133 return (result != NULL) ? kSecItemAuthResultOK : SecCTKProcessError(*aclOperations[operation], token,
134 kd->objectID, ac_pairs, error);
135 });
136
137 CFErrorPropagate(localError, error);
138 CFReleaseSafe(auth_params.mutable_dictionary);
139 CFReleaseSafe(token);
140 return result;
141 }
142
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()) {
147 CFIndex bitSize;
148 if (CFNumberGetValue(keySize, kCFNumberCFIndexType, &bitSize))
149 return (bitSize + 7) / 8;
150 }
151
152 return 0;
153 }
154
155 static OSStatus SecCTKKeyCopyPublicOctets(SecKeyRef key, CFDataRef *data) {
156 OSStatus status = errSecSuccess;
157 CFErrorRef error = NULL;
158 CFDataRef publicData = NULL;
159
160 SecCTKKeyData *kd = key->key;
161 require_action_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out,
162 status = SecErrorGetOSStatus(error));
163 *data = publicData;
164
165 out:
166 CFReleaseSafe(error);
167 return status;
168 }
169
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);
174 }
175
176 // Attributes allowed to be exported from all internal key attributes.
177 static const CFStringRef *kSecExportableCTKKeyAttributes[] = {
178 &kSecClass,
179 &kSecAttrTokenID,
180 &kSecAttrKeyClass,
181 &kSecAttrIsPermanent,
182 &kSecAttrIsPrivate,
183 &kSecAttrIsModifiable,
184 &kSecAttrKeyType,
185 &kSecAttrKeySizeInBits,
186 &kSecAttrEffectiveKeySize,
187 &kSecAttrIsSensitive,
188 &kSecAttrWasAlwaysSensitive,
189 &kSecAttrIsExtractable,
190 &kSecAttrWasNeverExtractable,
191 &kSecAttrCanEncrypt,
192 &kSecAttrCanDecrypt,
193 &kSecAttrCanDerive,
194 &kSecAttrCanSign,
195 &kSecAttrCanVerify,
196 &kSecAttrCanSignRecover,
197 &kSecAttrCanVerifyRecover,
198 &kSecAttrCanWrap,
199 &kSecAttrCanUnwrap,
200 NULL
201 };
202
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;
208
209 // Encode ApplicationLabel as SHA1 digest of public key bytes.
210 require_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out);
211
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);
216
217 for (const CFStringRef **attrKey = &kSecExportableCTKKeyAttributes[0]; *attrKey != NULL; attrKey++) {
218 CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrKey);
219 if (value != NULL) {
220 CFDictionarySetValue(attrs, **attrKey, value);
221 }
222 }
223
224 out:
225 CFReleaseSafe(error);
226 CFReleaseSafe(publicData);
227 CFReleaseSafe(digest);
228 return attrs;
229 }
230
231 static SecKeyRef SecCTKKeyCreateDuplicate(SecKeyRef key);
232
233 static Boolean SecCTKKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) {
234 SecCTKKeyData *kd = key->key;
235 CFTypeRef acm_reference = NULL;
236
237 static const CFStringRef *const knownUseFlags[] = {
238 &kSecUseOperationPrompt,
239 &kSecUseAuthenticationContext,
240 &kSecUseAuthenticationUI,
241 &kSecUseCallerName,
242 &kSecUseCredentialReference,
243 };
244
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)) {
249 isUseFlag = true;
250 break;
251 }
252 }
253
254 if (CFEqual(name, kSecUseAuthenticationContext)) {
255 // Preprocess LAContext to ACMRef value.
256 if (value != NULL) {
257 require_quiet(acm_reference = SecItemAttributesCopyPreparedAuthContext(value, error), out);
258 value = acm_reference;
259 }
260 name = kSecUseCredentialReference;
261 }
262
263 if (isUseFlag) {
264 // Release existing token connection to enforce creation of new connection with new auth params.
265 CFReleaseNull(kd->token);
266 if (value != NULL) {
267 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->auth_params), name, value);
268 } else {
269 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->auth_params), name);
270 }
271 } else {
272 if (kd->params == NULL) {
273 kd->params = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
274 }
275 if (value != NULL) {
276 CFDictionarySetValue(kd->params, name, value);
277 } else {
278 CFDictionaryRemoveValue(kd->params, name);
279 }
280 }
281
282 out:
283 CFReleaseSafe(acm_reference);
284 return TRUE;
285 }
286
287 static SecKeyDescriptor kSecCTKKeyDescriptor = {
288 .version = kSecKeyDescriptorVersion,
289 .name = "CTKKey",
290 .extraBytes = sizeof(SecCTKKeyData),
291
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,
301 };
302
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);
312 }
313 if (kd->auth_params.dictionary != NULL) {
314 rd->auth_params.dictionary = kd->auth_params.dictionary;
315 SecCFDictionaryCOWGetMutable(&rd->auth_params);
316 }
317 return result;
318 }
319
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);
332 }
333 return key;
334 }
335
336 OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
337 OSStatus status;
338 CFMutableDictionaryRef attrs = NULL;
339 CFDictionaryRef keyAttrs = NULL;
340 CFDataRef publicData = NULL;
341
342 require_action_quiet(publicKey != NULL, out, status = errSecParam);
343 require_action_quiet(privateKey != NULL, out, status = errSecParam);
344
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);
349
350 CFDictionaryForEach(parameters, ^(const void *key, const void *value) {
351 if (!CFEqual(key, kSecPrivateKeyAttrs) && !CFEqual(key, kSecPublicKeyAttrs)) {
352 CFDictionarySetValue(attrs, key, value);
353 }
354 });
355 CFDictionaryRemoveValue(attrs, kSecValueData);
356 CFDictionarySetValue(attrs, kSecClass, kSecClassKey);
357 CFDictionarySetValue(attrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
358 CFDictionarySetValue(attrs, kSecReturnRef, kCFBooleanTrue);
359
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);
362
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);
371 }
372
373 if (*publicKey != NULL) {
374 status = errSecSuccess;
375 } else {
376 status = errSecInvalidKey;
377 CFReleaseNull(*privateKey);
378 }
379
380 out:
381 CFReleaseSafe(attrs);
382 CFReleaseSafe(publicData);
383 return status;
384 }
385
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);
389 return NULL;
390 }
391
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
410 };
411
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
430 };
431
432 CFDataRef objectID = (keyType == kSecKeyAttestationKeyTypeSIK) ?
433 CFDataCreate(kCFAllocatorDefault, sikObjectIDBytes, sizeof(sikObjectIDBytes)) :
434 CFDataCreate(kCFAllocatorDefault, gidObjectIDBytes, sizeof(gidObjectIDBytes)) ;
435
436 const void *keys[] = { kSecUseToken, kSecUseTokenObjectID, kSecAttrTokenID };
437 const void *values[] = { kCFNull, objectID, CFSTR("com.apple.setoken.attest") };
438
439 CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault,
440 keys, values, sizeof(keys) / sizeof(*keys),
441 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
442
443 return SecKeyCreateCTKKey(kCFAllocatorDefault, attributes, error);
444 }
445
446 CFDataRef SecKeyCreateAttestation(SecKeyRef key, SecKeyRef keyToAttest, CFErrorRef *error) {
447 if (!key || !keyToAttest) {
448 SecError(errSecParam, error, CFSTR("attestation key(s) is NULL"));
449 return NULL;
450 }
451
452 SecCTKKeyData *attestingKeyData = key->key;
453 SecCTKKeyData *keyToAttestData = keyToAttest->key;
454
455 if (key->key_class != &kSecCTKKeyDescriptor) {
456 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported by key %@"), key);
457 return NULL;
458 }
459 if (keyToAttest->key_class != &kSecCTKKeyDescriptor || CFEqual(keyToAttestData->token, kCFNull)) {
460 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported for key %@"), keyToAttest);
461 return NULL;
462 }
463
464 const void *keys[] = {
465 CFSTR(kTKTokenControlAttribAttestingKey),
466 CFSTR(kTKTokenControlAttribKeyToAttest),
467 };
468 const void *values[] = {
469 attestingKeyData->objectID,
470 keyToAttestData->objectID
471 };
472
473 CFDictionaryRef attributes = NULL;
474 __block CFDictionaryRef outputAttributes = NULL;
475 CFDataRef attestationData = NULL;
476 __block SecCFDictionaryCOW sign_auth_params = { keyToAttestData->auth_params.dictionary };
477
478 attributes = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(*keys),
479 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
480
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);
484 });
485 require(outputAttributes, out);
486
487 attestationData = CFDictionaryGetValue(outputAttributes, CFSTR(kTKTokenControlAttribAttestationData));
488 require_action(attestationData, out, SecError(errSecInternal, error, CFSTR("could not get attestation data")));
489
490 if (CFGetTypeID(attestationData) != CFDataGetTypeID()) {
491 SecError(errSecInternal, error, CFSTR("unexpected attestation object type"));
492 attestationData = NULL;
493 }
494
495 CFRetainSafe(attestationData);
496
497 out:
498 CFReleaseSafe(attributes);
499 CFReleaseSafe(outputAttributes);
500 return attestationData;
501 }