1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 * 21 * 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This file implements the export operation for this tool. 30 * The basic flow of the process is to find the soft token, 31 * log into it, find the PKCS#11 objects in the soft token 32 * to be exported matching keys with their certificates, export 33 * them to the PKCS#12 file encrypting them with a file password 34 * if desired, and log out. 35 */ 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include "common.h" 43 44 #include <kmfapi.h> 45 46 static KMF_RETURN 47 pk_find_export_cert(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *parms, 48 KMF_X509_DER_CERT *cert) 49 { 50 KMF_RETURN rv = KMF_OK; 51 uint32_t numcerts = 0; 52 53 numcerts = 0; 54 (void) memset(cert, 0, sizeof (KMF_X509_DER_CERT)); 55 rv = KMF_FindCert(kmfhandle, parms, NULL, &numcerts); 56 if (rv != KMF_OK) { 57 return (rv); 58 } 59 if (numcerts == 0) { 60 cryptoerror(LOG_STDERR, 61 gettext("No matching certificates found.")); 62 return (KMF_ERR_CERT_NOT_FOUND); 63 64 } else if (numcerts == 1) { 65 rv = KMF_FindCert(kmfhandle, parms, cert, &numcerts); 66 67 } else if (numcerts > 1) { 68 cryptoerror(LOG_STDERR, 69 gettext("%d certificates found, refine the " 70 "search parameters to eliminate ambiguity\n"), 71 numcerts); 72 return (KMF_ERR_BAD_PARAMETER); 73 } 74 return (rv); 75 } 76 77 static KMF_RETURN 78 pk_export_file_objects(KMF_HANDLE_T kmfhandle, int oclass, 79 char *issuer, char *subject, KMF_BIGINT *serial, 80 KMF_ENCODE_FORMAT ofmt, 81 char *dir, char *infile, char *filename) 82 { 83 KMF_RETURN rv = KMF_OK; 84 KMF_STORECERT_PARAMS scparms; 85 KMF_X509_DER_CERT kmfcert; 86 87 /* If searching for public objects or certificates, find certs now */ 88 if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { 89 KMF_FINDCERT_PARAMS fcargs; 90 91 (void) memset(&fcargs, 0, sizeof (fcargs)); 92 fcargs.kstype = KMF_KEYSTORE_OPENSSL; 93 fcargs.certLabel = NULL; 94 fcargs.issuer = issuer; 95 fcargs.subject = subject; 96 fcargs.serial = serial; 97 fcargs.sslparms.dirpath = dir; 98 fcargs.sslparms.certfile = infile; 99 fcargs.sslparms.format = ofmt; 100 101 rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert); 102 if (rv == KMF_OK) { 103 (void) memset(&scparms, 0, sizeof (scparms)); 104 scparms.kstype = KMF_KEYSTORE_OPENSSL; 105 scparms.sslparms.certfile = filename; 106 rv = KMF_StoreCert(kmfhandle, &scparms, 107 &kmfcert.certificate); 108 109 KMF_FreeKMFCert(kmfhandle, &kmfcert); 110 } 111 } 112 return (rv); 113 } 114 115 static KMF_RETURN 116 pk_export_pk12_nss(KMF_HANDLE_T kmfhandle, 117 char *token_spec, char *dir, char *prefix, 118 char *certlabel, char *issuer, char *subject, 119 KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, 120 char *filename) 121 { 122 KMF_RETURN rv = KMF_OK; 123 KMF_EXPORTP12_PARAMS p12parms; 124 125 rv = configure_nss(kmfhandle, dir, prefix); 126 if (rv != KMF_OK) 127 return (rv); 128 129 (void) memset(&p12parms, 0, sizeof (p12parms)); 130 if (token_spec == NULL) 131 token_spec = DEFAULT_NSS_TOKEN; 132 133 p12parms.kstype = KMF_KEYSTORE_NSS; 134 p12parms.certLabel = certlabel; 135 p12parms.issuer = issuer; 136 p12parms.subject = subject; 137 p12parms.serial = serial; 138 p12parms.idstr = NULL; 139 if (tokencred != NULL) 140 p12parms.cred = *tokencred; 141 p12parms.nssparms.slotlabel = token_spec; 142 143 (void) get_pk12_password(&p12parms.p12cred); 144 145 rv = KMF_ExportPK12(kmfhandle, &p12parms, filename); 146 if (p12parms.p12cred.cred) 147 free(p12parms.p12cred.cred); 148 149 return (rv); 150 } 151 152 static KMF_RETURN 153 pk_export_pk12_files(KMF_HANDLE_T kmfhandle, 154 char *certfile, char *keyfile, char *dir, 155 char *outfile) 156 { 157 KMF_RETURN rv; 158 KMF_EXPORTP12_PARAMS p12parms; 159 160 (void) memset(&p12parms, 0, sizeof (p12parms)); 161 162 p12parms.kstype = KMF_KEYSTORE_OPENSSL; 163 p12parms.certLabel = NULL; 164 p12parms.issuer = NULL; 165 p12parms.subject = NULL; 166 p12parms.serial = 0; 167 p12parms.idstr = NULL; 168 p12parms.sslparms.dirpath = dir; 169 p12parms.sslparms.certfile = certfile; 170 p12parms.sslparms.keyfile = keyfile; 171 172 (void) get_pk12_password(&p12parms.p12cred); 173 174 rv = KMF_ExportPK12(kmfhandle, &p12parms, outfile); 175 176 if (p12parms.p12cred.cred) 177 free(p12parms.p12cred.cred); 178 179 return (rv); 180 } 181 182 static KMF_RETURN 183 pk_export_nss_objects(KMF_HANDLE_T kmfhandle, char *token_spec, 184 int oclass, char *certlabel, char *issuer, char *subject, 185 KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *dir, 186 char *prefix, char *filename) 187 { 188 KMF_RETURN rv = KMF_OK; 189 KMF_STORECERT_PARAMS scparms; 190 KMF_X509_DER_CERT kmfcert; 191 192 rv = configure_nss(kmfhandle, dir, prefix); 193 if (rv != KMF_OK) 194 return (rv); 195 196 /* If searching for public objects or certificates, find certs now */ 197 if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) { 198 KMF_FINDCERT_PARAMS fcargs; 199 200 (void) memset(&fcargs, 0, sizeof (fcargs)); 201 fcargs.kstype = KMF_KEYSTORE_NSS; 202 fcargs.certLabel = certlabel; 203 fcargs.issuer = issuer; 204 fcargs.subject = subject; 205 fcargs.serial = serial; 206 fcargs.nssparms.slotlabel = token_spec; 207 208 rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert); 209 if (rv == KMF_OK) { 210 (void) memset(&scparms, 0, sizeof (scparms)); 211 scparms.kstype = KMF_KEYSTORE_OPENSSL; 212 scparms.sslparms.certfile = filename; 213 scparms.sslparms.format = kfmt; 214 215 rv = KMF_StoreCert(kmfhandle, &scparms, 216 &kmfcert.certificate); 217 218 KMF_FreeKMFCert(kmfhandle, &kmfcert); 219 } 220 } 221 return (rv); 222 } 223 224 static KMF_RETURN 225 pk_export_pk12_pk11(KMF_HANDLE_T kmfhandle, char *token_spec, 226 char *certlabel, char *issuer, char *subject, 227 KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename) 228 { 229 KMF_RETURN rv = KMF_OK; 230 KMF_EXPORTP12_PARAMS p12parms; 231 232 rv = select_token(kmfhandle, token_spec, TRUE); 233 if (rv != KMF_OK) { 234 return (rv); 235 } 236 237 (void) memset(&p12parms, 0, sizeof (p12parms)); 238 239 p12parms.kstype = KMF_KEYSTORE_PK11TOKEN; 240 p12parms.certLabel = certlabel; 241 p12parms.issuer = issuer; 242 p12parms.subject = subject; 243 p12parms.serial = serial; 244 p12parms.idstr = NULL; 245 if (tokencred != NULL) 246 p12parms.cred = *tokencred; 247 (void) get_pk12_password(&p12parms.p12cred); 248 249 rv = KMF_ExportPK12(kmfhandle, &p12parms, filename); 250 251 if (p12parms.p12cred.cred) 252 free(p12parms.p12cred.cred); 253 254 return (rv); 255 } 256 257 static KMF_RETURN 258 pk_export_pk11_objects(KMF_HANDLE_T kmfhandle, char *token_spec, 259 char *certlabel, char *issuer, char *subject, 260 KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, 261 char *filename) 262 { 263 KMF_RETURN rv = KMF_OK; 264 KMF_FINDCERT_PARAMS fcparms; 265 KMF_STORECERT_PARAMS scparms; 266 KMF_X509_DER_CERT kmfcert; 267 268 rv = select_token(kmfhandle, token_spec, TRUE); 269 270 if (rv != KMF_OK) { 271 return (rv); 272 } 273 274 (void) memset(&fcparms, 0, sizeof (fcparms)); 275 fcparms.kstype = KMF_KEYSTORE_PK11TOKEN; 276 fcparms.certLabel = certlabel; 277 fcparms.issuer = issuer; 278 fcparms.subject = subject; 279 fcparms.serial = serial; 280 281 rv = pk_find_export_cert(kmfhandle, &fcparms, &kmfcert); 282 283 if (rv == KMF_OK) { 284 (void) memset(&scparms, 0, sizeof (scparms)); 285 scparms.kstype = KMF_KEYSTORE_OPENSSL; 286 scparms.sslparms.certfile = filename; 287 scparms.sslparms.format = kfmt; 288 289 rv = KMF_StoreCert(kmfhandle, &scparms, 290 &kmfcert.certificate); 291 292 KMF_FreeKMFCert(kmfhandle, &kmfcert); 293 } 294 return (rv); 295 } 296 297 /* 298 * Export objects from one keystore to a file. 299 */ 300 int 301 pk_export(int argc, char *argv[]) 302 { 303 int opt; 304 extern int optind_av; 305 extern char *optarg_av; 306 char *token_spec = NULL; 307 char *filename = NULL; 308 char *dir = NULL; 309 char *prefix = NULL; 310 char *certlabel = NULL; 311 char *subject = NULL; 312 char *issuer = NULL; 313 char *infile = NULL; 314 char *keyfile = NULL; 315 char *certfile = NULL; 316 char *serstr = NULL; 317 KMF_KEYSTORE_TYPE kstype = 0; 318 KMF_ENCODE_FORMAT kfmt = KMF_FORMAT_PKCS12; 319 KMF_RETURN rv = KMF_OK; 320 int oclass = PK_CERT_OBJ; 321 KMF_BIGINT serial = { NULL, 0 }; 322 KMF_HANDLE_T kmfhandle = NULL; 323 KMF_CREDENTIAL tokencred = {NULL, 0}; 324 325 /* Parse command line options. Do NOT i18n/l10n. */ 326 while ((opt = getopt_av(argc, argv, 327 "k:(keystore)y:(objtype)T:(token)" 328 "d:(dir)p:(prefix)" 329 "l:(label)n:(nickname)s:(subject)" 330 "i:(issuer)S:(serial)" 331 "K:(keyfile)c:(certfile)" 332 "F:(outformat)" 333 "I:(infile)o:(outfile)")) != EOF) { 334 if (EMPTYSTRING(optarg_av)) 335 return (PK_ERR_USAGE); 336 switch (opt) { 337 case 'k': 338 kstype = KS2Int(optarg_av); 339 if (kstype == 0) 340 return (PK_ERR_USAGE); 341 break; 342 case 'y': 343 oclass = OT2Int(optarg_av); 344 if (oclass == -1) 345 return (PK_ERR_USAGE); 346 break; 347 case 'T': /* token specifier */ 348 if (token_spec) 349 return (PK_ERR_USAGE); 350 token_spec = optarg_av; 351 break; 352 case 'd': 353 if (dir) 354 return (PK_ERR_USAGE); 355 dir = optarg_av; 356 break; 357 case 'p': 358 if (prefix) 359 return (PK_ERR_USAGE); 360 prefix = optarg_av; 361 break; 362 case 'n': 363 case 'l': 364 if (certlabel) 365 return (PK_ERR_USAGE); 366 certlabel = optarg_av; 367 break; 368 case 's': 369 if (subject) 370 return (PK_ERR_USAGE); 371 subject = optarg_av; 372 break; 373 case 'i': 374 if (issuer) 375 return (PK_ERR_USAGE); 376 issuer = optarg_av; 377 break; 378 case 'S': 379 serstr = optarg_av; 380 break; 381 case 'F': 382 kfmt = Str2Format(optarg_av); 383 if (kfmt == KMF_FORMAT_UNDEF) 384 return (PK_ERR_USAGE); 385 break; 386 case 'I': /* output file name */ 387 if (infile) 388 return (PK_ERR_USAGE); 389 infile = optarg_av; 390 break; 391 case 'o': /* output file name */ 392 if (filename) 393 return (PK_ERR_USAGE); 394 filename = optarg_av; 395 break; 396 case 'c': /* input cert file name */ 397 if (certfile) 398 return (PK_ERR_USAGE); 399 certfile = optarg_av; 400 break; 401 case 'K': /* input key file name */ 402 if (keyfile) 403 return (PK_ERR_USAGE); 404 keyfile = optarg_av; 405 break; 406 default: 407 return (PK_ERR_USAGE); 408 break; 409 } 410 } 411 412 /* Assume keystore = PKCS#11 if not specified */ 413 if (kstype == 0) 414 kstype = KMF_KEYSTORE_PK11TOKEN; 415 416 /* Filename arg is required. */ 417 if (EMPTYSTRING(filename)) { 418 cryptoerror(LOG_STDERR, gettext("You must specify " 419 "an 'outfile' parameter when exporting.\n")); 420 return (PK_ERR_USAGE); 421 } 422 423 /* No additional args allowed. */ 424 argc -= optind_av; 425 argv += optind_av; 426 if (argc) 427 return (PK_ERR_USAGE); 428 429 /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ 430 if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && 431 kstype != KMF_KEYSTORE_PK11TOKEN) { 432 433 (void) fprintf(stderr, gettext("The objtype parameter " 434 "is only relevant if keystore=pkcs11\n")); 435 return (PK_ERR_USAGE); 436 } 437 438 if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) 439 token_spec = PK_DEFAULT_PK11TOKEN; 440 else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) 441 token_spec = DEFAULT_NSS_TOKEN; 442 443 if (kstype == KMF_KEYSTORE_OPENSSL) { 444 if (kfmt != KMF_FORMAT_PKCS12) { 445 cryptoerror(LOG_STDERR, gettext("PKCS12 " 446 "is the only export format " 447 "supported for the 'file' " 448 "keystore.\n")); 449 return (PK_ERR_USAGE); 450 } 451 if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { 452 cryptoerror(LOG_STDERR, gettext("A cert file" 453 "and a key file must be specified " 454 "when exporting to PKCS12 from the " 455 "'file' keystore.\n")); 456 return (PK_ERR_USAGE); 457 } 458 } 459 460 /* Check if the file exists and might be overwritten. */ 461 if (access(filename, F_OK) == 0) { 462 cryptoerror(LOG_STDERR, 463 gettext("Warning: file \"%s\" exists, " 464 "will be overwritten."), filename); 465 if (yesno(gettext("Continue with export? "), 466 gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { 467 return (0); 468 } 469 } else { 470 rv = verify_file(filename); 471 if (rv != KMF_OK) { 472 cryptoerror(LOG_STDERR, gettext("The file (%s) " 473 "cannot be created.\n"), filename); 474 return (PK_ERR_USAGE); 475 } 476 } 477 478 if (serstr != NULL) { 479 uchar_t *bytes = NULL; 480 size_t bytelen; 481 482 rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen); 483 if (rv != KMF_OK || bytes == NULL) { 484 (void) fprintf(stderr, gettext("serial number " 485 "must be specified as a hex number " 486 "(ex: 0x0102030405ffeeddee)\n")); 487 return (PK_ERR_USAGE); 488 } 489 serial.val = bytes; 490 serial.len = bytelen; 491 } 492 493 if ((kstype == KMF_KEYSTORE_PK11TOKEN || 494 kstype == KMF_KEYSTORE_NSS) && 495 (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ) || 496 kfmt == KMF_FORMAT_PKCS12)) { 497 (void) get_token_password(kstype, token_spec, 498 &tokencred); 499 } 500 501 if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { 502 cryptoerror(LOG_STDERR, gettext("Error initializing " 503 "KMF: 0x%02x\n"), rv); 504 return (rv); 505 } 506 507 switch (kstype) { 508 case KMF_KEYSTORE_PK11TOKEN: 509 if (kfmt == KMF_FORMAT_PKCS12) 510 rv = pk_export_pk12_pk11( 511 kmfhandle, 512 token_spec, 513 certlabel, 514 issuer, subject, 515 &serial, &tokencred, 516 filename); 517 else 518 rv = pk_export_pk11_objects(kmfhandle, 519 token_spec, 520 certlabel, 521 issuer, subject, 522 &serial, kfmt, 523 filename); 524 break; 525 case KMF_KEYSTORE_NSS: 526 if (dir == NULL) 527 dir = PK_DEFAULT_DIRECTORY; 528 if (kfmt == KMF_FORMAT_PKCS12) 529 rv = pk_export_pk12_nss(kmfhandle, 530 token_spec, dir, prefix, 531 certlabel, issuer, 532 subject, &serial, 533 &tokencred, filename); 534 else 535 rv = pk_export_nss_objects(kmfhandle, 536 token_spec, 537 oclass, certlabel, issuer, subject, 538 &serial, kfmt, dir, prefix, filename); 539 break; 540 case KMF_KEYSTORE_OPENSSL: 541 if (kfmt == KMF_FORMAT_PKCS12) 542 rv = pk_export_pk12_files(kmfhandle, 543 certfile, keyfile, dir, 544 filename); 545 else 546 rv = pk_export_file_objects(kmfhandle, oclass, 547 issuer, subject, &serial, kfmt, 548 dir, infile, filename); 549 break; 550 default: 551 rv = PK_ERR_USAGE; 552 break; 553 } 554 555 if (rv != KMF_OK) { 556 display_error(kmfhandle, rv, 557 gettext("Error exporting objects")); 558 } 559 560 if (serial.val != NULL) 561 free(serial.val); 562 563 (void) KMF_Finalize(kmfhandle); 564 565 return (rv); 566 } 567