WIP:Use RSA/EC_KEY METHOD to provide X509 signatures using high-level OpenSSL API
This commit is contained in:
@@ -116,6 +116,62 @@ static bool sign_data(ykpiv_state *state, const unsigned char *in, size_t len, u
|
||||
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,
|
||||
enum enum_algorithm algorithm, const char *output_file_name,
|
||||
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;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 10100000L
|
||||
memcpy(digest, oid, oid_len);
|
||||
/* 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,
|
||||
@@ -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);
|
||||
goto request_out;
|
||||
}
|
||||
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
signinput = digest;
|
||||
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. */
|
||||
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) {
|
||||
PEM_write_X509_REQ(output_file, req);
|
||||
@@ -797,9 +862,11 @@ request_out:
|
||||
EVP_PKEY_free(public_key);
|
||||
}
|
||||
if(req) {
|
||||
#if OPENSSL_VERSION_NUMBER < 10100000L
|
||||
if(req->sig_alg->parameter) {
|
||||
req->sig_alg->parameter = NULL;
|
||||
}
|
||||
#endif
|
||||
X509_REQ_free(req);
|
||||
}
|
||||
if(name) {
|
||||
@@ -928,6 +995,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
|
||||
if(nid == 0) {
|
||||
goto selfsign_out;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER < 10100000L
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
signinput = digest;
|
||||
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. */
|
||||
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) {
|
||||
PEM_write_X509(output_file, x509);
|
||||
@@ -977,10 +1052,12 @@ selfsign_out:
|
||||
fclose(output_file);
|
||||
}
|
||||
if(x509) {
|
||||
#if OPENSSL_VERSION_NUMBER < 10100000L
|
||||
if(x509->sig_alg->parameter) {
|
||||
x509->sig_alg->parameter = NULL;
|
||||
x509->cert_info->signature->parameter = NULL;
|
||||
}
|
||||
#endif
|
||||
X509_free(x509);
|
||||
}
|
||||
if(public_key) {
|
||||
|
||||
@@ -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_notAfter(cert, tm);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 10100000L
|
||||
// Manually set the signature algorithms.
|
||||
// OpenSSL 1.0.1i complains about empty DER fields
|
||||
// 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)
|
||||
ASN1_BIT_STRING_set_bit(cert->signature, 8, 1);
|
||||
ASN1_BIT_STRING_set(cert->signature, "\x00", 1);
|
||||
#endif
|
||||
|
||||
len = i2d_X509(cert, NULL);
|
||||
if (len < 0)
|
||||
|
||||
Reference in New Issue
Block a user