1/*
2 * Copyright (c) 2000-2001,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// testutils - utilities for unit test drivers
27//
28#include "testutils.h"
29
30using namespace CssmClient;
31
32bool verbose = false;
33
34
35//
36// Error and diagnostic drivers
37//
38void error(const char *msg = NULL, ...)
39{
40	if (msg) {
41		va_list args;
42		va_start(args, msg);
43		vfprintf(stderr, msg, args);
44		va_end(args);
45		putc('\n', stderr);
46	}
47	abort();
48}
49
50void error(const CssmCommonError &err, const char *msg = NULL, ...)
51{
52	if (msg) {
53		va_list args;
54		va_start(args, msg);
55		vfprintf(stderr, msg, args);
56		va_end(args);
57		fprintf(stderr, ": %s", cssmErrorString(err.cssmError()).c_str());
58		putc('\n', stderr);
59	}
60	abort();
61}
62
63void detail(const char *msg = NULL, ...)
64{
65	if (verbose) {
66		va_list args;
67		va_start(args, msg);
68		vfprintf(stdout, msg, args);
69		va_end(args);
70		putc('\n', stdout);
71	}
72}
73
74void detail(const CssmCommonError &err, const char *msg)
75{
76	if (verbose)
77		printf("%s (ok): %s\n", msg, cssmErrorString(err).c_str());
78}
79
80void prompt(const char *msg)
81{
82	if (isatty(fileno(stdin)))
83		printf("[%s]", msg);
84}
85
86void prompt()
87{
88	if (isatty(fileno(stdin)))
89		printf(" OK\n");
90}
91
92
93//
94// FakeContext management
95//
96FakeContext::FakeContext(CSSM_CONTEXT_TYPE type, CSSM_ALGORITHMS alg, uint32 count)
97: Context(type, alg)
98{
99	NumberOfAttributes = count;
100	ContextAttributes = new Attr[count];
101}
102
103
104FakeContext::FakeContext(CSSM_CONTEXT_TYPE type, CSSM_ALGORITHMS alg, ...)
105: Context(type, alg)
106{
107	// count arguments
108	va_list args;
109	va_start(args, alg);
110	uint32 count = 0;
111	while (va_arg(args, Attr *))
112		count++;
113	va_end(args);
114
115	// make vector
116	NumberOfAttributes = count;
117	ContextAttributes = new Attr[count];
118
119	// stuff vector
120	va_start(args, alg);
121	for (uint32 n = 0; n < count; n++)
122		(*this)[n] = *va_arg(args, Attr *);
123	va_end(args);
124}
125
126
127//
128// ACL test driver class
129//
130AclTester::AclTester(ClientSession &ss, const AclEntryInput *acl) : session(ss)
131{
132	// make up a DES key
133	StringData keyBits("Tweedle!");
134	CssmKey key(keyBits);
135	key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY;
136
137	// wrap in the key
138	CssmData unwrappedData;
139	FakeContext unwrapContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_NONE, 0);
140    CssmKey::Header keyHeader;
141    ss.unwrapKey(noDb, unwrapContext, noKey, noKey,
142		key,
143		CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
144		CSSM_KEYATTR_EXTRACTABLE,
145		NULL /*cred*/, acl,
146		unwrappedData, keyRef, keyHeader);
147	detail("Key seeded with ACL");
148}
149
150
151void AclTester::testWrap(const AccessCredentials *cred, const char *howWrong)
152{
153	FakeContext wrapContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_NONE, 0);
154	CssmWrappedKey wrappedKey;
155	try {
156		session.wrapKey(wrapContext, noKey, keyRef,
157			cred, NULL /*descriptive*/, wrappedKey);
158		if (howWrong) {
159			error("WRAP MISTAKENLY SUCCEEDED: %s", howWrong);
160		}
161		detail("extract OK");
162	} catch (const CssmCommonError &err) {
163		if (!howWrong)
164			error(err, "FAILED TO EXTRACT KEY");
165		detail(err, "extract failed OK");
166	}
167}
168
169void AclTester::testEncrypt(const AccessCredentials *cred, const char *howWrong)
170{
171    CssmKey keyForm; memset(&keyForm, 0, sizeof(keyForm));
172    StringData iv("Aardvark");
173    StringData clearText("blah");
174	CssmData remoteCipher;
175    try {
176        if (cred) {
177            FakeContext cryptoContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_DES,
178                &::Context::Attr(CSSM_ATTRIBUTE_KEY, keyForm),
179                &::Context::Attr(CSSM_ATTRIBUTE_INIT_VECTOR, iv),
180                &::Context::Attr(CSSM_ATTRIBUTE_MODE, CSSM_ALGMODE_CBC_IV8),
181                &::Context::Attr(CSSM_ATTRIBUTE_PADDING, CSSM_PADDING_PKCS1),
182                &::Context::Attr(CSSM_ATTRIBUTE_ACCESS_CREDENTIALS, *cred),
183                NULL);
184            session.encrypt(cryptoContext, keyRef, clearText, remoteCipher);
185        } else {
186            FakeContext cryptoContext(CSSM_ALGCLASS_SYMMETRIC, CSSM_ALGID_DES,
187                &::Context::Attr(CSSM_ATTRIBUTE_KEY, keyForm),
188                &::Context::Attr(CSSM_ATTRIBUTE_INIT_VECTOR, iv),
189                &::Context::Attr(CSSM_ATTRIBUTE_MODE, CSSM_ALGMODE_CBC_IV8),
190                &::Context::Attr(CSSM_ATTRIBUTE_PADDING, CSSM_PADDING_PKCS1),
191                NULL);
192            session.encrypt(cryptoContext, keyRef, clearText, remoteCipher);
193        }
194		if (howWrong) {
195			error("ENCRYPT MISTAKENLY SUCCEEDED: %s", howWrong);
196		}
197		detail("encrypt OK");
198	} catch (CssmCommonError &err) {
199		if (!howWrong)
200			error(err, "FAILED TO ENCRYPT");
201		detail(err, "encrypt failed");
202	}
203}
204
205
206//
207// Database test driver class
208//
209DbTester::DbTester(ClientSession &ss, const char *path,
210	const AccessCredentials *cred, int timeout, bool sleepLock)
211: session(ss), dbId(ssuid, path, NULL)
212{
213	params.idleTimeout = timeout;
214	params.lockOnSleep = sleepLock;
215	dbRef = ss.createDb(dbId, cred, NULL, params);
216	detail("Database %s created", path);
217}
218
219
220void DbTester::unlock(const char *howWrong)
221{
222	session.lock(dbRef);
223	try {
224		session.unlock(dbRef);
225		if (howWrong)
226			error("DATABASE MISTAKENLY UNLOCKED: %s", howWrong);
227	} catch (CssmError &err) {
228		if (!howWrong)
229			error(err, howWrong);
230		detail(err, howWrong);
231	}
232}
233
234void DbTester::changePassphrase(const AccessCredentials *cred, const char *howWrong)
235{
236	session.lock(dbRef);
237	try {
238		session.changePassphrase(dbRef, cred);
239		if (howWrong)
240			error("PASSPHRASE CHANGE MISTAKENLY SUCCEEDED: %s", howWrong);
241	} catch (CssmError &err) {
242		if (!howWrong)
243			error(err, howWrong);
244		detail(err, howWrong);
245	}
246}
247