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