]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCTKKey.c
Security-57740.51.3.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 #include "SecECKey.h"
38 #include "SecRSAKey.h"
39 #include "SecCTKKeyPriv.h"
40
41 const CFStringRef kSecUseToken = CFSTR("u_Token");
42 const CFStringRef kSecUseTokenObjectID = CFSTR("u_TokenOID");
43
44 typedef struct {
45 TKTokenRef token;
46 CFStringRef token_id;
47 CFDataRef objectID;
48 SecCFDictionaryCOW auth_params;
49 SecCFDictionaryCOW attributes;
50 CFMutableDictionaryRef params;
51 } SecCTKKeyData;
52
53 static void SecCTKKeyDestroy(SecKeyRef key) {
54 SecCTKKeyData *kd = key->key;
55 CFReleaseSafe(kd->token);
56 CFReleaseSafe(kd->token_id);
57 CFReleaseSafe(kd->objectID);
58 CFReleaseSafe(kd->auth_params.mutable_dictionary);
59 CFReleaseSafe(kd->attributes.mutable_dictionary);
60 CFReleaseSafe(kd->params);
61 }
62
63 static CFIndex SecCTKGetAlgorithmID(SecKeyRef key) {
64 SecCTKKeyData *kd = key->key;
65 if (CFEqualSafe(CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType), kSecAttrKeyTypeECSECPrimeRandom)) {
66 return kSecECDSAAlgorithmID;
67 }
68 return kSecRSAAlgorithmID;
69 }
70
71 static SecItemAuthResult SecCTKProcessError(CFStringRef operation, TKTokenRef token, CFDataRef object_id, CFArrayRef *ac_pairs, CFErrorRef *error) {
72 if (CFEqualSafe(CFErrorGetDomain(*error), CFSTR(kTKErrorDomain)) &&
73 CFErrorGetCode(*error) == kTKErrorCodeAuthenticationFailed) {
74 CFDataRef access_control = TKTokenCopyObjectAccessControl(token, object_id, error);
75 if (access_control != NULL) {
76 CFArrayRef ac_pair = CFArrayCreateForCFTypes(NULL, access_control, operation, NULL);
77 CFAssignRetained(*ac_pairs, CFArrayCreateForCFTypes(NULL, ac_pair, NULL));
78
79 CFReleaseNull(*error);
80 CFRelease(ac_pair);
81 CFRelease(access_control);
82 return kSecItemAuthResultNeedAuth;
83 }
84 }
85 return kSecItemAuthResultError;
86 }
87
88 static const CFTypeRef *aclOperations[] = {
89 [kSecKeyOperationTypeSign] = &kAKSKeyOpSign,
90 [kSecKeyOperationTypeDecrypt] = &kAKSKeyOpDecrypt,
91 [kSecKeyOperationTypeKeyExchange] = &kAKSKeyOpComputeKey,
92 };
93
94 static CFTypeRef SecCTKKeyCopyOperationResult(SecKeyRef key, SecKeyOperationType operation, SecKeyAlgorithm algorithm,
95 CFArrayRef algorithms, SecKeyOperationMode mode,
96 CFTypeRef in1, CFTypeRef in2, CFErrorRef *error) {
97 SecCTKKeyData *kd = key->key;
98 __block SecCFDictionaryCOW auth_params = { kd->auth_params.dictionary };
99 __block TKTokenRef token = CFRetainSafe(kd->token);
100 __block CFTypeRef result = kCFNull;
101
102 CFErrorRef localError = NULL;
103 SecItemAuthDo(&auth_params, &localError, ^SecItemAuthResult(CFDictionaryRef ap, CFArrayRef *ac_pairs, CFErrorRef *error) {
104 if (auth_params.mutable_dictionary != NULL || token == NULL || kd->params != NULL) {
105 // token was not connected yet or auth_params were modified, so reconnect the token in order to update the attributes.
106 SecCFDictionaryCOW attributes = { ap };
107 if (kd->params && CFDictionaryGetCount(kd->params) > 0) {
108 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&attributes), CFSTR(kTKTokenCreateAttributeAuxParams), kd->params);
109 }
110 CFAssignRetained(token, SecTokenCreate(kd->token_id, attributes.dictionary, error));
111 CFReleaseSafe(attributes.mutable_dictionary);
112 if (token == NULL) {
113 return kSecItemAuthResultError;
114 }
115 }
116
117 result = TKTokenCopyOperationResult(token, kd->objectID, operation, algorithms, mode, in1, in2, error);
118 return (result != NULL) ? kSecItemAuthResultOK : SecCTKProcessError(*aclOperations[operation], token,
119 kd->objectID, ac_pairs, error);
120 });
121
122 CFErrorPropagate(localError, error);
123 CFReleaseSafe(auth_params.mutable_dictionary);
124 CFReleaseSafe(token);
125 return result;
126 }
127
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()) {
132 CFIndex bitSize;
133 if (CFNumberGetValue(keySize, kCFNumberCFIndexType, &bitSize))
134 return (bitSize + 7) / 8;
135 }
136
137 return 0;
138 }
139
140 static OSStatus SecCTKKeyCopyPublicOctets(SecKeyRef key, CFDataRef *data) {
141 OSStatus status = errSecSuccess;
142 CFErrorRef error = NULL;
143 CFDataRef publicData = NULL;
144
145 SecCTKKeyData *kd = key->key;
146 require_action_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out,
147 status = SecErrorGetOSStatus(error));
148 *data = publicData;
149
150 out:
151 CFReleaseSafe(error);
152 return status;
153 }
154
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);
159 }
160
161 // Attributes allowed to be exported from all internal key attributes.
162 static const CFStringRef *kSecExportableCTKKeyAttributes[] = {
163 &kSecClass,
164 &kSecAttrTokenID,
165 &kSecAttrKeyClass,
166 &kSecAttrIsPermanent,
167 &kSecAttrIsPrivate,
168 &kSecAttrIsModifiable,
169 &kSecAttrKeyType,
170 &kSecAttrKeySizeInBits,
171 &kSecAttrEffectiveKeySize,
172 &kSecAttrIsSensitive,
173 &kSecAttrWasAlwaysSensitive,
174 &kSecAttrIsExtractable,
175 &kSecAttrWasNeverExtractable,
176 &kSecAttrCanEncrypt,
177 &kSecAttrCanDecrypt,
178 &kSecAttrCanDerive,
179 &kSecAttrCanSign,
180 &kSecAttrCanVerify,
181 &kSecAttrCanSignRecover,
182 &kSecAttrCanVerifyRecover,
183 &kSecAttrCanWrap,
184 &kSecAttrCanUnwrap,
185 NULL
186 };
187
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;
193
194 // Encode ApplicationLabel as SHA1 digest of public key bytes.
195 require_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out);
196
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);
201
202 for (const CFStringRef **attrKey = &kSecExportableCTKKeyAttributes[0]; *attrKey != NULL; attrKey++) {
203 CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrKey);
204 if (value != NULL) {
205 CFDictionarySetValue(attrs, **attrKey, value);
206 }
207 }
208
209 out:
210 CFReleaseSafe(error);
211 CFReleaseSafe(publicData);
212 CFReleaseSafe(digest);
213 return attrs;
214 }
215
216 static SecKeyRef SecCTKKeyCreateDuplicate(SecKeyRef key);
217
218 static Boolean SecCTKKeySetParameter(SecKeyRef key, CFStringRef name, CFPropertyListRef value, CFErrorRef *error) {
219 SecCTKKeyData *kd = key->key;
220 CFTypeRef acm_reference = NULL;
221
222 static const CFStringRef *const knownUseFlags[] = {
223 &kSecUseOperationPrompt,
224 &kSecUseAuthenticationContext,
225 &kSecUseAuthenticationUI,
226 &kSecUseCallerName,
227 &kSecUseCredentialReference,
228 };
229
230 // Check, whether name is part of known use flags.
231 bool isUseFlag = false;
232 for (size_t i = 0; i < array_size(knownUseFlags); i++) {
233 if (CFEqual(*knownUseFlags[i], name)) {
234 isUseFlag = true;
235 break;
236 }
237 }
238
239 if (CFEqual(name, kSecUseAuthenticationContext)) {
240 // Preprocess LAContext to ACMRef value.
241 if (value != NULL) {
242 require_quiet(acm_reference = SecItemAttributesCopyPreparedAuthContext(value, error), out);
243 value = acm_reference;
244 }
245 name = kSecUseCredentialReference;
246 }
247
248 if (isUseFlag) {
249 // Release existing token connection to enforce creation of new connection with new auth params.
250 CFReleaseNull(kd->token);
251 if (value != NULL) {
252 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->auth_params), name, value);
253 } else {
254 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->auth_params), name);
255 }
256 } else {
257 if (kd->params == NULL) {
258 kd->params = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
259 }
260 if (value != NULL) {
261 CFDictionarySetValue(kd->params, name, value);
262 } else {
263 CFDictionaryRemoveValue(kd->params, name);
264 }
265 }
266
267 out:
268 CFReleaseSafe(acm_reference);
269 return TRUE;
270 }
271
272 static SecKeyDescriptor kSecCTKKeyDescriptor = {
273 .version = kSecKeyDescriptorVersion,
274 .name = "CTKKey",
275 .extraBytes = sizeof(SecCTKKeyData),
276
277 .destroy = SecCTKKeyDestroy,
278 .blockSize = SecCTKKeyBlockSize,
279 .copyDictionary = SecCTKKeyCopyAttributeDictionary,
280 .describe = SecCTKKeyCopyKeyDescription,
281 .getAlgorithmID = SecCTKGetAlgorithmID,
282 .copyPublic = SecCTKKeyCopyPublicOctets,
283 .copyOperationResult = SecCTKKeyCopyOperationResult,
284 .createDuplicate = SecCTKKeyCreateDuplicate,
285 .setParameter = SecCTKKeySetParameter,
286 };
287
288 static SecKeyRef SecCTKKeyCreateDuplicate(SecKeyRef key) {
289 SecKeyRef result = SecKeyCreate(CFGetAllocator(key), &kSecCTKKeyDescriptor, 0, 0, 0);
290 SecCTKKeyData *kd = key->key, *rd = result->key;
291 rd->token = CFRetainSafe(kd->token);
292 rd->objectID = CFRetainSafe(kd->objectID);
293 rd->token_id = CFRetainSafe(kd->token_id);
294 if (kd->attributes.dictionary != NULL) {
295 rd->attributes.dictionary = kd->attributes.dictionary;
296 SecCFDictionaryCOWGetMutable(&rd->attributes);
297 }
298 if (kd->auth_params.dictionary != NULL) {
299 rd->auth_params.dictionary = kd->auth_params.dictionary;
300 SecCFDictionaryCOWGetMutable(&rd->auth_params);
301 }
302 return result;
303 }
304
305 SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttributes, CFErrorRef *error) {
306 SecKeyRef key = SecKeyCreate(allocator, &kSecCTKKeyDescriptor, 0, 0, 0);
307 SecCTKKeyData *kd = key->key;
308 kd->token = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecUseToken));
309 kd->objectID = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecUseTokenObjectID));
310 kd->token_id = CFRetainSafe(CFDictionaryGetValue(refAttributes, kSecAttrTokenID));
311 kd->attributes.dictionary = refAttributes;
312 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecUseToken);
313 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecUseTokenObjectID);
314 SecItemAuthCopyParams(&kd->auth_params, &kd->attributes);
315 if (CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrIsPrivate) == NULL) {
316 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecAttrIsPrivate, kCFBooleanTrue);
317 }
318
319 // Convert some attributes which are stored as numbers in iOS keychain but a lot of code counts that the values
320 // are actually strings as specified by kSecAttrXxx constants.
321 static const CFStringRef *numericAttributes[] = {
322 &kSecAttrKeyType,
323 &kSecAttrKeyClass,
324 NULL,
325 };
326
327 for (const CFStringRef **attrName = &numericAttributes[0]; *attrName != NULL; attrName++) {
328 CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrName);
329 if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) {
330 CFIndex number;
331 if (CFNumberGetValue(value, kCFNumberCFIndexType, &number)) {
332 CFStringRef newValue = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), (long)number);
333 if (newValue != NULL) {
334 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), **attrName, newValue);
335 CFRelease(newValue);
336 }
337 }
338 }
339 }
340
341 return key;
342 }
343
344 OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
345 OSStatus status;
346 CFMutableDictionaryRef attrs = NULL;
347 CFDictionaryRef keyAttrs = NULL;
348 CFDataRef publicData = NULL;
349
350 require_action_quiet(publicKey != NULL, out, status = errSecParam);
351 require_action_quiet(privateKey != NULL, out, status = errSecParam);
352
353 // Simply adding key on the token without value will cause the token to generate the key and automatically
354 // add it to the keychain. Prepare dictionary specifying item to add.
355 keyAttrs = CFDictionaryGetValue(parameters, kSecPrivateKeyAttrs);
356 attrs = (keyAttrs == NULL) ? CFDictionaryCreateMutableForCFTypes(NULL) : CFDictionaryCreateMutableCopy(NULL, 0, keyAttrs);
357
358 CFDictionaryForEach(parameters, ^(const void *key, const void *value) {
359 if (!CFEqual(key, kSecPrivateKeyAttrs) && !CFEqual(key, kSecPublicKeyAttrs)) {
360 CFDictionarySetValue(attrs, key, value);
361 }
362 });
363 CFDictionaryRemoveValue(attrs, kSecValueData);
364 CFDictionarySetValue(attrs, kSecClass, kSecClassKey);
365 CFDictionarySetValue(attrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
366 CFDictionarySetValue(attrs, kSecReturnRef, kCFBooleanTrue);
367
368 // Add key from given attributes to the token (having no data will cause the token to actually generate the key).
369 require_noerr_quiet(status = SecItemAdd(attrs, (CFTypeRef *)privateKey), out);
370
371 // Create non-token public key.
372 require_noerr_quiet(status = SecCTKKeyCopyPublicOctets(*privateKey, &publicData), out);
373 if (CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeEC)) {
374 *publicKey = SecKeyCreateECPublicKey(NULL, CFDataGetBytePtr(publicData), CFDataGetLength(publicData),
375 kSecKeyEncodingBytes);
376 } else if (CFEqualSafe(CFDictionaryGetValue(parameters, kSecAttrKeyType), kSecAttrKeyTypeRSA)) {
377 *publicKey = SecKeyCreateRSAPublicKey(NULL, CFDataGetBytePtr(publicData), CFDataGetLength(publicData),
378 kSecKeyEncodingBytes);
379 }
380
381 if (*publicKey != NULL) {
382 status = errSecSuccess;
383 } else {
384 status = errSecInvalidKey;
385 CFReleaseNull(*privateKey);
386 }
387
388 out:
389 CFReleaseSafe(attrs);
390 CFReleaseSafe(publicData);
391 return status;
392 }
393
394 SecKeyRef SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType, CFErrorRef *error) {
395 if (keyType != kSecKeyAttestationKeyTypeSIK && keyType != kSecKeyAttestationKeyTypeGID) {
396 SecError(errSecParam, error, CFSTR("unexpected attestation key type %u"), (unsigned)keyType);
397 return NULL;
398 }
399
400 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.sik" dataUsingEncoding:NSUTF8StringEncoding]];
401 static const uint8_t sikObjectIDBytes[] = {
402 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
403 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
404 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
405 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
406 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
407 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
408 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x73, 0x69, 0x6b, 0x80, 0x02, 0xd2,
409 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
410 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
411 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
412 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
413 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
414 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
415 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
416 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
417 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
418 };
419
420 // [NSKeyedArchiver archivedDataWithRootObject:[@"com.apple.setoken.gid" dataUsingEncoding:NSUTF8StringEncoding]];
421 static const uint8_t gidObjectIDBytes[] = {
422 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x14,
423 0x15, 0x58, 0x24, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x58, 0x24, 0x6f, 0x62, 0x6a, 0x65,
424 0x63, 0x74, 0x73, 0x59, 0x24, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0x54, 0x24, 0x74,
425 0x6f, 0x70, 0x12, 0x00, 0x01, 0x86, 0xa0, 0xa3, 0x07, 0x08, 0x0d, 0x55, 0x24, 0x6e, 0x75, 0x6c,
426 0x6c, 0xd2, 0x09, 0x0a, 0x0b, 0x0c, 0x57, 0x4e, 0x53, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x56, 0x24,
427 0x63, 0x6c, 0x61, 0x73, 0x73, 0x4f, 0x10, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
428 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x67, 0x69, 0x64, 0x80, 0x02, 0xd2,
429 0x0e, 0x0f, 0x10, 0x11, 0x5a, 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x58,
430 0x24, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x5d, 0x4e, 0x53, 0x4d, 0x75, 0x74, 0x61, 0x62,
431 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0xa3, 0x10, 0x12, 0x13, 0x56, 0x4e, 0x53, 0x44, 0x61, 0x74,
432 0x61, 0x58, 0x4e, 0x53, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x10, 0x0f, 0x4e, 0x53, 0x4b,
433 0x65, 0x79, 0x65, 0x64, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x72, 0xd1, 0x16, 0x17, 0x54,
434 0x72, 0x6f, 0x6f, 0x74, 0x80, 0x01, 0x08, 0x11, 0x1a, 0x23, 0x2d, 0x32, 0x37, 0x3b, 0x41, 0x46,
435 0x4e, 0x55, 0x6d, 0x6f, 0x74, 0x7f, 0x88, 0x96, 0x9a, 0xa1, 0xaa, 0xbc, 0xbf, 0xc4, 0x00, 0x00,
436 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
437 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6
438 };
439
440 CFDataRef objectID = (keyType == kSecKeyAttestationKeyTypeSIK) ?
441 CFDataCreate(kCFAllocatorDefault, sikObjectIDBytes, sizeof(sikObjectIDBytes)) :
442 CFDataCreate(kCFAllocatorDefault, gidObjectIDBytes, sizeof(gidObjectIDBytes)) ;
443
444 const void *keys[] = { kSecUseToken, kSecUseTokenObjectID, kSecAttrTokenID };
445 const void *values[] = { kCFNull, objectID, CFSTR("com.apple.setoken.attest") };
446
447 CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault,
448 keys, values, sizeof(keys) / sizeof(*keys),
449 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
450
451 return SecKeyCreateCTKKey(kCFAllocatorDefault, attributes, error);
452 }
453
454 CFDataRef SecKeyCreateAttestation(SecKeyRef key, SecKeyRef keyToAttest, CFErrorRef *error) {
455 if (!key || !keyToAttest) {
456 SecError(errSecParam, error, CFSTR("attestation key(s) is NULL"));
457 return NULL;
458 }
459
460 SecCTKKeyData *attestingKeyData = key->key;
461 SecCTKKeyData *keyToAttestData = keyToAttest->key;
462
463 if (key->key_class != &kSecCTKKeyDescriptor) {
464 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported by key %@"), key);
465 return NULL;
466 }
467 if (keyToAttest->key_class != &kSecCTKKeyDescriptor || CFEqual(keyToAttestData->token, kCFNull)) {
468 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported for key %@"), keyToAttest);
469 return NULL;
470 }
471
472 const void *keys[] = {
473 CFSTR(kTKTokenControlAttribAttestingKey),
474 CFSTR(kTKTokenControlAttribKeyToAttest),
475 };
476 const void *values[] = {
477 attestingKeyData->objectID,
478 keyToAttestData->objectID
479 };
480
481 CFDictionaryRef attributes = NULL;
482 __block CFDictionaryRef outputAttributes = NULL;
483 CFDataRef attestationData = NULL;
484 __block SecCFDictionaryCOW sign_auth_params = { keyToAttestData->auth_params.dictionary };
485
486 attributes = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(*keys),
487 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
488
489 SecItemAuthDo(&sign_auth_params, error, ^SecItemAuthResult(CFDictionaryRef auth_params, CFArrayRef *ac_pairs, CFErrorRef *error) {
490 outputAttributes = TKTokenControl(keyToAttestData->token, attributes, error);
491 return outputAttributes ? kSecItemAuthResultOK : SecCTKProcessError(kAKSKeyOpAttest, keyToAttestData->token, keyToAttestData->objectID, ac_pairs, error);
492 });
493 require(outputAttributes, out);
494
495 attestationData = CFDictionaryGetValue(outputAttributes, CFSTR(kTKTokenControlAttribAttestationData));
496 require_action(attestationData, out, SecError(errSecInternal, error, CFSTR("could not get attestation data")));
497
498 if (CFGetTypeID(attestationData) != CFDataGetTypeID()) {
499 SecError(errSecInternal, error, CFSTR("unexpected attestation object type"));
500 attestationData = NULL;
501 }
502
503 CFRetainSafe(attestationData);
504
505 out:
506 CFReleaseSafe(attributes);
507 CFReleaseSafe(outputAttributes);
508 return attestationData;
509 }