]> git.saurik.com Git - apple/security.git/blob - Security/sec/securityd/SecDbKeychainItem.c
Security-57031.10.10.tar.gz
[apple/security.git] / Security / sec / securityd / SecDbKeychainItem.c
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 #include <securityd/SecItemSchema.h>
33 #include <CommonCrypto/CommonCryptor.h>
34 #include <CommonCrypto/CommonCryptorSPI.h>
35 #include <Security/SecBasePriv.h>
36 #include <Security/SecItem.h>
37 #include <Security/SecItemInternal.h>
38 #include <Security/SecRandom.h>
39 #include <Security/SecAccessControl.h>
40 #include <Security/SecAccessControlPriv.h>
41 #include <utilities/der_plist.h>
42
43 #if USE_KEYSTORE
44 #include <LocalAuthentication/LAPublicDefines.h>
45 #include <LocalAuthentication/LAPrivateDefines.h>
46 #include <coreauthd_spi.h>
47 #include <libaks_acl_cf_keys.h>
48 #include <securityd/spi.h>
49 #endif /* USE_KEYSTORE */
50
51 pthread_key_t CURRENT_CONNECTION_KEY;
52
53 // From SecItemServer, should be a acl-check block
54 bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups);
55
56 static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error);
57 static CFTypeRef kc_encode_keyclass(keyclass_t keyclass);
58 static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control);
59 static CFTypeRef kc_copy_protection_from_data(CFDataRef data);
60 static CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error);
61 static CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error);
62 #if USE_KEYSTORE
63 static CFDataRef kc_copy_constraints_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes);
64 static void kc_dict_from_auth_data(const SecDbClass *class, const uint8_t *der, const uint8_t *der_end, CFMutableDictionaryRef *authenticated_attributes, CFMutableDictionaryRef *acl);
65 static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error);
66 #endif
67
68 /* Given plainText create and return a CFDataRef containing:
69 BULK_KEY = RandomKey()
70 version || keyclass|ACL || KeyStore_WRAP(keyclass, BULK_KEY) ||
71 AES(BULK_KEY, NULL_IV, plainText || padding)
72 */
73 bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFTypeRef *cred_handle,
74 CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFErrorRef *error) {
75 CFMutableDataRef blob = NULL;
76 CFDataRef ac_data = NULL;
77 bool ok = true;
78 //check(keybag >= 0);
79
80 /* Precalculate output blob length. */
81 const uint32_t bulkKeySize = 32; /* Use 256 bit AES key for bulkKey. */
82 const uint32_t maxKeyWrapOverHead = 8 + 32;
83 uint8_t bulkKey[bulkKeySize];
84 CFMutableDataRef bulkKeyWrapped = CFDataCreateMutable(NULL, 0);
85 CFDataSetLength(bulkKeyWrapped, bulkKeySize + maxKeyWrapOverHead);
86 uint32_t key_wrapped_size;
87
88 #if USE_KEYSTORE
89 CFDataRef access_control_data = NULL;
90 CFDataRef constraint_data = NULL;
91 CFDataRef acm_context = NULL;
92 #endif
93
94 /* If access_control specifies only protection and no ACL, use legacy blob format version 3,
95 which has better support for sync/backup. Otherwise, force new format v4. */
96 const uint32_t version = SecAccessControlGetConstraints(access_control) ? 4 : 3;
97 CFDataRef plainText = NULL;
98 if (version < 4) {
99 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
100 if (authenticated_attributes) {
101 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
102 CFDictionaryAddValue(attributes_dict, key, value);
103 });
104 }
105
106 if (attributes_dict) {
107 // Drop the accc attribute for non v4 items during encode.
108 CFDictionaryRemoveValue(attributes_dict, kSecAttrAccessControl);
109 plainText = kc_plist_copy_der(attributes_dict, error);
110 CFRelease(attributes_dict);
111 }
112 } else {
113 #if USE_KEYSTORE
114 if (attributes) {
115 plainText = kc_plist_copy_der(attributes, error);
116 }
117 #else
118 CFMutableDictionaryRef attributes_dict = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
119 if (authenticated_attributes) {
120 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
121 CFDictionaryAddValue(attributes_dict, key, value);
122 });
123 }
124
125 if (attributes_dict) {
126 plainText = kc_plist_copy_der(attributes_dict, error);
127 CFRelease(attributes_dict);
128 }
129 #endif
130 }
131
132 if (!plainText || CFGetTypeID(plainText) != CFDataGetTypeID()
133 || access_control == 0) {
134 ok = SecError(errSecParam, error, CFSTR("ks_encrypt_data: invalid plain text"));
135 goto out;
136 }
137
138 size_t ptLen = CFDataGetLength(plainText);
139 size_t ctLen = ptLen;
140 size_t tagLen = 16;
141 keyclass_t actual_class;
142
143 if (SecRandomCopyBytes(kSecRandomDefault, bulkKeySize, bulkKey)) {
144 ok = SecError(errSecAllocate, error, CFSTR("ks_encrypt_data: SecRandomCopyBytes failed"));
145 goto out;
146 }
147
148 /* Extract keyclass from access control. */
149 keyclass_t keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error);
150 if (!keyclass)
151 goto out;
152
153 #if USE_KEYSTORE
154 if (version >= 4) {
155 if (*cred_handle == NULL || isData(*cred_handle)) {
156 CFTypeRef auth_ref = VRCreateNewReferenceWithACMContext(*cred_handle, error);
157 if (!auth_ref) {
158 ok = false;
159 goto out;
160 }
161 CFReleaseSafe(*cred_handle);
162 *cred_handle = auth_ref;
163 }
164
165 access_control_data = SecAccessControlCopyData(access_control);
166 CFErrorRef authError = NULL;
167 ok = VRValidateACL(*cred_handle, access_control_data, &authError);
168 if (!ok) {
169 ok = SecCFCreateError(errSecParam, kSecErrorDomain, CFSTR("Invalid ACL"), authError, error);
170 CFReleaseSafe(authError);
171 goto out;
172 }
173
174 constraint_data = kc_copy_constraints_data(access_control, authenticated_attributes);
175 require_quiet(ok = ks_crypt_acl(kSecKsWrap, keybag,
176 keyclass, bulkKeySize, bulkKey, bulkKeyWrapped, constraint_data, NULL, NULL, error), out);
177 }
178 else {
179 #endif
180 /* Encrypt bulkKey. */
181 require_quiet(ok = ks_crypt(kSecKsWrap, keybag,
182 keyclass, bulkKeySize, bulkKey,
183 &actual_class, bulkKeyWrapped,
184 error), out);
185 #if USE_KEYSTORE
186 }
187 #endif
188
189 key_wrapped_size = (uint32_t)CFDataGetLength(bulkKeyWrapped);
190 UInt8 *cursor;
191 size_t blobLen = sizeof(version);
192 uint32_t prot_length;
193
194 if (version == 3) {
195 blobLen += sizeof(actual_class);
196 } else {
197 require_quiet(ac_data = kc_copy_protection_data(access_control), out);
198 prot_length = (uint32_t)CFDataGetLength(ac_data);
199 blobLen += sizeof(prot_length) + prot_length;
200 }
201
202 blobLen += sizeof(key_wrapped_size) + key_wrapped_size + ctLen + tagLen;
203 require_quiet(blob = CFDataCreateMutable(NULL, blobLen), out);
204 CFDataSetLength(blob, blobLen);
205 cursor = CFDataGetMutableBytePtr(blob);
206
207 *((uint32_t *)cursor) = version;
208 cursor += sizeof(version);
209
210 //secerror("class: %d actual class: %d", keyclass, actual_class);
211 if (version == 3) {
212 *((keyclass_t *)cursor) = actual_class;
213 cursor += sizeof(keyclass);
214 } else {
215 *((uint32_t *)cursor) = prot_length;
216 cursor += sizeof(prot_length);
217
218 CFDataGetBytes(ac_data, CFRangeMake(0, prot_length), cursor);
219 cursor += prot_length;
220 }
221
222 *((uint32_t *)cursor) = key_wrapped_size;
223 cursor += sizeof(key_wrapped_size);
224
225 memcpy(cursor, CFDataGetBytePtr(bulkKeyWrapped), key_wrapped_size);
226 cursor += key_wrapped_size;
227
228 /* Encrypt the plainText with the bulkKey. */
229 CCCryptorStatus ccerr = CCCryptorGCM(kCCEncrypt, kCCAlgorithmAES128,
230 bulkKey, bulkKeySize,
231 NULL, 0, /* iv */
232 NULL, 0, /* auth data */
233 CFDataGetBytePtr(plainText), ptLen,
234 cursor,
235 cursor + ctLen, &tagLen);
236 if (ccerr) {
237 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM failed: %d"), ccerr);
238 goto out;
239 }
240 if (tagLen != 16) {
241 ok = SecError(errSecInternal, error, CFSTR("ks_encrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
242 goto out;
243 }
244
245 out:
246 memset(bulkKey, 0, sizeof(bulkKey));
247 CFReleaseSafe(ac_data);
248 CFReleaseSafe(bulkKeyWrapped);
249 CFReleaseSafe(plainText);
250 if (!ok) {
251 CFReleaseSafe(blob);
252 } else {
253 *pBlob = blob;
254 }
255
256 #if USE_KEYSTORE
257 CFReleaseSafe(access_control_data);
258 CFReleaseSafe(constraint_data);
259 CFReleaseSafe(acm_context);
260 #endif
261 return ok;
262 }
263
264 /* Given cipherText containing:
265 version || keyclass || KeyStore_WRAP(keyclass, BULK_KEY) ||
266 AES(BULK_KEY, NULL_IV, plainText || padding)
267 return the plainText. */
268 bool ks_decrypt_data(keybag_handle_t keybag, enum SecKsCryptoOp cryptoOp, SecAccessControlRef *paccess_control, CFTypeRef *cred_handle,
269 CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups,
270 CFMutableDictionaryRef *attributes_p, uint32_t *version_p, CFErrorRef *error) {
271 const uint32_t v0KeyWrapOverHead = 8;
272 CFMutableDataRef bulkKey = CFDataCreateMutable(0, 32); /* Use 256 bit AES key for bulkKey. */
273 CFDataSetLength(bulkKey, 32); /* Use 256 bit AES key for bulkKey. */
274 bool ok = true;
275 SecAccessControlRef access_control = NULL;
276
277 CFMutableDataRef plainText = NULL;
278 CFMutableDictionaryRef attributes = NULL;
279 uint32_t version = 0;
280 CFDataRef access_control_data = NULL;
281
282 #if USE_KEYSTORE
283 CFDataRef acm_context = NULL;
284 CFMutableDictionaryRef authenticated_attributes = NULL;
285 CFDataRef caller_access_groups_data = NULL;
286
287 #if TARGET_OS_IPHONE
288 check(keybag >= 0);
289 #else
290 check((keybag >= 0) || (keybag == session_keybag_handle));
291 #endif
292 #endif
293
294 if (!blob) {
295 ok = SecError(errSecParam, error, CFSTR("ks_decrypt_data: invalid blob"));
296 goto out;
297 }
298
299 size_t blobLen = CFDataGetLength(blob);
300 const uint8_t *cursor = CFDataGetBytePtr(blob);
301 keyclass_t keyclass;
302 uint32_t wrapped_key_size;
303
304 /* Check for underflow, ensuring we have at least one full AES block left. */
305 if (blobLen < sizeof(version) + sizeof(keyclass) +
306 CFDataGetLength(bulkKey) + v0KeyWrapOverHead + 16) {
307 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: Check for underflow"));
308 goto out;
309 }
310
311 version = *((uint32_t *)cursor);
312 cursor += sizeof(version);
313
314 size_t minimum_blob_len = sizeof(version) + 16;
315 size_t ctLen = blobLen - sizeof(version);
316
317 if (version == 4) {
318 /* Deserialize SecAccessControl object from the blob. */
319 uint32_t prot_length = *((uint32_t *)cursor);
320 cursor += sizeof(prot_length);
321
322 CFDataRef protection_data = CFDataCreate(kCFAllocatorDefault, cursor, prot_length);
323 CFTypeRef protection = kc_copy_protection_from_data(protection_data);
324 CFRelease(protection_data);
325 if (!protection) {
326 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
327 goto out;
328 }
329 else {
330 access_control = SecAccessControlCreate(NULL, NULL);
331 require_quiet(access_control, out);
332 ok = SecAccessControlSetProtection(access_control, protection, NULL);
333 CFRelease(protection);
334 if (!ok) {
335 SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
336 goto out;
337 }
338 }
339
340 cursor += prot_length;
341
342 minimum_blob_len += sizeof(prot_length) + prot_length;
343 ctLen -= sizeof(prot_length) + prot_length;
344
345 /* Get numeric value of keyclass from the access_control. */
346 keyclass = kc_parse_keyclass(SecAccessControlGetProtection(access_control), error);
347 if (!keyclass) {
348 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid ACL"));
349 goto out;
350 }
351 } else {
352 keyclass = *((keyclass_t *)cursor);
353 //secerror("class: %d keyclass: %d", keyclass, keyclass & key_class_last);
354 #if USE_KEYSTORE
355 CFTypeRef protection = kc_encode_keyclass(keyclass & key_class_last); // mask out generation
356 #else
357 CFTypeRef protection = kc_encode_keyclass(keyclass);
358 #endif
359 if (protection) {
360 access_control = SecAccessControlCreateWithFlags(kCFAllocatorDefault, protection, 0, error);
361 }
362 if (!access_control) {
363 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid keyclass detected"));
364 goto out;
365 }
366 cursor += sizeof(keyclass);
367
368 minimum_blob_len += sizeof(keyclass);
369 ctLen -= sizeof(keyclass);
370 }
371
372 size_t tagLen = 0;
373 switch (version) {
374 case 0:
375 wrapped_key_size = (uint32_t)CFDataGetLength(bulkKey) + v0KeyWrapOverHead;
376 break;
377 case 2:
378 case 3:
379 /* DROPTHROUGH */
380 /* v2 and v3 have the same crypto, just different dictionary encodings. */
381 /* Difference between v3 and v4 is already handled above, so treat v3 as v4. */
382 case 4:
383 tagLen = 16;
384 minimum_blob_len -= 16; // Remove PKCS7 padding block requirement
385 ctLen -= tagLen; // Remove tagLen from ctLen
386 /* DROPTHROUGH */
387 case 1:
388 wrapped_key_size = *((uint32_t *)cursor);
389 cursor += sizeof(wrapped_key_size);
390 minimum_blob_len += sizeof(wrapped_key_size);
391 ctLen -= sizeof(wrapped_key_size);
392 break;
393 default:
394 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version %d"), version);
395 goto out;
396 }
397
398 /* Validate key wrap length against total length */
399 require(blobLen - minimum_blob_len - tagLen >= wrapped_key_size, out);
400 ctLen -= wrapped_key_size;
401 if (version < 2 && (ctLen & 0xF) != 0) {
402 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: invalid version"));
403 goto out;
404 }
405
406 #if USE_KEYSTORE
407 if (version >= 4) {
408 /* Verify before we try to unwrap the key. */
409 if (*cred_handle == NULL || isData(*cred_handle)) {
410 CFTypeRef auth_ref = VRCreateNewReferenceWithACMContext(*cred_handle, error);
411 if (!auth_ref) {
412 ok = false;
413 goto out;
414 }
415 CFReleaseSafe(*cred_handle);
416 *cred_handle = auth_ref;
417 }
418
419 CFMutableDictionaryRef acl = NULL;
420 kc_dict_from_auth_data(db_class, cursor, cursor + wrapped_key_size, &authenticated_attributes, &acl);
421 SecAccessControlSetConstraints(access_control, acl);
422 CFReleaseSafe(acl);
423 access_control_data = SecAccessControlCopyData(access_control);
424
425 static CFDictionaryRef hints = NULL;
426 static dispatch_once_t onceToken;
427 dispatch_once(&onceToken, ^{
428 CFNumberRef noninteractiveKey = CFNumberCreateWithCFIndex(kCFAllocatorDefault, kLAOptionNotInteractive);
429 hints = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, noninteractiveKey, kCFBooleanTrue, NULL);
430 CFRelease(noninteractiveKey);
431 });
432
433 CFErrorRef authError = NULL;
434 ok = VREvaluateACL(*cred_handle, access_control_data, (cryptoOp == kSecKsDelete)?kAKSKeyOpDelete:kAKSKeyOpDecrypt, hints, &authError);
435 if (!ok) {
436 if (CFEqual(CFErrorGetDomain(authError), CFSTR(kLAErrorDomain)) &&
437 CFErrorGetCode(authError) == kLAErrorNotInteractive) {
438 /* UI is needed, but this is not really an error, just leave with no output data. */
439 ok = true;
440 } else {
441 ok = SecCFCreateError(errSecAuthFailed, kSecErrorDomain, CFSTR("CoreAuthentication failed"), authError, error);
442 }
443 CFReleaseSafe(authError);
444 goto out;
445 }
446
447 acm_context = VRCopyACMContext(*cred_handle, error);
448
449 if (caller_access_groups) {
450 caller_access_groups_data = kc_copy_access_groups_data(caller_access_groups, error);
451 require_quiet(ok = (caller_access_groups_data != NULL), out);
452 }
453 require_quiet(ok = ks_crypt_acl(cryptoOp, keybag,
454 keyclass, wrapped_key_size, cursor, bulkKey, NULL, acm_context, caller_access_groups_data, error), out);
455 if (cryptoOp == kSecKsDelete) {
456 attributes = CFRetainSafe(authenticated_attributes);
457 goto out;
458 }
459 }
460 else {
461 #endif
462 /* Now unwrap the bulk key using a key in the keybag. */
463 require_quiet(ok = ks_crypt(kSecKsUnwrap, keybag,
464 keyclass, wrapped_key_size, cursor, NULL, bulkKey, error), out);
465 #if USE_KEYSTORE
466 }
467 #endif
468
469 cursor += wrapped_key_size;
470
471 plainText = CFDataCreateMutable(NULL, ctLen);
472 if (!plainText) {
473 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: failed to allocate data for plain text"));
474 goto out;
475 }
476 CFDataSetLength(plainText, ctLen);
477
478 /* Decrypt the cipherText with the bulkKey. */
479 CCCryptorStatus ccerr;
480 if (tagLen) {
481 uint8_t tag[tagLen];
482 ccerr = CCCryptorGCM(kCCDecrypt, kCCAlgorithmAES128,
483 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey),
484 NULL, 0, /* iv */
485 NULL, 0, /* auth data */
486 cursor, ctLen,
487 CFDataGetMutableBytePtr(plainText),
488 tag, &tagLen);
489 if (ccerr) {
490 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
491 identifies uuid unwrap failures? */
492 /* errSecInteractionNotAllowed; */
493 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM failed: %d"), ccerr);
494 goto out;
495 }
496 if (tagLen != 16) {
497 ok = SecError(errSecInternal, error, CFSTR("ks_decrypt_data: CCCryptorGCM expected: 16 got: %ld byte tag"), tagLen);
498 goto out;
499 }
500 cursor += ctLen;
501 if (memcmp(tag, cursor, tagLen)) {
502 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCryptorGCM computed tag not same as tag in blob"));
503 goto out;
504 }
505 } else {
506 size_t ptLen;
507 ccerr = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
508 CFDataGetBytePtr(bulkKey), CFDataGetLength(bulkKey), NULL, cursor, ctLen,
509 CFDataGetMutableBytePtr(plainText), ctLen, &ptLen);
510 if (ccerr) {
511 /* TODO: Should this be errSecDecode once AppleKeyStore correctly
512 identifies uuid unwrap failures? */
513 /* errSecInteractionNotAllowed; */
514 ok = SecError(errSecDecode, error, CFSTR("ks_decrypt_data: CCCrypt failed: %d"), ccerr);
515 goto out;
516 }
517 CFDataSetLength(plainText, ptLen);
518 }
519
520 if (version < 2) {
521 attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
522 CFDictionaryAddValue(attributes, CFSTR("v_Data"), plainText);
523 } else if (version < 3) {
524 attributes = s3dl_item_v2_decode(plainText, error);
525 } else {
526 attributes = s3dl_item_v3_decode(plainText, error);
527
528 #if USE_KEYSTORE
529 if (version >= 4 && authenticated_attributes != NULL) {
530 CFDictionaryForEach(authenticated_attributes, ^(const void *key, const void *value) {
531 CFDictionaryAddValue(attributes, key, value);
532 });
533 }
534 #endif
535 }
536
537 if (!attributes) {
538 secerror("decode v%d failed: %@ [item: %@]", version, error ? *error : NULL, plainText);
539 ok = false;
540 }
541 out:
542 memset(CFDataGetMutableBytePtr(bulkKey), 0, CFDataGetLength(bulkKey));
543 CFReleaseSafe(bulkKey);
544 CFReleaseSafe(plainText);
545
546 // Always copy access control data (if present), because if we fail it may indicate why.
547 if (paccess_control)
548 *paccess_control = access_control;
549 else
550 CFReleaseSafe(access_control);
551
552 if (ok) {
553 if (attributes_p)
554 *attributes_p = CFRetainSafe(attributes);
555 if (version_p)
556 *version_p = version;
557 }
558 CFReleaseSafe(attributes);
559 CFReleaseSafe(access_control_data);
560 #if USE_KEYSTORE
561 CFReleaseSafe(acm_context);
562 CFReleaseSafe(authenticated_attributes);
563 CFReleaseSafe(caller_access_groups_data);
564 #endif
565 return ok;
566 }
567
568 // TODO: Move to utilities - CFPropertyListCopyDERData()
569 CFDataRef kc_plist_copy_der(CFPropertyListRef plist, CFErrorRef *error) {
570 size_t len = der_sizeof_plist(plist, error);
571 CFMutableDataRef encoded = CFDataCreateMutable(0, len);
572 CFDataSetLength(encoded, len);
573 uint8_t *der_end = CFDataGetMutableBytePtr(encoded);
574 const uint8_t *der = der_end;
575 der_end += len;
576 der_end = der_encode_plist(plist, error, der, der_end);
577 if (!der_end) {
578 CFReleaseNull(encoded);
579 } else {
580 assert(!der_end || der_end == der);
581 }
582 return encoded;
583 }
584
585 static CFDataRef kc_copy_digest(const struct ccdigest_info *di, size_t len,
586 const void *data, CFErrorRef *error) {
587 CFMutableDataRef digest = CFDataCreateMutable(0, di->output_size);
588 CFDataSetLength(digest, di->output_size);
589 ccdigest(di, len, data, CFDataGetMutableBytePtr(digest));
590 return digest;
591 }
592
593 CFDataRef kc_copy_sha1(size_t len, const void *data, CFErrorRef *error) {
594 return kc_copy_digest(ccsha1_di(), len, data, error);
595 }
596
597 CFDataRef kc_copy_plist_sha1(CFPropertyListRef plist, CFErrorRef *error) {
598 CFDataRef der = kc_plist_copy_der(plist, error);
599 CFDataRef digest = NULL;
600 if (der) {
601 digest = kc_copy_sha1(CFDataGetLength(der), CFDataGetBytePtr(der), error);
602 CFRelease(der);
603 }
604 return digest;
605 }
606
607 static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error) {
608 if (!isString(value)) {
609 SecError(errSecParam, error, CFSTR("accessible attribute %@ not a string"), value);
610 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlocked)) {
611 return key_class_ak;
612 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlock)) {
613 return key_class_ck;
614 } else if (CFEqual(value, kSecAttrAccessibleAlways)) {
615 return key_class_dk;
616 } else if (CFEqual(value, kSecAttrAccessibleWhenUnlockedThisDeviceOnly)) {
617 return key_class_aku;
618 } else if (CFEqual(value, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)) {
619 return key_class_cku;
620 } else if (CFEqual(value, kSecAttrAccessibleAlwaysThisDeviceOnly)) {
621 return key_class_dku;
622 } else if (CFEqual(value, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)) {
623 return key_class_akpu;
624 } else {
625 SecError(errSecParam, error, CFSTR("accessible attribute %@ unknown"), value);
626 }
627 return 0;
628 }
629
630 static CFTypeRef kc_encode_keyclass(keyclass_t keyclass) {
631 switch (keyclass) {
632 case key_class_ak:
633 return kSecAttrAccessibleWhenUnlocked;
634 case key_class_ck:
635 return kSecAttrAccessibleAfterFirstUnlock;
636 case key_class_dk:
637 return kSecAttrAccessibleAlways;
638 case key_class_aku:
639 return kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
640 case key_class_cku:
641 return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
642 case key_class_dku:
643 return kSecAttrAccessibleAlwaysThisDeviceOnly;
644 case key_class_akpu:
645 return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;
646 default:
647 return 0;
648 }
649 }
650
651 #if USE_KEYSTORE
652 static void kc_dict_from_auth_data(const SecDbClass *class, const uint8_t *der, const uint8_t *der_end, CFMutableDictionaryRef *authenticated_attributes, CFMutableDictionaryRef *acl)
653 {
654 CFPropertyListRef aks_data = NULL;
655 der = der_decode_plist(NULL, kCFPropertyListImmutable, &aks_data, NULL, der, der_end);
656 if(der == der_end) {
657 CFDictionaryRef authenticated_data = CFDictionaryGetValue(aks_data, kAKSKeyAuthData);
658 if (authenticated_data) {
659 *acl = CFDictionaryCreateMutableCopy(NULL, 0, authenticated_data);
660 SecDbForEachAttrWithMask(class, attr_desc, kSecDbInAuthenticatedDataFlag) {
661 CFDictionaryRemoveValue(*acl, attr_desc->name);
662 CFTypeRef value = CFDictionaryGetValue(authenticated_data, attr_desc->name);
663 if (value) {
664 if (!*authenticated_attributes)
665 *authenticated_attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
666
667 CFDictionaryAddValue(*authenticated_attributes, attr_desc->name, value);
668 }
669 }
670 }
671 }
672
673 CFReleaseSafe(aks_data);
674 }
675
676 static CFDataRef kc_copy_constraints_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes) {
677 CFDictionaryRef constraints = SecAccessControlGetConstraints(access_control);
678 CFMutableDictionaryRef auth_data = CFDictionaryCreateMutableCopy(NULL, 0, constraints);
679 if (auth_attributes) {
680 CFDictionaryForEach(auth_attributes, ^(const void *key, const void *value) {
681 CFDictionaryAddValue(auth_data, key, value);
682 });
683 }
684
685 CFDataRef encoded = kc_plist_copy_der(auth_data, NULL);
686 CFReleaseSafe(auth_data);
687 return encoded;
688 }
689
690 static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error)
691 {
692 size_t ag_size = der_sizeof_plist(access_groups, error);
693 CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0);
694 CFDataSetLength(result, ag_size);
695 if (!der_encode_plist(access_groups, error, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + ag_size)) {
696 CFRelease(result);
697 return NULL;
698 }
699 else
700 return result;
701 }
702
703 #endif /* USE_KEYSTORE */
704
705 static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control)
706 {
707 CFTypeRef protection = SecAccessControlGetProtection(access_control);
708 size_t protection_size = der_sizeof_plist(protection, NULL);
709 CFMutableDataRef result = CFDataCreateMutable(NULL, 0);
710 CFDataSetLength(result, protection_size);
711 if (!der_encode_plist(protection, NULL, CFDataGetMutableBytePtr(result), CFDataGetMutableBytePtr(result) + protection_size)) {
712 CFRelease(result);
713 return NULL;
714 }
715 else
716 return result;
717 }
718
719 static CFTypeRef kc_copy_protection_from_data(CFDataRef data)
720 {
721 CFTypeRef result = NULL;
722 der_decode_plist(NULL, kCFPropertyListImmutable, &result, NULL, CFDataGetBytePtr(data), CFDataGetBytePtr(data) + CFDataGetLength(data));
723 return result;
724 }
725
726 /* Return a (mutable) dictionary if plist is a dictionary, return NULL and set error otherwise. Does nothing if plist is already NULL. */
727 static CF_RETURNS_RETAINED
728 CFMutableDictionaryRef dictionaryFromPlist(CFPropertyListRef plist CF_CONSUMED, CFErrorRef *error) {
729 if (plist && !isDictionary(plist)) {
730 CFStringRef typeName = CFCopyTypeIDDescription(CFGetTypeID((CFTypeRef)plist));
731 SecError(errSecDecode, error, CFSTR("plist is a %@, expecting a dictionary"), typeName);
732 CFReleaseSafe(typeName);
733 CFReleaseNull(plist);
734 }
735 return (CFMutableDictionaryRef)plist;
736 }
737
738 static CF_RETURNS_RETAINED
739 CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) {
740 CFPropertyListRef item;
741 item = CFPropertyListCreateWithData(0, plain, kCFPropertyListMutableContainers, NULL, error);
742 return dictionaryFromPlist(item, error);
743 }
744
745 static CF_RETURNS_RETAINED
746 CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) {
747 CFPropertyListRef item = NULL;
748 const uint8_t *der = CFDataGetBytePtr(plain);
749 const uint8_t *der_end = der + CFDataGetLength(plain);
750 der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der, der_end);
751 if (der && der != der_end) {
752 SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error);
753 CFReleaseNull(item);
754 }
755 return dictionaryFromPlist(item, error);
756 }
757
758 bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups,
759 CFMutableDictionaryRef *item, SecAccessControlRef *access_control, CFErrorRef *error) {
760 SecAccessControlRef ac = NULL;
761 CFDataRef ac_data = NULL;
762 bool ok = false;
763
764 /* Decrypt and decode the item and check the decoded attributes against the query. */
765 uint32_t version = 0;
766 require_quiet((ok = ks_decrypt_data(q->q_keybag, q->q_crypto_op, &ac, &q->q_use_cred_handle, edata, q->q_class, q->q_caller_access_groups, item, &version, error)), out);
767 if (version < 2) {
768 goto out;
769 }
770
771 ac_data = SecAccessControlCopyData(ac);
772 if (!*item) {
773 /* Item cannot be decrypted, because interactive authentication is needed. */
774 if (!q->q_required_access_controls) {
775 ok = SecError(errSecInteractionNotAllowed, error, CFSTR("item would need ui for decrypting"));
776 goto out;
777 }
778 CFArrayAppendValue(q->q_required_access_controls, ac_data);
779 *item = NULL;
780 goto out;
781 }
782
783 if (*item && !itemInAccessGroup(*item, accessGroups)) {
784 secerror("items accessGroup %@ not in %@",
785 CFDictionaryGetValue(*item, kSecAttrAccessGroup),
786 accessGroups);
787 ok = SecError(errSecDecode, error, CFSTR("items accessGroup %@ not in %@"),
788 CFDictionaryGetValue(*item, kSecAttrAccessGroup),
789 accessGroups);
790 CFReleaseNull(*item);
791 }
792
793 /* AccessControl attribute does not exist in the db, so synthesize it. */
794 if (*item) {
795 CFDictionarySetValue(*item, kSecAttrAccessControl, ac_data);
796 }
797
798 /* TODO: Validate access_control attribute. */
799
800 out:
801 if (access_control)
802 *access_control = CFRetainSafe(ac);
803 CFReleaseSafe(ac);
804 CFReleaseSafe(ac_data);
805 return ok;
806 }
807
808 /* Infer accessibility and access group for pre-v2 (iOS4.x and earlier) items
809 being imported from a backup. */
810 static bool SecDbItemImportMigrate(SecDbItemRef item, CFErrorRef *error) {
811 bool ok = true;
812 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
813 CFStringRef accessible = SecDbItemGetCachedValueWithName(item, kSecAttrAccessible);
814
815 if (!isString(agrp) || !isString(accessible))
816 return ok;
817 if (SecDbItemGetClass(item) == &genp_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
818 CFStringRef svce = SecDbItemGetCachedValueWithName(item, kSecAttrService);
819 if (!isString(svce)) return ok;
820 if (CFEqual(agrp, CFSTR("apple"))) {
821 if (CFEqual(svce, CFSTR("AirPort"))) {
822 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
823 } else if (CFEqual(svce, CFSTR("com.apple.airplay.password"))) {
824 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
825 } else if (CFEqual(svce, CFSTR("YouTube"))) {
826 ok = (SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error) &&
827 SecDbItemSetValueWithName(item, kSecAttrAccessGroup, CFSTR("com.apple.youtube.credentials"), error));
828 } else {
829 CFStringRef desc = SecDbItemGetCachedValueWithName(item, kSecAttrDescription);
830 if (!isString(desc)) return ok;
831 if (CFEqual(desc, CFSTR("IPSec Shared Secret")) || CFEqual(desc, CFSTR("PPP Password"))) {
832 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlock, error);
833 }
834 }
835 }
836 } else if (SecDbItemGetClass(item) == &inet_class && CFEqual(accessible, kSecAttrAccessibleAlways)) {
837 if (CFEqual(agrp, CFSTR("PrintKitAccessGroup"))) {
838 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
839 } else if (CFEqual(agrp, CFSTR("apple"))) {
840 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
841 bool is_proxy = false;
842 if (isNumber(ptcl)) {
843 SInt32 iptcl;
844 CFNumberGetValue(ptcl, kCFNumberSInt32Type, &iptcl);
845 is_proxy = (iptcl == FOUR_CHAR_CODE('htpx') ||
846 iptcl == FOUR_CHAR_CODE('htsx') ||
847 iptcl == FOUR_CHAR_CODE('ftpx') ||
848 iptcl == FOUR_CHAR_CODE('rtsx') ||
849 iptcl == FOUR_CHAR_CODE('xpth') ||
850 iptcl == FOUR_CHAR_CODE('xsth') ||
851 iptcl == FOUR_CHAR_CODE('xptf') ||
852 iptcl == FOUR_CHAR_CODE('xstr'));
853 } else if (isString(ptcl)) {
854 is_proxy = (CFEqual(ptcl, kSecAttrProtocolHTTPProxy) ||
855 CFEqual(ptcl, kSecAttrProtocolHTTPSProxy) ||
856 CFEqual(ptcl, kSecAttrProtocolRTSPProxy) ||
857 CFEqual(ptcl, kSecAttrProtocolFTPProxy));
858 }
859 if (is_proxy)
860 ok = SecDbItemSetValueWithName(item, kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked, error);
861 }
862 }
863 return ok;
864 }
865
866 bool SecDbItemDecrypt(SecDbItemRef item, CFDataRef edata, CFDataRef *neededAuth, CFErrorRef *error) {
867 bool ok = true;
868 CFMutableDictionaryRef dict = NULL;
869 SecAccessControlRef access_control = NULL;
870 uint32_t version = 0;
871
872 if (!ks_decrypt_data(SecDbItemGetKeybag(item), item->cryptoOp, &access_control, &item->credHandle, edata, item->class, item->callerAccessGroups, &dict, &version, error)) {
873 // Copy access control data, which might indicate why decryption failed.
874 if (neededAuth)
875 *neededAuth = SecAccessControlCopyData(access_control);
876 ok = false;
877 goto out;
878 }
879
880 if (!dict) {
881 if (neededAuth)
882 *neededAuth = SecAccessControlCopyData(access_control);
883 else
884 require_quiet(ok = SecError(errSecInteractionNotAllowed, error, CFSTR("auth needed, but caller does not provide it")), out);
885 } else {
886 if (neededAuth)
887 *neededAuth = NULL;
888 if (version < 2) {
889 /* Old V4 style keychain backup being imported. */
890 ok = SecDbItemSetValueWithName(item, CFSTR("v_Data"), CFDictionaryGetValue(dict, CFSTR("v_Data")), error) &&
891 SecDbItemImportMigrate(item, error);
892 } else {
893 ok = dict && SecDbItemSetValues(item, dict, error);
894 }
895 }
896
897 SecAccessControlRef my_access_control = SecDbItemCopyAccessControl(item, error);
898 if (!my_access_control) {
899 ok = false;
900 goto out;
901 }
902
903 /* Make sure that the protection of ACL in the dictionary (read from DB) matched what we got
904 back from decoding the data blob. */
905 if (!CFEqual(SecAccessControlGetProtection(my_access_control), SecAccessControlGetProtection(access_control))) {
906 ok = SecError(errSecDecode, error, CFSTR("ACL protection doesn't match the one in blob (%@ : %@)"),
907 SecAccessControlGetProtection(my_access_control),
908 SecAccessControlGetProtection(access_control));
909 }
910 CFRelease(my_access_control);
911
912 // Update real protection used for decrypting in the item.
913 ok = ok && SecDbItemSetAccessControl(item, access_control, error);
914
915 out:
916 CFReleaseSafe(dict);
917 CFReleaseSafe(access_control);
918 return ok;
919 }
920
921 /* Automagically make a item syncable, based on various attributes. */
922 bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error)
923 {
924 CFStringRef agrp = SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup);
925
926 if (!isString(agrp))
927 return true;
928
929 if (CFEqual(agrp, CFSTR("com.apple.cfnetwork")) && SecDbItemGetClass(item) == &inet_class) {
930 CFTypeRef srvr = SecDbItemGetCachedValueWithName(item, kSecAttrServer);
931 CFTypeRef ptcl = SecDbItemGetCachedValueWithName(item, kSecAttrProtocol);
932 CFTypeRef atyp = SecDbItemGetCachedValueWithName(item, kSecAttrAuthenticationType);
933
934 if (isString(srvr) && isString(ptcl) && isString(atyp)) {
935 /* This looks like a Mobile Safari Password, make syncable */
936 secnotice("item", "Make this item syncable: %@", item);
937 return SecDbItemSetSyncable(item, true, error);
938 }
939 }
940
941 return true;
942 }
943
944 /* This create a SecDbItem from the item dictionnary that are exported for backups.
945 Item are stored in the backup as a dictionary containing two keys:
946 - v_Data: the encrypted data blob
947 - v_PersistentRef: a persistent Ref.
948 src_keybag is normally the backup keybag.
949 dst_keybag is normally the device keybag.
950 */
951 SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error)
952 {
953 CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data"));
954 SecDbItemRef item = NULL;
955
956 if (edata) {
957 item = SecDbItemCreateWithEncryptedData(kCFAllocatorDefault, dbclass, edata, src_keybag, error);
958 if (item)
959 if (!SecDbItemSetKeybag(item, dst_keybag, error))
960 CFReleaseNull(item);
961 } else {
962 SecError(errSecDecode, error, CFSTR("No v_Data in backup dictionary %@"), dict);
963 }
964
965 return item;
966 }
967
968 bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error) {
969 CFDataRef ref = CFDictionaryGetValue(dict, CFSTR("v_PersistentRef"));
970 if (!ref)
971 return SecError(errSecDecode, error, CFSTR("No v_PersistentRef in backup dictionary %@"), dict);
972
973 CFStringRef className;
974 sqlite3_int64 rowid;
975 if (!_SecItemParsePersistentRef(ref, &className, &rowid))
976 return SecError(errSecDecode, error, CFSTR("v_PersistentRef %@ failed to decode"), ref);
977
978 if (!CFEqual(SecDbItemGetClass(item)->name, className))
979 return SecError(errSecDecode, error, CFSTR("v_PersistentRef has unexpected class %@"), className);
980
981 return SecDbItemSetRowId(item, rowid, error);
982 }