WIP:Use RSA/EC_KEY METHOD to provide X509 signatures using high-level OpenSSL API

This commit is contained in:
Jakub Jelen
2017-10-20 16:35:09 +02:00
parent d2ffc41a6c
commit 4a847677cc
2 changed files with 79 additions and 0 deletions
+77
View File
@@ -116,6 +116,62 @@ static bool sign_data(ykpiv_state *state, const unsigned char *in, size_t len, u
return false; return false;
} }
static int ec_key_ex_data_idx = -1;
struct internal_key {
ykpiv_state *state;
int algorithm;
int key;
};
int
yk_rsa_meth_sign(int dtype, const unsigned char *m, unsigned int m_length,
unsigned char *sigret, unsigned int *siglen, const RSA *rsa)
{
const RSA_METHOD *meth = RSA_get_method(rsa);
const struct internal_key *key = RSA_meth_get0_app_data(meth);
if (sign_data(key->state, m, m_length, sigret, (size_t *)siglen, key->algorithm, key->key))
return 0;
return 1;
}
int
yk_ec_meth_sign(int type, const unsigned char *dgst, int dlen,
unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv,
const BIGNUM *r, EC_KEY *ec)
{
const struct internal_key *key = EC_KEY_get_ex_data(ec, ec_key_ex_data_idx);
if (sign_data(key->state, dgst, dlen, sig, (size_t *)siglen, key->algorithm, key->key))
return 0;
return 1;
}
static int
wrap_public_key(ykpiv_state *state, int algorithm, EVP_PKEY *public_key,
int key)
{
if(YKPIV_IS_RSA(algorithm)) {
RSA_METHOD *meth = RSA_meth_dup(RSA_get_default_method());
RSA *rsa = EVP_PKEY_get0_RSA(public_key);
struct internal_key int_key = {state, algorithm, key};
RSA_meth_set0_app_data(meth, &int_key);
RSA_meth_set_sign(meth, yk_rsa_meth_sign);
RSA_set_method(rsa, meth);
} else {
EC_KEY *ec = EVP_PKEY_get0_EC_KEY(public_key);
EC_KEY_METHOD *meth = EC_KEY_METHOD_new(EC_KEY_get_method(ec));
struct internal_key int_key = {state, algorithm, key};
if (ec_key_ex_data_idx == -1)
ec_key_ex_data_idx = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL, 0);
EC_KEY_set_ex_data(ec, ec_key_ex_data_idx, &int_key);
EC_KEY_METHOD_set_sign(meth, yk_ec_meth_sign, NULL, NULL); /* XXX ?? */
EC_KEY_set_method(ec, meth);
}
return 0;
}
static bool generate_key(ykpiv_state *state, const char *slot, static bool generate_key(ykpiv_state *state, const char *slot,
enum enum_algorithm algorithm, const char *output_file_name, enum enum_algorithm algorithm, const char *output_file_name,
enum enum_key_format key_format, enum enum_pin_policy pin_policy, enum enum_key_format key_format, enum enum_pin_policy pin_policy,
@@ -743,6 +799,7 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
goto request_out; goto request_out;
} }
#if OPENSSL_VERSION_NUMBER < 10100000L
memcpy(digest, oid, oid_len); memcpy(digest, oid, oid_len);
/* XXX: this should probably use X509_REQ_digest() but that's buggy */ /* XXX: this should probably use X509_REQ_digest() but that's buggy */
if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ_INFO), md, req->req_info, if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ_INFO), md, req->req_info,
@@ -756,6 +813,7 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
fprintf(stderr, "Unsupported algorithm %x or hash %x\n", algorithm, hash); fprintf(stderr, "Unsupported algorithm %x or hash %x\n", algorithm, hash);
goto request_out; goto request_out;
} }
if(YKPIV_IS_RSA(algorithm)) { if(YKPIV_IS_RSA(algorithm)) {
signinput = digest; signinput = digest;
len = oid_len + digest_len; len = oid_len + digest_len;
@@ -778,6 +836,13 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
/* mark that all bits should be used. */ /* mark that all bits should be used. */
req->signature->flags = ASN1_STRING_FLAG_BITS_LEFT; req->signature->flags = ASN1_STRING_FLAG_BITS_LEFT;
} }
#else
/* With opaque structures we can not touch whatever we want, but we need
* to embed the sign_data function in the RSA/EC key structures */
wrap_public_key(state, algorithm, public_key, key);
X509_REQ_sign(req, public_key, md);
#endif
if(key_format == key_format_arg_PEM) { if(key_format == key_format_arg_PEM) {
PEM_write_X509_REQ(output_file, req); PEM_write_X509_REQ(output_file, req);
@@ -797,9 +862,11 @@ request_out:
EVP_PKEY_free(public_key); EVP_PKEY_free(public_key);
} }
if(req) { if(req) {
#if OPENSSL_VERSION_NUMBER < 10100000L
if(req->sig_alg->parameter) { if(req->sig_alg->parameter) {
req->sig_alg->parameter = NULL; req->sig_alg->parameter = NULL;
} }
#endif
X509_REQ_free(req); X509_REQ_free(req);
} }
if(name) { if(name) {
@@ -928,6 +995,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
if(nid == 0) { if(nid == 0) {
goto selfsign_out; goto selfsign_out;
} }
#if OPENSSL_VERSION_NUMBER < 10100000L
if(YKPIV_IS_RSA(algorithm)) { if(YKPIV_IS_RSA(algorithm)) {
signinput = digest; signinput = digest;
len = oid_len + md_len; len = oid_len + md_len;
@@ -961,6 +1029,13 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
* certificate can be validated. */ * certificate can be validated. */
x509->signature->flags = ASN1_STRING_FLAG_BITS_LEFT; x509->signature->flags = ASN1_STRING_FLAG_BITS_LEFT;
} }
#else
/* With opaque structures we can not touch whatever we want, but we need
* to embed the sign_data function in the RSA/EC key structures */
wrap_public_key(state, algorithm, public_key, key);
X509_sign(x509, public_key, md);
#endif
if(key_format == key_format_arg_PEM) { if(key_format == key_format_arg_PEM) {
PEM_write_X509(output_file, x509); PEM_write_X509(output_file, x509);
@@ -977,10 +1052,12 @@ selfsign_out:
fclose(output_file); fclose(output_file);
} }
if(x509) { if(x509) {
#if OPENSSL_VERSION_NUMBER < 10100000L
if(x509->sig_alg->parameter) { if(x509->sig_alg->parameter) {
x509->sig_alg->parameter = NULL; x509->sig_alg->parameter = NULL;
x509->cert_info->signature->parameter = NULL; x509->cert_info->signature->parameter = NULL;
} }
#endif
X509_free(x509); X509_free(x509);
} }
if(public_key) { if(public_key) {
+2
View File
@@ -165,6 +165,7 @@ CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa,
X509_set_notBefore(cert, tm); X509_set_notBefore(cert, tm);
X509_set_notAfter(cert, tm); X509_set_notAfter(cert, tm);
#if OPENSSL_VERSION_NUMBER < 10100000L
// Manually set the signature algorithms. // Manually set the signature algorithms.
// OpenSSL 1.0.1i complains about empty DER fields // OpenSSL 1.0.1i complains about empty DER fields
// 8 => md5WithRsaEncryption // 8 => md5WithRsaEncryption
@@ -174,6 +175,7 @@ CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa,
// Manually set a signature (same reason as before) // Manually set a signature (same reason as before)
ASN1_BIT_STRING_set_bit(cert->signature, 8, 1); ASN1_BIT_STRING_set_bit(cert->signature, 8, 1);
ASN1_BIT_STRING_set(cert->signature, "\x00", 1); ASN1_BIT_STRING_set(cert->signature, "\x00", 1);
#endif
len = i2d_X509(cert, NULL); len = i2d_X509(cert, NULL);
if (len < 0) if (len < 0)