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// Tester - test driver for securityserver client side.
27//
28#include "testclient.h"
29#include "testutils.h"
30#include <unistd.h>		// getopt(3)
31#include <set>
32
33
34//
35// Global constants
36//
37const CssmData null;		// zero pointer, zero length constant data
38const AccessCredentials nullCred;	// null credentials
39
40CSSM_GUID ssguid = { 1,2,3 };
41CssmSubserviceUid ssuid(ssguid);
42
43
44//
45// Local functions
46//
47static void usage();
48static void runtest(char type);
49
50
51//
52// Default test set
53//
54static char testCodes[] = ".cesaAbdkKt";
55
56
57//
58// Main program
59//
60int main(int argc, char *argv[])
61{
62	setbuf(stdout, NULL);
63
64	long ranseq = 0;	// random stress test count
65	long ranseed = 1;	// random seed for it
66
67	int arg;
68	while ((arg = getopt(argc, argv, "r:v")) != -1) {
69		switch (arg) {
70		case 'r': {
71			ranseq = atoi(optarg);
72			if (const char *colon = strchr(optarg, ':'))
73				ranseed = atoi(colon + 1);
74			else
75				ranseed = getpid() ^ time(NULL);
76			break;
77			}
78		case 'v':
79			verbose = true;
80			break;
81		default:
82			usage();
83		}
84	}
85	if (optind < argc - 1)
86		usage();
87	const char *sequence = argv[optind];
88	if (sequence && !strcmp(sequence, "+"))
89		sequence = testCodes;
90
91	if (ranseq) {	// repeated random (stress test) sequence
92		if (!sequence)
93			sequence = testCodes;
94		printf("*** Random stress test: %ld iterations from <%s> with seed=%ld\n",
95			ranseq, sequence, ranseed);
96		srandom(ranseed);
97		int setSize = strlen(sequence);
98		for (long n = 0; n < ranseq; n++) {
99			char type = sequence[random() % setSize];
100			printf("\n[%ld:%c]", n, type);
101			runtest(type);
102		}
103		printf("*** Random test sequence complete.\n");
104		exit(0);
105	} else {		// single-pass selected tests sequence
106		if (!sequence)
107			sequence = ".";	// default to ping test
108		for (const char *s = sequence; *s; s++)
109			runtest(*s);
110		printf("*** Test sequence complete.\n");
111		exit(0);
112	}
113}
114
115void usage()
116{
117	fprintf(stderr, "Usage: SSTester [-r count[:seed]] [-v] [%s|.|+]\n",
118		testCodes);
119	exit(2);
120}
121
122
123//
124// Run a single type test
125//
126void runtest(char type)
127{
128	try {
129		debug("SStest", "Start test <%c>", type);
130		switch (type) {
131		case '.':	// default
132			integrity();
133			break;
134		case '-':
135			adhoc();
136			break;
137		case 'a':
138			acls();
139			break;
140		case 'A':
141			authAcls();
142			break;
143		case 'b':
144			blobs();
145			break;
146		case 'c':
147			codeSigning();
148			break;
149		case 'd':
150			databases();
151			break;
152		case 'e':
153			desEncryption();
154			break;
155		case 'k':
156			keychainAcls();
157			break;
158		case 'K':
159			keyBlobs();
160			break;
161		case 's':
162			signWithRSA();
163			break;
164		case 't':
165			authorizations();
166			break;
167		case 'T':
168			timeouts();
169			break;
170		default:
171			error("Invalid test selection (%c)", type);
172		}
173		printf("** Test step complete.\n");
174		debug("SStest", "End test <%c>", type);
175	} catch (CssmCommonError &err) {
176		error(err, "Unexpected exception");
177	} catch (...) {
178		error("Unexpected system exception");
179	}
180}
181
182
183//
184// Basic integrity test.
185//
186void integrity()
187{
188	ClientSession ss(CssmAllocator::standard(), CssmAllocator::standard());
189
190	printf("* Generating random sample: ");
191	DataBuffer<11> sample;
192	ss.generateRandom(sample);
193	for (uint32 n = 0; n < sample.length(); n++)
194		printf("%.2x", ((unsigned char *)sample)[n]);
195	printf("\n");
196}
197
198
199//
200// Database timeouts
201// @@@ Incomplete and not satisfactory
202//
203void timeouts()
204{
205	printf("* Database timeout locks test\n");
206    CssmAllocator &alloc = CssmAllocator::standard();
207	ClientSession ss(alloc, alloc);
208
209    DLDbIdentifier dbId1(ssuid, "/tmp/one", NULL);
210    DLDbIdentifier dbId2(ssuid, "/tmp/two", NULL);
211	DBParameters initialParams1 = { 4, false };	// 4 seconds timeout
212	DBParameters initialParams2 = { 8, false };	// 8 seconds timeout
213
214	// credential to set keychain passphrase
215    AutoCredentials pwCred(alloc);
216    StringData password("mumbojumbo");
217    pwCred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
218        new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
219        new(alloc) ListElement(password));
220
221	DbHandle db1 = ss.createDb(dbId1, &pwCred, NULL, initialParams1);
222	DbHandle db2 = ss.createDb(dbId2, &pwCred, NULL, initialParams2);
223	detail("Databases created");
224
225    // generate a key
226	const CssmCryptoData seed(StringData("rain tonight"));
227	FakeContext genContext(CSSM_ALGCLASS_KEYGEN, CSSM_ALGID_DES,
228		&::Context::Attr(CSSM_ATTRIBUTE_KEY_LENGTH, 64),
229		&::Context::Attr(CSSM_ATTRIBUTE_SEED, seed),
230		NULL);
231    KeyHandle key;
232    CssmKey::Header header;
233    ss.generateKey(db1, genContext, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
234        CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
235        /*cred*/NULL, NULL, key, header);
236    ss.generateKey(db2, genContext, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
237        CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
238        /*cred*/NULL, NULL, key, header);
239	detail("Keys generated and stored");
240
241	// credential to provide keychain passphrase
242    AutoCredentials pwCred2(alloc);
243    pwCred += TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
244        new(alloc) ListElement(CSSM_SAMPLE_TYPE_PASSWORD),
245        new(alloc) ListElement(password));
246
247	//@@@ incomplete
248	ss.releaseDb(db1);
249	ss.releaseDb(db2);
250}
251
252
253//
254// Ad-hoc test area.
255// Used for whatever is needed at the moment...
256//
257void adhoc()
258{
259	printf("* Ad-hoc test sequence (now what does it do *this* time?)\n");
260
261	Cssm cssm1;
262	Cssm cssm2;
263	cssm1->init();
264	cssm2->init();
265
266	{
267		Module m1(gGuidAppleCSP, cssm1);
268		Module m2(gGuidAppleCSP, cssm2);
269		CSP r1(m1);
270		CSP r2(m2);
271
272		Digest d1(r1, CSSM_ALGID_SHA1);
273		Digest d2(r2, CSSM_ALGID_SHA1);
274
275		StringData foo("foo de doo da blech");
276		DataBuffer<30> digest1, digest2;
277		d1.digest(foo, digest1);
278		d2.digest(foo, digest2);
279		if (digest1 == digest2)
280			detail("Digests verify");
281		else
282			error("Digests mismatch");
283	}
284
285	cssm1->terminate();
286	cssm2->terminate();
287}
288