]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCTKKey.c
Security-57740.1.18.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 <ctkclient.h>
34 #include <libaks_acl_cf_keys.h>
35
36 #if TKTOKEN_CLIENT_INTERFACE_VERSION <= 1
37 #define kTKTokenCreateAttributeAuxParams "auxParams"
38 #endif
39
40 #include "SecECKey.h"
41 #include "SecRSAKey.h"
42 #include "SecCTKKeyPriv.h"
43
44 const CFStringRef kSecUseToken = CFSTR("u_Token");
45 const CFStringRef kSecUseTokenObjectID = CFSTR("u_TokenOID");
46
47 typedef struct {
48 TKTokenRef token;
49 CFStringRef token_id;
50 CFDataRef objectID;
51 SecCFDictionaryCOW auth_params;
52 SecCFDictionaryCOW attributes;
53 CFMutableDictionaryRef params;
54 } SecCTKKeyData;
55
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);
64 }
65
66 static CFIndex SecCTKGetAlgorithmID(SecKeyRef key) {
67 SecCTKKeyData *kd = key->key;
68 CFTypeRef type = CFDictionaryGetValue(kd->attributes.dictionary, kSecAttrKeyType);
69 if (type != NULL) {
70 if (CFGetTypeID(type) == CFNumberGetTypeID()) {
71 CFIndex keyType;
72 if (CFNumberGetValue(type, kCFNumberCFIndexType, &keyType) && keyType == 73 /* kSecAttrKeyTypeEC */)
73 return kSecECDSAAlgorithmID;
74 } else if (CFGetTypeID(type) == CFStringGetTypeID() && CFEqual(type, kSecAttrKeyTypeEC)) {
75 return kSecECDSAAlgorithmID;
76 }
77 }
78 return kSecRSAAlgorithmID;
79 }
80
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));
88
89 CFReleaseNull(*error);
90 CFRelease(ac_pair);
91 CFRelease(access_control);
92 return kSecItemAuthResultNeedAuth;
93 }
94 }
95 return kSecItemAuthResultError;
96 }
97
98 static const CFTypeRef *aclOperations[] = {
99 [kSecKeyOperationTypeSign] = &kAKSKeyOpSign,
100 [kSecKeyOperationTypeDecrypt] = &kAKSKeyOpDecrypt,
101 [kSecKeyOperationTypeKeyExchange] = &kAKSKeyOpComputeKey,
102 };
103
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;
111
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);
119 }
120 CFAssignRetained(token, SecTokenCreate(kd->token_id, attributes.dictionary, error));
121 CFReleaseSafe(attributes.mutable_dictionary);
122 if (token == NULL) {
123 return kSecItemAuthResultError;
124 }
125 }
126
127 #if TKTOKEN_CLIENT_INTERFACE_VERSION >= 1
128 result = TKTokenCopyOperationResult(token, kd->objectID, operation, algorithms, mode, in1, in2, error);
129 #else
130 result = TKTokenCopyCryptoResult(token, kd->objectID, operation, (CFIndex)algorithm, in1, in2, error);
131 #endif
132 return (result != NULL) ? kSecItemAuthResultOK : SecCTKProcessError(*aclOperations[operation], token,
133 kd->objectID, ac_pairs, error);
134 });
135
136 CFErrorPropagate(localError, error);
137 CFReleaseSafe(auth_params.mutable_dictionary);
138 CFReleaseSafe(token);
139 return result;
140 }
141
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()) {
146 CFIndex bitSize;
147 if (CFNumberGetValue(keySize, kCFNumberCFIndexType, &bitSize))
148 return (bitSize + 7) / 8;
149 }
150
151 return 0;
152 }
153
154 static OSStatus SecCTKKeyCopyPublicOctets(SecKeyRef key, CFDataRef *data) {
155 OSStatus status = errSecSuccess;
156 CFErrorRef error = NULL;
157 CFDataRef publicData = NULL;
158
159 SecCTKKeyData *kd = key->key;
160 require_action_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out,
161 status = SecErrorGetOSStatus(error));
162 *data = publicData;
163
164 out:
165 CFReleaseSafe(error);
166 return status;
167 }
168
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);
173 }
174
175 // Attributes allowed to be exported from all internal key attributes.
176 static const CFStringRef *kSecExportableCTKKeyAttributes[] = {
177 &kSecClass,
178 &kSecAttrTokenID,
179 &kSecAttrKeyClass,
180 &kSecAttrIsPermanent,
181 &kSecAttrIsPrivate,
182 &kSecAttrIsModifiable,
183 &kSecAttrKeyType,
184 &kSecAttrKeySizeInBits,
185 &kSecAttrEffectiveKeySize,
186 &kSecAttrIsSensitive,
187 &kSecAttrWasAlwaysSensitive,
188 &kSecAttrIsExtractable,
189 &kSecAttrWasNeverExtractable,
190 &kSecAttrCanEncrypt,
191 &kSecAttrCanDecrypt,
192 &kSecAttrCanDerive,
193 &kSecAttrCanSign,
194 &kSecAttrCanVerify,
195 &kSecAttrCanSignRecover,
196 &kSecAttrCanVerifyRecover,
197 &kSecAttrCanWrap,
198 &kSecAttrCanUnwrap,
199 NULL
200 };
201
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;
207
208 // Encode ApplicationLabel as SHA1 digest of public key bytes.
209 require_quiet(publicData = TKTokenCopyPublicKeyData(kd->token, kd->objectID, &error), out);
210
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);
215
216 for (const CFStringRef **attrKey = &kSecExportableCTKKeyAttributes[0]; *attrKey != NULL; attrKey++) {
217 CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrKey);
218 if (value != NULL) {
219 CFDictionarySetValue(attrs, **attrKey, value);
220 }
221 }
222
223 out:
224 CFReleaseSafe(error);
225 CFReleaseSafe(publicData);
226 CFReleaseSafe(digest);
227 return attrs;
228 }
229
230 static SecKeyDescriptor kSecCTKKeyDescriptor = {
231 .version = kSecKeyDescriptorVersion,
232 .name = "CTKKey",
233 .extraBytes = sizeof(SecCTKKeyData),
234
235 .destroy = SecCTKKeyDestroy,
236 .blockSize = SecCTKKeyBlockSize,
237 .copyDictionary = SecCTKKeyCopyAttributeDictionary,
238 .describe = SecCTKKeyCopyKeyDescription,
239 .getAlgorithmID = SecCTKGetAlgorithmID,
240 .copyPublic = SecCTKKeyCopyPublicOctets,
241 .copyOperationResult = SecCTKKeyCopyOperationResult,
242 };
243
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);
256 }
257 return key;
258 }
259
260 OSStatus SecCTKKeyGeneratePair(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey) {
261 OSStatus status;
262 CFMutableDictionaryRef attrs = NULL;
263 CFDictionaryRef keyAttrs = NULL;
264 CFDataRef publicData = NULL;
265
266 require_action_quiet(publicKey != NULL, out, status = errSecParam);
267 require_action_quiet(privateKey != NULL, out, status = errSecParam);
268
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);
273
274 CFDictionaryForEach(parameters, ^(const void *key, const void *value) {
275 if (!CFEqual(key, kSecPrivateKeyAttrs) && !CFEqual(key, kSecPublicKeyAttrs)) {
276 CFDictionarySetValue(attrs, key, value);
277 }
278 });
279 CFDictionaryRemoveValue(attrs, kSecValueData);
280 CFDictionarySetValue(attrs, kSecClass, kSecClassKey);
281 CFDictionarySetValue(attrs, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
282 CFDictionarySetValue(attrs, kSecReturnRef, kCFBooleanTrue);
283
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);
286
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);
295 }
296
297 if (*publicKey != NULL) {
298 status = errSecSuccess;
299 } else {
300 status = errSecInvalidKey;
301 CFReleaseNull(*privateKey);
302 }
303
304 out:
305 CFReleaseSafe(attrs);
306 CFReleaseSafe(publicData);
307 return status;
308 }
309
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);
313 return NULL;
314 }
315
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
334 };
335
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
354 };
355
356 CFDataRef objectID = (keyType == kSecKeyAttestationKeyTypeSIK) ?
357 CFDataCreate(kCFAllocatorDefault, sikObjectIDBytes, sizeof(sikObjectIDBytes)) :
358 CFDataCreate(kCFAllocatorDefault, gidObjectIDBytes, sizeof(gidObjectIDBytes)) ;
359
360 const void *keys[] = { kSecUseToken, kSecUseTokenObjectID, kSecAttrTokenID };
361 const void *values[] = { kCFNull, objectID, CFSTR("com.apple.setoken.attest") };
362
363 CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault,
364 keys, values, sizeof(keys) / sizeof(*keys),
365 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
366
367 return SecKeyCreateCTKKey(kCFAllocatorDefault, attributes, error);
368 }
369
370 CFDataRef SecKeyCreateAttestation(SecKeyRef key, SecKeyRef keyToAttest, CFErrorRef *error) {
371 if (!key || !keyToAttest) {
372 SecError(errSecParam, error, CFSTR("attestation key(s) is NULL"));
373 return NULL;
374 }
375
376 SecCTKKeyData *attestingKeyData = key->key;
377 SecCTKKeyData *keyToAttestData = keyToAttest->key;
378
379 if (key->key_class != &kSecCTKKeyDescriptor) {
380 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported by key %@"), key);
381 return NULL;
382 }
383 if (keyToAttest->key_class != &kSecCTKKeyDescriptor || CFEqual(keyToAttestData->token, kCFNull)) {
384 SecError(errSecUnsupportedOperation, error, CFSTR("attestation not supported for key %@"), keyToAttest);
385 return NULL;
386 }
387
388 const void *keys[] = {
389 CFSTR(kTKTokenControlAttribAttestingKey),
390 CFSTR(kTKTokenControlAttribKeyToAttest),
391 };
392 const void *values[] = {
393 attestingKeyData->objectID,
394 keyToAttestData->objectID
395 };
396
397 CFDictionaryRef attributes = NULL;
398 __block CFDictionaryRef outputAttributes = NULL;
399 CFDataRef attestationData = NULL;
400 __block SecCFDictionaryCOW sign_auth_params = { keyToAttestData->auth_params.dictionary };
401
402 attributes = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys) / sizeof(*keys),
403 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
404
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);
408 });
409 require(outputAttributes, out);
410
411 attestationData = CFDictionaryGetValue(outputAttributes, CFSTR(kTKTokenControlAttribAttestationData));
412 require_action(attestationData, out, SecError(errSecInternal, error, CFSTR("could not get attestation data")));
413
414 if (CFGetTypeID(attestationData) != CFDataGetTypeID()) {
415 SecError(errSecInternal, error, CFSTR("unexpected attestation object type"));
416 attestationData = NULL;
417 }
418
419 CFRetainSafe(attestationData);
420
421 out:
422 CFReleaseSafe(attributes);
423 CFReleaseSafe(outputAttributes);
424 return attestationData;
425 }
426
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);
433 }
434 if (value != NULL) {
435 CFDictionarySetValue(kd->params, name, value);
436 } else {
437 CFDictionaryRemoveValue(kd->params, name);
438 }
439
440 out:
441 return TRUE;
442 }