xref: /onnv-gate/usr/src/cmd/cmd-crypto/pktool/import.c (revision 864:75df3e9f93de)
117Sdinak /*
217Sdinak  * CDDL HEADER START
317Sdinak  *
417Sdinak  * The contents of this file are subject to the terms of the
517Sdinak  * Common Development and Distribution License, Version 1.0 only
617Sdinak  * (the "License").  You may not use this file except in compliance
717Sdinak  * with the License.
817Sdinak  *
917Sdinak  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1017Sdinak  * or http://www.opensolaris.org/os/licensing.
1117Sdinak  * See the License for the specific language governing permissions
1217Sdinak  * and limitations under the License.
1317Sdinak  *
1417Sdinak  * When distributing Covered Code, include this CDDL HEADER in each
1517Sdinak  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1617Sdinak  * If applicable, add the following below this CDDL HEADER, with the
1717Sdinak  * fields enclosed by brackets "[]" replaced with your own identifying
1817Sdinak  * information: Portions Copyright [yyyy] [name of copyright owner]
1917Sdinak  *
2017Sdinak  * CDDL HEADER END
2117Sdinak  */
2217Sdinak /*
2317Sdinak  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
2417Sdinak  * Use is subject to license terms.
2517Sdinak  */
2617Sdinak 
2717Sdinak #pragma ident	"%Z%%M%	%I%	%E% SMI"
2817Sdinak 
2917Sdinak /*
3017Sdinak  * This file implements the import operation for this tool.
3117Sdinak  * The basic flow of the process is to decrypt the PKCS#12
3217Sdinak  * input file if it has a password, parse the elements in
3317Sdinak  * the file, find the soft token, log into it, import the
3417Sdinak  * PKCS#11 objects into the soft token, and log out.
3517Sdinak  */
3617Sdinak 
3717Sdinak #include <stdio.h>
3817Sdinak #include <stdlib.h>
3917Sdinak #include <string.h>
4017Sdinak #include <errno.h>
4117Sdinak #include <fcntl.h>
4217Sdinak #include <sys/types.h>
4317Sdinak #include <sys/stat.h>
4417Sdinak #include <cryptoutil.h>
4517Sdinak #include <security/cryptoki.h>
4617Sdinak #include "common.h"
4717Sdinak #include "biginteger.h"
4817Sdinak #include "osslcommon.h"
4917Sdinak #include "p12common.h"
5017Sdinak #include <openssl/pkcs12.h>
5117Sdinak #include <openssl/err.h>
5217Sdinak 
5317Sdinak /*
5417Sdinak  * Helper function decrypt and parse PKCS#12 import file.
5517Sdinak  */
5617Sdinak static CK_RV
5717Sdinak extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
5817Sdinak 	EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
5917Sdinak /* ARGSUSED */
6017Sdinak {
6117Sdinak 	PKCS12		*pk12, *pk12_tmp;
6217Sdinak 	EVP_PKEY	*temp_pkey = NULL;
6317Sdinak 	X509		*temp_cert = NULL;
6417Sdinak 	STACK_OF(X509)	*temp_ca = NULL;
6517Sdinak 
6617Sdinak 	cryptodebug("inside extract_pkcs12");
6717Sdinak 
6817Sdinak 	cryptodebug("calling PKCS12_new");
6917Sdinak 	if ((pk12 = PKCS12_new()) == NULL) {
7017Sdinak 		cryptoerror(LOG_STDERR, gettext(
7117Sdinak 		    "Unable to create PKCS#12 context."));
7217Sdinak 		return (CKR_GENERAL_ERROR);
7317Sdinak 	}
7417Sdinak 
7517Sdinak 	cryptodebug("calling d2i_PKCS12_bio");
7617Sdinak 	if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) {
7717Sdinak 		/* This is ok; it seems to mean there is no more to read. */
7817Sdinak 		if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 &&
7917Sdinak 		    ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG)
8017Sdinak 			goto end_extract_pkcs12;
8117Sdinak 
8217Sdinak 		cryptoerror(LOG_STDERR, gettext(
8317Sdinak 		    "Unable to populate PKCS#12 context."));
8417Sdinak 		PKCS12_free(pk12);
8517Sdinak 		return (CKR_GENERAL_ERROR);
8617Sdinak 	}
8717Sdinak 	pk12 = pk12_tmp;
8817Sdinak 
8917Sdinak 	cryptodebug("calling PKCS12_parse");
9017Sdinak 	if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert,
9117Sdinak 	    &temp_ca) <= 0) {
9217Sdinak 		cryptoerror(LOG_STDERR,
9317Sdinak 		    gettext("Unable to parse import file."));
9417Sdinak 		PKCS12_free(pk12);
9517Sdinak 		return (CKR_GENERAL_ERROR);
9617Sdinak 	}
9717Sdinak 
9817Sdinak end_extract_pkcs12:
9917Sdinak 
10017Sdinak 	*priv_key = temp_pkey;
10117Sdinak 	*cert = temp_cert;
10217Sdinak 	*ca = temp_ca;
10317Sdinak 
10417Sdinak 	PKCS12_free(pk12);
10517Sdinak 	return (CKR_OK);
10617Sdinak }
10717Sdinak 
10817Sdinak /*
10917Sdinak  * Converts OpenSSL BIGNUM into PKCS#11 biginteger_t format.
11017Sdinak  */
11117Sdinak static CK_RV
11217Sdinak cvt_bn2bigint(BIGNUM *from, biginteger_t *to)
11317Sdinak {
11417Sdinak 	CK_BYTE		*temp;
11517Sdinak 	CK_ULONG	temp_alloc_sz, temp_cvt_sz;
11617Sdinak 
11717Sdinak 	cryptodebug("inside cvt_bn2bigint");
11817Sdinak 
11917Sdinak 	if (from == NULL || to == NULL)
12017Sdinak 		return (CKR_ARGUMENTS_BAD);
12117Sdinak 
12217Sdinak 	cryptodebug("calling BN_num_bytes");
12317Sdinak 	temp_alloc_sz = BN_num_bytes(from);
12417Sdinak 	if ((temp = malloc(temp_alloc_sz)) == NULL)
12517Sdinak 		return (CKR_HOST_MEMORY);
12617Sdinak 
12717Sdinak 	cryptodebug("calling BN_bn2bin");
12817Sdinak 	temp_cvt_sz = BN_bn2bin(from, (unsigned char *)temp);
12917Sdinak 	if (temp_cvt_sz != temp_alloc_sz)
13017Sdinak 		return (CKR_GENERAL_ERROR);
13117Sdinak 
13217Sdinak 	to->big_value = temp;
13317Sdinak 	to->big_value_len = temp_cvt_sz;
13417Sdinak 	return (CKR_OK);
13517Sdinak }
13617Sdinak 
13717Sdinak /*
13817Sdinak  * Write RSA private key to token.
13917Sdinak  */
14017Sdinak static CK_RV
14117Sdinak write_rsa_private(CK_SESSION_HANDLE sess, RSA *rsa, X509 *cert)
14217Sdinak {
14317Sdinak 	CK_RV		rv = CKR_OK;
14417Sdinak 	int		i = 0;
14517Sdinak 	static CK_OBJECT_CLASS	objclass = CKO_PRIVATE_KEY;
14617Sdinak 	static CK_KEY_TYPE	keytype = CKK_RSA;
14717Sdinak 	CK_BYTE		*label = NULL;
14817Sdinak 	CK_ULONG	label_len = 0;
14917Sdinak 	CK_BYTE		*id = NULL;
15017Sdinak 	CK_ULONG	id_len = 0;
15117Sdinak 	CK_DATE		startdate = { "", "", "" };
15217Sdinak 	CK_DATE		enddate = { "", "", "" };
15317Sdinak 	char		tmpdate[8];
15417Sdinak 	biginteger_t	mod = { NULL, 0 };	/* required */
15517Sdinak 	biginteger_t	pubexp = { NULL, 0 };	/* required */
15617Sdinak 	biginteger_t	priexp = { NULL, 0 };	/* optional */
15717Sdinak 	biginteger_t	prime1 = { NULL, 0 };	/* optional */
15817Sdinak 	biginteger_t	prime2 = { NULL, 0 };	/* optional */
15917Sdinak 	biginteger_t	exp1 = { NULL, 0 };	/* optional */
16017Sdinak 	biginteger_t	exp2 = { NULL, 0 };	/* optional */
16117Sdinak 	biginteger_t	coef = { NULL, 0 };	/* optional */
16217Sdinak 	CK_ATTRIBUTE	rsa_pri_attrs[16] = {
16317Sdinak 		{ CKA_CLASS, &objclass, sizeof (objclass) },
16417Sdinak 		{ CKA_KEY_TYPE, &keytype, sizeof (keytype) },
16517Sdinak 		{ CKA_PRIVATE, &pk_true, sizeof (pk_true) },
16617Sdinak 		{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
16717Sdinak 		{ CKA_LABEL, NULL, 0 },
16817Sdinak 		{ CKA_ID, NULL, 0 },
16917Sdinak 		{ CKA_START_DATE, NULL, 0 },
17017Sdinak 		{ CKA_END_DATE, NULL, 0 },
17117Sdinak 		{ CKA_MODULUS, NULL, 0 },
17217Sdinak 		{ CKA_PUBLIC_EXPONENT, NULL, 0 },
17317Sdinak 		{ 0 /* CKA_PRIVATE_EXPONENT */, NULL, 0 },	/* optional */
17417Sdinak 		{ 0 /* CKA_PRIME_1 */, NULL, 0 },		/*  |  */
17517Sdinak 		{ 0 /* CKA_PRIME_2 */, NULL, 0 },		/*  |  */
17617Sdinak 		{ 0 /* CKA_EXPONENT_1 */, NULL, 0 },		/*  |  */
17717Sdinak 		{ 0 /* CKA_EXPONENT_2 */, NULL, 0 },		/*  |  */
17817Sdinak 		{ 0 /* CKA_COEFFICIENT */, NULL, 0 }		/*  V  */
17917Sdinak 	    };
18017Sdinak 	CK_ULONG	count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
18117Sdinak 	CK_OBJECT_HANDLE	obj;
18217Sdinak 
18317Sdinak 	cryptodebug("inside write_rsa_private");
18417Sdinak 
18517Sdinak 	/* Attributes start at array index 4. */
18617Sdinak 	i = 4;
18717Sdinak 
18817Sdinak 	/* Recycle the certificate label for the private key label. */
18917Sdinak 	cryptodebug("calling X509_alias_get0");
19017Sdinak 	if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
19117Sdinak 		label = (CK_BYTE *)gettext("no label");
19217Sdinak 		label_len = strlen((char *)label);
19317Sdinak 	}
19417Sdinak 	copy_string_to_attr(label, label_len, &(rsa_pri_attrs[i++]));
19517Sdinak 
19617Sdinak 	/* Recycle the certificate id for the private key id. */
19717Sdinak 	cryptodebug("calling PKTOOL_X509_keyid_get0");
19817Sdinak 	if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
19917Sdinak 		id = (CK_BYTE *)gettext("no id");
20017Sdinak 		id_len = strlen((char *)id);
20117Sdinak 	}
20217Sdinak 	copy_string_to_attr(id, id_len, &(rsa_pri_attrs[i++]));
20317Sdinak 
20417Sdinak 	/* Recycle the certificate start and end dates for private key.  */
20517Sdinak 	cryptodebug("calling X509_get_notBefore");
20617Sdinak 	if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
20717Sdinak 		(void) memcpy(&startdate, tmpdate, sizeof (startdate));
20817Sdinak 		copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
20917Sdinak 		    &(rsa_pri_attrs[i++]));
21017Sdinak 	}
21117Sdinak 
21217Sdinak 	cryptodebug("calling X509_get_notAfter");
21317Sdinak 	if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
21417Sdinak 		(void) memcpy(&enddate, tmpdate, sizeof (enddate));
21517Sdinak 		copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
21617Sdinak 		    &(rsa_pri_attrs[i++]));
21717Sdinak 	}
21817Sdinak 
21917Sdinak 	/* Modulus n */
22017Sdinak 	cryptodebug("converting RSA private key modulus");
22117Sdinak 	if ((rv = cvt_bn2bigint(rsa->n, &mod)) != CKR_OK) {
22217Sdinak 		cryptoerror(LOG_STDERR, gettext(
22317Sdinak 		    "Unable to convert RSA private key modulus."));
22417Sdinak 		return (rv);
22517Sdinak 	}
22617Sdinak 	copy_bigint_to_attr(mod, &(rsa_pri_attrs[i++]));
22717Sdinak 
22817Sdinak 	/* Public exponent e */
22917Sdinak 	cryptodebug("converting RSA private key public exponent");
23017Sdinak 	if ((rv = cvt_bn2bigint(rsa->e, &pubexp)) != CKR_OK) {
23117Sdinak 		cryptoerror(LOG_STDERR, gettext(
23217Sdinak 		    "Unable to convert RSA private key public exponent."));
23317Sdinak 		return (rv);
23417Sdinak 	}
23517Sdinak 	copy_bigint_to_attr(pubexp, &(rsa_pri_attrs[i++]));
23617Sdinak 
23717Sdinak 	/* Private exponent d */
23817Sdinak 	if (rsa->d != NULL) {
23917Sdinak 		cryptodebug("converting RSA private key private exponent");
24017Sdinak 		if ((rv = cvt_bn2bigint(rsa->d, &priexp)) != CKR_OK) {
24117Sdinak 			cryptoerror(LOG_STDERR, gettext("Unable to convert "
24217Sdinak 			    "RSA private key private exponent."));
24317Sdinak 			return (rv);
24417Sdinak 		}
24517Sdinak 		rsa_pri_attrs[i].type = CKA_PRIVATE_EXPONENT;
24617Sdinak 		copy_bigint_to_attr(priexp, &(rsa_pri_attrs[i++]));
24717Sdinak 	} else
24817Sdinak 		cryptodebug("no RSA private key private exponent");
24917Sdinak 
25017Sdinak 	/* Prime p */
25117Sdinak 	if (rsa->p != NULL) {
25217Sdinak 		cryptodebug("converting RSA private key prime 1");
25317Sdinak 		if ((rv = cvt_bn2bigint(rsa->p, &prime1)) != CKR_OK) {
25417Sdinak 			cryptoerror(LOG_STDERR, gettext(
25517Sdinak 			    "Unable to convert RSA private key prime 1."));
25617Sdinak 			return (rv);
25717Sdinak 		}
25817Sdinak 		rsa_pri_attrs[i].type = CKA_PRIME_1;
25917Sdinak 		copy_bigint_to_attr(prime1, &(rsa_pri_attrs[i++]));
26017Sdinak 	} else
26117Sdinak 		cryptodebug("no RSA private key prime 1");
26217Sdinak 
26317Sdinak 	/* Prime q */
26417Sdinak 	if (rsa->q != NULL) {
26517Sdinak 		cryptodebug("converting RSA private key prime 2");
26617Sdinak 		if ((rv = cvt_bn2bigint(rsa->q, &prime2)) != CKR_OK) {
26717Sdinak 			cryptoerror(LOG_STDERR, gettext(
26817Sdinak 			    "Unable to convert RSA private key prime 2."));
26917Sdinak 			return (rv);
27017Sdinak 		}
27117Sdinak 		rsa_pri_attrs[i].type = CKA_PRIME_2;
27217Sdinak 		copy_bigint_to_attr(prime2, &(rsa_pri_attrs[i++]));
27317Sdinak 	} else
27417Sdinak 		cryptodebug("no RSA private key prime 2");
27517Sdinak 
27617Sdinak 	/* Private exponent d modulo p-1 */
27717Sdinak 	if (rsa->dmp1 != NULL) {
27817Sdinak 		cryptodebug("converting RSA private key exponent 1");
27917Sdinak 		if ((rv = cvt_bn2bigint(rsa->dmp1, &exp1)) != CKR_OK) {
28017Sdinak 			cryptoerror(LOG_STDERR, gettext(
28117Sdinak 			    "Unable to convert RSA private key exponent 1."));
28217Sdinak 			return (rv);
28317Sdinak 		}
28417Sdinak 		rsa_pri_attrs[i].type = CKA_EXPONENT_1;
28517Sdinak 		copy_bigint_to_attr(exp1, &(rsa_pri_attrs[i++]));
28617Sdinak 	} else
28717Sdinak 		cryptodebug("no RSA private key exponent 1");
28817Sdinak 
28917Sdinak 	/* Private exponent d modulo q-1 */
29017Sdinak 	if (rsa->dmq1 != NULL) {
29117Sdinak 		cryptodebug("converting RSA private key exponent 2");
29217Sdinak 		if ((rv = cvt_bn2bigint(rsa->dmq1, &exp2)) != CKR_OK) {
29317Sdinak 			cryptoerror(LOG_STDERR, gettext(
29417Sdinak 			    "Unable to convert RSA private key exponent 2."));
29517Sdinak 			return (rv);
29617Sdinak 		}
29717Sdinak 		rsa_pri_attrs[i].type = CKA_EXPONENT_2;
29817Sdinak 		copy_bigint_to_attr(exp2, &(rsa_pri_attrs[i++]));
29917Sdinak 	} else
30017Sdinak 		cryptodebug("no RSA private key exponent 2");
30117Sdinak 
30217Sdinak 	/* CRT coefficient q-inverse mod p */
30317Sdinak 	if (rsa->iqmp != NULL) {
30417Sdinak 		cryptodebug("converting RSA private key coefficient");
30517Sdinak 		if ((rv = cvt_bn2bigint(rsa->iqmp, &coef)) != CKR_OK) {
30617Sdinak 			cryptoerror(LOG_STDERR, gettext(
30717Sdinak 			    "Unable to convert RSA private key coefficient."));
30817Sdinak 			return (rv);
30917Sdinak 		}
31017Sdinak 		rsa_pri_attrs[i].type = CKA_COEFFICIENT;
31117Sdinak 		copy_bigint_to_attr(coef, &(rsa_pri_attrs[i++]));
31217Sdinak 	} else
31317Sdinak 		cryptodebug("no RSA private key coefficient");
31417Sdinak 
31517Sdinak 	/* Indicates programming error:  attributes overran the template */
31617Sdinak 	if (i > count) {
31717Sdinak 		cryptodebug("error: more attributes found than accounted for");
31817Sdinak 		i = count;
31917Sdinak 	}
32017Sdinak 
32117Sdinak 	cryptodebug("calling C_CreateObject");
32217Sdinak 	if ((rv = C_CreateObject(sess, rsa_pri_attrs, i, &obj)) != CKR_OK) {
32317Sdinak 		cryptoerror(LOG_STDERR, gettext(
32417Sdinak 		    "Unable to create RSA private key object."));
32517Sdinak 		return (rv);
32617Sdinak 	}
32717Sdinak 
32817Sdinak 	return (CKR_OK);
32917Sdinak }
33017Sdinak 
33117Sdinak /*
33217Sdinak  * Write DSA private key to token.
33317Sdinak  */
33417Sdinak static CK_RV
33517Sdinak write_dsa_private(CK_SESSION_HANDLE sess, DSA *dsa, X509 *cert)
33617Sdinak {
33717Sdinak 	CK_RV		rv = CKR_OK;
33817Sdinak 	int		i = 0;
33917Sdinak 	static CK_OBJECT_CLASS	objclass = CKO_PRIVATE_KEY;
34017Sdinak 	static CK_KEY_TYPE	keytype = CKK_DSA;
34117Sdinak 	CK_BYTE		*label = NULL;
34217Sdinak 	CK_ULONG	label_len = 0;
34317Sdinak 	CK_BYTE		*id = NULL;
34417Sdinak 	CK_ULONG	id_len = 0;
34517Sdinak 	CK_DATE		startdate = { "", "", "" };
34617Sdinak 	CK_DATE		enddate = { "", "", "" };
34717Sdinak 	char		tmpdate[8];
34817Sdinak 	biginteger_t	prime = { NULL, 0 };	/* required */
34917Sdinak 	biginteger_t	subprime = { NULL, 0 };	/* required */
35017Sdinak 	biginteger_t	base = { NULL, 0 };	/* required */
35117Sdinak 	biginteger_t	value = { NULL, 0 };	/* required */
35217Sdinak 	CK_ATTRIBUTE	dsa_pri_attrs[12] = {
35317Sdinak 		{ CKA_CLASS, &objclass, sizeof (objclass) },
35417Sdinak 		{ CKA_KEY_TYPE, &keytype, sizeof (keytype) },
35517Sdinak 		{ CKA_PRIVATE, &pk_true, sizeof (pk_true) },
35617Sdinak 		{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
35717Sdinak 		{ CKA_LABEL, NULL, 0 },
35817Sdinak 		{ CKA_ID, NULL, 0 },
35917Sdinak 		{ CKA_START_DATE, NULL, 0 },
36017Sdinak 		{ CKA_END_DATE, NULL, 0 },
36117Sdinak 		{ CKA_PRIME, NULL, 0 },
36217Sdinak 		{ CKA_SUBPRIME, NULL, 0 },
36317Sdinak 		{ CKA_BASE, NULL, 0 },
36417Sdinak 		{ CKA_VALUE, NULL, 0 }
36517Sdinak 	    };
36617Sdinak 	CK_ULONG	count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
36717Sdinak 	CK_OBJECT_HANDLE	obj;
36817Sdinak 
36917Sdinak 	cryptodebug("inside write_dsa_private");
37017Sdinak 
37117Sdinak 	/* Attributes start at array index 4. */
37217Sdinak 	i = 4;
37317Sdinak 
37417Sdinak 	/* Recycle the certificate label for the private key label. */
37517Sdinak 	cryptodebug("calling X509_alias_get0");
37617Sdinak 	if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
37717Sdinak 		label = (CK_BYTE *)gettext("no label");
37817Sdinak 		label_len = strlen((char *)label);
37917Sdinak 	}
38017Sdinak 	copy_string_to_attr(label, label_len, &(dsa_pri_attrs[i++]));
38117Sdinak 
38217Sdinak 	/* Recycle the certificate id for the private key id. */
38317Sdinak 	cryptodebug("calling PKTOOL_X509_keyid_get0");
38417Sdinak 	if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
38517Sdinak 		id = (CK_BYTE *)gettext("no id");
38617Sdinak 		id_len = strlen((char *)id);
38717Sdinak 	}
38817Sdinak 	copy_string_to_attr(id, id_len, &(dsa_pri_attrs[i++]));
38917Sdinak 
39017Sdinak 	/* Recycle the certificate start and end dates for private key.  */
39117Sdinak 	cryptodebug("calling X509_get_notBefore");
39217Sdinak 	if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
39317Sdinak 		(void) memcpy(&startdate, tmpdate, sizeof (startdate));
39417Sdinak 		copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
39517Sdinak 		    &(dsa_pri_attrs[i++]));
39617Sdinak 	}
39717Sdinak 
39817Sdinak 	cryptodebug("calling X509_get_notAfter");
39917Sdinak 	if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
40017Sdinak 		(void) memcpy(&enddate, tmpdate, sizeof (enddate));
40117Sdinak 		copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
40217Sdinak 		    &(dsa_pri_attrs[i++]));
40317Sdinak 	}
40417Sdinak 
40517Sdinak 	/* Prime p */
40617Sdinak 	cryptodebug("converting DSA private key prime");
40717Sdinak 	if ((rv = cvt_bn2bigint(dsa->p, &prime)) != CKR_OK) {
40817Sdinak 		cryptoerror(LOG_STDERR, gettext(
40917Sdinak 		    "Unable to convert DSA private key prime."));
41017Sdinak 		return (rv);
41117Sdinak 	}
41217Sdinak 	copy_bigint_to_attr(prime, &(dsa_pri_attrs[i++]));
41317Sdinak 
41417Sdinak 	/* Subprime q */
41517Sdinak 	cryptodebug("converting DSA private key subprime");
41617Sdinak 	if ((rv = cvt_bn2bigint(dsa->q, &subprime)) != CKR_OK) {
41717Sdinak 		cryptoerror(LOG_STDERR, gettext(
41817Sdinak 		    "Unable to convert DSA private key subprime."));
41917Sdinak 		return (rv);
42017Sdinak 	}
42117Sdinak 	copy_bigint_to_attr(subprime, &(dsa_pri_attrs[i++]));
42217Sdinak 
42317Sdinak 	/* Base g */
42417Sdinak 	cryptodebug("converting DSA private key base");
42517Sdinak 	if ((rv = cvt_bn2bigint(dsa->g, &base)) != CKR_OK) {
42617Sdinak 		cryptoerror(LOG_STDERR, gettext(
42717Sdinak 		    "Unable to convert DSA private key base."));
42817Sdinak 		return (rv);
42917Sdinak 	}
43017Sdinak 	copy_bigint_to_attr(base, &(dsa_pri_attrs[i++]));
43117Sdinak 
43217Sdinak 	/* Private key x */
43317Sdinak 	cryptodebug("converting DSA private key value");
43417Sdinak 	if ((rv = cvt_bn2bigint(dsa->priv_key, &value)) != CKR_OK) {
43517Sdinak 		cryptoerror(LOG_STDERR, gettext(
43617Sdinak 		    "Unable to convert DSA private key value."));
43717Sdinak 		return (rv);
43817Sdinak 	}
43917Sdinak 	copy_bigint_to_attr(value, &(dsa_pri_attrs[i++]));
44017Sdinak 
44117Sdinak 	/* Indicates programming error:  attributes overran the template */
44217Sdinak 	if (i > count) {
44317Sdinak 		cryptodebug("error: more attributes found than accounted for");
44417Sdinak 		i = count;
44517Sdinak 	}
44617Sdinak 
44717Sdinak 	cryptodebug("calling C_CreateObject");
44817Sdinak 	if ((rv = C_CreateObject(sess, dsa_pri_attrs, i, &obj)) != CKR_OK) {
44917Sdinak 		cryptoerror(LOG_STDERR, gettext(
45017Sdinak 		    "Unable to create DSA private key object."));
45117Sdinak 		return (rv);
45217Sdinak 	}
45317Sdinak 
45417Sdinak 	return (CKR_OK);
45517Sdinak }
45617Sdinak 
45717Sdinak /*
45817Sdinak  * Write DH private key to token.
45917Sdinak  */
46017Sdinak static CK_RV
46117Sdinak write_dh_private(CK_SESSION_HANDLE sess, DH *dh, X509 *cert)
46217Sdinak {
46317Sdinak 	CK_RV		rv = CKR_OK;
46417Sdinak 	int		i = 0;
46517Sdinak 	static CK_OBJECT_CLASS	objclass = CKO_PRIVATE_KEY;
46617Sdinak 	static CK_KEY_TYPE	keytype = CKK_DH;
46717Sdinak 	CK_BYTE		*label = NULL;
46817Sdinak 	CK_ULONG	label_len = 0;
46917Sdinak 	CK_BYTE		*id = NULL;
47017Sdinak 	CK_ULONG	id_len = 0;
47117Sdinak 	CK_DATE		startdate = { "", "", "" };
47217Sdinak 	CK_DATE		enddate = { "", "", "" };
47317Sdinak 	char		tmpdate[8];
47417Sdinak 	biginteger_t	prime = { NULL, 0 };	/* required */
47517Sdinak 	biginteger_t	base = { NULL, 0 };	/* required */
47617Sdinak 	biginteger_t	value = { NULL, 0 };	/* required */
47717Sdinak 	CK_ATTRIBUTE	dh_pri_attrs[11] = {
47817Sdinak 		{ CKA_CLASS, &objclass, sizeof (objclass) },
47917Sdinak 		{ CKA_KEY_TYPE, &keytype, sizeof (keytype) },
48017Sdinak 		{ CKA_PRIVATE, &pk_true, sizeof (pk_true) },
48117Sdinak 		{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
48217Sdinak 		{ CKA_LABEL, NULL, 0 },
48317Sdinak 		{ CKA_ID, NULL, 0 },
48417Sdinak 		{ CKA_START_DATE, NULL, 0 },
48517Sdinak 		{ CKA_END_DATE, NULL, 0 },
48617Sdinak 		{ CKA_PRIME, NULL, 0 },
48717Sdinak 		{ CKA_BASE, NULL, 0 },
48817Sdinak 		{ CKA_VALUE, NULL, 0 }
48917Sdinak 	    };
49017Sdinak 	CK_ULONG	count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE);
49117Sdinak 	CK_OBJECT_HANDLE	obj;
49217Sdinak 
49317Sdinak 	cryptodebug("inside write_dh_private");
49417Sdinak 
49517Sdinak 	/* Attributes start at array index 4. */
49617Sdinak 	i = 4;
49717Sdinak 
49817Sdinak 	/* Recycle the certificate label for the private key label. */
49917Sdinak 	cryptodebug("calling X509_alias_get0");
50017Sdinak 	if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
50117Sdinak 		label = (CK_BYTE *)gettext("no label");
50217Sdinak 		label_len = strlen((char *)label);
50317Sdinak 	}
50417Sdinak 	copy_string_to_attr(label, label_len, &(dh_pri_attrs[i++]));
50517Sdinak 
50617Sdinak 	/* Recycle the certificate id for the private key id. */
50717Sdinak 	cryptodebug("PKTOOL_X509_keyid_get0");
50817Sdinak 	if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
50917Sdinak 		id = (CK_BYTE *)gettext("no id");
51017Sdinak 		id_len = strlen((char *)id);
51117Sdinak 	}
51217Sdinak 	copy_string_to_attr(id, id_len, &(dh_pri_attrs[i++]));
51317Sdinak 
51417Sdinak 	/* Recycle the certificate start and end dates for private key.  */
51517Sdinak 	cryptodebug("calling X509_get_notBefore");
51617Sdinak 	if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
51717Sdinak 		(void) memcpy(&startdate, tmpdate, sizeof (startdate));
51817Sdinak 		copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
51917Sdinak 		    &(dh_pri_attrs[i++]));
52017Sdinak 	}
52117Sdinak 
52217Sdinak 	cryptodebug("calling X509_get_notAfter");
52317Sdinak 	if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
52417Sdinak 		(void) memcpy(&enddate, tmpdate, sizeof (enddate));
52517Sdinak 		copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
52617Sdinak 		    &(dh_pri_attrs[i++]));
52717Sdinak 	}
52817Sdinak 
52917Sdinak 	/* Prime p */
53017Sdinak 	cryptodebug("converting DH private key prime");
53117Sdinak 	if ((rv = cvt_bn2bigint(dh->p, &prime)) != CKR_OK) {
53217Sdinak 		cryptoerror(LOG_STDERR, gettext(
53317Sdinak 		    "Unable to convert DH private key prime."));
53417Sdinak 		return (rv);
53517Sdinak 	}
53617Sdinak 	copy_bigint_to_attr(prime, &(dh_pri_attrs[i++]));
53717Sdinak 
53817Sdinak 	/* Base g */
53917Sdinak 	cryptodebug("converting DH private key base");
54017Sdinak 	if ((rv = cvt_bn2bigint(dh->g, &base)) != CKR_OK) {
54117Sdinak 		cryptoerror(LOG_STDERR, gettext(
54217Sdinak 		    "Unable to convert DH private key base."));
54317Sdinak 		return (rv);
54417Sdinak 	}
54517Sdinak 	copy_bigint_to_attr(base, &(dh_pri_attrs[i++]));
54617Sdinak 
54717Sdinak 	/* Private value x */
54817Sdinak 	cryptodebug("converting DH private key value");
54917Sdinak 	if ((rv = cvt_bn2bigint(dh->priv_key, &value)) != CKR_OK) {
55017Sdinak 		cryptoerror(LOG_STDERR, gettext(
55117Sdinak 		    "Unable to convert DH private key value."));
55217Sdinak 		return (rv);
55317Sdinak 	}
55417Sdinak 	copy_bigint_to_attr(value, &(dh_pri_attrs[i++]));
55517Sdinak 
55617Sdinak 	/* Indicates programming error:  attributes overran the template */
55717Sdinak 	if (i > count) {
55817Sdinak 		cryptodebug("error: more attributes found than accounted for");
55917Sdinak 		i = count;
56017Sdinak 	}
56117Sdinak 
56217Sdinak 	cryptodebug("calling C_CreateObject");
56317Sdinak 	if ((rv = C_CreateObject(sess, dh_pri_attrs, i, &obj)) != CKR_OK) {
56417Sdinak 		cryptoerror(LOG_STDERR, gettext(
56517Sdinak 		    "Unable to create DH private key object."));
56617Sdinak 		return (rv);
56717Sdinak 	}
56817Sdinak 
56917Sdinak 	return (CKR_OK);
57017Sdinak }
57117Sdinak 
57217Sdinak /*
57317Sdinak  * Write certificate to token.
57417Sdinak  */
57517Sdinak static CK_RV
57617Sdinak write_cert(CK_SESSION_HANDLE sess, X509 *cert)
57717Sdinak {
57817Sdinak 	CK_RV		rv = CKR_OK;
57917Sdinak 	int		i = 0;
58017Sdinak 	static CK_OBJECT_CLASS	objclass = CKO_CERTIFICATE;
58117Sdinak 	static CK_CERTIFICATE_TYPE	certtype = CKC_X_509;
58217Sdinak 	CK_BYTE		*subject = NULL;
58317Sdinak 	CK_ULONG	subject_len = 0;
58417Sdinak 	CK_BYTE		*value = NULL;
58517Sdinak 	CK_ULONG	value_len = 0;
58617Sdinak 	CK_BYTE		*label = NULL;
58717Sdinak 	CK_ULONG	label_len = 0;
58817Sdinak 	CK_BYTE		*id = NULL;
58917Sdinak 	CK_ULONG	id_len = 0;
59017Sdinak 	CK_BYTE		*issuer = NULL;
59117Sdinak 	CK_ULONG	issuer_len = 0;
59217Sdinak 	CK_BYTE		*serial = NULL;
59317Sdinak 	CK_ULONG	serial_len = 0;
59417Sdinak 	CK_ATTRIBUTE	cert_attrs[9] = {
59517Sdinak 		{ CKA_CLASS, &objclass, sizeof (objclass) },
59617Sdinak 		{ CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) },
59717Sdinak 		{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
59817Sdinak 		{ CKA_SUBJECT, NULL, 0 },		/* required */
59917Sdinak 		{ CKA_VALUE, NULL, 0 },			/* required */
60017Sdinak 		{ 0 /* CKA_LABEL */, NULL, 0 },		/* optional */
60117Sdinak 		{ 0 /* CKA_ID */, NULL, 0 },		/* optional */
60217Sdinak 		{ 0 /* CKA_ISSUER */, NULL, 0 },	/* optional */
60317Sdinak 		{ 0 /* CKA_SERIAL_NUMBER */, NULL, 0 }	/* optional */
60417Sdinak 	    };
60517Sdinak 	CK_ULONG	count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE);
60617Sdinak 	CK_OBJECT_HANDLE	obj;
60717Sdinak 
60817Sdinak 	cryptodebug("inside write_cert");
60917Sdinak 
61017Sdinak 	/* Attributes start at array index 3. */
61117Sdinak 	i = 3;
61217Sdinak 
61317Sdinak 	/*
61417Sdinak 	 * OpenSSL subject name and issuer (a little further below) are
61517Sdinak 	 * actually stack structures that contain individual ASN.1
61617Sdinak 	 * components.  This stack of entries is packed into one DER string.
61717Sdinak 	 */
61817Sdinak 	cryptodebug("calling PKTOOL_X509_subject_name");
61917Sdinak 	if ((subject = PKTOOL_X509_subject_name(cert, (int *)&subject_len)) ==
62017Sdinak 	    NULL) {
62117Sdinak 		subject = (CK_BYTE *)gettext("no subject name");
62217Sdinak 		subject_len = strlen((char *)subject);
62317Sdinak 	}
62417Sdinak 	copy_string_to_attr(subject, subject_len, &(cert_attrs[i++]));
62517Sdinak 
62617Sdinak 	/* Get cert value, but it has to be reconstructed from cert.  */
62717Sdinak 	cryptodebug("calling PKTOOL_X509_cert_value");
62817Sdinak 	if ((value = PKTOOL_X509_cert_value(cert, (int *)&value_len)) == NULL) {
62917Sdinak 		value = (CK_BYTE *)gettext("no value");
63017Sdinak 		value_len = strlen((char *)value);
63117Sdinak 	}
63217Sdinak 	copy_string_to_attr(value, value_len, &(cert_attrs[i++]));
63317Sdinak 
63417Sdinak 	/*
63517Sdinak 	 * Get certificate label which is "friendlyName" Netscape,
63617Sdinak 	 * "alias" in OpenSSL.
63717Sdinak 	 */
63817Sdinak 	if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
63917Sdinak 		cryptodebug("no certificate label");
64017Sdinak 	} else {
64117Sdinak 		cert_attrs[i].type = CKA_LABEL;
64217Sdinak 		copy_string_to_attr(label, label_len, &(cert_attrs[i++]));
64317Sdinak 	}
64417Sdinak 
64517Sdinak 	/* Get the keyid for the cert. */
64617Sdinak 	if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
64717Sdinak 		cryptodebug("no certificate id");
64817Sdinak 	} else {
64917Sdinak 		cert_attrs[i].type = CKA_ID;
65017Sdinak 		copy_string_to_attr(id, id_len, &(cert_attrs[i++]));
65117Sdinak 	}
65217Sdinak 
65317Sdinak 	/* Get the issuer name for the cert. */
65417Sdinak 	if ((issuer = PKTOOL_X509_issuer_name(cert, (int *)&issuer_len)) ==
65517Sdinak 	    NULL) {
65617Sdinak 		cryptodebug("no certificate issuer name");
65717Sdinak 	} else {
65817Sdinak 		cert_attrs[i].type = CKA_ISSUER;
65917Sdinak 		copy_string_to_attr(issuer, issuer_len, &(cert_attrs[i++]));
66017Sdinak 	}
66117Sdinak 
66217Sdinak 	/* Get the cert serial number. */
66317Sdinak 	if ((serial  = PKTOOL_X509_serial_number(cert, (int *)&serial_len)) ==
66417Sdinak 	    NULL) {
66517Sdinak 		cryptodebug("no certificate serial number");
66617Sdinak 	} else {
66717Sdinak 		cert_attrs[i].type = CKA_SERIAL_NUMBER;
66817Sdinak 		copy_string_to_attr(serial, serial_len, &(cert_attrs[i++]));
66917Sdinak 	}
67017Sdinak 
67117Sdinak 	/* Indicates programming error:  attributes overran the template */
67217Sdinak 	if (i > count) {
67317Sdinak 		cryptodebug("error: more attributes found than accounted for");
67417Sdinak 		i = count;
67517Sdinak 	}
67617Sdinak 
67717Sdinak 	cryptodebug("calling C_CreateObject");
67817Sdinak 	if ((rv = C_CreateObject(sess, cert_attrs, i, &obj)) != CKR_OK) {
67917Sdinak 		cryptoerror(LOG_STDERR, gettext(
68017Sdinak 		    "Unable to create X.509 certificate object."));
68117Sdinak 		return (rv);
68217Sdinak 	}
68317Sdinak 
68417Sdinak 	return (CKR_OK);
68517Sdinak }
68617Sdinak 
68717Sdinak /*
68817Sdinak  * Helper function to write PKCS#12 items to token.  Returns CKR_OK
68917Sdinak  * or CKR_GENERAL_ERROR
69017Sdinak  */
69117Sdinak static CK_RV
69217Sdinak write_token_objs(CK_SESSION_HANDLE sess, EVP_PKEY *priv_key, X509 *cert,
69317Sdinak 	    STACK_OF(X509) *ca, int *successes, int *failures)
69417Sdinak {
69517Sdinak 	int		i;
69617Sdinak 	X509		*c;
69717Sdinak 	CK_RV		rv = CKR_OK;
69817Sdinak 
69917Sdinak 	cryptodebug("inside write_token_objs");
70017Sdinak 
70117Sdinak 	/* Do not reset *successes or *failures -- keep running totals. */
70217Sdinak 
70317Sdinak 	/* Import user key. */
70417Sdinak 	switch (priv_key->type) {
70517Sdinak 	case EVP_PKEY_RSA:
70617Sdinak 		(void) fprintf(stdout, gettext("Writing RSA private key...\n"));
70717Sdinak 		if ((rv = write_rsa_private(sess,
70817Sdinak 		    EVP_PKEY_get1_RSA(priv_key), cert)) != CKR_OK) {
70917Sdinak 			cryptoerror(LOG_STDERR, gettext(
71017Sdinak 			    "Unable to write RSA private key (%s)."),
71117Sdinak 			    pkcs11_strerror(rv));
71217Sdinak 			(*failures)++;
71317Sdinak 		} else
71417Sdinak 			(*successes)++;
71517Sdinak 		break;
71617Sdinak 	case EVP_PKEY_DSA:
71717Sdinak 		(void) fprintf(stdout, gettext("Writing DSA private key...\n"));
71817Sdinak 		if ((rv = write_dsa_private(sess,
71917Sdinak 		    EVP_PKEY_get1_DSA(priv_key), cert)) != CKR_OK) {
72017Sdinak 			cryptoerror(LOG_STDERR, gettext(
72117Sdinak 			    "Unable to write DSA private key (%s)."),
72217Sdinak 			    pkcs11_strerror(rv));
72317Sdinak 			(*failures)++;
72417Sdinak 		} else
72517Sdinak 			(*successes)++;
72617Sdinak 		break;
72717Sdinak 	case EVP_PKEY_DH:
72817Sdinak 		(void) fprintf(stdout, gettext("Writing DH private key...\n"));
72917Sdinak 		if ((rv = write_dh_private(sess,
73017Sdinak 		    EVP_PKEY_get1_DH(priv_key), cert)) != CKR_OK) {
73117Sdinak 			cryptoerror(LOG_STDERR, gettext(
73217Sdinak 			    "Unable to write DH private key (%s)."),
73317Sdinak 			    pkcs11_strerror(rv));
73417Sdinak 			(*failures)++;
73517Sdinak 		} else
73617Sdinak 			(*successes)++;
73717Sdinak 		break;
73817Sdinak 
73917Sdinak 	default:
74017Sdinak 		/*
74117Sdinak 		 * Note that EVP_PKEY_DH for X9.42 is not implemented
74217Sdinak 		 * in the OpenSSL library.
74317Sdinak 		 */
74417Sdinak 		cryptoerror(LOG_STDERR, gettext(
74517Sdinak 		    "Private key type 0x%02x import not supported."),
74617Sdinak 		    priv_key->type);
74717Sdinak 		(*failures)++;
74817Sdinak 		break;
74917Sdinak 	}
75017Sdinak 
75117Sdinak 	/* Import user certificate. */
75217Sdinak 	(void) fprintf(stdout, gettext("Writing user certificate...\n"));
75317Sdinak 	if ((rv = write_cert(sess, cert)) != CKR_OK) {
75417Sdinak 		cryptoerror(LOG_STDERR, gettext(
75517Sdinak 		    "Unable to write user certificate (%s)."),
75617Sdinak 		    pkcs11_strerror(rv));
75717Sdinak 		(*failures)++;
75817Sdinak 	} else
75917Sdinak 		(*successes)++;
76017Sdinak 
76117Sdinak 	/* Import as many stacks of authority certificates as possible. */
76217Sdinak 	for (i = 0; i != sk_X509_num(ca); i++) {
76317Sdinak 		/*
76417Sdinak 		 * sk_X509_value() is macro that embeds a cast to (X509 *).
76517Sdinak 		 * Here it translates into ((X509 *)sk_value((ca), (i))).
76617Sdinak 		 * Lint is complaining about the embedded casting, and
76717Sdinak 		 * to fix it, you need to fix openssl header files.
76817Sdinak 		 */
76917Sdinak 		/* LINTED E_BAD_PTR_CAST_ALIGN */
77017Sdinak 		c = sk_X509_value(ca, i);
77117Sdinak 		(void) fprintf(stdout, gettext(
77217Sdinak 		    "Writing authority certificate...\n"));
77317Sdinak 		if ((rv = write_cert(sess, c)) != CKR_OK) {
77417Sdinak 			cryptoerror(LOG_STDERR, gettext(
77517Sdinak 			    "Unable to write authority certificate (%s)."),
77617Sdinak 			    pkcs11_strerror(rv));
77717Sdinak 			(*failures)++;
77817Sdinak 		} else
77917Sdinak 			(*successes)++;
78017Sdinak 	}
78117Sdinak 
78217Sdinak 	(void) fprintf(stdout, gettext("PKCS#12 element scan completed.\n"));
78317Sdinak 	return (*failures != 0 ? CKR_GENERAL_ERROR : CKR_OK);
78417Sdinak }
78517Sdinak 
78617Sdinak /*
78717Sdinak  * Import objects from PKCS#12 file into token.
78817Sdinak  */
78917Sdinak int
79017Sdinak pk_import(int argc, char *argv[])
79117Sdinak {
792*864Sdinak 	int		opt;
793*864Sdinak 	extern int	optind_av;
794*864Sdinak 	extern char	*optarg_av;
795*864Sdinak 	char		*token_spec = NULL;
79617Sdinak 	char		*token_name = NULL;
79717Sdinak 	char		*manuf_id = NULL;
79817Sdinak 	char		*serial_no = NULL;
79917Sdinak 	char		full_name[FULL_NAME_LEN];
80017Sdinak 	char		*filename = NULL;
80117Sdinak 	struct stat	statbuf;
80217Sdinak 	CK_SLOT_ID	slot_id;
80317Sdinak 	CK_FLAGS	pin_state;
80417Sdinak 	CK_UTF8CHAR_PTR	pin = NULL;
80517Sdinak 	CK_ULONG	pinlen = 0;
80617Sdinak 	CK_UTF8CHAR_PTR	pk12pin = NULL;
80717Sdinak 	CK_ULONG	pk12pinlen = 0;
80817Sdinak 	CK_SESSION_HANDLE	sess;
80917Sdinak 	BIO		*fbio = NULL;
81017Sdinak 	EVP_PKEY	*priv_key = NULL;
81117Sdinak 	X509		*cert = NULL;
81217Sdinak 	STACK_OF(X509)	*ca = NULL;
81317Sdinak 	CK_RV		rv = CKR_OK;
81417Sdinak 	int		i;
81517Sdinak 	int		good_count = 0, bad_count = 0;	/* running totals */
81617Sdinak 
81717Sdinak 	cryptodebug("inside pk_import");
81817Sdinak 
819*864Sdinak 	/* Parse command line options.  Do NOT i18n/l10n. */
820*864Sdinak 	while ((opt = getopt_av(argc, argv, "T:(token)i:(infile)")) != EOF) {
821*864Sdinak 		switch (opt) {
822*864Sdinak 		case 'T':	/* token specifier */
823*864Sdinak 			if (token_spec)
824*864Sdinak 				return (PK_ERR_USAGE);
825*864Sdinak 			token_spec = optarg_av;
826*864Sdinak 			break;
827*864Sdinak 		case 'i':	/* input file name */
828*864Sdinak 			if (filename)
829*864Sdinak 				return (PK_ERR_USAGE);
830*864Sdinak 			filename = optarg_av;
831*864Sdinak 			break;
832*864Sdinak 		default:
833*864Sdinak 			return (PK_ERR_USAGE);
834*864Sdinak 			break;
835*864Sdinak 		}
836*864Sdinak 	}
83717Sdinak 
838*864Sdinak 	/* If nothing is specified, default is to use softtoken. */
839*864Sdinak 	if (token_spec == NULL) {
840*864Sdinak 		token_name = SOFT_TOKEN_LABEL;
841*864Sdinak 		manuf_id = SOFT_MANUFACTURER_ID;
842*864Sdinak 		serial_no = SOFT_TOKEN_SERIAL;
843*864Sdinak 	} else {
844*864Sdinak 		/*
845*864Sdinak 		 * Parse token specifier into token_name, manuf_id, serial_no.
846*864Sdinak 		 * Token_name is required; manuf_id and serial_no are optional.
847*864Sdinak 		 */
848*864Sdinak 		if (parse_token_spec(token_spec, &token_name, &manuf_id,
849*864Sdinak 		    &serial_no) < 0)
850*864Sdinak 			return (PK_ERR_USAGE);
851*864Sdinak 	}
852*864Sdinak 
853*864Sdinak 	/* Filename arg is required. */
854*864Sdinak 	if (filename == NULL)
85517Sdinak 		return (PK_ERR_USAGE);
85617Sdinak 
857*864Sdinak 	/* No additional args allowed. */
858*864Sdinak 	argc -= optind_av;
859*864Sdinak 	argv += optind_av;
860*864Sdinak 	if (argc)
861*864Sdinak 		return (PK_ERR_USAGE);
86217Sdinak 	/* Done parsing command line options. */
86317Sdinak 
86417Sdinak 	/* Check that the file exists and is non-empty. */
86517Sdinak 	if (access(filename, R_OK) < 0) {
86617Sdinak 		cryptoerror(LOG_STDERR, gettext("File \"%s\" is unreadable "
86717Sdinak 		    "(%s)."), filename, strerror(errno));
86817Sdinak 		return (CKR_OK);
86917Sdinak 	}
87017Sdinak 	if (stat(filename, &statbuf) < 0) {
87117Sdinak 		cryptoerror(LOG_STDERR, gettext("Unable to get size of "
87217Sdinak 		    "file \"%s\" (%s)."), filename, strerror(errno));
87317Sdinak 		return (CKR_OK);
87417Sdinak 	}
87517Sdinak 	if (statbuf.st_size == 0) {
87617Sdinak 		cryptoerror(LOG_STDERR, gettext("File \"%s\" is empty."),
87717Sdinak 		    filename);
87817Sdinak 		return (CKR_OK);
87917Sdinak 	}
88017Sdinak 
88117Sdinak 	full_token_name(token_name, manuf_id, serial_no, full_name);
88217Sdinak 
88317Sdinak 	/* Find the slot with token. */
88417Sdinak 	if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
88517Sdinak 	    &pin_state)) != CKR_OK) {
88617Sdinak 		cryptoerror(LOG_STDERR, gettext(
88717Sdinak 		    "Unable to find token %s (%s)."), full_name,
88817Sdinak 		    pkcs11_strerror(rv));
88917Sdinak 		return (PK_ERR_PK11);
89017Sdinak 	}
89117Sdinak 
89217Sdinak 	/* Get the user's PIN. */
89317Sdinak 	if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
89417Sdinak 	    &pinlen)) != CKR_OK) {
89517Sdinak 		cryptoerror(LOG_STDERR, gettext(
89617Sdinak 		    "Unable to get token passphrase (%s)."),
89717Sdinak 		    pkcs11_strerror(rv));
89817Sdinak 		quick_finish(NULL);
89917Sdinak 		return (PK_ERR_PK11);
90017Sdinak 	}
90117Sdinak 
90217Sdinak 	/* Assume user must be logged in R/W to import objects into token. */
90317Sdinak 	if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
90417Sdinak 	    CKR_OK) {
90517Sdinak 		cryptoerror(LOG_STDERR,
90617Sdinak 		    gettext("Unable to log into token (%s)."),
90717Sdinak 		    pkcs11_strerror(rv));
90817Sdinak 		quick_finish(sess);
90917Sdinak 		return (PK_ERR_PK11);
91017Sdinak 	}
91117Sdinak 
91217Sdinak 	/* Setup OpenSSL context. */
91317Sdinak 	PKTOOL_setup_openssl();
91417Sdinak 
91517Sdinak 	/* Open PKCS#12 file. */
91617Sdinak 	if ((open_pkcs12(filename, &fbio)) < 0) {
91717Sdinak 		cryptoerror(LOG_STDERR, gettext("Unable to open import file."));
91817Sdinak 		quick_finish(sess);
91917Sdinak 		return (PK_ERR_SYSTEM);
92017Sdinak 	}
92117Sdinak 
92217Sdinak 	/* Get the PIN for the PKCS#12 import file. */
92317Sdinak 	if ((rv = get_pin(gettext("Enter import file passphrase:"), NULL,
92417Sdinak 	    &pk12pin, &pk12pinlen)) != CKR_OK) {
92517Sdinak 		cryptoerror(LOG_STDERR, gettext(
92617Sdinak 		    "Unable to get import file passphrase (%s)."),
92717Sdinak 		    pkcs11_strerror(rv));
92817Sdinak 		close_pkcs12(fbio);
92917Sdinak 		quick_finish(sess);
93017Sdinak 		return (PK_ERR_PK11);
93117Sdinak 	}
93217Sdinak 
93317Sdinak 	/* PKCS#12 import file may have multiple elements, loop until done. */
93417Sdinak 	for (i = 0; /* */; i++) {
93517Sdinak 		/* Extract the contents of the PKCS#12 import file. */
93617Sdinak 		if ((rv = extract_pkcs12(fbio, pk12pin, pk12pinlen, &priv_key,
93717Sdinak 		    &cert, &ca)) != CKR_OK) {
93817Sdinak 			cryptoerror(LOG_STDERR, gettext(
93917Sdinak 			    "Unable to parse PKCS#12 element #%d "
94017Sdinak 			    "in import file (%s)."), i+1, pkcs11_strerror(rv));
94117Sdinak 			close_pkcs12(fbio);
94217Sdinak 			quick_finish(sess);
94317Sdinak 			return (PK_ERR_OPENSSL);
94417Sdinak 		}
94517Sdinak 
94617Sdinak 		/* Reached end of import file? */
94717Sdinak 		if (rv == CKR_OK && priv_key == NULL && cert == NULL &&
94817Sdinak 		    ca == NULL)
94917Sdinak 			break;
95017Sdinak 
95117Sdinak 		(void) fprintf(stdout, gettext(
95217Sdinak 		    "Scanning PKCS#12 element #%d for objects...\n"), i+1);
95317Sdinak 
95417Sdinak 		/* Write the objects to the token. */
95517Sdinak 		if ((rv = write_token_objs(sess, priv_key, cert, ca,
95617Sdinak 		    &good_count, &bad_count)) != CKR_OK) {
95717Sdinak 			cryptoerror(LOG_STDERR, gettext(
95817Sdinak 			    "Unable to write PKCS#12 element #%d to token %s."),
95917Sdinak 			    i+1, full_name);
96017Sdinak 			close_pkcs12(fbio);
96117Sdinak 			quick_finish(sess);
96217Sdinak 			return (PK_ERR_PK11);
96317Sdinak 		}
96417Sdinak 	}
96517Sdinak 
96617Sdinak 	(void) fprintf(stdout, gettext("%d PKCS#12 elements scanned: "
96717Sdinak 		"%d objects imported, %d errors occurred.\n"), i,
96817Sdinak 		good_count, bad_count);
96917Sdinak 
97017Sdinak 	/* Close PKCS#12 file. */
97117Sdinak 	close_pkcs12(fbio);
97217Sdinak 
97317Sdinak 	/* Clean up. */
97417Sdinak 	quick_finish(sess);
97517Sdinak 	return (0);
97617Sdinak }
977