1/* Copyright (c) 1998-2003,2005-2006,2008 Apple Inc.
2 *
3 * signerAndSubjTp.c
4 *
5 * Create two certs - a root, and a subject cert signed by the root. Includes
6 * extension construction. Verify certs every which way, including various expected
7 * failures. This version uses CSSM_TP_SubmitCredRequest to create the certs.
8 *
9 */
10
11#include <utilLib/common.h>
12#include <utilLib/cspwrap.h>
13#include <security_cdsa_utils/cuFileIo.h>
14#include <clAppUtils/clutils.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <Security/cssm.h>
19#include <Security/x509defs.h>
20#include <Security/oidsattr.h>
21#include <Security/oidscert.h>
22#include <Security/oidsalg.h>
23#include <Security/certextensions.h>
24#include <Security/cssmapple.h>
25#include <string.h>
26
27#define SUBJ_KEY_LABEL		"subjectKey"
28#define ROOT_KEY_LABEL		"rootKey"
29/* default key and signature algorithm */
30#define SIG_ALG_DEFAULT		CSSM_ALGID_SHA1WithRSA
31#define SIG_OID_DEFAULT		CSSMOID_SHA1WithRSA
32#define KEY_ALG_DEFAULT		CSSM_ALGID_RSA
33
34/* for write certs/keys option */
35#define ROOT_CERT_FILE_NAME		"ssRootCert.cer"
36#define SUBJ_CERT_FILE_NAME		"ssSubjCert.cer"
37#define ROOT_KEY_FILE_NAME		"ssRootKey.der"
38#define SUBJ_KEY_FILE_NAME		"ssSubjKey.der"
39
40/* public key in ref form, TP supports this as of 1/30/02 */
41#define PUB_KEY_IS_REF			CSSM_TRUE
42
43#define SERIAL_DEFAULT			0x12345678
44
45static void usage(char **argv)
46{
47	printf("Usage: %s [options]\n", argv[0]);
48	printf("Options:\n");
49	printf("    w[rite certs and keys]\n");
50	printf("    a=alg  where alg is s(RSA/SHA1), m(RSA/MD5), f(FEE/MD5), F(FEE/SHA1),\n");
51	printf("           2(RSA/SHA224), 6(RSA/SHA256), 3(RSA/SHA384) 5=RSA/SHA512,\n");
52	printf("           e(ECDSA), E(ANSI/ECDSA), 7(ECDSA/SHA256), 8(ECDSA/SHA384), 9(ECDSA/SHA512)\n");
53	printf("    k=keySizeInBits\n");
54	printf("    c=commonName (for SSL compatible subject name)\n");
55	printf("    P (loop and pause for malloc debug)\n");
56	printf("Extension options:\n");
57	printf("    t=authorityKeyName     -- AuthorityKeyID, generalNames, DNSName plus s/n variant\n");
58	printf("    s                      -- SubjectKey, data = aabbccddeeff\n");
59	printf("    e=emailAddress         -- subjectAltName, RFC822Name variant\n");
60	printf("    i=issuerAltName        -- DNSName variant\n");
61	printf("    r=crlDistributionPoint -- dpn, URI variant\n");
62	printf("    u=authorityInfoAccess  -- OCSP, DNSName variant\n");
63	printf("    p=certPolicyString     -- CertPolicies, id_cps variant\n");
64	printf("    n=netscapeCertType     -- NetscapeCertType, specify an integer\n");
65	printf("    N=serialNumber         -- in decimal, default is 0x%x\n", SERIAL_DEFAULT);
66	exit(1);
67}
68
69/*
70 * RDN components for root, subject
71 */
72static CSSM_APPLE_TP_NAME_OID rootRdn[] =
73{
74	{ "Apple Computer",					&CSSMOID_OrganizationName },
75	{ "The Big Cheesy Debug Root",		&CSSMOID_CommonName }
76};
77#define NUM_ROOT_NAMES	(sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
78
79static CSSM_APPLE_TP_NAME_OID subjRdn[] =
80{
81	/* note extra space for normalize test */
82	{ "Apple  Computer",				&CSSMOID_OrganizationName },
83	/* this can get overridden by cmd line */
84	{ "Doug Mitchell",					&CSSMOID_CommonName }
85};
86#define NUM_SUBJ_NAMES	(sizeof(subjRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
87
88static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2);
89static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand,
90	CSSM_CSP_HANDLE	cspHand,
91	CSSM_DATA_PTR	cert,
92	CSSM_DATA_PTR	signerCert,
93	CSSM_KEY_PTR	key,
94	CSSM_ALGORITHMS	sigAlg,
95	CSSM_RETURN		expectResult,
96	const char 		*opString);
97
98/*
99 * Cook up trivial CE_GeneralName, one component of specified NameType.
100 */
101static void makeGeneralName(
102	CE_GeneralName		*genName,		/* locally declared, persistent */
103	char				*str,
104	CE_GeneralNameType	nameType)		/* GNT_RFC822Name, etc. */
105{
106	genName->nameType = nameType;
107	genName->berEncoded = CSSM_FALSE;
108	genName->name.Data = (uint8 *)str;
109	genName->name.Length = strlen(str);
110}
111
112/*
113 * Cook up a trivial CE_GeneralNames, one component of specified NameType.
114 */
115static void makeGeneralNames(
116	CE_GeneralNames		*genNames,		/* pointer from CE_DataAndType */
117	CE_GeneralName		*genName,		/* locally declared, persistent */
118	char				*str,
119	CE_GeneralNameType	nameType)		/* GNT_RFC822Name, etc. */
120{
121	genNames->numNames = 1;
122	genNames->generalName = genName;
123	makeGeneralName(genName, str, nameType);
124}
125
126int main(int argc, char **argv)
127{
128	CSSM_CL_HANDLE	clHand;			// CL handle
129	CSSM_CSP_HANDLE	cspHand;		// CSP handle
130	CSSM_TP_HANDLE	tpHand;			// TP handle
131	CSSM_DATA		signedRootCert;	// from CSSM_CL_CertSign
132	CSSM_DATA		signedSubjCert;	// from CSSM_CL_CertSign
133	CSSM_KEY		subjPubKey;		// subject's RSA public key blob
134	CSSM_KEY		subjPrivKey;	// subject's RSA private key - ref format
135	CSSM_KEY		rootPubKey;		// root's RSA public key blob
136	CSSM_KEY		rootPrivKey;	// root's RSA private key - ref format
137	CSSM_RETURN		crtn;
138	CSSM_KEY_PTR	extractRootKey;	// from CSSM_CL_CertGetKeyInfo()
139	CSSM_KEY_PTR	extractSubjKey;	// ditto
140	unsigned		badByte;
141	int				arg;
142	unsigned		errorCount = 0;
143	CSSM_DATA		refId;			// mallocd by CSSM_TP_SubmitCredRequest
144	CSSM_APPLE_TP_CERT_REQUEST	certReq;
145	CSSM_TP_REQUEST_SET			reqSet;
146	sint32						estTime;
147	CSSM_BOOL					confirmRequired;
148	CSSM_TP_RESULT_SET_PTR		rootResultSet;
149	CSSM_TP_RESULT_SET_PTR		subjResultSet;
150	CSSM_ENCODED_CERT			*rootEncCert;
151	CSSM_ENCODED_CERT			*subjEncCert;
152	CSSM_TP_CALLERAUTH_CONTEXT 	CallerAuthContext;
153	CSSM_FIELD					policyId;
154
155	/* extension support */
156	CE_GeneralName				sanGenName;		/* subjectAltName */
157	CE_GeneralName				ianGenName;		/* issuerAltName */
158	CE_DistributionPointName	distPointName;
159	CE_GeneralName				crlGenName;
160	CE_GeneralNames				crlGenNames;
161	CE_CRLDistributionPoint		cdp;
162	CE_AccessDescription		accessDescr;
163	CE_GeneralNames				authKeyIdGenNames;
164	CE_GeneralName				authKeyIdGenName;
165	uint8						authKeyIdSerial[4] = {0x22, 0x33, 0x44, 0x55 };
166	uint8						subjKeyIdData[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
167	CE_PolicyQualifierInfo		polQualInfo;
168	CE_PolicyInformation		polInfo;
169
170	/* user-spec'd variables */
171	CSSM_BOOL		writeBlobs = CSSM_FALSE;
172	CSSM_ALGORITHMS	keyAlg = KEY_ALG_DEFAULT;
173	CSSM_ALGORITHMS sigAlg = SIG_ALG_DEFAULT;
174	CSSM_OID		sigOid = SIG_OID_DEFAULT;
175	uint32			keySizeInBits = CSP_KEY_SIZE_DEFAULT;
176	char			*subjectEmail = NULL;			// for S/MIME subjectAltName
177	char			*issuerAltName = NULL;
178	char			*crlDistPoint = NULL;
179	char			*authorityInfoAccess = NULL;
180	char			*authKeyIdName = NULL;
181	bool			subjectKeyId = false;
182	char			*certPoliciesStr = NULL;
183	bool			netscapeTypeSpec = false;
184	uint16			netscapeType = 0;
185	uint32			serialNumber = SERIAL_DEFAULT;
186	bool			loopPause = false;
187
188	/*
189	 * Extensions. Subject at least one (KeyUsage).
190	 * Root has KeyUsage and BasicConstraints.
191	 */
192	CE_DataAndType 			exts[8];
193	CE_DataAndType			*extp = &exts[0];
194
195	for(arg=1; arg<argc; arg++) {
196		switch(argv[arg][0]) {
197			case 'w':
198				writeBlobs = CSSM_TRUE;
199				break;
200			case 'a':
201				if((argv[arg][1] == '\0') || (argv[arg][2] == '\0')) {
202					usage(argv);
203				}
204				switch(argv[arg][2]) {
205					case 's':
206						keyAlg = CSSM_ALGID_RSA;
207						sigAlg = CSSM_ALGID_SHA1WithRSA;
208						sigOid = CSSMOID_SHA1WithRSA;
209						break;
210					case 'm':
211						keyAlg = CSSM_ALGID_RSA;
212						sigAlg = CSSM_ALGID_MD5WithRSA;
213						sigOid = CSSMOID_MD5WithRSA;
214						break;
215					case '2':
216						keyAlg = CSSM_ALGID_RSA;
217						sigAlg = CSSM_ALGID_SHA224WithRSA;
218						sigOid = CSSMOID_SHA224WithRSA;
219						break;
220					case '6':
221						keyAlg = CSSM_ALGID_RSA;
222						sigAlg = CSSM_ALGID_SHA256WithRSA;
223						sigOid = CSSMOID_SHA256WithRSA;
224						break;
225					case '3':
226						keyAlg = CSSM_ALGID_RSA;
227						sigAlg = CSSM_ALGID_SHA384WithRSA;
228						sigOid = CSSMOID_SHA384WithRSA;
229						break;
230					case '5':
231						keyAlg = CSSM_ALGID_RSA;
232						sigAlg = CSSM_ALGID_SHA512WithRSA;
233						sigOid = CSSMOID_SHA512WithRSA;
234						break;
235					case 'f':
236						keyAlg = CSSM_ALGID_FEE;
237						sigAlg = CSSM_ALGID_FEE_MD5;
238						sigOid = CSSMOID_APPLE_FEE_MD5;
239						break;
240					case 'F':
241						keyAlg = CSSM_ALGID_FEE;
242						sigAlg = CSSM_ALGID_FEE_SHA1;
243						sigOid = CSSMOID_APPLE_FEE_SHA1;
244						break;
245					case 'e':
246						keyAlg = CSSM_ALGID_FEE;
247						sigAlg = CSSM_ALGID_SHA1WithECDSA;
248						sigOid = CSSMOID_APPLE_ECDSA;
249						break;
250					case 'E':
251						keyAlg = CSSM_ALGID_ECDSA;
252						sigAlg = CSSM_ALGID_SHA1WithECDSA;
253						sigOid = CSSMOID_ECDSA_WithSHA1;
254						break;
255					case '7':
256						keyAlg = CSSM_ALGID_ECDSA;
257						sigAlg = CSSM_ALGID_SHA256WithECDSA;
258						sigOid = CSSMOID_ECDSA_WithSHA256;
259						break;
260					case '8':
261						keyAlg = CSSM_ALGID_ECDSA;
262						sigAlg = CSSM_ALGID_SHA384WithECDSA;
263						sigOid = CSSMOID_ECDSA_WithSHA384;
264						break;
265					case '9':
266						keyAlg = CSSM_ALGID_ECDSA;
267						sigAlg = CSSM_ALGID_SHA512WithECDSA;
268						sigOid = CSSMOID_ECDSA_WithSHA512;
269						break;
270					default:
271						usage(argv);
272				}
273				break;
274		    case 'k':
275				keySizeInBits = atoi(&argv[arg][2]);
276				break;
277			case 'e':
278				subjectEmail = &argv[arg][2];
279				break;
280			case 'i':
281				issuerAltName = &argv[arg][2];
282				break;
283			case 'r':
284				crlDistPoint = &argv[arg][2];
285				break;
286			case 'u':
287				authorityInfoAccess = &argv[arg][2];
288				break;
289			case 't':
290				authKeyIdName = &argv[arg][2];
291				break;
292			case 's':
293				subjectKeyId = true;
294				break;
295			case 'p':
296				certPoliciesStr =  &argv[arg][2];
297				break;
298			case 'n':
299				netscapeTypeSpec = true;
300				netscapeType = atoi(&argv[arg][2]);
301				break;
302			case 'c':
303				subjRdn[NUM_SUBJ_NAMES-1].string = &argv[arg][2];
304				break;
305		    case 'N':
306				serialNumber = atoi(&argv[arg][2]);
307				break;
308			case 'P':
309				loopPause = true;
310				break;
311			default:
312				usage(argv);
313		}
314	}
315
316	/* connect to CL, TP, and CSP */
317	clHand = clStartup();
318	if(clHand == 0) {
319		return 0;
320	}
321	tpHand = tpStartup();
322	if(tpHand == 0) {
323		return 0;
324	}
325	cspHand = cspStartup();
326	if(cspHand == 0) {
327		return 0;
328	}
329
330	/* subsequent errors to abort: to detach */
331
332	/* cook up an RSA key pair for the subject */
333	crtn = cspGenKeyPair(cspHand,
334		keyAlg,
335		SUBJ_KEY_LABEL,
336		strlen(SUBJ_KEY_LABEL),
337		keySizeInBits,
338		&subjPubKey,
339		#if PUB_KEY_IS_REF
340		CSSM_TRUE,
341		#else
342		CSSM_FALSE,								// pubIsRef
343		#endif
344		CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_ENCRYPT,
345		CSSM_KEYBLOB_RAW_FORMAT_NONE,
346		&subjPrivKey,
347		writeBlobs ? CSSM_FALSE : CSSM_TRUE,	// privIsRef
348		CSSM_KEYUSE_SIGN | CSSM_KEYUSE_DECRYPT,
349		CSSM_KEYBLOB_RAW_FORMAT_NONE,
350		CSSM_FALSE);
351	if(crtn) {
352		errorCount++;
353		goto abort;
354	}
355
356	/* and the root */
357	crtn = cspGenKeyPair(cspHand,
358		keyAlg,
359		ROOT_KEY_LABEL,
360		strlen(ROOT_KEY_LABEL),
361		keySizeInBits,
362		&rootPubKey,
363		CSSM_FALSE,			// pubIsRef - should work both ways, but not yet
364		CSSM_KEYUSE_VERIFY,
365		CSSM_KEYBLOB_RAW_FORMAT_NONE,
366		&rootPrivKey,
367		writeBlobs ? CSSM_FALSE : CSSM_TRUE,	// privIsRef
368		CSSM_KEYUSE_SIGN,
369		CSSM_KEYBLOB_RAW_FORMAT_NONE,
370		CSSM_FALSE);
371	if(crtn) {
372		errorCount++;
373		goto abort;
374	}
375
376	if(compareKeyData(&rootPubKey, &subjPubKey)) {
377	 	printf("**WARNING: Identical root and subj keys!\n");
378	}
379
380	if(writeBlobs) {
381		writeFile(ROOT_KEY_FILE_NAME, rootPrivKey.KeyData.Data,
382			rootPrivKey.KeyData.Length);
383		printf("...wrote %lu bytes to %s\n", rootPrivKey.KeyData.Length,
384			ROOT_KEY_FILE_NAME);
385		writeFile(SUBJ_KEY_FILE_NAME, subjPrivKey.KeyData.Data,
386			subjPrivKey.KeyData.Length);
387		printf("...wrote %lu bytes to %s\n", subjPrivKey.KeyData.Length,
388			SUBJ_KEY_FILE_NAME);
389	}
390
391	if(loopPause) {
392		fpurge(stdin);
393		printf("pausing before root CSSM_TP_SubmitCredRequest; CR to continue:");
394		getchar();
395	}
396loopTop:
397
398	/* A KeyUsage extension for both certs */
399	exts[0].type = DT_KeyUsage;
400	exts[0].critical = CSSM_FALSE;
401	exts[0].extension.keyUsage = CE_KU_DigitalSignature | CE_KU_KeyCertSign;
402
403	/* root - BasicConstraints extensions */
404	exts[1].type = DT_BasicConstraints;
405	exts[1].critical = CSSM_TRUE;
406	exts[1].extension.basicConstraints.cA = CSSM_TRUE;
407	exts[1].extension.basicConstraints.pathLenConstraintPresent = CSSM_TRUE;
408	exts[1].extension.basicConstraints.pathLenConstraint = 2;
409
410	/* certReq for root */
411	memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST));
412	certReq.cspHand = cspHand;
413	certReq.clHand = clHand;
414	certReq.serialNumber = serialNumber;
415	certReq.numSubjectNames = NUM_ROOT_NAMES;
416	certReq.subjectNames = rootRdn;
417	certReq.numIssuerNames = 0;
418	certReq.issuerNames = NULL;
419	certReq.certPublicKey = &rootPubKey;
420	certReq.issuerPrivateKey = &rootPrivKey;
421	certReq.signatureAlg = sigAlg;
422	certReq.signatureOid = sigOid;
423	certReq.notBefore = 0;			// now
424	certReq.notAfter = 10000;		// seconds from now
425	certReq.numExtensions = 2;
426	certReq.extensions = exts;
427
428	reqSet.NumberOfRequests = 1;
429	reqSet.Requests = &certReq;
430
431	/* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */
432	memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
433	memset(&policyId, 0, sizeof(CSSM_FIELD));
434	policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
435	CallerAuthContext.Policy.NumberOfPolicyIds = 1;
436	CallerAuthContext.Policy.PolicyIds = &policyId;
437
438	/* generate root cert */
439	printf("Creating root cert...\n");
440	crtn = CSSM_TP_SubmitCredRequest(tpHand,
441		NULL,				// PreferredAuthority
442		CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
443		&reqSet,
444		&CallerAuthContext,
445		&estTime,
446		&refId);
447	if(crtn) {
448		printError("CSSM_TP_SubmitCredRequest", crtn);
449		errorCount++;
450		goto abort;
451	}
452	crtn = CSSM_TP_RetrieveCredResult(tpHand,
453		&refId,
454		NULL,				// CallerAuthCredentials
455		&estTime,
456		&confirmRequired,
457		&rootResultSet);
458	if(crtn) {
459		printError("CSSM_TP_RetrieveCredResult", crtn);
460		errorCount++;
461		goto abort;
462	}
463	CSSM_FREE(refId.Data);
464	if(rootResultSet == NULL) {
465		printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
466		errorCount++;
467		goto abort;
468	}
469	rootEncCert = (CSSM_ENCODED_CERT *)rootResultSet->Results;
470	signedRootCert = rootEncCert->CertBlob;
471	if(writeBlobs) {
472		writeFile(ROOT_CERT_FILE_NAME, signedRootCert.Data, signedRootCert.Length);
473		printf("...wrote %lu bytes to %s\n", signedRootCert.Length,
474			ROOT_CERT_FILE_NAME);
475	}
476
477	if(loopPause) {
478		fpurge(stdin);
479		printf("pausing before subject CSSM_TP_SubmitCredRequest; CR to continue:");
480		getchar();
481	}
482
483	/* now a subject cert signed by the root cert */
484	printf("Creating subject cert...\n");
485	certReq.serialNumber = serialNumber + 1;
486	certReq.numSubjectNames = NUM_SUBJ_NAMES;
487	certReq.subjectNames = subjRdn;
488	certReq.numIssuerNames = NUM_ROOT_NAMES;
489	certReq.issuerNames = rootRdn;
490	certReq.certPublicKey = &subjPubKey;
491	certReq.issuerPrivateKey = &rootPrivKey;
492	certReq.numExtensions = 1;
493	certReq.extensions = exts;
494
495	/* subject cert extensions - at least KeyUsage, maybe more */
496	exts[0].type = DT_KeyUsage;
497	exts[0].critical = CSSM_FALSE;
498	exts[0].extension.keyUsage =
499		CE_KU_DigitalSignature | CE_KU_DataEncipherment | CE_KU_KeyAgreement;
500	extp = &exts[1];
501
502	if(subjectEmail) {
503		/* subjectAltName extension */
504		makeGeneralNames(&extp->extension.subjectAltName, &sanGenName,
505			subjectEmail, GNT_RFC822Name);
506		extp->type = DT_SubjectAltName;
507		extp->critical = CSSM_FALSE;
508		certReq.numExtensions++;
509		extp++;
510	}
511
512	if(authKeyIdName) {
513		/* AuthorityKeyID extension */
514		makeGeneralNames(&authKeyIdGenNames, &authKeyIdGenName,
515			authKeyIdName, GNT_DNSName);
516		CE_AuthorityKeyID *akid = &extp->extension.authorityKeyID;
517		memset(akid, 0, sizeof(*akid));
518		akid->generalNamesPresent = CSSM_TRUE;
519		akid->generalNames = &authKeyIdGenNames;
520		akid->serialNumberPresent = CSSM_TRUE;
521		akid->serialNumber.Data = authKeyIdSerial;
522		akid->serialNumber.Length = sizeof(authKeyIdSerial);
523
524		extp->type = DT_AuthorityKeyID;
525		extp->critical = CSSM_FALSE;
526		certReq.numExtensions++;
527		extp++;
528	}
529
530	if(subjectKeyId) {
531		/* SubjectKeyID extension */
532		CSSM_DATA *skid = &extp->extension.subjectKeyID;
533		skid->Data = subjKeyIdData;
534		skid->Length = sizeof(subjKeyIdData);
535
536		extp->type = DT_SubjectKeyID;
537		extp->critical = CSSM_FALSE;
538		certReq.numExtensions++;
539		extp++;
540	}
541
542	if(issuerAltName) {
543		/* issuerAltName extension */
544		makeGeneralNames(&extp->extension.issuerAltName, &ianGenName,
545			issuerAltName, GNT_DNSName);
546		extp->type = DT_IssuerAltName;
547		extp->critical = CSSM_FALSE;
548		certReq.numExtensions++;
549		extp++;
550	}
551
552	if(crlDistPoint) {
553		/* CRLDistributionPoints extension */
554		memset(&distPointName, 0, sizeof(distPointName));
555		makeGeneralNames(&crlGenNames, &crlGenName,
556			crlDistPoint, GNT_URI);
557		distPointName.nameType = CE_CDNT_FullName;
558		distPointName.dpn.fullName = &crlGenNames;
559
560		cdp.distPointName = &distPointName;
561		cdp.reasonsPresent = CSSM_FALSE;
562		cdp.reasons = 0;
563		cdp.crlIssuer = NULL;
564
565		CE_CRLDistPointsSyntax	*dps = &extp->extension.crlDistPoints;
566		dps->numDistPoints = 1;
567		dps->distPoints = &cdp;
568		extp->type = DT_CrlDistributionPoints;
569		extp->critical = CSSM_FALSE;
570
571		certReq.numExtensions++;
572		extp++;
573	}
574
575	if(authorityInfoAccess) {
576		/* AuthorityInfoAccess extension */
577		CE_AuthorityInfoAccess *cad = &extp->extension.authorityInfoAccess;
578		cad->numAccessDescriptions = 1;
579		cad->accessDescriptions = &accessDescr;
580		makeGeneralName(&accessDescr.accessLocation, authorityInfoAccess,
581			GNT_DNSName);
582		accessDescr.accessMethod = CSSMOID_AD_OCSP;
583		extp->type = DT_AuthorityInfoAccess;
584		extp->critical = CSSM_FALSE;
585		certReq.numExtensions++;
586		extp++;
587	}
588
589	if(certPoliciesStr) {
590		/* Cert Policies extension */
591		CE_CertPolicies *cp = &extp->extension.certPolicies;
592		cp->numPolicies = 1;
593		cp->policies = &polInfo;
594		/* just make this policy OID up */
595		polInfo.certPolicyId = CSSMOID_APPLE_TP_PKINIT_CLIENT;
596		polInfo.numPolicyQualifiers = 1;
597		polInfo.policyQualifiers = &polQualInfo;
598		polQualInfo.policyQualifierId = CSSMOID_QT_CPS;
599		polQualInfo.qualifier.Data = (uint8 *)certPoliciesStr;
600		polQualInfo.qualifier.Length = strlen(certPoliciesStr);
601
602		extp->type = DT_CertPolicies;
603		extp->critical = CSSM_FALSE;
604		certReq.numExtensions++;
605		extp++;
606	}
607
608	if(netscapeTypeSpec) {
609		/* NetscapeCertType extension */
610		extp->extension.netscapeCertType = netscapeType;
611		extp->type = DT_NetscapeCertType;
612		extp->critical = CSSM_FALSE;
613		certReq.numExtensions++;
614		extp++;
615	}
616
617	crtn = CSSM_TP_SubmitCredRequest(tpHand,
618		NULL,				// PreferredAuthority
619		CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
620		&reqSet,
621		&CallerAuthContext,
622		&estTime,
623		&refId);
624	if(crtn) {
625		printError("CSSM_TP_SubmitCredRequest (2)", crtn);
626		errorCount++;
627		goto abort;
628	}
629	crtn = CSSM_TP_RetrieveCredResult(tpHand,
630		&refId,
631		NULL,				// CallerAuthCredentials
632		&estTime,
633		&confirmRequired,
634		&subjResultSet);
635	if(crtn) {
636		printError("CSSM_TP_RetrieveCredResult (2)", crtn);
637		errorCount++;
638		goto abort;
639	}
640	CSSM_FREE(refId.Data);
641	if(subjResultSet == NULL) {
642		printf("***CSSM_TP_RetrieveCredResult (2) returned NULL result set.\n");
643		errorCount++;
644		goto abort;
645	}
646	subjEncCert = (CSSM_ENCODED_CERT *)subjResultSet->Results;
647	signedSubjCert = subjEncCert->CertBlob;
648
649	if(writeBlobs) {
650		writeFile(SUBJ_CERT_FILE_NAME, signedSubjCert.Data, signedSubjCert.Length);
651		printf("...wrote %lu bytes to %s\n", signedSubjCert.Length,
652			SUBJ_CERT_FILE_NAME);
653	}
654
655	/*
656	 * Extract public keys from the two certs, verify.
657	 */
658	crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedSubjCert, &extractSubjKey);
659	if(crtn) {
660		printError("CSSM_CL_CertGetKeyInfo", crtn);
661	}
662	else {
663		/* compare key data - header is different.
664		 * Known header differences:
665		 *  -- CspID - CSSM_CL_CertGetKeyInfo returns a key with NULL for
666		 *     this field
667		 * --  Format. rootPubKey      : 6 (CSSM_KEYBLOB_RAW_FORMAT_BSAFE)
668		 *             extractRootKey  : 1 (CSSM_KEYBLOB_RAW_FORMAT_PKCS1)
669		 * --  KeyAttr. rootPubKey     : 0x20 (CSSM_KEYATTR_EXTRACTABLE)
670		 *              extractRootKey : 0x0
671		 */
672		if(!compareKeyData(extractSubjKey, &subjPubKey)) {
673			printf("***CSSM_CL_CertGetKeyInfo(signedSubjCert) returned bad key data\n");
674		}
675		if(extractSubjKey->KeyHeader.LogicalKeySizeInBits !=
676				subjPubKey.KeyHeader.LogicalKeySizeInBits) {
677			printf("***EffectiveKeySizeInBits mismatch: extract %u subj %u\n",
678				(unsigned)extractSubjKey->KeyHeader.LogicalKeySizeInBits,
679				(unsigned)subjPubKey.KeyHeader.LogicalKeySizeInBits);
680		}
681	}
682	crtn = CSSM_CL_CertGetKeyInfo(clHand, &signedRootCert, &extractRootKey);
683	if(crtn) {
684		printError("CSSM_CL_CertGetKeyInfo", crtn);
685	}
686	else {
687		if(!compareKeyData(extractRootKey, &rootPubKey)) {
688			printf("***CSSM_CL_CertGetKeyInfo(signedRootCert) returned bad key data\n");
689		}
690	}
691
692	/*
693	 * Verify:
694	 */
695	printf("Verifying certificates...\n");
696
697	/*
698	 *  Verify root cert by root pub key, should succeed.
699	 */
700	if(verifyCert(clHand,
701			cspHand,
702			&signedRootCert,
703			NULL,
704			&rootPubKey,
705			sigAlg,
706			CSSM_OK,
707			"Verify(root by root key)")) {
708		errorCount++;
709		/* continue */
710	}
711
712	/*
713	 *  Verify root cert by root cert, should succeed.
714	 */
715	if(verifyCert(clHand,
716			cspHand,
717			&signedRootCert,
718			&signedRootCert,
719			NULL,
720			CSSM_ALGID_NONE,			// sigAlg not used here
721			CSSM_OK,
722			"Verify(root by root cert)")) {
723		errorCount++;
724		/* continue */
725	}
726
727
728	/*
729	 *  Verify subject cert by root pub key, should succeed.
730	 */
731	if(verifyCert(clHand,
732			cspHand,
733			&signedSubjCert,
734			NULL,
735			&rootPubKey,
736			sigAlg,
737			CSSM_OK,
738			"Verify(subj by root key)")) {
739		errorCount++;
740		/* continue */
741	}
742
743	/*
744	 *  Verify subject cert by root cert, should succeed.
745	 */
746	if(verifyCert(clHand,
747			cspHand,
748			&signedSubjCert,
749			&signedRootCert,
750			NULL,
751			CSSM_ALGID_NONE,			// sigAlg not used here
752			CSSM_OK,
753			"Verify(subj by root cert)")) {
754		errorCount++;
755		/* continue */
756	}
757
758	/*
759	 *  Verify subject cert by root cert AND key, should succeed.
760	 */
761	if(verifyCert(clHand,
762			cspHand,
763			&signedSubjCert,
764			&signedRootCert,
765			&rootPubKey,
766			sigAlg,
767			CSSM_OK,
768			"Verify(subj by root cert and key)")) {
769		errorCount++;
770		/* continue */
771	}
772
773	/*
774	 *  Verify subject cert by extracted root pub key, should succeed.
775	 */
776	if(verifyCert(clHand,
777			cspHand,
778			&signedSubjCert,
779			NULL,
780			extractRootKey,
781			sigAlg,
782			CSSM_OK,
783			"Verify(subj by extracted root key)")) {
784		errorCount++;
785		/* continue */
786	}
787
788	/*
789	 *  Verify subject cert by subject pub key, should fail.
790	 */
791	if(verifyCert(clHand,
792			cspHand,
793			&signedSubjCert,
794			NULL,
795			&subjPubKey,
796			sigAlg,
797			CSSMERR_CL_VERIFICATION_FAILURE,
798			"Verify(subj by subj key)")) {
799		errorCount++;
800		/* continue */
801	}
802
803	/*
804	 *  Verify subject cert by subject cert, should fail.
805	 */
806	if(verifyCert(clHand,
807			cspHand,
808			&signedSubjCert,
809			&signedSubjCert,
810			NULL,
811			CSSM_ALGID_NONE,			// sigAlg not used here
812			CSSMERR_CL_VERIFICATION_FAILURE,
813			"Verify(subj by subj cert)")) {
814		errorCount++;
815		/* continue */
816	}
817
818	/*
819	 *  Verify erroneous subject cert by root pub key, should fail.
820	 */
821	badByte = genRand(1, signedSubjCert.Length - 1);
822	signedSubjCert.Data[badByte] ^= 0x55;
823	if(verifyCert(clHand,
824			cspHand,
825			&signedSubjCert,
826			NULL,
827			&rootPubKey,
828			sigAlg,
829			CSSMERR_CL_VERIFICATION_FAILURE,
830			"Verify(bad subj by root key)")) {
831		errorCount++;
832		/* continue */
833	}
834
835
836	/* free/delete certs and keys */
837	CSSM_FREE(signedSubjCert.Data);
838	CSSM_FREE(signedRootCert.Data);
839	CSSM_FREE(rootEncCert);
840	CSSM_FREE(subjEncCert);
841	CSSM_FREE(rootResultSet);
842	CSSM_FREE(subjResultSet);
843
844	/* These don't work because CSSM_CL_CertGetKeyInfo() gives keys with
845	 * a bogus GUID. This may be a problem with the Apple CSP...
846	 *
847	cspFreeKey(cspHand, extractRootKey);
848	cspFreeKey(cspHand, extractSubjKey);
849	 *
850	 * do it this way instead...*/
851	CSSM_FREE(extractRootKey->KeyData.Data);
852	CSSM_FREE(extractSubjKey->KeyData.Data);
853
854	/* need to do this regardless...*/
855	CSSM_FREE(extractRootKey);
856	CSSM_FREE(extractSubjKey);
857
858	if(loopPause) {
859		fpurge(stdin);
860		printf("pausing at end of loop; CR to continue:");
861		getchar();
862		goto loopTop;
863	}
864
865abort:
866	cspFreeKey(cspHand, &rootPubKey);
867	cspFreeKey(cspHand, &subjPubKey);
868
869	if(cspHand != 0) {
870		CSSM_ModuleDetach(cspHand);
871	}
872	if(clHand != 0) {
873		CSSM_ModuleDetach(clHand);
874	}
875	if(tpHand != 0) {
876		CSSM_ModuleDetach(tpHand);
877	}
878
879	if(errorCount) {
880		printf("Signer/Subject test failed with %d errors\n", errorCount);
881	}
882	else {
883		printf("Signer/Subject test succeeded\n");
884	}
885	return 0;
886}
887
888
889/* compare KeyData for two keys. */
890static CSSM_BOOL compareKeyData(const CSSM_KEY *key1, const CSSM_KEY *key2)
891{
892	if(key1->KeyData.Length != key2->KeyData.Length) {
893		return CSSM_FALSE;
894	}
895	if(memcmp(key1->KeyData.Data,
896			key2->KeyData.Data,
897			key1->KeyData.Length)) {
898		return CSSM_FALSE;
899	}
900	return CSSM_TRUE;
901}
902
903/* verify a cert using specified key and/or signerCert */
904static CSSM_RETURN verifyCert(CSSM_CL_HANDLE clHand,
905	CSSM_CSP_HANDLE	cspHand,
906	CSSM_DATA_PTR	cert,
907	CSSM_DATA_PTR	signerCert,		// optional
908	CSSM_KEY_PTR	key,			// ditto, to work spec one, other, or both
909	CSSM_ALGORITHMS	sigAlg,			// CSSM_ALGID_SHA1WithRSA, etc.
910	CSSM_RETURN		expectResult,
911	const char 		*opString)
912{
913	CSSM_RETURN		crtn;
914	CSSM_CC_HANDLE	signContext = CSSM_INVALID_HANDLE;
915
916	if(key) {
917		crtn = CSSM_CSP_CreateSignatureContext(cspHand,
918				sigAlg,
919				NULL,				// AccessCred
920				key,
921				&signContext);
922		if(crtn) {
923			printf("Failure during %s\n", opString);
924			printError("CSSM_CSP_CreateSignatureContext", crtn);
925			return crtn;
926		}
927	}
928	crtn = CSSM_CL_CertVerify(clHand,
929		signContext,
930		cert,					// CertToBeVerified
931		signerCert,				// SignerCert
932		NULL,					// VerifyScope
933		0);						// ScopeSize
934
935	/* Hack to accomodate ECDSA returning CSSMERR_CSP_INVALID_SIGNATURE - a more detailed */
936	if(crtn != expectResult) {
937		printf("Failure during %s\n", opString);
938		if(crtn == CSSM_OK) {
939			printf("Unexpected CSSM_CL_CertVerify success\n");
940		}
941		else if(expectResult == CSSM_OK) {
942			printError("CSSM_CL_CertVerify", crtn);
943		}
944		else {
945			printError("CSSM_CL_CertVerify: expected", expectResult);
946			printError("CSSM_CL_CertVerify: got     ", crtn);
947		}
948		return CSSMERR_CL_VERIFICATION_FAILURE;
949	}
950	if(signContext != CSSM_INVALID_HANDLE) {
951		crtn = CSSM_DeleteContext(signContext);
952		if(crtn) {
953			printf("Failure during %s\n", opString);
954			printError("CSSM_DeleteContext", crtn);
955			return crtn;
956		}
957	}
958	return CSSM_OK;
959}
960