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} 673