1/*
2 * extenTest - verify encoding and decoding of extensions.
3 */
4
5#include <security_cdsa_utils/cuFileIo.h>
6#include <clAppUtils/CertBuilderApp.h>
7#include <utilLib/common.h>
8#include <utilLib/cspwrap.h>
9#include <clAppUtils/clutils.h>
10#include <security_cdsa_utils/cuPrintCert.h>
11#include <security_cdsa_utils/cuOidParser.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15#include <time.h>
16#include <Security/cssm.h>
17#include <Security/x509defs.h>
18#include <Security/oidsattr.h>
19#include <Security/oidscert.h>
20#include <Security/certextensions.h>
21
22#define KEY_ALG			CSSM_ALGID_RSA
23#define SIG_ALG			CSSM_ALGID_SHA1WithRSA
24#define KEY_SIZE_BITS	CSP_RSA_KEY_SIZE_DEFAULT
25#define SUBJ_KEY_LABEL	"subjectKey"
26
27#define LOOPS_DEF	10
28
29static void usage(char **argv)
30{
31	printf("Usage: %s [options]\n", argv[0]);
32	printf("Options:\n");
33	printf("   e=extenSpec (default = all)\n");
34	printf("      k  keyUsage\n");
35	printf("      b  basicConstraints\n");
36	printf("      x  extendedKeyUsage\n");
37	printf("      s  subjectKeyId\n");
38	printf("      a  authorityKeyId\n");
39	printf("      t  SubjectAltName\n");
40	printf("      i  IssuerAltName\n");
41	printf("      c  certPolicies\n");
42	printf("      n  netscapeCertType\n");
43	printf("      p  CRLDistributionPoints\n");
44	printf("      A  AuthorityInfoAccess\n");
45	printf("      S  SubjectInfoAccess\n");
46	printf("      q  QualifiedCertStatements\n");
47	printf("   w(rite blobs)\n");
48	printf("   f=fileName (default is extension-specific file name)\n");
49	printf("   d(isplay certs)\n");
50	printf("   l=loops (default = %d)\n", LOOPS_DEF);
51	printf("   p(ause on each loop)\n");
52	printf("   P(ause on each cert)\n");
53	exit(1);
54}
55
56/* dummy RDN - subject and issuer - we aren't testing this */
57CB_NameOid dummyRdn[] =
58{
59	{ "Apple Computer",					&CSSMOID_OrganizationName },
60	{ "Doug Mitchell",					&CSSMOID_CommonName }
61};
62#define NUM_DUMMY_NAMES	(sizeof(dummyRdn) / sizeof(CB_NameOid))
63
64/*
65 * Static components we reuse for each encode/decode.
66 */
67static CSSM_X509_NAME	*dummyName;
68static CSSM_X509_TIME	*notBefore;		// UTC-style "not before" time
69static CSSM_X509_TIME	*notAfter;		// UTC-style "not after" time
70static CSSM_KEY			subjPrivKey;
71static CSSM_KEY			subjPubKey;
72
73static CSSM_BOOL randBool()
74{
75	unsigned r = genRand(1, 0x10000000);
76	return (r & 0x1) ? CSSM_TRUE : CSSM_FALSE;
77}
78
79/* Fill a CSSM_DATA with random data. Its referent is allocd with malloc. */
80static void randData(
81	CSSM_DATA_PTR	data,
82	uint8			maxLen)
83{
84	data->Data = (uint8 *)malloc(maxLen);
85	simpleGenData(data, 1, maxLen);
86}
87
88/*
89 * Various compare tests
90 */
91int compBool(
92	CSSM_BOOL pre,
93	CSSM_BOOL post,
94	const char *desc)
95{
96	if(pre == post) {
97		return 0;
98	}
99	printf("***Boolean miscompare on %s\n", desc);
100	/* in case a CSSM_TRUE isn't exactly right... */
101	switch(post) {
102		case CSSM_FALSE:
103		case CSSM_TRUE:
104			break;
105		default:
106			printf("*** post value is %d expected %d\n",
107				(int)post, (int)pre);
108			break;
109	}
110	return 1;
111}
112
113static int compCssmData(
114	CSSM_DATA &d1,
115	CSSM_DATA &d2,
116	const char *desc)
117{
118	if(appCompareCssmData(&d1, &d2)) {
119		return 0;
120	}
121	printf("CSSM_DATA miscompare on %s\n", desc);
122	return 1;
123}
124
125#pragma mark ----- individual extension tests -----
126
127#pragma mark --- CE_KeyUsage ---
128static void kuCreate(void *arg)
129{
130	CE_KeyUsage *ku = (CE_KeyUsage *)arg;
131
132	/* set two random valid bits */
133	*ku = 0;
134	*ku |= 1 << genRand(7, 15);
135	*ku |= 1 << genRand(7, 15);
136}
137
138static unsigned kuCompare(const void *pre, const void *post)
139{
140	const CE_KeyUsage *kuPre = (CE_KeyUsage *)pre;
141	const CE_KeyUsage *kuPost = (CE_KeyUsage *)post;
142	if(*kuPre != *kuPost) {
143		printf("***Miscompare in CE_KeyUsage\n");
144		return 1;
145	}
146	return 0;
147}
148
149#pragma mark --- CE_BasicConstraints ---
150static void bcCreate(void *arg)
151{
152	CE_BasicConstraints *bc = (CE_BasicConstraints *)arg;
153	bc->cA = randBool();
154	bc->pathLenConstraintPresent = randBool();
155	if(bc->pathLenConstraintPresent) {
156		bc->pathLenConstraint = genRand(1,10);
157	}
158}
159
160static unsigned bcCompare(const void *pre, const void *post)
161{
162	const CE_BasicConstraints *bcpre = (CE_BasicConstraints *)pre;
163	const CE_BasicConstraints *bcpost = (CE_BasicConstraints *)post;
164	unsigned rtn = 0;
165
166	rtn += compBool(bcpre->cA, bcpost->cA, "BasicConstraints.cA");
167	rtn += compBool(bcpre->pathLenConstraintPresent,
168		bcpost->pathLenConstraintPresent,
169		"BasicConstraints.pathLenConstraintPresent");
170	if(bcpre->pathLenConstraint != bcpost->pathLenConstraint) {
171		printf("BasicConstraints.pathLenConstraint mismatch\n");
172		rtn++;
173	}
174	return rtn;
175}
176
177#pragma mark --- CE_SubjectKeyID ---
178static void skidCreate(void *arg)
179{
180	CSSM_DATA_PTR skid = (CSSM_DATA_PTR)arg;
181	randData(skid, 16);
182}
183
184static unsigned skidCompare(const void *pre, const void *post)
185{
186	CSSM_DATA_PTR spre = (CSSM_DATA_PTR)pre;
187	CSSM_DATA_PTR spost = (CSSM_DATA_PTR)post;
188	return compCssmData(*spre, *spost, "SubjectKeyID");
189}
190
191static void skidFree(void *arg)
192{
193	CSSM_DATA_PTR skid = (CSSM_DATA_PTR)arg;
194	free(skid->Data);
195}
196
197#pragma mark --- CE_NetscapeCertType ---
198static void nctCreate(void *arg)
199{
200	CE_NetscapeCertType *nct = (CE_NetscapeCertType *)arg;
201
202	/* set two random valid bits */
203	*nct = 0;
204	*nct |= 1 << genRand(8, 15);
205	*nct |= 1 << genRand(8, 15);
206}
207
208static unsigned nctCompare(const void *pre, const void *post)
209{
210	const CE_NetscapeCertType *nPre = (CE_NetscapeCertType *)pre;
211	const CE_NetscapeCertType *nPost = (CE_NetscapeCertType *)post;
212	if(*nPre != *nPost) {
213		printf("***Miscompare in CE_NetscapeCertType\n");
214		return 1;
215	}
216	return 0;
217}
218
219#pragma mark --- CE_ExtendedKeyUsage ---
220
221/* a static array of meaningless OIDs, use 1.. NUM_SKU_OIDS */
222CSSM_OID ekuOids[] = {
223	CSSMOID_CrlNumber,
224	CSSMOID_CrlReason,
225	CSSMOID_HoldInstructionCode,
226	CSSMOID_InvalidityDate
227};
228#define NUM_SKU_OIDS 4
229
230static void ekuCreate(void *arg)
231{
232	CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)arg;
233	eku->numPurposes = genRand(1, NUM_SKU_OIDS);
234	eku->purposes = ekuOids;
235}
236
237static unsigned ekuCompare(const void *pre, const void *post)
238{
239	CE_ExtendedKeyUsage *ekupre = (CE_ExtendedKeyUsage *)pre;
240	CE_ExtendedKeyUsage *ekupost = (CE_ExtendedKeyUsage *)post;
241
242	if(ekupre->numPurposes != ekupost->numPurposes) {
243		printf("CE_ExtendedKeyUsage.numPurposes miscompare\n");
244		return 1;
245	}
246	unsigned rtn = 0;
247	for(unsigned dex=0; dex<ekupre->numPurposes; dex++) {
248		rtn += compCssmData(ekupre->purposes[dex],
249			ekupost->purposes[dex], "CE_ExtendedKeyUsage.purposes");
250	}
251	return rtn;
252}
253
254
255#pragma mark --- general purpose X509 name generator ---
256
257/* Attr/Value pairs, pick one of NUM_ATTR_STRINGS */
258static char *attrStrings[] = {
259	(char *)"thisName",
260	(char *)"anotherName",
261	(char *)"someOtherName"
262};
263#define NUM_ATTR_STRINGS	3
264
265/* A/V type, pick one of NUM_ATTR_TYPES */
266static CSSM_OID attrTypes[] = {
267	CSSMOID_Surname,
268	CSSMOID_CountryName,
269	CSSMOID_OrganizationName,
270	CSSMOID_Description
271};
272#define NUM_ATTR_TYPES	4
273
274/* A/V tag, pick one of NUM_ATTR_TAGS */
275static char attrTags[] = {
276	BER_TAG_PRINTABLE_STRING,
277	BER_TAG_IA5_STRING,
278	BER_TAG_T61_STRING
279};
280#define NUM_ATTR_TAGS	3
281
282static void rdnCreate(
283	CSSM_X509_RDN_PTR rdn)
284{
285	unsigned numPairs = genRand(1,4);
286	rdn->numberOfPairs = numPairs;
287	unsigned len = numPairs * sizeof(CSSM_X509_TYPE_VALUE_PAIR);
288	rdn->AttributeTypeAndValue =
289		(CSSM_X509_TYPE_VALUE_PAIR_PTR)malloc(len);
290	memset(rdn->AttributeTypeAndValue, 0, len);
291
292	for(unsigned atvDex=0; atvDex<numPairs; atvDex++) {
293		CSSM_X509_TYPE_VALUE_PAIR &pair =
294			rdn->AttributeTypeAndValue[atvDex];
295		unsigned die = genRand(1, NUM_ATTR_TYPES);
296		pair.type = attrTypes[die - 1];
297		die = genRand(1, NUM_ATTR_STRINGS);
298		char *str = attrStrings[die - 1];
299		pair.value.Data = (uint8 *)str;
300		pair.value.Length = strlen(str);
301		die = genRand(1, NUM_ATTR_TAGS);
302		pair.valueType = attrTags[die - 1];
303	}
304}
305
306static unsigned rdnCompare(
307	CSSM_X509_RDN_PTR rdn1,
308	CSSM_X509_RDN_PTR rdn2)
309{
310	if(rdn1->numberOfPairs != rdn2->numberOfPairs) {
311		printf("***Mismatch in numberOfPairs\n");
312		return 1;
313	}
314	unsigned rtn = 0;
315	for(unsigned atvDex=0; atvDex<rdn1->numberOfPairs; atvDex++) {
316		CSSM_X509_TYPE_VALUE_PAIR &p1 =
317			rdn1->AttributeTypeAndValue[atvDex];
318		CSSM_X509_TYPE_VALUE_PAIR &p2 =
319			rdn2->AttributeTypeAndValue[atvDex];
320		if(p1.valueType != p2.valueType) {
321			printf("***valueType miscompare\n");
322			rtn++;
323		}
324		if(compCssmData(p1.type, p2.type, "ATV.type")) {
325			rtn++;
326		}
327		if(compCssmData(p1.value, p2.value, "ATV.value")) {
328			rtn++;
329		}
330	}
331	return rtn;
332}
333
334static void rdnFree(
335	CSSM_X509_RDN_PTR rdn)
336{
337	free(rdn->AttributeTypeAndValue);
338}
339
340static void x509NameCreate(
341	CSSM_X509_NAME_PTR x509Name)
342{
343	memset(x509Name, 0, sizeof(*x509Name));
344	unsigned numRdns = genRand(1,4);
345	x509Name->numberOfRDNs = numRdns;
346	unsigned len = numRdns * sizeof(CSSM_X509_RDN);
347	x509Name->RelativeDistinguishedName = (CSSM_X509_RDN_PTR)malloc(len);
348	memset(x509Name->RelativeDistinguishedName, 0, len);
349
350	for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
351		CSSM_X509_RDN &rdn = x509Name->RelativeDistinguishedName[rdnDex];
352		rdnCreate(&rdn);
353	}
354}
355
356static unsigned x509NameCompare(
357	const CSSM_X509_NAME_PTR n1,
358	const CSSM_X509_NAME_PTR n2)
359{
360	if(n1->numberOfRDNs != n2->numberOfRDNs) {
361		printf("***Mismatch in numberOfRDNs\n");
362		return 1;
363	}
364	unsigned rtn = 0;
365	for(unsigned rdnDex=0; rdnDex<n1->numberOfRDNs; rdnDex++) {
366		CSSM_X509_RDN &rdn1 = n1->RelativeDistinguishedName[rdnDex];
367		CSSM_X509_RDN &rdn2 = n2->RelativeDistinguishedName[rdnDex];
368		rtn += rdnCompare(&rdn1, &rdn2);
369	}
370	return rtn;
371}
372
373static void x509NameFree(
374	CSSM_X509_NAME_PTR n)
375{
376	for(unsigned rdnDex=0; rdnDex<n->numberOfRDNs; rdnDex++) {
377		CSSM_X509_RDN &rdn = n->RelativeDistinguishedName[rdnDex];
378		rdnFree(&rdn);
379	}
380	free(n->RelativeDistinguishedName);
381}
382
383#pragma mark --- general purpose GeneralNames generator ---
384
385#define SOME_URL_1	"http://foo.bar.com"
386#define SOME_URL_2	"http://bar.foo.com"
387#define SOME_DNS_1	"Some DNS"
388#define SOME_DNS_2	"Another DNS"
389unsigned char	someIpAdr_1[] = {208, 161, 124, 209 };
390unsigned char	someIpAdr_2[] = {10, 0, 61, 5};
391
392static void genNameCreate(CE_GeneralName *name)
393{
394	unsigned type = genRand(1, 5);
395	const char *src;
396	unsigned char *usrc;
397	switch(type) {
398		case 1:
399			name->nameType = GNT_URI;
400			name->berEncoded = CSSM_FALSE;
401			src = randBool() ? SOME_URL_1 : SOME_URL_2;
402			appCopyData(src, strlen(src), &name->name);
403			break;
404
405		case 2:
406			name->nameType = GNT_RegisteredID;
407			name->berEncoded = CSSM_FALSE;
408			appCopyData(CSSMOID_SubjectDirectoryAttributes.Data,
409				CSSMOID_SubjectDirectoryAttributes.Length,
410				&name->name);
411			break;
412
413		case 3:
414			name->nameType = GNT_DNSName;
415			name->berEncoded = CSSM_FALSE;
416			src = randBool() ? SOME_DNS_1 : SOME_DNS_2;
417			appCopyData(src, strlen(src), &name->name);
418			break;
419
420		case 4:
421			name->nameType = GNT_IPAddress;
422			name->berEncoded = CSSM_FALSE;
423			usrc = randBool() ? someIpAdr_1 : someIpAdr_2;
424			appCopyData(usrc, 4, &name->name);
425			break;
426
427		case 5:
428		{
429			/* X509_NAME, the hard one */
430			name->nameType = GNT_DirectoryName;
431			name->berEncoded = CSSM_FALSE;
432			appSetupCssmData(&name->name, sizeof(CSSM_X509_NAME));
433			x509NameCreate((CSSM_X509_NAME_PTR)name->name.Data);
434		}
435	}
436}
437
438static void genNamesCreate(void *arg)
439{
440	CE_GeneralNames *names = (CE_GeneralNames *)arg;
441	names->numNames = genRand(1, 3);
442	// one at a time
443	//names->numNames = 1;
444	names->generalName = (CE_GeneralName *)malloc(names->numNames *
445		sizeof(CE_GeneralName));
446	memset(names->generalName, 0, names->numNames * sizeof(CE_GeneralName));
447
448	for(unsigned i=0; i<names->numNames; i++) {
449		CE_GeneralName *name = &names->generalName[i];
450		genNameCreate(name);
451	}
452}
453
454static unsigned genNameCompare(
455	CE_GeneralName *npre,
456	CE_GeneralName *npost)
457{
458	unsigned rtn = 0;
459	if(npre->nameType != npost->nameType) {
460		printf("***CE_GeneralName.nameType miscompare\n");
461		rtn++;
462	}
463	if(compBool(npre->berEncoded, npost->berEncoded,
464			"CE_GeneralName.berEncoded")) {
465		rtn++;
466	}
467
468	/* nameType-specific compare */
469	switch(npre->nameType) {
470		case GNT_RFC822Name:
471			rtn += compCssmData(npre->name, npost->name,
472				"CE_GeneralName.RFC822Name");
473			break;
474		case GNT_DNSName:
475			rtn += compCssmData(npre->name, npost->name,
476				"CE_GeneralName.DNSName");
477			break;
478		case GNT_URI:
479			rtn += compCssmData(npre->name, npost->name,
480				"CE_GeneralName.URI");
481			break;
482		case GNT_IPAddress:
483			rtn += compCssmData(npre->name, npost->name,
484				"CE_GeneralName.RFIPAddressC822Name");
485			break;
486		case GNT_RegisteredID:
487			rtn += compCssmData(npre->name, npost->name,
488				"CE_GeneralName.RegisteredID");
489			break;
490		case GNT_DirectoryName:
491			rtn += x509NameCompare((CSSM_X509_NAME_PTR)npre->name.Data,
492				(CSSM_X509_NAME_PTR)npost->name.Data);
493			break;
494		default:
495			printf("****BRRZAP! genNamesCompare needs work\n");
496			rtn++;
497	}
498	return rtn;
499}
500
501static unsigned genNamesCompare(const void *pre, const void *post)
502{
503	const CE_GeneralNames *gnPre = (CE_GeneralNames *)pre;
504	const CE_GeneralNames *gnPost = (CE_GeneralNames *)post;
505	unsigned rtn = 0;
506
507	if((gnPre == NULL) || (gnPost == NULL)) {
508		printf("***Bad GenNames pointer\n");
509		return 1;
510	}
511	if(gnPre->numNames != gnPost->numNames) {
512		printf("***CE_GeneralNames.numNames miscompare\n");
513		return 1;
514	}
515	for(unsigned dex=0; dex<gnPre->numNames; dex++) {
516		CE_GeneralName *npre  = &gnPre->generalName[dex];
517		CE_GeneralName *npost = &gnPost->generalName[dex];
518		rtn += genNameCompare(npre, npost);
519	}
520	return rtn;
521}
522
523
524static void genNameFree(CE_GeneralName *n)
525{
526	switch(n->nameType) {
527		case GNT_DirectoryName:
528			x509NameFree((CSSM_X509_NAME_PTR)n->name.Data);
529			CSSM_FREE(n->name.Data);
530			break;
531		default:
532			CSSM_FREE(n->name.Data);
533			break;
534	}
535}
536
537
538static void genNamesFree(void *arg)
539{
540	const CE_GeneralNames *gn = (CE_GeneralNames *)arg;
541	for(unsigned dex=0; dex<gn->numNames; dex++) {
542		CE_GeneralName *n = (CE_GeneralName *)&gn->generalName[dex];
543		genNameFree(n);
544	}
545	free(gn->generalName);
546}
547
548#pragma mark --- CE_CRLDistPointsSyntax ---
549static void cdpCreate(void *arg)
550{
551	CE_CRLDistPointsSyntax *cdp = (CE_CRLDistPointsSyntax *)arg;
552	//cdp->numDistPoints = genRand(1,3);
553	// one at a time
554	cdp->numDistPoints = 1;
555	unsigned len = sizeof(CE_CRLDistributionPoint) * cdp->numDistPoints;
556	cdp->distPoints = (CE_CRLDistributionPoint *)malloc(len);
557	memset(cdp->distPoints, 0, len);
558
559	for(unsigned dex=0; dex<cdp->numDistPoints; dex++) {
560		CE_CRLDistributionPoint *pt = &cdp->distPoints[dex];
561
562		/* all fields optional */
563		if(randBool()) {
564			CE_DistributionPointName *dpn = pt->distPointName =
565				(CE_DistributionPointName *)malloc(
566					sizeof(CE_DistributionPointName));
567			memset(dpn, 0, sizeof(CE_DistributionPointName));
568
569			/* CE_DistributionPointName has two flavors */
570			if(randBool()) {
571				dpn->nameType = CE_CDNT_FullName;
572				dpn->dpn.fullName = (CE_GeneralNames *)malloc(
573					sizeof(CE_GeneralNames));
574				memset(dpn->dpn.fullName, 0, sizeof(CE_GeneralNames));
575				genNamesCreate(dpn->dpn.fullName);
576			}
577			else {
578				dpn->nameType = CE_CDNT_NameRelativeToCrlIssuer;
579				dpn->dpn.rdn = (CSSM_X509_RDN_PTR)malloc(
580					sizeof(CSSM_X509_RDN));
581				memset(dpn->dpn.rdn, 0, sizeof(CSSM_X509_RDN));
582				rdnCreate(dpn->dpn.rdn);
583			}
584		}	/* creating CE_DistributionPointName */
585
586		pt->reasonsPresent = randBool();
587		if(pt->reasonsPresent) {
588			CE_CrlDistReasonFlags *cdr = &pt->reasons;
589			/* set two random valid bits */
590			*cdr = 0;
591			*cdr |= 1 << genRand(0,7);
592			*cdr |= 1 << genRand(0,7);
593		}
594
595		/* make sure at least one present */
596		if((!pt->distPointName && !pt->reasonsPresent) || randBool()) {
597			pt->crlIssuer = (CE_GeneralNames *)malloc(sizeof(CE_GeneralNames));
598			memset(pt->crlIssuer, 0, sizeof(CE_GeneralNames));
599			genNamesCreate(pt->crlIssuer);
600		}
601	}
602}
603
604static unsigned cdpCompare(const void *pre, const void *post)
605{
606	CE_CRLDistPointsSyntax *cpre = (CE_CRLDistPointsSyntax *)pre;
607	CE_CRLDistPointsSyntax *cpost = (CE_CRLDistPointsSyntax *)post;
608
609	if(cpre->numDistPoints != cpost->numDistPoints) {
610		printf("***CE_CRLDistPointsSyntax.numDistPoints miscompare\n");
611		return 1;
612	}
613	unsigned rtn = 0;
614	for(unsigned dex=0; dex<cpre->numDistPoints; dex++) {
615		CE_CRLDistributionPoint *ptpre  = &cpre->distPoints[dex];
616		CE_CRLDistributionPoint *ptpost = &cpost->distPoints[dex];
617
618		if(ptpre->distPointName) {
619			if(ptpost->distPointName == NULL) {
620				printf("***NULL distPointName post decode\n");
621				rtn++;
622				goto checkReason;
623			}
624			CE_DistributionPointName *dpnpre = ptpre->distPointName;
625			CE_DistributionPointName *dpnpost = ptpost->distPointName;
626			if(dpnpre->nameType != dpnpost->nameType) {
627				printf("***CE_DistributionPointName.nameType miscompare\n");
628				rtn++;
629				goto checkReason;
630			}
631			if(dpnpre->nameType == CE_CDNT_FullName) {
632				rtn += genNamesCompare(dpnpre->dpn.fullName, dpnpost->dpn.fullName);
633			}
634			else {
635				rtn += rdnCompare(dpnpre->dpn.rdn, dpnpost->dpn.rdn);
636			}
637
638		}
639		else if(ptpost->distPointName != NULL) {
640			printf("***NON NULL distPointName post decode\n");
641			rtn++;
642		}
643
644	checkReason:
645		if(ptpre->reasons != ptpost->reasons) {
646			printf("***CE_CRLDistributionPoint.reasons miscompare\n");
647			rtn++;
648		}
649
650		if(ptpre->crlIssuer) {
651			if(ptpost->crlIssuer == NULL) {
652				printf("***NULL crlIssuer post decode\n");
653				rtn++;
654				continue;
655			}
656			CE_GeneralNames *gnpre = ptpre->crlIssuer;
657			CE_GeneralNames *gnpost = ptpost->crlIssuer;
658			rtn += genNamesCompare(gnpre, gnpost);
659		}
660		else if(ptpost->crlIssuer != NULL) {
661			printf("***NON NULL crlIssuer post decode\n");
662			rtn++;
663		}
664	}
665	return rtn;
666}
667
668static void cdpFree(void *arg)
669{
670	CE_CRLDistPointsSyntax *cdp = (CE_CRLDistPointsSyntax *)arg;
671	for(unsigned dex=0; dex<cdp->numDistPoints; dex++) {
672		CE_CRLDistributionPoint *pt = &cdp->distPoints[dex];
673		if(pt->distPointName) {
674			CE_DistributionPointName *dpn = pt->distPointName;
675			if(dpn->nameType == CE_CDNT_FullName) {
676				genNamesFree(dpn->dpn.fullName);
677				free(dpn->dpn.fullName);
678			}
679			else {
680				rdnFree(dpn->dpn.rdn);
681				free(dpn->dpn.rdn);
682			}
683			free(dpn);
684		}
685
686		if(pt->crlIssuer) {
687			genNamesFree(pt->crlIssuer);
688			free(pt->crlIssuer);
689		}
690	}
691	free(cdp->distPoints);
692}
693
694#pragma mark --- CE_AuthorityKeyID ---
695static void authKeyIdCreate(void *arg)
696{
697	CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)arg;
698
699	/* all three fields optional */
700
701	akid->keyIdentifierPresent = randBool();
702	if(akid->keyIdentifierPresent) {
703		randData(&akid->keyIdentifier, 16);
704	}
705
706	akid->generalNamesPresent = randBool();
707	if(akid->generalNamesPresent) {
708		akid->generalNames =
709			(CE_GeneralNames *)malloc(sizeof(CE_GeneralNames));
710		memset(akid->generalNames, 0, sizeof(CE_GeneralNames));
711		genNamesCreate(akid->generalNames);
712	}
713
714	if(!akid->keyIdentifierPresent & !akid->generalNamesPresent) {
715		/* force at least one to be present */
716		akid->serialNumberPresent = CSSM_TRUE;
717	}
718	else  {
719		akid->serialNumberPresent = randBool();
720	}
721	if(akid->serialNumberPresent) {
722		randData(&akid->serialNumber, 16);
723	}
724
725}
726
727static unsigned authKeyIdCompare(const void *pre, const void *post)
728{
729	CE_AuthorityKeyID *akpre = (CE_AuthorityKeyID *)pre;
730	CE_AuthorityKeyID *akpost = (CE_AuthorityKeyID *)post;
731	unsigned rtn = 0;
732
733	if(compBool(akpre->keyIdentifierPresent, akpost->keyIdentifierPresent,
734			"CE_AuthorityKeyID.keyIdentifierPresent")) {
735		rtn++;
736	}
737	else if(akpre->keyIdentifierPresent) {
738		rtn += compCssmData(akpre->keyIdentifier,
739			akpost->keyIdentifier, "CE_AuthorityKeyID.keyIdentifier");
740	}
741
742	if(compBool(akpre->generalNamesPresent, akpost->generalNamesPresent,
743			"CE_AuthorityKeyID.generalNamesPresent")) {
744		rtn++;
745	}
746	else if(akpre->generalNamesPresent) {
747		rtn += genNamesCompare(akpre->generalNames,
748			akpost->generalNames);
749	}
750
751	if(compBool(akpre->serialNumberPresent, akpost->serialNumberPresent,
752			"CE_AuthorityKeyID.serialNumberPresent")) {
753		rtn++;
754	}
755	else if(akpre->serialNumberPresent) {
756		rtn += compCssmData(akpre->serialNumber,
757			akpost->serialNumber, "CE_AuthorityKeyID.serialNumber");
758	}
759	return rtn;
760}
761
762static void authKeyIdFree(void *arg)
763{
764	CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)arg;
765
766	if(akid->keyIdentifier.Data) {
767		free(akid->keyIdentifier.Data);
768	}
769	if(akid->generalNames) {
770		genNamesFree(akid->generalNames);		// genNamesCreate mallocd
771		free(akid->generalNames);				// we mallocd
772	}
773	if(akid->serialNumber.Data) {
774		free(akid->serialNumber.Data);
775	}
776}
777
778#pragma mark --- CE_CertPolicies ---
779
780/* random OIDs, pick 1..NUM_CP_OIDS */
781static CSSM_OID cpOids[] =
782{
783	CSSMOID_EmailAddress,
784	CSSMOID_UnstructuredName,
785	CSSMOID_ContentType,
786	CSSMOID_MessageDigest
787};
788#define NUM_CP_OIDS 4
789
790/* CPS strings, pick one of NUM_CPS_STR */
791static char *someCPSs[] =
792{
793	(char *)"http://www.apple.com",
794	(char *)"https://cdnow.com",
795	(char *)"ftp:backwards.com"
796};
797#define NUM_CPS_STR		3
798
799/* make these looks like real sequences */
800static uint8 someUnotice[] = {0x30, 0x03, BER_TAG_BOOLEAN, 1, 0xff};
801static uint8 someOtherData[] = {0x30, 0x02, BER_TAG_NULL, 0};
802
803static void cpCreate(void *arg)
804{
805	CE_CertPolicies *cp = (CE_CertPolicies *)arg;
806	cp->numPolicies = genRand(1,3);
807	//cp->numPolicies = 1;
808	unsigned len = sizeof(CE_PolicyInformation) * cp->numPolicies;
809	cp->policies = (CE_PolicyInformation *)malloc(len);
810	memset(cp->policies, 0, len);
811
812	for(unsigned polDex=0; polDex<cp->numPolicies; polDex++) {
813		CE_PolicyInformation *pi = &cp->policies[polDex];
814		unsigned die = genRand(1, NUM_CP_OIDS);
815		pi->certPolicyId = cpOids[die - 1];
816		unsigned numQual = genRand(1,3);
817		pi->numPolicyQualifiers = numQual;
818		len = sizeof(CE_PolicyQualifierInfo) * numQual;
819		pi->policyQualifiers = (CE_PolicyQualifierInfo *)
820			malloc(len);
821		memset(pi->policyQualifiers, 0, len);
822		for(unsigned cpiDex=0; cpiDex<numQual; cpiDex++) {
823			CE_PolicyQualifierInfo *qi =
824				&pi->policyQualifiers[cpiDex];
825			if(randBool()) {
826				qi->policyQualifierId = CSSMOID_QT_CPS;
827				die = genRand(1, NUM_CPS_STR);
828				qi->qualifier.Data = (uint8 *)someCPSs[die - 1];
829				qi->qualifier.Length = strlen((char *)qi->qualifier.Data);
830			}
831			else {
832				qi->policyQualifierId = CSSMOID_QT_UNOTICE;
833				if(randBool()) {
834					qi->qualifier.Data = someUnotice;
835					qi->qualifier.Length = 5;
836				}
837				else {
838					qi->qualifier.Data = someOtherData;
839					qi->qualifier.Length = 4;
840				}
841			}
842		}
843	}
844}
845
846static unsigned cpCompare(const void *pre, const void *post)
847{
848	CE_CertPolicies *cppre  = (CE_CertPolicies *)pre;
849	CE_CertPolicies *cppost = (CE_CertPolicies *)post;
850
851	if(cppre->numPolicies != cppost->numPolicies) {
852		printf("CE_CertPolicies.numPolicies mismatch\n");
853		return 1;
854	}
855	unsigned rtn = 0;
856	for(unsigned polDex=0; polDex<cppre->numPolicies; polDex++) {
857		CE_PolicyInformation *pipre  = &cppre->policies[polDex];
858		CE_PolicyInformation *pipost = &cppost->policies[polDex];
859		rtn += compCssmData(pipre->certPolicyId, pipost->certPolicyId,
860			"CE_PolicyInformation.certPolicyId");
861		if(pipre->numPolicyQualifiers != pipost->numPolicyQualifiers) {
862			printf("CE_PolicyInformation.CE_PolicyInformation mismatch\n");
863			rtn++;
864			continue;
865		}
866
867		for(unsigned qiDex=0; qiDex<pipre->numPolicyQualifiers; qiDex++) {
868			CE_PolicyQualifierInfo *qipre  = &pipre->policyQualifiers[qiDex];
869			CE_PolicyQualifierInfo *qipost = &pipost->policyQualifiers[qiDex];
870			rtn += compCssmData(qipre->policyQualifierId,
871				qipost->policyQualifierId,
872				"CE_PolicyQualifierInfo.policyQualifierId");
873			rtn += compCssmData(qipre->qualifier,
874				qipost->qualifier,
875				"CE_PolicyQualifierInfo.qualifier");
876		}
877	}
878	return rtn;
879}
880
881static void cpFree(void *arg)
882{
883	CE_CertPolicies *cp = (CE_CertPolicies *)arg;
884	for(unsigned polDex=0; polDex<cp->numPolicies; polDex++) {
885		CE_PolicyInformation *pi = &cp->policies[polDex];
886		free(pi->policyQualifiers);
887	}
888	free(cp->policies);
889}
890
891#pragma mark --- CE_AuthorityInfoAccess ---
892
893/* random OIDs, pick 1..NUM_AI_OIDS */
894static CSSM_OID aiOids[] =
895{
896	CSSMOID_AD_OCSP,
897	CSSMOID_AD_CA_ISSUERS,
898	CSSMOID_AD_TIME_STAMPING,
899	CSSMOID_AD_CA_REPOSITORY
900};
901#define NUM_AI_OIDS 4
902
903static void aiaCreate(void *arg)
904{
905	CE_AuthorityInfoAccess *aia = (CE_AuthorityInfoAccess *)arg;
906	aia->numAccessDescriptions = genRand(1,3);
907	unsigned len = aia->numAccessDescriptions * sizeof(CE_AccessDescription);
908	aia->accessDescriptions = (CE_AccessDescription *)malloc(len);
909	memset(aia->accessDescriptions, 0, len);
910
911	for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) {
912		CE_AccessDescription *ad = &aia->accessDescriptions[dex];
913		int die = genRand(1, NUM_AI_OIDS);
914		ad->accessMethod = aiOids[die - 1];
915		genNameCreate(&ad->accessLocation);
916	}
917}
918
919static unsigned aiaCompare(const void *pre, const void *post)
920{
921	CE_AuthorityInfoAccess *apre = (CE_AuthorityInfoAccess *)pre;
922	CE_AuthorityInfoAccess *apost = (CE_AuthorityInfoAccess *)post;
923	unsigned rtn = 0;
924
925	if(apre->numAccessDescriptions != apost->numAccessDescriptions) {
926		printf("***CE_AuthorityInfoAccess.numAccessDescriptions miscompare\n");
927		return 1;
928	}
929	for(unsigned dex=0; dex<apre->numAccessDescriptions; dex++) {
930		CE_AccessDescription *adPre  = &apre->accessDescriptions[dex];
931		CE_AccessDescription *adPost = &apost->accessDescriptions[dex];
932		if(compCssmData(adPre->accessMethod, adPost->accessMethod,
933				"CE_AccessDescription.accessMethod")) {
934			rtn++;
935		}
936		rtn += genNameCompare(&adPre->accessLocation, &adPost->accessLocation);
937	}
938	return rtn;
939}
940
941static void aiaFree(void *arg)
942{
943	CE_AuthorityInfoAccess *aia = (CE_AuthorityInfoAccess *)arg;
944	for(unsigned dex=0; dex<aia->numAccessDescriptions; dex++) {
945		CE_AccessDescription *ad = &aia->accessDescriptions[dex];
946		genNameFree(&ad->accessLocation);
947	}
948	free(aia->accessDescriptions);
949}
950
951#pragma mark --- CE_QC_Statements ---
952
953/* a static array of CE_QC_Statement.statementId */
954static const CSSM_OID qcsOids[] = {
955	CSSMOID_OID_QCS_SYNTAX_V1,
956	CSSMOID_OID_QCS_SYNTAX_V2,
957	CSSMOID_ETSI_QCS_QC_COMPLIANCE,
958};
959#define NUM_QCS_OIDS 3
960#define WHICH_QCS_V2 1
961
962static void qcsCreate(void *arg)
963{
964	CE_QC_Statements *qcss = (CE_QC_Statements *)arg;
965	//unsigned numQcs = genRand(1,3);
966	unsigned numQcs = 1;
967	qcss->numQCStatements = numQcs;
968	qcss->qcStatements = (CE_QC_Statement *)malloc(numQcs * sizeof(CE_QC_Statement));
969	memset(qcss->qcStatements, 0, numQcs * sizeof(CE_QC_Statement));
970
971	for(unsigned dex=0; dex<numQcs; dex++) {
972		CE_QC_Statement *qcs = &qcss->qcStatements[dex];
973		unsigned whichOid = genRand(0, NUM_QCS_OIDS-1);
974		qcs->statementId = qcsOids[whichOid];
975
976		/* three legal combos of (semanticsInfo, otherInfo), constrained by whichOid */
977		unsigned coin = genRand(1, 2);
978		switch(coin) {
979			case 1:
980				/* nothing */
981				break;
982			case 2:
983			{
984				/*
985				 * CSSMOID_OID_QCS_SYNTAX_V2 --> semanticsInfo
986				 * other --> otherInfo
987				 */
988				if(whichOid == WHICH_QCS_V2) {
989					CE_SemanticsInformation *si = (CE_SemanticsInformation *)malloc(
990						sizeof(CE_SemanticsInformation));
991					qcs->semanticsInfo = si;
992					memset(si, 0, sizeof(CE_SemanticsInformation));
993
994					/* flip a coin; heads --> semanticsIdentifier */
995					coin = genRand(1, 2);
996					if(coin == 2) {
997						si->semanticsIdentifier = (CSSM_OID *)malloc(sizeof(CSSM_OID));
998						*si->semanticsIdentifier = qcsOids[0];
999					}
1000
1001					/* flip a coin; heads --> nameRegistrationAuthorities */
1002					/* also gen this one if semanticsInfo is empty */
1003					coin = genRand(1, 2);
1004					if((coin == 2) || (si->semanticsIdentifier == NULL)) {
1005						si->nameRegistrationAuthorities = (CE_NameRegistrationAuthorities *)
1006							malloc(sizeof(CE_NameRegistrationAuthorities));
1007						genNamesCreate(si->nameRegistrationAuthorities);
1008					}
1009				}
1010				else {
1011					/* ASN_ANY - just take an encoded NULL */
1012					CSSM_DATA *otherInfo = (CSSM_DATA *)malloc(sizeof(CSSM_DATA));
1013					otherInfo->Data = (uint8 *)malloc(2);
1014					otherInfo->Data[0] = 5;
1015					otherInfo->Data[1] = 0;
1016					otherInfo->Length = 2;
1017					qcs->otherInfo = otherInfo;
1018				}
1019				break;
1020			}
1021		}
1022	}
1023}
1024
1025static unsigned qcsCompare(const void *pre, const void *post)
1026{
1027	CE_QC_Statements *qpre = (CE_QC_Statements *)pre;
1028	CE_QC_Statements *qpost = (CE_QC_Statements *)post;
1029	uint32 numQcs = qpre->numQCStatements;
1030	if(numQcs != qpost->numQCStatements) {
1031		printf("***numQCStatements miscompare\n");
1032		return 1;
1033	}
1034
1035	unsigned rtn = 0;
1036	for(unsigned dex=0; dex<numQcs; dex++) {
1037		CE_QC_Statement *qcsPre  = &qpre->qcStatements[dex];
1038		CE_QC_Statement *qcsPost = &qpost->qcStatements[dex];
1039		if(compCssmData(qcsPre->statementId, qcsPost->statementId,
1040				"CE_QC_Statement.statementId")) {
1041			rtn++;
1042		}
1043		if(qcsPre->semanticsInfo) {
1044			if(qcsPost->semanticsInfo == NULL) {
1045				printf("***semanticsInfo in pre but not in post\n");
1046				rtn++;
1047			}
1048			else {
1049				CE_SemanticsInformation *siPre  = qcsPre->semanticsInfo;
1050				CE_SemanticsInformation *siPost = qcsPost->semanticsInfo;
1051				if((siPre->semanticsIdentifier == NULL) != (siPost->semanticsIdentifier == NULL)) {
1052					printf("***mismatch in presence of semanticsIdentifier\n");
1053					rtn++;
1054				}
1055				else if(siPre->semanticsIdentifier) {
1056					if(compCssmData(*siPre->semanticsIdentifier, *siPost->semanticsIdentifier,
1057							"CE_SemanticsInformation.semanticsIdentifier")) {
1058						rtn++;
1059					}
1060				}
1061				if((siPre->nameRegistrationAuthorities == NULL) !=
1062				   (siPost->nameRegistrationAuthorities == NULL)) {
1063					printf("***mismatch in presence of nameRegistrationAuthorities\n");
1064					rtn++;
1065				}
1066				else if(siPre->nameRegistrationAuthorities) {
1067					rtn += genNamesCompare(siPre->nameRegistrationAuthorities,
1068						siPost->nameRegistrationAuthorities);
1069				}
1070			}
1071		}
1072		else if(qcsPost->semanticsInfo != NULL) {
1073			printf("***semanticsInfo in post but not in pre\n");
1074			rtn++;
1075		}
1076		if(qcsPre->otherInfo) {
1077			if(qcsPost->otherInfo == NULL) {
1078				printf("***otherInfo in pre but not in post\n");
1079				rtn++;
1080			}
1081			else {
1082				if(compCssmData(*qcsPre->otherInfo, *qcsPre->otherInfo,
1083						"CE_QC_Statement.otherInfo")) {
1084					rtn++;
1085				}
1086			}
1087		}
1088		else if(qcsPost->otherInfo != NULL) {
1089			printf("***otherInfo in post but not in pre\n");
1090			rtn++;
1091		}
1092	}
1093	return rtn;
1094}
1095
1096static void qcsFree(void *arg)
1097{
1098	CE_QC_Statements *qcss = (CE_QC_Statements *)arg;
1099	uint32 numQcs = qcss->numQCStatements;
1100	for(unsigned dex=0; dex<numQcs; dex++) {
1101		CE_QC_Statement *qcs = &qcss->qcStatements[dex];
1102		if(qcs->semanticsInfo) {
1103			CE_SemanticsInformation *si = qcs->semanticsInfo;
1104			if(si->semanticsIdentifier) {
1105				free(si->semanticsIdentifier);
1106			}
1107			if(si->nameRegistrationAuthorities) {
1108				genNamesFree(si->nameRegistrationAuthorities);
1109				free(si->nameRegistrationAuthorities);
1110			}
1111			free(qcs->semanticsInfo);
1112		}
1113		if(qcs->otherInfo) {
1114			free(qcs->otherInfo->Data);
1115			free(qcs->otherInfo);
1116		}
1117	}
1118	free(qcss->qcStatements);
1119}
1120
1121#pragma mark --- test definitions ---
1122
1123/*
1124 * Define one extension test.
1125 */
1126
1127/*
1128 * Cook up this extension with random, reasonable values.
1129 * Incoming pointer refers to extension-specific C struct, mallocd
1130 * and zeroed by main test routine.
1131 */
1132typedef void (*extenCreateFcn)(void *arg);
1133
1134/*
1135 * Compare two instances of this extension. Return number of
1136 * compare errors.
1137 */
1138typedef unsigned (*extenCompareFcn)(
1139	const void *preEncode,
1140	const void *postEncode);
1141
1142/*
1143 * Free struct components mallocd in extenCreateFcn. Do not free
1144 * the outer struct.
1145 */
1146typedef void (*extenFreeFcn)(void *arg);
1147
1148typedef struct {
1149	/* three extension-specific functions */
1150	extenCreateFcn		createFcn;
1151	extenCompareFcn		compareFcn;
1152	extenFreeFcn		freeFcn;
1153
1154	/* size of C struct passed to all three functions */
1155	unsigned			extenSize;
1156
1157	/* the OID for this extension */
1158	CSSM_OID			extenOid;
1159
1160	/* description for error logging and blob writing */
1161	const char			*extenDescr;
1162
1163	/* command-line letter for this one */
1164	char				extenLetter;
1165
1166} ExtenTest;
1167
1168/* empty freeFcn means no extension-specific resources to free */
1169#define NO_FREE		NULL
1170
1171static ExtenTest extenTests[] = {
1172	{ kuCreate, kuCompare, NO_FREE,
1173	  sizeof(CE_KeyUsage), CSSMOID_KeyUsage,
1174	  "KeyUsage", 'k' },
1175	{ bcCreate, bcCompare, NO_FREE,
1176	  sizeof(CE_BasicConstraints), CSSMOID_BasicConstraints,
1177	  "BasicConstraints", 'b' },
1178	{ ekuCreate, ekuCompare, NO_FREE,
1179	  sizeof(CE_ExtendedKeyUsage), CSSMOID_ExtendedKeyUsage,
1180	  "ExtendedKeyUsage", 'x' },
1181	{ skidCreate, skidCompare, skidFree,
1182	  sizeof(CSSM_DATA), CSSMOID_SubjectKeyIdentifier,
1183	  "SubjectKeyID", 's' },
1184	{ authKeyIdCreate, authKeyIdCompare, authKeyIdFree,
1185	  sizeof(CE_AuthorityKeyID), CSSMOID_AuthorityKeyIdentifier,
1186	  "AuthorityKeyID", 'a' },
1187	{ genNamesCreate, genNamesCompare, genNamesFree,
1188	  sizeof(CE_GeneralNames), CSSMOID_SubjectAltName,
1189	  "SubjectAltName", 't' },
1190	{ genNamesCreate, genNamesCompare, genNamesFree,
1191	  sizeof(CE_GeneralNames), CSSMOID_IssuerAltName,
1192	  "IssuerAltName", 'i' },
1193	{ nctCreate, nctCompare, NO_FREE,
1194	  sizeof(CE_NetscapeCertType), CSSMOID_NetscapeCertType,
1195	  "NetscapeCertType", 'n' },
1196	{ cdpCreate, cdpCompare, cdpFree,
1197	  sizeof(CE_CRLDistPointsSyntax), CSSMOID_CrlDistributionPoints,
1198	  "CRLDistPoints", 'p' },
1199	{ cpCreate, cpCompare, cpFree,
1200	  sizeof(CE_CertPolicies), CSSMOID_CertificatePolicies,
1201	  "CertPolicies", 'c' },
1202	{ aiaCreate, aiaCompare, aiaFree,
1203	  sizeof(CE_AuthorityInfoAccess), CSSMOID_AuthorityInfoAccess,
1204	  "AuthorityInfoAccess", 'A' },
1205	{ aiaCreate, aiaCompare, aiaFree,
1206	  sizeof(CE_AuthorityInfoAccess), CSSMOID_SubjectInfoAccess,
1207	  "SubjectInfoAccess", 'S' },
1208	{ qcsCreate, qcsCompare, qcsFree,
1209	  sizeof(CE_QC_Statements), CSSMOID_QC_Statements,
1210	  "QualifiedCertStatements", 'q' },
1211};
1212
1213#define NUM_EXTEN_TESTS		(sizeof(extenTests) / sizeof(ExtenTest))
1214
1215static void printExten(
1216	CSSM_X509_EXTENSION	&extn,
1217	bool				preEncode,
1218	OidParser			&parser)
1219{
1220	CSSM_FIELD field;
1221	field.FieldOid = extn.extnId;
1222	field.FieldValue.Data = (uint8 *)&extn;
1223	field.FieldValue.Length = sizeof(CSSM_X509_EXTENSION);
1224	printf("=== %s:\n", preEncode ? "PRE-ENCODE" : "POST-DECODE" );
1225	printCertField(field, parser, CSSM_TRUE);
1226}
1227
1228static int doTest(
1229	CSSM_CL_HANDLE	clHand,
1230	CSSM_CSP_HANDLE	cspHand,
1231	ExtenTest		&extenTest,
1232	bool			writeBlobs,
1233	const char		*constFileName,	// all blobs to this file if non-NULL
1234	bool			displayExtens,
1235	OidParser 		&parser)
1236{
1237	/*
1238	 * 1. Cook up a random and reasonable instance of the C struct
1239	 *    associated with this extension.
1240	 */
1241	void *preEncode = CSSM_MALLOC(extenTest.extenSize);
1242	memset(preEncode, 0, extenTest.extenSize);
1243	extenTest.createFcn(preEncode);
1244
1245	/*
1246	 * Cook up the associated CSSM_X509_EXTENSION.
1247	 */
1248	CSSM_X509_EXTENSION	extnPre;
1249
1250	extnPre.extnId   			= extenTest.extenOid;
1251	extnPre.critical 			= randBool();
1252	extnPre.format   			= CSSM_X509_DATAFORMAT_PARSED;
1253	extnPre.value.parsedValue 	= preEncode;
1254	extnPre.BERvalue.Data = NULL;
1255	extnPre.BERvalue.Length = 0;
1256
1257	/* encode the extension in a TBSCert */
1258	CSSM_DATA_PTR rawCert = CB_MakeCertTemplate(clHand,
1259		0x12345678,			// serial number
1260		dummyName,
1261		dummyName,
1262		notBefore,
1263		notAfter,
1264		&subjPubKey,
1265		SIG_ALG,
1266		NULL,				// subjUniqueId
1267		NULL,				// issuerUniqueId
1268		&extnPre,			// extensions
1269		1);					// numExtensions
1270	if(rawCert == NULL) {
1271		printf("Error generating template; aborting.\n");
1272		/* show what we tried to encode */
1273		printExten(extnPre, true, parser);
1274		return 1;
1275	}
1276
1277	/* sign the cert */
1278	CSSM_DATA signedCert = {0, NULL};
1279	CSSM_CC_HANDLE sigHand;
1280	CSSM_RETURN crtn = CSSM_CSP_CreateSignatureContext(cspHand,
1281			SIG_ALG,
1282			NULL,			// no passphrase for now
1283			&subjPrivKey,
1284			&sigHand);
1285	if(crtn) {
1286		printError("CreateSignatureContext", crtn);
1287		return 1;
1288	}
1289
1290	crtn = CSSM_CL_CertSign(clHand,
1291		sigHand,
1292		rawCert,			// CertToBeSigned
1293		NULL,				// SignScope per spec
1294		0,					// ScopeSize per spec
1295		&signedCert);
1296	if(crtn) {
1297		printError("CSSM_CL_CertSign", crtn);
1298		/* show what we tried to encode */
1299		printExten(extnPre, true, parser);
1300		return 1;
1301	}
1302	CSSM_DeleteContext(sigHand);
1303
1304	if(writeBlobs) {
1305		char fileName[200];
1306		if(constFileName) {
1307			strcpy(fileName, constFileName);
1308		}
1309		else {
1310			sprintf(fileName, "%scert.der", extenTest.extenDescr);
1311		}
1312		writeFile(fileName, signedCert.Data, signedCert.Length);
1313		printf("...wrote %lu bytes to %s\n", signedCert.Length, fileName);
1314	}
1315
1316	/* snag the same extension from the encoded cert */
1317	CSSM_DATA_PTR postField;
1318	CSSM_HANDLE resultHand;
1319	uint32 numFields;
1320
1321	crtn = CSSM_CL_CertGetFirstFieldValue(clHand,
1322		&signedCert,
1323		&extenTest.extenOid,
1324		&resultHand,
1325		&numFields,
1326		&postField);
1327	if(crtn) {
1328		printf("****Extension field not found on decode for %s\n",
1329			extenTest.extenDescr);
1330		printError("CSSM_CL_CertGetFirstFieldValue", crtn);
1331
1332		/* show what we tried to encode and decode */
1333		printExten(extnPre, true, parser);
1334		return 1;
1335	}
1336
1337	if(numFields != 1) {
1338		printf("****GetFirstFieldValue: expect 1 value, got %u\n",
1339			(unsigned)numFields);
1340		return 1;
1341	}
1342	CSSM_CL_CertAbortQuery(clHand, resultHand);
1343
1344	/* verify the fields we generated */
1345	CSSM_X509_EXTENSION *extnPost = (CSSM_X509_EXTENSION *)postField->Data;
1346	if((extnPost == NULL) ||
1347	   (postField->Length != sizeof(CSSM_X509_EXTENSION))) {
1348		printf("***Malformed CSSM_X509_EXTENSION (1) after decode\n");
1349		return 1;
1350	}
1351	int rtn = 0;
1352	rtn += compBool(extnPre.critical, extnPost->critical,
1353		"CSSM_X509_EXTENSION.critical");
1354	rtn += compCssmData(extnPre.extnId, extnPost->extnId,
1355		"CSSM_X509_EXTENSION.extnId");
1356
1357	if(extnPost->format != CSSM_X509_DATAFORMAT_PARSED) {
1358		printf("***Expected CSSM_X509_DATAFORMAT_PARSED (%x(x), got %x(x)\n",
1359			CSSM_X509_DATAFORMAT_PARSED, extnPost->format);
1360	}
1361	if(extnPost->value.parsedValue == NULL) {
1362		printf("***no parsedValue pointer!\n");
1363		return 1;
1364	}
1365
1366	/* down to extension-specific compare */
1367	rtn += extenTest.compareFcn(preEncode, extnPost->value.parsedValue);
1368
1369	if(rtn) {
1370		/* print preencode only on error */
1371		printExten(extnPre, true, parser);
1372	}
1373	if(displayExtens || rtn) {
1374		printExten(*extnPost, false, parser);
1375	}
1376
1377	/* free the allocated data */
1378	if(extenTest.freeFcn) {
1379		extenTest.freeFcn(preEncode);
1380	}
1381	CSSM_CL_FreeFieldValue(clHand, &extenTest.extenOid, postField);
1382	CSSM_FREE(rawCert->Data);
1383	CSSM_FREE(rawCert);
1384	CSSM_FREE(signedCert.Data);
1385	CSSM_FREE(preEncode);
1386	return rtn;
1387}
1388
1389static void doPause(bool pause)
1390{
1391	if(!pause) {
1392		return;
1393	}
1394	fpurge(stdin);
1395	printf("CR to continue ");
1396	getchar();
1397}
1398
1399int main(int argc, char **argv)
1400{
1401	CSSM_CL_HANDLE		clHand;
1402	CSSM_CSP_HANDLE		cspHand;
1403	CSSM_RETURN			crtn;
1404	int					arg;
1405	int					rtn;
1406	OidParser			parser;
1407	char				*argp;
1408	unsigned			i;
1409
1410	/* user-specificied params */
1411	unsigned			minExtenNum = 0;
1412	unsigned 			maxExtenNum = NUM_EXTEN_TESTS-1;
1413	bool				writeBlobs = false;
1414	bool				displayExtens = false;
1415	bool				quiet = false;
1416	unsigned			loops = LOOPS_DEF;
1417	bool				pauseLoop = false;
1418	bool				pauseCert = false;
1419	const char			*constFileName = NULL;
1420
1421	for(arg=1; arg<argc; arg++) {
1422		argp = argv[arg];
1423		switch(argp[0]) {
1424			case 'w':
1425				writeBlobs = true;
1426				break;
1427			case 'd':
1428				displayExtens = true;
1429				break;
1430			case 'q':
1431				quiet = true;
1432				break;
1433			case 'p':
1434				pauseLoop = true;
1435				break;
1436			case 'P':
1437				pauseCert = true;
1438				break;
1439			case 'l':
1440				loops = atoi(&argp[2]);
1441				break;
1442			case 'f':
1443				constFileName = &argp[2];
1444				break;
1445			case 'e':
1446				if(argp[1] != '=') {
1447					usage(argv);
1448				}
1449				/* scan thru test array looking for epecified extension */
1450				for(i=0; i<NUM_EXTEN_TESTS; i++) {
1451					if(extenTests[i].extenLetter == argp[2]) {
1452						minExtenNum = maxExtenNum = i;
1453						break;
1454					}
1455				}
1456				if(i == NUM_EXTEN_TESTS) {
1457					usage(argv);
1458				}
1459				break;
1460			default:
1461				usage(argv);
1462		}
1463	}
1464
1465
1466	/* common setup */
1467	clHand = clStartup();
1468	if(clHand == 0) {
1469		return 0;
1470	}
1471	cspHand = cspStartup();
1472	if(cspHand == 0) {
1473		return 0;
1474	}
1475
1476	printf("Starting extenTest; args: ");
1477	for(i=1; i<(unsigned)argc; i++) {
1478		printf("%s ", argv[i]);
1479	}
1480	printf("\n");
1481
1482	/* one common key pair - we're definitely not testing this */
1483	crtn = cspGenKeyPair(cspHand,
1484		KEY_ALG,
1485		SUBJ_KEY_LABEL,
1486		strlen(SUBJ_KEY_LABEL),
1487		KEY_SIZE_BITS,
1488		&subjPubKey,
1489		CSSM_FALSE,			// pubIsRef - should work both ways, but not yet
1490		CSSM_KEYUSE_VERIFY,
1491		CSSM_KEYBLOB_RAW_FORMAT_NONE,
1492		&subjPrivKey,
1493		CSSM_TRUE,			// privIsRef - doesn't matter
1494		CSSM_KEYUSE_SIGN,
1495		CSSM_KEYBLOB_RAW_FORMAT_NONE,
1496		CSSM_FALSE);
1497	if(crtn) {
1498		exit(1);
1499	}
1500
1501	/* common issuer/subject - not testing this */
1502	dummyName = CB_BuildX509Name(dummyRdn, NUM_DUMMY_NAMES);
1503	if(dummyName == NULL) {
1504		printf("CB_BuildX509Name failure");
1505		exit(1);
1506	}
1507
1508	/* not before/after in generalized time format */
1509	notBefore = CB_BuildX509Time(0);
1510	notAfter  = CB_BuildX509Time(10000);
1511
1512	for(unsigned loop=0; loop<loops; loop++) {
1513		if(!quiet) {
1514			printf("...loop %u\n", loop);
1515		}
1516		for(unsigned extenDex=minExtenNum; extenDex<=maxExtenNum; extenDex++) {
1517			rtn = doTest(clHand, cspHand, extenTests[extenDex],
1518				writeBlobs, constFileName, displayExtens, parser);
1519			if(rtn) {
1520				break;
1521			}
1522			doPause(pauseCert);
1523		}
1524		if(rtn) {
1525			break;
1526		}
1527		doPause(pauseLoop);
1528	}
1529
1530	if(rtn) {
1531		printf("***%s FAILED\n", argv[0]);
1532	}
1533	else if(!quiet) {
1534		printf("...%s passed\n", argv[0]);
1535	}
1536
1537
1538	/* cleanup */
1539	CB_FreeX509Name(dummyName);
1540	CB_FreeX509Time(notBefore);
1541	CB_FreeX509Time(notAfter);
1542	CSSM_ModuleDetach(cspHand);
1543	CSSM_ModuleDetach(clHand);
1544	return 0;
1545}
1546
1547