]> git.saurik.com Git - apple/security.git/blame - SecurityTests/cspxutils/pubKeyTool/pubKeyTool.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / pubKeyTool / pubKeyTool.cpp
CommitLineData
d8f41ccd
A
1/*
2 * pubKeyTool.cpp - calculate public key hash of arbitrary keys and certs; derive
3 * public key from a private key or a cert.
4 */
5
6#include <stdlib.h>
7#include <strings.h>
8#include <stdio.h>
9#include <unistd.h>
10#include <Security/Security.h>
11#include <security_cdsa_utils/cuFileIo.h>
12#include <security_cdsa_utils/cuCdsaUtils.h>
13#include "cspwrap.h"
14#include "common.h"
15
16static void usage(char **argv)
17{
18 printf("usage: %s [options]\n", argv[0]);
19 printf("Options:\n");
20 printf(" -k priv_key_file -- private key file to read\n");
21 printf(" -b pub_key_file -- public key file to read\n");
22 printf(" -c cert_file -- cert file to read\n");
23 printf(" -d -- print public key digest\n");
24 printf(" -o out_file -- write public key to out_file\n");
25 printf(" -f pkcs1|pkcs8|x509 -- input key format\n");
26 printf(" -- default is PKCS8 for private key, PKCS1 for"
27 " public\n");
28 printf(" -K keychain -- import pub key to this keychain; workaround "
29 "for Radar 4191851)\n");
30 exit(1);
31}
32
33/* Convert raw key blob into a respectable CSSM_KEY. */
34static CSSM_RETURN inferCssmKey(
35 const CSSM_DATA &keyBlob,
36 bool isPrivKey,
37 CSSM_KEYBLOB_FORMAT keyForm,
38 CSSM_CSP_HANDLE cspHand,
39 CSSM_KEY &outKey)
40{
41 memset(&outKey, 0, sizeof(CSSM_KEY));
42 outKey.KeyData = keyBlob;
43 CSSM_KEYHEADER &hdr = outKey.KeyHeader;
44 hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
45 /* CspId blank */
46 hdr.BlobType = CSSM_KEYBLOB_RAW;
47 hdr.AlgorithmId = CSSM_ALGID_RSA;
48 hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
49 hdr.Format = keyForm;
50 hdr.KeyClass = isPrivKey ? CSSM_KEYCLASS_PRIVATE_KEY : CSSM_KEYCLASS_PUBLIC_KEY;
51 hdr.KeyUsage = CSSM_KEYUSE_ANY;
52 hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
53 hdr.WrapMode = CSSM_ALGMODE_NONE;
54 /*
55 * LogicalKeySizeInBits - ask the CSP
56 */
57 CSSM_KEY_SIZE keySize;
58 CSSM_RETURN crtn;
59 crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, &outKey,
60 &keySize);
61 if(crtn) {
62 cssmPerror("CSSM_QueryKeySizeInBits", crtn);
63 return crtn;
64 }
65 hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits;
66 return CSSM_OK;
67}
68
69/*
70 * Given any key in either blob or reference format,
71 * obtain the associated public key's SHA-1 hash.
72 */
73static CSSM_RETURN keyDigest(
74 CSSM_CSP_HANDLE cspHand,
75 const CSSM_KEY *key,
76 CSSM_DATA_PTR *hashData) /* struct and contents cuAppMalloc'd and RETURNED */
77{
78 CSSM_CC_HANDLE ccHand;
79 CSSM_RETURN crtn;
80 CSSM_DATA_PTR dp;
81
82 *hashData = NULL;
83
84 /* validate input params */
85 if((key == NULL) ||
86 (hashData == NULL)) {
87 printf("keyHash: bogus args\n");
88 return CSSMERR_CSSM_INTERNAL_ERROR;
89 }
90
91 /* cook up a context for a passthrough op */
92 crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
93 key,
94 &ccHand);
95 if(ccHand == 0) {
96 cssmPerror("CSSM_CSP_CreatePassThroughContext", crtn);
97 return crtn;
98 }
99
100 /* now it's up to the CSP */
101 crtn = CSSM_CSP_PassThrough(ccHand,
102 CSSM_APPLECSP_KEYDIGEST,
103 NULL,
104 (void **)&dp);
105 if(crtn) {
106 cssmPerror("CSSM_CSP_PassThrough(KEYDIGEST)", crtn);
107 }
108 else {
109 *hashData = dp;
110 crtn = CSSM_OK;
111 }
112 CSSM_DeleteContext(ccHand);
113 return crtn;
114}
115
116/*
117 * Here's a tricky one. Given a private key, obtain the correspoding public key.
118 * This uses a private key blob format that's used internally in the CSP
119 * to generate key digests.
120 */
121
122/*
123 * this magic const copied from BinaryKey.h
124 */
125#define CSSM_KEYBLOB_RAW_FORMAT_DIGEST \
126 (CSSM_KEYBLOB_RAW_FORMAT_VENDOR_DEFINED + 0x12345)
127
128static CSSM_RETURN pubKeyFromPrivKey(
129 CSSM_CSP_HANDLE cspHand,
130 const CSSM_KEY *privKey, // assumed to be raw format
131 CSSM_KEY *pubKey)
132{
133 /* first convert to reference key */
134 CSSM_KEY refKey;
135 CSSM_RETURN crtn;
136 crtn = cspRawKeyToRef(cspHand, privKey, &refKey);
137 if(crtn) {
138 return crtn;
139 }
140
141 /* now a NULL wrap with the magic format attribute */
142 CSSM_CC_HANDLE ccHand;
143 CSSM_ACCESS_CREDENTIALS creds;
144 CSSM_DATA descData = {0, 0};
145
146 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
147 CSSM_ALGID_NONE,
148 CSSM_ALGMODE_NONE,
149 NULL, // passPhrase,
150 NULL, // key
151 NULL, // initVector,
152 CSSM_PADDING_NONE,
153 NULL, // Reserved
154 &ccHand);
155 if(crtn) {
156 cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn);
157 return crtn;
158 }
159 crtn = AddContextAttribute(ccHand,
160 /*
161 * The output of the WrapKey is a private key as far as the CSP is
162 * concerned, at the level that this attribute is used anyway....
163 */
164 CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
165 sizeof(uint32),
166 CAT_Uint32,
167 NULL,
168 CSSM_KEYBLOB_RAW_FORMAT_DIGEST);
169 if(crtn) {
170 cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn);
171 goto errOut;
172 }
173 memset(pubKey, 0, sizeof(CSSM_KEY));
174 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
175 crtn = CSSM_WrapKey(ccHand,
176 &creds,
177 &refKey,
178 &descData,
179 pubKey);
180 if(crtn) {
181 cssmPerror("CSSM_WrapKey", crtn);
182 goto errOut;
183 }
184
185 /* now: presto chango - don't do this at home! */
186 pubKey->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
187errOut:
188 CSSM_FreeKey(cspHand, NULL, &refKey, CSSM_FALSE);
189 CSSM_DeleteContext(ccHand);
190 return crtn;
191}
192
193/*
194 * Import a key into a DLDB.
195 */
196static CSSM_RETURN importToDlDb(
197 CSSM_CSP_HANDLE cspHand,
198 CSSM_DL_DB_HANDLE_PTR dlDbHand,
199 const CSSM_KEY *rawPubKey,
200 CSSM_DATA_PTR labelData,
201 CSSM_KEY_PTR importedKey)
202{
203 CSSM_CC_HANDLE ccHand = 0;
204 CSSM_RETURN crtn;
205 uint32 keyAttr;
206 CSSM_ACCESS_CREDENTIALS creds;
207 CSSM_CONTEXT_ATTRIBUTE newAttr;
208 CSSM_DATA descData = {0, 0};
209
210 memset(importedKey, 0, sizeof(CSSM_KEY));
211 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
212 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
213 CSSM_ALGID_NONE,
214 CSSM_ALGMODE_NONE,
215 &creds,
216 NULL, // unwrappingKey
217 NULL, // initVector
218 CSSM_PADDING_NONE,
219 0, // Params
220 &ccHand);
221 if(crtn) {
222 cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn);
223 return crtn;
224 }
225 keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT;
226
227 /* Add DLDB to context */
228 newAttr.AttributeType = CSSM_ATTRIBUTE_DL_DB_HANDLE;
229 newAttr.AttributeLength = sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE);
230 newAttr.Attribute.Data = (CSSM_DATA_PTR)dlDbHand;
231 crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr);
232 if(crtn) {
233 cssmPerror("CSSM_UpdateContextAttributes", crtn);
234 goto errOut;
235 }
236
237 /* import */
238 crtn = CSSM_UnwrapKey(ccHand,
239 NULL, // PublicKey
240 rawPubKey,
241 CSSM_KEYUSE_ANY,
242 keyAttr,
243 labelData,
244 NULL, // CredAndAclEntry
245 importedKey,
246 &descData); // required
247 if(crtn) {
248 cssmPerror("CSSM_UnwrapKey", crtn);
249 }
250errOut:
251 if(ccHand) {
252 CSSM_DeleteContext(ccHand);
253 }
254 return crtn;
255}
256
257/*
258 * Free memory via specified plugin's app-level allocator
259 */
260void impExpFreeCssmMemory(
261 CSSM_HANDLE hand,
262 void *p)
263{
264 CSSM_API_MEMORY_FUNCS memFuncs;
265 CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs);
266 if(crtn) {
267 return;
268 }
269 memFuncs.free_func(p, memFuncs.AllocRef);
270}
271
272/*
273 * Key attrribute names and values.
274 *
275 * This is where the public key hash goes.
276 */
277#define SEC_KEY_HASH_ATTR_NAME "Label"
278
279/*
280 * This is where the publicly visible name goes.
281 */
282#define SEC_KEY_PRINT_NAME_ATTR_NAME "PrintName"
283
284/*
285 * Look up public key by label
286 * Set label to new specified label (SHA1 digest)
287 * Set print name to new specified user-visible name
288 */
289static CSSM_RETURN setPubKeyLabel(
290 CSSM_CSP_HANDLE cspHand, // where the key lives
291 CSSM_DL_DB_HANDLE *dlDbHand, // ditto
292 const CSSM_DATA *existKeyLabel, // existing label, a random string, for lookup
293 const CSSM_DATA *keyDigest, // SHA1 digest, the new label
294 const CSSM_DATA *newPrintName) // new user-visible name
295{
296 CSSM_QUERY query;
297 CSSM_SELECTION_PREDICATE predicate;
298 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
299 CSSM_RETURN crtn;
300 CSSM_HANDLE resultHand = 0;
301
302 /*
303 * Look up the key in the DL.
304 */
305 query.RecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
306 query.Conjunctive = CSSM_DB_NONE;
307 query.NumSelectionPredicates = 1;
308 predicate.DbOperator = CSSM_DB_EQUAL;
309
310 predicate.Attribute.Info.AttributeNameFormat =
311 CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
312 predicate.Attribute.Info.Label.AttributeName = (char *)"Label";
313 predicate.Attribute.Info.AttributeFormat =
314 CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
315 /* hope this cast is OK */
316 predicate.Attribute.Value = (CSSM_DATA_PTR)existKeyLabel;
317 query.SelectionPredicate = &predicate;
318
319 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
320 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
321 query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA; // FIXME - used?
322
323 /* build Record attribute with two attrs */
324 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
325 CSSM_DB_ATTRIBUTE_DATA attr[2];
326
327 attr[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
328 attr[0].Info.Label.AttributeName = (char *)SEC_KEY_HASH_ATTR_NAME;
329 attr[0].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
330 attr[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
331 attr[1].Info.Label.AttributeName = (char *)SEC_KEY_PRINT_NAME_ATTR_NAME;
332 attr[1].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
333
334 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
335 recordAttrs.NumberOfAttributes = 2;
336 recordAttrs.AttributeData = attr;
337
338 crtn = CSSM_DL_DataGetFirst(*dlDbHand,
339 &query,
340 &resultHand,
341 &recordAttrs,
342 NULL, // theData
343 &record);
344 /* abort only on success */
345 if(crtn != CSSM_OK) {
346 cssmPerror("CSSM_DL_DataGetFirst", crtn);
347 goto errOut;
348 }
349
350 /*
351 * Update existing attr data.
352 * NOTE: the module which allocated this attribute data - a DL -
353 * was loaded and attached by the keychain layer, not by us. Thus
354 * we can't use the memory allocator functions *we* used when
355 * attaching to the CSP - we have to use the ones
356 * which the client registered with the DL.
357 */
358 impExpFreeCssmMemory(dlDbHand->DLHandle, attr[0].Value->Data);
359 impExpFreeCssmMemory(dlDbHand->DLHandle, attr[0].Value);
360 impExpFreeCssmMemory(dlDbHand->DLHandle, attr[1].Value->Data);
361 impExpFreeCssmMemory(dlDbHand->DLHandle, attr[1].Value);
362 attr[0].Value = const_cast<CSSM_DATA *>(keyDigest);
363 attr[1].Value = const_cast<CSSM_DATA *>(newPrintName);
364
365 crtn = CSSM_DL_DataModify(*dlDbHand,
366 CSSM_DL_DB_RECORD_PUBLIC_KEY,
367 record,
368 &recordAttrs,
369 NULL, // DataToBeModified
370 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
371 if(crtn) {
372 cssmPerror("CSSM_DL_DataModify", crtn);
373 }
374errOut:
375 /* free resources */
376 if(resultHand) {
377 CSSM_DL_DataAbortQuery(*dlDbHand, resultHand);
378 }
379 if(record) {
380 CSSM_DL_FreeUniqueRecord(*dlDbHand, record);
381 }
382 return crtn;
383}
384
385#define SHA1_LABEL_LEN 20
386#define IMPORTED_KEY_NAME "Imported Public Key"
387
388/*
389 * Import a public key into a keychain, with proper Label attribute setting.
390 * A workaround for Radar 4191851.
391 */
392static int pubKeyImport(
393 const char *kcName,
394 const CSSM_KEY *pubKey,
395 CSSM_CSP_HANDLE rawCspHand) /* raw CSP handle for calculating digest */
396{
397 CSSM_CSP_HANDLE cspHand;
398 CSSM_DL_DB_HANDLE dlDbHand;
399 OSStatus ortn;
400 CSSM_RETURN crtn;
401 SecKeychainRef kcRef = NULL;
402 int ourRtn = 0;
403 CSSM_DATA_PTR digest = NULL;
404 CSSM_KEY importedKey;
405 CSSM_DATA newPrintName =
406 { (uint32)strlen(IMPORTED_KEY_NAME), (uint8 *)IMPORTED_KEY_NAME};
407
408 /* NULL unwrap stuff */
409 uint8 tempLabel[SHA1_LABEL_LEN];
410 CSSM_DATA labelData = {SHA1_LABEL_LEN, tempLabel};
411
412 ortn = SecKeychainOpen(kcName, &kcRef);
413 if(ortn) {
414 cssmPerror("SecKeychainOpen", ortn);
415 return -1;
416 }
417 /* subsequent errors to errOut: */
418
419 /* Get CSSM handles */
420 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
421 if(ortn) {
422 cssmPerror("SecKeychainGetCSPHandle", ortn);
423 ourRtn = -1;
424 goto errOut;
425 }
426 ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand);
427 if(ortn) {
428 cssmPerror("SecKeychainGetCSPHandle", ortn);
429 ourRtn = -1;
430 goto errOut;
431 }
432
433 /* public key hash from raw CSP */
434 crtn = keyDigest(rawCspHand, pubKey, &digest);
435 if(crtn) {
436 ourRtn = -1;
437 goto errOut;
438 }
439
440 /* random label for initial storage and later retrieval */
441 appGetRandomBytes(tempLabel, SHA1_LABEL_LEN);
442
443 /* import the key into the keychain's DLDB */
444 memset(&importedKey, 0, sizeof(CSSM_KEY));
445 crtn = importToDlDb(cspHand, &dlDbHand, pubKey, &labelData, &importedKey);
446 if(crtn) {
447 ourRtn = -1;
448 goto errOut;
449 }
450
451 /* don't need this */
452 CSSM_FreeKey(cspHand, NULL, &importedKey, CSSM_FALSE);
453
454 /* update the label and printName attributes */
455 crtn = setPubKeyLabel(cspHand, &dlDbHand, &labelData, digest, &newPrintName);
456 if(crtn) {
457 ourRtn = -1;
458 }
459errOut:
460 CFRelease(kcRef);
461 if(digest) {
462 APP_FREE(digest->Data);
463 APP_FREE(digest);
464 }
465 return ourRtn;
466}
467
468int main(int argc, char **argv)
469{
470 char *privKeyFile = NULL;
471 char *pubKeyFile = NULL;
472 char *certFile = NULL;
473 char *outFile = NULL;
474 bool printDigest = false;
475 CSSM_KEYBLOB_FORMAT keyForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
476 char *kcName = NULL;
477
478 if(argc < 3) {
479 usage(argv);
480 }
481 extern char *optarg;
482 int arg;
483 while ((arg = getopt(argc, argv, "k:b:c:do:f:K:h")) != -1) {
484 switch (arg) {
485 case 'k':
486 privKeyFile = optarg;
487 break;
488 case 'b':
489 pubKeyFile = optarg;
490 break;
491 case 'c':
492 certFile = optarg;
493 break;
494 case 'd':
495 printDigest = true;
496 break;
497 case 'o':
498 outFile = optarg;
499 break;
500 case 'f':
501 if(!strcmp("pkcs1", optarg)) {
502 keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
503 }
504 else if(!strcmp("pkcs8", optarg)) {
505 keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
506 }
507 else if(!strcmp("x509", optarg)) {
508 keyForm = CSSM_KEYBLOB_RAW_FORMAT_X509;
509 }
510 break;
511 case 'K':
512 kcName = optarg;
513 break;
514 case 'h':
515 usage(argv);
516 }
517 }
518 if(optind != argc) {
519 usage(argv);
520 }
521
522 CSSM_DATA privKeyBlob = {0, NULL};
523 CSSM_DATA pubKeyBlob = {0, NULL};
524 CSSM_KEY thePrivKey; // constructed
525 CSSM_KEY thePubKey; // null-wrapped
526 CSSM_KEY_PTR pubKey = NULL;
527 CSSM_KEY_PTR privKey = NULL;
528 CSSM_RETURN crtn;
529 CSSM_CL_HANDLE clHand = 0;
530 CSSM_CSP_HANDLE cspHand = cuCspStartup(CSSM_TRUE);
531
532 /* gather input */
533 if(privKeyFile) {
534 /* key blob from a file ==> a private CSSM_KEY */
535
536 if(pubKeyFile || certFile) {
537 printf("****Specify exactly one of {cert_file, priv_key_file, "
538 "pub_key_file}.\n");
539 exit(1);
540 }
541 unsigned len;
542 if(readFile(privKeyFile, &privKeyBlob.Data, &len)) {
543 printf("***Error reading private key from %s. Aborting.\n", privKeyFile);
544 exit(1);
545 }
546 privKeyBlob.Length = len;
547 if(keyForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) {
548 /* default for private keys */
549 keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
550 }
551 crtn = inferCssmKey(privKeyBlob, true, keyForm, cspHand, thePrivKey);
552 if(crtn) {
553 goto errOut;
554 }
555 privKey = &thePrivKey;
556 }
557 if(pubKeyFile) {
558 /* key blob from a file ==> a public CSSM_KEY */
559
560 if(privKeyFile || certFile) {
561 printf("****Specify exactly one of {cert_file, priv_key_file, "
562 "pub_key_file}.\n");
563 exit(1);
564 }
565
566 unsigned len;
567 if(readFile(pubKeyFile, &pubKeyBlob.Data, &len)) {
568 printf("***Error reading public key from %s. Aborting.\n", pubKeyFile);
569 exit(1);
570 }
571 pubKeyBlob.Length = len;
572 if(keyForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) {
573 /* default for public keys */
574 keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
575 }
576 crtn = inferCssmKey(pubKeyBlob, false, keyForm, cspHand, thePubKey);
577 if(crtn) {
578 goto errOut;
579 }
580 pubKey = &thePubKey;
581 }
582 if(certFile) {
583 /* cert from a file ==> a public CSSM_KEY */
584
585 if(privKeyFile || pubKeyFile) {
586 printf("****Specify exactly one of {cert_file, priv_key_file, "
587 "pub_key_file}.\n");
588 exit(1);
589 }
590
591 CSSM_DATA certData = {0, NULL};
592 unsigned len;
593 if(readFile(certFile, &certData.Data, &len)) {
594 printf("***Error reading cert from %s. Aborting.\n", certFile);
595 exit(1);
596 }
597 certData.Length = len;
598
599 /* Extract public key - that's what we will be using later */
600 clHand = cuClStartup();
601 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey);
602 if(crtn) {
603 cssmPerror("CSSM_CL_CertGetKeyInfo", crtn);
604 goto errOut;
605 }
606 }
607
608 /* now do something useful */
609 if(printDigest) {
610 CSSM_KEY_PTR theKey = privKey;
611 if(theKey == NULL) {
612 /* maybe we got public key from a cert */
613 theKey = pubKey;
614 }
615 if(theKey == NULL) {
616 printf("***Can't calculate digest because I don't have a key or a clue.\n");
617 goto errOut;
618 }
619 CSSM_DATA_PTR dig = NULL;
620 crtn = keyDigest(cspHand, theKey, &dig);
621 if(crtn) {
622 printf("Sorry, can't get the digest for this key.\n");
623 goto errOut;
624 }
625 if((dig == NULL) || (dig->Length == 0)) {
626 printf("Screwup calculating digest.\n");
627 goto errOut;
628 }
629 printf("Key Digest:\n");
630 for(unsigned dex=0; dex<dig->Length; dex++) {
631 printf("%02X ", dig->Data[dex]);
632 }
633 printf("\n");
634 APP_FREE(dig->Data);
635 APP_FREE(dig);
636 }
637
638 if(outFile || kcName) {
639 /* get a public key if we don't already have one */
640 if(pubKey == NULL) {
641 if(privKey == NULL) {
642 printf("***PubKey file name specified but no privKey or cert. "
643 "Aborting.\n");
644 goto errOut;
645 }
646 crtn = pubKeyFromPrivKey(cspHand, privKey, &thePubKey);
647 if(crtn) {
648 goto errOut;
649 }
650 pubKey = &thePubKey;
651 }
652 }
653 if(outFile) {
654 if(writeFile(outFile, pubKey->KeyData.Data, pubKey->KeyData.Length)) {
655 printf("***Error writing to %s.\n", outFile);
656 }
657 else {
658 printf("...%lu bytes written to %s.\n", pubKey->KeyData.Length, outFile);
659 }
660 }
661 if(kcName) {
662 if(pubKeyImport(kcName, pubKey, cspHand) == 0) {
663 printf("....public key %s imported to %s\n", pubKeyFile, kcName);
664 }
665 else {
666 printf("***Error importing public key %s to %s\n", pubKeyFile, kcName);
667 }
668 }
669errOut:
670 /* clean up here if you must */
671 return 0;
672}