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