Don't expose EVP_PKEY internal representation through EVP_PKEY_assign While EVP_PKEY_RSA, EVP_PKEY_DSA, and EVP_PKEY_EC have publicly-exposed internaly representations, other EVP_PKEY types to not. EVP_PKEY_assign should not allow callers to manipulate those representations. As part of this, teach EVP_PKEY_assign_RSA, etc. to find their method tables directly, rather than indirecting through an integer. This makes those EVP APIs static-linker-friendly. Bug: 618, 497 Change-Id: Ic45a7514e9a3adc505759f2327129f13faf03a65 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/60645 Auto-Submit: David Benjamin <davidben@google.com> Reviewed-by: Bob Beck <bbe@google.com> Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c index 8383d2e..37b3631 100644 --- a/crypto/evp/evp.c +++ b/crypto/evp/evp.c
@@ -229,6 +229,13 @@ } } +static void evp_pkey_set_method(EVP_PKEY *pkey, + const EVP_PKEY_ASN1_METHOD *method) { + free_it(pkey); + pkey->ameth = method; + pkey->type = pkey->ameth->pkey_id; +} + int EVP_PKEY_type(int nid) { const EVP_PKEY_ASN1_METHOD *meth = evp_pkey_asn1_find(nid); if (meth == NULL) { @@ -246,7 +253,9 @@ } int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) { - return EVP_PKEY_assign(pkey, EVP_PKEY_RSA, key); + evp_pkey_set_method(pkey, &rsa_asn1_meth); + pkey->pkey = key; + return key != NULL; } RSA *EVP_PKEY_get0_RSA(const EVP_PKEY *pkey) { @@ -274,7 +283,9 @@ } int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) { - return EVP_PKEY_assign(pkey, EVP_PKEY_DSA, key); + evp_pkey_set_method(pkey, &dsa_asn1_meth); + pkey->pkey = key; + return key != NULL; } DSA *EVP_PKEY_get0_DSA(const EVP_PKEY *pkey) { @@ -302,7 +313,9 @@ } int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) { - return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key); + evp_pkey_set_method(pkey, &ec_asn1_meth); + pkey->pkey = key; + return key != NULL; } EC_KEY *EVP_PKEY_get0_EC_KEY(const EVP_PKEY *pkey) { @@ -325,21 +338,32 @@ DH *EVP_PKEY_get1_DH(const EVP_PKEY *pkey) { return NULL; } int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { - if (!EVP_PKEY_set_type(pkey, type)) { - return 0; + // This function can only be used to assign RSA, DSA, and EC keys. Other key + // types have internal representations which are not exposed through the + // public API. + switch (type) { + case EVP_PKEY_RSA: + return EVP_PKEY_assign_RSA(pkey, key); + case EVP_PKEY_DSA: + return EVP_PKEY_assign_DSA(pkey, key); + case EVP_PKEY_EC: + return EVP_PKEY_assign_EC_KEY(pkey, key); } - pkey->pkey = key; - return key != NULL; + + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + ERR_add_error_dataf("algorithm %d", type); + return 0; } int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) { - const EVP_PKEY_ASN1_METHOD *ameth; - if (pkey && pkey->pkey) { + // This isn't strictly necessary, but historically |EVP_PKEY_set_type| would + // clear |pkey| even if |evp_pkey_asn1_find| failed, so we preserve that + // behavior. free_it(pkey); } - ameth = evp_pkey_asn1_find(type); + const EVP_PKEY_ASN1_METHOD *ameth = evp_pkey_asn1_find(type); if (ameth == NULL) { OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); ERR_add_error_dataf("algorithm %d", type); @@ -347,8 +371,7 @@ } if (pkey) { - pkey->ameth = ameth; - pkey->type = pkey->ameth->pkey_id; + evp_pkey_set_method(pkey, ameth); } return 1;
diff --git a/include/openssl/evp.h b/include/openssl/evp.h index f69cf75..1cdaca2 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h
@@ -180,11 +180,6 @@ #define EVP_PKEY_X25519 NID_X25519 #define EVP_PKEY_HKDF NID_hkdf -// EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of -// the given type. It returns one if successful or zero if the |type| argument -// is not one of the |EVP_PKEY_*| values or if |key| is NULL. -OPENSSL_EXPORT int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); - // EVP_PKEY_set_type sets the type of |pkey| to |type|. It returns one if // successful or zero if the |type| argument is not one of the |EVP_PKEY_*| // values. If |pkey| is NULL, it simply reports whether the type is known. @@ -1032,6 +1027,15 @@ OPENSSL_EXPORT int EVP_PKEY_CTX_set_dsa_paramgen_q_bits(EVP_PKEY_CTX *ctx, int qbits); +// EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of +// the given type. If successful, it returns one. If the |type| argument +// is not one of |EVP_PKEY_RSA|, |EVP_PKEY_DSA|, or |EVP_PKEY_EC| values or if +// |key| is NULL, it returns zero. This function may not be used with other +// |EVP_PKEY_*| types. +// +// Use the |EVP_PKEY_assign_*| functions instead. +OPENSSL_EXPORT int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); + // Preprocessor compatibility section (hidden). //