]> git.saurik.com Git - apple/security.git/blob - SecurityServer/tests/testblobs.cpp
Security-163.tar.gz
[apple/security.git] / SecurityServer / tests / testblobs.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
25
26 //
27 // Blob tests.
28 // Encodes and decodes Db and Key blobs and all that jazz.
29 //
30 void blobs()
31 {
32 printf("* Database blob encryption test\n");
33 ClientSession ss(CssmAllocator::standard(), CssmAllocator::standard());
34
35 DbTester db1(ss, "/tmp/one", NULL, 60, true);
36 DbTester db2(ss, "/tmp/two", NULL, 30, false);
37
38 // encode db1, purge it, decode it again
39 CssmData dbBlob;
40 ss.encodeDb(db1, dbBlob);
41 DbHandle db1a = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
42 ss.releaseDb(db1);
43 if (db1 == db1a)
44 detail("REUSED DB HANDLE ON DECODEDB (probably wrong)");
45 DBParameters savedParams;
46 ss.getDbParameters(db1a, savedParams);
47 assert(savedParams.idleTimeout == db1.params.idleTimeout);
48 assert(savedParams.lockOnSleep == db1.params.lockOnSleep);
49 detail("Database encode/decode passed");
50
51 // make sure the old handle isn't valid anymore
52 try {
53 ss.getDbParameters(db1, savedParams);
54 printf("OLD DATABASE HANDLE NOT PURGED (possibly wrong)\n");
55 } catch (const CssmCommonError &err) {
56 detail(err, "old DB handle rejected");
57 }
58
59 // open db1 a second time (so now there's two db handles for db1)
60 DbHandle db1b = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
61
62 // release both db1 handles and db2
63 ss.releaseDb(db1a);
64 ss.releaseDb(db1b);
65 ss.releaseDb(db2);
66 }
67
68
69 //
70 // Database tests.
71 // Database locks/unlocks etc.
72 //
73 void databases()
74 {
75 printf("* Database manipulation test\n");
76 CssmAllocator &alloc = CssmAllocator::standard();
77 ClientSession ss(alloc, alloc);
78
79 AutoCredentials pwCred(alloc);
80 StringData passphrase("two");
81 StringData badPassphrase("three");
82 pwCred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
83 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
84 new(alloc) ListElement(passphrase));
85 pwCred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
86 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
87 new(alloc) ListElement(badPassphrase));
88 // pwCred = (NEW: two, OLD: three)
89
90 DbTester db1(ss, "/tmp/one", NULL, 30, true);
91 DbTester db2(ss, "/tmp/two", &pwCred, 60, false);
92 // db2.passphrase = two
93
94 // encode db1 and re-open it
95 CssmData dbBlob;
96 ss.encodeDb(db1, dbBlob);
97 DbHandle db1b = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
98 if (db1b == db1.dbRef)
99 detail("REUSED DB HANDLE ON DECODEDB (probably wrong)");
100
101 // open db1 a third time (so now there's three db handles for db1)
102 DbHandle db1c = ss.decodeDb(db1.dbId, &nullCred, dbBlob);
103
104 // lock them to get started
105 ss.lock(db1);
106 ss.lock(db2);
107
108 // unlock it through user
109 prompt("unlock");
110 ss.unlock(db1);
111 prompt();
112 ss.unlock(db1b); // 2nd unlock should not prompt
113 ss.lock(db1c); // lock it again
114 prompt("unlock");
115 ss.unlock(db1); // and that should prompt again
116 prompt();
117
118 // db2 has a passphrase lock credentials - it'll work without U/I
119 db2.unlock("wrong passphrase"); // pw=two, cred=three
120 AutoCredentials pwCred2(alloc);
121 pwCred2 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
122 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
123 new(alloc) ListElement(passphrase));
124 // pwCred2 = (OLD: two)
125 ss.authenticateDb(db2, CSSM_DB_ACCESS_WRITE, &pwCred2); // set it
126 db2.unlock();
127 ss.lock(db2);
128
129 // now change db2's passphrase
130 ss.lock(db2);
131 pwCred2 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
132 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
133 new(alloc) ListElement(badPassphrase));
134 // pwCred2 = (OLD: two, NEW: three)
135 db2.changePassphrase(&pwCred2);
136 // passphrase = three, cred = (OLD: two)
137
138 // encode and re-decode to make sure new data is there
139 CssmData blob2;
140 ss.encodeDb(db2, blob2);
141 DbHandle db2a = ss.decodeDb(db2.dbId, &pwCred, blob2);
142 // db2a cred = (OLD: two, NEW: three)
143
144 // now, the *old* cred won't work anymore
145 db2.unlock("old passphrase accepted");
146
147 // back to the old credentials, which *do* have the (old bad, now good) passphrase
148 ss.lock(db2a);
149 ss.unlock(db2a);
150 detail("New passphrase accepted");
151
152 // clear the credentials (this will prompt; cancel it)
153 ss.authenticateDb(db2, CSSM_DB_ACCESS_WRITE, NULL);
154 prompt("cancel");
155 db2.unlock("null credential accepted");
156 prompt();
157
158 // fell-swoop from-to change password operation
159 StringData newPassphrase("hollerith");
160 AutoCredentials pwCred3(alloc);
161 pwCred3 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
162 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
163 new(alloc) ListElement(newPassphrase));
164 pwCred3 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
165 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
166 new(alloc) ListElement(passphrase));
167 db2.changePassphrase(&pwCred3, "accepting original (unchanged) passphrase");
168
169 AutoCredentials pwCred4(alloc);
170 pwCred4 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
171 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
172 new(alloc) ListElement(newPassphrase));
173 pwCred4 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
174 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
175 new(alloc) ListElement(badPassphrase));
176 db2.changePassphrase(&pwCred4);
177
178 // final status check
179 AutoCredentials pwCred5(alloc);
180 pwCred5 += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
181 new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
182 new(alloc) ListElement(newPassphrase));
183 ss.authenticateDb(db2, CSSM_DB_ACCESS_WRITE, &pwCred5);
184 db2.unlock();
185 detail("Final passphrase change verified");
186 }
187
188
189 //
190 // Key encryption tests.
191 //
192 void keyBlobs()
193 {
194 printf("* Keyblob encryption test\n");
195 CssmAllocator &alloc = CssmAllocator::standard();
196 ClientSession ss(alloc, alloc);
197
198 DLDbIdentifier dbId1(ssuid, "/tmp/one", NULL);
199 DBParameters initialParams1 = { 3600, false };
200
201 // create a new database
202 DbHandle db = ss.createDb(dbId1, NULL, NULL, initialParams1);
203 detail("Database created");
204
205 // establish an ACL for the key
206 StringData theAclPassword("Strenge Geheimsache");
207 AclEntryPrototype initialAcl;
208 initialAcl.TypedSubject = TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD,
209 new(alloc) ListElement(theAclPassword));
210 AclEntryInput initialAclInput(initialAcl);
211
212 AutoCredentials cred(alloc);
213 cred += TypedList(alloc, CSSM_SAMPLE_TYPE_PASSWORD,
214 new(alloc) ListElement(theAclPassword));
215
216 // generate a key
217 const CssmCryptoData seed(StringData("Farmers' day"));
218 FakeContext genContext(CSSM_ALGCLASS_KEYGEN, CSSM_ALGID_DES,
219 &::Context::Attr(CSSM_ATTRIBUTE_KEY_LENGTH, 64),
220 &::Context::Attr(CSSM_ATTRIBUTE_SEED, seed),
221 NULL);
222 KeyHandle key;
223 CssmKey::Header header;
224 ss.generateKey(db, genContext, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
225 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
226 /*cred*/NULL, &initialAclInput, key, header);
227 detail("Key generated");
228
229 // encrypt with the key
230 StringData clearText("Yet another boring cleartext sample string text sequence.");
231 StringData iv("Aardvark");
232 CssmKey nullKey; memset(&nullKey, 0, sizeof(nullKey));
233 FakeContext cryptoContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_DES,
234 &::Context::Attr(CSSM_ATTRIBUTE_KEY, nullKey),
235 &::Context::Attr(CSSM_ATTRIBUTE_INIT_VECTOR, iv),
236 &::Context::Attr(CSSM_ATTRIBUTE_MODE, CSSM_ALGMODE_CBC_IV8),
237 &::Context::Attr(CSSM_ATTRIBUTE_PADDING, CSSM_PADDING_PKCS1),
238 &::Context::Attr(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, cred),
239 NULL);
240 CssmData cipherText;
241 ss.encrypt(cryptoContext, key, clearText, cipherText);
242 detail("Plaintext encrypted with original key");
243
244 // encode the key and release it
245 CssmData blob;
246 ss.encodeKey(key, blob);
247 ss.releaseKey(key);
248 detail("Key encoded and released");
249
250 // decode it again, re-introducing it
251 CssmKey::Header decodedHeader;
252 KeyHandle key2 = ss.decodeKey(db, blob, decodedHeader);
253 detail("Key decoded");
254
255 // decrypt with decoded key
256 CssmData recovered;
257 ss.decrypt(cryptoContext, key2, cipherText, recovered);
258 assert(recovered == clearText);
259 detail("Decoded key correctly decrypts ciphertext");
260
261 // check a few header fields
262 if (!memcmp(&header, &decodedHeader, sizeof(header))) {
263 detail("All header fields match");
264 } else {
265 assert(header.algorithm() == decodedHeader.algorithm());
266 assert(header.blobType() == decodedHeader.blobType());
267 assert(header.blobFormat() == decodedHeader.blobFormat());
268 assert(header.keyClass() == decodedHeader.keyClass());
269 assert(header.attributes() == decodedHeader.attributes());
270 assert(header.usage() == decodedHeader.usage());
271 printf("Some header fields differ (probably okay)\n");
272 }
273
274 // make sure we need the credentials (destructive)
275 memset(&cred, 0, sizeof(cred));
276 try {
277 ss.decrypt(cryptoContext, key2, cipherText, recovered);
278 error("RESTORED ACL FAILS TO RESTRICT");
279 } catch (CssmError &err) {
280 detail(err, "Restored key restricts access properly");
281 }
282 }