1/*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
17 */
18
19/*
20	File:		 CertTool.cpp
21
22	Description: certificate manipulation tool
23
24	Author:		 dmitch
25*/
26
27#include <Security/Security.h>
28#include <Security/certextensions.h>
29#include <Security/cssmapple.h>
30#include <Security/oidsattr.h>
31#include <Security/oidscert.h>
32#include <Security/oidsalg.h>
33#include <Security/SecIdentityPriv.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <strings.h>
37#include <ctype.h>
38#include <sys/param.h>
39#include <unistd.h>
40#include <security_cdsa_utils/cuCdsaUtils.h>
41#include <security_cdsa_utils/cuDbUtils.h>
42#include <security_cdsa_utils/cuPrintCert.h>
43#include <security_cdsa_utils/cuFileIo.h>
44#include <security_cdsa_utils/cuPem.h>
45#include <security_utilities/alloc.h>
46#include <security_cdsa_client/aclclient.h>
47#include <security_utilities/devrandom.h>
48#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
49#include "CertUI.h"
50#include <CoreFoundation/CoreFoundation.h>
51
52#define KC_DB_PATH			"Library/Keychains"		/* relative to home */
53#define SYSTEM_KDC			"com.apple.kerberos.kdc"
54
55/*
56 * defaults for undocumented 'Z' option
57 */
58#define ZDEF_KEY_LABEL		"testCert"
59#define ZDEF_KEY_ALG		CSSM_ALGID_RSA
60#define ZDEF_KEY_SIZE		512
61#define ZDEF_KEY_USAGE		(kKeyUseSigning | kKeyUseEncrypting)
62#define ZDEF_SIG_ALG		CSSM_ALGID_SHA256WithRSA
63#define ZDEF_SIG_OID		CSSMOID_SHA256WithRSA
64#define ZDEF_COMMON_NAME	"localhost"
65#define ZDEF_ORG_NAME		"Apple Computer - DEBUG ONLY"
66#define ZDEF_COUNTRY		"US"
67#define ZDEF_STATE			"Washington"
68#define ZDEF_CHALLENGE		"someChallenge"
69
70/*
71 * Key and cert parameters for creating system identity
72 */
73#define SI_DEF_KEY_LABEL	"System Identity"
74#define SI_DEF_KEY_ALG		CSSM_ALGID_RSA
75#define SI_DEF_KEY_SIZE		(1024 * 2)
76#define SI_DEF_KEY_USAGE	(kKeyUseSigning | kKeyUseEncrypting)
77#define SI_DEF_SIG_ALG		CSSM_ALGID_SHA256WithRSA
78#define SI_DEF_SIG_OID		CSSMOID_SHA256WithRSA
79/* common name = domain */
80#define SI_DEF_ORG_NAME		"System Identity"
81/* org unit = hostname */
82#define SI_DEF_VALIDITY		(60 * 60 * 24 * 365 * 20)	/* 20 years */
83
84/*
85 * Default validity
86 */
87#define DEFAULT_CERT_VALIDITY	(60 * 60 * 24 * 30)		/* 30 days */
88
89/*
90 * Validity period environment variable
91 * <rdar://problem/16760570> Update certtool to support validate period via an environment variable
92 */
93#define VALIDITY_DAYS_ENVIRONMENT_VARIABLE	"CERTTOOL_EXPIRATION_DAYS"
94
95	CSSM_BOOL			verbose = CSSM_FALSE;
96
97static void usage(char **argv)
98{
99	printf("usage:\n");
100	printf("   Create a keypair and cert: %s c [options]\n", argv[0]);
101	printf("   Create a CSR:              %s r outFileName [options]\n",
102			argv[0]);
103	printf("   Verify a CSR:              %s v infileName [options]\n", argv[0]);
104	printf("   Create a system Identity:  %s C domainName [options]\n", argv[0]);
105	printf("   Import a certificate:      %s i inFileName [options]\n", argv[0]);
106	printf("   Display a certificate:     %s d inFileName [options]\n", argv[0]);
107	printf("   Import a CRL:              %s I inFileName [options]\n", argv[0]);
108	printf("   Display a CRL:             %s D inFileName [options]\n", argv[0]);
109	printf("   Display certs and CRLs in keychain: %s y [options]\n", argv[0]);
110	printf("Options:\n");
111	printf("   k=keychainName\n");
112	printf("   c (create the keychain)\n");
113	printf("   p=passphrase (specify passphrase at keychain creation)\n");
114	printf("   o=outFileName (create cert command only)\n");
115	printf("   v (verbose)\n");
116	printf("   d (infile/outfile in DER format; default is PEM)\n");
117	printf("   r=privateKeyFileName (optional; for Import Certificate only)\n");
118	printf("   f=[18fo] (private key format = PKCS1/PKCS8/FIPS186; default is PKCS1\n"
119		   "     (openssl) for RSA, openssl for DSA, PKCS8 for Diffie-Hellman,\n"
120		   "     OpenSSL for ECDSA\n");
121	printf("   x=[asSm] (Extended Key Usage: a=Any; s=SSL Client; S=SSL Server; m=SMIME)\n");
122	printf("   a (create key with default ACL)\n");
123	printf("   u (create key with ACL limiting access to current UID)\n");
124	printf("   P (Don't create system identity if one already exists for specified domain)\n");
125	printf("   h(elp)\n");
126	exit(1);
127}
128
129static void printError(const char *errDescription,const char *errLocation,OSStatus crtn)
130{
131	// Show error in text form. If verbose, show location and decimal and hex error values
132	int len=64+(errLocation?strlen(errLocation):0);
133	if (verbose)
134	{
135		char *buf=(char *)malloc(len);
136		if (errDescription)
137			fprintf(stderr,"%s : ",errDescription);
138	//	sprintf(buf," %s : %d [0x%x] : ", errLocation,(int)crtn,(unsigned int)crtn);
139	//	cuPrintError(buf, crtn);
140		cuPrintError(errLocation, crtn);
141		free(buf);
142	}
143	else
144	{
145		if (errDescription)
146			fprintf(stderr,"%s\n",errDescription);
147		else
148		if (errLocation)
149			fprintf(stderr,"%s\n",errLocation);
150		else
151			fprintf(stderr,"Error: %d [0x%x]\n",(int)crtn,(unsigned int)crtn);
152	}
153}
154
155void check_obsolete_keychain(const char *kcName)
156{
157	if(!strcmp(kcName, "/System/Library/Keychains/X509Anchors")) {
158		fprintf(stderr, "***************************************************************\n");
159		fprintf(stderr, "                         WARNING\n");
160		fprintf(stderr, "\n");
161		fprintf(stderr, "The keychain you are accessing, X509Anchors, is no longer\n");
162		fprintf(stderr, "used by Mac OS X as the system root certificate store.\n");
163		fprintf(stderr, "Please read the security man page for information on the \n");
164		fprintf(stderr, "add-trusted-cert command. New system root certificates should\n");
165		fprintf(stderr, "be added to the Admin Trust Settings domain and to the \n");
166		fprintf(stderr, "System keychain in /Library/Keychains.\n");
167		fprintf(stderr, "***************************************************************\n");
168	}
169	else if(!strcmp(kcName, "/System/Library/Keychains/X509Certificates")) {
170		fprintf(stderr, "***************************************************************\n");
171		fprintf(stderr, "                         WARNING\n");
172		fprintf(stderr, "\n");
173		fprintf(stderr, "The keychain you are accessing, X509Certificates, is no longer\n");
174		fprintf(stderr, "used by Mac OS X as the system intermediate certificate\n");
175		fprintf(stderr, "store. New system intermediate certificates should be added\n");
176		fprintf(stderr, "to the System keychain in /Library/Keychains.\n");
177		fprintf(stderr, "***************************************************************\n");
178	}
179}
180
181//
182// Create a SecAccessRef with a custom form.
183// Both the owner and the ACL set allow free access to the specified,
184// UID, but nothing to anyone else.
185//
186static OSStatus makeUidAccess(uid_t uid, SecAccessRef *rtnAccess)
187{
188	// make the "uid/gid" ACL subject
189	// this is a CSSM_LIST_ELEMENT chain
190	CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector = {
191		CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION,	// selector version
192		CSSM_ACL_MATCH_UID,	// set mask: match uids (only)
193		uid,				// uid to match
194		0					// gid (not matched here)
195	};
196	CSSM_LIST_ELEMENT subject2 = { NULL, 0 };
197	subject2.Element.Word.Data = (UInt8 *)&selector;
198	subject2.Element.Word.Length = sizeof(selector);
199	CSSM_LIST_ELEMENT subject1 = {
200		&subject2, CSSM_ACL_SUBJECT_TYPE_PROCESS, CSSM_LIST_ELEMENT_WORDID
201	};
202
203
204	// rights granted (replace with individual list if desired)
205	CSSM_ACL_AUTHORIZATION_TAG rights[] = {
206		CSSM_ACL_AUTHORIZATION_ANY	// everything
207	};
208	// owner component (right to change ACL)
209	CSSM_ACL_OWNER_PROTOTYPE owner = {
210		// TypedSubject
211		{ CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
212		// Delegate
213		false
214	};
215	// ACL entries (any number, just one here)
216	CSSM_ACL_ENTRY_INFO acls[] = {
217		{
218			// prototype
219			{
220				// TypedSubject
221				{ CSSM_LIST_TYPE_UNKNOWN, &subject1, &subject2 },
222				false,	// Delegate
223				// rights for this entry
224				{ sizeof(rights) / sizeof(rights[0]), rights },
225				// rest is defaulted
226			}
227		}
228	};
229
230	return SecAccessCreateFromOwnerAndACL(&owner,
231		sizeof(acls) / sizeof(acls[0]), acls, rtnAccess);
232}
233
234static OSStatus setKeyPrintName(
235	SecKeyRef keyRef,
236	const char *keyName)
237{
238	UInt32 tag = kSecKeyPrintName;
239	SecKeychainAttributeInfo attrInfo;
240	attrInfo.count = 1;
241	attrInfo.tag = &tag;
242	attrInfo.format = NULL;
243	SecKeychainAttributeList *copiedAttrs = NULL;
244
245	OSStatus ortn = SecKeychainItemCopyAttributesAndData(
246		(SecKeychainItemRef)keyRef,
247		&attrInfo,
248		NULL,			// itemClass
249		&copiedAttrs,
250		NULL,			// length - don't need the data
251		NULL);			// outData
252	if(ortn) {
253		printError("***Error creating key pair",
254			"SecKeychainItemCopyAttributesAndData", ortn);
255		return ortn;
256	}
257
258	SecKeychainAttributeList newAttrList;
259	newAttrList.count = 1;
260	SecKeychainAttribute newAttr;
261	newAttrList.attr = &newAttr;
262	newAttr.tag = copiedAttrs->attr->tag;
263	newAttr.length = strlen(keyName);
264	newAttr.data = (void*)keyName;
265	ortn = SecKeychainItemModifyAttributesAndData((SecKeychainItemRef)keyRef,
266		&newAttrList, 0, NULL);
267	if(ortn) {
268		printError("***Error creating key pair",
269			"SecKeychainItemModifyAttributesAndData", ortn);
270	}
271	SecKeychainItemFreeAttributesAndData(copiedAttrs, NULL);
272	return ortn;
273}
274
275/*
276 * Generate a key pair using SecKeyCreatePair.
277 */
278static OSStatus generateSecKeyPair(
279	SecKeychainRef		kcRef,
280	CSSM_ALGORITHMS 	keyAlg,				// e.g., CSSM_ALGID_RSA
281	uint32				keySizeInBits,
282	CU_KeyUsage			keyUsage,			// CUK_Signing, etc.
283	CSSM_BOOL 			aclForUid,			// ACL for current UID
284	CSSM_BOOL 			verbose,
285	const char			*keyLabel,			// optional
286	CSSM_KEY_PTR 		*pubKeyPtr,			// RETURNED, owned by Sec layer
287	CSSM_KEY_PTR 		*privKeyPtr,		// RETURNED, owned by Sec layer
288	SecKeyRef			*pubSecKey,			// caller must release
289	SecKeyRef			*privSecKey)		// caller must release
290{
291	OSStatus ortn;
292	CSSM_KEYUSE pubKeyUse = 0;
293	CSSM_KEYUSE privKeyUse = 0;
294	SecAccessRef secAccess = NULL;
295
296	if(aclForUid) {
297		ortn = makeUidAccess(geteuid(), &secAccess);
298		if(ortn) {
299			printError("***Error creating key pair",
300				"SecAccessCreateFromOwnerAndACL", ortn);
301			return ortn;
302		}
303	}
304	if(keyUsage & kKeyUseSigning) {
305		pubKeyUse  |= CSSM_KEYUSE_VERIFY;
306		privKeyUse |= CSSM_KEYUSE_SIGN;
307	}
308	if(keyUsage & kKeyUseEncrypting) {
309		pubKeyUse  |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP);
310		privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP);
311	}
312	if(keyUsage & kKeyUseDerive) {
313		pubKeyUse  |= CSSM_KEYUSE_DERIVE;
314		privKeyUse |= CSSM_KEYUSE_DERIVE;
315	}
316	ortn = SecKeyCreatePair(kcRef,
317		keyAlg, keySizeInBits,
318		0,					// contextHandle
319		pubKeyUse,
320		CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE |
321			CSSM_KEYATTR_RETURN_REF,
322		privKeyUse,
323		CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF |
324			CSSM_KEYATTR_PERMANENT |CSSM_KEYATTR_EXTRACTABLE,
325		secAccess,
326		pubSecKey,
327		privSecKey);
328	if(secAccess) {
329		CFRelease(secAccess);
330	}
331	if(ortn) {
332		printError("***Error creating key pair",
333			"SecKeyCreatePair", ortn);
334		cuPrintError("", ortn);
335		return ortn;
336	}
337	if(keyLabel != NULL) {
338		ortn = setKeyPrintName(*pubSecKey, keyLabel);
339		if(ortn) {
340			return ortn;
341		}
342		ortn = setKeyPrintName(*privSecKey, keyLabel);
343		if(ortn) {
344			return ortn;
345		}
346	}
347
348	/* extract CSSM keys for caller */
349	ortn = SecKeyGetCSSMKey(*pubSecKey, const_cast<const CSSM_KEY **>(pubKeyPtr));
350	if(ortn) {
351		printError("***Error extracting public key",
352			"SecKeyGetCSSMKey", ortn);
353		cuPrintError("", ortn);
354	}
355	else ortn = SecKeyGetCSSMKey(*privSecKey, const_cast<const CSSM_KEY **>(privKeyPtr));
356	if(ortn) {
357		printError("***Error extracting private key",
358			"SecKeyGetCSSMKey", ortn);
359		cuPrintError("", ortn);
360	}
361	if(ortn) {
362		CFRelease(*pubSecKey);
363		*pubSecKey = NULL;
364		CFRelease(*privSecKey);
365		*privSecKey = NULL;
366	}
367	return ortn;
368}
369
370/*
371 * Find private key by label, modify its Label attr to be the
372 * hash of the associated public key.
373 */
374static CSSM_RETURN setPubKeyHash(
375	CSSM_CSP_HANDLE 	cspHand,
376	CSSM_DL_DB_HANDLE 	dlDbHand,
377	const char			*keyLabel)		// look up by this
378{
379	CSSM_QUERY						query;
380	CSSM_SELECTION_PREDICATE		predicate;
381	CSSM_DB_UNIQUE_RECORD_PTR		record = NULL;
382	CSSM_RETURN						crtn;
383	CSSM_DATA						labelData;
384	CSSM_HANDLE						resultHand;
385
386	labelData.Data = (uint8 *)keyLabel;
387	labelData.Length = strlen(keyLabel) + 1;	// incl. NULL
388	query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
389	query.Conjunctive = CSSM_DB_NONE;
390	query.NumSelectionPredicates = 1;
391	predicate.DbOperator = CSSM_DB_EQUAL;
392
393	predicate.Attribute.Info.AttributeNameFormat =
394		CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
395	predicate.Attribute.Info.Label.AttributeName = (char*) "Label";
396	predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
397	/* hope this cast is OK */
398	predicate.Attribute.Value = &labelData;
399	query.SelectionPredicate = &predicate;
400
401	query.QueryLimits.TimeLimit = 0;	// FIXME - meaningful?
402	query.QueryLimits.SizeLimit = 1;	// FIXME - meaningful?
403	query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA;	// FIXME - used?
404
405	/* build Record attribute with one attr */
406	CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
407	CSSM_DB_ATTRIBUTE_DATA attr;
408	attr.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
409	attr.Info.Label.AttributeName = (char*) "Label";
410	attr.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
411
412	recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
413	recordAttrs.NumberOfAttributes = 1;
414	recordAttrs.AttributeData = &attr;
415
416	CSSM_DATA recordData = {0, NULL};
417	crtn = CSSM_DL_DataGetFirst(dlDbHand,
418		&query,
419		&resultHand,
420		&recordAttrs,
421		&recordData,
422		&record);
423	/* abort only on success */
424	if(crtn != CSSM_OK) {
425		printError("***setPubKeyHash: can't find private key","CSSM_DL_DataGetFirst",crtn);
426		return crtn;
427	}
428
429	CSSM_KEY_PTR keyToDigest = (CSSM_KEY_PTR)recordData.Data;
430	CSSM_DATA_PTR keyDigest = NULL;
431	CSSM_CC_HANDLE ccHand;
432	crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
433	 	keyToDigest,
434		&ccHand);
435	if(crtn) {
436		printError("***Error calculating public key hash. Aborting.",
437			"CSSM_CSP_CreatePassThroughContext", crtn);
438		return crtn;
439	}
440	crtn = CSSM_CSP_PassThrough(ccHand,
441		CSSM_APPLECSP_KEYDIGEST,
442		NULL,
443		(void **)&keyDigest);
444	if(crtn) {
445		printError("***Error calculating public key hash. Aborting.",
446			"CSSM_CSP_PassThrough(PUBKEYHASH)", crtn);
447		return -1;
448	}
449	CSSM_FreeKey(cspHand, NULL, keyToDigest, CSSM_FALSE);
450	CSSM_DeleteContext(ccHand);
451
452	/*
453	 * Replace Label attr data with hash.
454	 * NOTE: the module which allocated this attribute data - a DL -
455	 * was loaded and attached by the Sec layer, not by us. Thus
456	 * we can't use the memory allocator functions *we* used when
457	 * attaching to the CSPDL - we have to use the ones
458	 * which the Sec layer registered with the DL.
459	 */
460	CSSM_API_MEMORY_FUNCS memFuncs;
461	crtn = CSSM_GetAPIMemoryFunctions(dlDbHand.DLHandle, &memFuncs);
462	if(crtn) {
463		printError("***Error ","CSSM_GetAPIMemoryFunctions(DLHandle)",crtn);
464		/* oh well, leak and continue */
465	}
466	else {
467		memFuncs.free_func(attr.Value->Data, memFuncs.AllocRef);
468		memFuncs.free_func(attr.Value, memFuncs.AllocRef);
469	}
470	attr.Value = keyDigest;
471
472	/* modify key attributes */
473	crtn = CSSM_DL_DataModify(dlDbHand,
474			CSSM_DL_DB_RECORD_PRIVATE_KEY,
475			record,
476			&recordAttrs,
477            NULL,				// DataToBeModified
478			CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
479	if(crtn) {
480		printError("***Error setting public key hash. Aborting.",
481			"CSSM_DL_DataModify(PUBKEYHASH)", crtn);
482		return crtn;
483	}
484	crtn = CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
485	if(crtn) {
486		printError("***Error while stopping query",
487			"CSSM_DL_DataAbortQuery", crtn);
488		/* let's keep going in this case */
489	}
490	crtn = CSSM_DL_FreeUniqueRecord(dlDbHand, record);
491	if(crtn) {
492		printError("***Error while freeing record",
493			"CSSM_DL_FreeUniqueRecord", crtn);
494		/* let's keep going in this case */
495		crtn = CSSM_OK;
496	}
497
498	/* free resources */
499	cuAppFree(keyDigest->Data, NULL);
500	return CSSM_OK;
501}
502
503/*
504 * Generate a key pair using the CSPDL.
505 */
506static OSStatus generateKeyPair(
507	CSSM_CSP_HANDLE 	cspHand,
508	CSSM_DL_DB_HANDLE 	dlDbHand,
509	CSSM_ALGORITHMS 	keyAlg,				// e.g., CSSM_ALGID_RSA
510	uint32				keySizeInBits,
511	const char 			*keyLabel,			// C string
512	CU_KeyUsage			keyUsage,			// CUK_Signing, etc.
513	CSSM_BOOL 			verbose,
514	CSSM_KEY_PTR 		*pubKeyPtr,			// mallocd, created, RETURNED
515	CSSM_KEY_PTR 		*privKeyPtr)		// mallocd, created, RETURNED
516{
517	CSSM_KEY_PTR pubKey = reinterpret_cast<CSSM_KEY_PTR>(
518		APP_MALLOC(sizeof(CSSM_KEY)));
519	CSSM_KEY_PTR privKey = reinterpret_cast<CSSM_KEY_PTR>(
520		APP_MALLOC(sizeof(CSSM_KEY)));
521	if((pubKey == NULL) || (privKey == NULL)) {
522		return memFullErr;
523	}
524
525	CSSM_RETURN crtn;
526	CSSM_KEYUSE pubKeyUse = 0;
527	CSSM_KEYUSE privKeyUse = 0;
528
529	if(keyUsage & kKeyUseSigning) {
530		pubKeyUse  |= CSSM_KEYUSE_VERIFY;
531		privKeyUse |= CSSM_KEYUSE_SIGN;
532	}
533	if(keyUsage & kKeyUseEncrypting) {
534		pubKeyUse  |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP);
535		privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP);
536	}
537	if(keyUsage & kKeyUseDerive) {
538		pubKeyUse  |= CSSM_KEYUSE_DERIVE;
539		privKeyUse |= CSSM_KEYUSE_DERIVE;
540	}
541
542	crtn = cuCspGenKeyPair(cspHand,
543		&dlDbHand,
544		keyAlg,
545		keyLabel,
546		strlen(keyLabel) + 1,
547		keySizeInBits,
548		pubKey,
549		pubKeyUse,
550		CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF,
551		privKey,
552		privKeyUse,
553		CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT |
554			CSSM_KEYATTR_EXTRACTABLE);
555	if(crtn) {
556		APP_FREE(pubKey);
557		APP_FREE(privKey);
558		return paramErr;
559	}
560	if(verbose) {
561		printf("...%u bit key pair generated.\n",
562			(unsigned)keySizeInBits);
563	}
564
565	/* bind private key to cert by public key hash */
566	crtn = setPubKeyHash(cspHand,
567		dlDbHand,
568		keyLabel);
569	if(crtn) {
570		printError("***Error setting public key hash. Continuing at peril.",
571			"setPubKeyHash", crtn);
572	}
573
574	*pubKeyPtr = pubKey;
575	*privKeyPtr = privKey;
576	return noErr;
577}
578
579static OSStatus verifyCsr(
580	CSSM_CL_HANDLE	clHand,
581	const char		*fileName,
582	CSSM_BOOL		pemFormat)
583{
584	unsigned char *csr = NULL;
585	unsigned csrLen;
586	CSSM_DATA csrData;
587	unsigned char *der = NULL;
588	unsigned derLen = 0;
589
590	if(readFile(fileName, &csr, &csrLen)) {
591		printf("***Error reading CSR from file %s. Aborting.\n",
592			fileName);
593		return ioErr;
594	}
595	if(pemFormat) {
596		int rtn = pemDecode(csr, csrLen, &der, &derLen);
597		if(rtn) {
598			printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
599			return ioErr;
600		}
601		csrData.Data = der;
602		csrData.Length = derLen;
603	}
604	else {
605		csrData.Data = csr;
606		csrData.Length = csrLen;
607	}
608
609	CSSM_RETURN crtn = CSSM_CL_PassThrough(clHand,
610		0,			// CCHandle
611		CSSM_APPLEX509CL_VERIFY_CSR,
612		&csrData,
613		NULL);
614	if(crtn) {
615		printError("***Error verifying CSR","Verify CSR",crtn);
616	}
617	else {
618		printf("...CSR verified successfully.\n");
619	}
620	if(der) {
621		free(der);
622	}
623	if(csr) {
624		free(csr);
625	}
626	return crtn;
627}
628
629typedef enum {
630	CC_Cert,
631	CC_CRL
632} CertOrCrl;
633
634static OSStatus displayCertCRL(
635	const char		*fileName,
636	CSSM_BOOL		pemFormat,
637	CertOrCrl		certOrCrl,
638	CSSM_BOOL		verbose)
639{
640	unsigned char *rawData = NULL;
641	unsigned rawDataSize;
642	unsigned char *derData = NULL;
643	unsigned derDataSize;
644	int rtn;
645
646	rtn = readFile(fileName, &rawData, &rawDataSize);
647	if(rtn) {
648		printf("Error reading %s; aborting.\n", fileName);
649		return ioErr;
650	}
651	if(pemFormat && isPem(rawData, rawDataSize)) {
652		/*
653		 * Here we cut the user some slack. See if the thing is actually
654		 * PEM encoded and assume DER-encoded if it's not.
655		 */
656		rtn = pemDecode(rawData, rawDataSize, &derData, &derDataSize);
657		if(rtn) {
658			printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
659			return ioErr;
660		}
661		rawData = derData;
662		rawDataSize = derDataSize;
663	}
664	if(certOrCrl == CC_Cert) {
665		printCert(rawData, rawDataSize, verbose);
666	}
667	else {
668		printCrl(rawData, rawDataSize, verbose);
669	}
670	if(derData != NULL) {
671		free(derData);
672	}
673	return noErr;
674}
675
676static CSSM_RETURN importPrivateKey(
677	CSSM_DL_DB_HANDLE	dlDbHand,
678	CSSM_CSP_HANDLE		cspHand,
679	const char			*privKeyFileName,
680	CSSM_ALGORITHMS		keyAlg,
681	CSSM_BOOL			pemFormat,			// of the file
682	CSSM_KEYBLOB_FORMAT	keyFormat)			// of the key blob itself, NONE means use
683											//   default
684{
685	unsigned char 			*derKey = NULL;
686	unsigned 				derKeyLen;
687	unsigned char 			*pemKey = NULL;
688	unsigned 				pemKeyLen;
689	CSSM_KEY 				wrappedKey;
690	CSSM_KEY 				unwrappedKey;
691	CSSM_ACCESS_CREDENTIALS	creds;
692	CSSM_CC_HANDLE			ccHand = 0;
693	CSSM_RETURN				crtn;
694	CSSM_DATA				labelData;
695	CSSM_KEYHEADER_PTR		hdr = &wrappedKey.KeyHeader;
696	CSSM_DATA 				descData = {0, NULL};
697	CSSM_CSP_HANDLE			rawCspHand = 0;
698	const char				*privKeyLabel = NULL;
699
700	/*
701	 * Validate specified format for clarity
702	 */
703	switch(keyAlg) {
704		case CSSM_ALGID_RSA:
705			switch(keyFormat) {
706				case CSSM_KEYBLOB_RAW_FORMAT_NONE:
707					keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;	// default
708					break;
709				case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
710				case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
711					break;
712				default:
713					printf("***RSA Private key must be in PKCS1 or PKCS8 format\n");
714					return CSSMERR_CSSM_INTERNAL_ERROR;
715			}
716			privKeyLabel = "Imported RSA key";
717			break;
718		case CSSM_ALGID_DSA:
719			switch(keyFormat) {
720				case CSSM_KEYBLOB_RAW_FORMAT_NONE:
721					keyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;	// default
722					break;
723				case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
724				case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
725				case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
726					break;
727				default:
728					printf("***DSA Private key must be in openssl, FIPS186, "
729						"or PKCS8 format\n");
730					return CSSMERR_CSSM_INTERNAL_ERROR;
731			}
732			privKeyLabel = "Imported DSA key";
733			break;
734		case CSSM_ALGID_DH:
735			switch(keyFormat) {
736				case CSSM_KEYBLOB_RAW_FORMAT_NONE:
737					keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;	// default
738					break;
739				case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
740					break;
741				default:
742					printf("***Diffie-Hellman Private key must be in PKCS8 format.\n");
743					return CSSMERR_CSSM_INTERNAL_ERROR;
744			}
745			privKeyLabel = "Imported Diffie-Hellman key";
746			break;
747		case CSSM_ALGID_ECDSA:
748			switch(keyFormat) {
749				case CSSM_KEYBLOB_RAW_FORMAT_NONE:
750					keyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;	// default
751					break;
752				case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
753				case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
754					break;
755				default:
756					printf("***ECDSA Private key must be in PKCS8 or OpenSSLformat.\n");
757					return CSSMERR_CSSM_INTERNAL_ERROR;
758			}
759			privKeyLabel = "Imported ECDSA key";
760			break;
761	}
762	if(readFile(privKeyFileName, &pemKey, &pemKeyLen)) {
763		printf("***Error reading private key from file %s. Aborting.\n",
764			privKeyFileName);
765		return CSSMERR_CSSM_INTERNAL_ERROR;
766	}
767	/* subsequent errors to done: */
768	if(pemFormat) {
769		int rtn = pemDecode(pemKey, pemKeyLen, &derKey, &derKeyLen);
770		if(rtn) {
771			printf("***%s: Bad PEM formatting. Aborting.\n", privKeyFileName);
772			crtn = CSSMERR_CSP_INVALID_KEY;
773			goto done;
774		}
775	}
776	else {
777		derKey = pemKey;
778		derKeyLen = pemKeyLen;
779	}
780
781	/* importing a raw key into the CSPDL involves a NULL unwrap */
782	memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
783	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
784
785	/* set up the imported key to look like a CSSM_KEY */
786	hdr->HeaderVersion 			= CSSM_KEYHEADER_VERSION;
787	hdr->BlobType 				= CSSM_KEYBLOB_RAW;
788	hdr->AlgorithmId		 	= keyAlg;
789	hdr->KeyClass 				= CSSM_KEYCLASS_PRIVATE_KEY;
790	hdr->KeyAttr 				= CSSM_KEYATTR_EXTRACTABLE;
791	hdr->KeyUsage 				= CSSM_KEYUSE_ANY;
792	hdr->Format 				= keyFormat;
793	wrappedKey.KeyData.Data 	= derKey;
794	wrappedKey.KeyData.Length 	= derKeyLen;
795
796	/* get key size in bits from raw CSP */
797	rawCspHand = cuCspStartup(CSSM_TRUE);
798	if(rawCspHand == 0) {
799		printf("***Error attaching to CSP. Aborting.\n");
800		crtn = CSSMERR_CSSM_INTERNAL_ERROR;
801		goto done;
802	}
803	CSSM_KEY_SIZE keySize;
804	crtn = CSSM_QueryKeySizeInBits(rawCspHand, CSSM_INVALID_HANDLE, &wrappedKey, &keySize);
805	if(crtn) {
806		printError("***Error finding size of key","CSSM_QueryKeySizeInBits",crtn);
807		goto done;
808	}
809	hdr->LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
810
811	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
812	crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
813		CSSM_ALGID_NONE,			// unwrapAlg
814		CSSM_ALGMODE_NONE,			// unwrapMode
815		&creds,
816		NULL, 						// unwrappingKey
817		NULL,						// initVector
818		CSSM_PADDING_NONE, 			// unwrapPad
819		0,							// Params
820		&ccHand);
821	if(crtn) {
822		printError("***Error creating context","CSSM_CSP_CreateSymmetricContext",crtn);
823		goto done;
824	}
825
826	/* add DL/DB to context */
827	CSSM_CONTEXT_ATTRIBUTE newAttr;
828	newAttr.AttributeType     = CSSM_ATTRIBUTE_DL_DB_HANDLE;
829	newAttr.AttributeLength   = sizeof(CSSM_DL_DB_HANDLE);
830	newAttr.Attribute.Data    = (CSSM_DATA_PTR)&dlDbHand;
831	crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr);
832	if(crtn) {
833		printError("***Error updating context attributes","CSSM_UpdateContextAttributes",crtn);
834		goto done;
835	}
836
837	/* do the NULL unwrap */
838	labelData.Data = (uint8 *)privKeyLabel;
839	labelData.Length = strlen(privKeyLabel) + 1;
840	crtn = CSSM_UnwrapKey(ccHand,
841		NULL,				// PublicKey
842		&wrappedKey,
843		CSSM_KEYUSE_ANY,
844		CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE |
845			CSSM_KEYATTR_EXTRACTABLE,
846		&labelData,
847		NULL,				// CredAndAclEntry
848		&unwrappedKey,
849		&descData);		// required
850	if(crtn != CSSM_OK) {
851		cuPrintError("CSSM_UnwrapKey", crtn);
852		goto done;
853	}
854
855	/* one more thing: bind this private key to its public key */
856	crtn = setPubKeyHash(cspHand, dlDbHand, privKeyLabel);
857
858	/* We don't need the unwrapped key any more */
859	CSSM_FreeKey(cspHand,
860		NULL,			// access cred
861		&unwrappedKey,
862		CSSM_FALSE);	// delete
863
864done:
865	if(ccHand) {
866		CSSM_DeleteContext(ccHand);
867	}
868	if(derKey) {
869		free(derKey);
870	}
871	if(pemFormat && pemKey) {
872		free(pemKey);
873	}
874	if(rawCspHand) {
875		CSSM_ModuleDetach(rawCspHand);
876	}
877	return crtn;
878}
879
880static OSStatus importCert(
881	SecKeychainRef		kcRef,
882	CSSM_DL_DB_HANDLE	dlDbHand,
883	CSSM_CSP_HANDLE		cspHand,
884	CSSM_CL_HANDLE		clHand,
885	const char			*fileName,
886	const char			*privKeyFileName,	// optional for importing priv key
887	CSSM_BOOL			pemFormat,			// format of files
888	CSSM_KEYBLOB_FORMAT	privKeyFormat)		// optional format of priv key
889{
890	unsigned char *cert = NULL;
891	unsigned certLen;
892	CSSM_DATA certData;
893	unsigned char *der = NULL;
894	unsigned derLen = 0;
895
896	if(readFile(fileName, &cert, &certLen)) {
897		printf("***Error reading certificate from file %s. Aborting.\n",
898			fileName);
899		return ioErr;
900	}
901	if(pemFormat) {
902		int rtn = pemDecode(cert, certLen, &der, &derLen);
903		if(rtn) {
904			printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
905			return ioErr;
906		}
907		certData.Data = der;
908		certData.Length = derLen;
909	}
910	else {
911		certData.Data = cert;
912		certData.Length = certLen;
913	}
914
915	SecCertificateRef certRef;
916	OSStatus ortn = SecCertificateCreateFromData(
917		&certData,
918		CSSM_CERT_X_509v3,
919		CSSM_CERT_ENCODING_DER,
920		&certRef);
921	if(ortn) {
922		printError("***Error creating certificate","SecCertificateCreateFromData",ortn);
923		cuPrintError("", ortn);
924		return ortn;
925	}
926	ortn = SecCertificateAddToKeychain(certRef, kcRef);
927	if(ortn) {
928		printError("***Error adding certificate to keychain","SecCertificateAddToKeychain",ortn);
929		return ortn;
930	}
931
932	if(privKeyFileName) {
933		/* Importing private key requires algorithm, from cert */
934		CSSM_RETURN crtn;
935		CSSM_KEY_PTR pubKey;
936		crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey);
937		if(crtn) {
938			printError("***Error obtaining public key from cert. Aborting","CSSM_CL_CertGetKeyInfo",crtn);
939			return crtn;
940		}
941		crtn = importPrivateKey(dlDbHand, cspHand, privKeyFileName,
942			pubKey->KeyHeader.AlgorithmId, pemFormat, privKeyFormat);
943		if(crtn) {
944			printError("***Error importing private key. Aborting","importPrivateKey",crtn);
945			return crtn;
946		}
947		/* this was mallocd by the CL */
948		cuAppFree(pubKey->KeyData.Data, NULL);
949		cuAppFree(pubKey, NULL);
950	}
951	printf("...certificate successfully imported.\n");
952	if(der) {
953		free(der);
954	}
955	if(cert) {
956		free(cert);
957	}
958	return noErr;
959}
960
961static OSStatus importCRL(
962	CSSM_DL_DB_HANDLE	dlDbHand,
963	CSSM_CL_HANDLE		clHand,
964	const char			*fileName,
965	CSSM_BOOL			pemFormat)
966{
967	unsigned char *crl = NULL;
968	unsigned crlLen;
969	CSSM_DATA crlData;
970	unsigned char *der = NULL;
971	unsigned derLen = 0;
972
973	if(readFile(fileName, &crl, &crlLen)) {
974		printf("***Error reading CRL from file %s. Aborting.\n",
975			fileName);
976		return ioErr;
977	}
978	if(pemFormat) {
979		int rtn = pemDecode(crl, crlLen, &der, &derLen);
980		if(rtn) {
981			printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
982			return ioErr;
983		}
984		crlData.Data = der;
985		crlData.Length = derLen;
986	}
987	else {
988		crlData.Data = crl;
989		crlData.Length = crlLen;
990	}
991	CSSM_RETURN crtn = cuAddCrlToDb(dlDbHand, clHand, &crlData, NULL);
992	if(crtn) {
993		printError("***Error adding CRL to keychain. Aborting","cuAddCrlToDb",crtn);
994	}
995	else {
996		printf("...CRL successfully imported.\n");
997	}
998	if(der) {
999		free(der);
1000	}
1001	if(crl) {
1002		free(crl);
1003	}
1004	return noErr;
1005}
1006
1007/* Get validity period */
1008uint32 notValidAfter(int isSystemDomain)
1009{
1010  char *validityEnv = NULL;
1011  uint32 validAfter = 0;
1012  int result = 0;
1013
1014  if (isSystemDomain) return SI_DEF_VALIDITY;
1015
1016  validityEnv = getenv(VALIDITY_DAYS_ENVIRONMENT_VARIABLE);
1017
1018  if (validityEnv != NULL) {
1019    result = sscanf(validityEnv, "%u", &validAfter);
1020
1021    /* could we actually parse it? */
1022    if (result == 1) {
1023      /* check that it is between 30 days and 20 years */
1024      if (validAfter < 30) validAfter = 30;
1025      if (validAfter > (365 * 20)) validAfter = (365 * 20);
1026
1027      /* convert to seconds, which is what we need to use */
1028      validAfter *= (60 * 60 * 24);
1029
1030      return validAfter;
1031    }
1032  }
1033
1034  return DEFAULT_CERT_VALIDITY;
1035}
1036
1037
1038/* serial number is generated randomly */
1039#define SERIAL_NUM_LENGTH	4
1040
1041static OSStatus createCertCsr(
1042	CSSM_BOOL			createCsr,			// true: CSR, false: Cert
1043	CSSM_TP_HANDLE		tpHand,				// eventually, a SecKeychainRef
1044	CSSM_CL_HANDLE		clHand,
1045	CSSM_CSP_HANDLE		cspHand,
1046	CSSM_KEY_PTR		subjPubKey,
1047	CSSM_KEY_PTR		signerPrivKey,
1048	CSSM_ALGORITHMS 	sigAlg,
1049	const CSSM_OID		*sigOid,
1050	CU_KeyUsage			keyUsage,			// kKeyUseSigning, etc.
1051	/*
1052	 * Issuer's RDN is obtained from the issuer cert, if present, or is
1053	 * assumed to be the same as the subject name (i.e., we're creating
1054	 * a self-signed root cert).
1055	 */
1056	const CSSM_DATA		*issuerCert,
1057	const CSSM_OID		*extendedKeyUse,	// optional
1058	CSSM_BOOL			useAllDefaults,		// secret 'Z' option
1059	const char			*systemDomain,		// domain name for system identities
1060	CSSM_DATA_PTR		certData)			// cert or CSR: mallocd and RETURNED
1061{
1062	CE_DataAndType 				exts[4];
1063	CE_DataAndType 				*extp = exts;
1064	unsigned					numExts;
1065
1066	CSSM_DATA					refId;		// mallocd by CSSM_TP_SubmitCredRequest
1067	CSSM_APPLE_TP_CERT_REQUEST	certReq;
1068	CSSM_TP_REQUEST_SET			reqSet;
1069	sint32						estTime;
1070	CSSM_BOOL					confirmRequired;
1071	CSSM_TP_RESULT_SET_PTR		resultSet;
1072	CSSM_ENCODED_CERT			*encCert;
1073	CSSM_APPLE_TP_NAME_OID		subjectNames[MAX_NAMES];
1074	uint32						numNames;
1075	CSSM_TP_CALLERAUTH_CONTEXT 	CallerAuthContext;
1076	CSSM_FIELD					policyId;
1077	unsigned char				serialNum[SERIAL_NUM_LENGTH];
1078	CSSM_BOOL			isSystemKDC = CSSM_FALSE;
1079
1080	/* Note a lot of the CSSM_APPLE_TP_CERT_REQUEST fields are not
1081	 * used for the createCsr option, but we'll fill in as much as is practical
1082	 * for either case.
1083	 */
1084	if(issuerCert != NULL) {
1085		printf("createCertCsr: issuerCert not implemented\n");
1086		return unimpErr;
1087	}
1088
1089	numExts = 0;
1090
1091	if (systemDomain != NULL && strncmp(SYSTEM_KDC, systemDomain, strlen(SYSTEM_KDC)) == 0) {
1092		isSystemKDC = CSSM_TRUE;
1093	}
1094
1095	char challengeBuf[400];
1096	if(createCsr) {
1097		if(useAllDefaults) {
1098			strcpy(challengeBuf, ZDEF_CHALLENGE);
1099		}
1100		else {
1101			while(1) {
1102				getStringWithPrompt("Enter challenge string: ",
1103					challengeBuf, sizeof(challengeBuf));
1104				if(challengeBuf[0] != '\0') {
1105					break;
1106				}
1107			}
1108		}
1109		certReq.challengeString = challengeBuf;
1110	}
1111	else {
1112		/* creating cert */
1113		certReq.challengeString = NULL;
1114
1115		/* KeyUsage extension */
1116		if(systemDomain) {
1117			extp->type = DT_KeyUsage;
1118			extp->critical = CSSM_FALSE;
1119			extp->extension.keyUsage = 0;
1120			if(keyUsage & kKeyUseSigning) {
1121				extp->extension.keyUsage |=
1122					(CE_KU_DigitalSignature);
1123			}
1124			if (isSystemKDC) {
1125			    if(keyUsage & kKeyUseEncrypting) {
1126				extp->extension.keyUsage |=
1127					(CE_KU_KeyEncipherment);
1128			    }
1129			}
1130			else {
1131			    if(keyUsage & kKeyUseEncrypting) {
1132				extp->extension.keyUsage |=
1133					(CE_KU_KeyEncipherment | CE_KU_DataEncipherment);
1134			    }
1135			    if(keyUsage & kKeyUseDerive) {
1136				extp->extension.keyUsage |= CE_KU_KeyAgreement;
1137			    }
1138			}
1139			extp++;
1140			numExts++;
1141		}
1142
1143		/* BasicConstraints */
1144		if(!systemDomain) {
1145			extp->type = DT_BasicConstraints;
1146			extp->critical = CSSM_TRUE;
1147			extp->extension.basicConstraints.cA = CSSM_TRUE;
1148			extp->extension.basicConstraints.pathLenConstraintPresent = CSSM_FALSE;
1149			extp++;
1150			numExts++;
1151		}
1152
1153		/* Extended Key Usage, optional */
1154		if (extendedKeyUse != NULL) {
1155			extp->type = DT_ExtendedKeyUsage;
1156			extp->critical = CSSM_FALSE;
1157			extp->extension.extendedKeyUsage.numPurposes = 1;
1158			extp->extension.extendedKeyUsage.purposes = const_cast<CSSM_OID_PTR>(extendedKeyUse);
1159			extp++;
1160			numExts++;
1161		}
1162
1163	    if (isSystemKDC) {
1164		uint8_t	    oidData[] = {0x2B, 0x6, 0x1, 0x5, 0x2, 0x3, 0x5};
1165		CSSM_OID    oid = {sizeof(oidData), oidData};
1166		extp->type = DT_ExtendedKeyUsage;
1167		extp->critical = CSSM_FALSE;
1168		extp->extension.extendedKeyUsage.numPurposes = 1;
1169		extp->extension.extendedKeyUsage.purposes = &oid;
1170		extp++;
1171		numExts++;
1172	    }
1173
1174
1175	}
1176
1177	/* name array */
1178	if(systemDomain) {
1179		subjectNames[0].string 	= systemDomain;
1180		subjectNames[0].oid 	= &CSSMOID_CommonName;
1181		subjectNames[1].string 	= SI_DEF_ORG_NAME;
1182		subjectNames[1].oid 	= &CSSMOID_OrganizationName;
1183		numNames = 2;
1184	}
1185	else if(useAllDefaults) {
1186		subjectNames[0].string 	= ZDEF_COMMON_NAME;
1187		subjectNames[0].oid 	= &CSSMOID_CommonName;
1188		subjectNames[1].string	= ZDEF_ORG_NAME;
1189		subjectNames[1].oid 	= &CSSMOID_OrganizationName;
1190		subjectNames[2].string	= ZDEF_COUNTRY;
1191		subjectNames[2].oid 	= &CSSMOID_CountryName;
1192		subjectNames[3].string	= ZDEF_STATE;
1193		subjectNames[3].oid 	= &CSSMOID_StateProvinceName;
1194		numNames = 4;
1195	}
1196	else {
1197		getNameOids(subjectNames, &numNames);
1198	}
1199
1200	/* certReq */
1201	certReq.cspHand = cspHand;
1202	certReq.clHand = clHand;
1203	certReq.numSubjectNames = numNames;
1204	certReq.subjectNames = subjectNames;
1205
1206	/* random serial number */
1207	try {
1208		DevRandomGenerator drg;
1209		drg.random(serialNum, SERIAL_NUM_LENGTH);
1210		/* MS bit must be zero */
1211		serialNum[0] &= 0x7f;
1212		certReq.serialNumber = ((uint32)(serialNum[0])) << 24 |
1213							   ((uint32)(serialNum[1])) << 16 |
1214							   ((uint32)(serialNum[2])) << 8 |
1215							   ((uint32)(serialNum[3]));
1216	}
1217	catch(...) {
1218		certReq.serialNumber = 0x12345678;
1219	}
1220
1221	/* TBD - if we're passed in a signing cert, certReq.issuerNameX509 will
1222	 * be obtained from that cert. For now we specify "self-signed" cert
1223	 * by not providing an issuer name at all. */
1224	certReq.numIssuerNames = 0;				// root for now
1225	certReq.issuerNames = NULL;
1226	certReq.issuerNameX509 = NULL;
1227	certReq.certPublicKey = subjPubKey;
1228	certReq.issuerPrivateKey = signerPrivKey;
1229	certReq.signatureAlg = sigAlg;
1230	certReq.signatureOid = *sigOid;
1231	certReq.notBefore = 0;					// TBD - from user
1232	certReq.notAfter = notValidAfter((systemDomain == NULL) ? 0 : 1);
1233
1234	certReq.numExtensions = numExts;
1235	certReq.extensions = exts;
1236
1237	reqSet.NumberOfRequests = 1;
1238	reqSet.Requests = &certReq;
1239
1240	/* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */
1241	memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
1242	memset(&policyId, 0, sizeof(CSSM_FIELD));
1243	if(createCsr) {
1244		policyId.FieldOid = CSSMOID_APPLE_TP_CSR_GEN;
1245	}
1246	else {
1247		policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
1248	}
1249	CallerAuthContext.Policy.NumberOfPolicyIds = 1;
1250	CallerAuthContext.Policy.PolicyIds = &policyId;
1251
1252	CssmClient::AclFactory factory;
1253	CallerAuthContext.CallerCredentials =
1254		const_cast<Security::AccessCredentials *>(factory.promptCred());
1255
1256	CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tpHand,
1257		NULL,				// PreferredAuthority
1258		CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
1259		&reqSet,
1260		&CallerAuthContext,
1261		&estTime,
1262		&refId);
1263
1264	/* before proceeding, free resources allocated thus far */
1265	if(!useAllDefaults && (systemDomain == NULL)) {
1266		freeNameOids(subjectNames, numNames);
1267	}
1268
1269	if(crtn) {
1270		printError("***Error submitting credential request","CSSM_TP_SubmitCredRequest",crtn);
1271		return crtn;
1272	}
1273	crtn = CSSM_TP_RetrieveCredResult(tpHand,
1274		&refId,
1275		NULL,				// CallerAuthCredentials
1276		&estTime,
1277		&confirmRequired,
1278		&resultSet);
1279	if(crtn) {
1280		printError("***Error retreiving credential request","CSSM_TP_RetrieveCredResult",crtn);
1281		return crtn;
1282	}
1283	if(resultSet == NULL) {
1284		printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
1285		return ioErr;
1286	}
1287	encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
1288	*certData = encCert->CertBlob;
1289
1290	/* free resources allocated by TP */
1291	APP_FREE(refId.Data);
1292	APP_FREE(encCert);
1293	APP_FREE(resultSet);
1294	return noErr;
1295}
1296
1297/* dump all certs & CRLs in a DL/DB */
1298static OSStatus dumpCrlsCerts(
1299	CSSM_DL_DB_HANDLE	dlDbHand,
1300	CSSM_CL_HANDLE		clHand,
1301	CSSM_BOOL			verbose)
1302{
1303	CSSM_RETURN crtn;
1304	unsigned numItems;
1305
1306	crtn = cuDumpCrlsCerts(dlDbHand, clHand, CSSM_TRUE, numItems, verbose);
1307	if(crtn && (crtn != CSSMERR_DL_INVALID_RECORDTYPE)) {
1308		/* invalid record type just means "this hasn't been set up
1309		 * for certs yet". */
1310		return noErr;
1311	}
1312	printf("...%u certificates found\n", numItems);
1313	crtn = cuDumpCrlsCerts(dlDbHand, clHand, CSSM_FALSE, numItems, verbose);
1314	if(crtn && (crtn != CSSMERR_DL_INVALID_RECORDTYPE)) {
1315		/* invalid record type just means "this hasn't been set up
1316		 * for CRLs yet". */
1317		return noErr;
1318	}
1319	printf("...%u CRLs found\n", numItems);
1320	return noErr;
1321}
1322
1323
1324typedef enum {
1325	CO_Nop,
1326	CO_CreateCert,
1327	CO_CreateCSR,
1328	CO_VerifyCSR,
1329	CO_ImportCert,
1330	CO_DisplayCert,
1331	CO_ImportCRL,
1332	CO_DisplayCRL,
1333	CO_DumpDb,			// display certs & CRLs from a DB
1334	CO_SystemIdentity
1335} CertOp;
1336
1337int realmain (int argc, char **argv)
1338{
1339	SecKeychainRef 		kcRef = nil;
1340	char 				kcPath[MAXPATHLEN + 1];
1341	UInt32 				kcPathLen = MAXPATHLEN + 1;
1342	CSSM_BOOL			createKc = CSSM_FALSE;
1343	OSStatus 			ortn;
1344	CSSM_DL_DB_HANDLE 	dlDbHand = {0, 0};
1345	CSSM_CSP_HANDLE		cspHand = 0;
1346	CSSM_TP_HANDLE		tpHand = 0;
1347	CSSM_CL_HANDLE		clHand = 0;
1348	CSSM_KEY_PTR		pubKey;
1349	CSSM_KEY_PTR		privKey;
1350	int					arg;
1351	char				*argp;
1352	CSSM_ALGORITHMS 	keyAlg;
1353	CSSM_ALGORITHMS 	sigAlg;
1354	const CSSM_OID		*sigOid;
1355	CSSM_DATA			certData = {0, NULL};
1356	CU_KeyUsage			keyUsage = 0;
1357	bool				isRoot;
1358	CSSM_DATA			keyLabel;
1359	CSSM_BOOL			createCsr = CSSM_FALSE;			// else create cert
1360	int					optArgs = 0;
1361	UInt32 				pwdLen = 0;
1362	Boolean 			promptUser = true;
1363	char				*allocdPassPhrase = NULL;
1364	OSStatus			ourRtn = noErr;
1365
1366	/* command line arguments */
1367	char				*fileName = NULL;
1368	CSSM_BOOL			pemFormat = CSSM_TRUE;
1369	CertOp				op = CO_Nop;
1370	uint32				keySizeInBits;
1371	char				*kcName = NULL;
1372	CSSM_BOOL			useAllDefaults = CSSM_FALSE;	// undoc'd cmd option
1373	char				*passPhrase = NULL;
1374	const char			*privKeyFileName = NULL;		// optional openssl-style private key
1375	CSSM_KEYBLOB_FORMAT	privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE;
1376	SecKeyRef			pubSecKey = NULL;
1377	SecKeyRef			privSecKey = NULL;
1378	CSSM_BOOL			useSecKey = CSSM_FALSE; 		// w/default ACL
1379	const CSSM_OID		*extKeyUse = NULL;
1380	CSSM_BOOL			aclForUid = CSSM_FALSE;			// ACL limited to current uid */
1381	CSSM_BOOL			avoidDupIdentity = CSSM_FALSE;
1382	const char			*domainName = NULL;
1383	CFStringRef			cfDomain = NULL;
1384
1385	if(argc < 2) {
1386		usage(argv);
1387	}
1388	switch(argv[1][0]) {
1389		case 'c':
1390			op = CO_CreateCert;
1391			optArgs = 2;
1392			break;
1393		case 'r':
1394			if(argc < 3) {
1395				usage(argv);
1396			}
1397			op = CO_CreateCSR;
1398			createCsr = CSSM_TRUE;
1399			fileName = argv[2];
1400			optArgs = 3;
1401			break;
1402
1403		case 'C':
1404			if(argc < 3) {
1405				usage(argv);
1406			}
1407			op = CO_SystemIdentity;
1408			domainName = argv[2];
1409			cfDomain = CFStringCreateWithCString(NULL,
1410					domainName, kCFStringEncodingASCII);
1411			optArgs = 3;
1412			/* custom ExtendedKeyUse for this type of cert */
1413			extKeyUse = &CSSMOID_APPLE_EKU_SYSTEM_IDENTITY;
1414			/* *some* ACL - default, or per-uid (specified later) */
1415			useSecKey = CSSM_TRUE;
1416			break;
1417
1418		case 'i':
1419			if(argc < 3) {
1420				usage(argv);
1421			}
1422			optArgs = 3;
1423			op = CO_ImportCert;
1424			fileName = argv[2];
1425			break;
1426		case 'd':
1427			if(argc < 3) {
1428				usage(argv);
1429			}
1430			op = CO_DisplayCert;
1431			fileName = argv[2];
1432			optArgs = 3;
1433			break;
1434		case 'I':
1435			if(argc < 3) {
1436				usage(argv);
1437			}
1438			optArgs = 3;
1439			op = CO_ImportCRL;
1440			fileName = argv[2];
1441			break;
1442		case 'D':
1443			if(argc < 3) {
1444				usage(argv);
1445			}
1446			op = CO_DisplayCRL;
1447			fileName = argv[2];
1448			optArgs = 3;
1449			break;
1450		case 'y':
1451			op = CO_DumpDb;
1452			optArgs = 2;
1453			break;
1454		default:
1455			usage(argv);
1456	}
1457	for(arg=optArgs; arg<argc; arg++) {
1458		argp = argv[arg];
1459		switch(argp[0]) {
1460			case 'k':
1461				if(argp[1] != '=') {
1462					usage(argv);
1463				}
1464				kcName = &argp[2];
1465				break;
1466		    case 'v':
1467				verbose = CSSM_TRUE;
1468				break;
1469			case 'd':
1470				pemFormat = CSSM_FALSE;
1471				break;
1472			case 'c':
1473				createKc = CSSM_TRUE;
1474				break;
1475			case 'p':
1476				if(argp[1] != '=') {
1477					usage(argv);
1478				}
1479				passPhrase = &argp[2];
1480				break;
1481			case 'o':
1482				if((op != CO_CreateCert) || (argp[1] != '=')){
1483					usage(argv);
1484				}
1485				fileName = &argp[2];
1486				break;
1487			case 'r':
1488				privKeyFileName = &argp[2];
1489				break;
1490			case 'f':
1491				if(argp[1] != '=') {
1492					usage(argv);
1493				}
1494				switch(argp[2]) {
1495					case '1':
1496						privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
1497						break;
1498					case '8':
1499						privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
1500						break;
1501					case 'f':
1502						privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
1503						break;
1504					case 'o':
1505						privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
1506						break;
1507					default:usage(argv);
1508				}
1509				break;
1510			case 'x':
1511				if(argp[1] != '=') {
1512					usage(argv);
1513				}
1514				switch(argp[2]) {
1515					case 'a':
1516						extKeyUse = &CSSMOID_ExtendedKeyUsageAny;
1517						break;
1518					case 's':
1519						extKeyUse = &CSSMOID_ClientAuth;
1520						break;
1521					case 'S':
1522						extKeyUse = &CSSMOID_ServerAuth;
1523						break;
1524					case 'm':
1525						extKeyUse = &CSSMOID_EmailProtection;
1526						break;
1527					default:
1528						usage(argv);
1529				}
1530				break;
1531			case 'Z':
1532				/* undocumented "use all defaults quickly" option */
1533				useAllDefaults = CSSM_TRUE;
1534				break;
1535			case 'a':
1536				/* default ACL */
1537				useSecKey = CSSM_TRUE;
1538				break;
1539			case 'u':
1540				/* ACL for uid */
1541				useSecKey = CSSM_TRUE;
1542				aclForUid = CSSM_TRUE;
1543				break;
1544			case 'P':
1545				avoidDupIdentity = CSSM_TRUE;
1546				break;
1547			default:
1548				usage(argv);
1549		}
1550	}
1551	if((passPhrase != NULL) && !createKc) {
1552		printf("***passphrase specification only allowed on keychain create. Aborting.\n");
1553		exit(1);
1554	}
1555
1556	switch(op) {
1557		case CO_DisplayCert:
1558			/* ready to roll */
1559			displayCertCRL(fileName, pemFormat, CC_Cert, verbose);
1560			return 0;
1561		case CO_DisplayCRL:
1562			displayCertCRL(fileName, pemFormat, CC_CRL, verbose);
1563			return 0;
1564		case CO_SystemIdentity:
1565			if(avoidDupIdentity) {
1566				/*
1567				 * We're done if there already exists an identity for
1568				 * the specified domain.
1569				 */
1570				CFStringRef actualDomain = NULL;
1571				SecIdentityRef idRef = NULL;
1572				bool done = false;
1573
1574				OSStatus ortn = SecIdentityCopySystemIdentity(cfDomain,
1575					&idRef, &actualDomain);
1576				if(ortn == noErr) {
1577					if((actualDomain != NULL) && CFEqual(actualDomain, cfDomain)) {
1578						printf("...System identity already exists for domain %s. Done.\n",
1579							domainName);
1580						done = true;
1581					}
1582				}
1583				if(actualDomain) {
1584					CFRelease(actualDomain);
1585				}
1586				if(idRef) {
1587					CFRelease(idRef);
1588				}
1589				if(done) {
1590					CFRelease(cfDomain);
1591					return 0;
1592				}
1593			}
1594			break;
1595		default:
1596			/* proceed */
1597			break;
1598	}
1599
1600	clHand = cuClStartup();
1601	if(clHand == 0) {
1602		printf("Error connecting to CL. Aborting.\n");
1603		exit(1);
1604	}
1605
1606	/* that's all we need for verifying a CSR */
1607	if(op == CO_VerifyCSR) {
1608		ourRtn = verifyCsr(clHand, fileName, pemFormat);
1609		goto abort;
1610	}
1611
1612	/* Cook up a keychain path */
1613	if(op == CO_SystemIdentity) {
1614		/* this one's implied and hard coded */
1615		const char *sysKcPath = kSystemKeychainDir  kSystemKeychainName;
1616		strncpy(kcPath, sysKcPath, MAXPATHLEN);
1617	}
1618	else if(kcName) {
1619		if(kcName[0] == '/') {
1620			/* specific keychain not in Library/Keychains */
1621			check_obsolete_keychain(kcName);
1622			strncpy(kcPath, kcName, MAXPATHLEN);
1623		}
1624		else {
1625			const char *userHome = getenv("HOME");
1626
1627			if(userHome == NULL) {
1628				/* well, this is probably not going to work */
1629				userHome = "";
1630			}
1631			snprintf(kcPath, MAXPATHLEN, "%s/%s/%s", userHome, KC_DB_PATH, kcName);
1632		}
1633	}
1634	else {
1635		/* use default keychain */
1636		ortn = SecKeychainCopyDefault(&kcRef);
1637		if(ortn) {
1638			printError("***Error retreiving default keychain","SecKeychainCopyDefault",ortn);
1639			exit(1);
1640		}
1641		ortn = SecKeychainGetPath(kcRef, &kcPathLen, kcPath);
1642		if(ortn) {
1643			printError("***Error retreiving default keychain path","SecKeychainGetPath",ortn);
1644			exit(1);
1645		}
1646
1647		/*
1648		 * OK, we have a path, we have to release the first KC ref,
1649		 * then get another one by opening it
1650		 */
1651		CFRelease(kcRef);
1652	}
1653
1654	if(passPhrase != NULL) {
1655		pwdLen = strlen(passPhrase);
1656		/* work around bug - incoming passphrase gets freed */
1657		Security::Allocator &alloc = Security::Allocator::standard();
1658		allocdPassPhrase = (char *)alloc.malloc(pwdLen);
1659		memmove(allocdPassPhrase, passPhrase, pwdLen);
1660		promptUser = false;
1661	}
1662	if(createKc) {
1663		ortn = SecKeychainCreate(kcPath,
1664			pwdLen,
1665			allocdPassPhrase,
1666			promptUser,
1667			nil,	// initialAccess
1668			&kcRef);
1669		/* fixme - do we have to open it? */
1670		if(ortn) {
1671			printError("***Error creating keychain","SecKeychainCreate",ortn);
1672			printf("***Path: %s\n", kcPath);
1673			exit(1);
1674		}
1675	}
1676	else {
1677		ortn = SecKeychainOpen(kcPath, &kcRef);
1678		if(ortn) {
1679			printError("***Error opening keychain. Aborting","SecKeychainOpen",ortn);
1680			printf("***Path: %s\n", kcPath);
1681			exit(1);
1682		}
1683	}
1684
1685	/* get associated DL/DB handle */
1686	ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand);
1687	if(ortn) {
1688		printError("***Error getting keychain handle","SecKeychainGetDLDBHandle",ortn);
1689		exit(1);
1690	}
1691
1692	ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
1693	if(ortn) {
1694		printError("***Error getting keychain CSP handle","SecKeychainGetCSPHandle",ortn);
1695		exit(1);
1696	}
1697
1698	switch(op) {
1699		case CO_ImportCert:
1700			ourRtn = importCert(kcRef, dlDbHand, cspHand, clHand, fileName, privKeyFileName,
1701				pemFormat, privKeyFormat);
1702			goto abort;
1703		case CO_ImportCRL:
1704			ourRtn = importCRL(dlDbHand, clHand, fileName, pemFormat);
1705			goto abort;
1706		case CO_DumpDb:
1707			ourRtn = dumpCrlsCerts(dlDbHand, clHand, verbose);
1708			goto abort;
1709		default:
1710			break;
1711	}
1712
1713	/* remaining ops need TP as well */
1714	tpHand = cuTpStartup();
1715	if(tpHand == 0) {
1716		printf("Error connecting to TP. Aborting.\n");
1717		exit(1);
1718	}
1719
1720	/*** op = CO_CreateCert, CO_CreateCSR, CO_SystemIdentity ***/
1721
1722	/*
1723	 * TBD: eventually we want to present the option of using an existing
1724	 * SecIdentityRef from the keychain as the signing cert/key.
1725	 */
1726	isRoot = true;
1727
1728	/*
1729	 * Generate a key pair - via CDSA if no ACL is requested, else
1730	 * SecKeyCreatePair().
1731	 */
1732	char labelBuf[200];
1733	if(op == CO_SystemIdentity) {
1734		strncpy(labelBuf, domainName, sizeof(labelBuf));
1735	}
1736	else if(useAllDefaults) {
1737		/* the secret 'Z' option */
1738		strcpy(labelBuf, ZDEF_KEY_LABEL);
1739	}
1740	else {
1741		while(1) {
1742			getStringWithPrompt("Enter key and certificate label: ", labelBuf,
1743				sizeof(labelBuf));
1744			if(labelBuf[0] != '\0') {
1745				break;
1746			}
1747		}
1748	}
1749	keyLabel.Data = (uint8 *)labelBuf;
1750	keyLabel.Length = strlen(labelBuf);
1751
1752	/* get key algorithm and size */
1753	if(op == CO_SystemIdentity) {
1754		keyAlg = SI_DEF_KEY_ALG;
1755		keySizeInBits = SI_DEF_KEY_SIZE;
1756	}
1757	else if(useAllDefaults) {
1758		keyAlg = ZDEF_KEY_ALG;
1759		keySizeInBits = ZDEF_KEY_SIZE;
1760	}
1761	else {
1762		getKeyParams(keyAlg, keySizeInBits);
1763	}
1764
1765	/* get usage for keys and certs */
1766	if(op == CO_SystemIdentity) {
1767		keyUsage = SI_DEF_KEY_USAGE;
1768	}
1769	else if(useAllDefaults) {
1770		keyUsage = ZDEF_KEY_USAGE;
1771	}
1772	else {
1773		keyUsage = getKeyUsage(isRoot);
1774	}
1775
1776	printf("...Generating key pair...\n");
1777
1778	if(useSecKey) {
1779		/* generate keys using SecKeyCreatePair */
1780		ourRtn = generateSecKeyPair(kcRef,
1781			keyAlg,
1782			keySizeInBits,
1783			keyUsage,
1784			aclForUid,
1785			verbose,
1786			labelBuf,
1787			&pubKey,
1788			&privKey,
1789			&pubSecKey,
1790			&privSecKey);
1791	}
1792	else {
1793		/* generate keys using CSPDL */
1794		ourRtn = generateKeyPair(cspHand,
1795			dlDbHand,
1796			keyAlg,
1797			keySizeInBits,
1798			labelBuf,
1799			keyUsage,
1800			verbose,
1801			&pubKey,
1802			&privKey);
1803	}
1804	if(ourRtn) {
1805		printError("Error generating keys; aborting","generateKeyPair",ourRtn);
1806		goto abort;
1807	}
1808
1809	/* get signing algorithm per the signing key */
1810	if(op == CO_SystemIdentity) {
1811		sigAlg = SI_DEF_SIG_ALG;
1812		sigOid = &SI_DEF_SIG_OID;
1813	}
1814	else if(useAllDefaults) {
1815		sigAlg = ZDEF_SIG_ALG;
1816		sigOid = &ZDEF_SIG_OID;
1817	}
1818	else {
1819		ourRtn = getSigAlg(privKey, sigAlg, sigOid);
1820		if(ourRtn) {
1821			printError("Cannot sign with this private key. Aborting","getSigAlg",ourRtn);
1822			goto abort;
1823		}
1824	}
1825
1826	if(createCsr) {
1827		printf("...creating CSR...\n");
1828	}
1829	else {
1830		printf("...creating certificate...\n");
1831	}
1832	/* generate the cert */
1833	ourRtn = createCertCsr(createCsr,
1834		tpHand,
1835		clHand,
1836		cspHand,
1837		pubKey,
1838		privKey,
1839		sigAlg,
1840		sigOid,
1841		keyUsage,
1842		NULL,		// issuer cert
1843		extKeyUse,
1844		useAllDefaults,
1845		domainName,
1846		&certData);
1847	if(ourRtn) {
1848		goto abort;
1849	}
1850	if(verbose) {
1851		printCert(certData.Data, certData.Length, CSSM_FALSE);
1852		printCertShutdown();
1853	}
1854
1855	if(fileName) {
1856		/*
1857		 * Create CSR, or create cert with outFileName option.
1858		 * Write results to a file
1859		 */
1860		unsigned char *pem = NULL;
1861		unsigned pemLen;
1862		int rtn;
1863
1864		if(pemFormat) {
1865			const char *headerStr;
1866			switch(op) {
1867				case CO_CreateCSR:
1868					headerStr = "CERTIFICATE REQUEST";
1869					break;
1870				case CO_CreateCert:
1871					headerStr = "CERTIFICATE";
1872					break;
1873				default:
1874					printf("***INTERNAL ERROR; aborting.\n");
1875					exit(1);
1876			}
1877			rtn = pemEncode(certData.Data, certData.Length, &pem, &pemLen, headerStr);
1878			if(rtn) {
1879				/* very unlikely, I think malloc is the only failure */
1880				printf("***Error PEM-encoding output. Aborting.\n");
1881				goto abort;
1882			}
1883			rtn = writeFile(fileName, pem, pemLen);
1884		}
1885		else {
1886			rtn = writeFile(fileName, certData.Data, certData.Length);
1887		}
1888		if(rtn) {
1889			printf("***Error writing CSR to %s\n", fileName);
1890			ourRtn = ioErr;
1891		}
1892		else {
1893			printf("Wrote %u bytes of CSR to %s\n", (unsigned)certData.Length,
1894				fileName);
1895		}
1896		if(pem) {
1897			free(pem);
1898		}
1899	}
1900	if((op == CO_CreateCert) || (op == CO_SystemIdentity)) {
1901		/* store the cert in the same DL/DB as the key pair */
1902		SecCertificateRef certRef = NULL;
1903
1904		OSStatus ortn = SecCertificateCreateFromData(
1905			&certData,
1906			CSSM_CERT_X_509v3,
1907			CSSM_CERT_ENCODING_DER,
1908			&certRef);
1909		if(ortn) {
1910			printError("***Error creating certificate",
1911				"SecCertificateCreateFromData", ortn);
1912			cuPrintError("", ortn);
1913			ourRtn = ortn;
1914		}
1915		else {
1916			ortn = SecCertificateAddToKeychain(certRef, kcRef);
1917			if(ortn) {
1918				printError("***Error adding certificate to keychain",
1919					"SecCertificateAddToKeychain", ortn);
1920				ourRtn = ortn;
1921			}
1922		}
1923		if(ourRtn == noErr) {
1924			printf("..cert stored in Keychain.\n");
1925			if(op == CO_SystemIdentity) {
1926				/*
1927				 * Get the SecIdentityRef assocaited with this cert and
1928				 * register it
1929				 */
1930				SecIdentityRef idRef;
1931				ortn = SecIdentityCreateWithCertificate(kcRef, certRef, &idRef);
1932				if(ortn) {
1933					printError("Cannot register Identity",
1934						"SecIdentityCreateWithCertificate", ortn);
1935				}
1936				else {
1937					ortn = SecIdentitySetSystemIdentity(cfDomain, idRef);
1938					CFRelease(idRef);
1939					if(ortn) {
1940						printError("Cannot register Identity",
1941							"SecIdentitySetSystemIdentity", ortn);
1942					}
1943					else {
1944						printf("..identity registered for domain %s.\n", domainName);
1945
1946					}
1947				}
1948				CFRelease(cfDomain);
1949			}	/* CO_SystemIdentity */
1950		}	/* cert store successful */
1951		if(certRef) {
1952			CFRelease(certRef);
1953		}
1954	}	/* generated/stored a cert */
1955abort:
1956	/* CLEANUP */
1957	if(pubSecKey != NULL) {
1958		CFRelease(pubSecKey);
1959	}
1960	if(privSecKey != NULL) {
1961		CFRelease(privSecKey);
1962	}
1963	return ourRtn;
1964}
1965
1966int main (int argc, char **argv)
1967{
1968	try {
1969		return realmain (argc, argv);
1970	}
1971	catch (AbortException e)
1972	{
1973		putchar ('\n'); // prompt on the next line.
1974		return 1;
1975	}
1976}
1977
1978