2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // testacls - ACL-related test cases.
22 #include "testclient.h"
23 #include "testutils.h"
24 #include <Security/osxsigner.h>
26 using namespace CodeSigning
;
34 printf("* Basic ACL tests\n");
35 CssmAllocator
&alloc
= CssmAllocator::standard();
36 ClientSession
ss(alloc
, alloc
);
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
);
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);
52 // get the acl entry and verify
56 ss
.getKeyAcl(tester
.keyRef
, NULL
/*tag*/, count
, acls
);
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);
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
);
74 // now *replace* the ACL entry with a new one...
76 detail("Changing ACL");
79 ss
.getKeyAcl(tester
.keyRef
, NULL
, count
, infos
);
80 assert(count
== 1); // one entry
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
);
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");
102 ss
.changeKeyAcl(tester
.keyRef
, cred
, edit
);
103 detail("ACL changed OK");
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");
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");
116 // Threshold subjects
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!")))
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");
141 tester
.testWrap(&cred
);
142 #endif //STRICT_THRESHOLD_SUBJECTS
145 // comment ACLs and tags
147 detail("Adding Comment entry");
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
);
158 ss
.changeKeyAcl(tester
.keyRef
, cred
, edit
);
159 detail("Entry added");
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!");
174 detail("Comment entry retrieved okay");
180 // ACL authorization tests
184 printf("* ACL authorizations test\n");
185 CssmAllocator
&alloc
= CssmAllocator::standard();
186 ClientSession
ss(alloc
, alloc
);
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
);
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);
207 // get the acl entry and verify
211 ss
.getKeyAcl(tester
.keyRef
, NULL
/*tag*/, count
, acls
);
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
);
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
);
232 tester
.testEncrypt(&nullCred
, "ACCEPTING NULL CREDENTIAL FOR UNAUTHORIZED OPERATION");
233 tester
.testEncrypt(&cred
, "ACCEPTING GOOD CREDENTIAL FOR UNAUTHORIZED OPERATION");
235 // now *add* a new ACL entry for encryption
237 detail("Adding new ACL entry");
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
);
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");
254 ss
.changeKeyAcl(tester
.keyRef
, cred
, edit
);
255 detail("ACL changed OK");
257 // read it back and check
261 ss
.getKeyAcl(tester
.keyRef
, NULL
/*tag*/, count
, acls
);
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
);
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");
294 // Keychain ACL subjects
298 printf("* Keychain (interactive) ACL test\n");
299 CssmAllocator
&alloc
= CssmAllocator::standard();
300 ClientSession
ss(alloc
, alloc
);
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
);
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);
315 // get the acl entry and verify
319 ss
.getKeyAcl(tester
.keyRef
, NULL
/*tag*/, count
, acls
);
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");
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
);
342 // Code-signing ACL subjects
346 printf("* Code Signing ACL test\n");
347 CssmAllocator
&alloc
= CssmAllocator::standard();
348 ClientSession
ss(alloc
, alloc
);
352 OSXCode
*main
= OSXCode::main();
353 Signature
*mySignature
= signer
.sign(*main
);
354 detail("Code signature for testclient obtained");
356 // make a variant signature that isn't right
357 Signature
*badSignature
;
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());
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
);
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);
380 // we are us, so the SecurityServer should accept us
381 tester
.testWrap(&nullCred
);
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");
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");