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 *  SecDbQuery.c - CoreFoundation-based constants and functions for
26    access to Security items (certificates, keys, identities, and
27    passwords.)
28 */
29
30#include <securityd/SecDbQuery.h>
31
32#include <securityd/SecItemDb.h>
33#include <securityd/SecItemSchema.h>
34#include <securityd/SecItemServer.h>
35#include <securityd/spi.h>
36#include <Security/SecBasePriv.h>
37#include <Security/SecCertificateInternal.h>
38#include <Security/SecItem.h>
39#include <Security/SecItemPriv.h>
40#include <Security/SecItemInternal.h>
41#include <Security/SecAccessControl.h>
42#include <Security/SecAccessControlPriv.h>
43#include <CommonCrypto/CommonDigest.h>
44#include <CommonCrypto/CommonDigestSPI.h>
45
46#include <pthread/pthread.h>
47
48#if USE_KEYSTORE
49#include <LocalAuthentication/LAPublicDefines.h>
50#include <coreauthd_spi.h>
51#include <libaks_acl_cf_keys.h>
52#endif
53
54/* Upper limit for number of keys in a QUERY dictionary. */
55#define QUERY_KEY_LIMIT_BASE    (128)
56#ifdef NO_SERVER
57#define QUERY_KEY_LIMIT  (31 + QUERY_KEY_LIMIT_BASE)
58#else
59#define QUERY_KEY_LIMIT  QUERY_KEY_LIMIT_BASE
60#endif
61
62/* Inline accessors to attr and match values in a query. */
63CFIndex query_attr_count(const Query *q)
64{
65    return q->q_attr_end;
66}
67
68Pair query_attr_at(const Query *q, CFIndex ix)
69{
70    return q->q_pairs[ix];
71}
72
73CFIndex query_match_count(const Query *q)
74{
75    return q->q_match_end - q->q_match_begin;
76}
77
78__unused static inline Pair query_match_at(const Query *q, CFIndex ix)
79{
80    return q->q_pairs[q->q_match_begin + ix];
81}
82
83/* Private routines used to parse a query. */
84
85const SecDbClass *kc_class_with_name(CFStringRef name) {
86    if (isString(name)) {
87#if 0
88        // TODO Iterate kc_db_classes and look for name == class->name.
89        // Or get clever and switch on first letter of class name and compare to verify
90        static const void *kc_db_classes[] = {
91            &genp_class,
92            &inet_class,
93            &cert_class,
94            &keys_class,
95            &identity_class
96        };
97#endif
98        if (CFEqual(name, kSecClassGenericPassword))
99            return &genp_class;
100        else if (CFEqual(name, kSecClassInternetPassword))
101            return &inet_class;
102        else if (CFEqual(name, kSecClassCertificate))
103            return &cert_class;
104        else if (CFEqual(name, kSecClassKey))
105            return &keys_class;
106        else if (CFEqual(name, kSecClassIdentity))
107            return &identity_class;
108    }
109    return NULL;
110}
111
112static void query_set_access_control(Query *q, SecAccessControlRef access_control) {
113    if (q->q_access_control) {
114        if (!CFEqual(q->q_access_control, access_control)) {
115            SecError(errSecItemIllegalQuery, &q->q_error, CFSTR("conflicting kSecAccess and kSecAccessControl attributes"));
116        }
117    } else {
118        /* Store access control virtual attribute. */
119        q->q_access_control = (SecAccessControlRef)CFRetain(access_control);
120
121        /* Also set legacy access attribute. */
122        CFDictionarySetValue(q->q_item, kSecAttrAccessible, SecAccessControlGetProtection(q->q_access_control));
123    }
124}
125
126/* AUDIT[securityd](done):
127 key (ok) is a caller provided, string or number of length 4.
128 value (ok) is a caller provided, non NULL CFTypeRef.
129 */
130static void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q)
131{
132    if (CFEqual(desc->name, kSecAttrSynchronizable)) {
133        q->q_sync = true;
134        if (CFEqual(value, kSecAttrSynchronizableAny))
135            return; /* skip the attribute so it isn't part of the search */
136    }
137
138    CFTypeRef attr = NULL;
139    switch (desc->kind) {
140        case kSecDbDataAttr:
141            attr = copyData(value);
142            break;
143        case kSecDbBlobAttr:
144        case kSecDbAccessControlAttr:
145            attr = copyBlob(value);
146            break;
147        case kSecDbDateAttr:
148        case kSecDbCreationDateAttr:
149        case kSecDbModificationDateAttr:
150            attr = copyDate(value);
151            break;
152        case kSecDbNumberAttr:
153        case kSecDbSyncAttr:
154        case kSecDbTombAttr:
155            attr = copyNumber(value);
156            break;
157        case kSecDbAccessAttr:
158        case kSecDbStringAttr:
159            attr = copyString(value);
160            break;
161        case kSecDbSHA1Attr:
162            attr = copySHA1(value);
163            break;
164        case kSecDbRowIdAttr:
165        case kSecDbPrimaryKeyAttr:
166        case kSecDbEncryptedDataAttr:
167            break;
168    }
169
170    if (!attr) {
171        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
172        return;
173    }
174
175    /* Store plaintext attr data in q_item unless it's a kSecDbSHA1Attr. */
176    if (q->q_item && desc->kind != kSecDbSHA1Attr) {
177        CFDictionarySetValue(q->q_item, desc->name, attr);
178    }
179
180    if (desc->kind == kSecDbAccessControlAttr) {
181        SecAccessControlRef access_control = SecAccessControlCreateFromData(kCFAllocatorDefault, attr, &q->q_error);
182        if (access_control) {
183            query_set_access_control(q, access_control);
184            CFRelease(access_control);
185        }
186    }
187
188    if (desc->kind == kSecDbAccessAttr) {
189        SecAccessControlRef access_control = SecAccessControlCreateWithFlags(kCFAllocatorDefault, attr, 0, &q->q_error);
190        if (access_control) {
191            query_set_access_control(q, access_control);
192            CFRelease(access_control);
193        }
194    }
195
196    /* Convert attr to (sha1) digest if requested. */
197    if (desc->flags & kSecDbSHA1ValueInFlag) {
198        CFDataRef data = copyData(attr);
199        CFRelease(attr);
200        if (!data) {
201            SecError(errSecInternal, &q->q_error, CFSTR("failed to get attribute %@ data"), desc->name);
202            return;
203        }
204
205        CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH);
206        CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH);
207        /* 64 bits cast: worst case is we generate the wrong hash */
208        assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
209        CCDigest(kCCDigestSHA1, CFDataGetBytePtr(data), (CC_LONG)CFDataGetLength(data),
210                 CFDataGetMutableBytePtr(digest));
211        CFRelease(data);
212        attr = digest;
213    }
214
215    if (desc->kind != kSecDbAccessControlAttr) {
216        /* Record the new attr key, value in q_pairs. */
217        q->q_pairs[q->q_attr_end].key = desc->name;
218        q->q_pairs[q->q_attr_end++].value = attr;
219    } else {
220        CFReleaseSafe(attr);
221    }
222}
223
224void query_add_attribute(const void *key, const void *value, Query *q)
225{
226    const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
227    if (desc)
228        query_add_attribute_with_desc(desc, value, q);
229}
230
231/* First remove key from q->q_pairs if it's present, then add the attribute again. */
232static void query_set_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q) {
233    if (CFDictionaryContainsKey(q->q_item, desc->name)) {
234        CFIndex ix;
235        for (ix = 0; ix < q->q_attr_end; ++ix) {
236            if (CFEqual(desc->name, q->q_pairs[ix].key)) {
237                CFReleaseSafe(q->q_pairs[ix].value);
238                --q->q_attr_end;
239                for (; ix < q->q_attr_end; ++ix) {
240                    q->q_pairs[ix] = q->q_pairs[ix + 1];
241                }
242                CFDictionaryRemoveValue(q->q_item, desc->name);
243                break;
244            }
245        }
246    }
247    query_add_attribute_with_desc(desc, value, q);
248}
249
250/* AUDIT[securityd](done):
251 key (ok) is a caller provided, string starting with 'm'.
252 value (ok) is a caller provided, non NULL CFTypeRef.
253 */
254static void query_add_match(const void *key, const void *value, Query *q)
255{
256    /* Record the match key, value in q_pairs. */
257    --(q->q_match_begin);
258    q->q_pairs[q->q_match_begin].key = key;
259    q->q_pairs[q->q_match_begin].value = value;
260
261    if (CFEqual(kSecMatchLimit, key)) {
262        /* Figure out what the value for kSecMatchLimit is if specified. */
263        if (CFGetTypeID(value) == CFNumberGetTypeID()) {
264            if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
265                SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value);
266        } else if (CFEqual(kSecMatchLimitAll, value)) {
267            q->q_limit = kSecMatchUnlimited;
268        } else if (CFEqual(kSecMatchLimitOne, value)) {
269            q->q_limit = 1;
270        } else {
271            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value);
272        }
273    } else if (CFEqual(kSecMatchIssuers, key) &&
274               (CFGetTypeID(value) == CFArrayGetTypeID()))
275    {
276        CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
277        if (canonical_issuers) {
278            CFIndex i, count = CFArrayGetCount(value);
279            for (i = 0; i < count; i++) {
280                CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i);
281                CFDataRef issuer_canonical = NULL;
282                if (CFDataGetTypeID() == CFGetTypeID(issuer_data))
283                    issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data);
284                if (issuer_canonical) {
285                    CFArrayAppendValue(canonical_issuers, issuer_canonical);
286                    CFRelease(issuer_canonical);
287                }
288            }
289
290            if (CFArrayGetCount(canonical_issuers) > 0) {
291                q->q_match_issuer = canonical_issuers;
292            } else
293                CFRelease(canonical_issuers);
294        }
295    }
296}
297
298static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) {
299    const SecDbClass *value;
300    if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
301        (value = kc_class_with_name(c_name)) &&
302        (q->q_class == 0 || q->q_class == value)) {
303        q->q_class = value;
304        return true;
305    }
306
307    if (error && !*error)
308        SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name);
309
310
311    return false;
312}
313
314static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) {
315    CFStringRef c_name = NULL;
316    const void *value = CFDictionaryGetValue(query, kSecClass);
317    if (isString(value)) {
318        c_name = value;
319    } else {
320        value = CFDictionaryGetValue(query, kSecValuePersistentRef);
321        if (isData(value)) {
322            CFDataRef pref = value;
323            _SecItemParsePersistentRef(pref, &c_name, 0);
324        }
325    }
326
327    if (c_name && (value = kc_class_with_name(c_name))) {
328        return value;
329    } else {
330        if (c_name)
331            SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name);
332        else
333            SecError(errSecItemClassMissing, error, CFSTR("query missing class name"));
334        return NULL;
335    }
336}
337
338/* AUDIT[securityd](done):
339 key (ok) is a caller provided, string starting with 'c'.
340 value (ok) is a caller provided, non NULL CFTypeRef.
341 */
342static void query_add_class(const void *key, const void *value, Query *q)
343{
344    if (CFEqual(key, kSecClass)) {
345        query_set_class(q, value, &q->q_error);
346    } else {
347        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass);
348    }
349}
350
351/* AUDIT[securityd](done):
352 key (ok) is a caller provided, string starting with 'r'.
353 value (ok) is a caller provided, non NULL CFTypeRef.
354 */
355static void query_add_return(const void *key, const void *value, Query *q)
356{
357    ReturnTypeMask mask;
358    if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
359        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value);
360        return;
361    }
362
363    int set_it = CFEqual(value, kCFBooleanTrue);
364
365    if (CFEqual(key, kSecReturnData))
366        mask = kSecReturnDataMask;
367    else if (CFEqual(key, kSecReturnAttributes))
368        mask = kSecReturnAttributesMask;
369    else if (CFEqual(key, kSecReturnRef))
370        mask = kSecReturnRefMask;
371    else if (CFEqual(key, kSecReturnPersistentRef))
372        mask = kSecReturnPersistentRefMask;
373    else {
374        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key);
375        return;
376    }
377
378    if ((q->q_return_type & mask) && !set_it) {
379        /* Clear out this bit (it's set so xor with the mask will clear it). */
380        q->q_return_type ^= mask;
381    } else if (!(q->q_return_type & mask) && set_it) {
382        /* Set this bit. */
383        q->q_return_type |= mask;
384    }
385}
386
387/* AUDIT[securityd](done):
388 key (ok) is a caller provided, string starting with 'u'.
389 value (ok since q_use_item_list is unused) is a caller provided, non
390 NULL CFTypeRef.
391 */
392static void query_add_use(const void *key, const void *value, Query *q)
393{
394    if (CFEqual(key, kSecUseItemList)) {
395        /* TODO: Add sanity checking when we start using this. */
396        q->q_use_item_list = value;
397    } else if (CFEqual(key, kSecUseTombstones)) {
398        if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
399            q->q_use_tomb = value;
400        } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
401            q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
402        } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
403            q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
404        } else {
405            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
406            return;
407        }
408    } else if (CFEqual(key, kSecUseCredentialReference)) {
409        if (isData(value)) {
410            CFRetainAssign(q->q_use_cred_handle, value);
411        } else {
412            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFData"), value, key);
413            return;
414        }
415    } else if (CFEqual(key, kSecUseOperationPrompt)) {
416        if (isString(value)) {
417            CFRetainAssign(q->q_use_operation_prompt, value);
418        } else {
419            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFString"), value, key);
420            return;
421        }
422    } else if (CFEqual(key, kSecUseNoAuthenticationUI)) {
423        if (isBoolean(value)) {
424            q->q_use_no_authentication_ui = value;
425        } else if (isNumber(value)) {
426            q->q_use_no_authentication_ui = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
427        } else if (isString(value)) {
428            q->q_use_no_authentication_ui = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
429        } else {
430            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
431            return;
432        }
433#if defined(MULTIPLE_KEYCHAINS)
434    } else if (CFEqual(key, kSecUseKeychain)) {
435        q->q_use_keychain = value;
436    } else if (CFEqual(key, kSecUseKeychainList)) {
437        q->q_use_keychain_list = value;
438#endif /* !defined(MULTIPLE_KEYCHAINS) */
439    } else {
440        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key);
441        return;
442    }
443}
444
445static void query_set_data(const void *value, Query *q) {
446    if (!isData(value)) {
447        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value);
448    } else {
449        q->q_data = value;
450        if (q->q_item)
451            CFDictionarySetValue(q->q_item, kSecValueData, value);
452    }
453}
454
455/* AUDIT[securityd](done):
456 key (ok) is a caller provided, string starting with 'u'.
457 value (ok) is a caller provided, non NULL CFTypeRef.
458 */
459static void query_add_value(const void *key, const void *value, Query *q)
460{
461    if (CFEqual(key, kSecValueData)) {
462        query_set_data(value, q);
463#ifdef NO_SERVER
464    } else if (CFEqual(key, kSecValueRef)) {
465        q->q_ref = value;
466        /* TODO: Add value type sanity checking. */
467#endif
468    } else if (CFEqual(key, kSecValuePersistentRef)) {
469        CFStringRef c_name;
470        if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id))
471            query_set_class(q, c_name, &q->q_error);
472        else
473            SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value);
474    } else {
475        SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key);
476        return;
477    }
478}
479
480/* AUDIT[securityd](done):
481 key (ok) is a caller provided, unchecked.
482 value (ok) is a caller provided, unchecked.
483 */
484static void query_update_applier(const void *key, const void *value,
485                                 void *context)
486{
487    Query *q = (Query *)context;
488    /* If something went wrong there is no point processing any more args. */
489    if (q->q_error)
490        return;
491
492    /* Make sure we have a string key. */
493    if (!isString(key)) {
494        SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key);
495        return;
496    }
497
498    if (!value) {
499        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key);
500        return;
501    }
502
503    if (CFEqual(key, kSecValueData)) {
504        query_set_data(value, q);
505    } else {
506        query_add_attribute(key, value, q);
507    }
508}
509
510/* AUDIT[securityd](done):
511 key (ok) is a caller provided, unchecked.
512 value (ok) is a caller provided, unchecked.
513 */
514static void query_applier(const void *key, const void *value, void *context)
515{
516    Query *q = (Query *)context;
517    /* If something went wrong there is no point processing any more args. */
518    if (q->q_error)
519        return;
520
521    /* Make sure we have a key. */
522    if (!key) {
523        SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key"));
524        return;
525    }
526
527    /* Make sure we have a value. */
528    if (!value) {
529        SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key);
530        return;
531    }
532
533    /* Figure out what type of key we are dealing with. */
534    CFTypeID key_id = CFGetTypeID(key);
535    if (key_id == CFStringGetTypeID()) {
536        CFIndex key_len = CFStringGetLength(key);
537        /* String keys can be different things.  The subtype is determined by:
538         length 4 strings are all attributes.  Otherwise the first char
539         determines the type:
540         c: class must be kSecClass
541         m: match like kSecMatchPolicy
542         r: return like kSecReturnData
543         u: use keys
544         v: value
545         */
546        if (key_len == 4) {
547            /* attributes */
548            query_add_attribute(key, value, q);
549        } else if (key_len > 1) {
550            UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
551            switch (k_first_char)
552            {
553                case 'c': /* class */
554                    query_add_class(key, value, q);
555                    break;
556                case 'm': /* match */
557                    query_add_match(key, value, q);
558                    break;
559                case 'r': /* return */
560                    query_add_return(key, value, q);
561                    break;
562                case 'u': /* use */
563                    query_add_use(key, value, q);
564                    break;
565                case 'v': /* value */
566                    query_add_value(key, value, q);
567                    break;
568                default:
569                    SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key);
570                    break;
571            }
572        } else {
573            SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key);
574        }
575    } else if (key_id == CFNumberGetTypeID()) {
576        /* Numeric keys are always (extended) attributes. */
577        /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
578        query_add_attribute(key, value, q);
579    } else {
580        /* We only support string and number type keys. */
581        SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key);
582    }
583}
584
585static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
586    /* apsd and lockdown are always dku. */
587    if (CFEqual(agrp, CFSTR("com.apple.apsd"))
588        || CFEqual(agrp, CFSTR("lockdown-identities"))) {
589        return kSecAttrAccessibleAlwaysThisDeviceOnly;
590    }
591    /* All other certs or in the apple agrp is dk. */
592    if (q->q_class == &cert_class) {
593        /* third party certs are always dk. */
594        return kSecAttrAccessibleAlways;
595    }
596    /* The rest defaults to ak. */
597    return kSecAttrAccessibleWhenUnlocked;
598}
599
600void query_ensure_access_control(Query *q, CFStringRef agrp) {
601    if (q->q_access_control == 0) {
602        CFStringRef accessible = query_infer_keyclass(q, agrp);
603        query_add_attribute(kSecAttrAccessible, accessible, q);
604    }
605}
606
607bool query_error(Query *q, CFErrorRef *error) {
608    CFErrorRef tmp = q->q_error;
609    q->q_error = NULL;
610    return CFErrorPropagate(tmp, error);
611}
612
613bool query_destroy(Query *q, CFErrorRef *error) {
614    bool ok = query_error(q, error);
615    CFIndex ix, attr_count = query_attr_count(q);
616    for (ix = 0; ix < attr_count; ++ix) {
617        CFReleaseSafe(query_attr_at(q, ix).value);
618    }
619    CFReleaseSafe(q->q_item);
620    CFReleaseSafe(q->q_primary_key_digest);
621    CFReleaseSafe(q->q_match_issuer);
622    CFReleaseSafe(q->q_access_control);
623    CFReleaseSafe(q->q_use_cred_handle);
624    CFReleaseSafe(q->q_required_access_controls);
625    CFReleaseSafe(q->q_use_operation_prompt);
626    CFReleaseSafe(q->q_caller_access_groups);
627
628    free(q);
629    return ok;
630}
631
632bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
633    if (ok && !q->q_error && q->q_sync_changed) {
634        SecKeychainChanged(true);
635    }
636    return query_destroy(q, error) && ok;
637}
638
639/* Allocate and initialize a Query object for query. */
640Query *query_create(const SecDbClass *qclass, CFDictionaryRef query,
641                    CFErrorRef *error)
642{
643    if (!qclass) {
644        if (error && !*error)
645            SecError(errSecItemClassMissing, error, CFSTR("Missing class"));
646        return NULL;
647    }
648
649    /* Number of pairs we need is the number of attributes in this class
650     plus the number of keys in the dictionary, minus one for each key in
651     the dictionary that is a regular attribute. */
652    CFIndex key_count = SecDbClassAttrCount(qclass);
653    if (key_count == 0) {
654        // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
655        key_count = SecDbClassAttrCount(&cert_class) + SecDbClassAttrCount(&keys_class);
656    }
657
658    if (query) {
659        key_count += CFDictionaryGetCount(query);
660        SecDbForEachAttr(qclass, attr) {
661            if (CFDictionaryContainsKey(query, attr->name))
662                --key_count;
663        }
664    }
665
666    if (key_count > QUERY_KEY_LIMIT) {
667        if (error && !*error)
668        {
669            secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT);
670            SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit"));
671        }
672        return NULL;
673    }
674
675    Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
676    if (q == NULL) {
677        if (error && !*error)
678            SecError(errSecAllocate, error, CFSTR("Out of memory"));
679        return NULL;
680    }
681
682    q->q_keybag = KEYBAG_DEVICE;
683    q->q_class = qclass;
684    q->q_match_begin = q->q_match_end = key_count;
685    q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
686    q->q_crypto_op = kSecKsUnwrap;
687
688    return q;
689}
690
691/* Parse query for a Query object q. */
692static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
693                                     CFDictionaryApplierFunction applier,
694                                     CFErrorRef *error) {
695    CFDictionaryApplyFunction(query, applier, q);
696    return query_error(q, error);
697}
698
699/* Parse query for a Query object q. */
700static bool query_parse(Query *q, CFDictionaryRef query,
701                        CFErrorRef *error) {
702    return query_parse_with_applier(q, query, query_applier, error);
703}
704
705/* Parse query for a Query object q. */
706bool query_update_parse(Query *q, CFDictionaryRef update,
707                               CFErrorRef *error) {
708    return query_parse_with_applier(q, update, query_update_applier, error);
709}
710
711Query *query_create_with_limit(CFDictionaryRef query, CFIndex limit,
712                                      CFErrorRef *error) {
713    Query *q;
714    q = query_create(query_get_class(query, error), query, error);
715    if (q) {
716        q->q_limit = limit;
717        if (!query_parse(q, query, error)) {
718            query_destroy(q, error);
719            return NULL;
720        }
721        if (!q->q_sync && !q->q_row_id) {
722            /* query did not specify a kSecAttrSynchronizable attribute,
723             * and did not contain a persistent reference. */
724            query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q);
725        }
726    }
727    return q;
728}
729
730
731//TODO: Move this to SecDbItemRef
732
733/* Make sure all attributes that are marked as not_null have a value.  If
734 force_date is false, only set mdat and cdat if they aren't already set. */
735void
736query_pre_add(Query *q, bool force_date) {
737    CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
738    SecDbForEachAttrWithMask(q->q_class, desc, kSecDbInFlag) {
739        if (desc->kind == kSecDbCreationDateAttr ||
740            desc->kind == kSecDbModificationDateAttr) {
741            if (force_date) {
742                query_set_attribute_with_desc(desc, now, q);
743            } else if (!CFDictionaryContainsKey(q->q_item, desc->name)) {
744                query_add_attribute_with_desc(desc, now, q);
745            }
746        } else if ((desc->flags & kSecDbNotNullFlag) &&
747                   !CFDictionaryContainsKey(q->q_item, desc->name)) {
748            CFTypeRef value = NULL;
749            if (desc->flags & kSecDbDefault0Flag) {
750                if (desc->kind == kSecDbDateAttr)
751                    value = CFDateCreate(kCFAllocatorDefault, 0.0);
752                else {
753                    SInt32 vzero = 0;
754                    value = CFNumberCreate(0, kCFNumberSInt32Type, &vzero);
755                }
756            } else if (desc->flags & kSecDbDefaultEmptyFlag) {
757                if (desc->kind == kSecDbDataAttr)
758                    value = CFDataCreate(kCFAllocatorDefault, NULL, 0);
759                else {
760                    value = CFSTR("");
761                    CFRetain(value);
762                }
763            }
764            if (value) {
765                /* Safe to use query_add_attribute here since the attr wasn't
766                 set yet. */
767                query_add_attribute_with_desc(desc, value, q);
768                CFRelease(value);
769            }
770        }
771    }
772    CFReleaseSafe(now);
773}
774
775//TODO: Move this to SecDbItemRef
776
777/* Update modification_date if needed. */
778void
779query_pre_update(Query *q) {
780    SecDbForEachAttr(q->q_class, desc) {
781        if (desc->kind == kSecDbModificationDateAttr) {
782            CFDateRef now = CFDateCreate(0, CFAbsoluteTimeGetCurrent());
783            query_set_attribute_with_desc(desc, now, q);
784            CFReleaseSafe(now);
785        }
786    }
787}
788
789void
790query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups) {
791    CFRetainAssign(q->q_caller_access_groups, caller_access_groups);
792}
793
794bool
795query_needs_authentication(Query *q) {
796    return q->q_required_access_controls && CFArrayGetCount(q->q_required_access_controls) > 0;
797}
798
799void
800query_enable_interactive(Query *q) {
801    CFAssignRetained(q->q_required_access_controls, CFArrayCreateMutableForCFTypes(kCFAllocatorDefault));
802}
803
804bool
805query_authenticate(Query *q, CFErrorRef **error) {
806    bool ok = true;
807    CFMutableDictionaryRef hints = NULL;
808#if USE_KEYSTORE
809    if (q->q_use_no_authentication_ui && CFBooleanGetValue(q->q_use_no_authentication_ui)) {
810        SecError(errSecInteractionNotAllowed, *error, CFSTR("authentication UI is not allowed"));
811        return false;
812    }
813    if (isString(q->q_use_operation_prompt)) {
814        if (!hints) {
815            hints = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
816        }
817        // VRHintAppAction
818        CFNumberRef reasonKey = CFNumberCreateWithCFIndex(kCFAllocatorDefault, kLAOptionAuthenticationReason);
819        CFDictionaryAddValue(hints, reasonKey, q->q_use_operation_prompt);
820        CFRelease(reasonKey);
821    }
822
823    if (*error)
824        CFReleaseNull(**error);
825
826    CFErrorRef authError = NULL;
827    CFDataRef ac_data;
828    CFArrayForEachC(q->q_required_access_controls, ac_data) {
829        ok = VREvaluateACL(q->q_use_cred_handle, ac_data, kAKSKeyOpDecrypt, hints, &authError);
830        if (!ok) {
831            ok = SecCFCreateError(errSecAuthFailed, kSecErrorDomain, CFSTR("LocalAuthentication failed"), authError, *error);
832            CFReleaseSafe(authError);
833            goto out;
834        }
835    }
836    CFArrayRemoveAllValues(q->q_required_access_controls);
837
838out:
839#endif
840    CFReleaseSafe(hints);
841    return ok;
842}
843