2 * Copyright (c) 2016 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 xLicense.
21 * @APPLE_LICENSE_HEADER_END@
24 #import <Security/Security.h>
25 #include "keychain_regressions.h"
26 #include "kc-helpers.h"
27 #include "kc-keychain-file-helpers.h"
28 #include "regressions/test/testenv.h"
30 // testKeychainXattrs.c
32 // Basic test of SecKeychainItemExtendedAttributes functionality
33 // to store arbitrary data in the extended attributes of a keychain
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <CoreServices/CoreServices.h>
39 #include <Security/Security.h>
40 #include <Security/SecKeychainItemExtendedAttributes.h> /* private */
47 #include <sys/param.h>
49 static int TestAddItems(SecKeychainRef keychain
)
53 SecKeychainItemRef item
= NULL
;
54 CFDataRef blob
= NULL
;
56 /* add generic password item */
57 status
= SecKeychainAddGenericPassword(keychain
,
58 strlen("Test Cloud Service 42"), "Test Cloud Service 42",
59 strlen("nobody"), "nobody",
60 strlen("weakpass"), "weakpass",
62 ok_status(status
, "%s: SecKeychainAddGenericPassword", testName
);
64 if (status
&& status
!= errSecDuplicateItem
) { // ignore error if duplicate
67 /* add an extended CFDataRef attribute to this item */
68 UInt8 buf1
[6] = { 's', 'e', 'c', 'r', 'e', 't' };
69 blob
= CFDataCreate(NULL
, buf1
, sizeof(buf1
));
70 status
= SecKeychainItemSetExtendedAttribute(item
, CFSTR("CloudyGoodness"), blob
);
71 ok_status(status
, "%s: SecKeychainItemSetExtendedAttribute (generic)", testName
);
85 /* add internet password item */
86 status
= SecKeychainAddInternetPassword(keychain
,
87 strlen("test42.icloud.com"), "test42.icloud.com",
89 strlen("nobody"), "nobody",
91 80, kSecProtocolTypeHTTP
, kSecAuthenticationTypeDefault
,
92 strlen("weakpass"), "weakpass",
94 ok_status(status
, "%s: SecKeychainAddInternetPassword", testName
);
95 if (status
&& status
!= errSecDuplicateItem
) { // ignore error if duplicate
98 /* add an extended CFDataRef attribute to this item */
99 UInt8 buf2
[5] = { 'm', 'a', 'g', 'i', 'c' };
100 blob
= CFDataCreate(NULL
, buf2
, sizeof(buf2
));
101 status
= SecKeychainItemSetExtendedAttribute(item
, CFSTR("CloudyGoodness"), blob
);
102 ok_status(status
, "%s: SecKeychainItemSetExtendedAttribute (internet)", testName
);
120 static int TestFindItems(SecKeychainRef keychain
)
124 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
125 CFArrayAppendValue((CFMutableArrayRef
)searchList
, keychain
);
127 /* find generic password we added previously */
129 const void *keys
[] = {
137 const void *values
[] = {
139 kSecClassGenericPassword
,
141 CFSTR("Test Cloud Service 42"),
146 OSStatus status
= noErr
;
147 CFTypeRef results
= NULL
;
148 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
,
149 sizeof(keys
) / sizeof(*keys
),
150 &kCFTypeDictionaryKeyCallBacks
,
151 &kCFTypeDictionaryValueCallBacks
);
153 status
= SecItemCopyMatching(query
, &results
);
154 ok_status(status
, "%s: SecItemCopyMatching (generic password)", testName
);
157 fprintf(stderr
, "Unable to find \"Test Cloud Service 42\" generic password: error %d\n", (int)status
);
161 /* found the item; since we asked for one item and a ref, this is a SecKeychainItemRef */
162 SecKeychainItemRef item
= (SecKeychainItemRef
) results
;
163 CFDataRef blob
= NULL
;
164 status
= SecKeychainItemCopyExtendedAttribute(item
, CFSTR("CloudyGoodness"), &blob
);
165 ok_status(status
, "%s: SecKeychainItemCopyExtendedAttribute", testName
);
168 fprintf(stderr
, "Unable to retrieve xattr from \"Test Cloud Service 42\" generic password: error %d\n", (int)status
);
172 const UInt8
*dataPtr
= CFDataGetBytePtr(blob
);
174 eq_stringn( (const char *) dataPtr
, strlen((const char *)dataPtr
), "secret", strlen("secret"), "%s: Retrieved xattr value matches expected value", testName
);
175 if (memcmp(dataPtr
, "secret", strlen("secret"))) {
189 /* find internet password we added previously */
191 const void *keys
[] = {
199 const void *values
[] = {
201 kSecClassInternetPassword
,
203 CFSTR("test42.icloud.com"),
208 OSStatus status
= noErr
;
209 CFTypeRef results
= NULL
;
210 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
,
211 sizeof(keys
) / sizeof(*keys
),
212 &kCFTypeDictionaryKeyCallBacks
,
213 &kCFTypeDictionaryValueCallBacks
);
215 status
= SecItemCopyMatching(query
, &results
);
216 ok_status(status
, "%s: SecItemCopyMatching (internet password)", testName
);
218 fprintf(stderr
, "Unable to find \"test42.icloud.com\" internet password: error %d\n", (int)status
);
222 /* found the item; since we asked for one item and a ref, this is a SecKeychainItemRef */
223 SecKeychainItemRef item
= (SecKeychainItemRef
) results
;
224 CFDataRef blob
= NULL
;
225 status
= SecKeychainItemCopyExtendedAttribute(item
, CFSTR("CloudyGoodness"), &blob
);
226 ok_status(status
, "%s: SecKeychainItemCopyExtendedAttribute", testName
);
228 fprintf(stderr
, "Unable to retrieve xattr from \"test42.icloud.com2\" internet password: error %d\n", (int)status
);
232 const UInt8
*dataPtr
= CFDataGetBytePtr(blob
);
233 eq_stringn( (const char *) dataPtr
, strlen((const char *)dataPtr
), "magic", strlen("magic"), "%s: Retrieved xattr value matches expected value", testName
);
235 if (memcmp(dataPtr
, "magic", strlen("magic"))) {
236 fprintf(stderr
, "Retrieved xattr value did not match expected value!\n");
253 static int TestDeleteItems(SecKeychainRef keychain
)
257 CFMutableArrayRef searchList
= (CFMutableArrayRef
) CFArrayCreateMutable(kCFAllocatorDefault
, 1, &kCFTypeArrayCallBacks
);
258 CFArrayAppendValue((CFMutableArrayRef
)searchList
, keychain
);
260 /* find generic password we added previously */
262 const void *keys
[] = {
270 const void *values
[] = {
272 kSecClassGenericPassword
,
274 CFSTR("Test Cloud Service 42"),
279 OSStatus status
= noErr
;
280 CFTypeRef results
= NULL
;
281 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
,
282 sizeof(keys
) / sizeof(*keys
),
283 &kCFTypeDictionaryKeyCallBacks
,
284 &kCFTypeDictionaryValueCallBacks
);
286 status
= SecItemCopyMatching(query
, &results
);
287 ok_status(status
, "%s: SecItemCopyMatching (Test Cloud Service 42)", testName
);
290 fprintf(stderr
, "Unable to find \"Test Cloud Service 42\" generic password: error %d\n", (int)status
);
294 /* found the item; since we asked for one item and a ref, this is a SecKeychainItemRef */
295 SecKeychainItemRef item
= (SecKeychainItemRef
) results
;
297 /* set the xattr to NULL in order to delete it */
298 status
= SecKeychainItemSetExtendedAttribute(item
, CFSTR("CloudyGoodness"), NULL
);
299 ok_status( status
, "%s: SecKeychainItemSetExtendedAttribute (generic password, null data)", testName
);
302 fprintf(stderr
, "Unable to remove xattr from \"Test Cloud Service 42\" generic password: error %d\n", (int)status
);
306 /* delete the item itself */
307 status
= SecKeychainItemDelete(item
);
308 ok_status(status
, "%s: SecKeychainItemDelete (generic password)", testName
);
311 fprintf(stderr
, "Unable to delete \"Test Cloud Service 42\" generic password: error %d\n", (int)status
);
322 /* find internet password we added previously */
324 const void *keys
[] = {
332 const void *values
[] = {
334 kSecClassInternetPassword
,
336 CFSTR("test42.icloud.com"),
341 OSStatus status
= noErr
;
342 CFTypeRef results
= NULL
;
343 CFDictionaryRef query
= CFDictionaryCreate(NULL
, keys
, values
,
344 sizeof(keys
) / sizeof(*keys
),
345 &kCFTypeDictionaryKeyCallBacks
,
346 &kCFTypeDictionaryValueCallBacks
);
348 status
= SecItemCopyMatching(query
, &results
);
349 ok_status(status
, "%s: SecItemCopyMatching (test42.icloud.com)", testName
);
352 fprintf(stderr
, "Unable to find \"test42.icloud.com\" internet password: error %d\n", (int)status
);
356 /* found the item; since we asked for one item and a ref, this is a SecKeychainItemRef */
357 SecKeychainItemRef item
= (SecKeychainItemRef
) results
;
359 /* set the xattr to NULL in order to delete it */
360 status
= SecKeychainItemSetExtendedAttribute(item
, CFSTR("CloudyGoodness"), NULL
);
361 ok_status( status
, "%s: SecKeychainItemSetExtendedAttribute (internet password, null data)", testName
);
364 fprintf(stderr
, "Unable to remove xattr from \"test42.icloud.com2\" internet password: error %d\n", (int)status
);
368 /* delete the item itself */
369 status
= SecKeychainItemDelete(item
);
370 ok_status(status
, "%s: SecKeychainItemDelete (generic password)", testName
);
373 fprintf(stderr
, "Unable to delete \"test42.icloud.com2\" internet password: error %d\n", (int)status
);
387 int kc_21_item_xattrs(int argc
, char *const *argv
)
390 initializeKeychainTests(__FUNCTION__
);
392 SecKeychainRef keychain
= getPopulatedTestKeychain();
394 TestAddItems(keychain
);
395 TestFindItems(keychain
);
396 TestDeleteItems(keychain
);
398 ok_status(SecKeychainDelete(keychain
), "%s: SecKeychainDelete", testName
);
399 CFReleaseNull(keychain
);
400 checkPrompts(0, "No prompts");