]> git.saurik.com Git - apple/security.git/blob - CertTool/CertTool.cpp
daba817842240fe5a4a1b7de828f6591bde49e86
[apple/security.git] / CertTool / CertTool.cpp
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/cssmalloc.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <ctype.h>
38 #include <sys/param.h>
39 #include <CdsaUtils/cuCdsaUtils.h>
40 #include <CdsaUtils/cuDbUtils.h>
41 #include <CdsaUtils/cuPrintCert.h>
42 #include <CdsaUtils/cuFileIo.h>
43 #include <CdsaUtils/cuPem.h>
44 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
45 #include "CertUI.h"
46 #include <CoreFoundation/CoreFoundation.h>
47 #include <Security/utilities.h>
48 #include <Security/aclclient.h>
49
50 /*
51 * Workaround flags.
52 */
53
54 /* SecKeychainGetCSPHandle implemented? */
55 #define SEC_KEYCHAIN_GET_CSP 1
56
57 /* SecKeyCreatePair() implemented */
58 #define SEC_KEY_CREATE_PAIR 1
59
60 /* munge Label attr if manually generating or importing keys */
61 #define MUNGE_LABEL_ATTR 1
62
63 #define KC_DB_PATH "Library/Keychains" /* relative to home */
64
65 /*
66 * defaults for undocumented 'Z' option
67 */
68 #define ZDEF_KEY_LABEL "testCert"
69 #define ZDEF_KEY_ALG CSSM_ALGID_RSA
70 #define ZDEF_KEY_SIZE 512
71 #define ZDEF_KEY_USAGE (kKeyUseSigning | kKeyUseEncrypting)
72 #define ZDEF_SIG_ALG CSSM_ALGID_SHA1WithRSA
73 #define ZDEF_SIG_OID CSSMOID_SHA1WithRSA
74 #define ZDEF_COMMON_NAME "localhost"
75 #define ZDEF_ORG_NAME "Apple Computer - DEBUG ONLY"
76 #define ZDEF_COUNTRY "US"
77 #define ZDEF_STATE "Washington"
78 #define ZDEF_CHALLENGE "someChallenge"
79
80 CSSM_BOOL verbose = CSSM_FALSE;
81
82 static void usage(char **argv)
83 {
84 printf("usage:\n");
85 printf(" Create a keypair and cert: %s c [options]\n", argv[0]);
86 printf(" Create a CSR: %s r outFileName [options]\n",
87 argv[0]);
88 printf(" Verify a CSR: %s v infileName [options]\n", argv[0]);
89 printf(" Import a certificate: %s i inFileName [options]\n", argv[0]);
90 printf(" Display a certificate: %s d inFileName [options]\n", argv[0]);
91 printf(" Import a CRL: %s I inFileName [options]\n", argv[0]);
92 printf(" Display a CRL: %s D inFileName [options]\n", argv[0]);
93 printf(" Display certs and CRLs in keychain: %s y [options]\n", argv[0]);
94 printf("Options:\n");
95 printf(" k=keychainName\n");
96 printf(" c (create the keychain)\n");
97 printf(" p=passphrase (specify passphrase at keychain creation)\n");
98 printf(" o=outFileName (create cert command only)\n");
99 printf(" v (verbose)\n");
100 printf(" d (infile/outfile in DER format; default is PEM)\n");
101 printf(" r=privateKeyFileName (optional; for Import Certificate only)\n");
102 printf(" f=[18f] (private key format = PKCS1/PKCS8/FIPS186; default is PKCS1\n"
103 " (openssl) for RSA, openssl for DSA, PKCS8 for Diffie-Hellman\n");
104 #if SEC_KEY_CREATE_PAIR
105 printf(" a (create key with default ACL)\n");
106 #endif
107 printf(" h(elp)\n");
108 exit(1);
109 }
110
111 static void printError(const char *errDescription,const char *errLocation,OSStatus crtn)
112 {
113 // Show error in text form. If verbose, show location and decimal and hex error values
114 int len=64+(errLocation?strlen(errLocation):0);
115 if (verbose)
116 {
117 char *buf=(char *)malloc(len);
118 if (errDescription)
119 fprintf(stderr,"%s : ",errDescription);
120 // sprintf(buf," %s : %d [0x%x] : ", errLocation,(int)crtn,(unsigned int)crtn);
121 // cuPrintError(buf, crtn);
122 cuPrintError(errLocation, crtn);
123 free(buf);
124 }
125 else
126 {
127 if (errDescription)
128 fprintf(stderr,"%s\n",errDescription);
129 else
130 if (errLocation)
131 fprintf(stderr,"%s\n",errLocation);
132 else
133 fprintf(stderr,"Error: %d [0x%x]\n",(int)crtn,(unsigned int)crtn);
134 }
135 }
136
137 #if SEC_KEY_CREATE_PAIR
138 /*
139 * Generate a key pair using the SecKeyCreatePair.
140 */
141 static OSStatus generateSecKeyPair(
142 SecKeychainRef kcRef,
143 CSSM_ALGORITHMS keyAlg, // e.g., CSSM_ALGID_RSA
144 uint32 keySizeInBits,
145 CU_KeyUsage keyUsage, // CUK_Signing, etc.
146 CSSM_BOOL verbose,
147 CSSM_KEY_PTR *pubKeyPtr, // RETURNED, owned by Sec layer
148 CSSM_KEY_PTR *privKeyPtr, // RETURNED, owned by Sec layer
149 SecKeyRef *pubSecKey, // caller must release
150 SecKeyRef *privSecKey) // caller must release
151 {
152 OSStatus ortn;
153 CSSM_KEYUSE pubKeyUse = 0;
154 CSSM_KEYUSE privKeyUse = 0;
155
156 if(keyUsage & kKeyUseSigning) {
157 pubKeyUse |= CSSM_KEYUSE_VERIFY;
158 privKeyUse |= CSSM_KEYUSE_SIGN;
159 }
160 if(keyUsage & kKeyUseEncrypting) {
161 pubKeyUse |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP);
162 privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP);
163 }
164 ortn = SecKeyCreatePair(kcRef,
165 keyAlg, keySizeInBits,
166 0, // contextHandle
167 pubKeyUse,
168 CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_EXTRACTABLE |
169 CSSM_KEYATTR_RETURN_REF,
170 privKeyUse,
171 CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF |
172 CSSM_KEYATTR_PERMANENT |CSSM_KEYATTR_EXTRACTABLE,
173 NULL, // FIXME - initialAccess
174 pubSecKey,
175 privSecKey);
176 if(ortn) {
177 printError("***Error creating key pair",
178 "SecKeyCreatePair", ortn);
179 cuPrintError("", ortn);
180 return ortn;
181 }
182
183 /* extract CSSM keys for caller */
184 ortn = SecKeyGetCSSMKey(*pubSecKey, const_cast<const CSSM_KEY **>(pubKeyPtr));
185 if(ortn) {
186 printError("***Error extracting public key",
187 "SecKeyGetCSSMKey", ortn);
188 cuPrintError("", ortn);
189 }
190 else ortn = SecKeyGetCSSMKey(*privSecKey, const_cast<const CSSM_KEY **>(privKeyPtr));
191 if(ortn) {
192 printError("***Error extracting private key",
193 "SecKeyGetCSSMKey", ortn);
194 cuPrintError("", ortn);
195 }
196 if(ortn) {
197 CFRelease(*pubSecKey);
198 *pubSecKey = NULL;
199 CFRelease(*privSecKey);
200 *privSecKey = NULL;
201 }
202 return ortn;
203 }
204 #endif
205
206 /*
207 * Workaround to manually generate a key pair and munge its DB attributes
208 * to include the hash of the public key in the private key's Label attr.
209 */
210 #if MUNGE_LABEL_ATTR
211
212 /*
213 * Find private key by label, modify its Label attr to be the
214 * hash of the associated public key.
215 */
216 static CSSM_RETURN setPubKeyHash(
217 CSSM_CSP_HANDLE cspHand,
218 CSSM_DL_DB_HANDLE dlDbHand,
219 const char *keyLabel) // look up by this
220 {
221 CSSM_QUERY query;
222 CSSM_SELECTION_PREDICATE predicate;
223 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
224 CSSM_RETURN crtn;
225 CSSM_DATA labelData;
226 CSSM_HANDLE resultHand;
227
228 labelData.Data = (uint8 *)keyLabel;
229 labelData.Length = strlen(keyLabel) + 1; // incl. NULL
230 query.RecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
231 query.Conjunctive = CSSM_DB_NONE;
232 query.NumSelectionPredicates = 1;
233 predicate.DbOperator = CSSM_DB_EQUAL;
234
235 predicate.Attribute.Info.AttributeNameFormat =
236 CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
237 predicate.Attribute.Info.Label.AttributeName = "Label";
238 predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
239 /* hope this cast is OK */
240 predicate.Attribute.Value = &labelData;
241 query.SelectionPredicate = &predicate;
242
243 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
244 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
245 query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA; // FIXME - used?
246
247 /* build Record attribute with one attr */
248 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
249 CSSM_DB_ATTRIBUTE_DATA attr;
250 attr.Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
251 attr.Info.Label.AttributeName = "Label";
252 attr.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
253
254 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
255 recordAttrs.NumberOfAttributes = 1;
256 recordAttrs.AttributeData = &attr;
257
258 CSSM_DATA recordData = {NULL, 0};
259 crtn = CSSM_DL_DataGetFirst(dlDbHand,
260 &query,
261 &resultHand,
262 &recordAttrs,
263 &recordData,
264 &record);
265 /* abort only on success */
266 if(crtn != CSSM_OK) {
267 printError("***setPubKeyHash: can't find private key","CSSM_DL_DataGetFirst",crtn);
268 return crtn;
269 }
270
271 CSSM_KEY_PTR keyToDigest = (CSSM_KEY_PTR)recordData.Data;
272 CSSM_DATA_PTR keyDigest = NULL;
273 CSSM_CC_HANDLE ccHand;
274 crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
275 keyToDigest,
276 &ccHand);
277 if(crtn) {
278 printError("***Error calculating public key hash. Aborting.",
279 "CSSM_CSP_CreatePassThroughContext", crtn);
280 return crtn;
281 }
282 crtn = CSSM_CSP_PassThrough(ccHand,
283 CSSM_APPLECSP_KEYDIGEST,
284 NULL,
285 (void **)&keyDigest);
286 if(crtn) {
287 printError("***Error calculating public key hash. Aborting.",
288 "CSSM_CSP_PassThrough(PUBKEYHASH)", crtn);
289 return -1;
290 }
291 CSSM_FreeKey(cspHand, NULL, keyToDigest, CSSM_FALSE);
292 CSSM_DeleteContext(ccHand);
293
294 /*
295 * Replace Label attr data with hash.
296 * NOTE: the module which allocated this attribute data - a DL -
297 * was loaded and attached by the Sec layer, not by us. Thus
298 * we can't use the memory allocator functions *we* used when
299 * attaching to the CSPDL - we have to use the ones
300 * which the Sec layer registered with the DL.
301 */
302 CSSM_API_MEMORY_FUNCS memFuncs;
303 crtn = CSSM_GetAPIMemoryFunctions(dlDbHand.DLHandle, &memFuncs);
304 if(crtn) {
305 printError("***Error ","CSSM_GetAPIMemoryFunctions(DLHandle)",crtn);
306 /* oh well, leak and continue */
307 }
308 else {
309 memFuncs.free_func(attr.Value->Data, memFuncs.AllocRef);
310 memFuncs.free_func(attr.Value, memFuncs.AllocRef);
311 }
312 attr.Value = keyDigest;
313
314 /* modify key attributes */
315 crtn = CSSM_DL_DataModify(dlDbHand,
316 CSSM_DL_DB_RECORD_PRIVATE_KEY,
317 record,
318 &recordAttrs,
319 NULL, // DataToBeModified
320 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
321 if(crtn) {
322 printError("***Error setting public key hash. Aborting.",
323 "CSSM_DL_DataModify(PUBKEYHASH)", crtn);
324 return crtn;
325 }
326 crtn = CSSM_DL_DataAbortQuery(dlDbHand, resultHand);
327 if(crtn) {
328 printError("***Error while stopping query",
329 "CSSM_DL_DataAbortQuery", crtn);
330 /* let's keep going in this case */
331 }
332 crtn = CSSM_DL_FreeUniqueRecord(dlDbHand, record);
333 if(crtn) {
334 printError("***Error while freeing record",
335 "CSSM_DL_FreeUniqueRecord", crtn);
336 /* let's keep going in this case */
337 crtn = CSSM_OK;
338 }
339
340 /* free resources */
341 cuAppFree(keyDigest->Data, NULL);
342 return CSSM_OK;
343 }
344 #endif /* MUNGE_LABEL_ATTR */
345
346 /*
347 * Generate a key pair using the CSPDL.
348 */
349 static OSStatus generateKeyPair(
350 CSSM_CSP_HANDLE cspHand,
351 CSSM_DL_DB_HANDLE dlDbHand,
352 CSSM_ALGORITHMS keyAlg, // e.g., CSSM_ALGID_RSA
353 uint32 keySizeInBits,
354 const char *keyLabel, // C string
355 CU_KeyUsage keyUsage, // CUK_Signing, etc.
356 CSSM_BOOL verbose,
357 CSSM_KEY_PTR *pubKeyPtr, // mallocd, created, RETURNED
358 CSSM_KEY_PTR *privKeyPtr) // mallocd, created, RETURNED
359 {
360 CSSM_KEY_PTR pubKey = reinterpret_cast<CSSM_KEY_PTR>(
361 APP_MALLOC(sizeof(CSSM_KEY)));
362 CSSM_KEY_PTR privKey = reinterpret_cast<CSSM_KEY_PTR>(
363 APP_MALLOC(sizeof(CSSM_KEY)));
364 if((pubKey == NULL) || (privKey == NULL)) {
365 return memFullErr;
366 }
367
368 CSSM_RETURN crtn;
369 CSSM_KEYUSE pubKeyUse = 0;
370 CSSM_KEYUSE privKeyUse = 0;
371
372 if(keyUsage & kKeyUseSigning) {
373 pubKeyUse |= CSSM_KEYUSE_VERIFY;
374 privKeyUse |= CSSM_KEYUSE_SIGN;
375 }
376 if(keyUsage & kKeyUseEncrypting) {
377 pubKeyUse |= (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_WRAP);
378 privKeyUse |= (CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_UNWRAP);
379 }
380
381 crtn = cuCspGenKeyPair(cspHand,
382 &dlDbHand,
383 keyAlg,
384 keyLabel,
385 strlen(keyLabel) + 1,
386 keySizeInBits,
387 pubKey,
388 pubKeyUse,
389 CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF,
390 privKey,
391 privKeyUse,
392 CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT |
393 CSSM_KEYATTR_EXTRACTABLE);
394 if(crtn) {
395 APP_FREE(pubKey);
396 APP_FREE(privKey);
397 return paramErr;
398 }
399 if(verbose) {
400 printf("...%u bit key pair generated.\n",
401 (unsigned)keySizeInBits);
402 }
403
404 #if MUNGE_LABEL_ATTR
405 /* bind private key to cert by public key hash */
406 crtn = setPubKeyHash(cspHand,
407 dlDbHand,
408 keyLabel);
409 if(crtn) {
410 printError("***Error setting public key hash. Continuing at peril.",
411 "setPubKeyHash", crtn);
412 }
413 #endif /* MUNGE_LABEL_ATTR */
414
415 *pubKeyPtr = pubKey;
416 *privKeyPtr = privKey;
417 return noErr;
418 }
419
420 static OSStatus verifyCsr(
421 CSSM_CL_HANDLE clHand,
422 const char *fileName,
423 CSSM_BOOL pemFormat)
424 {
425 unsigned char *csr = NULL;
426 unsigned csrLen;
427 CSSM_DATA csrData;
428 unsigned char *der = NULL;
429 unsigned derLen = 0;
430
431 if(readFile(fileName, &csr, &csrLen)) {
432 printf("***Error reading CSR from file %s. Aborting.\n",
433 fileName);
434 return ioErr;
435 }
436 if(pemFormat) {
437 int rtn = pemDecode(csr, csrLen, &der, &derLen);
438 if(rtn) {
439 printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
440 return ioErr;
441 }
442 csrData.Data = der;
443 csrData.Length = derLen;
444 }
445 else {
446 csrData.Data = csr;
447 csrData.Length = csrLen;
448 }
449
450 CSSM_RETURN crtn = CSSM_CL_PassThrough(clHand,
451 0, // CCHandle
452 CSSM_APPLEX509CL_VERIFY_CSR,
453 &csrData,
454 NULL);
455 if(crtn) {
456 printError("***Error verifying CSR","Verify CSR",crtn);
457 }
458 else {
459 printf("...CSR verified successfully.\n");
460 }
461 if(der) {
462 free(der);
463 }
464 if(csr) {
465 free(csr);
466 }
467 return crtn;
468 }
469
470 typedef enum {
471 CC_Cert,
472 CC_CRL
473 } CertOrCrl;
474
475 static OSStatus displayCertCRL(
476 const char *fileName,
477 CSSM_BOOL pemFormat,
478 CertOrCrl certOrCrl,
479 CSSM_BOOL verbose)
480 {
481 unsigned char *rawData = NULL;
482 unsigned rawDataSize;
483 unsigned char *derData = NULL;
484 unsigned derDataSize;
485 int rtn;
486
487 rtn = readFile(fileName, &rawData, &rawDataSize);
488 if(rtn) {
489 printf("Error reading %s; aborting.\n", fileName);
490 return ioErr;
491 }
492 if(pemFormat && isPem(rawData, rawDataSize)) {
493 /*
494 * Here we cut the user some slack. See if the thing is actually
495 * PEM encoded and assume DER-encoded if it's not.
496 */
497 rtn = pemDecode(rawData, rawDataSize, &derData, &derDataSize);
498 if(rtn) {
499 printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
500 return ioErr;
501 }
502 rawData = derData;
503 rawDataSize = derDataSize;
504 }
505 if(certOrCrl == CC_Cert) {
506 printCert(rawData, rawDataSize, verbose);
507 }
508 else {
509 printCrl(rawData, rawDataSize, verbose);
510 }
511 if(derData != NULL) {
512 free(derData);
513 }
514 return noErr;
515 }
516
517 static CSSM_RETURN importPrivateKey(
518 CSSM_DL_DB_HANDLE dlDbHand,
519 CSSM_CSP_HANDLE cspHand,
520 const char *privKeyFileName,
521 CSSM_ALGORITHMS keyAlg,
522 CSSM_BOOL pemFormat, // of the file
523 CSSM_KEYBLOB_FORMAT keyFormat) // of the key blob itself, NONE means use
524 // default
525 {
526 unsigned char *derKey = NULL;
527 unsigned derKeyLen;
528 unsigned char *pemKey = NULL;
529 unsigned pemKeyLen;
530 CSSM_KEY wrappedKey;
531 CSSM_KEY unwrappedKey;
532 CSSM_ACCESS_CREDENTIALS creds;
533 CSSM_CC_HANDLE ccHand = 0;
534 CSSM_RETURN crtn;
535 CSSM_DATA labelData;
536 CSSM_KEYHEADER_PTR hdr = &wrappedKey.KeyHeader;
537 CSSM_DATA descData = {0, NULL};
538 CSSM_CSP_HANDLE rawCspHand = 0;
539 const char *privKeyLabel = NULL;
540
541 /*
542 * Validate specified format for clarity
543 */
544 switch(keyAlg) {
545 case CSSM_ALGID_RSA:
546 switch(keyFormat) {
547 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
548 keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; // default
549 break;
550 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
551 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
552 break;
553 default:
554 printf("***RSA Private key must be in PKCS1 or PKCS8 format\n");
555 return CSSMERR_CSSM_INTERNAL_ERROR;
556 }
557 privKeyLabel = "Imported RSA key";
558 break;
559 case CSSM_ALGID_DSA:
560 switch(keyFormat) {
561 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
562 keyFormat = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; // default
563 break;
564 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
565 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
566 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
567 break;
568 default:
569 printf("***DSA Private key must be in openssl, FIPS186, "
570 "or PKCS8 format\n");
571 return CSSMERR_CSSM_INTERNAL_ERROR;
572 }
573 privKeyLabel = "Imported DSA key";
574 break;
575 case CSSM_ALGID_DH:
576 switch(keyFormat) {
577 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
578 keyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; // default
579 break;
580 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
581 break;
582 default:
583 printf("***Diffie-Hellman Private key must be in PKCS8 format.\n");
584 return CSSMERR_CSSM_INTERNAL_ERROR;
585 }
586 privKeyLabel = "Imported Diffie-Hellman key";
587 break;
588 }
589 if(readFile(privKeyFileName, &pemKey, &pemKeyLen)) {
590 printf("***Error reading private key from file %s. Aborting.\n",
591 privKeyFileName);
592 return CSSMERR_CSSM_INTERNAL_ERROR;
593 }
594 /* subsequent errors to done: */
595 if(pemFormat) {
596 int rtn = pemDecode(pemKey, pemKeyLen, &derKey, &derKeyLen);
597 if(rtn) {
598 printf("***%s: Bad PEM formatting. Aborting.\n", privKeyFileName);
599 crtn = CSSMERR_CSP_INVALID_KEY;
600 goto done;
601 }
602 }
603 else {
604 derKey = pemKey;
605 derKeyLen = pemKeyLen;
606 }
607
608 /* importing a raw key into the CSPDL involves a NULL unwrap */
609 memset(&unwrappedKey, 0, sizeof(CSSM_KEY));
610 memset(&wrappedKey, 0, sizeof(CSSM_KEY));
611
612 /* set up the imported key to look like a CSSM_KEY */
613 hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
614 hdr->BlobType = CSSM_KEYBLOB_RAW;
615 hdr->AlgorithmId = keyAlg;
616 hdr->KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
617 hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
618 hdr->KeyUsage = CSSM_KEYUSE_ANY;
619 hdr->Format = keyFormat;
620 wrappedKey.KeyData.Data = derKey;
621 wrappedKey.KeyData.Length = derKeyLen;
622
623 /* get key size in bits from raw CSP */
624 rawCspHand = cuCspStartup(CSSM_TRUE);
625 if(rawCspHand == 0) {
626 printf("***Error attaching to CSP. Aborting.\n");
627 crtn = CSSMERR_CSSM_INTERNAL_ERROR;
628 goto done;
629 }
630 CSSM_KEY_SIZE keySize;
631 crtn = CSSM_QueryKeySizeInBits(rawCspHand, NULL, &wrappedKey, &keySize);
632 if(crtn) {
633 printError("***Error finding size of key","CSSM_QueryKeySizeInBits",crtn);
634 goto done;
635 }
636 hdr->LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
637
638 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
639 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
640 CSSM_ALGID_NONE, // unwrapAlg
641 CSSM_ALGMODE_NONE, // unwrapMode
642 &creds,
643 NULL, // unwrappingKey
644 NULL, // initVector
645 CSSM_PADDING_NONE, // unwrapPad
646 0, // Params
647 &ccHand);
648 if(crtn) {
649 printError("***Error creating context","CSSM_CSP_CreateSymmetricContext",crtn);
650 goto done;
651 }
652
653 /* add DL/DB to context */
654 CSSM_CONTEXT_ATTRIBUTE newAttr;
655 newAttr.AttributeType = CSSM_ATTRIBUTE_DL_DB_HANDLE;
656 newAttr.AttributeLength = sizeof(CSSM_DL_DB_HANDLE);
657 newAttr.Attribute.Data = (CSSM_DATA_PTR)&dlDbHand;
658 crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr);
659 if(crtn) {
660 printError("***Error updating context attributes","CSSM_UpdateContextAttributes",crtn);
661 goto done;
662 }
663
664 /* do the NULL unwrap */
665 labelData.Data = (uint8 *)privKeyLabel;
666 labelData.Length = strlen(privKeyLabel) + 1;
667 crtn = CSSM_UnwrapKey(ccHand,
668 NULL, // PublicKey
669 &wrappedKey,
670 CSSM_KEYUSE_ANY,
671 CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE |
672 CSSM_KEYATTR_EXTRACTABLE,
673 &labelData,
674 NULL, // CredAndAclEntry
675 &unwrappedKey,
676 &descData); // required
677 if(crtn != CSSM_OK) {
678 cuPrintError("CSSM_UnwrapKey", crtn);
679 goto done;
680 }
681
682 /* one more thing: bind this private key to its public key */
683 crtn = setPubKeyHash(cspHand, dlDbHand, privKeyLabel);
684
685 /* We don't need the unwrapped key any more */
686 CSSM_FreeKey(cspHand,
687 NULL, // access cred
688 &unwrappedKey,
689 CSSM_FALSE); // delete
690
691 done:
692 if(ccHand) {
693 CSSM_DeleteContext(ccHand);
694 }
695 if(derKey) {
696 free(derKey);
697 }
698 if(pemFormat && pemKey) {
699 free(pemKey);
700 }
701 if(rawCspHand) {
702 CSSM_ModuleDetach(rawCspHand);
703 }
704 return crtn;
705 }
706
707 static OSStatus importCert(
708 SecKeychainRef kcRef,
709 CSSM_DL_DB_HANDLE dlDbHand,
710 CSSM_CSP_HANDLE cspHand,
711 CSSM_CL_HANDLE clHand,
712 const char *fileName,
713 const char *privKeyFileName, // optional for importing priv key
714 CSSM_BOOL pemFormat, // format of files
715 CSSM_KEYBLOB_FORMAT privKeyFormat) // optional format of priv key
716 {
717 unsigned char *cert = NULL;
718 unsigned certLen;
719 CSSM_DATA certData;
720 unsigned char *der = NULL;
721 unsigned derLen = 0;
722
723 if(readFile(fileName, &cert, &certLen)) {
724 printf("***Error reading certificate from file %s. Aborting.\n",
725 fileName);
726 return ioErr;
727 }
728 if(pemFormat) {
729 int rtn = pemDecode(cert, certLen, &der, &derLen);
730 if(rtn) {
731 printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
732 return ioErr;
733 }
734 certData.Data = der;
735 certData.Length = derLen;
736 }
737 else {
738 certData.Data = cert;
739 certData.Length = certLen;
740 }
741
742 SecCertificateRef certRef;
743 OSStatus ortn = SecCertificateCreateFromData(
744 &certData,
745 CSSM_CERT_X_509v3,
746 CSSM_CERT_ENCODING_DER,
747 &certRef);
748 if(ortn) {
749 printError("***Error creating certificate","SecCertificateCreateFromData",ortn);
750 cuPrintError("", ortn);
751 return ortn;
752 }
753 ortn = SecCertificateAddToKeychain(certRef, kcRef);
754 if(ortn) {
755 printError("***Error adding certificate to keychain","SecCertificateAddToKeychain",ortn);
756 return ortn;
757 }
758
759 if(privKeyFileName) {
760 /* Importing private key requires algorithm, from cert */
761 CSSM_RETURN crtn;
762 CSSM_KEY_PTR pubKey;
763 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey);
764 if(crtn) {
765 printError("***Error obtaining public key from cert. Aborting","CSSM_CL_CertGetKeyInfo",crtn);
766 return crtn;
767 }
768 crtn = importPrivateKey(dlDbHand, cspHand, privKeyFileName,
769 pubKey->KeyHeader.AlgorithmId, pemFormat, privKeyFormat);
770 if(crtn) {
771 printError("***Error importing private key. Aborting","importPrivateKey",crtn);
772 return crtn;
773 }
774 /* this was mallocd by the CL */
775 cuAppFree(pubKey->KeyData.Data, NULL);
776 cuAppFree(pubKey, NULL);
777 }
778 printf("...certificate successfully imported.\n");
779 if(der) {
780 free(der);
781 }
782 if(cert) {
783 free(cert);
784 }
785 return noErr;
786 }
787
788 static OSStatus importCRL(
789 CSSM_DL_DB_HANDLE dlDbHand,
790 CSSM_CL_HANDLE clHand,
791 const char *fileName,
792 CSSM_BOOL pemFormat)
793 {
794 unsigned char *crl = NULL;
795 unsigned crlLen;
796 CSSM_DATA crlData;
797 unsigned char *der = NULL;
798 unsigned derLen = 0;
799
800 if(readFile(fileName, &crl, &crlLen)) {
801 printf("***Error reading CRL from file %s. Aborting.\n",
802 fileName);
803 return ioErr;
804 }
805 if(pemFormat) {
806 int rtn = pemDecode(crl, crlLen, &der, &derLen);
807 if(rtn) {
808 printf("***%s: Bad PEM formatting. Aborting.\n", fileName);
809 return ioErr;
810 }
811 crlData.Data = der;
812 crlData.Length = derLen;
813 }
814 else {
815 crlData.Data = crl;
816 crlData.Length = crlLen;
817 }
818 CSSM_RETURN crtn = cuAddCrlToDb(dlDbHand, clHand, &crlData, NULL);
819 if(crtn) {
820 printError("***Error adding CRL to keychain. Aborting","cuAddCrlToDb",crtn);
821 }
822 else {
823 printf("...CRL successfully imported.\n");
824 }
825 if(der) {
826 free(der);
827 }
828 if(crl) {
829 free(crl);
830 }
831 return noErr;
832 }
833
834 static OSStatus createCertCsr(
835 CSSM_BOOL createCsr, // true: CSR, false: Cert
836 CSSM_TP_HANDLE tpHand, // eventually, a SecKeychainRef
837 CSSM_CL_HANDLE clHand,
838 CSSM_CSP_HANDLE cspHand,
839 CSSM_KEY_PTR subjPubKey,
840 CSSM_KEY_PTR signerPrivKey,
841 CSSM_ALGORITHMS sigAlg,
842 const CSSM_OID *sigOid,
843 CU_KeyUsage keyUsage, // kKeyUseSigning, etc.
844 /*
845 * Issuer's RDN is obtained from the issuer cert, if present, or is
846 * assumed to be the same as the subject name (i.e., we're creating
847 * a self-signed root cert).
848 */
849 const CSSM_DATA *issuerCert,
850 CSSM_BOOL useAllDefaults,
851 CSSM_DATA_PTR certData) // cert or CSR: mallocd and RETURNED
852 {
853 CE_DataAndType exts[2];
854 CE_DataAndType *extp = exts;
855 unsigned numExts;
856
857 CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest
858 CSSM_APPLE_TP_CERT_REQUEST certReq;
859 CSSM_TP_REQUEST_SET reqSet;
860 sint32 estTime;
861 CSSM_BOOL confirmRequired;
862 CSSM_TP_RESULT_SET_PTR resultSet;
863 CSSM_ENCODED_CERT *encCert;
864 CSSM_APPLE_TP_NAME_OID subjectNames[MAX_NAMES];
865 uint32 numNames;
866 CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext;
867 CSSM_FIELD policyId;
868
869 /* Note a lot of the CSSM_APPLE_TP_CERT_REQUEST fields are not
870 * used for the createCsr option, but we'll fill in as much as is practical
871 * for either case.
872 */
873 if(issuerCert != NULL) {
874 printf("createCertCsr: issuerCert not implemented\n");
875 return unimpErr;
876 }
877
878 numExts = 0;
879
880 char challengeBuf[400];
881 if(createCsr) {
882 if(useAllDefaults) {
883 strcpy(challengeBuf, ZDEF_CHALLENGE);
884 }
885 else {
886 while(1) {
887 getStringWithPrompt("Enter challenge string: ",
888 challengeBuf, sizeof(challengeBuf));
889 if(challengeBuf[0] != '\0') {
890 break;
891 }
892 }
893 }
894 certReq.challengeString = challengeBuf;
895 }
896 else {
897 /* creating cert */
898 certReq.challengeString = NULL;
899
900 /* KeyUsage extension */
901 extp->type = DT_KeyUsage;
902 extp->critical = CSSM_FALSE;
903 extp->extension.keyUsage = 0;
904 if(keyUsage & kKeyUseSigning) {
905 extp->extension.keyUsage |=
906 (CE_KU_DigitalSignature | CE_KU_KeyCertSign);
907 }
908 if(keyUsage & kKeyUseEncrypting) {
909 extp->extension.keyUsage |=
910 (CE_KU_KeyEncipherment | CE_KU_DataEncipherment);
911 }
912 extp++;
913 numExts++;
914
915 /* BasicConstraints */
916 extp->type = DT_BasicConstraints;
917 extp->critical = CSSM_TRUE;
918 extp->extension.basicConstraints.cA = CSSM_TRUE;
919 extp->extension.basicConstraints.pathLenConstraintPresent = CSSM_FALSE;
920 extp++;
921 numExts++;
922 }
923
924 /* name array, get from user. */
925 if(useAllDefaults) {
926 subjectNames[0].string = ZDEF_COMMON_NAME;
927 subjectNames[0].oid = &CSSMOID_CommonName;
928 subjectNames[1].string = ZDEF_ORG_NAME;
929 subjectNames[1].oid = &CSSMOID_OrganizationName;
930 subjectNames[2].string = ZDEF_COUNTRY;
931 subjectNames[2].oid = &CSSMOID_CountryName;
932 subjectNames[3].string = ZDEF_STATE;
933 subjectNames[3].oid = &CSSMOID_StateProvinceName;
934 numNames = 4;
935 }
936 else {
937 getNameOids(subjectNames, &numNames);
938 }
939
940 /* certReq */
941 certReq.cspHand = cspHand;
942 certReq.clHand = clHand;
943 certReq.serialNumber = 0x12345678; // TBD - random? From user?
944 certReq.numSubjectNames = numNames;
945 certReq.subjectNames = subjectNames;
946
947 /* TBD - if we're passed in a signing cert, certReq.issuerNameX509 will
948 * be obtained from that cert. For now we specify "self-signed" cert
949 * by not providing an issuer name at all. */
950 certReq.numIssuerNames = 0; // root for now
951 certReq.issuerNames = NULL;
952 certReq.issuerNameX509 = NULL;
953 certReq.certPublicKey = subjPubKey;
954 certReq.issuerPrivateKey = signerPrivKey;
955 certReq.signatureAlg = sigAlg;
956 certReq.signatureOid = *sigOid;
957 certReq.notBefore = 0; // TBD - from user
958 certReq.notAfter = 60 * 60 * 24 * 30; // seconds from now
959 certReq.numExtensions = numExts;
960 certReq.extensions = exts;
961
962 reqSet.NumberOfRequests = 1;
963 reqSet.Requests = &certReq;
964
965 /* a CSSM_TP_CALLERAUTH_CONTEXT to specify an OID */
966 memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
967 memset(&policyId, 0, sizeof(CSSM_FIELD));
968 if(createCsr) {
969 policyId.FieldOid = CSSMOID_APPLE_TP_CSR_GEN;
970 }
971 else {
972 policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN;
973 }
974 CallerAuthContext.Policy.NumberOfPolicyIds = 1;
975 CallerAuthContext.Policy.PolicyIds = &policyId;
976
977 #if SEC_KEY_CREATE_PAIR
978 /* from SUJag */
979 CssmClient::AclFactory factory;
980 CallerAuthContext.CallerCredentials =
981 const_cast<Security::AccessCredentials *>(factory.promptCred());
982 #endif /* SEC_KEY_CREATE_PAIR */
983
984 CSSM_RETURN crtn = CSSM_TP_SubmitCredRequest(tpHand,
985 NULL, // PreferredAuthority
986 CSSM_TP_AUTHORITY_REQUEST_CERTISSUE,
987 &reqSet,
988 &CallerAuthContext,
989 &estTime,
990 &refId);
991
992 /* before proceeding, free resources allocated thus far */
993 if(!useAllDefaults) {
994 freeNameOids(subjectNames, numNames);
995 }
996
997 if(crtn) {
998 printError("***Error submitting credential request","CSSM_TP_SubmitCredRequest",crtn);
999 return crtn;
1000 }
1001 crtn = CSSM_TP_RetrieveCredResult(tpHand,
1002 &refId,
1003 NULL, // CallerAuthCredentials
1004 &estTime,
1005 &confirmRequired,
1006 &resultSet);
1007 if(crtn) {
1008 printError("***Error retreiving credential request","CSSM_TP_RetrieveCredResult",crtn);
1009 return crtn;
1010 }
1011 if(resultSet == NULL) {
1012 printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n");
1013 return ioErr;
1014 }
1015 encCert = (CSSM_ENCODED_CERT *)resultSet->Results;
1016 *certData = encCert->CertBlob;
1017
1018 /* free resources allocated by TP */
1019 APP_FREE(refId.Data);
1020 APP_FREE(encCert);
1021 APP_FREE(resultSet);
1022 return noErr;
1023 }
1024
1025 /* dump all certs & CRLs in a DL/DB */
1026 static OSStatus dumpCrlsCerts(
1027 CSSM_DL_DB_HANDLE dlDbHand,
1028 CSSM_CL_HANDLE clHand,
1029 CSSM_BOOL verbose)
1030 {
1031 CSSM_RETURN crtn;
1032 unsigned numItems;
1033
1034 crtn = cuDumpCrlsCerts(dlDbHand, clHand, CSSM_TRUE, numItems, verbose);
1035 if(crtn && (crtn != CSSMERR_DL_INVALID_RECORDTYPE)) {
1036 /* invalid record type just means "this hasn't been set up
1037 * for certs yet". */
1038 return noErr;
1039 }
1040 printf("...%u certificates found\n", numItems);
1041 crtn = cuDumpCrlsCerts(dlDbHand, clHand, CSSM_FALSE, numItems, verbose);
1042 if(crtn && (crtn != CSSMERR_DL_INVALID_RECORDTYPE)) {
1043 /* invalid record type just means "this hasn't been set up
1044 * for CRLs yet". */
1045 return noErr;
1046 }
1047 printf("...%u CRLs found\n", numItems);
1048 return noErr;
1049 }
1050
1051
1052 typedef enum {
1053 CO_Nop,
1054 CO_CreateCert,
1055 CO_CreateCSR,
1056 CO_VerifyCSR,
1057 CO_ImportCert,
1058 CO_DisplayCert,
1059 CO_ImportCRL,
1060 CO_DisplayCRL,
1061 CO_DumpDb // display certs & CRLs from a DB
1062 } CertOp;
1063
1064 int realmain (int argc, char **argv)
1065 {
1066 SecKeychainRef kcRef = nil;
1067 char kcPath[MAXPATHLEN + 1];
1068 UInt32 kcPathLen = MAXPATHLEN + 1;
1069 CSSM_BOOL createKc = CSSM_FALSE;
1070 OSStatus ortn;
1071 CSSM_DL_DB_HANDLE dlDbHand = {0, 0};
1072 CSSM_CSP_HANDLE cspHand = 0;
1073 CSSM_TP_HANDLE tpHand = 0;
1074 CSSM_CL_HANDLE clHand = 0;
1075 CSSM_KEY_PTR pubKey;
1076 CSSM_KEY_PTR privKey;
1077 int arg;
1078 char *argp;
1079 CSSM_ALGORITHMS keyAlg;
1080 CSSM_ALGORITHMS sigAlg;
1081 const CSSM_OID *sigOid;
1082 CSSM_DATA certData = {0, NULL};
1083 CSSM_RETURN crtn;
1084 CU_KeyUsage keyUsage = 0;
1085 bool isRoot;
1086 CSSM_DATA keyLabel;
1087 CSSM_BOOL createCsr = CSSM_FALSE; // else create cert
1088 int optArgs = 0;
1089 UInt32 pwdLen = 0;
1090 Boolean promptUser = true;
1091 char *allocdPassPhrase = NULL;
1092 OSStatus ourRtn = noErr;
1093
1094 /* command line arguments */
1095 char *fileName = NULL;
1096 CSSM_BOOL pemFormat = CSSM_TRUE;
1097 CertOp op = CO_Nop;
1098 uint32 keySizeInBits;
1099 char *kcName = NULL;
1100 CSSM_BOOL useAllDefaults = CSSM_FALSE; // undoc'd cmd option
1101 char *passPhrase = NULL;
1102 const char *privKeyFileName = NULL; // optional openssl-style private key
1103 CSSM_KEYBLOB_FORMAT privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_NONE;
1104 #if SEC_KEY_CREATE_PAIR
1105 SecKeyRef pubSecKey = NULL;
1106 SecKeyRef privSecKey = NULL;
1107 #endif
1108 CSSM_BOOL useSecKey = CSSM_FALSE; // w/default ACL
1109
1110 if(argc < 2) {
1111 usage(argv);
1112 }
1113 switch(argv[1][0]) {
1114 case 'c':
1115 op = CO_CreateCert;
1116 optArgs = 2;
1117 break;
1118 case 'r':
1119 if(argc < 3) {
1120 usage(argv);
1121 }
1122 op = CO_CreateCSR;
1123 createCsr = CSSM_TRUE;
1124 fileName = argv[2];
1125 optArgs = 3;
1126 break;
1127 case 'v':
1128 if(argc < 3) {
1129 usage(argv);
1130 }
1131 op = CO_VerifyCSR;
1132 fileName = argv[2];
1133 optArgs = 3;
1134 break;
1135 case 'i':
1136 if(argc < 3) {
1137 usage(argv);
1138 }
1139 optArgs = 3;
1140 op = CO_ImportCert;
1141 fileName = argv[2];
1142 break;
1143 case 'd':
1144 if(argc < 3) {
1145 usage(argv);
1146 }
1147 op = CO_DisplayCert;
1148 fileName = argv[2];
1149 optArgs = 3;
1150 break;
1151 case 'I':
1152 if(argc < 3) {
1153 usage(argv);
1154 }
1155 optArgs = 3;
1156 op = CO_ImportCRL;
1157 fileName = argv[2];
1158 break;
1159 case 'D':
1160 if(argc < 3) {
1161 usage(argv);
1162 }
1163 op = CO_DisplayCRL;
1164 fileName = argv[2];
1165 optArgs = 3;
1166 break;
1167 case 'y':
1168 op = CO_DumpDb;
1169 optArgs = 2;
1170 break;
1171 default:
1172 usage(argv);
1173 }
1174 for(arg=optArgs; arg<argc; arg++) {
1175 argp = argv[arg];
1176 switch(argp[0]) {
1177 case 'k':
1178 if(argp[1] != '=') {
1179 usage(argv);
1180 }
1181 kcName = &argp[2];
1182 break;
1183 case 'v':
1184 verbose = CSSM_TRUE;
1185 break;
1186 case 'd':
1187 pemFormat = CSSM_FALSE;
1188 break;
1189 case 'c':
1190 createKc = CSSM_TRUE;
1191 break;
1192 case 'p':
1193 if(argp[1] != '=') {
1194 usage(argv);
1195 }
1196 passPhrase = &argp[2];
1197 break;
1198 case 'o':
1199 if((op != CO_CreateCert) || (argp[1] != '=')){
1200 usage(argv);
1201 }
1202 fileName = &argp[2];
1203 break;
1204 case 'r':
1205 privKeyFileName = &argp[2];
1206 break;
1207 case 'f':
1208 if(argp[1] != '=') {
1209 usage(argv);
1210 }
1211 switch(argp[2]) {
1212 case '1':
1213 privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
1214 break;
1215 case '8':
1216 privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
1217 break;
1218 case 'f':
1219 privKeyFormat = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
1220 break;
1221 default:usage(argv);
1222 }
1223 break;
1224 case 'Z':
1225 /* undocumented "use all defaults quickly" option */
1226 useAllDefaults = CSSM_TRUE;
1227 break;
1228 #if SEC_KEY_CREATE_PAIR
1229 case 'a':
1230 useSecKey = CSSM_TRUE;
1231 break;
1232 #endif
1233 default:
1234 usage(argv);
1235 }
1236 }
1237 if((passPhrase != NULL) && !createKc) {
1238 printf("***passphrase specification only allowed on keychain create. Aborting.\n");
1239 exit(1);
1240 }
1241 switch(op) {
1242 case CO_DisplayCert:
1243 /* ready to roll */
1244 displayCertCRL(fileName, pemFormat, CC_Cert, verbose);
1245 return 0;
1246 case CO_DisplayCRL:
1247 displayCertCRL(fileName, pemFormat, CC_CRL, verbose);
1248 return 0;
1249 default:
1250 /* proceed */
1251 break;
1252 }
1253
1254 clHand = cuClStartup();
1255 if(clHand == 0) {
1256 printf("Error connecting to CL. Aborting.\n");
1257 exit(1);
1258 }
1259
1260 /* that's all we need for verifying a CSR */
1261 if(op == CO_VerifyCSR) {
1262 ourRtn = verifyCsr(clHand, fileName, pemFormat);
1263 goto abort;
1264 }
1265
1266 if(kcName) {
1267 if(kcName[0] == '/') {
1268 /* specific keychain not in Library/Keychains */
1269 strcpy(kcPath, kcName);
1270 }
1271 else {
1272 char *userHome = getenv("HOME");
1273
1274 if(userHome == NULL) {
1275 /* well, this is probably not going to work */
1276 userHome = "";
1277 }
1278 sprintf(kcPath, "%s/%s/%s", userHome, KC_DB_PATH, kcName);
1279 }
1280 }
1281 else {
1282 /* use default keychain */
1283 ortn = SecKeychainCopyDefault(&kcRef);
1284 if(ortn) {
1285 printError("***Error retreiving default keychain","SecKeychainCopyDefault",ortn);
1286 exit(1);
1287 }
1288 ortn = SecKeychainGetPath(kcRef, &kcPathLen, kcPath);
1289 if(ortn) {
1290 printError("***Error retreiving default keychain path","SecKeychainGetPath",ortn);
1291 exit(1);
1292 }
1293
1294 /*
1295 * OK, we have a path, we have to release the first KC ref,
1296 * then get another one by opening it
1297 */
1298 CFRelease(kcRef);
1299 }
1300
1301 if(passPhrase != NULL) {
1302 pwdLen = strlen(passPhrase);
1303 /* work around bug - incoming passphrase gets freed */
1304 Security::CssmAllocator &alloc = Security::CssmAllocator::standard();
1305 allocdPassPhrase = (char *)alloc.malloc(pwdLen);
1306 memmove(allocdPassPhrase, passPhrase, pwdLen);
1307 promptUser = false;
1308 }
1309 if(createKc) {
1310 ortn = SecKeychainCreate(kcPath,
1311 pwdLen,
1312 allocdPassPhrase,
1313 promptUser,
1314 nil, // initialAccess
1315 &kcRef);
1316 /* fixme - do we have to open it? */
1317 if(ortn) {
1318 printError("***Error creating keychain","SecKeychainCreate",ortn);
1319 printf("***Path: %s\n", kcPath);
1320 exit(1);
1321 }
1322 }
1323 else {
1324 ortn = SecKeychainOpen(kcPath, &kcRef);
1325 if(ortn) {
1326 printError("***Error opening keychain. Aborting","SecKeychainOpen",ortn);
1327 printf("***Path: %s\n", kcPath);
1328 exit(1);
1329 }
1330 }
1331
1332 /* get associated DL/DB handle */
1333 ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand);
1334 if(ortn) {
1335 printError("***Error getting keychain handle","SecKeychainGetDLDBHandle",ortn);
1336 exit(1);
1337 }
1338
1339 #if SEC_KEYCHAIN_GET_CSP
1340 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
1341 if(ortn) {
1342 printError("***Error getting keychain CSP handle","SecKeychainGetCSPHandle",ortn);
1343 exit(1);
1344 }
1345 #else
1346 cspHand = cuCspStartup(CSSM_FALSE);
1347 if(cspHand == 0) {
1348 printf("Error connecting to CSP/DL. Aborting.\n");
1349 exit(1);
1350 }
1351 #endif /* SEC_KEYCHAIN_GET_CSP */
1352
1353 switch(op) {
1354 case CO_ImportCert:
1355 ourRtn = importCert(kcRef, dlDbHand, cspHand, clHand, fileName, privKeyFileName,
1356 pemFormat, privKeyFormat);
1357 goto abort;
1358 case CO_ImportCRL:
1359 ourRtn = importCRL(dlDbHand, clHand, fileName, pemFormat);
1360 goto abort;
1361 case CO_DumpDb:
1362 ourRtn = dumpCrlsCerts(dlDbHand, clHand, verbose);
1363 goto abort;
1364 default:
1365 break;
1366 }
1367
1368 /* remaining ops need TP as well */
1369 tpHand = cuTpStartup();
1370 if(tpHand == 0) {
1371 printf("Error connecting to TP. Aborting.\n");
1372 exit(1);
1373 }
1374
1375 /*** op = CO_CreateCert or CO_CreateCSR ***/
1376
1377 /*
1378 * TBD: eventually we want to present the option of using an existing
1379 * SecIdentityRef from the keychain as the signing cert/key. If none
1380 * found or the user says they want a root, we generate the signing key
1381 * pair as follows....
1382 */
1383 isRoot = true;
1384
1385 /*
1386 * Generate a key pair. For now we do this via CDSA.
1387 */
1388 char labelBuf[200];
1389 if(useAllDefaults) {
1390 strcpy(labelBuf, ZDEF_KEY_LABEL);
1391 }
1392 else {
1393 while(1) {
1394 getStringWithPrompt("Enter key and certificate label: ", labelBuf,
1395 sizeof(labelBuf));
1396 if(labelBuf[0] != '\0') {
1397 break;
1398 }
1399 }
1400 }
1401 keyLabel.Data = (uint8 *)labelBuf;
1402 keyLabel.Length = strlen(labelBuf);
1403
1404 /* get key algorithm and size */
1405 if(useAllDefaults) {
1406 keyAlg = ZDEF_KEY_ALG;
1407 keySizeInBits = ZDEF_KEY_SIZE;
1408 }
1409 else {
1410 getKeyParams(keyAlg, keySizeInBits);
1411 }
1412
1413 /* get usage for keys and certs */
1414 if(useAllDefaults) {
1415 keyUsage = ZDEF_KEY_USAGE;
1416 }
1417 else {
1418 keyUsage = getKeyUsage(isRoot);
1419 }
1420
1421 printf("...Generating key pair...\n");
1422
1423 if(useSecKey) {
1424 /* generate keys using SecKeyCreatePair */
1425 #if SEC_KEY_CREATE_PAIR
1426 ourRtn = generateSecKeyPair(kcRef,
1427 keyAlg,
1428 keySizeInBits,
1429 keyUsage,
1430 verbose,
1431 &pubKey,
1432 &privKey,
1433 &pubSecKey,
1434 &privSecKey);
1435 #else
1436 /* can't happen, useSecKey must be false */
1437 #endif
1438 }
1439 else {
1440 /* generate keys using CSPDL */
1441 ourRtn = generateKeyPair(cspHand,
1442 dlDbHand,
1443 keyAlg,
1444 keySizeInBits,
1445 labelBuf,
1446 keyUsage,
1447 verbose,
1448 &pubKey,
1449 &privKey);
1450 }
1451 if(ourRtn) {
1452 printError("Error generating keys; aborting","generateKeyPair",ourRtn);
1453 goto abort;
1454 }
1455
1456 /* get signing algorithm per the signing key */
1457 if(useAllDefaults) {
1458 sigAlg = ZDEF_SIG_ALG;
1459 sigOid = &ZDEF_SIG_OID;
1460 }
1461 else {
1462 ourRtn = getSigAlg(privKey, sigAlg, sigOid);
1463 if(ourRtn) {
1464 printError("Cannot sign with this private key. Aborting","getSigAlg",ourRtn);
1465 goto abort;
1466 }
1467 }
1468
1469 if(createCsr) {
1470 printf("...creating CSR...\n");
1471 }
1472 else {
1473 printf("...creating certificate...\n");
1474 }
1475 /* generate the cert */
1476 ourRtn = createCertCsr(createCsr,
1477 tpHand,
1478 clHand,
1479 cspHand,
1480 pubKey,
1481 privKey,
1482 sigAlg,
1483 sigOid,
1484 keyUsage,
1485 NULL, // issuer cert
1486 useAllDefaults,
1487 &certData);
1488 if(ourRtn) {
1489 goto abort;
1490 }
1491 if(verbose) {
1492 printCert(certData.Data, certData.Length, CSSM_FALSE);
1493 printCertShutdown();
1494 }
1495
1496 if(fileName) {
1497 /*
1498 * Create CSR, or create cert with outFileName option.
1499 * Write results to a file
1500 */
1501 unsigned char *pem = NULL;
1502 unsigned pemLen;
1503 int rtn;
1504
1505 if(pemFormat) {
1506 char *headerStr;
1507 switch(op) {
1508 case CO_CreateCSR:
1509 headerStr = "CERTIFICATE REQUEST";
1510 break;
1511 case CO_CreateCert:
1512 headerStr = "CERTIFICATE";
1513 break;
1514 default:
1515 printf("***INTERNAL ERROR; aborting.\n");
1516 exit(1);
1517 }
1518 rtn = pemEncode(certData.Data, certData.Length, &pem, &pemLen, headerStr);
1519 if(rtn) {
1520 /* very unlikely, I think malloc is the only failure */
1521 printf("***Error PEM-encoding output. Aborting.\n");
1522 goto abort;
1523 }
1524 rtn = writeFile(fileName, pem, pemLen);
1525 }
1526 else {
1527 rtn = writeFile(fileName, certData.Data, certData.Length);
1528 }
1529 if(rtn) {
1530 printf("***Error writing CSR to %s\n", fileName);
1531 ourRtn = ioErr;
1532 }
1533 else {
1534 printf("Wrote %u bytes of CSR to %s\n", (unsigned)certData.Length,
1535 fileName);
1536 }
1537 if(pem) {
1538 free(pem);
1539 }
1540 }
1541 if(op == CO_CreateCert) {
1542 /* store the cert in the same DL/DB as the key pair */
1543 crtn = cuAddCertToKC(kcRef,
1544 &certData,
1545 CSSM_CERT_X_509v3,
1546 CSSM_CERT_ENCODING_DER,
1547 labelBuf, // printName
1548 &keyLabel);
1549 if(crtn == CSSM_OK) {
1550 printf("..cert stored in Keychain.\n");
1551 }
1552 else {
1553 printError("Cannot store certificate","cuAddCertToKC",crtn);
1554 ourRtn = crtn;
1555 }
1556 }
1557 abort:
1558 /* CLEANUP */
1559 #if SEC_KEY_CREATE_PAIR
1560 if(pubSecKey != NULL) {
1561 CFRelease(pubSecKey);
1562 }
1563 if(privSecKey != NULL) {
1564 CFRelease(privSecKey);
1565 }
1566 #endif
1567 return ourRtn;
1568 }
1569
1570 int main (int argc, char **argv)
1571 {
1572 try {
1573 return realmain (argc, argv);
1574 }
1575 catch (AbortException e)
1576 {
1577 putchar ('\n'); // prompt on the next line.
1578 return 1;
1579 }
1580 }
1581