/ keychain / securityd / SecDbQuery.c
SecDbQuery.c
  1  
  2  /*
  3   * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
  4   *
  5   * @APPLE_LICENSE_HEADER_START@
  6   * 
  7   * This file contains Original Code and/or Modifications of Original Code
  8   * as defined in and that are subject to the Apple Public Source License
  9   * Version 2.0 (the 'License'). You may not use this file except in
 10   * compliance with the License. Please obtain a copy of the License at
 11   * http://www.opensource.apple.com/apsl/ and read it before using this
 12   * file.
 13   * 
 14   * The Original Code and all software distributed under the License are
 15   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 16   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 17   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 18   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 19   * Please see the License for the specific language governing rights and
 20   * limitations under the License.
 21   * 
 22   * @APPLE_LICENSE_HEADER_END@
 23   */
 24  
 25  /*
 26   *  SecDbQuery.c - CoreFoundation-based constants and functions for
 27      access to Security items (certificates, keys, identities, and
 28      passwords.)
 29   */
 30  
 31  #include "keychain/securityd/SecDbQuery.h"
 32  
 33  #include "keychain/securityd/SecItemDb.h"
 34  #include "keychain/securityd/SecItemSchema.h"
 35  #include "keychain/securityd/SecItemServer.h"
 36  #include "keychain/securityd/spi.h"
 37  #include <Security/SecBasePriv.h>
 38  #include <Security/SecCertificateInternal.h>
 39  #include <Security/SecItem.h>
 40  #include <Security/SecItemPriv.h>
 41  #include <Security/SecItemInternal.h>
 42  #include <Security/SecAccessControl.h>
 43  #include <Security/SecAccessControlPriv.h>
 44  #include <Security/SecPolicyPriv.h>
 45  #include <Security/SecuritydXPC.h>
 46  #include <CommonCrypto/CommonDigest.h>
 47  #include <CommonCrypto/CommonDigestSPI.h>
 48  
 49  #include <pthread/pthread.h>
 50  
 51  #if USE_KEYSTORE
 52  #include <LocalAuthentication/LAPublicDefines.h>
 53  #include <coreauthd_spi.h>
 54  #include <libaks_acl_cf_keys.h>
 55  #endif
 56  
 57  /* Upper limit for number of keys in a QUERY dictionary. */
 58  #define QUERY_KEY_LIMIT_BASE    (128)
 59  #ifdef NO_SERVER
 60  #define QUERY_KEY_LIMIT  (31 + QUERY_KEY_LIMIT_BASE)
 61  #else
 62  #define QUERY_KEY_LIMIT  QUERY_KEY_LIMIT_BASE
 63  #endif
 64  
 65  
 66  static const uint8_t systemKeychainUUID[] = "\xF6\x23\xAE\x5C\xCC\x81\x4C\xAC\x8A\xD4\xF0\x01\x3F\x31\x35\x11";
 67  
 68  CFDataRef
 69  SecMUSRCopySystemKeychainUUID(void)
 70  {
 71      return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)systemKeychainUUID, 16, kCFAllocatorNull);
 72  }
 73  
 74  CFDataRef
 75  SecMUSRGetSystemKeychainUUID(void)
 76  {
 77      static dispatch_once_t onceToken;
 78      static CFDataRef systemKeychainData = NULL;
 79      dispatch_once(&onceToken, ^{
 80          systemKeychainData = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)systemKeychainUUID, 16, kCFAllocatorNull);
 81      });
 82      return systemKeychainData;
 83  }
 84  
 85  CFDataRef
 86  SecMUSRGetSingleUserKeychainUUID(void)
 87  {
 88      static dispatch_once_t onceToken;
 89      static CFDataRef singleUser = NULL;
 90      dispatch_once(&onceToken, ^{
 91          singleUser = CFDataCreateWithBytesNoCopy(NULL, NULL, 0, kCFAllocatorNull);
 92      });
 93      return singleUser;
 94  }
 95  
 96  bool
 97  SecMUSRIsSingleUserView(CFDataRef musr)
 98  {
 99      return CFEqual(musr, SecMUSRGetSingleUserKeychainUUID());
100  }
101  
102  static const uint8_t allKeychainViewsUUID[16] = "\xC8\x60\x07\xEC\x89\x62\x4D\xAF\x85\x65\x1F\xE6\x0F\x50\x5D\xB7";
103  
104  CFDataRef
105  SecMUSRGetAllViews(void)
106  {
107      static dispatch_once_t onceToken;
108      static CFDataRef allKeychainViewsData = NULL;
109      dispatch_once(&onceToken, ^{
110          allKeychainViewsData = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)allKeychainViewsUUID, 16, kCFAllocatorNull);
111      });
112      return allKeychainViewsData;
113  }
114  
115  bool
116  SecMUSRIsViewAllViews(CFDataRef musr)
117  {
118      return CFEqual(musr, SecMUSRGetAllViews());
119  }
120  
121  #if TARGET_OS_IPHONE
122  
123  CFDataRef
124  SecMUSRCreateActiveUserUUID(uid_t uid)
125  {
126      uint8_t uuid[16] = "\xA7\x5A\x3A\x35\xA5\x57\x4B\x10\xBE\x2E\x83\x94\x7E\x4A\x34\x72";
127      uint32_t num = htonl(uid);
128      memcpy(&uuid[12], &num, sizeof(num));
129      return CFDataCreate(NULL, uuid, sizeof(uuid));
130  }
131  
132  CFDataRef
133  SecMUSRCreateSyncBubbleUserUUID(uid_t uid)
134  {
135      uint8_t uuid[16] = "\x82\x1A\xAB\x9F\xA3\xC8\x4E\x11\xAA\x90\x4C\xE8\x9E\xA6\xD7\xEC";
136      uint32_t num = htonl(uid);
137      memcpy(&uuid[12], &num, sizeof(num));
138      return CFDataCreate(NULL, uuid, sizeof(uuid));
139  }
140  
141  static const uint8_t bothUserAndSystemUUID[12] = "\x36\xC4\xBE\x2E\x99\x0A\x46\x9A\xAC\x89\x09\xA4";
142  
143  
144  CFDataRef
145  SecMUSRCreateBothUserAndSystemUUID(uid_t uid)
146  {
147      uint8_t uuid[16];
148      memcpy(uuid, bothUserAndSystemUUID, 12);
149      uint32_t num = htonl(uid);
150      memcpy(&uuid[12], &num, sizeof(num));
151      return CFDataCreate(NULL, uuid, sizeof(uuid));
152  }
153  
154  bool
155  SecMUSRGetBothUserAndSystemUUID(CFDataRef musr, uid_t *uid)
156  {
157      if (CFDataGetLength(musr) != 16)
158          return false;
159      const uint8_t *uuid = CFDataGetBytePtr(musr);
160      if (memcmp(uuid, bothUserAndSystemUUID, 12) != 0)
161          return false;
162      if (uid) {
163          uint32_t num;
164          memcpy(&num, &uuid[12], sizeof(num));
165          *uid = htonl(num);
166      }
167      return true;
168  }
169  
170  #endif
171  
172  /* Inline accessors to attr and match values in a query. */
173  CFIndex query_attr_count(const Query *q)
174  {
175      return q->q_attr_end;
176  }
177  
178  Pair query_attr_at(const Query *q, CFIndex ix)
179  {
180      return q->q_pairs[ix];
181  }
182  
183  CFIndex query_match_count(const Query *q)
184  {
185      return q->q_match_end - q->q_match_begin;
186  }
187  
188  __unused static inline Pair query_match_at(const Query *q, CFIndex ix)
189  {
190      return q->q_pairs[q->q_match_begin + ix];
191  }
192  
193  /* Private routines used to parse a query. */
194  
195  const SecDbClass *kc_class_with_name(CFStringRef name) {
196      if (isString(name)) {
197          if (CFEqual(name, kSecClassGenericPassword))
198              return genp_class();
199          else if (CFEqual(name, kSecClassInternetPassword))
200              return inet_class();
201          else if (CFEqual(name, kSecClassCertificate))
202              return cert_class();
203          else if (CFEqual(name, kSecClassKey))
204              return keys_class();
205          else if (CFEqual(name, kSecClassIdentity))
206              return identity_class();
207      }
208      return NULL;
209  }
210  
211  static void query_set_access_control(Query *q, SecAccessControlRef access_control) {
212      if (q->q_access_control) {
213          if (!CFEqual(q->q_access_control, access_control)) {
214              SecError(errSecItemIllegalQuery, &q->q_error, CFSTR("conflicting kSecAccess and kSecAccessControl attributes"));
215          }
216      } else {
217          /* Store access control virtual attribute. */
218          q->q_access_control = (SecAccessControlRef)CFRetain(access_control);
219          
220          /* Also set legacy access attribute. */
221          CFTypeRef protection = SecAccessControlGetProtection(q->q_access_control);
222          if (!protection) {
223              SecError(errSecParam, &q->q_error, CFSTR("kSecAccessControl missing protection"));
224              return;
225          }
226          CFDictionarySetValue(q->q_item, kSecAttrAccessible, protection);
227      }
228  }
229  
230  /* AUDIT[securityd](done):
231   key (ok) is a caller provided, string or number of length 4.
232   value (ok) is a caller provided, non NULL CFTypeRef.
233   */
234  void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q)
235  {
236      if (CFEqual(desc->name, kSecAttrSynchronizable)) {
237          q->q_sync = true;
238          if (CFEqual(value, kSecAttrSynchronizableAny))
239              return; /* skip the attribute so it isn't part of the search */
240      }
241  
242      CFTypeRef attr = NULL;
243      switch (desc->kind) {
244          case kSecDbDataAttr:
245              attr = copyData(value);
246              break;
247          case kSecDbBlobAttr:
248          case kSecDbAccessControlAttr:
249              attr = copyBlob(value);
250              break;
251          case kSecDbDateAttr:
252          case kSecDbCreationDateAttr:
253          case kSecDbModificationDateAttr:
254              attr = copyDate(value);
255              break;
256          case kSecDbNumberAttr:
257          case kSecDbSyncAttr:
258          case kSecDbTombAttr:
259              attr = copyNumber(value);
260              break;
261          case kSecDbAccessAttr:
262          case kSecDbStringAttr:
263              attr = copyString(value);
264              break;
265          case kSecDbSHA1Attr:
266              attr = copySHA1(value);
267              break;
268          case kSecDbRowIdAttr:
269          case kSecDbPrimaryKeyAttr:
270          case kSecDbEncryptedDataAttr:
271          case kSecDbUTombAttr:
272              break;
273          case kSecDbUUIDAttr:
274              attr = copyUUID(value);
275              break;
276      }
277  
278      if (!attr) {
279          SecError(errSecItemInvalidValue, &q->q_error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
280          return;
281      }
282  
283      /* Store plaintext attr data in q_item unless it's a kSecDbSHA1Attr. */
284      if (q->q_item && desc->kind != kSecDbSHA1Attr) {
285          CFDictionarySetValue(q->q_item, desc->name, attr);
286      }
287  
288      /* Convert attr to (sha1) digest if requested. */
289      if (desc->flags & kSecDbSHA1ValueInFlag) {
290          CFDataRef data = copyData(attr);
291          CFRelease(attr);
292          if (!data) {
293              SecError(errSecInternal, &q->q_error, CFSTR("failed to get attribute %@ data"), desc->name);
294              return;
295          }
296  
297          CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH);
298          CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH);
299          /* 64 bits cast: worst case is we generate the wrong hash */
300          assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
301          CCDigest(kCCDigestSHA1, CFDataGetBytePtr(data), (CC_LONG)CFDataGetLength(data),
302                   CFDataGetMutableBytePtr(digest));
303          CFRelease(data);
304          attr = digest;
305      }
306  
307      if (desc->kind != kSecDbAccessControlAttr) {
308          /* Record the new attr key, value in q_pairs. */
309          if (q->q_attr_end + 1 < q->q_pairs_count) {
310              q->q_pairs[q->q_attr_end].key = desc->name;
311              q->q_pairs[q->q_attr_end++].value = attr;
312          } else {
313              SecError(errSecInternal, &q->q_error, CFSTR("q_pairs overflow"));
314              CFReleaseSafe(attr);
315          }
316      } else {
317          CFReleaseSafe(attr);
318      }
319  }
320  
321  void query_add_attribute(const void *key, const void *value, Query *q)
322  {
323      if (CFEqual(key, kSecAttrDeriveSyncIDFromItemAttributes)) {
324          q->q_uuid_from_primary_key = CFBooleanGetValue(value);
325          return; /* skip the attribute so it isn't part of the search */
326      }
327  
328      const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
329      if (desc) {
330          query_add_attribute_with_desc(desc, value, q);
331  
332          if (desc->kind == kSecDbAccessControlAttr) {
333              CFDataRef attr = (CFDataRef)CFDictionaryGetValue(q->q_item, desc->name);
334              if (attr) {
335                  SecAccessControlRef access_control = SecAccessControlCreateFromData(kCFAllocatorDefault, attr, &q->q_error);
336                  if (access_control) {
337                      query_set_access_control(q, access_control);
338                      CFRelease(access_control);
339                  }
340              }
341          }
342  
343          if (desc->kind == kSecDbAccessAttr) {
344              SecAccessControlRef access_control = SecAccessControlCreate(kCFAllocatorDefault, &q->q_error);
345              if (access_control) {
346                  CFStringRef attr = (CFStringRef)CFDictionaryGetValue(q->q_item, desc->name);
347                  if (attr) {
348                      if (SecAccessControlSetProtection(access_control, attr, &q->q_error))
349                          query_set_access_control(q, access_control);
350                  }
351                  CFRelease(access_control);
352              }
353          }
354      }
355  }
356  
357  void query_add_or_attribute(const void *key, const void *value, Query *q)
358  {
359      const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
360      if (desc) {
361          CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name);
362          CFMutableArrayRef array = NULL;
363          if (oldValue) {
364              if (isArray(oldValue)) {
365                  array = (CFMutableArrayRef)CFRetain(oldValue);
366              } else {
367                  array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
368                  CFArrayAppendValue(array, oldValue);
369              }
370              CFDictionaryRemoveValue(q->q_item, desc->name);
371          } else {
372              array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
373          }
374          if (array) {
375              query_add_attribute_with_desc(desc, value, q);
376              CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name);
377              CFArrayAppendValue(array, newValue);
378              CFDictionarySetValue(q->q_item, desc->name, array);
379              CFRelease(array);
380          }
381      }
382  }
383  
384  void query_add_not_attribute(const void *key, const void *value, Query *q)
385  {
386      const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
387      if (desc) {
388          CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name);
389          CFMutableArrayRef array = NULL;
390          if (oldValue) {
391              if (isArray(oldValue)) {
392                  array = (CFMutableArrayRef)CFRetain(oldValue);
393              } else {
394                  // This should never run, as we shouldn't be turning a attr = value into a attr not in (value, value2)
395                  secerror("negating %@ = %@ in query", desc->name, oldValue);
396                  array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
397                  CFArrayAppendValue(array, kCFNull);
398                  CFArrayAppendValue(array, oldValue);
399              }
400              CFDictionaryRemoveValue(q->q_item, desc->name);
401          } else {
402              array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
403              CFArrayAppendValue(array, kCFNull);
404          }
405          if (array) {
406              query_add_attribute_with_desc(desc, value, q);
407              CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name);
408              CFArrayAppendValue(array, newValue);
409              CFDictionarySetValue(q->q_item, desc->name, array);
410              CFRelease(array);
411          }
412      }
413  }
414  
415  static void query_add_match(const void *key, const void *value, Query *q)
416  {
417      /* Record the match key, value in q_pairs. */
418      --(q->q_match_begin);
419      q->q_pairs[q->q_match_begin].key = key;
420      q->q_pairs[q->q_match_begin].value = value;
421  
422      if (CFEqual(kSecMatchLimit, key)) {
423          /* Figure out what the value for kSecMatchLimit is if specified. */
424          if (CFGetTypeID(value) == CFNumberGetTypeID()) {
425              if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
426                  SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value);
427          } else if (CFEqual(kSecMatchLimitAll, value)) {
428              q->q_limit = kSecMatchUnlimited;
429          } else if (CFEqual(kSecMatchLimitOne, value)) {
430              q->q_limit = 1;
431          } else {
432              SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value);
433          }
434      } else if (CFEqual(kSecMatchIssuers, key) &&
435                 (CFGetTypeID(value) == CFArrayGetTypeID()))
436      {
437          CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
438          if (canonical_issuers) {
439              CFIndex i, count = CFArrayGetCount(value);
440              for (i = 0; i < count; i++) {
441                  CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i);
442                  CFDataRef issuer_canonical = NULL;
443                  if (CFDataGetTypeID() == CFGetTypeID(issuer_data))
444                      issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data);
445                  if (issuer_canonical) {
446                      CFArrayAppendValue(canonical_issuers, issuer_canonical);
447                      CFRelease(issuer_canonical);
448                  }
449              }
450  
451              if (CFArrayGetCount(canonical_issuers) > 0) {
452                  q->q_match_issuer = canonical_issuers;
453              } else
454                  CFRelease(canonical_issuers);
455          }
456      } else if (CFEqual(kSecMatchPolicy, key)) {
457          if (CFGetTypeID(value) != CFArrayGetTypeID()) {
458              SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchPolicy attribute"));
459              return;
460          }
461          xpc_object_t policiesArrayXPC = _CFXPCCreateXPCObjectFromCFObject(value);
462          if (!policiesArrayXPC) {
463              SecError(errSecParam, &q->q_error, CFSTR("unsupported kSecMatchPolicy object in query"));
464              return;
465          }
466  
467          CFArrayRef policiesArray = SecPolicyXPCArrayCopyArray(policiesArrayXPC, &q->q_error);
468          xpc_release(policiesArrayXPC);
469          if (!policiesArray)
470              return;
471  
472          if (CFArrayGetCount(policiesArray) != 1 || CFGetTypeID(CFArrayGetValueAtIndex(policiesArray, 0)) != SecPolicyGetTypeID()) {
473              CFRelease(policiesArray);
474              SecError(errSecParam, &q->q_error, CFSTR("unsupported array of policies"));
475              return;
476          }
477  
478          query_set_policy(q, (SecPolicyRef)CFArrayGetValueAtIndex(policiesArray, 0));
479          CFRelease(policiesArray);
480      } else if (CFEqual(kSecMatchValidOnDate, key)) {
481          if (CFGetTypeID(value) == CFNullGetTypeID()) {
482              CFDateRef date = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
483              query_set_valid_on_date(q, date);
484              CFRelease(date);
485          } else if (CFGetTypeID(value) == CFDateGetTypeID()) {
486              query_set_valid_on_date(q, value);
487          } else {
488              SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchValidOnDate attribute"));
489              return;
490          }
491      } else if (CFEqual(kSecMatchTrustedOnly, key)) {
492          if ((CFGetTypeID(value) == CFBooleanGetTypeID())) {
493              query_set_trusted_only(q, value);
494          } else {
495              SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchTrustedOnly attribute"));
496              return;
497          }
498      }
499  }
500  
501  static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) {
502      const SecDbClass *value;
503      if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
504          (value = kc_class_with_name(c_name)) &&
505          (q->q_class == 0 || q->q_class == value)) {
506          q->q_class = value;
507          return true;
508      }
509  
510      if (error && !*error)
511          SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name);
512  
513  
514      return false;
515  }
516  
517  static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) {
518      CFStringRef c_name = NULL;
519      const void *value = CFDictionaryGetValue(query, kSecClass);
520      if (isString(value)) {
521          c_name = value;
522      } else {
523          value = CFDictionaryGetValue(query, kSecValuePersistentRef);
524          if (isData(value)) {
525              CFDataRef pref = value;
526              _SecItemParsePersistentRef(pref, &c_name, NULL, NULL);
527          }
528      }
529  
530      if (c_name && (value = kc_class_with_name(c_name))) {
531          return value;
532      } else {
533          if (c_name)
534              SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name);
535          else
536              SecError(errSecItemClassMissing, error, CFSTR("query missing class name"));
537          return NULL;
538      }
539  }
540  
541  /* AUDIT[securityd](done):
542   key (ok) is a caller provided, string starting with 'c'.
543   value (ok) is a caller provided, non NULL CFTypeRef.
544   */
545  static void query_add_class(const void *key, const void *value, Query *q)
546  {
547      if (CFEqual(key, kSecClass)) {
548          query_set_class(q, value, &q->q_error);
549      } else {
550          SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass);
551      }
552  }
553  
554  /* AUDIT[securityd](done):
555   key (ok) is a caller provided, string starting with 'r'.
556   value (ok) is a caller provided, non NULL CFTypeRef.
557   */
558  static void query_add_return(const void *key, const void *value, Query *q)
559  {
560      ReturnTypeMask mask;
561      if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
562          SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value);
563          return;
564      }
565  
566      int set_it = CFEqual(value, kCFBooleanTrue);
567  
568      if (CFEqual(key, kSecReturnData))
569          mask = kSecReturnDataMask;
570      else if (CFEqual(key, kSecReturnAttributes))
571          mask = kSecReturnAttributesMask;
572      else if (CFEqual(key, kSecReturnRef))
573          mask = kSecReturnRefMask;
574      else if (CFEqual(key, kSecReturnPersistentRef))
575          mask = kSecReturnPersistentRefMask;
576      else {
577          SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key);
578          return;
579      }
580  
581      if ((q->q_return_type & mask) && !set_it) {
582          /* Clear out this bit (it's set so xor with the mask will clear it). */
583          q->q_return_type ^= mask;
584      } else if (!(q->q_return_type & mask) && set_it) {
585          /* Set this bit. */
586          q->q_return_type |= mask;
587      }
588  }
589  
590  /* AUDIT[securityd](done):
591   key (ok) is a caller provided, string starting with 'u'.
592   value (ok since q_use_item_list is unused) is a caller provided, non
593   NULL CFTypeRef.
594   */
595  static void query_add_use(const void *key, const void *value, Query *q)
596  {
597      // Gotta use a string literal because we just outlawed this symbol on iOS
598      if (CFEqual(key, CFSTR("u_ItemList"))) {
599          /* TODO: Add sanity checking when we start using this. */
600          q->q_use_item_list = value;
601      } else if (CFEqual(key, kSecUseTombstones)) {
602          if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
603              q->q_use_tomb = value;
604          } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
605              q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
606          } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
607              q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
608          } else {
609              SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
610              return;
611          }
612      } else if (CFEqual(key, kSecUseCredentialReference)) {
613          if (isData(value)) {
614              CFRetainAssign(q->q_use_cred_handle, value);
615          } else {
616              SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFData"), value, key);
617              return;
618          }
619      } else if (CFEqual(key, kSecUseAuthenticationUI)) {
620          if (isString(value)) {
621              q->q_skip_acl_items = CFEqualSafe(kSecUseAuthenticationUISkip, value);
622          } else {
623              SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFString"), value, key);
624              return;
625          }
626  #if TARGET_OS_IPHONE
627      } else if (CFEqual(key, kSecUseSystemKeychain)) {
628  #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
629          q->q_keybag = KEYBAG_DEVICE;
630  #endif
631          q->q_system_keychain = true;
632      } else if (CFEqual(key, kSecUseSyncBubbleKeychain)) {
633          if (isNumber(value) && CFNumberGetValue(value, kCFNumberSInt32Type, &q->q_sync_bubble) && q->q_sync_bubble > 0) {
634  #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
635              q->q_keybag = KEYBAG_DEVICE;
636  #endif
637          } else {
638              SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not valid uid"), value, key);
639              return;
640          }
641  #endif
642      } else {
643          SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key);
644          return;
645      }
646  }
647  
648  static void query_set_data(const void *value, Query *q) {
649      if (!isData(value)) {
650          SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value);
651      } else {
652          q->q_data = value;
653          if (q->q_item)
654              CFDictionarySetValue(q->q_item, kSecValueData, value);
655      }
656  }
657  
658  static void query_set_token_persistent_ref(Query *q, CFDictionaryRef token_persistent_ref) {
659      if (token_persistent_ref) {
660          query_add_attribute(kSecAttrTokenID, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenID), q);
661          CFRetainAssign(q->q_token_object_id, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenOID));
662      }
663  }
664  
665  /* AUDIT[securityd](done):
666   key (ok) is a caller provided, string starting with 'u'.
667   value (ok) is a caller provided, non NULL CFTypeRef.
668   */
669  static void query_add_value(const void *key, const void *value, Query *q)
670  {
671      if (CFEqual(key, kSecValueData)) {
672          query_set_data(value, q);
673  #ifdef NO_SERVER
674      } else if (CFEqual(key, kSecValueRef)) {
675          q->q_ref = value;
676          /* TODO: Add value type sanity checking. */
677  #endif
678      } else if (CFEqual(key, kSecValuePersistentRef)) {
679          CFStringRef c_name;
680          CFDictionaryRef token_persistent_ref = NULL;
681          if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id, &token_persistent_ref)) {
682              query_set_class(q, c_name, &q->q_error);
683              query_set_token_persistent_ref(q, token_persistent_ref);
684              CFReleaseNull(token_persistent_ref);
685          } else
686              SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value);
687      } else {
688          SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key);
689          return;
690      }
691  }
692  
693  /* AUDIT[securityd](done):
694   key (ok) is a caller provided, unchecked.
695   value (ok) is a caller provided, unchecked.
696   */
697  static void query_update_applier(const void *key, const void *value,
698                                   void *context)
699  {
700      Query *q = (Query *)context;
701      /* If something went wrong there is no point processing any more args. */
702      if (q->q_error)
703          return;
704  
705      /* Make sure we have a string key. */
706      if (!isString(key)) {
707          SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key);
708          return;
709      }
710  
711      if (!value) {
712          SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key);
713          return;
714      }
715  
716      if (CFEqual(key, CFSTR("musr"))) {
717          secnotice("item", "update_applier: refusing to update musr");
718          return;
719      }
720  
721      if (CFEqual(key, kSecValueData)) {
722          query_set_data(value, q);
723      } else {
724          query_add_attribute(key, value, q);
725      }
726  }
727  
728  /* AUDIT[securityd](done):
729   key (ok) is a caller provided, unchecked.
730   value (ok) is a caller provided, unchecked.
731   */
732  static void query_applier(const void *key, const void *value, void *context)
733  {
734      Query *q = (Query *)context;
735      /* If something went wrong there is no point processing any more args. */
736      if (q->q_error)
737          return;
738  
739      /* Make sure we have a key. */
740      if (!key) {
741          SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key"));
742          return;
743      }
744  
745      /* Make sure we have a value. */
746      if (!value) {
747          SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key);
748          return;
749      }
750  
751      /* Figure out what type of key we are dealing with. */
752      CFTypeID key_id = CFGetTypeID(key);
753      if (key_id == CFStringGetTypeID()) {
754          CFIndex key_len = CFStringGetLength(key);
755          /* String keys can be different things.  The subtype is determined by:
756           length 4 strings are all attributes.  Otherwise the first char
757           determines the type:
758           c: class must be kSecClass
759           m: match like kSecMatchPolicy
760           r: return like kSecReturnData
761           u: use keys
762           v: value
763           f: callbacks (ignored by the query applier)
764           */
765          if (key_len == 4) {
766              /* attributes */
767              query_add_attribute(key, value, q);
768          } else if (key_len > 1) {
769              // We added a database column named 'persistref', which is returned as an attribute but doesn't comply with
770              // these matching rules. skip it for now, since it isn't filled in anyway.
771              if(CFEqualSafe(key, CFSTR("persistref"))) {
772                  return;
773              }
774  
775              UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
776              switch (k_first_char)
777              {
778                  case 'c': /* class */
779                      query_add_class(key, value, q);
780                      break;
781                  case 'm': /* match */
782                      query_add_match(key, value, q);
783                      break;
784                  case 'r': /* return */
785                      query_add_return(key, value, q);
786                      break;
787                  case 'u': /* use */
788                      query_add_use(key, value, q);
789                      break;
790                  case 'v': /* value */
791                      query_add_value(key, value, q);
792                      break;
793                  case 'f':
794                      break;
795                  default:
796                      SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key);
797                      break;
798              }
799          } else {
800              SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key);
801          }
802      } else if (key_id == CFNumberGetTypeID()) {
803          /* Numeric keys are always (extended) attributes. */
804          /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
805          query_add_attribute(key, value, q);
806      } else {
807          /* We only support string and number type keys. */
808          SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key);
809      }
810  }
811  
812  static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
813      /* apsd are always dku. */
814      if (CFEqual(agrp, CFSTR("com.apple.apsd"))) {
815          return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate;
816      }
817      /* All other certs or in the apple agrp is dk. */
818      if (q->q_class == cert_class()) {
819          /* third party certs are always dk. */
820          return kSecAttrAccessibleAlwaysPrivate;
821      }
822      /* The rest defaults to ak. */
823      return kSecAttrAccessibleWhenUnlocked;
824  }
825  
826  void query_ensure_access_control(Query *q, CFStringRef agrp) {
827      if (q->q_access_control == 0) {
828          CFStringRef accessible = query_infer_keyclass(q, agrp);
829          query_add_attribute(kSecAttrAccessible, accessible, q);
830      }
831  }
832  
833  bool query_error(Query *q, CFErrorRef *error) {
834      CFErrorRef tmp = q->q_error;
835      q->q_error = NULL;
836      return SecErrorPropagate(tmp, error);
837  }
838  
839  bool query_destroy(Query *q, CFErrorRef *error) {
840      bool ok = query_error(q, error);
841      CFIndex ix, attr_count = query_attr_count(q);
842      for (ix = 0; ix < attr_count; ++ix) {
843          CFReleaseSafe(query_attr_at(q, ix).value);
844      }
845      CFReleaseSafe(q->q_item);
846      CFReleaseSafe(q->q_musrView);
847      CFReleaseSafe(q->q_primary_key_digest);
848      CFReleaseSafe(q->q_match_issuer);
849      CFReleaseSafe(q->q_access_control);
850      CFReleaseSafe(q->q_use_cred_handle);
851      CFReleaseSafe(q->q_caller_access_groups);
852      CFReleaseSafe(q->q_match_policy);
853      CFReleaseSafe(q->q_match_valid_on_date);
854      CFReleaseSafe(q->q_match_trusted_only);
855      CFReleaseSafe(q->q_token_object_id);
856  
857      free(q);
858      return ok;
859  }
860  
861  bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
862      if (ok && !q->q_error && (q->q_sync_changed || (q->q_changed && !SecMUSRIsSingleUserView(q->q_musrView)))) {
863          SecKeychainChanged();
864      }
865      return query_destroy(q, error) && ok;
866  }
867  
868  /* Allocate and initialize a Query object for query. */
869  Query *query_create(const SecDbClass *qclass,
870                      CFDataRef musr,
871                      CFDictionaryRef query,
872                      SecurityClient* client,
873                      CFErrorRef *error)
874  {
875      if (!qclass) {
876          if (error && !*error)
877              SecError(errSecItemClassMissing, error, CFSTR("Missing class"));
878          return NULL;
879      }
880  
881      if (musr == NULL)
882          musr = SecMUSRGetSingleUserKeychainUUID();
883  
884      /* Number of pairs we need is the number of attributes in this class
885       plus the number of keys in the dictionary, minus one for each key in
886       the dictionary that is a regular attribute. */
887      CFIndex key_count = SecDbClassAttrCount(qclass);
888      if (key_count == 0) {
889          // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
890          key_count = SecDbClassAttrCount(cert_class()) + SecDbClassAttrCount(keys_class());
891      }
892  
893      if (query) {
894          key_count += CFDictionaryGetCount(query);
895          SecDbForEachAttr(qclass, attr) {
896              if (CFDictionaryContainsKey(query, attr->name))
897                  --key_count;
898          }
899      }
900  
901      if (key_count > QUERY_KEY_LIMIT) {
902          if (error && !*error)
903          {
904              secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT);
905              SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit"));
906          }
907          return NULL;
908      }
909  
910      Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
911      if (q == NULL) {
912          if (error && !*error)
913              SecError(errSecAllocate, error, CFSTR("Out of memory"));
914          return NULL;
915      }
916  
917      q->q_pairs_count = key_count;
918      q->q_musrView = (CFDataRef)CFRetain(musr);
919      q->q_uuid_from_primary_key = false;
920      q->q_keybag = KEYBAG_DEVICE;
921      q->q_class = qclass;
922      q->q_match_begin = q->q_match_end = key_count;
923      q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
924  
925      if (client) {
926          // If not, don't do anything. Parent apps, schema migration, etc. all need access to all items, clip or no
927          if (client->isAppClip) {
928              secdebug("query", "Client is app clip, adding restriction to query attribute");
929              CFDictionaryAddValue(q->q_item, kSecAttrAppClipItem, kCFBooleanTrue);
930          }
931      } else {
932          secdebug("query", "no client information specified so not tweaking query attributes");
933      }
934  
935      return q;
936  }
937  
938  /* Parse query for a Query object q. */
939  static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
940                                       CFDictionaryApplierFunction applier,
941                                       CFErrorRef *error) {
942      CFDictionaryApplyFunction(query, applier, q);
943      return query_error(q, error);
944  }
945  
946  /* Parse query for a Query object q. */
947  static bool query_parse(Query *q, CFDictionaryRef query,
948                          CFErrorRef *error) {
949      return query_parse_with_applier(q, query, query_applier, error);
950  }
951  
952  /* Parse query for a Query object q. */
953  bool query_update_parse(Query *q, CFDictionaryRef update,
954                                 CFErrorRef *error) {
955      return query_parse_with_applier(q, update, query_update_applier, error);
956  }
957  
958  Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, SecurityClient* client, CFErrorRef *error) {
959      Query *q;
960      q = query_create(query_get_class(query, error), musr, query, client, error);
961      if (q) {
962          q->q_limit = limit;
963          if (!query_parse(q, query, error)) {
964              query_destroy(q, error);
965              return NULL;
966          }
967          if (!q->q_sync && !q->q_row_id && !q->q_token_object_id) {
968              /* query did not specify a kSecAttrSynchronizable attribute,
969               * and did not contain a persistent reference. */
970              query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q);
971          }
972      }
973      return q;
974  }
975  
976  
977  void
978  query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups) {
979      CFRetainAssign(q->q_caller_access_groups, caller_access_groups);
980  }
981  
982  void
983  query_set_policy(Query *q, SecPolicyRef policy) {
984      CFRetainAssign(q->q_match_policy, policy);
985  }
986  
987  void query_set_valid_on_date(Query *q, CFDateRef date) {
988      CFRetainAssign(q->q_match_valid_on_date, date);
989  }
990  
991  void query_set_trusted_only(Query *q, CFBooleanRef trusted_only) {
992      CFRetainAssign(q->q_match_trusted_only, trusted_only);
993  }