diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index 9bef6982..2ae33b2b 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -243,6 +243,10 @@ int EC_KEY_up_ref(EC_KEY *r) { return CRYPTO_add(&r->references, 1, CRYPTO_LOCK_EC) > 1; } +int EC_KEY_is_opaque(const EC_KEY *key) { + return key->ecdsa_meth && (key->ecdsa_meth->flags & ECDSA_FLAG_OPAQUE); +} + const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; } int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) { diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c index 3871859e..06fdabfa 100644 --- a/crypto/evp/evp.c +++ b/crypto/evp/evp.c @@ -117,6 +117,13 @@ void EVP_PKEY_free(EVP_PKEY *pkey) { OPENSSL_free(pkey); } +int EVP_PKEY_is_opaque(const EVP_PKEY *pkey) { + if (pkey->ameth && pkey->ameth->pkey_opaque) { + return pkey->ameth->pkey_opaque(pkey); + } + return 0; +} + int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { if (a->type != b->type) { return -1; diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h index 8561960d..36755f0f 100644 --- a/crypto/evp/internal.h +++ b/crypto/evp/internal.h @@ -87,6 +87,10 @@ struct evp_pkey_asn1_method_st { int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); + /* pkey_opaque returns 1 if the |pk| is opaque. Opaque keys are backed by + * custom implementations which do not expose key material and parameters.*/ + int (*pkey_opaque)(const EVP_PKEY *pk); + int (*pkey_size)(const EVP_PKEY *pk); int (*pkey_bits)(const EVP_PKEY *pk); diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c index 3038b9ea..fe3ce0ea 100644 --- a/crypto/evp/p_ec_asn1.c +++ b/crypto/evp/p_ec_asn1.c @@ -519,6 +519,10 @@ static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); } +static int eckey_opaque(const EVP_PKEY *pkey) { + return EC_KEY_is_opaque(pkey->pkey.ec); +} + static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, int derlen) { EC_KEY *ec; @@ -561,6 +565,8 @@ const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { eckey_priv_encode, eckey_priv_print, + eckey_opaque, + int_ec_size, ec_bits, diff --git a/crypto/evp/p_hmac_asn1.c b/crypto/evp/p_hmac_asn1.c index cabd7379..3d5e8017 100644 --- a/crypto/evp/p_hmac_asn1.c +++ b/crypto/evp/p_hmac_asn1.c @@ -91,6 +91,7 @@ const EVP_PKEY_ASN1_METHOD hmac_asn1_meth = { "HMAC", "OpenSSL HMAC method", 0 /* pub_decode */, 0 /* pub_encode */, 0 /* pub_cmp */, 0 /* pub_print */, 0 /*priv_decode */, 0 /* priv_encode */, 0 /* priv_print */, + 0 /* pkey_opaque */, hmac_size, 0 /* pkey_bits */, 0 /* param_decode */, 0 /* param_encode*/, 0 /* param_missing*/, 0 /* param_copy*/, 0 /* param_cmp*/, 0 /* param_print*/, 0 /* sig_print*/, diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c index f43cdc3a..a9334ab0 100644 --- a/crypto/evp/p_rsa_asn1.c +++ b/crypto/evp/p_rsa_asn1.c @@ -149,6 +149,10 @@ static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { return 1; } +static int rsa_opaque(const EVP_PKEY *pkey) { + return RSA_is_opaque(pkey->pkey.rsa); +} + static int int_rsa_size(const EVP_PKEY *pkey) { return RSA_size(pkey->pkey.rsa); } @@ -728,6 +732,8 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { rsa_priv_encode, rsa_priv_print, + rsa_opaque, + int_rsa_size, rsa_bits, diff --git a/crypto/rsa/rsa.c b/crypto/rsa/rsa.c index 526e468c..8057a253 100644 --- a/crypto/rsa/rsa.c +++ b/crypto/rsa/rsa.c @@ -256,6 +256,10 @@ unsigned RSA_size(const RSA *rsa) { return RSA_default_method.size(rsa); } +int RSA_is_opaque(const RSA *rsa) { + return rsa->meth && (rsa->meth->flags & RSA_FLAG_OPAQUE); +} + int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_RSA, argl, argp, new_func, diff --git a/include/openssl/ec_key.h b/include/openssl/ec_key.h index ac58a8f5..4a48ffcc 100644 --- a/include/openssl/ec_key.h +++ b/include/openssl/ec_key.h @@ -109,6 +109,10 @@ EC_KEY *EC_KEY_dup(const EC_KEY *src); * success and zero otherwise. */ int EC_KEY_up_ref(EC_KEY *key); +/* EC_KEY_is_opaque returns one if |key| is opaque and doesn't expose its key + * material. Otherwise it return zero. */ +int EC_KEY_is_opaque(const EC_KEY *key); + /* EC_KEY_get0_group returns a pointer to the |EC_GROUP| object inside |key|. */ const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key); @@ -229,6 +233,11 @@ void *EC_KEY_get_ex_data(const EC_KEY *r, int idx); /* ECDSA method. */ +/* ECDSA_FLAG_OPAQUE specifies that this ECDSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define ECDSA_FLAG_OPAQUE 1 + /* ecdsa_method_st is a structure of function pointers for implementing ECDSA. * See engine.h. */ struct ecdsa_method_st { @@ -251,6 +260,8 @@ struct ecdsa_method_st { /* verify matches the arguments and behaviour of |ECDSA_verify|. */ int (*verify)(const uint8_t *digest, size_t digest_len, const uint8_t *sig, size_t sig_len, EC_KEY *eckey); + + int flags; }; diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 2d82fd92..b522e8f5 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -89,6 +89,11 @@ EVP_PKEY *EVP_PKEY_new(); * itself. */ void EVP_PKEY_free(EVP_PKEY *pkey); +/* EVP_PKEY_is_opaque returns one if |pkey| is opaque. Opaque keys are backed by + * custom implementations which do not expose key material and parameters. It is + * an error to attempt to duplicate, export, or compare an opaque key. */ +int EVP_PKEY_is_opaque(const EVP_PKEY *pkey); + /* EVP_PKEY_cmp compares |a| and |b| and returns one if they are equal, zero if * not and a negative number on error. * diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h index b67d3965..89c56ede 100644 --- a/include/openssl/rsa.h +++ b/include/openssl/rsa.h @@ -235,6 +235,10 @@ int RSA_public_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, * of a signature of encrypted value using |rsa|. */ unsigned RSA_size(const RSA *rsa); +/* RSA_is_opaque returns one if |rsa| is opaque and doesn't expose its key + * material. Otherwise it return zero. */ +int RSA_is_opaque(const RSA *rsa); + /* RSAPublicKey_dup allocates a fresh |RSA| and copies the private key from * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ RSA *RSAPublicKey_dup(const RSA *rsa); @@ -291,6 +295,10 @@ int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, int RSA_set_ex_data(RSA *r, int idx, void *arg); void *RSA_get_ex_data(const RSA *r, int idx); +/* RSA_FLAG_OPAQUE specifies that this RSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define RSA_FLAG_OPAQUE 1 /* RSA_FLAG_CACHE_PUBLIC causes a precomputed Montgomery context to be created, * on demand, for the public key operations. */ diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index a56cd3e5..2a8dfce0 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -213,16 +213,10 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) EVP_PKEY_free(pktmp); ERR_clear_error(); - /* TODO(fork): remove this? */ -#if 0 - /* Don't check the public/private key, this is mostly - * for smart cards. */ - if ((pkey->type == EVP_PKEY_RSA) && - (RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) - ; - else -#endif - if (!X509_check_private_key(c->pkeys[i].x509,pkey)) + /* Sanity-check that the private key and the certificate match, + * unless the key is opaque (in case of, say, a smartcard). */ + if (!EVP_PKEY_is_opaque(pkey) && + !X509_check_private_key(c->pkeys[i].x509,pkey)) { X509_free(c->pkeys[i].x509); c->pkeys[i].x509 = NULL; @@ -430,17 +424,10 @@ static int ssl_set_cert(CERT *c, X509 *x) EVP_PKEY_copy_parameters(pkey,c->pkeys[i].privatekey); ERR_clear_error(); - /* TODO(fork): remove this? */ -#if 0 - /* Don't check the public/private key, this is mostly - * for smart cards. */ - if ((c->pkeys[i].privatekey->type == EVP_PKEY_RSA) && - (RSA_flags(c->pkeys[i].privatekey->pkey.rsa) & - RSA_METHOD_FLAG_NO_CHECK)) - ; - else -#endif - if (!X509_check_private_key(x,c->pkeys[i].privatekey)) + /* Sanity-check that the private key and the certificate match, + * unless the key is opaque (in case of, say, a smartcard). */ + if (!EVP_PKEY_is_opaque(c->pkeys[i].privatekey) && + !X509_check_private_key(x,c->pkeys[i].privatekey)) { /* don't fail for a cert/key mismatch, just free * current private key (when switching to a different