From 23dcf88e1875666f26bd0bf0a7fde9260eda7ee6 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 25 Jan 2019 04:44:22 +0000 Subject: [PATCH] Add some Node compatibility functions. This doesn't cover all the functions used by Node, but it's the easy bits. (EVP_PKEY_paramgen will be done separately as its a non-trivial bit of machinery.) Change-Id: I6501e99f9239ffcdcc57b961ebe85d0ad3965549 Reviewed-on: https://boringssl-review.googlesource.com/c/34544 Reviewed-by: Adam Langley Commit-Queue: Adam Langley --- crypto/bn_extra/convert.c | 8 ++++++++ crypto/evp/evp_asn1.c | 41 +++++++++++++++++++++++++++++++++++++++ crypto/fipsmodule/ec/ec.c | 16 +++++++++++++++ include/openssl/bn.h | 6 ++++++ include/openssl/ec.h | 5 +++++ include/openssl/evp.h | 14 +++++++++++++ include/openssl/mem.h | 4 ++++ 7 files changed, 94 insertions(+) diff --git a/crypto/bn_extra/convert.c b/crypto/bn_extra/convert.c index 9a1a69e3..6e930fc6 100644 --- a/crypto/bn_extra/convert.c +++ b/crypto/bn_extra/convert.c @@ -460,3 +460,11 @@ BIGNUM *BN_mpi2bn(const uint8_t *in, size_t len, BIGNUM *out) { } return out; } + +int BN_bn2binpad(const BIGNUM *in, uint8_t *out, int len) { + if (len < 0 || + !BN_bn2bin_padded(out, (size_t)len, in)) { + return -1; + } + return len; +} diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c index 383e2f9b..d56b93b0 100644 --- a/crypto/evp/evp_asn1.c +++ b/crypto/evp/evp_asn1.c @@ -344,3 +344,44 @@ int i2d_PublicKey(const EVP_PKEY *key, uint8_t **outp) { return -1; } } + +EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **out, const uint8_t **inp, + long len) { + EVP_PKEY *ret = EVP_PKEY_new(); + if (ret == NULL) { + return NULL; + } + + CBS cbs; + CBS_init(&cbs, *inp, len < 0 ? 0 : (size_t)len); + switch (type) { + case EVP_PKEY_RSA: { + RSA *rsa = RSA_parse_public_key(&cbs); + if (rsa == NULL || !EVP_PKEY_assign_RSA(ret, rsa)) { + RSA_free(rsa); + goto err; + } + break; + } + + // Unlike OpenSSL, we do not support EC keys with this API. The raw EC + // public key serialization requires knowing the group. In OpenSSL, calling + // this function with |EVP_PKEY_EC| and setting |out| to NULL does not work. + // It requires |*out| to include a partially-initiazed |EVP_PKEY| to extract + // the group. + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + goto err; + } + + *inp = CBS_data(&cbs); + if (out != NULL) { + EVP_PKEY_free(*out); + *out = ret; + } + return ret; + +err: + EVP_PKEY_free(ret); + return NULL; +} diff --git a/crypto/fipsmodule/ec/ec.c b/crypto/fipsmodule/ec/ec.c index 90b9d71f..4ea5529b 100644 --- a/crypto/fipsmodule/ec/ec.c +++ b/crypto/fipsmodule/ec/ec.c @@ -660,6 +660,22 @@ const char *EC_curve_nid2nist(int nid) { return NULL; } +int EC_curve_nist2nid(const char *name) { + if (strcmp(name, "P-224") == 0) { + return NID_secp224r1; + } + if (strcmp(name, "P-256") == 0) { + return NID_X9_62_prime256v1; + } + if (strcmp(name, "P-384") == 0) { + return NID_secp384r1; + } + if (strcmp(name, "P-521") == 0) { + return NID_secp521r1; + } + return NID_undef; +} + EC_POINT *EC_POINT_new(const EC_GROUP *group) { if (group == NULL) { OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); diff --git a/include/openssl/bn.h b/include/openssl/bn.h index c198f4df..b6b7e9ab 100644 --- a/include/openssl/bn.h +++ b/include/openssl/bn.h @@ -932,6 +932,12 @@ OPENSSL_EXPORT BN_MONT_CTX *BN_MONT_CTX_new(void); OPENSSL_EXPORT int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx); +// BN_bn2binpad behaves like |BN_bn2bin_padded|, but it returns |len| on success +// and -1 on error. +// +// Use |BN_bn2bin_padded| instead. It is |size_t|-clean. +OPENSSL_EXPORT int BN_bn2binpad(const BIGNUM *in, uint8_t *out, int len); + // Private functions diff --git a/include/openssl/ec.h b/include/openssl/ec.h index c65a1a75..16dadf27 100644 --- a/include/openssl/ec.h +++ b/include/openssl/ec.h @@ -162,6 +162,11 @@ OPENSSL_EXPORT unsigned EC_GROUP_get_degree(const EC_GROUP *group); // for |NID_X9_62_prime256v1|. OPENSSL_EXPORT const char *EC_curve_nid2nist(int nid); +// EC_curve_nist2nid returns the NID of the elliptic curve specified by the NIST +// name |name|, or |NID_undef| if |name| is not a recognized name. For example, +// it returns |NID_X9_62_prime256v1| for "P-256". +OPENSSL_EXPORT int EC_curve_nist2nid(const char *name); + // Points on elliptic curves. diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 1d7192da..cbe93d80 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -826,6 +826,20 @@ OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, OPENSSL_EXPORT EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len); +// d2i_PublicKey parse a public key from |len| bytes at |*inp| in a type- +// specific format specified by |type|. If |out| is not NULL then, on exit, a +// pointer to the result is in |*out|. Note that, even if |*out| is already non- +// NULL on entry, it will not be written to. Rather, a fresh |EVP_PKEY| is +// allocated and the previous one is freed. On successful exit, |*inp| is +// advanced past the decoded key. It returns the result or NULL on error. +// +// RSA keys are parsed as a DER-encoded RSAPublicKey (RFC 3447) structure. +// Parsing EC keys is not supported by this function. +// +// Use |RSA_parse_public_key| instead. +OPENSSL_EXPORT EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **out, + const uint8_t **inp, long len); + // EVP_PKEY_get0_DH returns NULL. OPENSSL_EXPORT DH *EVP_PKEY_get0_DH(const EVP_PKEY *pkey); diff --git a/include/openssl/mem.h b/include/openssl/mem.h index 9f9c00dd..4e1c2ca6 100644 --- a/include/openssl/mem.h +++ b/include/openssl/mem.h @@ -136,6 +136,10 @@ OPENSSL_EXPORT int BIO_vsnprintf(char *buf, size_t n, const char *format, #define CRYPTO_realloc OPENSSL_realloc #define CRYPTO_free OPENSSL_free +// OPENSSL_clear_free calls |OPENSSL_free|. BoringSSL automatically clears all +// allocations on free, but we define |OPENSSL_clear_free| for compatibility. +#define OPENSSL_clear_free(ptr, len) OPENSSL_free(ptr) + #if defined(__cplusplus) } // extern C