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