]> git.saurik.com Git - apple/security.git/blob - SecurityTests/regressions/kc/kc-20-item-change-label.m
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / regressions / kc / kc-20-item-change-label.m
1 //
2 // keychain_test.m
3 // Keychain item access control example
4 //
5 // Created by Perry Kiehtreiber on Wed Jun 19 2002
6 // Modified by Ken McLeod, Mon Apr 21 2003 -- added "always allow" ACL support
7 // Wed Jul 28 2004 -- add test code for persistent ref SPI
8 // Mon Aug 02 2004 -- add test code to change label attributes
9 //
10 // To build and run this example:
11 // cc -framework Security -framework Foundation keychain_test.m ; ./a.out
12 //
13 // Copyright (c) 2003-2005 Apple Computer, Inc. All Rights Reserved.
14 //
15
16 #define TEST_PERSISTENT_REFS 0
17 #define USE_SYSTEM_KEYCHAIN 0
18
19
20 #import <Cocoa/Cocoa.h>
21
22 #include <Security/SecBase.h>
23 #include <Security/SecKeychain.h>
24 #include <Security/SecKeychainItem.h>
25 #include <Security/SecKeychainItemPriv.h>
26 #include <Security/SecKeychainSearch.h>
27 #include <Security/SecAccess.h>
28 #include <Security/SecTrustedApplication.h>
29 #include <Security/SecACL.h>
30
31 #import "testmore.h"
32 #import "testenv.h"
33 #import "testleaks.h"
34
35 SecAccessRef createAccess(NSString *accessLabel, BOOL allowAny)
36 {
37 SecAccessRef access=nil;
38 NSArray *trustedApplications=nil;
39
40 if (!allowAny) // use default access ("confirm access")
41 {
42 // make an exception list of applications you want to trust, which
43 // are allowed to access the item without requiring user confirmation
44 SecTrustedApplicationRef myself, someOther;
45 ok_status(SecTrustedApplicationCreateFromPath(NULL, &myself),
46 "create trusted app for self");
47 ok_status(SecTrustedApplicationCreateFromPath("/Applications/Mail.app",
48 &someOther), "create trusted app for Mail.app");
49 trustedApplications = [NSArray arrayWithObjects:(id)myself,
50 (id)someOther, nil];
51 CFRelease(myself);
52 CFRelease(someOther);
53 }
54
55 ok_status(SecAccessCreate((CFStringRef)accessLabel,
56 (CFArrayRef)trustedApplications, &access), "SecAccessCreate");
57
58 if (allowAny)
59 {
60 // change access to be wide-open for decryption ("always allow access")
61 // get the access control list for decryption operations
62 CFArrayRef aclList=nil;
63 ok_status(SecAccessCopySelectedACLList(access,
64 CSSM_ACL_AUTHORIZATION_DECRYPT, &aclList),
65 "SecAccessCopySelectedACLList");
66
67 // get the first entry in the access control list
68 SecACLRef aclRef=(SecACLRef)CFArrayGetValueAtIndex(aclList, 0);
69 CFArrayRef appList=nil;
70 CFStringRef promptDescription=nil;
71 CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector;
72 ok_status(SecACLCopySimpleContents(aclRef, &appList,
73 &promptDescription, &promptSelector), "SecACLCopySimpleContents");
74
75 // modify the default ACL to not require the passphrase, and have a
76 // nil application list
77 promptSelector.flags &= ~CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE;
78 ok_status(SecACLSetSimpleContents(aclRef, NULL, promptDescription,
79 &promptSelector), "SecACLSetSimpleContents");
80
81 if (appList) CFRelease(appList);
82 if (promptDescription) CFRelease(promptDescription);
83 if (aclList) CFRelease(aclList);
84 }
85
86 return access;
87 }
88
89
90 void addApplicationPassword(SecKeychainRef keychain, NSString *password,
91 NSString *account, NSString *service, BOOL allowAny)
92 {
93 SecKeychainItemRef item = nil;
94 const char *serviceUTF8 = [service UTF8String];
95 const char *accountUTF8 = [account UTF8String];
96 const char *passwordUTF8 = [password UTF8String];
97 // use the service string as the name of this item for display purposes
98 NSString *itemLabel = service;
99 const char *itemLabelUTF8 = [itemLabel UTF8String];
100
101 #if USE_SYSTEM_KEYCHAIN
102 const char *sysKeychainPath = "/Library/Keychains/System.keychain";
103 status = SecKeychainOpen(sysKeychainPath, &keychain);
104 if (status) { NSLog(@"SecKeychainOpen returned %d", status); return; }
105 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
106 if (status) { NSLog(@"SecKeychainSetPreferenceDomain returned %d", status); return; }
107 #endif
108
109 // create initial access control settings for the item
110 SecAccessRef access = createAccess(itemLabel, allowAny);
111
112 // Below is the lower-layer equivalent to the
113 // SecKeychainAddGenericPassword() function; it does the same thing
114 // (except specify the access controls) set up attribute vector
115 // (each attribute consists of {tag, length, pointer})
116 SecKeychainAttribute attrs[] = {
117 { kSecLabelItemAttr, strlen(itemLabelUTF8), (char *)itemLabelUTF8 },
118 { kSecAccountItemAttr, strlen(accountUTF8), (char *)accountUTF8 },
119 { kSecServiceItemAttr, strlen(serviceUTF8), (char *)serviceUTF8 }
120 };
121 SecKeychainAttributeList attributes =
122 { sizeof(attrs) / sizeof(attrs[0]), attrs };
123
124 ok_status(SecKeychainItemCreateFromContent(kSecGenericPasswordItemClass,
125 &attributes, strlen(passwordUTF8), passwordUTF8, keychain, access,
126 &item), "SecKeychainItemCreateFromContent");
127
128 if (access) CFRelease(access);
129 if (item) CFRelease(item);
130 }
131
132
133 void addInternetPassword(SecKeychainRef keychain, NSString *password,
134 NSString *account, NSString *server, NSString *path,
135 SecProtocolType protocol, int port, BOOL allowAny)
136 {
137 SecKeychainItemRef item = nil;
138 const char *pathUTF8 = [path UTF8String];
139 const char *serverUTF8 = [server UTF8String];
140 const char *accountUTF8 = [account UTF8String];
141 const char *passwordUTF8 = [password UTF8String];
142 // use the server string as the name of this item for display purposes
143 NSString *itemLabel = server;
144 const char *itemLabelUTF8 = [itemLabel UTF8String];
145
146 #if USE_SYSTEM_KEYCHAIN
147 const char *sysKeychainPath = "/Library/Keychains/System.keychain";
148 status = SecKeychainOpen(sysKeychainPath, &keychain);
149 if (status) { NSLog(@"SecKeychainOpen returned %d", status); return 1; }
150 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
151 if (status) { NSLog(@"SecKeychainSetPreferenceDomain returned %d", status); return 1; }
152 #endif
153
154 // create initial access control settings for the item
155 SecAccessRef access = createAccess(itemLabel, allowAny);
156
157 // below is the lower-layer equivalent to the
158 // SecKeychainAddInternetPassword() function; it does the same
159 // thing (except specify the access controls) set up attribute
160 // vector (each attribute consists of {tag, length, pointer})
161 SecKeychainAttribute attrs[] = {
162 { kSecLabelItemAttr, strlen(itemLabelUTF8), (char *)itemLabelUTF8 },
163 { kSecAccountItemAttr, strlen(accountUTF8), (char *)accountUTF8 },
164 { kSecServerItemAttr, strlen(serverUTF8), (char *)serverUTF8 },
165 { kSecPortItemAttr, sizeof(int), (int *)&port },
166 { kSecProtocolItemAttr, sizeof(SecProtocolType),
167 (SecProtocolType *)&protocol },
168 { kSecPathItemAttr, strlen(pathUTF8), (char *)pathUTF8 }
169 };
170 SecKeychainAttributeList attributes =
171 { sizeof(attrs) / sizeof(attrs[0]), attrs };
172
173 ok_status(SecKeychainItemCreateFromContent(kSecInternetPasswordItemClass,
174 &attributes, strlen(passwordUTF8), passwordUTF8, keychain, access,
175 &item), "SecKeychainItemCreateFromContent");
176
177 //*** code to test persistent reference SPI
178 #if TEST_PERSISTENT_REFS
179 CFDataRef persistentRef = NULL;
180 SecKeychainItemRef item2 = NULL;
181 status = SecKeychainItemCopyPersistentReference(item, &persistentRef);
182 if (!status)
183 {
184 NSLog(@"Created persistent reference for item %@:\n%@", item,
185 persistentRef);
186 status = SecKeychainItemFromPersistentReference(persistentRef, &item2);
187 if (!status)
188 NSLog(@"SUCCESS: Got item from persistent reference (%@)", item2);
189 else
190 NSLog(@"ERROR: unable to reconsitute item (%d)", status);
191 }
192 else
193 {
194 NSLog(@"ERROR: unable to create persistent reference (%d)", status);
195 }
196 //[(NSData*)pref writeToFile:@"/tmp/persistentData" atomically:YES];
197 if (item2) CFRelease(item2);
198 if (persistentRef) CFRelease(persistentRef);
199 #endif
200 //*** end persistent reference test code
201
202 if (access) CFRelease(access);
203 if (item) CFRelease(item);
204 }
205
206 void testLabelChange(SecKeychainRef keychain)
207 {
208 // Find each generic password item in any keychain whose label
209 // is "sample service", and modify the existing label attribute
210 // by adding a " [label]" suffix. (Note that if the Keychain
211 // Access app is running, you may need to quit and relaunch it to
212 // see the changes, due to notification bugs.)
213
214 const char *searchString = "sample service";
215 const char *labelSuffix = " [label]";
216
217 #if USE_SYSTEM_KEYCHAIN
218 const char *sysKeychainPath = "/Library/Keychains/System.keychain";
219 status = SecKeychainOpen(sysKeychainPath, &keychain);
220 if (status) { NSLog(@"SecKeychainOpen returned %d", status); return 0; }
221 status = SecKeychainSetPreferenceDomain(kSecPreferencesDomainSystem);
222 if (status) { NSLog(@"SecKeychainSetPreferenceDomain returned %d", status); return 0; }
223 #endif
224
225 SecKeychainSearchRef searchRef = nil;
226 SecKeychainAttribute sAttrs[] =
227 { { kSecServiceItemAttr, strlen(searchString), (char*)searchString } };
228 SecKeychainAttributeList sAttrList =
229 { sizeof(sAttrs) / sizeof(sAttrs[0]), sAttrs };
230 ok_status(SecKeychainSearchCreateFromAttributes(keychain,
231 kSecGenericPasswordItemClass, &sAttrList, &searchRef),
232 "SecKeychainSearchCreateFromAttributes");
233
234 SecKeychainItemRef foundItemRef = NULL;
235 int count;
236 for (count = 0; count < 2; ++count)
237 {
238 ok_status(SecKeychainSearchCopyNext(searchRef, &foundItemRef),
239 "SecKeychainSearchCopyNext");
240
241 // get the item's label attribute (allocated for us by
242 // SecKeychainItemCopyContent, must free later...)
243 SecKeychainAttribute itemAttrs[] = { { kSecLabelItemAttr, 0, NULL } };
244 SecKeychainAttributeList itemAttrList =
245 { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
246
247 ok_status(SecKeychainItemCopyContent(foundItemRef, NULL, &itemAttrList,
248 NULL, NULL), "get label");
249
250 // malloc enough space to hold our new label string
251 // (length = old label string + suffix string + terminating NULL)
252 CFIndex newLen = itemAttrs[0].length + strlen(labelSuffix);
253 char *p = (char*) malloc(newLen);
254 memcpy(p, itemAttrs[0].data, itemAttrs[0].length);
255 memcpy(p + itemAttrs[0].length, labelSuffix, strlen(labelSuffix));
256
257 // set up the attribute we want to change with its new value
258 SecKeychainAttribute newAttrs[] = { { kSecLabelItemAttr, newLen, p } };
259 SecKeychainAttributeList newAttrList =
260 { sizeof(newAttrs) / sizeof(newAttrs[0]), newAttrs };
261
262 // modify the attribute
263 ok_status(SecKeychainItemModifyContent(foundItemRef, &newAttrList,
264 0, NULL), "modify label PR-3751523");
265
266 // free the memory we allocated for the new label string
267 free(p);
268
269 // free the memory in the itemAttrList structure which was
270 // allocated by SecKeychainItemCopyContent
271 ok_status(SecKeychainItemFreeContent(&itemAttrList, NULL),
272 "SecKeychainItemFreeContent");
273
274 if (foundItemRef)
275 CFRelease(foundItemRef);
276 }
277
278 is_status(SecKeychainSearchCopyNext(searchRef, &foundItemRef),
279 errSecItemNotFound, "SecKeychainSearchCopyNext at end");
280
281 if (searchRef) CFRelease(searchRef);
282 }
283
284 void tests(void)
285 {
286 SecKeychainRef keychain = NULL;
287 ok_status(SecKeychainCreate("login.keychain", 4, "test", NO, NULL,
288 &keychain), "SecKeychainCreate");
289
290 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
291
292 // add some example passwords to the keychain
293 addApplicationPassword(keychain, @"sample password",
294 @"sample account", @"sample service", NO);
295 addApplicationPassword(keychain, @"sample password",
296 @"different account", @"sample service", NO);
297 addApplicationPassword(keychain, @"sample password",
298 @"sample account", @"sample unprotected service", YES);
299 addInternetPassword(keychain, @"sample password",
300 @"sample account", @"samplehost.apple.com",
301 @"cgi-bin/bogus/testpath", kSecProtocolTypeHTTP, 8080, NO);
302
303 // test searching and changing item label attributes
304 testLabelChange(keychain);
305
306 [pool release];
307
308 SKIP: {
309 skip("no keychain", 1, keychain);
310 ok_status(SecKeychainDelete(keychain), "SecKeychainDelete");
311 CFRelease(keychain);
312 }
313
314 tests_end(1);
315 }
316
317 int main(int argc, char * const *argv)
318 {
319 plan_tests(30);
320 tests_begin(argc, argv);
321
322 tests();
323
324 ok_leaks("leaks");
325
326 return 0;
327 }