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