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