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