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).
//