import.c revision 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "common.h"
#include <kmfapi.h>
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(&params, 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, &params, &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(&params, 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, &params, &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(&params, 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, &params);
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(&params, 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, &params, &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);
}