]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCTKKey.c
Security-57740.20.22.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 SecKeyDescriptor kSecCTKKeyDescriptor = {
234 .version = kSecKeyDescriptorVersion,
235 .name = "CTKKey",
236 .extraBytes = sizeof(SecCTKKeyData),
237
238 .destroy = SecCTKKeyDestroy,
239 .blockSize = SecCTKKeyBlockSize,
240 .copyDictionary = SecCTKKeyCopyAttributeDictionary,
241 .describe = SecCTKKeyCopyKeyDescription,
242 .getAlgorithmID = SecCTKGetAlgorithmID,
243 .copyPublic = SecCTKKeyCopyPublicOctets,
244 .copyOperationResult = SecCTKKeyCopyOperationResult,
245 .createDuplicate = SecCTKKeyCreateDuplicate,
246 };
247
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);
257 }
258 if (kd->auth_params.dictionary != NULL) {
259 rd->auth_params.dictionary = kd->auth_params.dictionary;
260 SecCFDictionaryCOWGetMutable(&rd->auth_params);
261 }
262 return result;
263 }
264
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);
277 }
278 return key;
279 }
280
281 OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
282 OSStatus status;
283 CFMutableDictionaryRef attrs = NULL;
284 CFDictionaryRef keyAttrs = NULL;
285 CFDataRef publicData = NULL;
286
287 require_action_quiet(publicKey != NULL, out, status = errSecParam);
288 require_action_quiet(privateKey != NULL, out, status = errSecParam);
289
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);
294
295 CFDictionaryForEach(parameters, ^(const void *key, const void *value) {
296 if (!CFEqual(key, kSecPrivateKeyAttrs) && !CFEqual(key, kSecPublicKeyAttrs)) {
297 CFDictionarySetValue(attrs, key, value);
298 }
299 });
300 CFDictionaryRemoveValue(attrs, kSecValueData);
301 CFDictionarySetValue(attrs, kSecClass, kSecClassKey);
302 CFDictionarySetValue(attrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
303 CFDictionarySetValue(attrs, kSecReturnRef, kCFBooleanTrue);
304
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);
307
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);
316 }
317
318 if (*publicKey != NULL) {
319 status = errSecSuccess;
320 } else {
321 status = errSecInvalidKey;
322 CFReleaseNull(*privateKey);
323 }
324
325 out:
326 CFReleaseSafe(attrs);
327 CFReleaseSafe(publicData);
328 return status;
329 }
330
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);
334 return NULL;
335 }
336
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
355 };
356
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
375 };
376
377 CFDataRef objectID = (keyType == kSecKeyAttestationKeyTypeSIK) ?
378 CFDataCreate(kCFAllocatorDefault, sikObjectIDBytes, sizeof(sikObjectIDBytes)) :
379 CFDataCreate(kCFAllocatorDefault, gidObjectIDBytes, sizeof(gidObjectIDBytes)) ;
380
381 const void *keys[] = { kSecUseToken, kSecUseTokenObjectID, kSecAttrTokenID };
382 const void *values[] = { kCFNull, objectID, CFSTR("com.apple.setoken.attest") };
383
384 CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault,
385 keys, values, sizeof(keys) / sizeof(*keys),
386 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
387
388 return SecKeyCreateCTKKey(kCFAllocatorDefault, attributes, error);
389 }
390
391 CFDataRef SecKeyCreateAttestation(SecKeyRef key, SecKeyRef keyToAttest, CFErrorRef *error) {
392 if (!key || !keyToAttest) {
393 SecError(errSecParam, error, CFSTR("attestation key(s) is NULL"));
394 return NULL;
395 }
396
397 SecCTKKeyData *attestingKeyData = key->key;
398 SecCTKKeyData *keyToAttestData = keyToAttest->key;
399
400 if (key->key_class != &kSecCTKKeyDescriptor) {
401 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported by key %@"), key);
402 return NULL;
403 }
404 if (keyToAttest->key_class != &kSecCTKKeyDescriptor || CFEqual(keyToAttestData->token, kCFNull)) {
405 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported for key %@"), keyToAttest);
406 return NULL;
407 }
408
409 const void *keys[] = {
410 CFSTR(kTKTokenControlAttribAttestingKey),
411 CFSTR(kTKTokenControlAttribKeyToAttest),
412 };
413 const void *values[] = {
414 attestingKeyData->objectID,
415 keyToAttestData->objectID
416 };
417
418 CFDictionaryRef attributes = NULL;
419 __block CFDictionaryRef outputAttributes = NULL;
420 CFDataRef attestationData = NULL;
421 __block SecCFDictionaryCOW sign_auth_params = { keyToAttestData->auth_params.dictionary };
422
423 attributes = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(*keys),
424 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
425
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);
429 });
430 require(outputAttributes, out);
431
432 attestationData = CFDictionaryGetValue(outputAttributes, CFSTR(kTKTokenControlAttribAttestationData));
433 require_action(attestationData, out, SecError(errSecInternal, error, CFSTR("could not get attestation data")));
434
435 if (CFGetTypeID(attestationData) != CFDataGetTypeID()) {
436 SecError(errSecInternal, error, CFSTR("unexpected attestation object type"));
437 attestationData = NULL;
438 }
439
440 CFRetainSafe(attestationData);
441
442 out:
443 CFReleaseSafe(attributes);
444 CFReleaseSafe(outputAttributes);
445 return attestationData;
446 }
447
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;
453
454 static const CFStringRef *const knownUseFlags[] = {
455 &kSecUseOperationPrompt,
456 &kSecUseAuthenticationContext,
457 &kSecUseAuthenticationUI,
458 &kSecUseCallerName,
459 &kSecUseCredentialReference,
460 };
461
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)) {
466 isUseFlag = true;
467 break;
468 }
469 }
470
471 if (CFEqual(name, kSecUseAuthenticationContext)) {
472 // Preprocess LAContext to ACMRef value.
473 if (value != NULL) {
474 require_quiet(acm_reference = SecItemAttributesCopyPreparedAuthContext(value, error), out);
475 value = acm_reference;
476 }
477 name = kSecUseCredentialReference;
478 }
479
480 if (isUseFlag) {
481 // Release existing token connection to enforce creation of new connection with new auth params.
482 CFReleaseNull(kd->token);
483 if (value != NULL) {
484 CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->auth_params), name, value);
485 } else {
486 CFDictionaryRemoveValue(SecCFDictionaryCOWGetMutable(&kd->auth_params), name);
487 }
488 } else {
489 if (kd->params == NULL) {
490 kd->params = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
491 }
492 if (value != NULL) {
493 CFDictionarySetValue(kd->params, name, value);
494 } else {
495 CFDictionaryRemoveValue(kd->params, name);
496 }
497 }
498
499 out:
500 CFReleaseSafe(acm_reference);
501 return TRUE;
502 }