/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * This file implements the import operation for this tool. * The basic flow of the process is to decrypt the PKCS#12 * input file if it has a password, parse the elements in * the file, find the soft token, log into it, import the * PKCS#11 objects into the soft token, and log out. */ #include #include #include #include #include #include #include #include #include "common.h" #include static KMF_RETURN pk_import_pk12_files(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *cred, char *outfile, char *certfile, char *keyfile, char *dir, char *keydir, KMF_ENCODE_FORMAT outformat) { KMF_RETURN rv = KMF_OK; KMF_DATA *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; rv = KMF_ImportPK12(kmfhandle, outfile, cred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) { (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, outfile); } if (rv == KMF_OK && ncerts > 0) { KMF_STORECERT_PARAMS params; char newcertfile[MAXPATHLEN]; (void) memset(¶ms, 0, sizeof (KMF_STORECERT_PARAMS)); params.kstype = KMF_KEYSTORE_OPENSSL; params.sslparms.dirpath = dir; params.sslparms.format = outformat; for (i = 0; rv == KMF_OK && i < ncerts; i++) { /* * If storing more than 1 cert, gotta change * the name so we don't overwrite the previous one. * Just append a _# to the name. */ if (i > 0) { (void) snprintf(newcertfile, sizeof (newcertfile), "%s_%d", certfile, i); params.sslparms.certfile = newcertfile; } else { params.sslparms.certfile = certfile; } rv = KMF_StoreCert(kmfhandle, ¶ms, &certs[i]); } } if (rv == KMF_OK && nkeys > 0) { KMF_STOREKEY_PARAMS skparms; char newkeyfile[MAXPATHLEN]; (void) memset(&skparms, 0, sizeof (skparms)); /* The order of certificates and keys should match */ for (i = 0; rv == KMF_OK && i < nkeys; i++) { skparms.kstype = KMF_KEYSTORE_OPENSSL; skparms.sslparms.dirpath = keydir; skparms.sslparms.format = outformat; skparms.cred = *cred; skparms.certificate = &certs[i]; if (i > 0) { (void) snprintf(newkeyfile, sizeof (newkeyfile), "%s_%d", keyfile, i); skparms.sslparms.keyfile = newkeyfile; } else { skparms.sslparms.keyfile = keyfile; } rv = KMF_StorePrivateKey(kmfhandle, &skparms, &keys[i]); } } /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) KMF_FreeData(&certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) KMF_FreeRawKey(&keys[i]); free(keys); } return (rv); } static KMF_RETURN pk_import_pk12_nss( KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *kmfcred, KMF_CREDENTIAL *tokencred, char *token_spec, char *dir, char *prefix, char *nickname, char *trustflags, char *filename) { KMF_RETURN rv = KMF_OK; KMF_DATA *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); rv = KMF_ImportPK12(kmfhandle, filename, kmfcred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, filename); if (rv == KMF_OK) { KMF_STORECERT_PARAMS params; (void) memset(¶ms, 0, sizeof (KMF_STORECERT_PARAMS)); params.kstype = KMF_KEYSTORE_NSS; params.nssparms.slotlabel = token_spec; params.nssparms.trustflag = trustflags; for (i = 0; rv == KMF_OK && i < ncerts; i++) { if (i == 0) params.certLabel = nickname; else params.certLabel = NULL; rv = KMF_StoreCert(kmfhandle, ¶ms, &certs[i]); } if (rv != KMF_OK) { display_error(kmfhandle, rv, gettext("Error storing certificate " "in PKCS11 token")); } } if (rv == KMF_OK) { KMF_STOREKEY_PARAMS skparms; /* The order of certificates and keys should match */ for (i = 0; i < nkeys; i++) { (void) memset(&skparms, 0, sizeof (KMF_STOREKEY_PARAMS)); skparms.kstype = KMF_KEYSTORE_NSS; skparms.cred = *tokencred; skparms.label = nickname; skparms.certificate = &certs[i]; skparms.nssparms.slotlabel = token_spec; rv = KMF_StorePrivateKey(kmfhandle, &skparms, &keys[i]); } } /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) KMF_FreeData(&certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) KMF_FreeRawKey(&keys[i]); free(keys); } return (rv); } static KMF_RETURN pk_import_cert( KMF_HANDLE_T kmfhandle, KMF_KEYSTORE_TYPE kstype, char *label, char *token_spec, char *filename, char *dir, char *prefix, char *trustflags) { KMF_RETURN rv = KMF_OK; KMF_IMPORTCERT_PARAMS params; if (kstype == KMF_KEYSTORE_PK11TOKEN) { rv = select_token(kmfhandle, token_spec, FALSE); if (rv != KMF_OK) { return (rv); } } (void) memset(¶ms, 0, sizeof (params)); params.kstype = kstype; params.certfile = filename; params.certLabel = label; if (kstype == KMF_KEYSTORE_NSS) { rv = configure_nss(kmfhandle, dir, prefix); if (rv != KMF_OK) return (rv); params.nssparms.trustflag = trustflags; params.nssparms.slotlabel = token_spec; } rv = KMF_ImportCert(kmfhandle, ¶ms); return (rv); } static KMF_RETURN pk_import_file_crl(void *kmfhandle, char *infile, char *outfile, char *outdir, KMF_ENCODE_FORMAT outfmt) { KMF_IMPORTCRL_PARAMS icrl_params; KMF_OPENSSL_PARAMS sslparams; sslparams.crlfile = infile; sslparams.dirpath = outdir; sslparams.outcrlfile = outfile; sslparams.format = outfmt; sslparams.crl_check = B_FALSE; icrl_params.kstype = KMF_KEYSTORE_OPENSSL; icrl_params.sslparms = sslparams; return (KMF_ImportCRL(kmfhandle, &icrl_params)); } static KMF_RETURN pk_import_nss_crl(void *kmfhandle, boolean_t verify_crl_flag, char *infile, char *outdir, char *prefix) { KMF_IMPORTCRL_PARAMS icrl_params; KMF_RETURN rv; rv = configure_nss(kmfhandle, outdir, prefix); if (rv != KMF_OK) return (rv); icrl_params.kstype = KMF_KEYSTORE_NSS; icrl_params.nssparms.slotlabel = NULL; icrl_params.nssparms.crlfile = infile; icrl_params.nssparms.crl_check = verify_crl_flag; return (KMF_ImportCRL(kmfhandle, &icrl_params)); } static KMF_RETURN pk_import_pk12_pk11( KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *p12cred, KMF_CREDENTIAL *tokencred, char *label, char *token_spec, char *filename) { KMF_RETURN rv = KMF_OK; KMF_DATA *certs = NULL; KMF_RAW_KEY_DATA *keys = NULL; int ncerts = 0; int nkeys = 0; int i; rv = select_token(kmfhandle, token_spec, FALSE); if (rv != KMF_OK) { return (rv); } rv = KMF_ImportPK12(kmfhandle, filename, p12cred, &certs, &ncerts, &keys, &nkeys); if (rv == KMF_OK) { KMF_STOREKEY_PARAMS skparms; /* The order of certificates and keys should match */ for (i = 0; i < nkeys; i++) { (void) memset(&skparms, 0, sizeof (KMF_STOREKEY_PARAMS)); skparms.kstype = KMF_KEYSTORE_PK11TOKEN; skparms.certificate = &certs[i]; if (tokencred != NULL) skparms.cred = *tokencred; if (i == 0) skparms.label = label; else skparms.label = NULL; rv = KMF_StorePrivateKey(kmfhandle, &skparms, &keys[i]); } } if (rv == KMF_OK) { KMF_STORECERT_PARAMS params; (void) printf(gettext("Found %d certificate(s) and %d " "key(s) in %s\n"), ncerts, nkeys, filename); (void) memset(¶ms, 0, sizeof (KMF_STORECERT_PARAMS)); params.kstype = KMF_KEYSTORE_PK11TOKEN; for (i = 0; rv == KMF_OK && i < ncerts; i++) { if (i == 0) params.certLabel = label; else params.certLabel = NULL; rv = KMF_StoreCert(kmfhandle, ¶ms, &certs[i]); } } /* * Cleanup memory. */ if (certs) { for (i = 0; i < ncerts; i++) KMF_FreeData(&certs[i]); free(certs); } if (keys) { for (i = 0; i < nkeys; i++) KMF_FreeRawKey(&keys[i]); free(keys); } return (rv); } /* * Import objects from into KMF repositories. */ int pk_import(int argc, char *argv[]) { int opt; extern int optind_av; extern char *optarg_av; char *token_spec = NULL; char *filename = NULL; char *keyfile = NULL; char *certfile = NULL; char *crlfile = NULL; char *certlabel = NULL; char *dir = NULL; char *keydir = NULL; char *prefix = NULL; char *trustflags = NULL; char *verify_crl = NULL; boolean_t verify_crl_flag = B_FALSE; int oclass = 0; KMF_KEYSTORE_TYPE kstype = 0; KMF_ENCODE_FORMAT kfmt = 0; KMF_ENCODE_FORMAT okfmt = KMF_FORMAT_ASN1; KMF_RETURN rv = KMF_OK; KMF_CREDENTIAL pk12cred = { NULL, 0 }; KMF_CREDENTIAL tokencred = { NULL, 0 }; KMF_HANDLE_T kmfhandle = NULL; /* Parse command line options. Do NOT i18n/l10n. */ while ((opt = getopt_av(argc, argv, "T:(token)i:(infile)" "k:(keystore)y:(objtype)" "d:(dir)p:(prefix)" "n:(certlabel)N:(label)" "K:(outkey)c:(outcert)" "v:(verifycrl)l:(outcrl)" "t:(trust)D:(keydir)F:(outformat)")) != EOF) { if (EMPTYSTRING(optarg_av)) return (PK_ERR_USAGE); switch (opt) { case 'T': /* token specifier */ if (token_spec) return (PK_ERR_USAGE); token_spec = optarg_av; break; case 'c': /* output cert file name */ if (certfile) return (PK_ERR_USAGE); certfile = optarg_av; break; case 'l': /* output CRL file name */ if (crlfile) return (PK_ERR_USAGE); crlfile = optarg_av; break; case 'K': /* output key file name */ if (keyfile) return (PK_ERR_USAGE); keyfile = optarg_av; break; case 'i': /* input file name */ if (filename) return (PK_ERR_USAGE); filename = optarg_av; break; case 'k': kstype = KS2Int(optarg_av); if (kstype == 0) return (PK_ERR_USAGE); break; case 'y': oclass = OT2Int(optarg_av); if (oclass == -1) return (PK_ERR_USAGE); break; case 'd': dir = optarg_av; break; case 'D': keydir = optarg_av; break; case 'p': if (prefix) return (PK_ERR_USAGE); prefix = optarg_av; break; case 'n': case 'N': if (certlabel) return (PK_ERR_USAGE); certlabel = optarg_av; break; case 'F': okfmt = Str2Format(optarg_av); if (okfmt == KMF_FORMAT_UNDEF) return (PK_ERR_USAGE); break; case 't': if (trustflags) return (PK_ERR_USAGE); trustflags = optarg_av; break; case 'v': verify_crl = optarg_av; if (tolower(verify_crl[0]) == 'y') verify_crl_flag = B_TRUE; else if (tolower(verify_crl[0]) == 'n') verify_crl_flag = B_FALSE; else return (PK_ERR_USAGE); break; default: return (PK_ERR_USAGE); break; } } /* Assume keystore = PKCS#11 if not specified */ if (kstype == 0) kstype = KMF_KEYSTORE_PK11TOKEN; /* Filename arg is required. */ if (EMPTYSTRING(filename)) { cryptoerror(LOG_STDERR, gettext("The 'infile' parameter" "is required for the import operation.\n")); return (PK_ERR_USAGE); } /* No additional args allowed. */ argc -= optind_av; argv += optind_av; if (argc) return (PK_ERR_USAGE); /* if PUBLIC or PRIVATE obj was given, the old syntax was used. */ if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) && kstype != KMF_KEYSTORE_PK11TOKEN) { (void) fprintf(stderr, gettext("The objtype parameter " "is only relevant if keystore=pkcs11\n")); return (PK_ERR_USAGE); } /* * You must specify a certlabel (cert label) when importing * into NSS or PKCS#11. */ if (kstype == KMF_KEYSTORE_NSS && (oclass != PK_CRL_OBJ) && EMPTYSTRING(certlabel)) { cryptoerror(LOG_STDERR, gettext("The 'label' argument " "is required for this operation\n")); return (PK_ERR_USAGE); } /* * PKCS11 only imports PKCS#12 files or PEM/DER Cert files. */ if (kstype == KMF_KEYSTORE_PK11TOKEN) { /* we do not import private keys except in PKCS12 bundles */ if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) { cryptoerror(LOG_STDERR, gettext( "The PKCS11 keystore only imports PKCS12 " "files or raw certificate data files " " or CRL file.\n")); return (PK_ERR_USAGE); } } if ((rv = KMF_GetFileFormat(filename, &kfmt)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("File format not recognized.")); return (rv); } if (oclass == 0 && (kfmt == KMF_FORMAT_ASN1 || kfmt == KMF_FORMAT_PEM)) oclass = PK_CERT_OBJ; if (kstype == KMF_KEYSTORE_NSS) { if (oclass == PK_CRL_OBJ && (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { cryptoerror(LOG_STDERR, gettext( "CRL data can only be imported as DER or " "PEM format")); return (PK_ERR_USAGE); } if (oclass == PK_CERT_OBJ && (kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) { cryptoerror(LOG_STDERR, gettext( "Certificates can only be imported as DER or " "PEM format")); return (PK_ERR_USAGE); } /* we do not import private keys except in PKCS12 bundles */ if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) { cryptoerror(LOG_STDERR, gettext( "Private key data can only be imported as part " "of a PKCS12 file.\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_OPENSSL && oclass != PK_CRL_OBJ) { if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) { cryptoerror(LOG_STDERR, gettext( "The 'outkey' and 'outcert' parameters " "are required for the import operation " "when the 'file' keystore is used.\n")); return (PK_ERR_USAGE); } } if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec)) token_spec = PK_DEFAULT_PK11TOKEN; else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec)) token_spec = DEFAULT_NSS_TOKEN; if (kfmt == KMF_FORMAT_PKCS12) { (void) get_pk12_password(&pk12cred); if (kstype == KMF_KEYSTORE_PK11TOKEN || kstype == KMF_KEYSTORE_NSS) (void) get_token_password(kstype, token_spec, &tokencred); } if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { cryptoerror(LOG_STDERR, gettext("Error initializing " "KMF: 0x%02x\n"), rv); goto end; } switch (kstype) { case KMF_KEYSTORE_PK11TOKEN: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_pk11( kmfhandle, &pk12cred, &tokencred, certlabel, token_spec, filename); else if (oclass == PK_CERT_OBJ) rv = pk_import_cert( kmfhandle, kstype, certlabel, token_spec, filename, NULL, NULL, NULL); else if (oclass == PK_CRL_OBJ) rv = pk_import_file_crl( kmfhandle, filename, crlfile, dir, okfmt); break; case KMF_KEYSTORE_NSS: if (dir == NULL) dir = PK_DEFAULT_DIRECTORY; if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_nss( kmfhandle, &pk12cred, &tokencred, token_spec, dir, prefix, certlabel, trustflags, filename); else if (oclass == PK_CERT_OBJ) { rv = pk_import_cert( kmfhandle, kstype, certlabel, token_spec, filename, dir, prefix, trustflags); } else if (oclass == PK_CRL_OBJ) { rv = pk_import_nss_crl( kmfhandle, verify_crl_flag, filename, dir, prefix); } break; case KMF_KEYSTORE_OPENSSL: if (kfmt == KMF_FORMAT_PKCS12) rv = pk_import_pk12_files( kmfhandle, &pk12cred, filename, certfile, keyfile, dir, keydir, okfmt); else if (oclass == PK_CRL_OBJ) { rv = pk_import_file_crl( kmfhandle, filename, crlfile, dir, okfmt); } else /* * It doesn't make sense to import anything * else for the files plugin. */ return (PK_ERR_USAGE); break; default: rv = PK_ERR_USAGE; break; } end: if (rv != KMF_OK) display_error(kmfhandle, rv, gettext("Error importing objects")); if (tokencred.cred != NULL) free(tokencred.cred); if (pk12cred.cred != NULL) free(pk12cred.cred); (void) KMF_Finalize(kmfhandle); if (rv != KMF_OK) return (PK_ERR_USAGE); return (0); }