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
51pthread_key_t CURRENT_CONNECTION_KEY;
52
53// From SecItemServer, should be a acl-check block
54bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups);
55
56static keyclass_t kc_parse_keyclass(CFTypeRef value, CFErrorRef *error);
57static CFTypeRef kc_encode_keyclass(keyclass_t keyclass);
58static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control);
59static CFTypeRef kc_copy_protection_from_data(CFDataRef data);
60static CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error);
61static CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error);
62#if USE_KEYSTORE
63static CFDataRef kc_copy_constraints_data(SecAccessControlRef access_control, CFDictionaryRef auth_attributes);
64static void kc_dict_from_auth_data(const SecDbClass *class, const uint8_t *der, const uint8_t *der_end, CFMutableDictionaryRef *authenticated_attributes, CFMutableDictionaryRef *acl);
65static 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 */
73bool 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
245out:
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. */
268bool 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    }
541out:
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()
569CFDataRef 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
585static 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
593CFDataRef kc_copy_sha1(size_t len, const void *data, CFErrorRef *error) {
594    return kc_copy_digest(ccsha1_di(), len, data, error);
595}
596
597CFDataRef 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
607static 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
630static 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
652static 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
676static 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
690static 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
705static 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
719static 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. */
727static CF_RETURNS_RETAINED
728CFMutableDictionaryRef 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
738static CF_RETURNS_RETAINED
739CFMutableDictionaryRef 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
745static CF_RETURNS_RETAINED
746CFMutableDictionaryRef 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
758bool 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
800out:
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.  */
810static 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
866bool 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
915out:
916    CFReleaseSafe(dict);
917    CFReleaseSafe(access_control);
918    return ok;
919}
920
921/* Automagically make a item syncable, based on various attributes. */
922bool 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 */
951SecDbItemRef 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
968bool 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}
983