1/* Copyright (c) 2006 Apple Computer, Inc.
2 *
3 * certSerialEncodeTest.cpp
4 *
5 * Verify proper encoding of unsigned integer as a DER_encoded signed integer.
6 * Verifies Radar 4471281.
7 *
8 */
9
10#include <utilLib/common.h>
11#include <utilLib/cspwrap.h>
12#include <security_cdsa_utils/cuFileIo.h>
13#include <clAppUtils/clutils.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17#include <Security/cssm.h>
18#include <Security/x509defs.h>
19#include <Security/oidsattr.h>
20#include <Security/oidscert.h>
21#include <Security/oidsalg.h>
22#include <Security/certextensions.h>
23#include <Security/cssmapple.h>
24#include <string.h>
25
26#define SUBJ_KEY_LABEL		"subjectKey"
27#define ROOT_KEY_LABEL		"rootKey"
28/* default key and signature algorithm */
29#define SIG_ALG_DEFAULT		CSSM_ALGID_SHA1WithRSA
30#define SIG_OID_DEFAULT		CSSMOID_SHA1WithRSA
31#define KEY_ALG_DEFAULT		CSSM_ALGID_RSA
32
33/* for write certs/keys option */
34#define ROOT_CERT_FILE_NAME		"ssRootCert.cer"
35#define SUBJ_CERT_FILE_NAME		"ssSubjCert.cer"
36
37/* public key in ref form, TP supports this as of 1/30/02 */
38#define PUB_KEY_IS_REF			CSSM_TRUE
39
40static void usage(char **argv)
41{
42	printf("Usage: %s [options]\n", argv[0]);
43	printf("Options:\n");
44	printf("    w[rite certs]\n");
45	printf("    p(ause for MallocDebug)\n");
46	printf("    q(uiet)\n");
47	exit(1);
48}
49
50/*
51 * RDN components
52 */
53static CSSM_APPLE_TP_NAME_OID rootRdn[] =
54{
55	{ "Apple Computer",					&CSSMOID_OrganizationName },
56	{ "The Big Cheesy Debug Root",		&CSSMOID_CommonName }
57};
58#define NUM_ROOT_NAMES	(sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID))
59
60/* test cases */
61typedef struct {
62	uint32		serialIn;		/* --> CSSM_TP_SubmitCredRequest */
63	CSSM_SIZE	expectLen;
64	const uint8	*expect;
65} SerialNumber;
66
67/* 0x7f */
68static const uint8 sn0_Data[1] = {0x7f};
69static const SerialNumber sn0 = {0x7f, 1, sn0_Data };
70
71/* 0x80 */
72static const uint8 sn1_Data[2] = {0x00, 0x80};
73static const SerialNumber sn1 = {0x80, 2, sn1_Data };
74
75/* 0x7ff */
76static const uint8 sn2_Data[2] = {0x07, 0xff};
77static const SerialNumber sn2 = {0x7ff, 2, sn2_Data };
78
79/* 0x80ff */
80static const uint8 sn3_Data[3] = {0x00, 0x80, 0xff};
81static const SerialNumber sn3 = {0x80ff, 3, sn3_Data };
82
83/* 0xfffffff */
84static const uint8 sn4_Data[4] = {0x0f, 0xff, 0xff, 0xff};
85static const SerialNumber sn4 = {0xfffffff, 4, sn4_Data };
86
87/* 0x0fffffff */
88static const uint8 sn5_Data[4] = {0x0f, 0xff, 0xff, 0xff};
89static const SerialNumber sn5 = {0x0fffffff, 4, sn5_Data };
90
91/* 0x80000000 */
92static const uint8 sn6_Data[5] = {0x00, 0x80, 0x00, 0x00, 0x00};
93static const SerialNumber sn6 = {0x80000000, 5, sn6_Data };
94
95static const SerialNumber *serialNumbers[] = {
96	&sn0, &sn1, &sn2, &sn3, &sn4, &sn5, &sn6
97};
98#define NUM_SERIAL_NUMS (sizeof(serialNumbers) / sizeof(serialNumbers[0]))
99
100static int doTest(
101	CSSM_CL_HANDLE	clHand,			// CL handle
102	CSSM_CSP_HANDLE	cspHand,		// CSP handle
103	CSSM_TP_HANDLE	tpHand,			// TP handle
104	CSSM_KEY_PTR	subjPubKey,
105	CSSM_KEY_PTR	signerPrivKey,
106	uint32			serialNumIn,
107	CSSM_SIZE		serialNumExpLen,
108	const uint8		*serialNumExp,
109	CSSM_BOOL		quiet,
110	CSSM_BOOL 		writeBlobs)
111{
112	CSSM_DATA					refId;			// mallocd by CSSM_TP_SubmitCredRequest
113	CSSM_APPLE_TP_CERT_REQUEST	certReq;
114	CSSM_TP_REQUEST_SET			reqSet;
115	sint32						estTime;
116	CSSM_BOOL					confirmRequired;
117	CSSM_TP_RESULT_SET_PTR		resultSet;
118	CSSM_ENCODED_CERT			*encCert;
119	CSSM_TP_CALLERAUTH_CONTEXT 	CallerAuthContext;
120	CSSM_FIELD					policyId;
121	CSSM_RETURN					crtn;
122	CSSM_DATA					*signedRootCert;
123	int							ourRtn = 0;
124	CSSM_DATA_PTR 				foundSerial = NULL;
125	CSSM_HANDLE 				resultHand = 0;
126	uint32 						numFields;
127
128	/* certReq for root */
129	memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST));
130	certReq.cspHand = cspHand;
131	certReq.clHand = clHand;
132	certReq.serialNumber = serialNumIn;
133	certReq.numSubjectNames = NUM_ROOT_NAMES;
134	certReq.subjectNames = rootRdn;
135	certReq.numIssuerNames = 0;
136	certReq.issuerNames = NULL;
137	certReq.certPublicKey = subjPubKey;
138	certReq.issuerPrivateKey = signerPrivKey;
139	certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA;
140	certReq.signatureOid = CSSMOID_SHA1WithRSA;
141	certReq.notBefore = 0;			// now
142	certReq.notAfter = 10000;		// seconds from now
143	certReq.numExtensions = 0;
144	certReq.extensions = NULL;
145
146	reqSet.NumberOfRequests = 1;
147	reqSet.Requests = &certReq;
148
149	/* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */
150	memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
151	memset(&policyId, 0, sizeof(CSSM_FIELD));
152	policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
153	CallerAuthContext.Policy.NumberOfPolicyIds = 1;
154	CallerAuthContext.Policy.PolicyIds = &policyId;
155
156	/* generate root cert */
157	if(!quiet) {
158		printf("Creating root cert...\n");
159	}
160	crtn = CSSM_TP_SubmitCredRequest(tpHand,
161		NULL,				// PreferredAuthority
162		CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
163		&reqSet,
164		&CallerAuthContext,
165		&estTime,
166		&refId);
167	if(crtn) {
168		printError("CSSM_TP_SubmitCredRequest", crtn);
169		ourRtn = -1;
170		goto errOut;
171	}
172	crtn = CSSM_TP_RetrieveCredResult(tpHand,
173		&refId,
174		NULL,				// CallerAuthCredentials
175		&estTime,
176		&confirmRequired,
177		&resultSet);
178	if(crtn) {
179		printError("CSSM_TP_RetrieveCredResult", crtn);
180		ourRtn = -1;
181		goto errOut;
182	}
183	if(resultSet == NULL) {
184		printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
185		ourRtn = -1;
186		goto errOut;
187	}
188	encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
189	signedRootCert = &encCert->CertBlob;
190	if(writeBlobs) {
191		writeFile(ROOT_CERT_FILE_NAME, signedRootCert->Data, signedRootCert->Length);
192		printf("...wrote %lu bytes to %s\n", signedRootCert->Length,
193			ROOT_CERT_FILE_NAME);
194	}
195
196	/* make sure it self-verifies */
197	crtn = CSSM_CL_CertVerify(clHand, 0 /* CCHandle */,
198		signedRootCert, signedRootCert,
199		NULL, 0);
200	if(crtn) {
201		cssmPerror("CSSM_CL_CertVerify", crtn);
202		printf("***Created cert does not self-verify\n");
203		ourRtn = -1;
204		goto errOut;
205	}
206
207	/* extract the field we're interested in verifying */
208	crtn = CSSM_CL_CertGetFirstFieldValue(clHand, signedRootCert,
209		&CSSMOID_X509V1SerialNumber, &resultHand, &numFields, &foundSerial);
210	if(crtn) {
211		cssmPerror("CSSM_CL_CertGetFirstFieldValue(serialNumber)", crtn);
212		printf("***Can't obtain serial number\n");
213		ourRtn = -1;
214		goto errOut;
215	}
216	CSSM_CL_CertAbortQuery(clHand, resultHand);
217	if(foundSerial->Length != serialNumExpLen) {
218		printf("***expected serialNumber len 0x%lu, got 0x%lu\n",
219			(unsigned long)serialNumExpLen, (unsigned long)foundSerial->Length);
220		ourRtn = -1;
221		goto errOut;
222	}
223	for(unsigned dex=0; dex<serialNumExpLen; dex++) {
224		if(foundSerial->Data[dex] != serialNumExp[dex]) {
225			printf("***SerialNumber mismatch at index %u: exp %02X got %02X\n",
226				dex, (unsigned)serialNumExp[dex],
227				(unsigned)foundSerial->Data[dex]);
228			ourRtn = -1;
229		}
230	}
231	/* free retrieved serial number and the result set itself */
232	CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SerialNumber, foundSerial);
233	CSSM_FREE(signedRootCert->Data);
234	CSSM_FREE(encCert);
235	CSSM_FREE(resultSet);
236	/* Per the spec, this is supposed to be Opaque to us and the TP is supposed to free
237	 * it when it goes out of scope...but libsecurity_keychains's
238	 * CertificateRequest::submitDotMac() frees this...that would have to change
239	 * in order for the TP to free this properly. Someday maybe. No big deal.
240	 */
241	CSSM_FREE(refId.Data);
242errOut:
243	return ourRtn;
244}
245
246int main(int argc, char **argv)
247{
248	CSSM_CL_HANDLE	clHand;			// CL handle
249	CSSM_CSP_HANDLE	cspHand;		// CSP handle
250	CSSM_TP_HANDLE	tpHand;			// TP handle
251	CSSM_KEY		rootPubKey;		// root's RSA public key blob
252	CSSM_KEY		rootPrivKey;	// root's RSA private key - ref format
253	CSSM_RETURN		crtn;
254	int				arg;
255	unsigned 		dex;
256	int 			ourRtn = 0;
257	uint32			keySizeInBits = 512;
258	CSSM_BOOL		doPause = CSSM_FALSE;
259
260	/* user-spec'd variables */
261	CSSM_BOOL		writeBlobs = CSSM_FALSE;
262	CSSM_BOOL		quiet = CSSM_FALSE;
263
264	for(arg=1; arg<argc; arg++) {
265		switch(argv[arg][0]) {
266			case 'w':
267				writeBlobs = CSSM_TRUE;
268				break;
269			case 'q':
270				quiet = CSSM_TRUE;
271				break;
272			case 'p':
273				doPause = CSSM_TRUE;
274				break;
275			default:
276				usage(argv);
277		}
278	}
279
280	testStartBanner("certSerialEncodeTest", argc, argv);
281
282
283	/* connect to CL, TP, and CSP */
284	clHand = clStartup();
285	if(clHand == 0) {
286		return -1;
287	}
288	tpHand = tpStartup();
289	if(tpHand == 0) {
290		return -1;
291	}
292	cspHand = cspStartup();
293	if(cspHand == 0) {
294		return -1;
295	}
296
297	/* cook up key pair for self-signed cert */
298	crtn = cspGenKeyPair(cspHand,
299		CSSM_ALGID_RSA,
300		ROOT_KEY_LABEL,
301		strlen(ROOT_KEY_LABEL),
302		keySizeInBits,
303		&rootPubKey,
304		CSSM_FALSE,			// pubIsRef - should work both ways, but not yet
305		CSSM_KEYUSE_VERIFY,
306		CSSM_KEYBLOB_RAW_FORMAT_NONE,
307		&rootPrivKey,
308		writeBlobs ? CSSM_FALSE : CSSM_TRUE,	// privIsRef
309		CSSM_KEYUSE_SIGN,
310		CSSM_KEYBLOB_RAW_FORMAT_NONE,
311		CSSM_FALSE);
312	if(crtn) {
313		ourRtn = -1;
314		goto abort;
315	}
316
317	for(dex=0; dex<NUM_SERIAL_NUMS; dex++) {
318		const SerialNumber *sn = serialNumbers[dex];
319		if(!quiet) {
320			printf("...testing serial number 0x%lx\n", (unsigned long)sn->serialIn);
321		}
322		ourRtn = doTest(clHand, cspHand, tpHand,
323			&rootPubKey, &rootPrivKey,
324			sn->serialIn, sn->expectLen, sn->expect,
325			quiet, writeBlobs);
326		if(ourRtn) {
327			break;
328		}
329		if(doPause) {
330			fpurge(stdin);
331			printf("Pausing for MallocDebug. a to abort, anything else to continue: ");
332			if(getchar() == 'a') {
333				break;
334			}
335		}
336	}
337
338	cspFreeKey(cspHand, &rootPubKey);
339	cspFreeKey(cspHand, &rootPrivKey);
340
341abort:
342	if(cspHand != 0) {
343		CSSM_ModuleDetach(cspHand);
344	}
345	if(clHand != 0) {
346		CSSM_ModuleDetach(clHand);
347	}
348	if(tpHand != 0) {
349		CSSM_ModuleDetach(tpHand);
350	}
351
352	if((ourRtn == 0) && !quiet) {
353		printf("certSerialEncodeTest test succeeded\n");
354	}
355	return ourRtn;
356}
357
358
359