]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecDbKeychainItem.m
Security-59306.11.20.tar.gz
[apple/security.git] / OSX / sec / securityd / SecDbKeychainItem.m
1 /*
2 * Copyright (c) 2006-2014 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 /*
25 * SecDbKeychainItem.c - CoreFoundation-based constants and functions for
26 access to Security items (certificates, keys, identities, and
27 passwords.)
28 */
29
30 #include <securityd/SecDbKeychainItem.h>
31
32 #import "SecInternalReleasePriv.h"
33 #include <securityd/SecItemSchema.h>
34 #include <securityd/SecItemServer.h>
35 #include <securityd/SecItemDb.h>
36 #include <CommonCrypto/CommonCryptor.h>
37 #include <CommonCrypto/CommonCryptorSPI.h>
38 #include <Security/SecBasePriv.h>
39 #include <Security/SecItem.h>
40 #include <Security/SecItemPriv.h>
41 #include <Security/SecItemInternal.h>
42 #include <Security/SecRandom.h>
43 #include <Security/SecAccessControl.h>
44 #include <Security/SecAccessControlPriv.h>
45 #include <utilities/der_plist.h>
46 #include <utilities/der_plist_internal.h>
47 #include <utilities/SecCFCCWrappers.h>
48 #import "SecDbKeychainItemV7.h"
49 #import "SecDbKeychainMetadataKeyStore.h"
50 #import "sec_action.h"
51
52 #if USE_KEYSTORE
53 #include <LocalAuthentication/LAPublicDefines.h>
54 #include <LocalAuthentication/LAPrivateDefines.h>
55 #include <coreauthd_spi.h>
56 #include <libaks_acl_cf_keys.h>
57 #include <securityd/spi.h>
58
59 #endif /* USE_KEYSTORE */
60
61 #include "OSX/utilities/SecAKSWrappers.h"
62
63 pthread_key_t CURRENT_CONNECTION_KEY;
64
65 // From SecItemServer, should be a acl-check block
66 bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups);
67
68 static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error);
69 static CFTypeRef kc_encode_keyclass(keyclass_t keyclass);
70 static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control);
71 static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end);
72 static CF_RETURNS_RETAINED CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error);
73 static CF_RETURNS_RETAINED CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error);
74 #if USE_KEYSTORE
75 static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version,
76 CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error);
77 static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes);
78 static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error);
79 #endif
80
81 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl, CFOptionFlags mutability, CFPropertyListRef* cf, CFErrorRef *error,
82 const uint8_t* der, const uint8_t *der_end,
83 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
84 const uint8_t* der, const uint8_t *der_end));
85 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFDictionaryRef* dictionary, CFErrorRef *error,
86 const uint8_t* der, const uint8_t *der_end,
87 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
88 const uint8_t* der, const uint8_t *der_end));
89 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
90 const uint8_t* der, const uint8_t *der_end,
91 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
92 const uint8_t* der, const uint8_t *der_end));
93 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFArrayRef* array, CFErrorRef *error,
94 const uint8_t* der, const uint8_t *der_end,
95 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
96 const uint8_t* der, const uint8_t *der_end));
97 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFSetRef* set, CFErrorRef *error,
98 const uint8_t* der, const uint8_t *der_end,
99 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
100 const uint8_t* der, const uint8_t *der_end));
101
102 const uint32_t kUseDefaultIVMask = 1<<31;
103 const int16_t kIVSizeAESGCM = 12;
104
105 // echo "keychainblobstaticiv" | openssl dgst -sha256 | cut -c1-24 | xargs -I {} echo "0x{}" | xxd -r | xxd -p -i
106 static const uint8_t gcmIV[kIVSizeAESGCM] = {
107 0x1e, 0xa0, 0x5c, 0xa9, 0x98, 0x2e, 0x87, 0xdc, 0xf1, 0x45, 0xe8, 0x24
108 };
109
110 /* Given plainText create and return a CFDataRef containing:
111 BULK_KEY = RandomKey()
112 version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) ||
113 AES(BULK_KEY, NULL_IV, plainText || padding)
114 */
115 bool ks_encrypt_data_legacy(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
116 CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) {
117 CFMutableDataRef blob = NULL;
118 CFDataRef ac_data = NULL;
119 bool ok = true;
120 //check(keybag >= 0);
121
122 /* Precalculate output blob length. */
123 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
124 const uint32_t maxKeyWrapOverHead = 8 + 32;
125 uint8_t bulkKey[bulkKeySize];
126 CFMutableDataRef bulkKeyWrapped = CFDataCreateMutable(NULL, 0);
127 CFDataSetLength(bulkKeyWrapped, bulkKeySize + maxKeyWrapOverHead);
128 uint32_t key_wrapped_size;
129 size_t ivLen = 0;
130 const uint8_t *iv = NULL;
131 const uint8_t *aad = NULL; // Additional Authenticated Data
132 ptrdiff_t aadLen = 0;
133
134 #if USE_KEYSTORE
135 CFDataRef auth_data = NULL;
136 #endif
137
138 /* If access_control specifies only protection and no ACL, use legacy blob format version 3,
139 which has better support for sync/backup. Otherwise, force new format v6 unless useDefaultIV is set. */
140 bool hasACLConstraints = SecAccessControlGetConstraints(access_control);
141 const uint32_t version = (hasACLConstraints ? 6 : 3);
142 CFDataRef plainText = NULL;
143 if (version < 4) {
144 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
145 if (authenticated_attributes) {
146 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
147 CFDictionaryAddValue(attributes_dict, key, value);
148 });
149 }
150
151 if (attributes_dict) {
152 // Drop the accc attribute for non v6 items during encode.
153 CFDictionaryRemoveValue(attributes_dict, kSecAttrAccessControl);
154 plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error);
155 CFRelease(attributes_dict);
156 }
157 } else {
158 #if USE_KEYSTORE
159 if (attributes) {
160 plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes, error);
161 }
162 #else
163 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
164 if (authenticated_attributes) {
165 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
166 CFDictionaryAddValue(attributes_dict, key, value);
167 });
168 }
169
170 if (attributes_dict) {
171 plainText = CFPropertyListCreateDERData(kCFAllocatorDefault, attributes_dict, error);
172 CFRelease(attributes_dict);
173 }
174 #endif
175 }
176
177 if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID()
178 || access_control == 0) {
179 ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text"));
180 goto out;
181 }
182
183 size_t ptLen = CFDataGetLength(plainText);
184 size_t ctLen = ptLen;
185 size_t tagLen = 16;
186 keyclass_t actual_class = 0;
187
188 if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) {
189 ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
190 goto out;
191 }
192
193 /* Extract keyclass from access control. */
194 keyclass_t keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error);
195 if (!keyclass)
196 goto out;
197
198 #if USE_KEYSTORE
199 if (version >= 4) {
200 auth_data = kc_create_auth_data(access_control, authenticated_attributes);
201 require_quiet(ok = ks_encrypt_acl(keybag, keyclass, bulkKeySize, bulkKey, bulkKeyWrapped, auth_data, acm_context, access_control, error), out);
202 } else
203 #endif
204 {
205 /* Encrypt bulkKey. */
206 require_quiet(ok = ks_crypt(kAKSKeyOpEncrypt, keybag,
207 keyclass, bulkKeySize, bulkKey,
208 &actual_class, bulkKeyWrapped,
209 error), out);
210 }
211
212 key_wrapped_size = (uint32_t)CFDataGetLength(bulkKeyWrapped);
213 UInt8 *cursor;
214 size_t blobLen = sizeof(version);
215 uint32_t prot_length = 0;
216
217 if (!hasACLConstraints) {
218 blobLen += sizeof(actual_class);
219 } else {
220 require_quiet(ac_data = kc_copy_protection_data(access_control), out);
221 prot_length = (uint32_t)CFDataGetLength(ac_data);
222 blobLen += sizeof(prot_length) + prot_length;
223 }
224
225 blobLen += sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen;
226 require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out);
227 CFDataSetLength(blob, blobLen);
228 cursor = CFDataGetMutableBytePtr(blob);
229
230 *((uint32_t *)cursor) = useDefaultIV ? (version | kUseDefaultIVMask) : version;
231 cursor += sizeof(version);
232
233 //secerror("class: %d actual class: %d", keyclass, actual_class);
234 if (!hasACLConstraints) {
235 *((keyclass_t *)cursor) = actual_class;
236 cursor += sizeof(keyclass);
237 } else {
238 *((uint32_t *)cursor) = prot_length;
239 cursor += sizeof(prot_length);
240
241 CFDataGetBytes(ac_data, CFRangeMake(0, prot_length), cursor);
242 cursor += prot_length;
243 }
244
245 *((uint32_t *)cursor) = key_wrapped_size;
246 cursor += sizeof(key_wrapped_size);
247
248 if (useDefaultIV) {
249 iv = gcmIV;
250 ivLen = kIVSizeAESGCM;
251 // AAD is (version || ac_data || key_wrapped_size)
252 aad = CFDataGetMutableBytePtr(blob);
253 aadLen = cursor - aad;
254 }
255
256 memcpy(cursor, CFDataGetBytePtr(bulkKeyWrapped), key_wrapped_size);
257 cursor += key_wrapped_size;
258
259 /* Encrypt the plainText with the bulkKey. */
260 CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128,
261 bulkKey, bulkKeySize,
262 iv, ivLen, /* iv */
263 aad, aadLen, /* auth data */
264 CFDataGetBytePtr(plainText), ptLen,
265 cursor,
266 cursor + ctLen, &tagLen);
267 if (ccerr) {
268 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr);
269 goto out;
270 }
271 if (tagLen != 16) {
272 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
273 goto out;
274 }
275
276 out:
277 memset(bulkKey, 0, sizeof(bulkKey));
278 CFReleaseSafe(ac_data);
279 CFReleaseSafe(bulkKeyWrapped);
280 CFReleaseSafe(plainText);
281 if (!ok) {
282 CFReleaseSafe(blob);
283 } else {
284 *pBlob = blob;
285 }
286
287 #if USE_KEYSTORE
288 CFReleaseSafe(auth_data);
289 #endif
290 return ok;
291 }
292
293 static void
294 ks_warn_non_device_keybag(void)
295 {
296 static dispatch_once_t once;
297 static sec_action_t action;
298
299 dispatch_once(&once, ^{
300 action = sec_action_create("non-device keybag", 2);
301 sec_action_set_handler(action, ^{
302 secwarning("ks_encrypt_data: called with non-device keybag - call should be rerouted to ks_encrypt_data_legacy");
303 });
304 });
305 sec_action_perform(action);
306 }
307
308 bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
309 CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) {
310 return ks_encrypt_data_with_backupuuid(keybag, access_control, acm_context, secretData, attributes, authenticated_attributes, pBlob, NULL, useDefaultIV, error);
311 }
312
313 bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
314 CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFDataRef *bkUUID, bool useDefaultIV, CFErrorRef *error) {
315 if (keybag != KEYBAG_DEVICE) {
316 ks_warn_non_device_keybag();
317
318 CFMutableDictionaryRef allAttributes = CFDictionaryCreateMutableCopy(NULL, CFDictionaryGetCount(secretData) + CFDictionaryGetCount(attributes), attributes);
319 CFDictionaryForEach(secretData, ^(const void *key, const void *value) {
320 CFDictionaryAddValue(allAttributes, key, value);
321 });
322 bool result = ks_encrypt_data_legacy(keybag, access_control, acm_context, allAttributes, authenticated_attributes, pBlob, useDefaultIV, error);
323 CFReleaseNull(allAttributes);
324 return result;
325 }
326
327 keyclass_t key_class = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error);
328 if (!key_class) {
329 return false;
330 }
331
332 if (SecAccessControlGetConstraints(access_control)) {
333 NSMutableDictionary* allAttributes = [(__bridge NSDictionary*)attributes mutableCopy];
334 [allAttributes addEntriesFromDictionary:(__bridge NSDictionary*)secretData];
335 return ks_encrypt_data_legacy(keybag, access_control, acm_context, (__bridge CFDictionaryRef)allAttributes, authenticated_attributes, pBlob, useDefaultIV, error);
336 }
337
338 bool success = false;
339 @autoreleasepool {
340 NSMutableDictionary* metadataAttributes = attributes ? [(__bridge NSDictionary*)attributes mutableCopy] : [NSMutableDictionary dictionary];
341 [metadataAttributes addEntriesFromDictionary:(__bridge NSDictionary*)authenticated_attributes];
342 metadataAttributes[@"SecAccessControl"] = (__bridge_transfer NSData*)SecAccessControlCopyData(access_control);
343
344 NSString* tamperCheck = [[NSUUID UUID] UUIDString]; // can use the item persistent reference when that starts getting filled in
345 SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithSecretAttributes:(__bridge NSDictionary*)secretData metadataAttributes:metadataAttributes tamperCheck:tamperCheck keyclass:key_class];
346
347 NSError* localError = nil;
348 NSData* encryptedBlob = [item encryptedBlobWithKeybag:keybag accessControl:access_control acmContext:(__bridge NSData*)acm_context error:&localError];
349 if (encryptedBlob) {
350 NSMutableData* encryptedBlobWithVersion = [NSMutableData dataWithLength:encryptedBlob.length + sizeof(uint32_t)];
351 *((uint32_t*)encryptedBlobWithVersion.mutableBytes) = (uint32_t)7;
352 memcpy((uint32_t*)encryptedBlobWithVersion.mutableBytes + 1, encryptedBlob.bytes, encryptedBlob.length);
353 *pBlob = (__bridge_retained CFDataRef)encryptedBlobWithVersion;
354 if (bkUUID && item.backupUUID) { // TODO: Failing this should turn into at least a stern warning at some point
355 *bkUUID = (__bridge_retained CFDataRef)[item.backupUUID copy];
356 }
357 success = true;
358 }
359 else {
360 if (error) {
361 *error = (__bridge_retained CFErrorRef)localError;
362 }
363 }
364 }
365
366 return success;
367 }
368
369 /* Given cipherText containing:
370 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
371 AES(BULK_KEY, NULL_IV, plainText || padding)
372 return the plainText. */
373 bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef *paccess_control, CFDataRef acm_context,
374 CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups,
375 CFMutableDictionaryRef *attributes_p, uint32_t *version_p, bool decryptSecretData, keyclass_t* outKeyclass, CFErrorRef *error) {
376 const uint32_t v0KeyWrapOverHead = 8;
377 CFMutableDataRef bulkKey = CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */
378 CFDataSetLength(bulkKey, 32); /* Use 256 bit AES key for bulkKey. */
379 bool ok = true;
380 SecAccessControlRef access_control = NULL;
381
382 if (attributes_p)
383 *attributes_p = NULL;
384 if (version_p)
385 *version_p = 0;
386
387 CFMutableDataRef plainText = NULL;
388 CFMutableDictionaryRef attributes = NULL;
389 uint32_t version = 0;
390 size_t ivLen = 0;
391 const uint8_t *iv = NULL;
392 const uint8_t *aad = NULL; // Additional Authenticated Data
393 ptrdiff_t aadLen = 0;
394
395 #if USE_KEYSTORE
396 CFMutableDictionaryRef authenticated_attributes = NULL;
397 CFDataRef caller_access_groups_data = NULL;
398 CFDataRef ed_data = NULL;
399 aks_ref_key_t ref_key = NULL;
400 #if TARGET_OS_IPHONE
401 check(keybag >= 0);
402 #else
403 check((keybag >= 0) || (keybag == session_keybag_handle));
404 #endif
405 #endif
406
407 if (!blob) {
408 ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob"));
409 goto out;
410 }
411
412 size_t blobLen = CFDataGetLength(blob);
413 const uint8_t *cursor = CFDataGetBytePtr(blob);
414 keyclass_t keyclass;
415
416 if (blobLen < sizeof(version)) {
417 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (length)"));
418 goto out;
419 }
420
421 version = *((uint32_t *)cursor);
422 if (version & kUseDefaultIVMask) {
423 version &= ~kUseDefaultIVMask;
424 iv = gcmIV;
425 ivLen = kIVSizeAESGCM;
426 }
427
428 cursor += sizeof(version);
429 blobLen -= sizeof(version);
430
431 bool hasProtectionData = (version >= 4 && version < 7);
432
433 if (version >= 7) {
434 @autoreleasepool {
435 NSError* localError = nil;
436 NSData* encryptedBlob = [NSData dataWithBytes:cursor length:blobLen];
437 SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithData:encryptedBlob decryptionKeybag:keybag error:&localError];
438 if (outKeyclass) {
439 *outKeyclass = item.keyclass;
440 }
441
442 NSMutableDictionary* itemAttributes = [[item metadataAttributesWithError:&localError] mutableCopy];
443 if (itemAttributes && !localError) {
444 NSData* accessControlData = itemAttributes[@"SecAccessControl"];
445 access_control = SecAccessControlCreateFromData(NULL, (__bridge CFDataRef)accessControlData, error);
446 [itemAttributes removeObjectForKey:@"SecAccessControl"];
447
448 if (decryptSecretData) {
449 NSDictionary* secretAttributes = [item secretAttributesWithAcmContext:(__bridge NSData*)acm_context accessControl:access_control callerAccessGroups:(__bridge NSArray*)caller_access_groups error:&localError];
450 if (secretAttributes) {
451 [itemAttributes addEntriesFromDictionary:secretAttributes];
452 }
453 else {
454 ok = false;
455 }
456 }
457
458 if (ok) {
459 if (CFEqual(kAKSKeyOpDelete, cryptoOp)) {
460 ok = [item deleteWithAcmContext:(__bridge NSData*)acm_context accessControl:access_control callerAccessGroups:(__bridge NSArray*)caller_access_groups error:&localError];
461 }
462
463 attributes = (__bridge_retained CFMutableDictionaryRef)itemAttributes;
464 }
465 }
466 else {
467 ok = false;
468 }
469
470 if (!ok && error) {
471 *error = (__bridge_retained CFErrorRef)localError;
472 }
473 }
474 goto out;
475 }
476
477 if (hasProtectionData) {
478 /* Deserialize SecAccessControl object from the blob. */
479 uint32_t prot_length;
480
481 /*
482 * Parse proto length
483 */
484
485 if (blobLen < sizeof(prot_length)) {
486 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (prot_length)"));
487 goto out;
488 }
489
490 prot_length = *((uint32_t *)cursor);
491 cursor += sizeof(prot_length);
492 blobLen -= sizeof(prot_length);
493
494 /*
495 * Parse proto itself
496 */
497
498 if (blobLen < prot_length) {
499 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (prot)"));
500 goto out;
501 }
502
503 CFTypeRef protection = kc_copy_protection_from(cursor, cursor + prot_length);
504 if (!protection) {
505 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
506 goto out;
507 } else {
508 access_control = SecAccessControlCreate(NULL, NULL);
509 require_quiet(access_control, out);
510 ok = SecAccessControlSetProtection(access_control, protection, NULL);
511 CFRelease(protection);
512 if (!ok) {
513 SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
514 goto out;
515 }
516 }
517
518 cursor += prot_length;
519 blobLen -= prot_length;
520
521 /*
522 * Get numeric value of keyclass from the access_control.
523 */
524 keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error);
525 if (!keyclass) {
526 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
527 goto out;
528 }
529 } else {
530 if (blobLen < sizeof(keyclass)) {
531 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (keyclass)"));
532 goto out;
533 }
534
535 keyclass = *((keyclass_t *)cursor);
536
537 #if USE_KEYSTORE
538 CFTypeRef protection = kc_encode_keyclass(keyclass & key_class_last); // mask out generation
539 #else
540 CFTypeRef protection = kc_encode_keyclass(keyclass);
541 #endif
542 require_action_quiet(protection, out, ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid keyclass detected")));
543 require_action_quiet(access_control = SecAccessControlCreate(kCFAllocatorDefault, error), out,
544 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlCreate failed")));
545 require_action_quiet(SecAccessControlSetProtection(access_control, protection, error), out,
546 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: SecAccessControlSetProtection failed")));
547
548 cursor += sizeof(keyclass);
549 blobLen -= sizeof(keyclass);
550 }
551
552 size_t tagLen = 0;
553 uint32_t wrapped_key_size = 0;
554
555 switch (version) {
556 case 0:
557 wrapped_key_size = (uint32_t)CFDataGetLength(bulkKey) + v0KeyWrapOverHead;
558 break;
559 case 2:
560 case 3:
561 /* DROPTHROUGH */
562 /* v2 and v3 have the same crypto, just different dictionary encodings. */
563 /* Difference between v3 and v6 is already handled above, so treat v3 as v6. */
564 case 4:
565 case 5:
566 case 6:
567 tagLen = 16;
568 /* DROPTHROUGH */
569 case 1:
570 if (blobLen < sizeof(wrapped_key_size)) {
571 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key_size)"));
572 goto out;
573 }
574 wrapped_key_size = *((uint32_t *)cursor);
575
576 cursor += sizeof(wrapped_key_size);
577 blobLen -= sizeof(wrapped_key_size);
578
579 break;
580 default:
581 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version);
582 goto out;
583 }
584
585 if (blobLen < tagLen + wrapped_key_size) {
586 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (wrapped_key/taglen)"));
587 goto out;
588 }
589
590 size_t ctLen = blobLen - tagLen - wrapped_key_size;
591
592 /*
593 * Pre-version 2 have some additial constraints since it use AES in CBC mode
594 */
595 if (version < 2) {
596 if (ctLen < kCCBlockSizeAES128) {
597 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow (CBC check)"));
598 goto out;
599 }
600 if ((ctLen & 0xF) != 0) {
601 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid length on CBC data"));
602 goto out;
603 }
604 }
605
606 #if USE_KEYSTORE
607 if (hasProtectionData) {
608 if (caller_access_groups) {
609 caller_access_groups_data = kc_copy_access_groups_data(caller_access_groups, error);
610 require_quiet(ok = (caller_access_groups_data != NULL), out);
611 }
612
613 require_quiet(ok = kc_attribs_key_encrypted_data_from_blob(keybag, db_class, cursor, wrapped_key_size, access_control, version,
614 &authenticated_attributes, &ref_key, &ed_data, error), out);
615 if (CFEqual(cryptoOp, kAKSKeyOpDecrypt)) {
616 require_quiet(ok = ks_decrypt_acl(ref_key, ed_data, bulkKey, acm_context, caller_access_groups_data, access_control, error), out);
617 } else if (CFEqual(cryptoOp, kAKSKeyOpDelete)) {
618 require_quiet(ok = ks_delete_acl(ref_key, ed_data, acm_context, caller_access_groups_data, access_control, error), out);
619 attributes = CFRetainSafe(authenticated_attributes);
620 goto out;
621 } else {
622 ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: invalid operation"));
623 goto out;
624 }
625 } else
626 #endif
627 {
628 /* Now unwrap the bulk key using a key in the keybag. */
629 require_quiet(ok = ks_crypt(cryptoOp, keybag,
630 keyclass, wrapped_key_size, cursor, NULL, bulkKey, error), out);
631 }
632
633 if (iv) {
634 // AAD is (version || ... [|| key_wrapped_size ])
635 aad = CFDataGetBytePtr(blob);
636 aadLen = cursor - aad;
637 }
638
639 cursor += wrapped_key_size;
640
641 plainText = CFDataCreateMutable(NULL, ctLen);
642 if (!plainText) {
643 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
644 goto out;
645 }
646 CFDataSetLength(plainText, ctLen);
647
648 /* Decrypt the cipherText with the bulkKey. */
649 CCCryptorStatus ccerr;
650 if (tagLen) {
651 uint8_t tag[tagLen];
652 ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128,
653 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey),
654 iv, ivLen, /* iv */
655 aad, aadLen, /* auth data */
656 cursor, ctLen,
657 CFDataGetMutableBytePtr(plainText),
658 tag, &tagLen);
659 if (ccerr) {
660 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
661 identifies uuid unwrap failures? */
662 /* errSecInteractionNotAllowed; */
663 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr);
664 goto out;
665 }
666 if (tagLen != 16) {
667 ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
668 goto out;
669 }
670 cursor += ctLen;
671 if (timingsafe_bcmp(tag, cursor, tagLen)) {
672 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
673 goto out;
674 }
675 } else {
676 size_t ptLen;
677 ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
678 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), NULL, cursor, ctLen,
679 CFDataGetMutableBytePtr(plainText), ctLen, &ptLen);
680 if (ccerr) {
681 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
682 identifies uuid unwrap failures? */
683 /* errSecInteractionNotAllowed; */
684 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr);
685 goto out;
686 }
687 CFDataSetLength(plainText, ptLen);
688 }
689
690 if (version < 2) {
691 attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
692 CFDictionaryAddValue(attributes, CFSTR("v_Data"), plainText);
693 } else if (version < 3) {
694 attributes = s3dl_item_v2_decode(plainText, error);
695 } else {
696 attributes = s3dl_item_v3_decode(plainText, error);
697 }
698
699 require_action_quiet(attributes, out, { ok = false; secerror("decode v%d failed: %@", version, error ? *error : NULL); });
700
701 #if USE_KEYSTORE
702 if (version >= 4 && authenticated_attributes != NULL) {
703 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
704 CFDictionaryAddValue(attributes, key, value);
705 });
706 }
707 #endif
708
709 out:
710 memset(CFDataGetMutableBytePtr(bulkKey), 0, CFDataGetLength(bulkKey));
711 CFReleaseNull(bulkKey);
712 CFReleaseNull(plainText);
713
714 // Always copy access control data (if present), because if we fail it may indicate why.
715 if (paccess_control)
716 *paccess_control = access_control;
717 else
718 CFReleaseNull(access_control);
719
720 if (ok) {
721 if (attributes_p)
722 CFRetainAssign(*attributes_p, attributes);
723 if (version_p)
724 *version_p = version;
725 }
726 CFReleaseNull(attributes);
727 #if USE_KEYSTORE
728 CFReleaseNull(authenticated_attributes);
729 CFReleaseNull(caller_access_groups_data);
730 CFReleaseNull(ed_data);
731 if (ref_key) aks_ref_key_free(&ref_key);
732 #endif
733 return ok;
734 }
735
736 static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error) {
737 if (!isString(value)) {
738 SecError(errSecParam, error, CFSTR("accessible attribute %@ not a string"), value);
739 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) {
740 return key_class_ak;
741 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) {
742 return key_class_ck;
743 } else if (CFEqual(value, kSecAttrAccessibleAlwaysPrivate)) {
744 return key_class_dk;
745 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) {
746 return key_class_aku;
747 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) {
748 return key_class_cku;
749 } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate)) {
750 return key_class_dku;
751 } else if (CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) {
752 return key_class_akpu;
753 } else {
754 SecError(errSecParam, error, CFSTR("accessible attribute %@ unknown"), value);
755 }
756 return 0;
757 }
758
759 static CFTypeRef kc_encode_keyclass(keyclass_t keyclass) {
760 switch (keyclass) {
761 case key_class_ak:
762 return kSecAttrAccessibleWhenUnlocked;
763 case key_class_ck:
764 return kSecAttrAccessibleAfterFirstUnlock;
765 case key_class_dk:
766 return kSecAttrAccessibleAlwaysPrivate;
767 case key_class_aku:
768 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
769 case key_class_cku:
770 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
771 case key_class_dku:
772 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate;
773 case key_class_akpu:
774 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;
775 default:
776 return 0;
777 }
778 }
779
780 #if USE_KEYSTORE
781 static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, const SecDbClass *class, const void *blob_data, size_t blob_data_len, SecAccessControlRef access_control, uint32_t version,
782 CFMutableDictionaryRef *authenticated_attributes, aks_ref_key_t *ref_key, CFDataRef *encrypted_data, CFErrorRef *error)
783 {
784 CFMutableDictionaryRef acl = NULL;
785 CFDictionaryRef blob_dict = NULL;
786 aks_ref_key_t tmp_ref_key = NULL;
787 CFDataRef key_data = NULL;
788 CFDataRef ed = NULL;
789 bool ok = false;
790
791 der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)&blob_dict, NULL, blob_data, blob_data + blob_data_len);
792 require_action_quiet(blob_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'")));
793
794 if (!ks_separate_data_and_key(blob_dict, &ed, &key_data)) {
795 ed = CFDataCreate(kCFAllocatorDefault, blob_data, blob_data_len);
796 key_data = CFRetain(ed);
797 }
798 require_action_quiet(ed, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data'")));
799 require_action_quiet(key_data, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'key data'")));
800
801 const void *external_data = NULL;
802 size_t external_data_len = 0;
803 require_quiet(external_data = ks_ref_key_get_external_data(keybag, key_data, &tmp_ref_key, &external_data_len, error), out);
804
805 CFPropertyListRef external_data_dict = NULL;
806 der_decode_plist(NULL, kCFPropertyListImmutable, &external_data_dict, NULL, external_data, external_data + external_data_len);
807 require_action_quiet(external_data_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'")));
808 acl = CFDictionaryCreateMutableCopy(NULL, 0, external_data_dict);
809 SecDbForEachAttrWithMask(class, attr_desc, kSecDbInAuthenticatedDataFlag) {
810 CFDictionaryRemoveValue(acl, attr_desc->name);
811 CFTypeRef value = CFDictionaryGetValue(external_data_dict, attr_desc->name);
812 if (value) {
813 if (!*authenticated_attributes)
814 *authenticated_attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
815
816 CFDictionaryAddValue(*authenticated_attributes, attr_desc->name, value);
817 }
818 }
819 CFReleaseSafe(external_data_dict);
820
821 if (acl) {
822 /* v4 data format used wrong ACL placement, for backward compatibility we have to support both formats */
823 if (version == 4) {
824 SecAccessControlSetConstraints(access_control, acl);
825 } else {
826 CFDictionaryRef constraints = CFDictionaryGetValue(acl, kAKSKeyAcl);
827 require_action_quiet(isDictionary(constraints), out,
828 SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: acl missing")));
829 SecAccessControlSetConstraints(access_control, constraints);
830 }
831
832 /* v4/v5 data format usualy does not contain kAKSKeyOpEncrypt, so add kAKSKeyOpEncrypt if is missing */
833 if (version < 6) {
834 SecAccessConstraintRef encryptConstraint = SecAccessControlGetConstraint(access_control, kAKSKeyOpEncrypt);
835 if (!encryptConstraint)
836 SecAccessControlAddConstraintForOperation(access_control, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL);
837 }
838
839 }
840
841 if (encrypted_data)
842 *encrypted_data = CFRetain(ed);
843
844 if (ref_key) {
845 *ref_key = tmp_ref_key;
846 tmp_ref_key = NULL;
847 }
848
849 ok = true;
850
851 out:
852 if (tmp_ref_key)
853 aks_ref_key_free(&tmp_ref_key);
854 CFReleaseSafe(blob_dict);
855 CFReleaseSafe(key_data);
856 CFReleaseSafe(ed);
857 CFReleaseSafe(acl);
858
859
860 return ok;
861 }
862
863 static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes) {
864 CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control);
865 CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, auth_attributes);
866 CFDictionarySetValue(auth_data, kAKSKeyAcl, constraints);
867 CFDataRef encoded = CFPropertyListCreateDERData(kCFAllocatorDefault, auth_data, NULL);
868 CFReleaseSafe(auth_data);
869 return encoded;
870 }
871
872 static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error)
873 {
874 size_t ag_size = der_sizeof_plist(access_groups, error);
875 CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0);
876 CFDataSetLength(result, ag_size);
877 if (!der_encode_plist(access_groups, error, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + ag_size)) {
878 CFRelease(result);
879 return NULL;
880 }
881 else
882 return result;
883 }
884
885 #endif /* USE_KEYSTORE */
886
887 static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control)
888 {
889 CFTypeRef protection = SecAccessControlGetProtection(access_control);
890 size_t protection_size = der_sizeof_plist(protection, NULL);
891 CFMutableDataRef result = CFDataCreateMutable(NULL, 0);
892 CFDataSetLength(result, protection_size);
893 if (!der_encode_plist(protection, NULL, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + protection_size)) {
894 CFRelease(result);
895 return NULL;
896 }
897 else
898 return result;
899 }
900
901 static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end)
902 {
903 CFTypeRef result = NULL;
904 der_decode_plist(NULL, kCFPropertyListImmutable, &result, NULL, der, der_end);
905 return result;
906 }
907
908 /* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */
909 static CF_RETURNS_RETAINED
910 CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED, CFErrorRef *error) {
911 if (plist && !isDictionary(plist)) {
912 CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist));
913 SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName);
914 CFReleaseSafe(typeName);
915 CFReleaseNull(plist);
916 }
917 return (CFMutableDictionaryRef)plist;
918 }
919
920 static CF_RETURNS_RETAINED
921 CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) {
922 CFPropertyListRef item;
923 item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error);
924 return dictionaryFromPlist(item, error);
925 }
926
927 static const uint8_t* (^s3dl_item_v3_decode_repair_date)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, const uint8_t*, const uint8_t*) =
928 ^const uint8_t*(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) {
929 if (error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) {
930 CFAbsoluteTime date = 0;
931 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(allocator, kCFGregorianCalendar);
932 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, 0);
933 CFCalendarSetTimeZone(calendar, tz);
934 CFCalendarComposeAbsoluteTime(calendar, &date, "yMd", 2001, 3, 24); // random date for <rdar://problem/20458954> 15A143: can't recover keychain
935 CFReleaseSafe(tz);
936 CFReleaseSafe(calendar);
937
938 *pl = CFDateCreate(allocator, date);
939 if (NULL != *pl) {
940 CFReleaseNull(*error);
941 return der_end;
942 }
943 }
944 return NULL;
945 };
946
947 static CF_RETURNS_RETAINED
948 CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) {
949 CFPropertyListRef item = NULL;
950 const uint8_t *der_beg = CFDataGetBytePtr(plain);
951 const uint8_t *der_end = der_beg + CFDataGetLength(plain);
952 const uint8_t *der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end);
953 if (!der && error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) {
954 CFReleaseNull(*error);
955 der = der_decode_plist_with_repair(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end, s3dl_item_v3_decode_repair_date);
956 }
957 if (der && der != der_end) {
958 SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error);
959 CFReleaseNull(item);
960 }
961 return dictionaryFromPlist(item, error);
962 }
963
964 bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups,
965 CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error) {
966 SecAccessControlRef ac = NULL;
967 CFDataRef ac_data = NULL;
968 bool ok = false;
969
970 /* Decrypt and decode the item and check the decoded attributes against the query. */
971 uint32_t version = 0;
972
973 bool decryptSecretData = false;
974 if ((q->q_return_type & kSecReturnDataMask) || (q->q_return_type & kSecReturnRefMask)) {
975 decryptSecretData = true;
976 }
977 else if (q->q_match_policy || q->q_match_valid_on_date || q->q_match_trusted_only) {
978 decryptSecretData = true;
979 }
980
981 require_quiet((ok = ks_decrypt_data(q->q_keybag, kAKSKeyOpDecrypt, &ac, q->q_use_cred_handle, edata, q->q_class,
982 q->q_caller_access_groups, item, &version, decryptSecretData, keyclass, error)), out);
983 if (version < 2) {
984 SecError(errSecDecode, error, CFSTR("version is unexpected: %d"), (int)version);
985 ok = false;
986 goto out;
987 }
988
989 ac_data = SecAccessControlCopyData(ac);
990 if (!itemInAccessGroup(*item, accessGroups)) {
991 secerror("items accessGroup '%@' not in %@",
992 CFDictionaryGetValue(*item, kSecAttrAccessGroup),
993 accessGroups);
994 // We likely don't want to surface it to clients like this, but this is most accurate
995 SecError(errSecMissingEntitlement, error, CFSTR("item's access group '%@' not in %@"),
996 CFDictionaryGetValue(*item, kSecAttrAccessGroup), accessGroups);
997 CFReleaseNull(*item);
998 ok = false;
999 goto out;
1000 }
1001
1002 /* AccessControl attribute does not exist in the db, so synthesize it. */
1003 if (version > 3)
1004 CFDictionarySetValue(*item, kSecAttrAccessControl, ac_data);
1005
1006 /* TODO: Validate access_control attribute. */
1007
1008 out:
1009 if (access_control)
1010 *access_control = CFRetainSafe(ac);
1011 CFReleaseSafe(ac);
1012 CFReleaseSafe(ac_data);
1013 return ok;
1014 }
1015
1016 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
1017 being imported from a backup. */
1018 static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) {
1019 bool ok = true;
1020 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
1021 CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible);
1022
1023 if (!isString(agrp) || !isString(accessible))
1024 return ok;
1025 if (SecDbItemGetClass(item) == genp_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) {
1026 CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService);
1027 if (!isString(svce)) return ok;
1028 if (CFEqual(agrp, CFSTR("apple"))) {
1029 if (CFEqual(svce, CFSTR("AirPort"))) {
1030 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
1031 } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) {
1032 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
1033 } else if (CFEqual(svce, CFSTR("YouTube"))) {
1034 ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) &&
1035 SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error));
1036 } else {
1037 CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription);
1038 if (!isString(desc)) return ok;
1039 if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) {
1040 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
1041 }
1042 }
1043 }
1044 } else if (SecDbItemGetClass(item) == inet_class() && CFEqual(accessible, kSecAttrAccessibleAlwaysPrivate)) {
1045 if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) {
1046 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
1047 } else if (CFEqual(agrp, CFSTR("apple"))) {
1048 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
1049 bool is_proxy = false;
1050 if (isNumber(ptcl)) {
1051 SInt32 iptcl;
1052 CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl);
1053 is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') ||
1054 iptcl == FOUR_CHAR_CODE('htsx') ||
1055 iptcl == FOUR_CHAR_CODE('ftpx') ||
1056 iptcl == FOUR_CHAR_CODE('rtsx') ||
1057 iptcl == FOUR_CHAR_CODE('xpth') ||
1058 iptcl == FOUR_CHAR_CODE('xsth') ||
1059 iptcl == FOUR_CHAR_CODE('xptf') ||
1060 iptcl == FOUR_CHAR_CODE('xstr'));
1061 } else if (isString(ptcl)) {
1062 is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) ||
1063 CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) ||
1064 CFEqual(ptcl, kSecAttrProtocolRTSPProxy) ||
1065 CFEqual(ptcl, kSecAttrProtocolFTPProxy));
1066 }
1067 if (is_proxy)
1068 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
1069 }
1070 }
1071 return ok;
1072 }
1073
1074 bool SecDbItemDecrypt(SecDbItemRef item, bool decryptSecretData, CFDataRef edata, CFErrorRef *error) {
1075 bool ok = true;
1076 CFMutableDictionaryRef dict = NULL;
1077 SecAccessControlRef access_control = NULL;
1078 uint32_t version = 0;
1079
1080 require_quiet(ok = ks_decrypt_data(SecDbItemGetKeybag(item), item->cryptoOp, &access_control, item->credHandle, edata,
1081 item->class, item->callerAccessGroups, &dict, &version, decryptSecretData, NULL, error), out);
1082
1083 if (version < 2) {
1084 /* Old V4 style keychain backup being imported. */
1085 ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), CFDictionaryGetValue(dict, CFSTR("v_Data")), error) &&
1086 SecDbItemImportMigrate(item, error);
1087 } else {
1088 ok = dict && SecDbItemSetValues(item, dict, error);
1089 }
1090
1091 SecAccessControlRef my_access_control = SecDbItemCopyAccessControl(item, error);
1092 if (!my_access_control) {
1093 ok = false;
1094 goto out;
1095 }
1096
1097 /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got
1098 back from decoding the data blob. */
1099 if (!CFEqual(SecAccessControlGetProtection(my_access_control), SecAccessControlGetProtection(access_control))) {
1100 ok = SecError(errSecDecode, error, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"),
1101 SecAccessControlGetProtection(my_access_control),
1102 SecAccessControlGetProtection(access_control));
1103 }
1104 CFRelease(my_access_control);
1105
1106 out:
1107 // If we got protection back from ks_decrypt_data, update the appropriate attribute even if anything else
1108 // (incl. actual decryption) failed. We need to access the protection type even if we are not able to actually
1109 // decrypt the data.
1110 ok = SecDbItemSetAccessControl(item, access_control, NULL) && ok;
1111
1112 CFReleaseSafe(dict);
1113 CFReleaseSafe(access_control);
1114 return ok;
1115 }
1116
1117 /* Automagically make a item syncable, based on various attributes. */
1118 bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error)
1119 {
1120 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
1121
1122 if (!isString(agrp))
1123 return true;
1124
1125 if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == inet_class()) {
1126 CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer);
1127 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
1128 CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType);
1129
1130 if (isString(srvr) && isString(ptcl) && isString(atyp)) {
1131 /* This looks like a Mobile Safari Password, make syncable */
1132 secnotice("item", "Make this item syncable: %@", item);
1133 return SecDbItemSetSyncable(item, true, error);
1134 }
1135 }
1136
1137 return true;
1138 }
1139
1140 /* This create a SecDbItem from the item dictionnary that are exported for backups.
1141 Item are stored in the backup as a dictionary containing two keys:
1142 - v_Data: the encrypted data blob
1143 - v_PersistentRef: a persistent Ref.
1144 src_keybag is normally the backup keybag.
1145 dst_keybag is normally the device keybag.
1146 */
1147 SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error)
1148 {
1149 CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data"));
1150 SecDbItemRef item = NULL;
1151
1152 if (edata) {
1153 item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error);
1154 if (item)
1155 if (!SecDbItemSetKeybag(item, dst_keybag, error))
1156 CFReleaseNull(item);
1157 } else {
1158 SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict);
1159 }
1160
1161 return item;
1162 }
1163
1164 bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) {
1165 CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef"));
1166 if (!ref)
1167 return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict);
1168
1169 CFStringRef className;
1170 sqlite3_int64 rowid;
1171 if (!_SecItemParsePersistentRef(ref, &className, &rowid, NULL))
1172 return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref);
1173
1174 if (!CFEqual(SecDbItemGetClass(item)->name, className))
1175 return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className);
1176
1177 return SecDbItemSetRowId(item, rowid, error);
1178 }
1179
1180 static CFDataRef SecDbItemCopyDERWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
1181 CFDataRef der = NULL;
1182 CFMutableDictionaryRef dict = SecDbItemCopyPListWithMask(item, mask, error);
1183 if (dict) {
1184 der = CFPropertyListCreateDERData(kCFAllocatorDefault, dict, error);
1185 CFRelease(dict);
1186 }
1187 return der;
1188 }
1189
1190 static CFTypeRef SecDbItemCopyDigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
1191 CFDataRef digest = NULL;
1192 CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error);
1193 if (der) {
1194 digest = CFDataCopySHA1Digest(der, error);
1195 CFRelease(der);
1196 }
1197 return digest;
1198 }
1199
1200 static CFTypeRef SecDbItemCopySHA256DigestWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
1201 CFDataRef digest = NULL;
1202 CFDataRef der = SecDbItemCopyDERWithMask(item, mask, error);
1203 if (der) {
1204 digest = CFDataCopySHA256Digest(der, error);
1205 CFRelease(der);
1206 }
1207 return digest;
1208 }
1209
1210 CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1211 return SecDbItemCopyDigestWithMask(item, kSecDbPrimaryKeyFlag, error);
1212 }
1213
1214 CFTypeRef SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef *error) {
1215 return SecDbItemCopySHA256DigestWithMask(item, kSecDbPrimaryKeyFlag, error);
1216 }
1217
1218 CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1219 return SecDbItemCopyDigestWithMask(item, kSecDbInHashFlag, error);
1220 }
1221
1222 CFTypeRef SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1223 CFDataRef edata = NULL;
1224 CFDataRef bkuuid = NULL;
1225 CFMutableDictionaryRef secretStuff = SecDbItemCopyPListWithMask(item, kSecDbReturnDataFlag, error);
1226 CFMutableDictionaryRef attributes = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
1227 CFMutableDictionaryRef auth_attributes = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error);
1228 if (secretStuff || attributes || auth_attributes) {
1229 SecAccessControlRef access_control = SecDbItemCopyAccessControl(item, error);
1230 CFDataRef sha1 = SecDbKeychainItemCopySHA1(item, attr, error);
1231 if (access_control && sha1) {
1232 if (!auth_attributes) {
1233 auth_attributes = CFDictionaryCreateMutable(NULL, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1234 }
1235 CFDictionarySetValue(auth_attributes, kSecAttrSHA1, sha1);
1236
1237 CFDictionaryForEach(secretStuff, ^(const void *key, const void *value) {
1238 CFDictionaryRemoveValue(attributes, key);
1239 CFDictionaryRemoveValue(auth_attributes, key);
1240 });
1241
1242 if (ks_encrypt_data_with_backupuuid(item->keybag, access_control, item->credHandle, secretStuff, attributes, auth_attributes, &edata, &bkuuid, true, error)) {
1243 item->_edataState = kSecDbItemEncrypting;
1244 } else if (!error || !*error || CFErrorGetCode(*error) != errSecAuthNeeded || !CFEqualSafe(CFErrorGetDomain(*error), kSecErrorDomain) ) {
1245 seccritical("ks_encrypt_data (db): failed: %@", error ? *error : (CFErrorRef)CFSTR(""));
1246 }
1247 CFRelease(access_control);
1248 }
1249 CFReleaseNull(secretStuff);
1250 CFReleaseNull(attributes);
1251 CFReleaseNull(auth_attributes);
1252 CFReleaseNull(sha1);
1253 if (bkuuid) {
1254 // "data" is defined first in the schema so called first. The UUID will therefore be in the cache when ForEach gets to it
1255 CFErrorRef localError = NULL;
1256 SecDbItemSetValueWithName(item, CFSTR("backupUUID"), bkuuid, &localError);
1257 if (localError) {
1258 // Don't want to propagate this. It's bad but should be handled in the manager and not interrupt production
1259 secerror("Unable to wrap keychain item to backup: %@", localError);
1260 CFReleaseNull(localError);
1261 CFReleaseNull(bkuuid);
1262 }
1263 }
1264 }
1265 return edata;
1266 }
1267
1268 CFTypeRef SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error) {
1269 CFTypeRef value = NULL;
1270 switch (attr->kind) {
1271 case kSecDbDateAttr:
1272 value = CFDateCreate(kCFAllocatorDefault, 0.0);
1273 break;
1274 case kSecDbCreationDateAttr:
1275 case kSecDbModificationDateAttr:
1276 value = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
1277 break;
1278 default:
1279 SecError(errSecInternal, error, CFSTR("attr %@ has no default value"), attr->name);
1280 value = NULL;
1281 }
1282
1283 return value;
1284 }
1285
1286 SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error) {
1287 SecAccessControlRef accc = NULL, pdmn = NULL, result = NULL;
1288 CFTypeRef acccData = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessControlAttr, error), error);
1289 CFTypeRef pdmnValue = SecDbItemGetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), error);
1290
1291 if (!acccData || !pdmnValue)
1292 return NULL;
1293 if (!CFEqual(acccData, kCFNull))
1294 require_quiet(accc = SecAccessControlCreateFromData(CFGetAllocator(item), acccData, error), out);
1295
1296 if (!CFEqual(pdmnValue, kCFNull)) {
1297 require_quiet(pdmn = SecAccessControlCreate(CFGetAllocator(item), error), out);
1298 require_quiet(SecAccessControlSetProtection(pdmn, pdmnValue, error), out);
1299 }
1300
1301 if (accc && pdmn) {
1302 CFTypeRef acccProt = SecAccessControlGetProtection(accc);
1303 CFTypeRef pdmnProt = SecAccessControlGetProtection(pdmn);
1304 if (!acccProt || !pdmnProt || !CFEqual(acccProt, pdmnProt)) {
1305 secerror("SecDbItemCopyAccessControl accc %@ != pdmn %@, setting pdmn to accc value", acccProt, pdmnProt);
1306 __security_simulatecrash(CFSTR("Corrupted item on decrypt accc != pdmn"), __sec_exception_code_CorruptItem);
1307 // Setting pdmn to accc prot value.
1308 require_quiet(SecDbItemSetValue(item, SecDbClassAttrWithKind(item->class, kSecDbAccessAttr, error), acccProt, error), out);
1309 }
1310 }
1311
1312 if (accc)
1313 CFRetainAssign(result, accc);
1314 else if(pdmn)
1315 CFRetainAssign(result, pdmn);
1316
1317 out:
1318 CFReleaseSafe(accc);
1319 CFReleaseSafe(pdmn);
1320
1321 return result;
1322 }
1323
1324 static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1325 CFPropertyListRef* pl, CFErrorRef *error,
1326 const uint8_t* der, const uint8_t *der_end,
1327 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1328 const uint8_t*, const uint8_t*))
1329 {
1330 if (NULL == der) {
1331 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1332 return NULL;
1333 }
1334
1335 ccder_tag tag;
1336 if (NULL == ccder_decode_tag(&tag, der, der_end)) {
1337 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding"), NULL, error);
1338 return NULL;
1339 }
1340
1341 switch (tag) {
1342 case CCDER_NULL:
1343 return der_decode_null(allocator, mutability, (CFNullRef*)pl, error, der, der_end);
1344 case CCDER_BOOLEAN:
1345 return der_decode_boolean(allocator, mutability, (CFBooleanRef*)pl, error, der, der_end);
1346 case CCDER_OCTET_STRING:
1347 return der_decode_data(allocator, mutability, (CFDataRef*)pl, error, der, der_end);
1348 case CCDER_GENERALIZED_TIME: {
1349 const uint8_t* der_result = der_decode_date(allocator, mutability, (CFDateRef*)pl, error, der, der_end);
1350 if (!der_result) {
1351 der_result = repairBlock(allocator, mutability, pl, error, der, der_end);
1352 }
1353 return der_result;
1354 }
1355 case CCDER_CONSTRUCTED_SEQUENCE:
1356 return der_decode_array_with_repair(allocator, mutability, (CFArrayRef*)pl, error, der, der_end, repairBlock);
1357 case CCDER_UTF8_STRING:
1358 return der_decode_string(allocator, mutability, (CFStringRef*)pl, error, der, der_end);
1359 case CCDER_INTEGER:
1360 return der_decode_number(allocator, mutability, (CFNumberRef*)pl, error, der, der_end);
1361 case CCDER_CONSTRUCTED_SET:
1362 return der_decode_dictionary_with_repair(allocator, mutability, (CFDictionaryRef*)pl, error, der, der_end, repairBlock);
1363 case CCDER_CONSTRUCTED_CFSET:
1364 return der_decode_set_with_repair(allocator, mutability, (CFSetRef*)pl, error, der, der_end, repairBlock);
1365 default:
1366 SecCFDERCreateError(kSecDERErrorUnsupportedDERType, CFSTR("Unsupported DER Type"), NULL, error);
1367 return NULL;
1368 }
1369 }
1370
1371 static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1372 CFDictionaryRef* dictionary, CFErrorRef *error,
1373 const uint8_t* der, const uint8_t *der_end,
1374 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1375 const uint8_t*, const uint8_t*))
1376 {
1377 if (NULL == der) {
1378 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1379 return NULL;
1380 }
1381
1382 const uint8_t *payload_end = 0;
1383 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end);
1384
1385 if (NULL == payload) {
1386 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SET"), NULL, error);
1387 return NULL;
1388 }
1389
1390
1391 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1392
1393 if (NULL == dict) {
1394 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create dictionary"), NULL, error);
1395 payload = NULL;
1396 goto exit;
1397 }
1398
1399 while (payload != NULL && payload < payload_end) {
1400 CFTypeRef key = NULL;
1401 CFTypeRef value = NULL;
1402
1403 payload = der_decode_key_value_with_repair(allocator, mutability, &key, &value, error, payload, payload_end, repairBlock);
1404
1405 if (payload) {
1406 CFDictionaryAddValue(dict, key, value);
1407 }
1408
1409 CFReleaseNull(key);
1410 CFReleaseNull(value);
1411 }
1412
1413
1414 exit:
1415 if (payload == payload_end) {
1416 *dictionary = dict;
1417 dict = NULL;
1418 }
1419
1420 CFReleaseNull(dict);
1421
1422 return payload;
1423 }
1424
1425 static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1426 CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
1427 const uint8_t* der, const uint8_t *der_end,
1428 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1429 const uint8_t*, const uint8_t*))
1430 {
1431 const uint8_t *payload_end = 0;
1432 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &payload_end, der, der_end);
1433
1434 if (NULL == payload) {
1435 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_SEQUENCE"), NULL, error);
1436 return NULL;
1437 }
1438
1439 CFTypeRef keyObject = NULL;
1440 CFTypeRef valueObject = NULL;
1441
1442
1443 payload = der_decode_plist_with_repair(allocator, mutability, &keyObject, error, payload, payload_end, repairBlock);
1444 payload = der_decode_plist_with_repair(allocator, mutability, &valueObject, error, payload, payload_end, repairBlock);
1445
1446 if (payload != NULL) {
1447 *key = keyObject;
1448 *value = valueObject;
1449 } else {
1450 CFReleaseNull(keyObject);
1451 CFReleaseNull(valueObject);
1452 }
1453 return payload;
1454 }
1455
1456 static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1457 CFArrayRef* array, CFErrorRef *error,
1458 const uint8_t* der, const uint8_t *der_end,
1459 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1460 const uint8_t*, const uint8_t*))
1461 {
1462 if (NULL == der) {
1463 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1464 return NULL;
1465 }
1466
1467 CFMutableArrayRef result = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
1468
1469 const uint8_t *elements_end;
1470 const uint8_t *current_element = ccder_decode_sequence_tl(&elements_end, der, der_end);
1471
1472 while (current_element != NULL && current_element < elements_end) {
1473 CFPropertyListRef element = NULL;
1474 current_element = der_decode_plist_with_repair(allocator, mutability, &element, error, current_element, elements_end, repairBlock);
1475 if (current_element) {
1476 CFArrayAppendValue(result, element);
1477 CFReleaseNull(element);
1478 }
1479 }
1480
1481 if (current_element) {
1482 *array = result;
1483 result = NULL;
1484 }
1485
1486 CFReleaseNull(result);
1487 return current_element;
1488 }
1489
1490 static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
1491 CFSetRef* set, CFErrorRef *error,
1492 const uint8_t* der, const uint8_t *der_end,
1493 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
1494 const uint8_t*, const uint8_t*))
1495 {
1496 if (NULL == der) {
1497 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Null DER"), NULL, error);
1498 return NULL;
1499 }
1500
1501 const uint8_t *payload_end = 0;
1502 const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET, &payload_end, der, der_end);
1503
1504 if (NULL == payload) {
1505 SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding, expected CCDER_CONSTRUCTED_CFSET"), NULL, error);
1506 return NULL;
1507 }
1508
1509 CFMutableSetRef theSet = (set && *set) ? CFSetCreateMutableCopy(allocator, 0, *set)
1510 : CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks);
1511
1512 if (NULL == theSet) {
1513 SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create set"), NULL, error);
1514 payload = NULL;
1515 goto exit;
1516 }
1517
1518 while (payload != NULL && payload < payload_end) {
1519 CFTypeRef value = NULL;
1520
1521 payload = der_decode_plist_with_repair(allocator, mutability, &value, error, payload, payload_end, repairBlock);
1522
1523 if (payload) {
1524 CFSetAddValue(theSet, value);
1525 }
1526 CFReleaseNull(value);
1527 }
1528
1529
1530 exit:
1531 if (set && payload == payload_end) {
1532 CFTransferRetained(*set, theSet);
1533 }
1534
1535 CFReleaseNull(theSet);
1536
1537 return payload;
1538 }
1539
1540 void SecDbResetMetadataKeys(void) {
1541 [SecDbKeychainMetadataKeyStore resetSharedStore];
1542 }