2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <CoreFoundation/CoreFoundation.h>
26 #include <Security/SecCertificate.h>
27 #include <Security/SecItem.h>
28 #include <Security/SecItemPriv.h>
29 #include <Security/SecBase.h>
30 #include <utilities/array_size.h>
31 #include <utilities/SecCFWrappers.h>
35 #include "Security_regressions.h"
38 static void persistentRefIs(CFDataRef pref
, CFDataRef data
) {
39 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(NULL
, 0, NULL
, NULL
);
40 CFTypeRef result
= NULL
;
41 CFDictionaryAddValue(dict
, kSecValuePersistentRef
, pref
);
42 CFDictionaryAddValue(dict
, kSecReturnData
, kCFBooleanTrue
);
43 ok_status(SecItemCopyMatching(dict
, &result
), "lookup item data by persistent ref");
44 ok(CFEqual(data
, result
), "result %@ equals expected data %@", result
, data
);
45 CFReleaseNull(result
);
57 kAccessabilityItemAttr
,
61 static void WithEachString(void(^each
)(CFStringRef attr
, enum ItemAttrType atype
), ...) {
65 while((attr
= va_arg(ap
, CFStringRef
)) != NULL
) {
66 enum ItemAttrType atype
= va_arg(ap
, enum ItemAttrType
);
73 static void ItemForEachAttr(CFMutableDictionaryRef item
, void(^each
)(CFStringRef attr
, enum ItemAttrType atype
)) {
74 CFStringRef iclass
= CFDictionaryGetValue(item
, kSecClass
);
77 } else if (CFEqual(iclass
, kSecClassGenericPassword
)) {
79 kSecAttrAccessible
, kAccessabilityItemAttr
,
80 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
81 kSecAttrCreationDate
, kDateItemAttr
,
82 kSecAttrModificationDate
, kDateItemAttr
,
83 kSecAttrDescription
, kStringItemAttr
,
84 kSecAttrComment
, kStringItemAttr
,
85 kSecAttrCreator
, kNumberItemAttr
,
86 kSecAttrType
, kNumberItemAttr
,
87 kSecAttrLabel
, kStringItemAttr
,
88 kSecAttrIsInvisible
, kBoolItemAttr
,
89 kSecAttrIsNegative
, kBoolItemAttr
,
90 kSecAttrAccount
, kStringItemAttr
,
91 kSecAttrService
, kStringItemAttr
,
92 kSecAttrGeneric
, kDataItemAttr
,
93 kSecAttrSynchronizable
, kBoolItemAttr
,
95 } else if (CFEqual(iclass
, kSecClassInternetPassword
)) {
97 kSecAttrAccessible
, kAccessabilityItemAttr
,
98 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
99 kSecAttrCreationDate
, kDateItemAttr
,
100 kSecAttrModificationDate
, kDateItemAttr
,
101 kSecAttrDescription
, kStringItemAttr
,
102 kSecAttrComment
, kStringItemAttr
,
103 kSecAttrCreator
, kNumberItemAttr
,
104 kSecAttrType
, kNumberItemAttr
,
105 kSecAttrLabel
, kStringItemAttr
,
106 kSecAttrIsInvisible
, kBoolItemAttr
,
107 kSecAttrIsNegative
, kBoolItemAttr
,
108 kSecAttrAccount
, kStringItemAttr
,
109 kSecAttrSecurityDomain
, kStringItemAttr
,
110 kSecAttrServer
, kStringItemAttr
,
111 kSecAttrProtocol
, kNumberItemAttr
,
112 kSecAttrAuthenticationType
, kNumberItemAttr
,
113 kSecAttrPort
, kNumberItemAttr
,
114 kSecAttrPath
, kStringItemAttr
,
115 kSecAttrSynchronizable
, kBoolItemAttr
,
117 } else if (CFEqual(iclass
, kSecClassCertificate
)) {
119 kSecAttrAccessible
, kAccessabilityItemAttr
,
120 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
121 kSecAttrCertificateType
, kNumberItemAttr
,
122 kSecAttrCertificateEncoding
, kNumberItemAttr
,
123 kSecAttrLabel
, kStringItemAttr
,
124 kSecAttrSubject
, kDataItemAttr
,
125 kSecAttrIssuer
, kDataItemAttr
,
126 kSecAttrSerialNumber
, kDataItemAttr
,
127 kSecAttrSubjectKeyID
, kDataItemAttr
,
128 kSecAttrPublicKeyHash
, kDataItemAttr
,
129 kSecAttrSynchronizable
, kBoolItemAttr
,
131 } else if (CFEqual(iclass
, kSecClassKey
)) {
133 kSecAttrAccessible
, kAccessabilityItemAttr
,
134 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
135 kSecAttrKeyClass
, kStringItemAttr
, // Might be Number on replies
136 kSecAttrLabel
, kStringItemAttr
,
137 kSecAttrApplicationLabel
, kDataItemAttr
,
138 kSecAttrIsPermanent
, kBoolItemAttr
,
139 kSecAttrApplicationTag
, kDataItemAttr
,
140 kSecAttrKeyType
, kNumberItemAttr
,
141 kSecAttrKeySizeInBits
, kNumberItemAttr
,
142 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
143 kSecAttrCanEncrypt
, kBoolItemAttr
,
144 kSecAttrCanDecrypt
, kBoolItemAttr
,
145 kSecAttrCanDerive
, kBoolItemAttr
,
146 kSecAttrCanSign
, kBoolItemAttr
,
147 kSecAttrCanVerify
, kBoolItemAttr
,
148 kSecAttrCanWrap
, kBoolItemAttr
,
149 kSecAttrCanUnwrap
, kBoolItemAttr
,
150 kSecAttrStartDate
, kDateItemAttr
,
151 kSecAttrEndDate
, kDateItemAttr
,
152 kSecAttrSynchronizable
, kBoolItemAttr
,
154 } else if (CFEqual(iclass
, kSecClassIdentity
)) {
156 kSecAttrAccessible
, kAccessabilityItemAttr
,
157 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
158 kSecAttrCertificateType
, kNumberItemAttr
,
159 kSecAttrCertificateEncoding
, kNumberItemAttr
,
160 kSecAttrLabel
, kStringItemAttr
,
161 kSecAttrSubject
, kDataItemAttr
,
162 kSecAttrIssuer
, kDataItemAttr
,
163 kSecAttrSerialNumber
, kDataItemAttr
,
164 kSecAttrSubjectKeyID
, kDataItemAttr
,
165 kSecAttrPublicKeyHash
, kDataItemAttr
,
166 kSecAttrKeyClass
, kStringItemAttr
, // Might be Number on replies
167 kSecAttrApplicationLabel
, kDataItemAttr
,
168 kSecAttrIsPermanent
, kBoolItemAttr
,
169 kSecAttrApplicationTag
, kDataItemAttr
,
170 kSecAttrKeyType
, kNumberItemAttr
,
171 kSecAttrKeySizeInBits
, kNumberItemAttr
,
172 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
173 kSecAttrCanEncrypt
, kBoolItemAttr
,
174 kSecAttrCanDecrypt
, kBoolItemAttr
,
175 kSecAttrCanDerive
, kBoolItemAttr
,
176 kSecAttrCanSign
, kBoolItemAttr
,
177 kSecAttrCanVerify
, kBoolItemAttr
,
178 kSecAttrCanWrap
, kBoolItemAttr
,
179 kSecAttrCanUnwrap
, kBoolItemAttr
,
180 kSecAttrStartDate
, kDateItemAttr
,
181 kSecAttrEndDate
, kDateItemAttr
,
182 kSecAttrSynchronizable
, kBoolItemAttr
,
188 static void ItemForEachPKAttr(CFMutableDictionaryRef item
, void(^each
)(CFStringRef attr
, enum ItemAttrType atype
)) {
189 CFStringRef iclass
= CFDictionaryGetValue(item
, kSecClass
);
192 } else if (CFEqual(iclass
, kSecClassGenericPassword
)) {
194 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
195 kSecAttrAccount
, kStringItemAttr
,
196 kSecAttrService
, kStringItemAttr
,
197 kSecAttrSynchronizable
, kBoolItemAttr
,
199 } else if (CFEqual(iclass
, kSecClassInternetPassword
)) {
201 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
202 kSecAttrAccount
, kStringItemAttr
,
203 kSecAttrSecurityDomain
, kStringItemAttr
,
204 kSecAttrServer
, kStringItemAttr
,
205 kSecAttrProtocol
, kNumberItemAttr
,
206 kSecAttrAuthenticationType
, kNumberItemAttr
,
207 kSecAttrPort
, kNumberItemAttr
,
208 kSecAttrPath
, kStringItemAttr
,
209 kSecAttrSynchronizable
, kBoolItemAttr
,
211 } else if (CFEqual(iclass
, kSecClassCertificate
)) {
213 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
214 kSecAttrCertificateType
, kNumberItemAttr
,
215 kSecAttrIssuer
, kDataItemAttr
,
216 kSecAttrSerialNumber
, kDataItemAttr
,
217 kSecAttrSynchronizable
, kBoolItemAttr
,
219 } else if (CFEqual(iclass
, kSecClassKey
)) {
221 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
222 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
223 kSecAttrApplicationLabel
, kDataItemAttr
,
224 kSecAttrApplicationTag
, kDataItemAttr
,
225 kSecAttrKeyType
, kNumberItemAttr
,
226 kSecAttrKeySizeInBits
, kNumberItemAttr
,
227 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
228 kSecAttrStartDate
, kDateItemAttr
,
229 kSecAttrEndDate
, kDateItemAttr
,
230 kSecAttrSynchronizable
, kBoolItemAttr
,
232 } else if (CFEqual(iclass
, kSecClassIdentity
)) {
234 kSecAttrAccessGroup
, kAccessGroupItemAttr
,
235 kSecAttrCertificateType
, kNumberItemAttr
,
236 kSecAttrIssuer
, kDataItemAttr
,
237 kSecAttrSerialNumber
, kDataItemAttr
,
238 kSecAttrSynchronizable
, kBoolItemAttr
,
239 kSecAttrKeyClass
, kStringItemAttr
, // kNumberItemAttr on replies
240 kSecAttrApplicationLabel
, kDataItemAttr
,
241 kSecAttrApplicationTag
, kDataItemAttr
,
242 kSecAttrKeyType
, kNumberItemAttr
,
243 kSecAttrKeySizeInBits
, kNumberItemAttr
,
244 kSecAttrEffectiveKeySize
, kNumberItemAttr
,
245 kSecAttrStartDate
, kDateItemAttr
,
246 kSecAttrEndDate
, kDateItemAttr
,
247 kSecAttrSynchronizable
, kBoolItemAttr
,
252 static CFMutableDictionaryRef
ItemCreate(int num
) {
253 CFStringRef iclass
= NULL
;
256 iclass
= kSecClassInternetPassword
;
259 iclass
= kSecClassGenericPassword
;
262 iclass
= kSecClassKey
;
265 iclass
= kSecClassCertificate
;
268 return CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault
, kSecClass
, iclass
, NULL
);
271 /* Test add api in all it's variants. */
272 static void tests(void)
274 for (int num
= 0 ; num
< 8; ++num
) {
275 CFMutableDictionaryRef item
= ItemCreate(num
);
276 ItemForEachPKAttr(item
, ^(CFStringRef attr
, enum ItemAttrType atype
) {
277 CFTypeRef value
= NULL
;
280 value
= (num
% 2 == 0 ? kCFBooleanTrue
: kCFBooleanFalse
);
283 case kNumberItemAttr
:
284 value
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &num
);
286 case kStringItemAttr
:
288 value
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("string-%d"), num
);
293 int len
= snprintf(buf
, sizeof(buf
), "data-%d", num
);
294 value
= CFDataCreate(kCFAllocatorDefault
, (const UInt8
*)buf
, len
);
298 value
= NULL
; // Don't mess with dates on create.
300 case kAccessabilityItemAttr
:
302 CFStringRef accessabilites
[] = {
303 kSecAttrAccessibleWhenUnlocked
,
304 kSecAttrAccessibleAfterFirstUnlock
,
305 kSecAttrAccessibleAlwaysPrivate
,
306 kSecAttrAccessibleWhenUnlockedThisDeviceOnly
,
307 kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
,
308 kSecAttrAccessibleAlwaysThisDeviceOnlyPrivate
,
310 value
= accessabilites
[num
% array_size(accessabilites
)];
313 case kAccessGroupItemAttr
:
315 CFStringRef accessGroups
[] = {
321 CFSTR("lockdown-identities"),
325 CFSTR("com.apple.security.sos"), // Secd internally uses this
327 CFSTR("com.apple.security.regressions"), // SecurityTestApp is in this group.
330 value
= accessGroups
[num
% array_size(accessGroups
)];
335 CFDictionarySetValue(item
, attr
, value
);
336 CFReleaseSafe(value
);
339 CFDictionarySetValue(item
, kSecAttrSynchronizable
, kCFBooleanTrue
);
340 ok_status(SecItemAdd(item
, NULL
), "add sync");
342 // No tombstones by default per rdar://14680869, so explicitly add one
343 CFDictionarySetValue(item
, kSecUseTombstones
, kCFBooleanTrue
);
344 ok_status(SecItemDelete(item
), "delete sync");
346 CFDictionarySetValue(item
, kSecAttrTombstone
, kCFBooleanTrue
);
347 ok_status(SecItemCopyMatching(item
, NULL
), "find tombstone after delete sync");
348 ok_status(SecItemDelete(item
), "delete sync tombstone");
349 CFDictionaryRemoveValue(item
, kSecAttrTombstone
);
351 ok_status(SecItemAdd(item
, NULL
), "add sync again");
353 CFDictionarySetValue(item
, kSecUseTombstones
, kCFBooleanFalse
);
354 ok_status(SecItemDelete(item
), "delete sync without leaving a tombstone behind");
355 CFDictionaryRemoveValue(item
, kSecUseTombstones
);
357 CFDictionarySetValue(item
, kSecAttrTombstone
, kCFBooleanTrue
);
358 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find tombstone after delete sync with kSecUseTombstones=false");
360 CFDictionaryRemoveValue(item
, kSecAttrSynchronizable
);
361 ok_status(SecItemAdd(item
, NULL
), "add local");
362 ok_status(SecItemDelete(item
), "delete local");
364 CFDictionarySetValue(item
, kSecAttrTombstone
, kCFBooleanTrue
);
365 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find tombstone after delete local");
366 is_status(SecItemDelete(item
), errSecItemNotFound
, "do not delete tombstone after delete local");
367 CFDictionaryRemoveValue(item
, kSecAttrTombstone
);
369 ok_status(SecItemAdd(item
, NULL
), "add local again");
371 CFDictionarySetValue(item
, kSecUseTombstones
, kCFBooleanTrue
);
372 ok_status(SecItemDelete(item
), "delete local and leave a tombstone behind");
373 CFDictionaryRemoveValue(item
, kSecUseTombstones
);
375 CFDictionarySetValue(item
, kSecAttrTombstone
, kCFBooleanTrue
);
376 ok_status(SecItemCopyMatching(item
, NULL
), "find tombstone after delete sync with kSecUseTombstones=true");
378 CFDictionarySetValue(item
, kSecUseTombstones
, kCFBooleanTrue
);
379 ok_status(SecItemDelete(item
), "delete local tombstone kSecUseTombstones=true");
380 CFDictionaryRemoveValue(item
, kSecUseTombstones
);
382 ok_status(SecItemCopyMatching(item
, NULL
), "find tombstone after delete local tombstone with kSecUseTombstones=true");
383 ok_status(SecItemDelete(item
), "delete local tombstone");
384 is_status(SecItemCopyMatching(item
, NULL
), errSecItemNotFound
, "do not find tombstone after delete local");
390 int si_12_item_stress(int argc
, char *const *argv
)