]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/SecDbQuery.c
Security-57740.60.18.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 if (q->q_attr_end + 1 < q->q_pairs_count) {
321 q->q_pairs[q->q_attr_end].key = desc->name;
322 q->q_pairs[q->q_attr_end++].value = attr;
323 } else {
324 SecError(errSecInternal, &q->q_error, CFSTR("q_pairs overflow"));
325 CFReleaseSafe(attr);
326 }
327 } else {
328 CFReleaseSafe(attr);
329 }
330 }
331
332 void query_add_attribute(const void *key, const void *value, Query *q)
333 {
334 const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
335 if (desc) {
336 query_add_attribute_with_desc(desc, value, q);
337
338 if (desc->kind == kSecDbAccessControlAttr) {
339 CFDataRef attr = (CFDataRef)CFDictionaryGetValue(q->q_item, desc->name);
340 if (attr) {
341 SecAccessControlRef access_control = SecAccessControlCreateFromData(kCFAllocatorDefault, attr, &q->q_error);
342 if (access_control) {
343 query_set_access_control(q, access_control);
344 CFRelease(access_control);
345 }
346 }
347 }
348
349 if (desc->kind == kSecDbAccessAttr) {
350 SecAccessControlRef access_control = SecAccessControlCreate(kCFAllocatorDefault, &q->q_error);
351 if (access_control) {
352 CFStringRef attr = (CFStringRef)CFDictionaryGetValue(q->q_item, desc->name);
353 if (attr) {
354 if (SecAccessControlSetProtection(access_control, attr, &q->q_error))
355 query_set_access_control(q, access_control);
356 }
357 CFRelease(access_control);
358 }
359 }
360 }
361 }
362
363 void query_add_or_attribute(const void *key, const void *value, Query *q)
364 {
365 const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
366 if (desc) {
367 CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name);
368 CFMutableArrayRef array = NULL;
369 if (oldValue) {
370 if (isArray(oldValue)) {
371 array = (CFMutableArrayRef)CFRetain(oldValue);
372 } else {
373 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
374 CFArrayAppendValue(array, oldValue);
375 }
376 CFDictionaryRemoveValue(q->q_item, desc->name);
377 } else {
378 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
379 }
380 if (array) {
381 query_add_attribute_with_desc(desc, value, q);
382 CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name);
383 CFArrayAppendValue(array, newValue);
384 CFDictionarySetValue(q->q_item, desc->name, array);
385 CFRelease(array);
386 }
387 }
388 }
389
390 void query_add_not_attribute(const void *key, const void *value, Query *q)
391 {
392 const SecDbAttr *desc = SecDbAttrWithKey(q->q_class, key, &q->q_error);
393 if (desc) {
394 CFTypeRef oldValue = CFDictionaryGetValue(q->q_item, desc->name);
395 CFMutableArrayRef array = NULL;
396 if (oldValue) {
397 if (isArray(oldValue)) {
398 array = (CFMutableArrayRef)CFRetain(oldValue);
399 } else {
400 // This should never run, as we shouldn't be turning a attr = value into a attr not in (value, value2)
401 secerror("negating %@ = %@ in query", desc->name, oldValue);
402 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
403 CFArrayAppendValue(array, kCFNull);
404 CFArrayAppendValue(array, oldValue);
405 }
406 CFDictionaryRemoveValue(q->q_item, desc->name);
407 } else {
408 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
409 CFArrayAppendValue(array, kCFNull);
410 }
411 if (array) {
412 query_add_attribute_with_desc(desc, value, q);
413 CFTypeRef newValue = CFDictionaryGetValue(q->q_item, desc->name);
414 CFArrayAppendValue(array, newValue);
415 CFDictionarySetValue(q->q_item, desc->name, array);
416 CFRelease(array);
417 }
418 }
419 }
420
421
422 /* AUDIT[securityd](done):
423 key (ok) is a caller provided, string starting with 'm'.
424 value (ok) is a caller provided, non NULL CFTypeRef.
425 */
426 static void query_add_match(const void *key, const void *value, Query *q)
427 {
428 /* Record the match key, value in q_pairs. */
429 --(q->q_match_begin);
430 q->q_pairs[q->q_match_begin].key = key;
431 q->q_pairs[q->q_match_begin].value = value;
432
433 if (CFEqual(kSecMatchLimit, key)) {
434 /* Figure out what the value for kSecMatchLimit is if specified. */
435 if (CFGetTypeID(value) == CFNumberGetTypeID()) {
436 if (!CFNumberGetValue(value, kCFNumberCFIndexType, &q->q_limit))
437 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("failed to convert match limit %@ to CFIndex"), value);
438 } else if (CFEqual(kSecMatchLimitAll, value)) {
439 q->q_limit = kSecMatchUnlimited;
440 } else if (CFEqual(kSecMatchLimitOne, value)) {
441 q->q_limit = 1;
442 } else {
443 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("unsupported match limit %@"), value);
444 }
445 } else if (CFEqual(kSecMatchIssuers, key) &&
446 (CFGetTypeID(value) == CFArrayGetTypeID()))
447 {
448 CFMutableArrayRef canonical_issuers = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
449 if (canonical_issuers) {
450 CFIndex i, count = CFArrayGetCount(value);
451 for (i = 0; i < count; i++) {
452 CFTypeRef issuer_data = CFArrayGetValueAtIndex(value, i);
453 CFDataRef issuer_canonical = NULL;
454 if (CFDataGetTypeID() == CFGetTypeID(issuer_data))
455 issuer_canonical = SecDistinguishedNameCopyNormalizedContent((CFDataRef)issuer_data);
456 if (issuer_canonical) {
457 CFArrayAppendValue(canonical_issuers, issuer_canonical);
458 CFRelease(issuer_canonical);
459 }
460 }
461
462 if (CFArrayGetCount(canonical_issuers) > 0) {
463 q->q_match_issuer = canonical_issuers;
464 } else
465 CFRelease(canonical_issuers);
466 }
467 } else if (CFEqual(kSecMatchPolicy, key)) {
468 if (CFGetTypeID(value) != CFArrayGetTypeID()) {
469 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchPolicy attribute"));
470 return;
471 }
472 xpc_object_t policiesArrayXPC = _CFXPCCreateXPCObjectFromCFObject(value);
473 if (!policiesArrayXPC) {
474 SecError(errSecParam, &q->q_error, CFSTR("unsupported kSecMatchPolicy object in query"));
475 return;
476 }
477
478 CFArrayRef policiesArray = SecPolicyXPCArrayCopyArray(policiesArrayXPC, &q->q_error);
479 xpc_release(policiesArrayXPC);
480 if (!policiesArray)
481 return;
482
483 if (CFArrayGetCount(policiesArray) != 1 || CFGetTypeID(CFArrayGetValueAtIndex(policiesArray, 0)) != SecPolicyGetTypeID()) {
484 CFRelease(policiesArray);
485 SecError(errSecParam, &q->q_error, CFSTR("unsupported array of policies"));
486 return;
487 }
488
489 query_set_policy(q, (SecPolicyRef)CFArrayGetValueAtIndex(policiesArray, 0));
490 CFRelease(policiesArray);
491 } else if (CFEqual(kSecMatchValidOnDate, key)) {
492 if (CFGetTypeID(value) == CFNullGetTypeID()) {
493 CFDateRef date = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent());
494 query_set_valid_on_date(q, date);
495 CFRelease(date);
496 } else if (CFGetTypeID(value) == CFDateGetTypeID()) {
497 query_set_valid_on_date(q, value);
498 } else {
499 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchValidOnDate attribute"));
500 return;
501 }
502 } else if (CFEqual(kSecMatchTrustedOnly, key)) {
503 if ((CFGetTypeID(value) == CFBooleanGetTypeID())) {
504 query_set_trusted_only(q, value);
505 } else {
506 SecError(errSecParam, &q->q_error, CFSTR("unsupported value for kSecMatchTrustedOnly attribute"));
507 return;
508 }
509 }
510 }
511
512 static bool query_set_class(Query *q, CFStringRef c_name, CFErrorRef *error) {
513 const SecDbClass *value;
514 if (c_name && CFGetTypeID(c_name) == CFStringGetTypeID() &&
515 (value = kc_class_with_name(c_name)) &&
516 (q->q_class == 0 || q->q_class == value)) {
517 q->q_class = value;
518 return true;
519 }
520
521 if (error && !*error)
522 SecError((c_name ? errSecNoSuchClass : errSecItemClassMissing), error, CFSTR("can find class named: %@"), c_name);
523
524
525 return false;
526 }
527
528 static const SecDbClass *query_get_class(CFDictionaryRef query, CFErrorRef *error) {
529 CFStringRef c_name = NULL;
530 const void *value = CFDictionaryGetValue(query, kSecClass);
531 if (isString(value)) {
532 c_name = value;
533 } else {
534 value = CFDictionaryGetValue(query, kSecValuePersistentRef);
535 if (isData(value)) {
536 CFDataRef pref = value;
537 _SecItemParsePersistentRef(pref, &c_name, 0);
538 }
539 }
540
541 if (c_name && (value = kc_class_with_name(c_name))) {
542 return value;
543 } else {
544 if (c_name)
545 SecError(errSecNoSuchClass, error, CFSTR("can't find class named: %@"), c_name);
546 else
547 SecError(errSecItemClassMissing, error, CFSTR("query missing class name"));
548 return NULL;
549 }
550 }
551
552 /* AUDIT[securityd](done):
553 key (ok) is a caller provided, string starting with 'c'.
554 value (ok) is a caller provided, non NULL CFTypeRef.
555 */
556 static void query_add_class(const void *key, const void *value, Query *q)
557 {
558 if (CFEqual(key, kSecClass)) {
559 query_set_class(q, value, &q->q_error);
560 } else {
561 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_class: key %@ is not %@"), key, kSecClass);
562 }
563 }
564
565 /* AUDIT[securityd](done):
566 key (ok) is a caller provided, string starting with 'r'.
567 value (ok) is a caller provided, non NULL CFTypeRef.
568 */
569 static void query_add_return(const void *key, const void *value, Query *q)
570 {
571 ReturnTypeMask mask;
572 if (CFGetTypeID(value) != CFBooleanGetTypeID()) {
573 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_return: value %@ is not CFBoolean"), value);
574 return;
575 }
576
577 int set_it = CFEqual(value, kCFBooleanTrue);
578
579 if (CFEqual(key, kSecReturnData))
580 mask = kSecReturnDataMask;
581 else if (CFEqual(key, kSecReturnAttributes))
582 mask = kSecReturnAttributesMask;
583 else if (CFEqual(key, kSecReturnRef))
584 mask = kSecReturnRefMask;
585 else if (CFEqual(key, kSecReturnPersistentRef))
586 mask = kSecReturnPersistentRefMask;
587 else {
588 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_return: unknown key %@"), key);
589 return;
590 }
591
592 if ((q->q_return_type & mask) && !set_it) {
593 /* Clear out this bit (it's set so xor with the mask will clear it). */
594 q->q_return_type ^= mask;
595 } else if (!(q->q_return_type & mask) && set_it) {
596 /* Set this bit. */
597 q->q_return_type |= mask;
598 }
599 }
600
601 /* AUDIT[securityd](done):
602 key (ok) is a caller provided, string starting with 'u'.
603 value (ok since q_use_item_list is unused) is a caller provided, non
604 NULL CFTypeRef.
605 */
606 static void query_add_use(const void *key, const void *value, Query *q)
607 {
608 if (CFEqual(key, kSecUseItemList)) {
609 /* TODO: Add sanity checking when we start using this. */
610 q->q_use_item_list = value;
611 } else if (CFEqual(key, kSecUseTombstones)) {
612 if (CFGetTypeID(value) == CFBooleanGetTypeID()) {
613 q->q_use_tomb = value;
614 } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
615 q->q_use_tomb = CFBooleanGetValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
616 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
617 q->q_use_tomb = CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse;
618 } else {
619 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value, key);
620 return;
621 }
622 } else if (CFEqual(key, kSecUseCredentialReference)) {
623 if (isData(value)) {
624 CFRetainAssign(q->q_use_cred_handle, value);
625 } else {
626 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFData"), value, key);
627 return;
628 }
629 } else if (CFEqual(key, kSecUseAuthenticationUI)) {
630 if (isString(value)) {
631 q->q_skip_acl_items = CFEqualSafe(kSecUseAuthenticationUISkip, value);
632 } else {
633 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not CFString"), value, key);
634 return;
635 }
636 #if TARGET_OS_IPHONE
637 } else if (CFEqual(key, kSecUseSystemKeychain)) {
638 #if TARGET_OS_EMBEDDED
639 q->q_keybag = KEYBAG_DEVICE;
640 #endif
641 q->q_system_keychain = true;
642 } else if (CFEqual(key, kSecUseSyncBubbleKeychain)) {
643 if (isNumber(value) && CFNumberGetValue(value, kCFNumberSInt32Type, &q->q_sync_bubble) && q->q_sync_bubble > 0) {
644 #if TARGET_OS_EMBEDDED
645 q->q_keybag = KEYBAG_DEVICE;
646 #endif
647 } else {
648 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("add_use: value %@ for key %@ is not valid uid"), value, key);
649 return;
650 }
651 #endif
652 } else {
653 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("add_use: unknown key %@"), key);
654 return;
655 }
656 }
657
658 static void query_set_data(const void *value, Query *q) {
659 if (!isData(value)) {
660 SecError(errSecItemInvalidValue, &q->q_error, CFSTR("set_data: value %@ is not type data"), value);
661 } else {
662 q->q_data = value;
663 if (q->q_item)
664 CFDictionarySetValue(q->q_item, kSecValueData, value);
665 }
666 }
667
668 /* AUDIT[securityd](done):
669 key (ok) is a caller provided, string starting with 'u'.
670 value (ok) is a caller provided, non NULL CFTypeRef.
671 */
672 static void query_add_value(const void *key, const void *value, Query *q)
673 {
674 if (CFEqual(key, kSecValueData)) {
675 query_set_data(value, q);
676 #ifdef NO_SERVER
677 } else if (CFEqual(key, kSecValueRef)) {
678 q->q_ref = value;
679 /* TODO: Add value type sanity checking. */
680 #endif
681 } else if (CFEqual(key, kSecValuePersistentRef)) {
682 CFStringRef c_name;
683 if (_SecItemParsePersistentRef(value, &c_name, &q->q_row_id))
684 query_set_class(q, c_name, &q->q_error);
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 */
764 if (key_len == 4) {
765 /* attributes */
766 query_add_attribute(key, value, q);
767 } else if (key_len > 1) {
768 UniChar k_first_char = CFStringGetCharacterAtIndex(key, 0);
769 switch (k_first_char)
770 {
771 case 'c': /* class */
772 query_add_class(key, value, q);
773 break;
774 case 'm': /* match */
775 query_add_match(key, value, q);
776 break;
777 case 'r': /* return */
778 query_add_return(key, value, q);
779 break;
780 case 'u': /* use */
781 query_add_use(key, value, q);
782 break;
783 case 'v': /* value */
784 query_add_value(key, value, q);
785 break;
786 default:
787 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid"), key);
788 break;
789 }
790 } else {
791 SecError(errSecItemInvalidKey, &q->q_error, CFSTR("applier: key %@ invalid length"), key);
792 }
793 } else if (key_id == CFNumberGetTypeID()) {
794 /* Numeric keys are always (extended) attributes. */
795 /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
796 query_add_attribute(key, value, q);
797 } else {
798 /* We only support string and number type keys. */
799 SecError(errSecItemInvalidKeyType, &q->q_error, CFSTR("applier: key %@ neither string nor number"), key);
800 }
801 }
802
803 static CFStringRef query_infer_keyclass(Query *q, CFStringRef agrp) {
804 /* apsd are always dku. */
805 if (CFEqual(agrp, CFSTR("com.apple.apsd"))) {
806 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate;
807 }
808 /* All other certs or in the apple agrp is dk. */
809 if (q->q_class == &cert_class) {
810 /* third party certs are always dk. */
811 return kSecAttrAccessibleAlwaysPrivate;
812 }
813 /* The rest defaults to ak. */
814 return kSecAttrAccessibleWhenUnlocked;
815 }
816
817 void query_ensure_access_control(Query *q, CFStringRef agrp) {
818 if (q->q_access_control == 0) {
819 CFStringRef accessible = query_infer_keyclass(q, agrp);
820 query_add_attribute(kSecAttrAccessible, accessible, q);
821 }
822 }
823
824 bool query_error(Query *q, CFErrorRef *error) {
825 CFErrorRef tmp = q->q_error;
826 q->q_error = NULL;
827 return SecErrorPropagate(tmp, error);
828 }
829
830 bool query_destroy(Query *q, CFErrorRef *error) {
831 bool ok = query_error(q, error);
832 CFIndex ix, attr_count = query_attr_count(q);
833 for (ix = 0; ix < attr_count; ++ix) {
834 CFReleaseSafe(query_attr_at(q, ix).value);
835 }
836 CFReleaseSafe(q->q_item);
837 CFReleaseSafe(q->q_musrView);
838 CFReleaseSafe(q->q_primary_key_digest);
839 CFReleaseSafe(q->q_match_issuer);
840 CFReleaseSafe(q->q_access_control);
841 CFReleaseSafe(q->q_use_cred_handle);
842 CFReleaseSafe(q->q_caller_access_groups);
843 CFReleaseSafe(q->q_match_policy);
844 CFReleaseSafe(q->q_match_valid_on_date);
845 CFReleaseSafe(q->q_match_trusted_only);
846
847 free(q);
848 return ok;
849 }
850
851 bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
852 if (ok && !q->q_error && (q->q_sync_changed || (q->q_changed && !SecMUSRIsSingleUserView(q->q_musrView)))) {
853 SecKeychainChanged();
854 }
855 return query_destroy(q, error) && ok;
856 }
857
858 /* Allocate and initialize a Query object for query. */
859 Query *query_create(const SecDbClass *qclass,
860 CFDataRef musr,
861 CFDictionaryRef query,
862 CFErrorRef *error)
863 {
864 if (!qclass) {
865 if (error && !*error)
866 SecError(errSecItemClassMissing, error, CFSTR("Missing class"));
867 return NULL;
868 }
869
870 if (musr == NULL)
871 musr = SecMUSRGetSingleUserKeychainUUID();
872
873 /* Number of pairs we need is the number of attributes in this class
874 plus the number of keys in the dictionary, minus one for each key in
875 the dictionary that is a regular attribute. */
876 CFIndex key_count = SecDbClassAttrCount(qclass);
877 if (key_count == 0) {
878 // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
879 key_count = SecDbClassAttrCount(&cert_class) + SecDbClassAttrCount(&keys_class);
880 }
881
882 if (query) {
883 key_count += CFDictionaryGetCount(query);
884 SecDbForEachAttr(qclass, attr) {
885 if (CFDictionaryContainsKey(query, attr->name))
886 --key_count;
887 }
888 }
889
890 if (key_count > QUERY_KEY_LIMIT) {
891 if (error && !*error)
892 {
893 secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count, QUERY_KEY_LIMIT);
894 SecError(errSecItemIllegalQuery, error, CFSTR("Past query key limit"));
895 }
896 return NULL;
897 }
898
899 Query *q = calloc(1, sizeof(Query) + sizeof(Pair) * key_count);
900 if (q == NULL) {
901 if (error && !*error)
902 SecError(errSecAllocate, error, CFSTR("Out of memory"));
903 return NULL;
904 }
905
906 q->q_pairs_count = key_count;
907 q->q_musrView = (CFDataRef)CFRetain(musr);
908 q->q_keybag = KEYBAG_DEVICE;
909 q->q_class = qclass;
910 q->q_match_begin = q->q_match_end = key_count;
911 q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
912
913 return q;
914 }
915
916 /* Parse query for a Query object q. */
917 static bool query_parse_with_applier(Query *q, CFDictionaryRef query,
918 CFDictionaryApplierFunction applier,
919 CFErrorRef *error) {
920 CFDictionaryApplyFunction(query, applier, q);
921 return query_error(q, error);
922 }
923
924 /* Parse query for a Query object q. */
925 static bool query_parse(Query *q, CFDictionaryRef query,
926 CFErrorRef *error) {
927 return query_parse_with_applier(q, query, query_applier, error);
928 }
929
930 /* Parse query for a Query object q. */
931 bool query_update_parse(Query *q, CFDictionaryRef update,
932 CFErrorRef *error) {
933 return query_parse_with_applier(q, update, query_update_applier, error);
934 }
935
936 Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error) {
937 Query *q;
938 q = query_create(query_get_class(query, error), musr, query, error);
939 if (q) {
940 q->q_limit = limit;
941 if (!query_parse(q, query, error)) {
942 query_destroy(q, error);
943 return NULL;
944 }
945 if (!q->q_sync && !q->q_row_id) {
946 /* query did not specify a kSecAttrSynchronizable attribute,
947 * and did not contain a persistent reference. */
948 query_add_attribute(kSecAttrSynchronizable, kCFBooleanFalse, q);
949 }
950 }
951 return q;
952 }
953
954
955 void
956 query_set_caller_access_groups(Query *q, CFArrayRef caller_access_groups) {
957 CFRetainAssign(q->q_caller_access_groups, caller_access_groups);
958 }
959
960 void
961 query_set_policy(Query *q, SecPolicyRef policy) {
962 CFRetainAssign(q->q_match_policy, policy);
963 }
964
965 void query_set_valid_on_date(Query *q, CFDateRef date) {
966 CFRetainAssign(q->q_match_valid_on_date, date);
967 }
968
969 void query_set_trusted_only(Query *q, CFBooleanRef trusted_only) {
970 CFRetainAssign(q->q_match_trusted_only, trusted_only);
971 }