import.c revision 7711facfe58561dd91d6ece0f5f41150c3956c83
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 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 <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <cryptoutil.h>
#include <security/cryptoki.h>
#include "common.h"
#include "biginteger.h"
#include "osslcommon.h"
#include "p12common.h"
#include <openssl/pkcs12.h>
#include <openssl/err.h>
/*
* Helper function decrypt and parse PKCS#12 import file.
*/
static CK_RV
extract_pkcs12(BIO *fbio, CK_UTF8CHAR *pin, CK_ULONG pinlen,
EVP_PKEY **priv_key, X509 **cert, STACK_OF(X509) **ca)
/* ARGSUSED */
{
PKCS12 *pk12, *pk12_tmp;
EVP_PKEY *temp_pkey = NULL;
X509 *temp_cert = NULL;
STACK_OF(X509) *temp_ca = NULL;
cryptodebug("inside extract_pkcs12");
cryptodebug("calling PKCS12_new");
if ((pk12 = PKCS12_new()) == NULL) {
cryptoerror(LOG_STDERR, gettext(
"Unable to create PKCS#12 context."));
return (CKR_GENERAL_ERROR);
}
cryptodebug("calling d2i_PKCS12_bio");
if ((pk12_tmp = d2i_PKCS12_bio(fbio, &pk12)) == NULL) {
/* This is ok; it seems to mean there is no more to read. */
if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_ASN1 &&
ERR_GET_REASON(ERR_peek_error()) == ASN1_R_HEADER_TOO_LONG)
goto end_extract_pkcs12;
cryptoerror(LOG_STDERR, gettext(
"Unable to populate PKCS#12 context."));
PKCS12_free(pk12);
return (CKR_GENERAL_ERROR);
}
pk12 = pk12_tmp;
cryptodebug("calling PKCS12_parse");
if (PKCS12_parse(pk12, (char *)pin, &temp_pkey, &temp_cert,
&temp_ca) <= 0) {
cryptoerror(LOG_STDERR,
gettext("Unable to parse import file."));
PKCS12_free(pk12);
return (CKR_GENERAL_ERROR);
}
end_extract_pkcs12:
*priv_key = temp_pkey;
*cert = temp_cert;
*ca = temp_ca;
PKCS12_free(pk12);
return (CKR_OK);
}
/*
* Converts OpenSSL BIGNUM into PKCS#11 biginteger_t format.
*/
static CK_RV
cvt_bn2bigint(BIGNUM *from, biginteger_t *to)
{
CK_BYTE *temp;
CK_ULONG temp_alloc_sz, temp_cvt_sz;
cryptodebug("inside cvt_bn2bigint");
if (from == NULL || to == NULL)
return (CKR_ARGUMENTS_BAD);
cryptodebug("calling BN_num_bytes");
temp_alloc_sz = BN_num_bytes(from);
if ((temp = malloc(temp_alloc_sz)) == NULL)
return (CKR_HOST_MEMORY);
cryptodebug("calling BN_bn2bin");
temp_cvt_sz = BN_bn2bin(from, (unsigned char *)temp);
if (temp_cvt_sz != temp_alloc_sz)
return (CKR_GENERAL_ERROR);
to->big_value = temp;
to->big_value_len = temp_cvt_sz;
return (CKR_OK);
}
/*
* Write RSA private key to token.
*/
static CK_RV
write_rsa_private(CK_SESSION_HANDLE sess, RSA *rsa, X509 *cert)
{
CK_RV rv = CKR_OK;
int i = 0;
static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
static CK_KEY_TYPE keytype = CKK_RSA;
CK_BYTE *label = NULL;
CK_ULONG label_len = 0;
CK_BYTE *id = NULL;
CK_ULONG id_len = 0;
CK_DATE startdate = { "", "", "" };
CK_DATE enddate = { "", "", "" };
char tmpdate[8];
biginteger_t mod = { NULL, 0 }; /* required */
biginteger_t pubexp = { NULL, 0 }; /* required */
biginteger_t priexp = { NULL, 0 }; /* optional */
biginteger_t prime1 = { NULL, 0 }; /* optional */
biginteger_t prime2 = { NULL, 0 }; /* optional */
biginteger_t exp1 = { NULL, 0 }; /* optional */
biginteger_t exp2 = { NULL, 0 }; /* optional */
biginteger_t coef = { NULL, 0 }; /* optional */
CK_ATTRIBUTE rsa_pri_attrs[16] = {
{ CKA_CLASS, &objclass, sizeof (objclass) },
{ CKA_KEY_TYPE, &keytype, sizeof (keytype) },
{ CKA_PRIVATE, &pk_true, sizeof (pk_true) },
{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
{ CKA_LABEL, NULL, 0 },
{ CKA_ID, NULL, 0 },
{ CKA_START_DATE, NULL, 0 },
{ CKA_END_DATE, NULL, 0 },
{ CKA_MODULUS, NULL, 0 },
{ CKA_PUBLIC_EXPONENT, NULL, 0 },
{ 0 /* CKA_PRIVATE_EXPONENT */, NULL, 0 }, /* optional */
{ 0 /* CKA_PRIME_1 */, NULL, 0 }, /* | */
{ 0 /* CKA_PRIME_2 */, NULL, 0 }, /* | */
{ 0 /* CKA_EXPONENT_1 */, NULL, 0 }, /* | */
{ 0 /* CKA_EXPONENT_2 */, NULL, 0 }, /* | */
{ 0 /* CKA_COEFFICIENT */, NULL, 0 } /* V */
};
CK_ULONG count = sizeof (rsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
CK_OBJECT_HANDLE obj;
cryptodebug("inside write_rsa_private");
/* Attributes start at array index 4. */
i = 4;
/* Recycle the certificate label for the private key label. */
cryptodebug("calling X509_alias_get0");
if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
label = (CK_BYTE *)gettext("no label");
label_len = strlen((char *)label);
}
copy_string_to_attr(label, label_len, &(rsa_pri_attrs[i++]));
/* Recycle the certificate id for the private key id. */
cryptodebug("calling PKTOOL_X509_keyid_get0");
if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
id = (CK_BYTE *)gettext("no id");
id_len = strlen((char *)id);
}
copy_string_to_attr(id, id_len, &(rsa_pri_attrs[i++]));
/* Recycle the certificate start and end dates for private key. */
cryptodebug("calling X509_get_notBefore");
if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
(void) memcpy(&startdate, tmpdate, sizeof (startdate));
copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
&(rsa_pri_attrs[i++]));
}
cryptodebug("calling X509_get_notAfter");
if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
(void) memcpy(&enddate, tmpdate, sizeof (enddate));
copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
&(rsa_pri_attrs[i++]));
}
/* Modulus n */
cryptodebug("converting RSA private key modulus");
if ((rv = cvt_bn2bigint(rsa->n, &mod)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert RSA private key modulus."));
return (rv);
}
copy_bigint_to_attr(mod, &(rsa_pri_attrs[i++]));
/* Public exponent e */
cryptodebug("converting RSA private key public exponent");
if ((rv = cvt_bn2bigint(rsa->e, &pubexp)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert RSA private key public exponent."));
return (rv);
}
copy_bigint_to_attr(pubexp, &(rsa_pri_attrs[i++]));
/* Private exponent d */
if (rsa->d != NULL) {
cryptodebug("converting RSA private key private exponent");
if ((rv = cvt_bn2bigint(rsa->d, &priexp)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext("Unable to convert "
"RSA private key private exponent."));
return (rv);
}
rsa_pri_attrs[i].type = CKA_PRIVATE_EXPONENT;
copy_bigint_to_attr(priexp, &(rsa_pri_attrs[i++]));
} else
cryptodebug("no RSA private key private exponent");
/* Prime p */
if (rsa->p != NULL) {
cryptodebug("converting RSA private key prime 1");
if ((rv = cvt_bn2bigint(rsa->p, &prime1)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert RSA private key prime 1."));
return (rv);
}
rsa_pri_attrs[i].type = CKA_PRIME_1;
copy_bigint_to_attr(prime1, &(rsa_pri_attrs[i++]));
} else
cryptodebug("no RSA private key prime 1");
/* Prime q */
if (rsa->q != NULL) {
cryptodebug("converting RSA private key prime 2");
if ((rv = cvt_bn2bigint(rsa->q, &prime2)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert RSA private key prime 2."));
return (rv);
}
rsa_pri_attrs[i].type = CKA_PRIME_2;
copy_bigint_to_attr(prime2, &(rsa_pri_attrs[i++]));
} else
cryptodebug("no RSA private key prime 2");
/* Private exponent d modulo p-1 */
if (rsa->dmp1 != NULL) {
cryptodebug("converting RSA private key exponent 1");
if ((rv = cvt_bn2bigint(rsa->dmp1, &exp1)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert RSA private key exponent 1."));
return (rv);
}
rsa_pri_attrs[i].type = CKA_EXPONENT_1;
copy_bigint_to_attr(exp1, &(rsa_pri_attrs[i++]));
} else
cryptodebug("no RSA private key exponent 1");
/* Private exponent d modulo q-1 */
if (rsa->dmq1 != NULL) {
cryptodebug("converting RSA private key exponent 2");
if ((rv = cvt_bn2bigint(rsa->dmq1, &exp2)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert RSA private key exponent 2."));
return (rv);
}
rsa_pri_attrs[i].type = CKA_EXPONENT_2;
copy_bigint_to_attr(exp2, &(rsa_pri_attrs[i++]));
} else
cryptodebug("no RSA private key exponent 2");
/* CRT coefficient q-inverse mod p */
if (rsa->iqmp != NULL) {
cryptodebug("converting RSA private key coefficient");
if ((rv = cvt_bn2bigint(rsa->iqmp, &coef)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert RSA private key coefficient."));
return (rv);
}
rsa_pri_attrs[i].type = CKA_COEFFICIENT;
copy_bigint_to_attr(coef, &(rsa_pri_attrs[i++]));
} else
cryptodebug("no RSA private key coefficient");
/* Indicates programming error: attributes overran the template */
if (i > count) {
cryptodebug("error: more attributes found than accounted for");
i = count;
}
cryptodebug("calling C_CreateObject");
if ((rv = C_CreateObject(sess, rsa_pri_attrs, i, &obj)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to create RSA private key object."));
return (rv);
}
return (CKR_OK);
}
/*
* Write DSA private key to token.
*/
static CK_RV
write_dsa_private(CK_SESSION_HANDLE sess, DSA *dsa, X509 *cert)
{
CK_RV rv = CKR_OK;
int i = 0;
static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
static CK_KEY_TYPE keytype = CKK_DSA;
CK_BYTE *label = NULL;
CK_ULONG label_len = 0;
CK_BYTE *id = NULL;
CK_ULONG id_len = 0;
CK_DATE startdate = { "", "", "" };
CK_DATE enddate = { "", "", "" };
char tmpdate[8];
biginteger_t prime = { NULL, 0 }; /* required */
biginteger_t subprime = { NULL, 0 }; /* required */
biginteger_t base = { NULL, 0 }; /* required */
biginteger_t value = { NULL, 0 }; /* required */
CK_ATTRIBUTE dsa_pri_attrs[12] = {
{ CKA_CLASS, &objclass, sizeof (objclass) },
{ CKA_KEY_TYPE, &keytype, sizeof (keytype) },
{ CKA_PRIVATE, &pk_true, sizeof (pk_true) },
{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
{ CKA_LABEL, NULL, 0 },
{ CKA_ID, NULL, 0 },
{ CKA_START_DATE, NULL, 0 },
{ CKA_END_DATE, NULL, 0 },
{ CKA_PRIME, NULL, 0 },
{ CKA_SUBPRIME, NULL, 0 },
{ CKA_BASE, NULL, 0 },
{ CKA_VALUE, NULL, 0 }
};
CK_ULONG count = sizeof (dsa_pri_attrs) / sizeof (CK_ATTRIBUTE);
CK_OBJECT_HANDLE obj;
cryptodebug("inside write_dsa_private");
/* Attributes start at array index 4. */
i = 4;
/* Recycle the certificate label for the private key label. */
cryptodebug("calling X509_alias_get0");
if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
label = (CK_BYTE *)gettext("no label");
label_len = strlen((char *)label);
}
copy_string_to_attr(label, label_len, &(dsa_pri_attrs[i++]));
/* Recycle the certificate id for the private key id. */
cryptodebug("calling PKTOOL_X509_keyid_get0");
if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
id = (CK_BYTE *)gettext("no id");
id_len = strlen((char *)id);
}
copy_string_to_attr(id, id_len, &(dsa_pri_attrs[i++]));
/* Recycle the certificate start and end dates for private key. */
cryptodebug("calling X509_get_notBefore");
if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
(void) memcpy(&startdate, tmpdate, sizeof (startdate));
copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
&(dsa_pri_attrs[i++]));
}
cryptodebug("calling X509_get_notAfter");
if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
(void) memcpy(&enddate, tmpdate, sizeof (enddate));
copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
&(dsa_pri_attrs[i++]));
}
/* Prime p */
cryptodebug("converting DSA private key prime");
if ((rv = cvt_bn2bigint(dsa->p, &prime)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert DSA private key prime."));
return (rv);
}
copy_bigint_to_attr(prime, &(dsa_pri_attrs[i++]));
/* Subprime q */
cryptodebug("converting DSA private key subprime");
if ((rv = cvt_bn2bigint(dsa->q, &subprime)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert DSA private key subprime."));
return (rv);
}
copy_bigint_to_attr(subprime, &(dsa_pri_attrs[i++]));
/* Base g */
cryptodebug("converting DSA private key base");
if ((rv = cvt_bn2bigint(dsa->g, &base)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert DSA private key base."));
return (rv);
}
copy_bigint_to_attr(base, &(dsa_pri_attrs[i++]));
/* Private key x */
cryptodebug("converting DSA private key value");
if ((rv = cvt_bn2bigint(dsa->priv_key, &value)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert DSA private key value."));
return (rv);
}
copy_bigint_to_attr(value, &(dsa_pri_attrs[i++]));
/* Indicates programming error: attributes overran the template */
if (i > count) {
cryptodebug("error: more attributes found than accounted for");
i = count;
}
cryptodebug("calling C_CreateObject");
if ((rv = C_CreateObject(sess, dsa_pri_attrs, i, &obj)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to create DSA private key object."));
return (rv);
}
return (CKR_OK);
}
/*
* Write DH private key to token.
*/
static CK_RV
write_dh_private(CK_SESSION_HANDLE sess, DH *dh, X509 *cert)
{
CK_RV rv = CKR_OK;
int i = 0;
static CK_OBJECT_CLASS objclass = CKO_PRIVATE_KEY;
static CK_KEY_TYPE keytype = CKK_DH;
CK_BYTE *label = NULL;
CK_ULONG label_len = 0;
CK_BYTE *id = NULL;
CK_ULONG id_len = 0;
CK_DATE startdate = { "", "", "" };
CK_DATE enddate = { "", "", "" };
char tmpdate[8];
biginteger_t prime = { NULL, 0 }; /* required */
biginteger_t base = { NULL, 0 }; /* required */
biginteger_t value = { NULL, 0 }; /* required */
CK_ATTRIBUTE dh_pri_attrs[11] = {
{ CKA_CLASS, &objclass, sizeof (objclass) },
{ CKA_KEY_TYPE, &keytype, sizeof (keytype) },
{ CKA_PRIVATE, &pk_true, sizeof (pk_true) },
{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
{ CKA_LABEL, NULL, 0 },
{ CKA_ID, NULL, 0 },
{ CKA_START_DATE, NULL, 0 },
{ CKA_END_DATE, NULL, 0 },
{ CKA_PRIME, NULL, 0 },
{ CKA_BASE, NULL, 0 },
{ CKA_VALUE, NULL, 0 }
};
CK_ULONG count = sizeof (dh_pri_attrs) / sizeof (CK_ATTRIBUTE);
CK_OBJECT_HANDLE obj;
cryptodebug("inside write_dh_private");
/* Attributes start at array index 4. */
i = 4;
/* Recycle the certificate label for the private key label. */
cryptodebug("calling X509_alias_get0");
if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
label = (CK_BYTE *)gettext("no label");
label_len = strlen((char *)label);
}
copy_string_to_attr(label, label_len, &(dh_pri_attrs[i++]));
/* Recycle the certificate id for the private key id. */
cryptodebug("PKTOOL_X509_keyid_get0");
if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
id = (CK_BYTE *)gettext("no id");
id_len = strlen((char *)id);
}
copy_string_to_attr(id, id_len, &(dh_pri_attrs[i++]));
/* Recycle the certificate start and end dates for private key. */
cryptodebug("calling X509_get_notBefore");
if (PKTOOL_cvt_ossltime(X509_get_notBefore(cert), tmpdate)) {
(void) memcpy(&startdate, tmpdate, sizeof (startdate));
copy_string_to_attr((CK_BYTE *)&startdate, sizeof (startdate),
&(dh_pri_attrs[i++]));
}
cryptodebug("calling X509_get_notAfter");
if (PKTOOL_cvt_ossltime(X509_get_notAfter(cert), tmpdate)) {
(void) memcpy(&enddate, tmpdate, sizeof (enddate));
copy_string_to_attr((CK_BYTE *)&enddate, sizeof (enddate),
&(dh_pri_attrs[i++]));
}
/* Prime p */
cryptodebug("converting DH private key prime");
if ((rv = cvt_bn2bigint(dh->p, &prime)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert DH private key prime."));
return (rv);
}
copy_bigint_to_attr(prime, &(dh_pri_attrs[i++]));
/* Base g */
cryptodebug("converting DH private key base");
if ((rv = cvt_bn2bigint(dh->g, &base)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert DH private key base."));
return (rv);
}
copy_bigint_to_attr(base, &(dh_pri_attrs[i++]));
/* Private value x */
cryptodebug("converting DH private key value");
if ((rv = cvt_bn2bigint(dh->priv_key, &value)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to convert DH private key value."));
return (rv);
}
copy_bigint_to_attr(value, &(dh_pri_attrs[i++]));
/* Indicates programming error: attributes overran the template */
if (i > count) {
cryptodebug("error: more attributes found than accounted for");
i = count;
}
cryptodebug("calling C_CreateObject");
if ((rv = C_CreateObject(sess, dh_pri_attrs, i, &obj)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to create DH private key object."));
return (rv);
}
return (CKR_OK);
}
/*
* Write certificate to token.
*/
static CK_RV
write_cert(CK_SESSION_HANDLE sess, X509 *cert)
{
CK_RV rv = CKR_OK;
int i = 0;
static CK_OBJECT_CLASS objclass = CKO_CERTIFICATE;
static CK_CERTIFICATE_TYPE certtype = CKC_X_509;
CK_BYTE *subject = NULL;
CK_ULONG subject_len = 0;
CK_BYTE *value = NULL;
CK_ULONG value_len = 0;
CK_BYTE *label = NULL;
CK_ULONG label_len = 0;
CK_BYTE *id = NULL;
CK_ULONG id_len = 0;
CK_BYTE *issuer = NULL;
CK_ULONG issuer_len = 0;
CK_BYTE *serial = NULL;
CK_ULONG serial_len = 0;
CK_ATTRIBUTE cert_attrs[9] = {
{ CKA_CLASS, &objclass, sizeof (objclass) },
{ CKA_CERTIFICATE_TYPE, &certtype, sizeof (certtype) },
{ CKA_TOKEN, &pk_true, sizeof (pk_true) },
{ CKA_SUBJECT, NULL, 0 }, /* required */
{ CKA_VALUE, NULL, 0 }, /* required */
{ 0 /* CKA_LABEL */, NULL, 0 }, /* optional */
{ 0 /* CKA_ID */, NULL, 0 }, /* optional */
{ 0 /* CKA_ISSUER */, NULL, 0 }, /* optional */
{ 0 /* CKA_SERIAL_NUMBER */, NULL, 0 } /* optional */
};
CK_ULONG count = sizeof (cert_attrs) / sizeof (CK_ATTRIBUTE);
CK_OBJECT_HANDLE obj;
cryptodebug("inside write_cert");
/* Attributes start at array index 3. */
i = 3;
/*
* OpenSSL subject name and issuer (a little further below) are
* actually stack structures that contain individual ASN.1
* components. This stack of entries is packed into one DER string.
*/
cryptodebug("calling PKTOOL_X509_subject_name");
if ((subject = PKTOOL_X509_subject_name(cert, (int *)&subject_len)) ==
NULL) {
subject = (CK_BYTE *)gettext("no subject name");
subject_len = strlen((char *)subject);
}
copy_string_to_attr(subject, subject_len, &(cert_attrs[i++]));
/* Get cert value, but it has to be reconstructed from cert. */
cryptodebug("calling PKTOOL_X509_cert_value");
if ((value = PKTOOL_X509_cert_value(cert, (int *)&value_len)) == NULL) {
value = (CK_BYTE *)gettext("no value");
value_len = strlen((char *)value);
}
copy_string_to_attr(value, value_len, &(cert_attrs[i++]));
/*
* Get certificate label which is "friendlyName" Netscape,
* "alias" in OpenSSL.
*/
if ((label = X509_alias_get0(cert, (int *)&label_len)) == NULL) {
cryptodebug("no certificate label");
} else {
cert_attrs[i].type = CKA_LABEL;
copy_string_to_attr(label, label_len, &(cert_attrs[i++]));
}
/* Get the keyid for the cert. */
if ((id = PKTOOL_X509_keyid_get0(cert, (int *)&id_len)) == NULL) {
cryptodebug("no certificate id");
} else {
cert_attrs[i].type = CKA_ID;
copy_string_to_attr(id, id_len, &(cert_attrs[i++]));
}
/* Get the issuer name for the cert. */
if ((issuer = PKTOOL_X509_issuer_name(cert, (int *)&issuer_len)) ==
NULL) {
cryptodebug("no certificate issuer name");
} else {
cert_attrs[i].type = CKA_ISSUER;
copy_string_to_attr(issuer, issuer_len, &(cert_attrs[i++]));
}
/* Get the cert serial number. */
if ((serial = PKTOOL_X509_serial_number(cert, (int *)&serial_len)) ==
NULL) {
cryptodebug("no certificate serial number");
} else {
cert_attrs[i].type = CKA_SERIAL_NUMBER;
copy_string_to_attr(serial, serial_len, &(cert_attrs[i++]));
}
/* Indicates programming error: attributes overran the template */
if (i > count) {
cryptodebug("error: more attributes found than accounted for");
i = count;
}
cryptodebug("calling C_CreateObject");
if ((rv = C_CreateObject(sess, cert_attrs, i, &obj)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to create X.509 certificate object."));
return (rv);
}
return (CKR_OK);
}
/*
* Helper function to write PKCS#12 items to token. Returns CKR_OK
* or CKR_GENERAL_ERROR
*/
static CK_RV
write_token_objs(CK_SESSION_HANDLE sess, EVP_PKEY *priv_key, X509 *cert,
STACK_OF(X509) *ca, int *successes, int *failures)
{
int i;
X509 *c;
CK_RV rv = CKR_OK;
cryptodebug("inside write_token_objs");
/* Do not reset *successes or *failures -- keep running totals. */
/* Import user key. */
switch (priv_key->type) {
case EVP_PKEY_RSA:
(void) fprintf(stdout, gettext("Writing RSA private key...\n"));
if ((rv = write_rsa_private(sess,
EVP_PKEY_get1_RSA(priv_key), cert)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to write RSA private key (%s)."),
pkcs11_strerror(rv));
(*failures)++;
} else
(*successes)++;
break;
case EVP_PKEY_DSA:
(void) fprintf(stdout, gettext("Writing DSA private key...\n"));
if ((rv = write_dsa_private(sess,
EVP_PKEY_get1_DSA(priv_key), cert)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to write DSA private key (%s)."),
pkcs11_strerror(rv));
(*failures)++;
} else
(*successes)++;
break;
case EVP_PKEY_DH:
(void) fprintf(stdout, gettext("Writing DH private key...\n"));
if ((rv = write_dh_private(sess,
EVP_PKEY_get1_DH(priv_key), cert)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to write DH private key (%s)."),
pkcs11_strerror(rv));
(*failures)++;
} else
(*successes)++;
break;
default:
/*
* Note that EVP_PKEY_DH for X9.42 is not implemented
* in the OpenSSL library.
*/
cryptoerror(LOG_STDERR, gettext(
"Private key type 0x%02x import not supported."),
priv_key->type);
(*failures)++;
break;
}
/* Import user certificate. */
(void) fprintf(stdout, gettext("Writing user certificate...\n"));
if ((rv = write_cert(sess, cert)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to write user certificate (%s)."),
pkcs11_strerror(rv));
(*failures)++;
} else
(*successes)++;
/* Import as many stacks of authority certificates as possible. */
for (i = 0; i != sk_X509_num(ca); i++) {
/*
* sk_X509_value() is macro that embeds a cast to (X509 *).
* Here it translates into ((X509 *)sk_value((ca), (i))).
* Lint is complaining about the embedded casting, and
* to fix it, you need to fix openssl header files.
*/
/* LINTED E_BAD_PTR_CAST_ALIGN */
c = sk_X509_value(ca, i);
(void) fprintf(stdout, gettext(
"Writing authority certificate...\n"));
if ((rv = write_cert(sess, c)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to write authority certificate (%s)."),
pkcs11_strerror(rv));
(*failures)++;
} else
(*successes)++;
}
(void) fprintf(stdout, gettext("PKCS#12 element scan completed.\n"));
return (*failures != 0 ? CKR_GENERAL_ERROR : CKR_OK);
}
/*
* Import objects from PKCS#12 file into token.
*/
int
pk_import(int argc, char *argv[])
{
char *token_name = NULL;
char *manuf_id = NULL;
char *serial_no = NULL;
char full_name[FULL_NAME_LEN];
char *filename = NULL;
struct stat statbuf;
CK_SLOT_ID slot_id;
CK_FLAGS pin_state;
CK_UTF8CHAR_PTR pin = NULL;
CK_ULONG pinlen = 0;
CK_UTF8CHAR_PTR pk12pin = NULL;
CK_ULONG pk12pinlen = 0;
CK_SESSION_HANDLE sess;
BIO *fbio = NULL;
EVP_PKEY *priv_key = NULL;
X509 *cert = NULL;
STACK_OF(X509) *ca = NULL;
CK_RV rv = CKR_OK;
int i;
int good_count = 0, bad_count = 0; /* running totals */
cryptodebug("inside pk_import");
/* Get rid of subcommand word "import". */
argc--;
argv++;
/* One additional arg required: filename. */
if (argc != 1)
return (PK_ERR_USAGE);
filename = argv[0];
/* Done parsing command line options. */
/* Check that the file exists and is non-empty. */
if (access(filename, R_OK) < 0) {
cryptoerror(LOG_STDERR, gettext("File \"%s\" is unreadable "
"(%s)."), filename, strerror(errno));
return (CKR_OK);
}
if (stat(filename, &statbuf) < 0) {
cryptoerror(LOG_STDERR, gettext("Unable to get size of "
"file \"%s\" (%s)."), filename, strerror(errno));
return (CKR_OK);
}
if (statbuf.st_size == 0) {
cryptoerror(LOG_STDERR, gettext("File \"%s\" is empty."),
filename);
return (CKR_OK);
}
/* Import operation only supported on softtoken. */
if (token_name == NULL)
token_name = SOFT_TOKEN_LABEL;
if (manuf_id == NULL)
manuf_id = SOFT_MANUFACTURER_ID;
if (serial_no == NULL)
serial_no = SOFT_TOKEN_SERIAL;
full_token_name(token_name, manuf_id, serial_no, full_name);
/* Find the slot with token. */
if ((rv = find_token_slot(token_name, manuf_id, serial_no, &slot_id,
&pin_state)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to find token %s (%s)."), full_name,
pkcs11_strerror(rv));
return (PK_ERR_PK11);
}
/* Get the user's PIN. */
if ((rv = get_pin(gettext("Enter token passphrase:"), NULL, &pin,
&pinlen)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to get token passphrase (%s)."),
pkcs11_strerror(rv));
quick_finish(NULL);
return (PK_ERR_PK11);
}
/* Assume user must be logged in R/W to import objects into token. */
if ((rv = quick_start(slot_id, CKF_RW_SESSION, pin, pinlen, &sess)) !=
CKR_OK) {
cryptoerror(LOG_STDERR,
gettext("Unable to log into token (%s)."),
pkcs11_strerror(rv));
quick_finish(sess);
return (PK_ERR_PK11);
}
/* Setup OpenSSL context. */
PKTOOL_setup_openssl();
/* Open PKCS#12 file. */
if ((open_pkcs12(filename, &fbio)) < 0) {
cryptoerror(LOG_STDERR, gettext("Unable to open import file."));
quick_finish(sess);
return (PK_ERR_SYSTEM);
}
/* Get the PIN for the PKCS#12 import file. */
if ((rv = get_pin(gettext("Enter import file passphrase:"), NULL,
&pk12pin, &pk12pinlen)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to get import file passphrase (%s)."),
pkcs11_strerror(rv));
close_pkcs12(fbio);
quick_finish(sess);
return (PK_ERR_PK11);
}
/* PKCS#12 import file may have multiple elements, loop until done. */
for (i = 0; /* */; i++) {
/* Extract the contents of the PKCS#12 import file. */
if ((rv = extract_pkcs12(fbio, pk12pin, pk12pinlen, &priv_key,
&cert, &ca)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to parse PKCS#12 element #%d "
"in import file (%s)."), i+1, pkcs11_strerror(rv));
close_pkcs12(fbio);
quick_finish(sess);
return (PK_ERR_OPENSSL);
}
/* Reached end of import file? */
if (rv == CKR_OK && priv_key == NULL && cert == NULL &&
ca == NULL)
break;
(void) fprintf(stdout, gettext(
"Scanning PKCS#12 element #%d for objects...\n"), i+1);
/* Write the objects to the token. */
if ((rv = write_token_objs(sess, priv_key, cert, ca,
&good_count, &bad_count)) != CKR_OK) {
cryptoerror(LOG_STDERR, gettext(
"Unable to write PKCS#12 element #%d to token %s."),
i+1, full_name);
close_pkcs12(fbio);
quick_finish(sess);
return (PK_ERR_PK11);
}
}
(void) fprintf(stdout, gettext("%d PKCS#12 elements scanned: "
"%d objects imported, %d errors occurred.\n"), i,
good_count, bad_count);
/* Close PKCS#12 file. */
close_pkcs12(fbio);
/* Clean up. */
quick_finish(sess);
return (0);
}