]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecDbQuery.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / sec / securityd / 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 <securityd/SecDbQuery.h>
32
33 #include <securityd/SecItemDb.h>
34 #include <securityd/SecItemSchema.h>
35 #include <securityd/SecItemServer.h>
36 #include <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/SecPolicyInternal.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 0
198 // TODO Iterate kc_db_classes and look for name == class->name.
199 // Or get clever and switch on first letter of class name and compare to verify
200 static const void *kc_db_classes[] = {
201 &genp_class,
202 &inet_class,
203 &cert_class,
204 &keys_class,
205 &identity_class
206 };
207 #endif
208 if (CFEqual(name, kSecClassGenericPassword))
209 return &genp_class;
210 else if (CFEqual(name, kSecClassInternetPassword))
211 return &inet_class;
212 else if (CFEqual(name, kSecClassCertificate))
213 return &cert_class;
214 else if (CFEqual(name, kSecClassKey))
215 return &keys_class;
216 else if (CFEqual(name, kSecClassIdentity))
217 return &identity_class;
218 }
219 return NULL;
220 }
221
222 static void query_set_access_control(Query *q, SecAccessControlRef access_control) {
223 if (q->q_access_control) {
224 if (!CFEqual(q->q_access_control, access_control)) {
225 SecError(errSecItemIllegalQuery, &q->q_error, CFSTR("conflicting kSecAccess and kSecAccessControl attributes"));
226 }
227 } else {
228 /* Store access control virtual attribute. */
229 q->q_access_control = (SecAccessControlRef)CFRetain(access_control);
230
231 /* Also set legacy access attribute. */
232 CFTypeRef protection = SecAccessControlGetProtection(q->q_access_control);
233 if (!protection) {
234 SecError(errSecParam, &q->q_error, CFSTR("kSecAccessControl missing protection"));
235 return;
236 }
237 CFDictionarySetValue(q->q_item, kSecAttrAccessible, protection);
238 }
239 }
240
241 /* AUDIT[securityd](done):
242 key (ok) is a caller provided, string or number of length 4.
243 value (ok) is a caller provided, non NULL CFTypeRef.
244 */
245 void query_add_attribute_with_desc(const SecDbAttr *desc, const void *value, Query *q)
246 {
247 if (CFEqual(desc->name, kSecAttrSynchronizable)) {
248 q->q_sync = true;
249 if (CFEqual(value, kSecAttrSynchronizableAny))
250 return; /* skip the attribute so it isn't part of the search */
251 }
252
253 CFTypeRef attr = NULL;
254 switch (desc->kind) {
255 case kSecDbDataAttr:
256 attr = copyData(value);
257 break;
258 case kSecDbBlobAttr:
259 case kSecDbAccessControlAttr:
260 attr = copyBlob(value);
261 break;
262 case kSecDbDateAttr:
263 case kSecDbCreationDateAttr:
264 case kSecDbModificationDateAttr:
265 attr = copyDate(value);
266 break;
267 case kSecDbNumberAttr:
268 case kSecDbSyncAttr:
269 case kSecDbTombAttr:
270 attr = copyNumber(value);
271 break;
272 case kSecDbAccessAttr:
273 case kSecDbStringAttr:
274 attr = copyString(value);
275 break;
276 case kSecDbSHA1Attr:
277 attr = copySHA1(value);
278 break;
279 case kSecDbRowIdAttr:
280 case kSecDbPrimaryKeyAttr:
281 case kSecDbEncryptedDataAttr:
282 case kSecDbUTombAttr:
283 break;
284 case kSecDbUUIDAttr:
285 attr = copyUUID(value);
286 break;
287 }
288
289 if (!attr) {
290 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("attribute %@: value: %@ failed to convert"), desc->name, value);
291 return;
292 }
293
294 /* Store plaintext attr data in q_item unless it's a kSecDbSHA1Attr. */
295 if (q->q_item && desc->kind != kSecDbSHA1Attr) {
296 CFDictionarySetValue(q->q_item, desc->name, attr);
297 }
298
299 /* Convert attr to (sha1) digest if requested. */
300 if (desc->flags & kSecDbSHA1ValueInFlag) {
301 CFDataRef data = copyData(attr);
302 CFRelease(attr);
303 if (!data) {
304 SecError(errSecInternal, &q->q_error, CFSTR("failed to get attribute %@ data"), desc->name);
305 return;
306 }
307
308 CFMutableDataRef digest = CFDataCreateMutable(0, CC_SHA1_DIGEST_LENGTH);
309 CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH);
310 /* 64 bits cast: worst case is we generate the wrong hash */
311 assert((unsigned long)CFDataGetLength(data)<UINT32_MAX); /* Debug check. Correct as long as CFIndex is long */
312 CCDigest(kCCDigestSHA1, CFDataGetBytePtr(data), (CC_LONG)CFDataGetLength(data),
313 CFDataGetMutableBytePtr(digest));
314 CFRelease(data);
315 attr = digest;
316 }
317
318 if (desc->kind != kSecDbAccessControlAttr) {
319 /* Record the new attr key, value in q_pairs. */
320 q->q_pairs[q->q_attr_end].key = desc->name;
321 q->q_pairs[q->q_attr_end++].value = attr;
322 } else {
323 CFReleaseSafe(attr);
324 }
325 }
326
327 void query_add_attribute(const void *key, const void *value, Query *q)
328 {
329 const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
330 if (desc) {
331 query_add_attribute_with_desc(desc, value, q);
332
333 if (desc->kind == kSecDbAccessControlAttr) {
334 CFDataRef attr = (CFDataRef)CFDictionaryGetValue(q->q_item, desc->name);
335 if (attr) {
336 SecAccessControlRef access_control = SecAccessControlCreateFromData(kCFAllocatorDefault, attr, &q->q_error);
337 if (access_control) {
338 query_set_access_control(q, access_control);
339 CFRelease(access_control);
340 }
341 }
342 }
343
344 if (desc->kind == kSecDbAccessAttr) {
345 SecAccessControlRef access_control = SecAccessControlCreate(kCFAllocatorDefault, &q->q_error);
346 if (access_control) {
347 CFStringRef attr = (CFStringRef)CFDictionaryGetValue(q->q_item, desc->name);
348 if (attr) {
349 if (SecAccessControlSetProtection(access_control, attr, &q->q_error))
350 query_set_access_control(q, access_control);
351 }
352 CFRelease(access_control);
353 }
354 }
355 }
356 }
357
358 void query_add_or_attribute(const void *key, const void *value, Query *q)
359 {
360 const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
361 if (desc) {
362 CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name);
363 CFMutableArrayRef array = NULL;
364 if (oldValue) {
365 if (isArray(oldValue)) {
366 array = (CFMutableArrayRef)CFRetain(oldValue);
367 } else {
368 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
369 CFArrayAppendValue(array, oldValue);
370 }
371 CFDictionaryRemoveValue(q->q_item, desc->name);
372 } else {
373 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
374 }
375 if (array) {
376 query_add_attribute_with_desc(desc, value, q);
377 CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name);
378 CFArrayAppendValue(array, newValue);
379 CFDictionarySetValue(q->q_item, desc->name, array);
380 CFRelease(array);
381 }
382 }
383 }
384
385 void query_add_not_attribute(const void *key, const void *value, Query *q)
386 {
387 const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
388 if (desc) {
389 CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name);
390 CFMutableArrayRef array = NULL;
391 if (oldValue) {
392 if (isArray(oldValue)) {
393 array = (CFMutableArrayRef)CFRetain(oldValue);
394 } else {
395 // This should never run, as we shouldn't be turning a attr = value into a attr not in (value, value2)
396 secerror("negating %@ = %@ in query", desc->name, oldValue);
397 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
398 CFArrayAppendValue(array, kCFNull);
399 CFArrayAppendValue(array, oldValue);
400 }
401 CFDictionaryRemoveValue(q->q_item, desc->name);
402 } else {
403 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
404 CFArrayAppendValue(array, kCFNull);
405 }
406 if (array) {
407 query_add_attribute_with_desc(desc, value, q);
408 CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name);
409 CFArrayAppendValue(array, newValue);
410 CFDictionarySetValue(q->q_item, desc->name, array);
411 CFRelease(array);
412 }
413 }
414 }
415
416
417 /* AUDIT[securityd](done):
418 key (ok) is a caller provided, string starting with 'm'.
419 value (ok) is a caller provided, non NULL CFTypeRef.
420 */
421 static void query_add_match(const void *key, const void *value, Query *q)
422 {
423 /* Record the match key, value in q_pairs. */
424 --(q->q_match_begin);
425 q->q_pairs[q->q_match_begin].key = key;
426 q->q_pairs[q->q_match_begin].value = value;
427
428 if (CFEqual(kSecMatchLimit, key)) {
429 /* Figure out what the value for kSecMatchLimit is if specified. */
430 if (CFGetTypeID(value) == CFNumberGetTypeID()) {
431 if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
432 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value);
433 } else if (CFEqual(kSecMatchLimitAll, value)) {
434 q->q_limit = kSecMatchUnlimited;
435 } else if (CFEqual(kSecMatchLimitOne, value)) {
436 q->q_limit = 1;
437 } else {
438 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value);
439 }
440 } else if (CFEqual(kSecMatchIssuers, key) &&
441 (CFGetTypeID(value) == CFArrayGetTypeID()))
442 {
443 CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
444 if (canonical_issuers) {
445 CFIndex i, count = CFArrayGetCount(value);
446 for (i = 0; i < count; i++) {
447 CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i);
448 CFDataRef issuer_canonical = NULL;
449 if (CFDataGetTypeID() == CFGetTypeID(issuer_data))
450 issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data);
451 if (issuer_canonical) {
452 CFArrayAppendValue(canonical_issuers, issuer_canonical);
453 CFRelease(issuer_canonical);
454 }
455 }
456
457 if (CFArrayGetCount(canonical_issuers) > 0) {
458 q->q_match_issuer = canonical_issuers;
459 } else
460 CFRelease(canonical_issuers);
461 }
462 } else if (CFEqual(kSecMatchPolicy, key)) {
463 if (CFGetTypeID(value) != CFArrayGetTypeID()) {
464 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchPolicy attribute"));
465 return;
466 }
467 xpc_object_t policiesArrayXPC = _CFXPCCreateXPCObjectFromCFObject(value);
468 if (!policiesArrayXPC) {
469 SecError(errSecParam, &q->q_error, CFSTR("unsupported kSecMatchPolicy object in query"));
470 return;
471 }
472
473 CFArrayRef policiesArray = SecPolicyXPCArrayCopyArray(policiesArrayXPC, &q->q_error);
474 xpc_release(policiesArrayXPC);
475 if (!policiesArray)
476 return;
477
478 if (CFArrayGetCount(policiesArray) != 1 || CFGetTypeID(CFArrayGetValueAtIndex(policiesArray, 0)) != SecPolicyGetTypeID()) {
479 CFRelease(policiesArray);
480 SecError(errSecParam, &q->q_error, CFSTR("unsupported array of policies"));
481 return;
482 }
483
484 query_set_policy(q, (SecPolicyRef)CFArrayGetValueAtIndex(policiesArray, 0));
485 CFRelease(policiesArray);
486 } else if (CFEqual(kSecMatchValidOnDate, key)) {
487 if (CFGetTypeID(value) == CFNullGetTypeID()) {
488 CFDateRef date = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
489 query_set_valid_on_date(q, date);
490 CFRelease(date);
491 } else if (CFGetTypeID(value) == CFDateGetTypeID()) {
492 query_set_valid_on_date(q, value);
493 } else {
494 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchValidOnDate attribute"));
495 return;
496 }
497 } else if (CFEqual(kSecMatchTrustedOnly, key)) {
498 if ((CFGetTypeID(value) == CFBooleanGetTypeID())) {
499 query_set_trusted_only(q, value);
500 } else {
501 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchTrustedOnly attribute"));
502 return;
503 }
504 }
505 }
506
507 static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) {
508 const SecDbClass *value;
509 if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
510 (value = kc_class_with_name(c_name)) &&
511 (q->q_class == 0 || q->q_class == value)) {
512 q->q_class = value;
513 return true;
514 }
515
516 if (error && !*error)
517 SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name);
518
519
520 return false;
521 }
522
523 static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) {
524 CFStringRef c_name = NULL;
525 const void *value = CFDictionaryGetValue(query, kSecClass);
526 if (isString(value)) {
527 c_name = value;
528 } else {
529 value = CFDictionaryGetValue(query, kSecValuePersistentRef);
530 if (isData(value)) {
531 CFDataRef pref = value;
532 _SecItemParsePersistentRef(pref, &c_name, 0);
533 }
534 }
535
536 if (c_name && (value = kc_class_with_name(c_name))) {
537 return value;
538 } else {
539 if (c_name)
540 SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name);
541 else
542 SecError(errSecItemClassMissing, error, CFSTR("query missing class name"));
543 return NULL;
544 }
545 }
546
547 /* AUDIT[securityd](done):
548 key (ok) is a caller provided, string starting with 'c'.
549 value (ok) is a caller provided, non NULL CFTypeRef.
550 */
551 static void query_add_class(const void *key, const void *value, Query *q)
552 {
553 if (CFEqual(key, kSecClass)) {
554 query_set_class(q, value, &q->q_error);
555 } else {
556 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass);
557 }
558 }
559
560 /* AUDIT[securityd](done):
561 key (ok) is a caller provided, string starting with 'r'.
562 value (ok) is a caller provided, non NULL CFTypeRef.
563 */
564 static void query_add_return(const void *key, const void *value, Query *q)
565 {
566 ReturnTypeMask mask;
567 if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
568 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value);
569 return;
570 }
571
572 int set_it = CFEqual(value, kCFBooleanTrue);
573
574 if (CFEqual(key, kSecReturnData))
575 mask = kSecReturnDataMask;
576 else if (CFEqual(key, kSecReturnAttributes))
577 mask = kSecReturnAttributesMask;
578 else if (CFEqual(key, kSecReturnRef))
579 mask = kSecReturnRefMask;
580 else if (CFEqual(key, kSecReturnPersistentRef))
581 mask = kSecReturnPersistentRefMask;
582 else {
583 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key);
584 return;
585 }
586
587 if ((q->q_return_type & mask) && !set_it) {
588 /* Clear out this bit (it's set so xor with the mask will clear it). */
589 q->q_return_type ^= mask;
590 } else if (!(q->q_return_type & mask) && set_it) {
591 /* Set this bit. */
592 q->q_return_type |= mask;
593 }
594 }
595
596 /* AUDIT[securityd](done):
597 key (ok) is a caller provided, string starting with 'u'.
598 value (ok since q_use_item_list is unused) is a caller provided, non
599 NULL CFTypeRef.
600 */
601 static void query_add_use(const void *key, const void *value, Query *q)
602 {
603 if (CFEqual(key, kSecUseItemList)) {
604 /* TODO: Add sanity checking when we start using this. */
605 q->q_use_item_list = value;
606 } else if (CFEqual(key, kSecUseTombstones)) {
607 if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
608 q->q_use_tomb = value;
609 } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
610 q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
611 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
612 q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
613 } else {
614 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
615 return;
616 }
617 } else if (CFEqual(key, kSecUseCredentialReference)) {
618 if (isData(value)) {
619 CFRetainAssign(q->q_use_cred_handle, value);
620 } else {
621 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFData"), value, key);
622 return;
623 }
624 } else if (CFEqual(key, kSecUseAuthenticationUI)) {
625 if (isString(value)) {
626 q->q_skip_acl_items = CFEqualSafe(kSecUseAuthenticationUISkip, value);
627 } else {
628 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFString"), value, key);
629 return;
630 }
631 #if TARGET_OS_IPHONE
632 } else if (CFEqual(key, kSecUseSystemKeychain)) {
633 #if TARGET_OS_EMBEDDED
634 q->q_keybag = KEYBAG_DEVICE;
635 #endif
636 q->q_system_keychain = true;
637 } else if (CFEqual(key, kSecUseSyncBubbleKeychain)) {
638 if (isNumber(value) && CFNumberGetValue(value, kCFNumberSInt32Type, &q->q_sync_bubble) && q->q_sync_bubble > 0) {
639 #if TARGET_OS_EMBEDDED
640 q->q_keybag = KEYBAG_DEVICE;
641 #endif
642 } else {
643 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not valid uid"), value, key);
644 return;
645 }
646 #endif
647 } else {
648 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key);
649 return;
650 }
651 }
652
653 static void query_set_data(const void *value, Query *q) {
654 if (!isData(value)) {
655 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value);
656 } else {
657 q->q_data = value;
658 if (q->q_item)
659 CFDictionarySetValue(q->q_item, kSecValueData, value);
660 }
661 }
662
663 /* AUDIT[securityd](done):
664 key (ok) is a caller provided, string starting with 'u'.
665 value (ok) is a caller provided, non NULL CFTypeRef.
666 */
667 static void query_add_value(const void *key, const void *value, Query *q)
668 {
669 if (CFEqual(key, kSecValueData)) {
670 query_set_data(value, q);
671 #ifdef NO_SERVER
672 } else if (CFEqual(key, kSecValueRef)) {
673 q->q_ref = value;
674 /* TODO: Add value type sanity checking. */
675 #endif
676 } else if (CFEqual(key, kSecValuePersistentRef)) {
677 CFStringRef c_name;
678 if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id))
679 query_set_class(q, c_name, &q->q_error);
680 else
681 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value);
682 } else {
683 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key);
684 return;
685 }
686 }
687
688 /* AUDIT[securityd](done):
689 key (ok) is a caller provided, unchecked.
690 value (ok) is a caller provided, unchecked.
691 */
692 static void query_update_applier(const void *key, const void *value,
693 void *context)
694 {
695 Query *q = (Query *)context;
696 /* If something went wrong there is no point processing any more args. */
697 if (q->q_error)
698 return;
699
700 /* Make sure we have a string key. */
701 if (!isString(key)) {
702 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key);
703 return;
704 }
705
706 if (!value) {
707 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key);
708 return;
709 }
710
711 if (CFEqual(key, CFSTR("musr"))) {
712 secnotice("item", "update_applier: refusing to update musr");
713 return;
714 }
715
716 if (CFEqual(key, kSecValueData)) {
717 query_set_data(value, q);
718 } else {
719 query_add_attribute(key, value, q);
720 }
721 }
722
723 /* AUDIT[securityd](done):
724 key (ok) is a caller provided, unchecked.
725 value (ok) is a caller provided, unchecked.
726 */
727 static void query_applier(const void *key, const void *value, void *context)
728 {
729 Query *q = (Query *)context;
730 /* If something went wrong there is no point processing any more args. */
731 if (q->q_error)
732 return;
733
734 /* Make sure we have a key. */
735 if (!key) {
736 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key"));
737 return;
738 }
739
740 /* Make sure we have a value. */
741 if (!value) {
742 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key);
743 return;
744 }
745
746 /* Figure out what type of key we are dealing with. */
747 CFTypeID key_id = CFGetTypeID(key);
748 if (key_id == CFStringGetTypeID()) {
749 CFIndex key_len = CFStringGetLength(key);
750 /* String keys can be different things. The subtype is determined by:
751 length 4 strings are all attributes. Otherwise the first char
752 determines the type:
753 c: class must be kSecClass
754 m: match like kSecMatchPolicy
755 r: return like kSecReturnData
756 u: use keys
757 v: value
758 */
759 if (key_len == 4) {
760 /* attributes */
761 query_add_attribute(key, value, q);
762 } else if (key_len > 1) {
763 UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
764 switch (k_first_char)
765 {
766 case 'c': /* class */
767 query_add_class(key, value, q);
768 break;
769 case 'm': /* match */
770 query_add_match(key, value, q);
771 break;
772 case 'r': /* return */
773 query_add_return(key, value, q);
774 break;
775 case 'u': /* use */
776 query_add_use(key, value, q);
777 break;
778 case 'v': /* value */
779 query_add_value(key, value, q);
780 break;
781 default:
782 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key);
783 break;
784 }
785 } else {
786 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key);
787 }
788 } else if (key_id == CFNumberGetTypeID()) {
789 /* Numeric keys are always (extended) attributes. */
790 /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
791 query_add_attribute(key, value, q);
792 } else {
793 /* We only support string and number type keys. */
794 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key);
795 }
796 }
797
798 static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
799 /* apsd are always dku. */
800 if (CFEqual(agrp, CFSTR("com.apple.apsd"))) {
801 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate;
802 }
803 /* All other certs or in the apple agrp is dk. */
804 if (q->q_class == &cert_class) {
805 /* third party certs are always dk. */
806 return kSecAttrAccessibleAlwaysPrivate;
807 }
808 /* The rest defaults to ak. */
809 return kSecAttrAccessibleWhenUnlocked;
810 }
811
812 void query_ensure_access_control(Query *q, CFStringRef agrp) {
813 if (q->q_access_control == 0) {
814 CFStringRef accessible = query_infer_keyclass(q, agrp);
815 query_add_attribute(kSecAttrAccessible, accessible, q);
816 }
817 }
818
819 bool query_error(Query *q, CFErrorRef *error) {
820 CFErrorRef tmp = q->q_error;
821 q->q_error = NULL;
822 return SecErrorPropagate(tmp, error);
823 }
824
825 bool query_destroy(Query *q, CFErrorRef *error) {
826 bool ok = query_error(q, error);
827 CFIndex ix, attr_count = query_attr_count(q);
828 for (ix = 0; ix < attr_count; ++ix) {
829 CFReleaseSafe(query_attr_at(q, ix).value);
830 }
831 CFReleaseSafe(q->q_item);
832 CFReleaseSafe(q->q_musrView);
833 CFReleaseSafe(q->q_primary_key_digest);
834 CFReleaseSafe(q->q_match_issuer);
835 CFReleaseSafe(q->q_access_control);
836 CFReleaseSafe(q->q_use_cred_handle);
837 CFReleaseSafe(q->q_caller_access_groups);
838 CFReleaseSafe(q->q_match_policy);
839 CFReleaseSafe(q->q_match_valid_on_date);
840 CFReleaseSafe(q->q_match_trusted_only);
841
842 free(q);
843 return ok;
844 }
845
846 bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
847 if (ok && !q->q_error && (q->q_sync_changed || (q->q_changed && !SecMUSRIsSingleUserView(q->q_musrView)))) {
848 SecKeychainChanged();
849 }
850 return query_destroy(q, error) && ok;
851 }
852
853 /* Allocate and initialize a Query object for query. */
854 Query *query_create(const SecDbClass *qclass,
855 CFDataRef musr,
856 CFDictionaryRef query,
857 CFErrorRef *error)
858 {
859 if (!qclass) {
860 if (error && !*error)
861 SecError(errSecItemClassMissing, error, CFSTR("Missing class"));
862 return NULL;
863 }
864
865 if (musr == NULL)
866 musr = SecMUSRGetSingleUserKeychainUUID();
867
868 /* Number of pairs we need is the number of attributes in this class
869 plus the number of keys in the dictionary, minus one for each key in
870 the dictionary that is a regular attribute. */
871 CFIndex key_count = SecDbClassAttrCount(qclass);
872 if (key_count == 0) {
873 // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
874 key_count = SecDbClassAttrCount(&cert_class) + SecDbClassAttrCount(&keys_class);
875 }
876
877 if (query) {
878 key_count += CFDictionaryGetCount(query);
879 SecDbForEachAttr(qclass, attr) {
880 if (CFDictionaryContainsKey(query, attr->name))
881 --key_count;
882 }
883 }
884
885 if (key_count > QUERY_KEY_LIMIT) {
886 if (error && !*error)
887 {
888 secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT);
889 SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit"));
890 }
891 return NULL;
892 }
893
894 Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
895 if (q == NULL) {
896 if (error && !*error)
897 SecError(errSecAllocate, error, CFSTR("Out of memory"));
898 return NULL;
899 }
900
901 q->q_musrView = (CFDataRef)CFRetain(musr);
902 q->q_keybag = KEYBAG_DEVICE;
903 q->q_class = qclass;
904 q->q_match_begin = q->q_match_end = key_count;
905 q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
906
907 return q;
908 }
909
910 /* Parse query for a Query object q. */
911 static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
912 CFDictionaryApplierFunction applier,
913 CFErrorRef *error) {
914 CFDictionaryApplyFunction(query, applier, q);
915 return query_error(q, error);
916 }
917
918 /* Parse query for a Query object q. */
919 static bool query_parse(Query *q, CFDictionaryRef query,
920 CFErrorRef *error) {
921 return query_parse_with_applier(q, query, query_applier, error);
922 }
923
924 /* Parse query for a Query object q. */
925 bool query_update_parse(Query *q, CFDictionaryRef update,
926 CFErrorRef *error) {
927 return query_parse_with_applier(q, update, query_update_applier, error);
928 }
929
930 Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error) {
931 Query *q;
932 q = query_create(query_get_class(query, error), musr, query, error);
933 if (q) {
934 q->q_limit = limit;
935 if (!query_parse(q, query, error)) {
936 query_destroy(q, error);
937 return NULL;
938 }
939 if (!q->q_sync && !q->q_row_id) {
940 /* query did not specify a kSecAttrSynchronizable attribute,
941 * and did not contain a persistent reference. */
942 query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q);
943 }
944 }
945 return q;
946 }
947
948
949 void
950 query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups) {
951 CFRetainAssign(q->q_caller_access_groups, caller_access_groups);
952 }
953
954 void
955 query_set_policy(Query *q, SecPolicyRef policy) {
956 CFRetainAssign(q->q_match_policy, policy);
957 }
958
959 void query_set_valid_on_date(Query *q, CFDateRef date) {
960 CFRetainAssign(q->q_match_valid_on_date, date);
961 }
962
963 void query_set_trusted_only(Query *q, CFBooleanRef trusted_only) {
964 CFRetainAssign(q->q_match_trusted_only, trusted_only);
965 }