]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecDbQuery.c
Security-58286.41.2.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 (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
416 /* AUDIT[securityd](done):
417 key (ok) is a caller provided, string starting with 'm'.
418 value (ok) is a caller provided, non NULL CFTypeRef.
419 */
420 static void query_add_match(const void *key, const void *value, Query *q)
421 {
422 /* Record the match key, value in q_pairs. */
423 --(q->q_match_begin);
424 q->q_pairs[q->q_match_begin].key = key;
425 q->q_pairs[q->q_match_begin].value = value;
426
427 if (CFEqual(kSecMatchLimit, key)) {
428 /* Figure out what the value for kSecMatchLimit is if specified. */
429 if (CFGetTypeID(value) == CFNumberGetTypeID()) {
430 if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
431 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value);
432 } else if (CFEqual(kSecMatchLimitAll, value)) {
433 q->q_limit = kSecMatchUnlimited;
434 } else if (CFEqual(kSecMatchLimitOne, value)) {
435 q->q_limit = 1;
436 } else {
437 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value);
438 }
439 } else if (CFEqual(kSecMatchIssuers, key) &&
440 (CFGetTypeID(value) == CFArrayGetTypeID()))
441 {
442 CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
443 if (canonical_issuers) {
444 CFIndex i, count = CFArrayGetCount(value);
445 for (i = 0; i < count; i++) {
446 CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i);
447 CFDataRef issuer_canonical = NULL;
448 if (CFDataGetTypeID() == CFGetTypeID(issuer_data))
449 issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data);
450 if (issuer_canonical) {
451 CFArrayAppendValue(canonical_issuers, issuer_canonical);
452 CFRelease(issuer_canonical);
453 }
454 }
455
456 if (CFArrayGetCount(canonical_issuers) > 0) {
457 q->q_match_issuer = canonical_issuers;
458 } else
459 CFRelease(canonical_issuers);
460 }
461 } else if (CFEqual(kSecMatchPolicy, key)) {
462 if (CFGetTypeID(value) != CFArrayGetTypeID()) {
463 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchPolicy attribute"));
464 return;
465 }
466 xpc_object_t policiesArrayXPC = _CFXPCCreateXPCObjectFromCFObject(value);
467 if (!policiesArrayXPC) {
468 SecError(errSecParam, &q->q_error, CFSTR("unsupported kSecMatchPolicy object in query"));
469 return;
470 }
471
472 CFArrayRef policiesArray = SecPolicyXPCArrayCopyArray(policiesArrayXPC, &q->q_error);
473 xpc_release(policiesArrayXPC);
474 if (!policiesArray)
475 return;
476
477 if (CFArrayGetCount(policiesArray) != 1 || CFGetTypeID(CFArrayGetValueAtIndex(policiesArray, 0)) != SecPolicyGetTypeID()) {
478 CFRelease(policiesArray);
479 SecError(errSecParam, &q->q_error, CFSTR("unsupported array of policies"));
480 return;
481 }
482
483 query_set_policy(q, (SecPolicyRef)CFArrayGetValueAtIndex(policiesArray, 0));
484 CFRelease(policiesArray);
485 } else if (CFEqual(kSecMatchValidOnDate, key)) {
486 if (CFGetTypeID(value) == CFNullGetTypeID()) {
487 CFDateRef date = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
488 query_set_valid_on_date(q, date);
489 CFRelease(date);
490 } else if (CFGetTypeID(value) == CFDateGetTypeID()) {
491 query_set_valid_on_date(q, value);
492 } else {
493 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchValidOnDate attribute"));
494 return;
495 }
496 } else if (CFEqual(kSecMatchTrustedOnly, key)) {
497 if ((CFGetTypeID(value) == CFBooleanGetTypeID())) {
498 query_set_trusted_only(q, value);
499 } else {
500 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchTrustedOnly attribute"));
501 return;
502 }
503 }
504 }
505
506 static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) {
507 const SecDbClass *value;
508 if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
509 (value = kc_class_with_name(c_name)) &&
510 (q->q_class == 0 || q->q_class == value)) {
511 q->q_class = value;
512 return true;
513 }
514
515 if (error && !*error)
516 SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name);
517
518
519 return false;
520 }
521
522 static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) {
523 CFStringRef c_name = NULL;
524 const void *value = CFDictionaryGetValue(query, kSecClass);
525 if (isString(value)) {
526 c_name = value;
527 } else {
528 value = CFDictionaryGetValue(query, kSecValuePersistentRef);
529 if (isData(value)) {
530 CFDataRef pref = value;
531 _SecItemParsePersistentRef(pref, &c_name, NULL, NULL);
532 }
533 }
534
535 if (c_name && (value = kc_class_with_name(c_name))) {
536 return value;
537 } else {
538 if (c_name)
539 SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name);
540 else
541 SecError(errSecItemClassMissing, error, CFSTR("query missing class name"));
542 return NULL;
543 }
544 }
545
546 /* AUDIT[securityd](done):
547 key (ok) is a caller provided, string starting with 'c'.
548 value (ok) is a caller provided, non NULL CFTypeRef.
549 */
550 static void query_add_class(const void *key, const void *value, Query *q)
551 {
552 if (CFEqual(key, kSecClass)) {
553 query_set_class(q, value, &q->q_error);
554 } else {
555 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass);
556 }
557 }
558
559 /* AUDIT[securityd](done):
560 key (ok) is a caller provided, string starting with 'r'.
561 value (ok) is a caller provided, non NULL CFTypeRef.
562 */
563 static void query_add_return(const void *key, const void *value, Query *q)
564 {
565 ReturnTypeMask mask;
566 if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
567 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value);
568 return;
569 }
570
571 int set_it = CFEqual(value, kCFBooleanTrue);
572
573 if (CFEqual(key, kSecReturnData))
574 mask = kSecReturnDataMask;
575 else if (CFEqual(key, kSecReturnAttributes))
576 mask = kSecReturnAttributesMask;
577 else if (CFEqual(key, kSecReturnRef))
578 mask = kSecReturnRefMask;
579 else if (CFEqual(key, kSecReturnPersistentRef))
580 mask = kSecReturnPersistentRefMask;
581 else {
582 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key);
583 return;
584 }
585
586 if ((q->q_return_type & mask) && !set_it) {
587 /* Clear out this bit (it's set so xor with the mask will clear it). */
588 q->q_return_type ^= mask;
589 } else if (!(q->q_return_type & mask) && set_it) {
590 /* Set this bit. */
591 q->q_return_type |= mask;
592 }
593 }
594
595 /* AUDIT[securityd](done):
596 key (ok) is a caller provided, string starting with 'u'.
597 value (ok since q_use_item_list is unused) is a caller provided, non
598 NULL CFTypeRef.
599 */
600 static void query_add_use(const void *key, const void *value, Query *q)
601 {
602 if (CFEqual(key, kSecUseItemList)) {
603 /* TODO: Add sanity checking when we start using this. */
604 q->q_use_item_list = value;
605 } else if (CFEqual(key, kSecUseTombstones)) {
606 if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
607 q->q_use_tomb = value;
608 } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
609 q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
610 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
611 q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
612 } else {
613 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
614 return;
615 }
616 } else if (CFEqual(key, kSecUseCredentialReference)) {
617 if (isData(value)) {
618 CFRetainAssign(q->q_use_cred_handle, value);
619 } else {
620 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFData"), value, key);
621 return;
622 }
623 } else if (CFEqual(key, kSecUseAuthenticationUI)) {
624 if (isString(value)) {
625 q->q_skip_acl_items = CFEqualSafe(kSecUseAuthenticationUISkip, value);
626 } else {
627 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFString"), value, key);
628 return;
629 }
630 #if TARGET_OS_IPHONE
631 } else if (CFEqual(key, kSecUseSystemKeychain)) {
632 #if TARGET_OS_EMBEDDED
633 q->q_keybag = KEYBAG_DEVICE;
634 #endif
635 q->q_system_keychain = true;
636 } else if (CFEqual(key, kSecUseSyncBubbleKeychain)) {
637 if (isNumber(value) && CFNumberGetValue(value, kCFNumberSInt32Type, &q->q_sync_bubble) && q->q_sync_bubble > 0) {
638 #if TARGET_OS_EMBEDDED
639 q->q_keybag = KEYBAG_DEVICE;
640 #endif
641 } else {
642 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not valid uid"), value, key);
643 return;
644 }
645 #endif
646 } else {
647 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key);
648 return;
649 }
650 }
651
652 static void query_set_data(const void *value, Query *q) {
653 if (!isData(value)) {
654 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value);
655 } else {
656 q->q_data = value;
657 if (q->q_item)
658 CFDictionarySetValue(q->q_item, kSecValueData, value);
659 }
660 }
661
662 static void query_set_token_persistent_ref(Query *q, CFDictionaryRef token_persistent_ref) {
663 if (token_persistent_ref) {
664 query_add_attribute(kSecAttrTokenID, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenID), q);
665 CFRetainAssign(q->q_token_object_id, CFDictionaryGetValue(token_persistent_ref, kSecAttrTokenOID));
666 }
667 }
668
669 /* AUDIT[securityd](done):
670 key (ok) is a caller provided, string starting with 'u'.
671 value (ok) is a caller provided, non NULL CFTypeRef.
672 */
673 static void query_add_value(const void *key, const void *value, Query *q)
674 {
675 if (CFEqual(key, kSecValueData)) {
676 query_set_data(value, q);
677 #ifdef NO_SERVER
678 } else if (CFEqual(key, kSecValueRef)) {
679 q->q_ref = value;
680 /* TODO: Add value type sanity checking. */
681 #endif
682 } else if (CFEqual(key, kSecValuePersistentRef)) {
683 CFStringRef c_name;
684 CFDictionaryRef token_persistent_ref = NULL;
685 if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id, &token_persistent_ref)) {
686 query_set_class(q, c_name, &q->q_error);
687 query_set_token_persistent_ref(q, token_persistent_ref);
688 CFReleaseNull(token_persistent_ref);
689 } else
690 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_value: value %@ is not a valid persitent ref"), value);
691 } else {
692 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_value: unknown key %@"), key);
693 return;
694 }
695 }
696
697 /* AUDIT[securityd](done):
698 key (ok) is a caller provided, unchecked.
699 value (ok) is a caller provided, unchecked.
700 */
701 static void query_update_applier(const void *key, const void *value,
702 void *context)
703 {
704 Query *q = (Query *)context;
705 /* If something went wrong there is no point processing any more args. */
706 if (q->q_error)
707 return;
708
709 /* Make sure we have a string key. */
710 if (!isString(key)) {
711 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("update_applier: unknown key type %@"), key);
712 return;
713 }
714
715 if (!value) {
716 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("update_applier: key %@ has NULL value"), key);
717 return;
718 }
719
720 if (CFEqual(key, CFSTR("musr"))) {
721 secnotice("item", "update_applier: refusing to update musr");
722 return;
723 }
724
725 if (CFEqual(key, kSecValueData)) {
726 query_set_data(value, q);
727 } else {
728 query_add_attribute(key, value, q);
729 }
730 }
731
732 /* AUDIT[securityd](done):
733 key (ok) is a caller provided, unchecked.
734 value (ok) is a caller provided, unchecked.
735 */
736 static void query_applier(const void *key, const void *value, void *context)
737 {
738 Query *q = (Query *)context;
739 /* If something went wrong there is no point processing any more args. */
740 if (q->q_error)
741 return;
742
743 /* Make sure we have a key. */
744 if (!key) {
745 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: NULL key"));
746 return;
747 }
748
749 /* Make sure we have a value. */
750 if (!value) {
751 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("applier: key %@ has NULL value"), key);
752 return;
753 }
754
755 /* Figure out what type of key we are dealing with. */
756 CFTypeID key_id = CFGetTypeID(key);
757 if (key_id == CFStringGetTypeID()) {
758 CFIndex key_len = CFStringGetLength(key);
759 /* String keys can be different things. The subtype is determined by:
760 length 4 strings are all attributes. Otherwise the first char
761 determines the type:
762 c: class must be kSecClass
763 m: match like kSecMatchPolicy
764 r: return like kSecReturnData
765 u: use keys
766 v: value
767 f: callbacks (ignored by the query applier)
768 */
769 if (key_len == 4) {
770 /* attributes */
771 query_add_attribute(key, value, q);
772 } else if (key_len > 1) {
773 // We added a database column named 'persistref', which is returned as an attribute but doesn't comply with
774 // these matching rules. skip it for now, since it isn't filled in anyway.
775 if(CFEqualSafe(key, CFSTR("persistref"))) {
776 return;
777 }
778
779 UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
780 switch (k_first_char)
781 {
782 case 'c': /* class */
783 query_add_class(key, value, q);
784 break;
785 case 'm': /* match */
786 query_add_match(key, value, q);
787 break;
788 case 'r': /* return */
789 query_add_return(key, value, q);
790 break;
791 case 'u': /* use */
792 query_add_use(key, value, q);
793 break;
794 case 'v': /* value */
795 query_add_value(key, value, q);
796 break;
797 case 'f':
798 break;
799 default:
800 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key);
801 break;
802 }
803 } else {
804 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key);
805 }
806 } else if (key_id == CFNumberGetTypeID()) {
807 /* Numeric keys are always (extended) attributes. */
808 /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
809 query_add_attribute(key, value, q);
810 } else {
811 /* We only support string and number type keys. */
812 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key);
813 }
814 }
815
816 static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
817 /* apsd are always dku. */
818 if (CFEqual(agrp, CFSTR("com.apple.apsd"))) {
819 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate;
820 }
821 /* All other certs or in the apple agrp is dk. */
822 if (q->q_class == cert_class()) {
823 /* third party certs are always dk. */
824 return kSecAttrAccessibleAlwaysPrivate;
825 }
826 /* The rest defaults to ak. */
827 return kSecAttrAccessibleWhenUnlocked;
828 }
829
830 void query_ensure_access_control(Query *q, CFStringRef agrp) {
831 if (q->q_access_control == 0) {
832 CFStringRef accessible = query_infer_keyclass(q, agrp);
833 query_add_attribute(kSecAttrAccessible, accessible, q);
834 }
835 }
836
837 bool query_error(Query *q, CFErrorRef *error) {
838 CFErrorRef tmp = q->q_error;
839 q->q_error = NULL;
840 return SecErrorPropagate(tmp, error);
841 }
842
843 bool query_destroy(Query *q, CFErrorRef *error) {
844 bool ok = query_error(q, error);
845 CFIndex ix, attr_count = query_attr_count(q);
846 for (ix = 0; ix < attr_count; ++ix) {
847 CFReleaseSafe(query_attr_at(q, ix).value);
848 }
849 CFReleaseSafe(q->q_item);
850 CFReleaseSafe(q->q_musrView);
851 CFReleaseSafe(q->q_primary_key_digest);
852 CFReleaseSafe(q->q_match_issuer);
853 CFReleaseSafe(q->q_access_control);
854 CFReleaseSafe(q->q_use_cred_handle);
855 CFReleaseSafe(q->q_caller_access_groups);
856 CFReleaseSafe(q->q_match_policy);
857 CFReleaseSafe(q->q_match_valid_on_date);
858 CFReleaseSafe(q->q_match_trusted_only);
859 CFReleaseSafe(q->q_token_object_id);
860
861 free(q);
862 return ok;
863 }
864
865 bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
866 if (ok && !q->q_error && (q->q_sync_changed || (q->q_changed && !SecMUSRIsSingleUserView(q->q_musrView)))) {
867 SecKeychainChanged();
868 }
869 return query_destroy(q, error) && ok;
870 }
871
872 /* Allocate and initialize a Query object for query. */
873 Query *query_create(const SecDbClass *qclass,
874 CFDataRef musr,
875 CFDictionaryRef query,
876 CFErrorRef *error)
877 {
878 if (!qclass) {
879 if (error && !*error)
880 SecError(errSecItemClassMissing, error, CFSTR("Missing class"));
881 return NULL;
882 }
883
884 if (musr == NULL)
885 musr = SecMUSRGetSingleUserKeychainUUID();
886
887 /* Number of pairs we need is the number of attributes in this class
888 plus the number of keys in the dictionary, minus one for each key in
889 the dictionary that is a regular attribute. */
890 CFIndex key_count = SecDbClassAttrCount(qclass);
891 if (key_count == 0) {
892 // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
893 key_count = SecDbClassAttrCount(cert_class()) + SecDbClassAttrCount(keys_class());
894 }
895
896 if (query) {
897 key_count += CFDictionaryGetCount(query);
898 SecDbForEachAttr(qclass, attr) {
899 if (CFDictionaryContainsKey(query, attr->name))
900 --key_count;
901 }
902 }
903
904 if (key_count > QUERY_KEY_LIMIT) {
905 if (error && !*error)
906 {
907 secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT);
908 SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit"));
909 }
910 return NULL;
911 }
912
913 Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
914 if (q == NULL) {
915 if (error && !*error)
916 SecError(errSecAllocate, error, CFSTR("Out of memory"));
917 return NULL;
918 }
919
920 q->q_pairs_count = key_count;
921 q->q_musrView = (CFDataRef)CFRetain(musr);
922 q->q_uuid_from_primary_key = false;
923 q->q_keybag = KEYBAG_DEVICE;
924 q->q_class = qclass;
925 q->q_match_begin = q->q_match_end = key_count;
926 q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
927
928 return q;
929 }
930
931 /* Parse query for a Query object q. */
932 static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
933 CFDictionaryApplierFunction applier,
934 CFErrorRef *error) {
935 CFDictionaryApplyFunction(query, applier, q);
936 return query_error(q, error);
937 }
938
939 /* Parse query for a Query object q. */
940 static bool query_parse(Query *q, CFDictionaryRef query,
941 CFErrorRef *error) {
942 return query_parse_with_applier(q, query, query_applier, error);
943 }
944
945 /* Parse query for a Query object q. */
946 bool query_update_parse(Query *q, CFDictionaryRef update,
947 CFErrorRef *error) {
948 return query_parse_with_applier(q, update, query_update_applier, error);
949 }
950
951 Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error) {
952 Query *q;
953 q = query_create(query_get_class(query, error), musr, query, error);
954 if (q) {
955 q->q_limit = limit;
956 if (!query_parse(q, query, error)) {
957 query_destroy(q, error);
958 return NULL;
959 }
960 if (!q->q_sync && !q->q_row_id && !q->q_token_object_id) {
961 /* query did not specify a kSecAttrSynchronizable attribute,
962 * and did not contain a persistent reference. */
963 query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q);
964 }
965 }
966 return q;
967 }
968
969
970 void
971 query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups) {
972 CFRetainAssign(q->q_caller_access_groups, caller_access_groups);
973 }
974
975 void
976 query_set_policy(Query *q, SecPolicyRef policy) {
977 CFRetainAssign(q->q_match_policy, policy);
978 }
979
980 void query_set_valid_on_date(Query *q, CFDateRef date) {
981 CFRetainAssign(q->q_match_valid_on_date, date);
982 }
983
984 void query_set_trusted_only(Query *q, CFBooleanRef trusted_only) {
985 CFRetainAssign(q->q_match_trusted_only, trusted_only);
986 }