]> git.saurik.com Git - apple/security.git/blob - SecurityServer/tests/testacls.cpp
Security-28.tar.gz
[apple/security.git] / SecurityServer / tests / testacls.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // testacls - ACL-related test cases.
21 //
22 #include "testclient.h"
23 #include "testutils.h"
24 #include <Security/osxsigner.h>
25
26 using namespace CodeSigning;
27
28
29 //
30 // ACL get/set tests
31 //
32 void acls()
33 {
34 printf("* Basic ACL tests\n");
35 CssmAllocator &alloc = CssmAllocator::standard();
36 ClientSession ss(alloc, alloc);
37
38 // create key with initial ACL
39 StringData initialAclPassphrase("very secret");
40 AclEntryPrototype initialAcl;
41 initialAcl.TypedSubject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
42 new(alloc) ListElement(initialAclPassphrase));
43 AclEntryInput initialAclInput(initialAcl);
44 AclTester tester(ss, &initialAclInput);
45
46 // get the owner and verify
47 AclOwnerPrototype owner;
48 ss.getKeyOwner(tester.keyRef, owner);
49 assert(owner.subject().type() == CSSM_ACL_SUBJECT_TYPE_PASSWORD);
50 assert(owner.subject().length() == 1);
51
52 // get the acl entry and verify
53 {
54 uint32 count;
55 AclEntryInfo *acls;
56 ss.getKeyAcl(tester.keyRef, NULL/*tag*/, count, acls);
57 assert(count == 1);
58 const AclEntryInfo &acl1 = acls[0];
59 const TypedList &subject1 = acl1.proto().subject();
60 assert(subject1.type() == CSSM_ACL_SUBJECT_TYPE_PASSWORD);
61 assert(subject1.length() == 1);
62 }
63
64 // try to use the key and see...
65 tester.testWrap(&nullCred, "ACCEPTING NULL CREDENTIAL");
66 AutoCredentials cred(alloc);
67 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
68 new(alloc) ListElement(StringData("wrongo")));
69 tester.testWrap(&cred, "ACCEPTING WRONG PASSWORD CREDENTIAL");
70 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
71 new(alloc) ListElement(StringData("very secret")));
72 tester.testWrap(&cred);
73
74 // now *replace* the ACL entry with a new one...
75 {
76 detail("Changing ACL");
77 uint32 count;
78 AclEntryInfo *infos;
79 ss.getKeyAcl(tester.keyRef, NULL, count, infos);
80 assert(count == 1); // one entry
81
82 AclEntryPrototype newAcl;
83 TypedList subject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_THRESHOLD,
84 new(alloc) ListElement(2), new(alloc) ListElement(3));
85 subject += new(alloc) ListElement(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
86 new(alloc) ListElement(alloc, "check me!")));
87 subject += new(alloc) ListElement(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
88 new(alloc) ListElement(alloc, "once again!")));
89 subject += new(alloc) ListElement(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
90 new(alloc) ListElement(alloc, "hug me!")));
91 newAcl.TypedSubject = subject;
92 AclEntryInput input(newAcl);
93 AclEdit edit(infos[0].handle(), input);
94
95 try {
96 AutoCredentials nullCred(alloc);
97 ss.changeKeyAcl(tester.keyRef, nullCred, edit);
98 error("ALLOWED ACL EDIT WITHOUT CREDENTIALS");
99 } catch (CssmCommonError &err) {
100 detail(err, "Acl Edit rejected properly");
101 }
102 ss.changeKeyAcl(tester.keyRef, cred, edit);
103 detail("ACL changed OK");
104 }
105
106 // ... and see how the new one reacts
107 tester.testWrap(&nullCred, "ACCEPTING NULL CREDENTIALS NOW");
108 tester.testWrap(&cred, "ACCEPTING OLD CREDENTIALS FOR NEW ACL");
109 {
110 AutoCredentials cred(alloc);
111 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
112 new(alloc) ListElement(alloc, "check me!"));
113 tester.testWrap(&cred, "ACCEPTING LEAF SAMPLE WITHOUT THRESHOLD FRAMEWORK");
114 }
115
116 // Threshold subjects
117 {
118 detail("Testing threshold ACLs");
119 AutoCredentials cred(alloc);
120 TypedList &threshold = cred += TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD,
121 new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
122 new(alloc) ListElement(alloc, "wrongo!")))
123 );
124 tester.testWrap(&cred, "ACCEPTING ALL WRONG SAMPLES IN THRESHOLD");
125 threshold += new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
126 new(alloc) ListElement(alloc, "hug me!")));
127 tester.testWrap(&cred, "ACCEPTING TOO FEW THRESHOLD SAMPLES");
128 threshold += new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
129 new(alloc) ListElement(alloc, "check me!")));
130 tester.testWrap(&cred);
131 // stuff the ballot box
132 threshold += new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
133 new(alloc) ListElement(alloc, "and this!")));
134 threshold += new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
135 new(alloc) ListElement(alloc, "and that!")));
136 threshold += new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
137 new(alloc) ListElement(alloc, "and more!")));
138 #ifdef STRICT_THRESHOLD_SUBJECTS
139 tester.testWrap(&cred, "ACCEPTING OVER-STUFFED THRESHOLD");
140 #else
141 tester.testWrap(&cred);
142 #endif //STRICT_THRESHOLD_SUBJECTS
143 }
144
145 // comment ACLs and tags
146 {
147 detail("Adding Comment entry");
148
149 AclEntryPrototype newAcl;
150 TypedList subject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_COMMENT,
151 new(alloc) ListElement(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_THRESHOLD,
152 new(alloc) ListElement(alloc, "Robby Ray!"))),
153 new(alloc) ListElement(666));
154 newAcl.TypedSubject = subject;
155 strcpy(newAcl.EntryTag, "vamos");
156 AclEntryInput input(newAcl);
157 AclEdit edit(input);
158 ss.changeKeyAcl(tester.keyRef, cred, edit);
159 detail("Entry added");
160
161 uint32 count;
162 AclEntryInfo *infos;
163 ss.getKeyAcl(tester.keyRef, "vamos", count, infos);
164 assert(count == 1); // one entry (with this tag)
165 const AclEntryInfo &acl = infos[0];
166 const TypedList &read = acl.proto().subject();
167 assert(read.type() == CSSM_ACL_SUBJECT_TYPE_COMMENT);
168 assert(read.length() == 3);
169 assert(read[2] == 666);
170 CssmList &sublist = read[1];
171 assert(sublist[0] == CSSM_ACL_SUBJECT_TYPE_THRESHOLD);
172 assert(string(sublist[1]) == "Robby Ray!");
173
174 detail("Comment entry retrieved okay");
175 }
176 }
177
178
179 //
180 // ACL authorization tests
181 //
182 void authAcls()
183 {
184 printf("* ACL authorizations test\n");
185 CssmAllocator &alloc = CssmAllocator::standard();
186 ClientSession ss(alloc, alloc);
187
188 // create key with initial ACL
189 CSSM_ACL_AUTHORIZATION_TAG wrapTag = CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR;
190 CSSM_ACL_AUTHORIZATION_TAG encryptTag = CSSM_ACL_AUTHORIZATION_ENCRYPT;
191 StringData initialAclPassphrase("very secret");
192 StringData the2ndAclPassword("most secret");
193 AclEntryPrototype initialAcl;
194 initialAcl.TypedSubject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
195 new(alloc) ListElement(initialAclPassphrase));
196 initialAcl.authorization().NumberOfAuthTags = 1;
197 initialAcl.authorization().AuthTags = &wrapTag;
198 AclEntryInput initialAclInput(initialAcl);
199 AclTester tester(ss, &initialAclInput);
200
201 // get the owner and verify
202 AclOwnerPrototype owner;
203 ss.getKeyOwner(tester.keyRef, owner);
204 assert(owner.subject().type() == CSSM_ACL_SUBJECT_TYPE_PASSWORD);
205 assert(owner.subject().length() == 1);
206
207 // get the acl entry and verify
208 {
209 uint32 count;
210 AclEntryInfo *acls;
211 ss.getKeyAcl(tester.keyRef, NULL/*tag*/, count, acls);
212 assert(count == 1);
213 const AclEntryInfo &acl1 = acls[0];
214 const TypedList &subject1 = acl1.proto().subject();
215 assert(subject1.type() == CSSM_ACL_SUBJECT_TYPE_PASSWORD);
216 assert(subject1.length() == 1);
217 const AuthorizationGroup &auths = acl1.proto().authorization();
218 assert(auths.count() == 1);
219 assert(auths[0] == CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR);
220 }
221
222 // try to use the key and see...
223 tester.testWrap(&nullCred, "ACCEPTING NULL CREDENTIAL");
224 AutoCredentials cred(alloc);
225 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
226 new(alloc) ListElement(StringData("wrongo")));
227 tester.testWrap(&cred, "ACCEPTING WRONG PASSWORD CREDENTIAL");
228 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
229 new(alloc) ListElement(initialAclPassphrase));
230 tester.testWrap(&cred);
231
232 tester.testEncrypt(&nullCred, "ACCEPTING NULL CREDENTIAL FOR UNAUTHORIZED OPERATION");
233 tester.testEncrypt(&cred, "ACCEPTING GOOD CREDENTIAL FOR UNAUTHORIZED OPERATION");
234
235 // now *add* a new ACL entry for encryption
236 {
237 detail("Adding new ACL entry");
238
239 AclEntryPrototype newAcl;
240 newAcl.TypedSubject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
241 new(alloc) ListElement(the2ndAclPassword));
242 newAcl.authorization().NumberOfAuthTags = 1;
243 newAcl.authorization().AuthTags = &encryptTag;
244 AclEntryInput newInput(newAcl);
245 AclEdit edit(newInput);
246
247 try {
248 AutoCredentials nullCred(alloc);
249 ss.changeKeyAcl(tester.keyRef, nullCred, edit);
250 error("ALLOWED ACL EDIT WITHOUT CREDENTIALS");
251 } catch (CssmCommonError &err) {
252 detail(err, "Acl Edit rejected properly");
253 }
254 ss.changeKeyAcl(tester.keyRef, cred, edit);
255 detail("ACL changed OK");
256
257 // read it back and check
258 {
259 uint32 count;
260 AclEntryInfo *acls;
261 ss.getKeyAcl(tester.keyRef, NULL/*tag*/, count, acls);
262 assert(count == 2);
263 const AclEntryInfo &acl1 = acls[0];
264 const TypedList &subject1 = acl1.proto().subject();
265 assert(subject1.type() == CSSM_ACL_SUBJECT_TYPE_PASSWORD);
266 assert(subject1.length() == 1);
267 const AuthorizationGroup &auths1 = acl1.proto().authorization();
268 assert(auths1.count() == 1);
269 assert(auths1[0] == CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR);
270 const AclEntryInfo &acl2 = acls[1];
271 const TypedList &subject2 = acl2.proto().subject();
272 assert(subject2.type() == CSSM_ACL_SUBJECT_TYPE_PASSWORD);
273 assert(subject2.length() == 1);
274 const AuthorizationGroup &auths2 = acl2.proto().authorization();
275 assert(auths2.count() == 1);
276 assert(auths2[0] == CSSM_ACL_AUTHORIZATION_ENCRYPT);
277 }
278 }
279
280 // ... and see how the new composite ACL behaves
281 AutoCredentials cred2(alloc);
282 cred2 += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
283 new(alloc) ListElement(the2ndAclPassword));
284 tester.testWrap(&nullCred, "ACCEPTING NULL CREDENTIALS FOR WRAPPING");
285 tester.testEncrypt(&nullCred, "ACCEPTING NULL CREDENTIALS FOR ENCRYPTION");
286 tester.testWrap(&cred); // "very secret" allows wrapping
287 tester.testEncrypt(&cred2); // "most secret" allows encrypting
288 tester.testWrap(&cred2, "ACCEPTING ENCRYPT CRED FOR WRAPPING");
289 tester.testEncrypt(&cred, "ACCEPTING WRAP CRED FOR ENCRYPTING");
290 }
291
292
293 //
294 // Keychain ACL subjects
295 //
296 void keychainAcls()
297 {
298 printf("* Keychain (interactive) ACL test\n");
299 CssmAllocator &alloc = CssmAllocator::standard();
300 ClientSession ss(alloc, alloc);
301
302 // create key with initial ACL
303 AclEntryPrototype initialAcl;
304 initialAcl.TypedSubject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT,
305 new(alloc) ListElement(alloc, "Test Key"));
306 AclEntryInput initialAclInput(initialAcl);
307 AclTester tester(ss, &initialAclInput);
308
309 // get the owner and verify
310 AclOwnerPrototype owner;
311 ss.getKeyOwner(tester.keyRef, owner);
312 assert(owner.subject().type() == CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT);
313 assert(owner.subject().length() == 2);
314
315 // get the acl entry and verify
316 {
317 uint32 count;
318 AclEntryInfo *acls;
319 ss.getKeyAcl(tester.keyRef, NULL/*tag*/, count, acls);
320 assert(count == 1);
321 const AclEntryInfo &acl1 = acls[0];
322 const TypedList &subject1 = acl1.proto().subject();
323 assert(subject1.type() == CSSM_ACL_SUBJECT_TYPE_KEYCHAIN_PROMPT);
324 assert(subject1.length() == 2);
325 assert(static_cast<string>(subject1[1]) == "Test Key");
326 }
327
328 // try to use the key and see...
329 tester.testWrap(NULL, "ACCEPTING NULL CREDENTIAL");
330 AutoCredentials cred(alloc);
331 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
332 new(alloc) ListElement(StringData("Test Key")));
333 tester.testWrap(&cred, "ACCEPTING PASSWORD CREDENTIAL");
334 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT);
335 tester.testWrap(&cred);
336 // once again, for allow-this-pid feature testing
337 tester.testWrap(&cred);
338 }
339
340
341 //
342 // Code-signing ACL subjects
343 //
344 void codeSigning()
345 {
346 printf("* Code Signing ACL test\n");
347 CssmAllocator &alloc = CssmAllocator::standard();
348 ClientSession ss(alloc, alloc);
349
350 // sign ourselves
351 OSXSigner signer;
352 OSXCode *main = OSXCode::main();
353 Signature *mySignature = signer.sign(*main);
354 detail("Code signature for testclient obtained");
355
356 // make a variant signature that isn't right
357 Signature *badSignature;
358 {
359 char buffer[512];
360 assert(mySignature->length() <= sizeof(buffer));
361 memcpy(buffer, mySignature->data(), mySignature->length());
362 memcpy(buffer, "xyz!", 4); // 1 in 2^32 this is right...
363 badSignature = signer.restore(mySignature->type(), buffer, mySignature->length());
364 }
365
366 // create key with good code signature ACL
367 AclEntryPrototype initialAcl;
368 initialAcl.subject() = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_CODE_SIGNATURE,
369 new(alloc) ListElement(mySignature->type()),
370 new(alloc) ListElement(alloc.alloc(*mySignature)));
371 AclEntryInput initialAclInput(initialAcl);
372 AclTester tester(ss, &initialAclInput);
373
374 // get the owner and verify
375 AclOwnerPrototype owner;
376 ss.getKeyOwner(tester.keyRef, owner);
377 assert(owner.subject().type() == CSSM_ACL_SUBJECT_TYPE_CODE_SIGNATURE);
378 assert(owner.subject().length() == 3);
379
380 // we are us, so the SecurityServer should accept us
381 tester.testWrap(&nullCred);
382
383 // now try this again with a *bad* signature...
384 AclEntryPrototype badAcl;
385 badAcl.TypedSubject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_CODE_SIGNATURE,
386 new(alloc) ListElement(badSignature->type()),
387 new(alloc) ListElement(alloc.alloc(*badSignature)));
388 AclEntryInput badAclInput(badAcl);
389 AclTester badTester(ss, &badAclInput);
390 badTester.testWrap(&nullCred, "BAD CODE SIGNATURE ACCEPTED");
391
392 // make sure the optional comment field makes it back out intact
393 // (reusing original initialAcl structures)
394 StringData comment("Walla Walla Washington!\nAbra cadabra.\n\n");
395 initialAcl.subject() += new(alloc) ListElement(alloc, comment);
396 AclEntryInput initialAclInputWithComment(initialAcl);
397 AclTester commentTester(ss, &initialAclInputWithComment);
398 ss.getKeyOwner(commentTester.keyRef, owner);
399 assert(owner.subject().type() == CSSM_ACL_SUBJECT_TYPE_CODE_SIGNATURE);
400 assert(owner.subject().length() == 4);
401 assert(owner.subject()[3] == comment);
402 detail("Verified comment field intact");
403 }