3 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
26 * SecDbQuery.c - CoreFoundation-based constants and functions for
27 access to Security items (certificates, keys, identities, and
31 #include <securityd/SecDbQuery.h>
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/SecPolicyPriv.h>
45 #include <Security/SecuritydXPC.h>
46 #include <CommonCrypto/CommonDigest.h>
47 #include <CommonCrypto/CommonDigestSPI.h>
49 #include <pthread/pthread.h>
52 #include <LocalAuthentication/LAPublicDefines.h>
53 #include <coreauthd_spi.h>
54 #include <libaks_acl_cf_keys.h>
57 /* Upper limit for number of keys in a QUERY dictionary. */
58 #define QUERY_KEY_LIMIT_BASE (128)
60 #define QUERY_KEY_LIMIT (31 + QUERY_KEY_LIMIT_BASE)
62 #define QUERY_KEY_LIMIT QUERY_KEY_LIMIT_BASE
66 static const uint8_t systemKeychainUUID
[] = "\xF6\x23\xAE\x5C\xCC\x81\x4C\xAC\x8A\xD4\xF0\x01\x3F\x31\x35\x11";
69 SecMUSRCopySystemKeychainUUID(void)
71 return CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)systemKeychainUUID
, 16, kCFAllocatorNull
);
75 SecMUSRGetSystemKeychainUUID(void)
77 static dispatch_once_t onceToken
;
78 static CFDataRef systemKeychainData
= NULL
;
79 dispatch_once(&onceToken
, ^{
80 systemKeychainData
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)systemKeychainUUID
, 16, kCFAllocatorNull
);
82 return systemKeychainData
;
86 SecMUSRGetSingleUserKeychainUUID(void)
88 static dispatch_once_t onceToken
;
89 static CFDataRef singleUser
= NULL
;
90 dispatch_once(&onceToken
, ^{
91 singleUser
= CFDataCreateWithBytesNoCopy(NULL
, NULL
, 0, kCFAllocatorNull
);
97 SecMUSRIsSingleUserView(CFDataRef musr
)
99 return CFEqual(musr
, SecMUSRGetSingleUserKeychainUUID());
102 static const uint8_t allKeychainViewsUUID
[16] = "\xC8\x60\x07\xEC\x89\x62\x4D\xAF\x85\x65\x1F\xE6\x0F\x50\x5D\xB7";
105 SecMUSRGetAllViews(void)
107 static dispatch_once_t onceToken
;
108 static CFDataRef allKeychainViewsData
= NULL
;
109 dispatch_once(&onceToken
, ^{
110 allKeychainViewsData
= CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)allKeychainViewsUUID
, 16, kCFAllocatorNull
);
112 return allKeychainViewsData
;
116 SecMUSRIsViewAllViews(CFDataRef musr
)
118 return CFEqual(musr
, SecMUSRGetAllViews());
124 SecMUSRCreateActiveUserUUID(uid_t uid
)
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
));
133 SecMUSRCreateSyncBubbleUserUUID(uid_t uid
)
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
));
141 static const uint8_t bothUserAndSystemUUID
[12] = "\x36\xC4\xBE\x2E\x99\x0A\x46\x9A\xAC\x89\x09\xA4";
145 SecMUSRCreateBothUserAndSystemUUID(uid_t uid
)
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
));
155 SecMUSRGetBothUserAndSystemUUID(CFDataRef musr
, uid_t
*uid
)
157 if (CFDataGetLength(musr
) != 16)
159 const uint8_t *uuid
= CFDataGetBytePtr(musr
);
160 if (memcmp(uuid
, bothUserAndSystemUUID
, 12) != 0)
164 memcpy(&num
, &uuid
[12], sizeof(num
));
172 /* Inline accessors to attr and match values in a query. */
173 CFIndex
query_attr_count(const Query
*q
)
175 return q
->q_attr_end
;
178 Pair
query_attr_at(const Query
*q
, CFIndex ix
)
180 return q
->q_pairs
[ix
];
183 CFIndex
query_match_count(const Query
*q
)
185 return q
->q_match_end
- q
->q_match_begin
;
188 __unused
static inline Pair
query_match_at(const Query
*q
, CFIndex ix
)
190 return q
->q_pairs
[q
->q_match_begin
+ ix
];
193 /* Private routines used to parse a query. */
195 const SecDbClass
*kc_class_with_name(CFStringRef name
) {
196 if (isString(name
)) {
197 if (CFEqual(name
, kSecClassGenericPassword
))
199 else if (CFEqual(name
, kSecClassInternetPassword
))
201 else if (CFEqual(name
, kSecClassCertificate
))
203 else if (CFEqual(name
, kSecClassKey
))
205 else if (CFEqual(name
, kSecClassIdentity
))
206 return identity_class();
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"));
217 /* Store access control virtual attribute. */
218 q
->q_access_control
= (SecAccessControlRef
)CFRetain(access_control
);
220 /* Also set legacy access attribute. */
221 CFTypeRef protection
= SecAccessControlGetProtection(q
->q_access_control
);
223 SecError(errSecParam
, &q
->q_error
, CFSTR("kSecAccessControl missing protection"));
226 CFDictionarySetValue(q
->q_item
, kSecAttrAccessible
, protection
);
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.
234 void query_add_attribute_with_desc(const SecDbAttr
*desc
, const void *value
, Query
*q
)
236 if (CFEqual(desc
->name
, kSecAttrSynchronizable
)) {
238 if (CFEqual(value
, kSecAttrSynchronizableAny
))
239 return; /* skip the attribute so it isn't part of the search */
242 CFTypeRef attr
= NULL
;
243 switch (desc
->kind
) {
245 attr
= copyData(value
);
248 case kSecDbAccessControlAttr
:
249 attr
= copyBlob(value
);
252 case kSecDbCreationDateAttr
:
253 case kSecDbModificationDateAttr
:
254 attr
= copyDate(value
);
256 case kSecDbNumberAttr
:
259 attr
= copyNumber(value
);
261 case kSecDbAccessAttr
:
262 case kSecDbStringAttr
:
263 attr
= copyString(value
);
266 attr
= copySHA1(value
);
268 case kSecDbRowIdAttr
:
269 case kSecDbPrimaryKeyAttr
:
270 case kSecDbEncryptedDataAttr
:
271 case kSecDbUTombAttr
:
274 attr
= copyUUID(value
);
279 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("attribute %@: value: %@ failed to convert"), desc
->name
, value
);
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
);
288 /* Convert attr to (sha1) digest if requested. */
289 if (desc
->flags
& kSecDbSHA1ValueInFlag
) {
290 CFDataRef data
= copyData(attr
);
293 SecError(errSecInternal
, &q
->q_error
, CFSTR("failed to get attribute %@ data"), desc
->name
);
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
));
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
;
313 SecError(errSecInternal
, &q
->q_error
, CFSTR("q_pairs overflow"));
321 void query_add_attribute(const void *key
, const void *value
, Query
*q
)
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 */
328 const SecDbAttr
*desc
= SecDbAttrWithKey(q
->q_class
, key
, &q
->q_error
);
330 query_add_attribute_with_desc(desc
, value
, q
);
332 if (desc
->kind
== kSecDbAccessControlAttr
) {
333 CFDataRef attr
= (CFDataRef
)CFDictionaryGetValue(q
->q_item
, desc
->name
);
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
);
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
);
348 if (SecAccessControlSetProtection(access_control
, attr
, &q
->q_error
))
349 query_set_access_control(q
, access_control
);
351 CFRelease(access_control
);
357 void query_add_or_attribute(const void *key
, const void *value
, Query
*q
)
359 const SecDbAttr
*desc
= SecDbAttrWithKey(q
->q_class
, key
, &q
->q_error
);
361 CFTypeRef oldValue
= CFDictionaryGetValue(q
->q_item
, desc
->name
);
362 CFMutableArrayRef array
= NULL
;
364 if (isArray(oldValue
)) {
365 array
= (CFMutableArrayRef
)CFRetain(oldValue
);
367 array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
368 CFArrayAppendValue(array
, oldValue
);
370 CFDictionaryRemoveValue(q
->q_item
, desc
->name
);
372 array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
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
);
384 void query_add_not_attribute(const void *key
, const void *value
, Query
*q
)
386 const SecDbAttr
*desc
= SecDbAttrWithKey(q
->q_class
, key
, &q
->q_error
);
388 CFTypeRef oldValue
= CFDictionaryGetValue(q
->q_item
, desc
->name
);
389 CFMutableArrayRef array
= NULL
;
391 if (isArray(oldValue
)) {
392 array
= (CFMutableArrayRef
)CFRetain(oldValue
);
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
);
400 CFDictionaryRemoveValue(q
->q_item
, desc
->name
);
402 array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
403 CFArrayAppendValue(array
, kCFNull
);
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
);
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.
420 static void query_add_match(const void *key
, const void *value
, Query
*q
)
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
;
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
)) {
437 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("unsupported match limit %@"), value
);
439 } else if (CFEqual(kSecMatchIssuers
, key
) &&
440 (CFGetTypeID(value
) == CFArrayGetTypeID()))
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
);
456 if (CFArrayGetCount(canonical_issuers
) > 0) {
457 q
->q_match_issuer
= canonical_issuers
;
459 CFRelease(canonical_issuers
);
461 } else if (CFEqual(kSecMatchPolicy
, key
)) {
462 if (CFGetTypeID(value
) != CFArrayGetTypeID()) {
463 SecError(errSecParam
, &q
->q_error
, CFSTR("unsupported value for kSecMatchPolicy attribute"));
466 xpc_object_t policiesArrayXPC
= _CFXPCCreateXPCObjectFromCFObject(value
);
467 if (!policiesArrayXPC
) {
468 SecError(errSecParam
, &q
->q_error
, CFSTR("unsupported kSecMatchPolicy object in query"));
472 CFArrayRef policiesArray
= SecPolicyXPCArrayCopyArray(policiesArrayXPC
, &q
->q_error
);
473 xpc_release(policiesArrayXPC
);
477 if (CFArrayGetCount(policiesArray
) != 1 || CFGetTypeID(CFArrayGetValueAtIndex(policiesArray
, 0)) != SecPolicyGetTypeID()) {
478 CFRelease(policiesArray
);
479 SecError(errSecParam
, &q
->q_error
, CFSTR("unsupported array of policies"));
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
);
490 } else if (CFGetTypeID(value
) == CFDateGetTypeID()) {
491 query_set_valid_on_date(q
, value
);
493 SecError(errSecParam
, &q
->q_error
, CFSTR("unsupported value for kSecMatchValidOnDate attribute"));
496 } else if (CFEqual(kSecMatchTrustedOnly
, key
)) {
497 if ((CFGetTypeID(value
) == CFBooleanGetTypeID())) {
498 query_set_trusted_only(q
, value
);
500 SecError(errSecParam
, &q
->q_error
, CFSTR("unsupported value for kSecMatchTrustedOnly attribute"));
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
)) {
515 if (error
&& !*error
)
516 SecError((c_name
? errSecNoSuchClass
: errSecItemClassMissing
), error
, CFSTR("can find class named: %@"), c_name
);
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
)) {
528 value
= CFDictionaryGetValue(query
, kSecValuePersistentRef
);
530 CFDataRef pref
= value
;
531 _SecItemParsePersistentRef(pref
, &c_name
, NULL
, NULL
);
535 if (c_name
&& (value
= kc_class_with_name(c_name
))) {
539 SecError(errSecNoSuchClass
, error
, CFSTR("can't find class named: %@"), c_name
);
541 SecError(errSecItemClassMissing
, error
, CFSTR("query missing class name"));
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.
550 static void query_add_class(const void *key
, const void *value
, Query
*q
)
552 if (CFEqual(key
, kSecClass
)) {
553 query_set_class(q
, value
, &q
->q_error
);
555 SecError(errSecItemInvalidKey
, &q
->q_error
, CFSTR("add_class: key %@ is not %@"), key
, kSecClass
);
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.
563 static void query_add_return(const void *key
, const void *value
, Query
*q
)
566 if (CFGetTypeID(value
) != CFBooleanGetTypeID()) {
567 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("add_return: value %@ is not CFBoolean"), value
);
571 int set_it
= CFEqual(value
, kCFBooleanTrue
);
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
;
582 SecError(errSecItemInvalidKey
, &q
->q_error
, CFSTR("add_return: unknown key %@"), key
);
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
) {
591 q
->q_return_type
|= mask
;
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
600 static void query_add_use(const void *key
, const void *value
, Query
*q
)
602 // Gotta use a string literal because we just outlawed this symbol on iOS
603 if (CFEqual(key
, CFSTR("u_ItemList"))) {
604 /* TODO: Add sanity checking when we start using this. */
605 q
->q_use_item_list
= value
;
606 } else if (CFEqual(key
, kSecUseTombstones
)) {
607 if (CFGetTypeID(value
) == CFBooleanGetTypeID()) {
608 q
->q_use_tomb
= value
;
609 } else if (CFGetTypeID(value
) == CFNumberGetTypeID()) {
610 q
->q_use_tomb
= CFBooleanGetValue(value
) ? kCFBooleanTrue
: kCFBooleanFalse
;
611 } else if (CFGetTypeID(value
) == CFStringGetTypeID()) {
612 q
->q_use_tomb
= CFStringGetIntValue(value
) ? kCFBooleanTrue
: kCFBooleanFalse
;
614 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("add_use: value %@ for key %@ is neither CFBoolean nor CFNumber"), value
, key
);
617 } else if (CFEqual(key
, kSecUseCredentialReference
)) {
619 CFRetainAssign(q
->q_use_cred_handle
, value
);
621 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("add_use: value %@ for key %@ is not CFData"), value
, key
);
624 } else if (CFEqual(key
, kSecUseAuthenticationUI
)) {
625 if (isString(value
)) {
626 q
->q_skip_acl_items
= CFEqualSafe(kSecUseAuthenticationUISkip
, value
);
628 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("add_use: value %@ for key %@ is not CFString"), value
, key
);
632 } else if (CFEqual(key
, kSecUseSystemKeychain
)) {
633 #if TARGET_OS_EMBEDDED
634 q
->q_keybag
= KEYBAG_DEVICE
;
636 q
->q_system_keychain
= true;
637 } else if (CFEqual(key
, kSecUseSyncBubbleKeychain
)) {
638 if (isNumber(value
) && CFNumberGetValue(value
, kCFNumberSInt32Type
, &q
->q_sync_bubble
) && q
->q_sync_bubble
> 0) {
639 #if TARGET_OS_EMBEDDED
640 q
->q_keybag
= KEYBAG_DEVICE
;
643 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("add_use: value %@ for key %@ is not valid uid"), value
, key
);
648 SecError(errSecItemInvalidKey
, &q
->q_error
, CFSTR("add_use: unknown key %@"), key
);
653 static void query_set_data(const void *value
, Query
*q
) {
654 if (!isData(value
)) {
655 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("set_data: value %@ is not type data"), value
);
659 CFDictionarySetValue(q
->q_item
, kSecValueData
, value
);
663 static void query_set_token_persistent_ref(Query
*q
, CFDictionaryRef token_persistent_ref
) {
664 if (token_persistent_ref
) {
665 query_add_attribute(kSecAttrTokenID
, CFDictionaryGetValue(token_persistent_ref
, kSecAttrTokenID
), q
);
666 CFRetainAssign(q
->q_token_object_id
, CFDictionaryGetValue(token_persistent_ref
, kSecAttrTokenOID
));
670 /* AUDIT[securityd](done):
671 key (ok) is a caller provided, string starting with 'u'.
672 value (ok) is a caller provided, non NULL CFTypeRef.
674 static void query_add_value(const void *key
, const void *value
, Query
*q
)
676 if (CFEqual(key
, kSecValueData
)) {
677 query_set_data(value
, q
);
679 } else if (CFEqual(key
, kSecValueRef
)) {
681 /* TODO: Add value type sanity checking. */
683 } else if (CFEqual(key
, kSecValuePersistentRef
)) {
685 CFDictionaryRef token_persistent_ref
= NULL
;
686 if (_SecItemParsePersistentRef(value
, &c_name
, &q
->q_row_id
, &token_persistent_ref
)) {
687 query_set_class(q
, c_name
, &q
->q_error
);
688 query_set_token_persistent_ref(q
, token_persistent_ref
);
689 CFReleaseNull(token_persistent_ref
);
691 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("add_value: value %@ is not a valid persitent ref"), value
);
693 SecError(errSecItemInvalidKey
, &q
->q_error
, CFSTR("add_value: unknown key %@"), key
);
698 /* AUDIT[securityd](done):
699 key (ok) is a caller provided, unchecked.
700 value (ok) is a caller provided, unchecked.
702 static void query_update_applier(const void *key
, const void *value
,
705 Query
*q
= (Query
*)context
;
706 /* If something went wrong there is no point processing any more args. */
710 /* Make sure we have a string key. */
711 if (!isString(key
)) {
712 SecError(errSecItemInvalidKeyType
, &q
->q_error
, CFSTR("update_applier: unknown key type %@"), key
);
717 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("update_applier: key %@ has NULL value"), key
);
721 if (CFEqual(key
, CFSTR("musr"))) {
722 secnotice("item", "update_applier: refusing to update musr");
726 if (CFEqual(key
, kSecValueData
)) {
727 query_set_data(value
, q
);
729 query_add_attribute(key
, value
, q
);
733 /* AUDIT[securityd](done):
734 key (ok) is a caller provided, unchecked.
735 value (ok) is a caller provided, unchecked.
737 static void query_applier(const void *key
, const void *value
, void *context
)
739 Query
*q
= (Query
*)context
;
740 /* If something went wrong there is no point processing any more args. */
744 /* Make sure we have a key. */
746 SecError(errSecItemInvalidKeyType
, &q
->q_error
, CFSTR("applier: NULL key"));
750 /* Make sure we have a value. */
752 SecError(errSecItemInvalidValue
, &q
->q_error
, CFSTR("applier: key %@ has NULL value"), key
);
756 /* Figure out what type of key we are dealing with. */
757 CFTypeID key_id
= CFGetTypeID(key
);
758 if (key_id
== CFStringGetTypeID()) {
759 CFIndex key_len
= CFStringGetLength(key
);
760 /* String keys can be different things. The subtype is determined by:
761 length 4 strings are all attributes. Otherwise the first char
763 c: class must be kSecClass
764 m: match like kSecMatchPolicy
765 r: return like kSecReturnData
768 f: callbacks (ignored by the query applier)
772 query_add_attribute(key
, value
, q
);
773 } else if (key_len
> 1) {
774 // We added a database column named 'persistref', which is returned as an attribute but doesn't comply with
775 // these matching rules. skip it for now, since it isn't filled in anyway.
776 if(CFEqualSafe(key
, CFSTR("persistref"))) {
780 UniChar k_first_char
= CFStringGetCharacterAtIndex(key
, 0);
781 switch (k_first_char
)
783 case 'c': /* class */
784 query_add_class(key
, value
, q
);
786 case 'm': /* match */
787 query_add_match(key
, value
, q
);
789 case 'r': /* return */
790 query_add_return(key
, value
, q
);
793 query_add_use(key
, value
, q
);
795 case 'v': /* value */
796 query_add_value(key
, value
, q
);
801 SecError(errSecItemInvalidKey
, &q
->q_error
, CFSTR("applier: key %@ invalid"), key
);
805 SecError(errSecItemInvalidKey
, &q
->q_error
, CFSTR("applier: key %@ invalid length"), key
);
807 } else if (key_id
== CFNumberGetTypeID()) {
808 /* Numeric keys are always (extended) attributes. */
809 /* TODO: Why is this here? query_add_attribute() doesn't take numbers. */
810 query_add_attribute(key
, value
, q
);
812 /* We only support string and number type keys. */
813 SecError(errSecItemInvalidKeyType
, &q
->q_error
, CFSTR("applier: key %@ neither string nor number"), key
);
817 static CFStringRef
query_infer_keyclass(Query
*q
, CFStringRef agrp
) {
818 /* apsd are always dku. */
819 if (CFEqual(agrp
, CFSTR("com.apple.apsd"))) {
820 return kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
;
822 /* All other certs or in the apple agrp is dk. */
823 if (q
->q_class
== cert_class()) {
824 /* third party certs are always dk. */
825 return kSecAttrAccessibleAlwaysPrivate
;
827 /* The rest defaults to ak. */
828 return kSecAttrAccessibleWhenUnlocked
;
831 void query_ensure_access_control(Query
*q
, CFStringRef agrp
) {
832 if (q
->q_access_control
== 0) {
833 CFStringRef accessible
= query_infer_keyclass(q
, agrp
);
834 query_add_attribute(kSecAttrAccessible
, accessible
, q
);
838 bool query_error(Query
*q
, CFErrorRef
*error
) {
839 CFErrorRef tmp
= q
->q_error
;
841 return SecErrorPropagate(tmp
, error
);
844 bool query_destroy(Query
*q
, CFErrorRef
*error
) {
845 bool ok
= query_error(q
, error
);
846 CFIndex ix
, attr_count
= query_attr_count(q
);
847 for (ix
= 0; ix
< attr_count
; ++ix
) {
848 CFReleaseSafe(query_attr_at(q
, ix
).value
);
850 CFReleaseSafe(q
->q_item
);
851 CFReleaseSafe(q
->q_musrView
);
852 CFReleaseSafe(q
->q_primary_key_digest
);
853 CFReleaseSafe(q
->q_match_issuer
);
854 CFReleaseSafe(q
->q_access_control
);
855 CFReleaseSafe(q
->q_use_cred_handle
);
856 CFReleaseSafe(q
->q_caller_access_groups
);
857 CFReleaseSafe(q
->q_match_policy
);
858 CFReleaseSafe(q
->q_match_valid_on_date
);
859 CFReleaseSafe(q
->q_match_trusted_only
);
860 CFReleaseSafe(q
->q_token_object_id
);
866 bool query_notify_and_destroy(Query
*q
, bool ok
, CFErrorRef
*error
) {
867 if (ok
&& !q
->q_error
&& (q
->q_sync_changed
|| (q
->q_changed
&& !SecMUSRIsSingleUserView(q
->q_musrView
)))) {
868 SecKeychainChanged();
870 return query_destroy(q
, error
) && ok
;
873 /* Allocate and initialize a Query object for query. */
874 Query
*query_create(const SecDbClass
*qclass
,
876 CFDictionaryRef query
,
880 if (error
&& !*error
)
881 SecError(errSecItemClassMissing
, error
, CFSTR("Missing class"));
886 musr
= SecMUSRGetSingleUserKeychainUUID();
888 /* Number of pairs we need is the number of attributes in this class
889 plus the number of keys in the dictionary, minus one for each key in
890 the dictionary that is a regular attribute. */
891 CFIndex key_count
= SecDbClassAttrCount(qclass
);
892 if (key_count
== 0) {
893 // Identities claim to have 0 attributes, but they really support any keys or cert attribute.
894 key_count
= SecDbClassAttrCount(cert_class()) + SecDbClassAttrCount(keys_class());
898 key_count
+= CFDictionaryGetCount(query
);
899 SecDbForEachAttr(qclass
, attr
) {
900 if (CFDictionaryContainsKey(query
, attr
->name
))
905 if (key_count
> QUERY_KEY_LIMIT
) {
906 if (error
&& !*error
)
908 secerror("key_count: %ld, QUERY_KEY_LIMIT: %d", (long)key_count
, QUERY_KEY_LIMIT
);
909 SecError(errSecItemIllegalQuery
, error
, CFSTR("Past query key limit"));
914 Query
*q
= calloc(1, sizeof(Query
) + sizeof(Pair
) * key_count
);
916 if (error
&& !*error
)
917 SecError(errSecAllocate
, error
, CFSTR("Out of memory"));
921 q
->q_pairs_count
= key_count
;
922 q
->q_musrView
= (CFDataRef
)CFRetain(musr
);
923 q
->q_uuid_from_primary_key
= false;
924 q
->q_keybag
= KEYBAG_DEVICE
;
926 q
->q_match_begin
= q
->q_match_end
= key_count
;
927 q
->q_item
= CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
932 /* Parse query for a Query object q. */
933 static bool query_parse_with_applier(Query
*q
, CFDictionaryRef query
,
934 CFDictionaryApplierFunction applier
,
936 CFDictionaryApplyFunction(query
, applier
, q
);
937 return query_error(q
, error
);
940 /* Parse query for a Query object q. */
941 static bool query_parse(Query
*q
, CFDictionaryRef query
,
943 return query_parse_with_applier(q
, query
, query_applier
, error
);
946 /* Parse query for a Query object q. */
947 bool query_update_parse(Query
*q
, CFDictionaryRef update
,
949 return query_parse_with_applier(q
, update
, query_update_applier
, error
);
952 Query
*query_create_with_limit(CFDictionaryRef query
, CFDataRef musr
, CFIndex limit
, CFErrorRef
*error
) {
954 q
= query_create(query_get_class(query
, error
), musr
, query
, error
);
957 if (!query_parse(q
, query
, error
)) {
958 query_destroy(q
, error
);
961 if (!q
->q_sync
&& !q
->q_row_id
&& !q
->q_token_object_id
) {
962 /* query did not specify a kSecAttrSynchronizable attribute,
963 * and did not contain a persistent reference. */
964 query_add_attribute(kSecAttrSynchronizable
, kCFBooleanFalse
, q
);
972 query_set_caller_access_groups(Query
*q
, CFArrayRef caller_access_groups
) {
973 CFRetainAssign(q
->q_caller_access_groups
, caller_access_groups
);
977 query_set_policy(Query
*q
, SecPolicyRef policy
) {
978 CFRetainAssign(q
->q_match_policy
, policy
);
981 void query_set_valid_on_date(Query
*q
, CFDateRef date
) {
982 CFRetainAssign(q
->q_match_valid_on_date
, date
);
985 void query_set_trusted_only(Query
*q
, CFBooleanRef trusted_only
) {
986 CFRetainAssign(q
->q_match_trusted_only
, trusted_only
);