Implement i2d_PUBKEY and friends without crypto/asn1.
Code which targets OpenSSL won't use EVP_parse_public_key. X509_PUBKEY
is fairly deeply tied to the old ASN.1 stack, but there's no reason for
i2d_PUBKEY and friends to be. Move them to crypto/evp and reimplement as
wrappers over our functions.
Bug: chromium:1102458
Change-Id: Ic11766acdac797602e4abe1253b0efe33faef298
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/42005
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c
index fc1dce3..4d13d59 100644
--- a/crypto/evp/evp_asn1.c
+++ b/crypto/evp/evp_asn1.c
@@ -65,6 +65,7 @@
#include <openssl/rsa.h>
#include "internal.h"
+#include "../bytestring/internal.h"
#include "../internal.h"
@@ -386,3 +387,145 @@
EVP_PKEY_free(ret);
return NULL;
}
+
+EVP_PKEY *d2i_PUBKEY(EVP_PKEY **out, const uint8_t **inp, long len) {
+ if (len < 0) {
+ return NULL;
+ }
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ EVP_PKEY *ret = EVP_parse_public_key(&cbs);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (out != NULL) {
+ EVP_PKEY_free(*out);
+ *out = ret;
+ }
+ *inp = CBS_data(&cbs);
+ return ret;
+}
+
+int i2d_PUBKEY(const EVP_PKEY *pkey, uint8_t **outp) {
+ CBB cbb;
+ if (!CBB_init(&cbb, 128) ||
+ !EVP_marshal_public_key(&cbb, pkey)) {
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+ return CBB_finish_i2d(&cbb, outp);
+}
+
+RSA *d2i_RSA_PUBKEY(RSA **out, const uint8_t **inp, long len) {
+ if (len < 0) {
+ return NULL;
+ }
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ EVP_PKEY *pkey = EVP_parse_public_key(&cbs);
+ if (pkey == NULL) {
+ return NULL;
+ }
+ RSA *rsa = EVP_PKEY_get1_RSA(pkey);
+ EVP_PKEY_free(pkey);
+ if (rsa == NULL) {
+ return NULL;
+ }
+ if (out != NULL) {
+ RSA_free(*out);
+ *out = rsa;
+ }
+ *inp = CBS_data(&cbs);
+ return rsa;
+}
+
+int i2d_RSA_PUBKEY(const RSA *rsa, uint8_t **outp) {
+ int ret = -1;
+ EVP_PKEY *pkey = EVP_PKEY_new();
+ if (pkey == NULL ||
+ !EVP_PKEY_set1_RSA(pkey, (RSA *)rsa)) {
+ goto err;
+ }
+
+ ret = i2d_PUBKEY(pkey, outp);
+
+err:
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
+DSA *d2i_DSA_PUBKEY(DSA **out, const uint8_t **inp, long len) {
+ if (len < 0) {
+ return NULL;
+ }
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ EVP_PKEY *pkey = EVP_parse_public_key(&cbs);
+ if (pkey == NULL) {
+ return NULL;
+ }
+ DSA *dsa = EVP_PKEY_get1_DSA(pkey);
+ EVP_PKEY_free(pkey);
+ if (dsa == NULL) {
+ return NULL;
+ }
+ if (out != NULL) {
+ DSA_free(*out);
+ *out = dsa;
+ }
+ *inp = CBS_data(&cbs);
+ return dsa;
+}
+
+int i2d_DSA_PUBKEY(const DSA *dsa, uint8_t **outp) {
+ int ret = -1;
+ EVP_PKEY *pkey = EVP_PKEY_new();
+ if (pkey == NULL ||
+ !EVP_PKEY_set1_DSA(pkey, (DSA *)dsa)) {
+ goto err;
+ }
+
+ ret = i2d_PUBKEY(pkey, outp);
+
+err:
+ EVP_PKEY_free(pkey);
+ return ret;
+}
+
+EC_KEY *d2i_EC_PUBKEY(EC_KEY **out, const uint8_t **inp, long len) {
+ if (len < 0) {
+ return NULL;
+ }
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ EVP_PKEY *pkey = EVP_parse_public_key(&cbs);
+ if (pkey == NULL) {
+ return NULL;
+ }
+ EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pkey);
+ EVP_PKEY_free(pkey);
+ if (ec_key == NULL) {
+ return NULL;
+ }
+ if (out != NULL) {
+ EC_KEY_free(*out);
+ *out = ec_key;
+ }
+ *inp = CBS_data(&cbs);
+ return ec_key;
+}
+
+int i2d_EC_PUBKEY(const EC_KEY *ec_key, uint8_t **outp) {
+ int ret = -1;
+ EVP_PKEY *pkey = EVP_PKEY_new();
+ if (pkey == NULL ||
+ !EVP_PKEY_set1_EC_KEY(pkey, (EC_KEY *)ec_key)) {
+ goto err;
+ }
+
+ ret = i2d_PUBKEY(pkey, outp);
+
+err:
+ EVP_PKEY_free(pkey);
+ return ret;
+}
diff --git a/crypto/x509/x_pubkey.c b/crypto/x509/x_pubkey.c
index 3d07d66..37dee49 100644
--- a/crypto/x509/x_pubkey.c
+++ b/crypto/x509/x_pubkey.c
@@ -180,160 +180,6 @@
return NULL;
}
-/*
- * Now two pseudo ASN1 routines that take an EVP_PKEY structure and encode or
- * decode as X509_PUBKEY
- */
-
-EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length)
-{
- X509_PUBKEY *xpk;
- EVP_PKEY *pktmp;
- xpk = d2i_X509_PUBKEY(NULL, pp, length);
- if (!xpk)
- return NULL;
- pktmp = X509_PUBKEY_get(xpk);
- X509_PUBKEY_free(xpk);
- if (!pktmp)
- return NULL;
- if (a) {
- EVP_PKEY_free(*a);
- *a = pktmp;
- }
- return pktmp;
-}
-
-int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp)
-{
- X509_PUBKEY *xpk = NULL;
- int ret;
- if (!a)
- return 0;
- if (!X509_PUBKEY_set(&xpk, (EVP_PKEY *)a))
- return 0;
- ret = i2d_X509_PUBKEY(xpk, pp);
- X509_PUBKEY_free(xpk);
- return ret;
-}
-
-/*
- * The following are equivalents but which return RSA and DSA keys
- */
-RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length)
-{
- EVP_PKEY *pkey;
- RSA *key;
- const unsigned char *q;
- q = *pp;
- pkey = d2i_PUBKEY(NULL, &q, length);
- if (!pkey)
- return NULL;
- key = EVP_PKEY_get1_RSA(pkey);
- EVP_PKEY_free(pkey);
- if (!key)
- return NULL;
- *pp = q;
- if (a) {
- RSA_free(*a);
- *a = key;
- }
- return key;
-}
-
-int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp)
-{
- EVP_PKEY *pktmp;
- int ret;
- if (!a)
- return 0;
- pktmp = EVP_PKEY_new();
- if (!pktmp) {
- OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- EVP_PKEY_set1_RSA(pktmp, (RSA *)a);
- ret = i2d_PUBKEY(pktmp, pp);
- EVP_PKEY_free(pktmp);
- return ret;
-}
-
-#ifndef OPENSSL_NO_DSA
-DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length)
-{
- EVP_PKEY *pkey;
- DSA *key;
- const unsigned char *q;
- q = *pp;
- pkey = d2i_PUBKEY(NULL, &q, length);
- if (!pkey)
- return NULL;
- key = EVP_PKEY_get1_DSA(pkey);
- EVP_PKEY_free(pkey);
- if (!key)
- return NULL;
- *pp = q;
- if (a) {
- DSA_free(*a);
- *a = key;
- }
- return key;
-}
-
-int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp)
-{
- EVP_PKEY *pktmp;
- int ret;
- if (!a)
- return 0;
- pktmp = EVP_PKEY_new();
- if (!pktmp) {
- OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- EVP_PKEY_set1_DSA(pktmp, (DSA *)a);
- ret = i2d_PUBKEY(pktmp, pp);
- EVP_PKEY_free(pktmp);
- return ret;
-}
-#endif
-
-EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length)
-{
- EVP_PKEY *pkey;
- EC_KEY *key;
- const unsigned char *q;
- q = *pp;
- pkey = d2i_PUBKEY(NULL, &q, length);
- if (!pkey)
- return (NULL);
- key = EVP_PKEY_get1_EC_KEY(pkey);
- EVP_PKEY_free(pkey);
- if (!key)
- return (NULL);
- *pp = q;
- if (a) {
- EC_KEY_free(*a);
- *a = key;
- }
- return (key);
-}
-
-int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp)
-{
- EVP_PKEY *pktmp;
- int ret;
- if (!a)
- return (0);
- if ((pktmp = EVP_PKEY_new()) == NULL) {
- OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE);
- return (0);
- }
- EVP_PKEY_set1_EC_KEY(pktmp, (EC_KEY *)a);
- ret = i2d_PUBKEY(pktmp, pp);
- EVP_PKEY_free(pktmp);
- return (ret);
-}
-
int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj,
int ptype, void *pval,
unsigned char *penc, int penclen)
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index fe6c8b6..b305225 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -947,6 +947,75 @@
OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(EVP_PKEY_CTX *ctx,
const EVP_MD *md);
+// i2d_PUBKEY marshals a public key from |pkey| as a DER-encoded
+// SubjectPublicKeyInfo. If |outp| is not NULL, the result is written to |*outp|
+// and |*outp| is advanced just past the output. It returns the number of bytes
+// in the result, whether written or not, or a negative value on error.
+//
+// Use |EVP_marshal_public_key| instead.
+OPENSSL_EXPORT int i2d_PUBKEY(const EVP_PKEY *pkey, uint8_t **outp);
+
+// d2i_PUBKEY parses a DER-encoded SubjectPublicKeyInfo from |len| bytes at
+// |*inp|. It returns a newly-allocated result, or NULL on error. On success,
+// |*inp| is advanced past the DER structure. If |out| is not NULL, it also
+// frees any existing object pointed by |*out| and writes the result.
+//
+// Use |EVP_parse_public_key| instead.
+OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY(EVP_PKEY **out, const uint8_t **inp,
+ long len);
+
+// i2d_RSA_PUBKEY marshals |rsa| as a DER-encoded SubjectPublicKeyInfo. If
+// |outp| is not NULL, the result is written to |*outp| and
+// |*outp| is advanced just past the output. It returns the number of bytes in
+// the result, whether written or not, or a negative value on error.
+//
+// Use |EVP_marshal_public_key| instead.
+OPENSSL_EXPORT int i2d_RSA_PUBKEY(const RSA *rsa, uint8_t **outp);
+
+// d2i_RSA_PUBKEY parses an RSA public key as a DER-encoded SubjectPublicKeyInfo
+// from |len| bytes at |*inp|. It returns a newly-allocated result, or NULL on
+// error. On success, |*inp| is advanced past the DER structure. If |out| is not
+// NULL, it also frees any existing object pointed by |*out| and writes the
+// result.
+//
+// Use |EVP_parse_public_key| instead.
+OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY(RSA **out, const uint8_t **inp, long len);
+
+// i2d_DSA_PUBKEY marshals |dsa| as a DER-encoded SubjectPublicKeyInfo. If
+// |outp| is not NULL, the result is written to |*outp| and |*outp| is advanced
+// just past the output. It returns the number of bytes in the result, whether
+// written or not, or a negative value on error.
+//
+// Use |EVP_marshal_public_key| instead.
+OPENSSL_EXPORT int i2d_DSA_PUBKEY(const DSA *dsa, uint8_t **outp);
+
+// d2i_DSA_PUBKEY parses a DSA public key as a DER-encoded SubjectPublicKeyInfo
+// from |len| bytes at |*inp|. It returns a newly-allocated result, or NULL on
+// error. On success, |*inp| is advanced past the DER structure. If |out| is not
+// NULL, it also frees any existing object pointed by |*out| and writes the
+// result.
+//
+// Use |EVP_parse_public_key| instead.
+OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY(DSA **out, const uint8_t **inp, long len);
+
+// i2d_EC_PUBKEY marshals |ec_key| as a DER-encoded SubjectPublicKeyInfo. If
+// |outp| is not NULL, the result is written to |*outp| and |*outp| is advanced
+// just past the output. It returns the number of bytes in the result, whether
+// written or not, or a negative value on error.
+//
+// Use |EVP_marshal_public_key| instead.
+OPENSSL_EXPORT int i2d_EC_PUBKEY(const EC_KEY *ec_key, uint8_t **outp);
+
+// d2i_EC_PUBKEY parses an EC public key as a DER-encoded SubjectPublicKeyInfo
+// from |len| bytes at |*inp|. It returns a newly-allocated result, or NULL on
+// error. On success, |*inp| is advanced past the DER structure. If |out| is not
+// NULL, it also frees any existing object pointed by |*out| and writes the
+// result.
+//
+// Use |EVP_parse_public_key| instead.
+OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY(EC_KEY **out, const uint8_t **inp,
+ long len);
+
// Preprocessor compatibility section (hidden).
//
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index d58e3ca..58dfad3 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -758,20 +758,6 @@
OPENSSL_EXPORT int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
OPENSSL_EXPORT EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key);
-OPENSSL_EXPORT int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp);
-OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp,
- long length);
-OPENSSL_EXPORT int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp);
-OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp,
- long length);
-#ifndef OPENSSL_NO_DSA
-OPENSSL_EXPORT int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp);
-OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp,
- long length);
-#endif
-OPENSSL_EXPORT int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp);
-OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp,
- long length);
DECLARE_ASN1_FUNCTIONS(X509_SIG)
DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO)