Merge pull request #665 from sfff/pkcs11tool-pubkey-2016

pkcs11-tool: support write of GOST Public Key object
This commit is contained in:
Frank Morgner 2016-02-16 23:27:56 +01:00
commit 1ca22a22d1
1 changed files with 132 additions and 78 deletions

View File

@ -1805,26 +1805,36 @@ static void parse_certificate(struct x509cert_info *cert,
}
static int
do_read_private_key(unsigned char *data, size_t data_len, EVP_PKEY **key)
do_read_key(unsigned char *data, size_t data_len, int private, EVP_PKEY **key)
{
BIO *mem;
BIO *mem;
BUF_MEM buf_mem;
if (!key)
return -1;
buf_mem.data = malloc(data_len);
if (!buf_mem.data)
if (!buf_mem.data)
return -1;
memcpy(buf_mem.data, data, data_len);
buf_mem.max = buf_mem.length = data_len;
memcpy(buf_mem.data, data, data_len);
buf_mem.max = buf_mem.length = data_len;
mem = BIO_new(BIO_s_mem());
BIO_set_mem_buf(mem, &buf_mem, BIO_NOCLOSE);
if (!strstr((char *)data, "-----BEGIN PRIVATE KEY-----") && !strstr((char *)data, "-----BEGIN EC PRIVATE KEY-----"))
*key = d2i_PrivateKey_bio(mem, NULL);
else
*key = PEM_read_bio_PrivateKey(mem, NULL, NULL, NULL);
if (private) {
if (!strstr((char *)data, "-----BEGIN "))
*key = d2i_PrivateKey_bio(mem, NULL);
else
*key = PEM_read_bio_PrivateKey(mem, NULL, NULL, NULL);
}
else {
if (!strstr((char *)data, "-----BEGIN "))
*key = d2i_PUBKEY_bio(mem, NULL);
else
*key = PEM_read_bio_PUBKEY(mem, NULL, NULL, NULL);
}
BIO_free(mem);
if (*key == NULL)
return -1;
@ -1841,60 +1851,49 @@ do_read_private_key(unsigned char *data, size_t data_len, EVP_PKEY **key)
} while (0)
static int
parse_rsa_private_key(struct rsakey_info *rsa, unsigned char *data, int len)
parse_rsa_pkey(EVP_PKEY *pkey, int private, struct rsakey_info *rsa)
{
RSA *r = NULL;
const unsigned char *p;
RSA *r;
p = data;
r = d2i_RSAPrivateKey(NULL, &p, len);
r = EVP_PKEY_get1_RSA(pkey);
if (!r) {
util_fatal("OpenSSL error during RSA private key parsing");
if (private)
util_fatal("OpenSSL error during RSA private key parsing");
else
util_fatal("OpenSSL error during RSA public key parsing");
}
RSA_GET_BN(modulus, r->n);
RSA_GET_BN(public_exponent, r->e);
RSA_GET_BN(private_exponent, r->d);
RSA_GET_BN(prime_1, r->p);
RSA_GET_BN(prime_2, r->q);
RSA_GET_BN(exponent_1, r->dmp1);
RSA_GET_BN(exponent_2, r->dmq1);
RSA_GET_BN(coefficient, r->iqmp);
if (private) {
RSA_GET_BN(private_exponent, r->d);
RSA_GET_BN(prime_1, r->p);
RSA_GET_BN(prime_2, r->q);
RSA_GET_BN(exponent_1, r->dmp1);
RSA_GET_BN(exponent_2, r->dmq1);
RSA_GET_BN(coefficient, r->iqmp);
}
RSA_free(r);
return 0;
}
static void parse_rsa_public_key(struct rsakey_info *rsa,
unsigned char *data, int len)
{
RSA *r = NULL;
const unsigned char *p;
p = data;
r = d2i_RSA_PUBKEY(NULL, &p, len);
if (!r) {
r = d2i_RSAPublicKey(NULL, &p, len);
}
if (!r) {
util_fatal("OpenSSL error during RSA public key parsing");
}
RSA_GET_BN(modulus, r->n);
RSA_GET_BN(public_exponent, r->e);
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
static int parse_gost_private_key(EVP_PKEY *evp_key, struct gostkey_info *gost)
static int
parse_gost_pkey(EVP_PKEY *pkey, int private, struct gostkey_info *gost)
{
EC_KEY *src = EVP_PKEY_get0(evp_key);
EC_KEY *src = EVP_PKEY_get0(pkey);
unsigned char *pder;
const BIGNUM *bignum;
BIGNUM *X, *Y;
const EC_POINT *point;
int nid, rv;
if (!src)
return -1;
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0(evp_key)));
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0(pkey)));
rv = i2d_ASN1_OBJECT(OBJ_nid2obj(nid), NULL);
if (rv < 0)
return -1;
@ -1907,13 +1906,39 @@ static int parse_gost_private_key(EVP_PKEY *evp_key, struct gostkey_info *gost)
rv = i2d_ASN1_OBJECT(OBJ_nid2obj(nid), &pder);
gost->param_oid.len = rv;
bignum = EC_KEY_get0_private_key(EVP_PKEY_get0(evp_key));
if (private) {
bignum = EC_KEY_get0_private_key(EVP_PKEY_get0(pkey));
gost->private.len = BN_num_bytes(bignum);
gost->private.value = malloc(gost->private.len);
if (!gost->private.value)
return -1;
BN_bn2bin(bignum, gost->private.value);
gost->private.len = BN_num_bytes(bignum);
gost->private.value = malloc(gost->private.len);
if (!gost->private.value)
return -1;
BN_bn2bin(bignum, gost->private.value);
}
else {
X = BN_new();
Y = BN_new();
point = EC_KEY_get0_public_key(src);
rv = -1;
if (X && Y && point && EC_KEY_get0_group(src))
rv = EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(src),
point, X, Y, NULL);
if (rv == 1) {
gost->public.len = BN_num_bytes(X) + BN_num_bytes(Y);
gost->public.value = malloc(gost->public.len);
if (!gost->public.value)
rv = -1;
else
{
BN_bn2bin(Y, gost->public.value);
BN_bn2bin(X, gost->public.value + BN_num_bytes(Y));
}
}
BN_free(X);
BN_free(Y);
if (rv != 1)
return -1;
}
return 0;
}
@ -1923,8 +1948,7 @@ static int parse_gost_private_key(EVP_PKEY *evp_key, struct gostkey_info *gost)
#define MAX_OBJECT_SIZE 5000
/* Currently for certificates (-type cert), private keys (-type privkey),
public keys (-type pubkey) and data objects (-type data).
Note: only RSA private keys are supported. */
public keys (-type pubkey) and data objects (-type data). */
static int write_object(CK_SESSION_HANDLE session)
{
CK_BBOOL _true = TRUE;
@ -1989,38 +2013,35 @@ static int write_object(CK_SESSION_HANDLE session)
util_fatal("No OpenSSL support, cannot parse certificate\n");
#endif
}
if (opt_object_class == CKO_PRIVATE_KEY) {
if (opt_object_class == CKO_PRIVATE_KEY || opt_object_class == CKO_PUBLIC_KEY) {
int is_private = opt_object_class == CKO_PRIVATE_KEY;
#ifdef ENABLE_OPENSSL
int rv;
rv = do_read_private_key(contents, contents_len, &evp_key);
if (rv)
util_fatal("Cannot read private key\n");
rv = do_read_key(contents, contents_len, is_private, &evp_key);
if (rv) {
if (is_private)
util_fatal("Cannot read private key\n");
else
util_fatal("Cannot read public key\n");
}
if (evp_key->type == EVP_PKEY_RSA) {
rv = parse_rsa_private_key(&rsa, contents, contents_len);
if (evp_key->type == EVP_PKEY_RSA) {
rv = parse_rsa_pkey(evp_key, is_private, &rsa);
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
else if (evp_key->type == NID_id_GostR3410_2001 || evp_key->type == EVP_PKEY_EC) {
/* parsing ECDSA is identical to GOST */
rv = parse_gost_private_key(evp_key, &gost);
rv = parse_gost_pkey(evp_key, is_private, &gost);
}
#endif
else {
else
util_fatal("Unsupported key type: 0x%X\n", evp_key->type);
}
if (rv)
util_fatal("Cannot parse private key\n");
util_fatal("Cannot parse key\n");
#else
util_fatal("No OpenSSL support, cannot parse private key\n");
#endif
}
if (opt_object_class == CKO_PUBLIC_KEY) {
#ifdef ENABLE_OPENSSL
parse_rsa_public_key(&rsa, contents, contents_len);
#else
util_fatal("No OpenSSL support, cannot parse RSA public key\n");
util_fatal("No OpenSSL support, cannot parse key\n");
#endif
}
@ -2146,10 +2167,11 @@ static int write_object(CK_SESSION_HANDLE session)
clazz = CKO_PUBLIC_KEY;
type = CKK_RSA;
FILL_ATTR(pubkey_templ[0], CKA_CLASS, &clazz, sizeof(clazz));
FILL_ATTR(pubkey_templ[1], CKA_KEY_TYPE, &type, sizeof(type));
FILL_ATTR(pubkey_templ[2], CKA_TOKEN, &_true, sizeof(_true));
n_pubkey_attr = 3;
n_pubkey_attr = 0;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_CLASS, &clazz, sizeof(clazz));
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_TOKEN, &_true, sizeof(_true));
n_pubkey_attr++;
if (opt_is_private != 0) {
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PRIVATE, &_true, sizeof(_true));
@ -2188,10 +2210,42 @@ static int write_object(CK_SESSION_HANDLE session)
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_SUBJECT, cert.subject, cert.subject_len);
n_pubkey_attr++;
}
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_MODULUS, rsa.modulus, rsa.modulus_len);
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PUBLIC_EXPONENT, rsa.public_exponent, rsa.public_exponent_len);
n_pubkey_attr++;
if (evp_key->type == EVP_PKEY_RSA) {
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_MODULUS,
rsa.modulus, rsa.modulus_len);
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_PUBLIC_EXPONENT,
rsa.public_exponent, rsa.public_exponent_len);
n_pubkey_attr++;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC)
else if (evp_key->type == EVP_PKEY_EC) {
type = CKK_EC;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_EC_PARAMS, gost.param_oid.value, gost.param_oid.len);
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_VALUE, gost.public.value, gost.public.len);
n_pubkey_attr++;
}
else if (evp_key->type == NID_id_GostR3410_2001) {
type = CKK_GOSTR3410;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type));
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_GOSTR3410_PARAMS, gost.param_oid.value, gost.param_oid.len);
n_pubkey_attr++;
FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_VALUE, gost.public.value, gost.public.len);
/* CKA_VALUE of the GOST key has to be in the little endian order */
rv = sc_mem_reverse(pubkey_templ[n_pubkey_attr].pValue, pubkey_templ[n_pubkey_attr].ulValueLen);
if (rv)
return rv;
n_pubkey_attr++;
}
#endif
#endif
}
else