Make EVP_PKEY_*_tls_encodedpoint work with EVP_PKEY_EC.
Some third-party code requires it.
For now, I've just introduced a new hook on the method table. This is
rather goofy though. First, making EVP know about TLS is a layering
violation that OpenSSL introduced. They've since fixed this and added
EVP_PKEY_get1_encoded_public_key in OpenSSL 3.0, but callers expect the
TLS one to exist in OpenSSL 1.1.1, so implement that one.
Along the way, implement EC_KEY_oct2key from upstream, which is slightly
less tedious when you're already working in EC_KEY.
To make this third-party code work (and to write a test without dipping
out of EVP, or using the very tedious EVP_PKEY_paramgen API), we also
need to change EVP_PKEY_copy_parameters to work when the source EVP_PKEY
is empty, per upstream's 2986ecdc08016de978f1134315623778420b51e5.
OpenSSL's API has *multiple* levels of empty states to worry about!
Something to avoid when we get to rethinking this error-prone API.
Bug: b:238920520
Change-Id: I3fd99be560db313c1bf549a4e46ffccc31e746e1
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/54905
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/evp/evp.c b/crypto/evp/evp.c
index bb31645..e982af7 100644
--- a/crypto/evp/evp.c
+++ b/crypto/evp/evp.c
@@ -448,6 +448,25 @@
void EVP_cleanup(void) {}
+int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, const uint8_t *in,
+ size_t len) {
+ if (pkey->ameth->set1_tls_encodedpoint == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return 0;
+ }
+
+ return pkey->ameth->set1_tls_encodedpoint(pkey, in, len);
+}
+
+size_t EVP_PKEY_get1_tls_encodedpoint(const EVP_PKEY *pkey, uint8_t **out_ptr) {
+ if (pkey->ameth->get1_tls_encodedpoint == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ return 0;
+ }
+
+ return pkey->ameth->get1_tls_encodedpoint(pkey, out_ptr);
+}
+
int EVP_PKEY_base_id(const EVP_PKEY *pkey) {
// OpenSSL has two notions of key type because it supports multiple OIDs for
// the same algorithm: NID_rsa vs NID_rsaEncryption and five distinct spelling
diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc
index f520598..0b915bd 100644
--- a/crypto/evp/evp_extra_test.cc
+++ b/crypto/evp/evp_extra_test.cc
@@ -782,3 +782,69 @@
ASSERT_TRUE(EVP_DigestVerify(ctx.get(), sig, len,
reinterpret_cast<const uint8_t *>("hello"), 5));
}
+
+// Test that OpenSSL's legacy TLS-specific APIs in EVP work correctly. When we
+// target OpenSSL 3.0, these should be renamed to
+// |EVP_PKEY_get1_encoded_public_key|.
+TEST(EVPExtraTest, TLSEncodedPoint) {
+ const struct {
+ int pkey_type;
+ std::vector<uint8_t> spki;
+ std::vector<uint8_t> encoded_point;
+ } kTests[] = {
+ {EVP_PKEY_EC,
+ {0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+ 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+ 0x42, 0x00, 0x04, 0x2c, 0x15, 0x0f, 0x42, 0x9c, 0xe7, 0x0f, 0x21, 0x6c,
+ 0x25, 0x2c, 0xf5, 0xe0, 0x62, 0xce, 0x1f, 0x63, 0x9c, 0xd5, 0xd1, 0x65,
+ 0xc7, 0xf8, 0x94, 0x24, 0x07, 0x2c, 0x27, 0x19, 0x7d, 0x78, 0xb3, 0x3b,
+ 0x92, 0x0e, 0x95, 0xcd, 0xb6, 0x64, 0xe9, 0x90, 0xdc, 0xf0, 0xcf, 0xea,
+ 0x0d, 0x94, 0xe2, 0xa8, 0xe6, 0xaf, 0x9d, 0x0e, 0x58, 0x05, 0x6e, 0x65,
+ 0x31, 0x04, 0x92, 0x5b, 0x9f, 0xe6, 0xc9},
+ {0x04, 0x2c, 0x15, 0x0f, 0x42, 0x9c, 0xe7, 0x0f, 0x21, 0x6c, 0x25,
+ 0x2c, 0xf5, 0xe0, 0x62, 0xce, 0x1f, 0x63, 0x9c, 0xd5, 0xd1, 0x65,
+ 0xc7, 0xf8, 0x94, 0x24, 0x07, 0x2c, 0x27, 0x19, 0x7d, 0x78, 0xb3,
+ 0x3b, 0x92, 0x0e, 0x95, 0xcd, 0xb6, 0x64, 0xe9, 0x90, 0xdc, 0xf0,
+ 0xcf, 0xea, 0x0d, 0x94, 0xe2, 0xa8, 0xe6, 0xaf, 0x9d, 0x0e, 0x58,
+ 0x05, 0x6e, 0x65, 0x31, 0x04, 0x92, 0x5b, 0x9f, 0xe6, 0xc9}},
+ {EVP_PKEY_X25519,
+ {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21,
+ 0x00, 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94,
+ 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26,
+ 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c},
+ {0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
+ 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
+ 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c}}};
+ for (const auto& test : kTests) {
+ SCOPED_TRACE(test.pkey_type);
+ SCOPED_TRACE(Bytes(test.spki));
+ CBS spki;
+ CBS_init(&spki, test.spki.data(), test.spki.size());
+ bssl::UniquePtr<EVP_PKEY> from_spki(EVP_parse_public_key(&spki));
+ ASSERT_TRUE(from_spki);
+
+ uint8_t *data;
+ size_t len = EVP_PKEY_get1_tls_encodedpoint(from_spki.get(), &data);
+ ASSERT_GT(len, 0u);
+ EXPECT_EQ(Bytes(data, len), Bytes(test.encoded_point));
+ OPENSSL_free(data);
+
+ bssl::UniquePtr<EVP_PKEY> from_encoded_point(EVP_PKEY_new());
+ ASSERT_TRUE(from_encoded_point);
+ ASSERT_TRUE(EVP_PKEY_set_type(from_encoded_point.get(), test.pkey_type));
+ if (test.pkey_type == EVP_PKEY_EC) {
+ // |EVP_PKEY_EC| should have been |EVP_PKEY_EC_P256|, etc., but instead
+ // part of the type is buried inside parameters.
+ ASSERT_TRUE(
+ EVP_PKEY_copy_parameters(from_encoded_point.get(), from_spki.get()));
+ }
+ ASSERT_TRUE(EVP_PKEY_set1_tls_encodedpoint(from_encoded_point.get(),
+ test.encoded_point.data(),
+ test.encoded_point.size()));
+
+ bssl::ScopedCBB cbb;
+ ASSERT_TRUE(CBB_init(cbb.get(), test.spki.size()));
+ ASSERT_TRUE(EVP_marshal_public_key(cbb.get(), from_encoded_point.get()));
+ EXPECT_EQ(Bytes(CBB_data(cbb.get()), CBB_len(cbb.get())), Bytes(test.spki));
+ }
+}
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index 0037de8..f189d4e 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -103,6 +103,17 @@
int (*get_priv_raw)(const EVP_PKEY *pkey, uint8_t *out, size_t *out_len);
int (*get_pub_raw)(const EVP_PKEY *pkey, uint8_t *out, size_t *out_len);
+ // TODO(davidben): Can these be merged with the functions above? OpenSSL does
+ // not implement |EVP_PKEY_get_raw_public_key|, etc., for |EVP_PKEY_EC|, but
+ // the distinction seems unimportant. OpenSSL 3.0 has since renamed
+ // |EVP_PKEY_get1_tls_encodedpoint| to |EVP_PKEY_get1_encoded_public_key|, and
+ // what is the difference between "raw" and an "encoded" public key.
+ //
+ // One nuisance is the notion of "raw" is slightly ambiguous for EC keys. Is
+ // it a DER ECPrivateKey or just the scalar?
+ int (*set1_tls_encodedpoint)(EVP_PKEY *pkey, const uint8_t *in, size_t len);
+ size_t (*get1_tls_encodedpoint)(const EVP_PKEY *pkey, uint8_t **out_ptr);
+
// 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);
diff --git a/crypto/evp/p_dsa_asn1.c b/crypto/evp/p_dsa_asn1.c
index 98615b7..cd787dd 100644
--- a/crypto/evp/p_dsa_asn1.c
+++ b/crypto/evp/p_dsa_asn1.c
@@ -248,34 +248,37 @@
static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); }
const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = {
- EVP_PKEY_DSA,
- // 1.2.840.10040.4.1
- {0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01}, 7,
+ EVP_PKEY_DSA,
+ // 1.2.840.10040.4.1
+ {0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01},
+ 7,
- NULL /* pkey_method */,
+ /*pkey_method=*/NULL,
- dsa_pub_decode,
- dsa_pub_encode,
- dsa_pub_cmp,
+ dsa_pub_decode,
+ dsa_pub_encode,
+ dsa_pub_cmp,
- dsa_priv_decode,
- dsa_priv_encode,
+ dsa_priv_decode,
+ dsa_priv_encode,
- NULL /* set_priv_raw */,
- NULL /* set_pub_raw */,
- NULL /* get_priv_raw */,
- NULL /* get_pub_raw */,
+ /*set_priv_raw=*/NULL,
+ /*set_pub_raw=*/NULL,
+ /*get_priv_raw=*/NULL,
+ /*get_pub_raw=*/NULL,
+ /*set1_tls_encodedpoint=*/NULL,
+ /*get1_tls_encodedpoint=*/NULL,
- NULL /* pkey_opaque */,
+ /*pkey_opaque=*/NULL,
- int_dsa_size,
- dsa_bits,
+ int_dsa_size,
+ dsa_bits,
- dsa_missing_parameters,
- dsa_copy_parameters,
- dsa_cmp_parameters,
+ dsa_missing_parameters,
+ dsa_copy_parameters,
+ dsa_cmp_parameters,
- int_dsa_free,
+ int_dsa_free,
};
int EVP_PKEY_CTX_set_dsa_paramgen_bits(EVP_PKEY_CTX *ctx, int nbits) {
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
index dd42121..c21cfd8 100644
--- a/crypto/evp/p_ec_asn1.c
+++ b/crypto/evp/p_ec_asn1.c
@@ -93,7 +93,6 @@
// See RFC 5480, section 2.
// The parameters are a named curve.
- EC_POINT *point = NULL;
EC_KEY *eckey = NULL;
EC_GROUP *group = EC_KEY_parse_curve_name(params);
if (group == NULL || CBS_len(params) != 0) {
@@ -102,25 +101,18 @@
}
eckey = EC_KEY_new();
- if (eckey == NULL || !EC_KEY_set_group(eckey, group)) {
- goto err;
- }
-
- point = EC_POINT_new(group);
- if (point == NULL ||
- !EC_POINT_oct2point(group, point, CBS_data(key), CBS_len(key), NULL) ||
- !EC_KEY_set_public_key(eckey, point)) {
+ if (eckey == NULL || //
+ !EC_KEY_set_group(eckey, group) ||
+ !EC_KEY_oct2key(eckey, CBS_data(key), CBS_len(key), NULL)) {
goto err;
}
EC_GROUP_free(group);
- EC_POINT_free(point);
EVP_PKEY_assign_EC_KEY(out, eckey);
return 1;
err:
EC_GROUP_free(group);
- EC_POINT_free(point);
EC_KEY_free(eckey);
return 0;
}
@@ -188,6 +180,28 @@
return 1;
}
+static int eckey_set1_tls_encodedpoint(EVP_PKEY *pkey, const uint8_t *in,
+ size_t len) {
+ EC_KEY *ec_key = pkey->pkey.ec;
+ if (ec_key == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
+ return 0;
+ }
+
+ return EC_KEY_oct2key(ec_key, in, len, NULL);
+}
+
+static size_t eckey_get1_tls_encodedpoint(const EVP_PKEY *pkey,
+ uint8_t **out_ptr) {
+ const EC_KEY *ec_key = pkey->pkey.ec;
+ if (ec_key == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
+ return 0;
+ }
+
+ return EC_KEY_key2buf(ec_key, POINT_CONVERSION_UNCOMPRESSED, out_ptr, NULL);
+}
+
static int int_ec_size(const EVP_PKEY *pkey) {
return ECDSA_size(pkey->pkey.ec);
}
@@ -206,7 +220,22 @@
}
static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) {
- return EC_KEY_set_group(to->pkey.ec, EC_KEY_get0_group(from->pkey.ec));
+ if (from->pkey.ec == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
+ return 0;
+ }
+ const EC_GROUP *group = EC_KEY_get0_group(from->pkey.ec);
+ if (group == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
+ return 0;
+ }
+ if (to->pkey.ec == NULL) {
+ to->pkey.ec = EC_KEY_new();
+ if (to->pkey.ec == NULL) {
+ return 0;
+ }
+ }
+ return EC_KEY_set_group(to->pkey.ec, group);
}
static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) {
@@ -226,32 +255,35 @@
}
const EVP_PKEY_ASN1_METHOD ec_asn1_meth = {
- EVP_PKEY_EC,
- // 1.2.840.10045.2.1
- {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01}, 7,
+ EVP_PKEY_EC,
+ // 1.2.840.10045.2.1
+ {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01},
+ 7,
- &ec_pkey_meth,
+ &ec_pkey_meth,
- eckey_pub_decode,
- eckey_pub_encode,
- eckey_pub_cmp,
+ eckey_pub_decode,
+ eckey_pub_encode,
+ eckey_pub_cmp,
- eckey_priv_decode,
- eckey_priv_encode,
+ eckey_priv_decode,
+ eckey_priv_encode,
- NULL /* set_priv_raw */,
- NULL /* set_pub_raw */,
- NULL /* get_priv_raw */,
- NULL /* get_pub_raw */,
+ /*set_priv_raw=*/NULL,
+ /*set_pub_raw=*/NULL,
+ /*get_priv_raw=*/NULL,
+ /*get_pub_raw=*/NULL,
+ eckey_set1_tls_encodedpoint,
+ eckey_get1_tls_encodedpoint,
- eckey_opaque,
+ eckey_opaque,
- int_ec_size,
- ec_bits,
+ int_ec_size,
+ ec_bits,
- ec_missing_parameters,
- ec_copy_parameters,
- ec_cmp_parameters,
+ ec_missing_parameters,
+ ec_copy_parameters,
+ ec_cmp_parameters,
- int_ec_free,
+ int_ec_free,
};
diff --git a/crypto/evp/p_ed25519_asn1.c b/crypto/evp/p_ed25519_asn1.c
index f823c0d..9f9251c 100644
--- a/crypto/evp/p_ed25519_asn1.c
+++ b/crypto/evp/p_ed25519_asn1.c
@@ -214,11 +214,13 @@
ed25519_set_pub_raw,
ed25519_get_priv_raw,
ed25519_get_pub_raw,
- NULL /* pkey_opaque */,
+ /*set1_tls_encodedpoint=*/NULL,
+ /*get1_tls_encodedpoint=*/NULL,
+ /*pkey_opaque=*/NULL,
ed25519_size,
ed25519_bits,
- NULL /* param_missing */,
- NULL /* param_copy */,
- NULL /* param_cmp */,
+ /*param_missing=*/NULL,
+ /*param_copy=*/NULL,
+ /*param_cmp=*/NULL,
ed25519_free,
};
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index 2e4942a..cfaf694 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -167,30 +167,35 @@
static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); }
const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
- EVP_PKEY_RSA,
- // 1.2.840.113549.1.1.1
- {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01}, 9,
+ EVP_PKEY_RSA,
+ // 1.2.840.113549.1.1.1
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01},
+ 9,
- &rsa_pkey_meth,
+ &rsa_pkey_meth,
- rsa_pub_decode,
- rsa_pub_encode,
- rsa_pub_cmp,
+ rsa_pub_decode,
+ rsa_pub_encode,
+ rsa_pub_cmp,
- rsa_priv_decode,
- rsa_priv_encode,
+ rsa_priv_decode,
+ rsa_priv_encode,
- NULL /* set_priv_raw */,
- NULL /* set_pub_raw */,
- NULL /* get_priv_raw */,
- NULL /* get_pub_raw */,
+ /*set_priv_raw=*/NULL,
+ /*set_pub_raw=*/NULL,
+ /*get_priv_raw=*/NULL,
+ /*get_pub_raw=*/NULL,
+ /*set1_tls_encodedpoint=*/NULL,
+ /*get1_tls_encodedpoint=*/NULL,
- rsa_opaque,
+ rsa_opaque,
- int_rsa_size,
- rsa_bits,
+ int_rsa_size,
+ rsa_bits,
- 0,0,0,
+ 0,
+ 0,
+ 0,
- int_rsa_free,
+ int_rsa_free,
};
diff --git a/crypto/evp/p_x25519_asn1.c b/crypto/evp/p_x25519_asn1.c
index 182f6a2..e36b41e 100644
--- a/crypto/evp/p_x25519_asn1.c
+++ b/crypto/evp/p_x25519_asn1.c
@@ -110,6 +110,23 @@
return 1;
}
+static int x25519_set1_tls_encodedpoint(EVP_PKEY *pkey, const uint8_t *in,
+ size_t len) {
+ return x25519_set_pub_raw(pkey, in, len);
+}
+
+static size_t x25519_get1_tls_encodedpoint(const EVP_PKEY *pkey,
+ uint8_t **out_ptr) {
+ const X25519_KEY *key = pkey->pkey.ptr;
+ if (key == NULL) {
+ OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
+ return 0;
+ }
+
+ *out_ptr = OPENSSL_memdup(key->pub, 32);
+ return *out_ptr == NULL ? 0 : 32;
+}
+
static int x25519_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) {
// See RFC 8410, section 4.
@@ -209,41 +226,13 @@
x25519_set_pub_raw,
x25519_get_priv_raw,
x25519_get_pub_raw,
- NULL /* pkey_opaque */,
+ x25519_set1_tls_encodedpoint,
+ x25519_get1_tls_encodedpoint,
+ /*pkey_opaque=*/NULL,
x25519_size,
x25519_bits,
- NULL /* param_missing */,
- NULL /* param_copy */,
- NULL /* param_cmp */,
+ /*param_missing=*/NULL,
+ /*param_copy=*/NULL,
+ /*param_cmp=*/NULL,
x25519_free,
};
-
-int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey, const uint8_t *in,
- size_t len) {
- // TODO(davidben): In OpenSSL, this function also works for |EVP_PKEY_EC|
- // keys. Add support if it ever comes up.
- if (pkey->type != EVP_PKEY_X25519) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
- return 0;
- }
-
- return x25519_set_pub_raw(pkey, in, len);
-}
-
-size_t EVP_PKEY_get1_tls_encodedpoint(const EVP_PKEY *pkey, uint8_t **out_ptr) {
- // TODO(davidben): In OpenSSL, this function also works for |EVP_PKEY_EC|
- // keys. Add support if it ever comes up.
- if (pkey->type != EVP_PKEY_X25519) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
- return 0;
- }
-
- const X25519_KEY *key = pkey->pkey.ptr;
- if (key == NULL) {
- OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
- return 0;
- }
-
- *out_ptr = OPENSSL_memdup(key->pub, 32);
- return *out_ptr == NULL ? 0 : 32;
-}
diff --git a/crypto/fipsmodule/ec/ec_key.c b/crypto/fipsmodule/ec/ec_key.c
index e676e3c..3b3da24 100644
--- a/crypto/fipsmodule/ec/ec_key.c
+++ b/crypto/fipsmodule/ec/ec_key.c
@@ -394,6 +394,20 @@
return ok;
}
+int EC_KEY_oct2key(EC_KEY *key, const uint8_t *in, size_t len, BN_CTX *ctx) {
+ if (key->group == NULL) {
+ OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
+ return 0;
+ }
+
+ EC_POINT *point = EC_POINT_new(key->group);
+ int ok = point != NULL &&
+ EC_POINT_oct2point(key->group, point, in, len, ctx) &&
+ EC_KEY_set_public_key(key, point);
+ EC_POINT_free(point);
+ return ok;
+}
+
size_t EC_KEY_key2buf(const EC_KEY *key, point_conversion_form_t form,
unsigned char **out_buf, BN_CTX *ctx) {
if (key == NULL || key->pub_key == NULL || key->group == NULL) {
diff --git a/include/openssl/ec_key.h b/include/openssl/ec_key.h
index 502bfc2..3143290 100644
--- a/include/openssl/ec_key.h
+++ b/include/openssl/ec_key.h
@@ -179,6 +179,13 @@
const BIGNUM *x,
const BIGNUM *y);
+// EC_KEY_oct2key decodes |len| bytes from |in| as an EC public key in X9.62
+// form. |key| must already have a group configured. On success, it sets the
+// public key in |key| to the result and returns one. Otherwise, it returns
+// zero.
+OPENSSL_EXPORT int EC_KEY_oct2key(EC_KEY *key, const uint8_t *in, size_t len,
+ BN_CTX *ctx);
+
// EC_KEY_key2buf encodes the public key in |key| to an allocated octet string
// and sets |*out_buf| to point to it. It returns the length of the encoded
// octet string or zero if an error occurred.
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 37daa9a..d8bd011 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -936,7 +936,10 @@
// EVP_PKEY_set1_tls_encodedpoint replaces |pkey| with a public key encoded by
// |in|. It returns one on success and zero on error.
//
-// This function only works on X25519 keys.
+// If |pkey| is an EC key, the format is an X9.62 point and |pkey| must already
+// have an EC group configured. If it is an X25519 key, it is the 32-byte X25519
+// public key representation. This function is not supported for other key types
+// and will fail.
OPENSSL_EXPORT int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey,
const uint8_t *in,
size_t len);
@@ -946,7 +949,10 @@
// |OPENSSL_free| to release this buffer. The function returns the length of the
// buffer on success and zero on error.
//
-// This function only works on X25519 keys.
+// If |pkey| is an EC key, the format is an X9.62 point with uncompressed
+// coordinates. If it is an X25519 key, it is the 32-byte X25519 public key
+// representation. This function is not supported for other key types and will
+// fail.
OPENSSL_EXPORT size_t EVP_PKEY_get1_tls_encodedpoint(const EVP_PKEY *pkey,
uint8_t **out_ptr);
diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
index f65492c..460a8e9 100644
--- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc
+++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -1558,12 +1558,8 @@
bssl::UniquePtr<BIGNUM> x(BytesToBIGNUM(args[1]));
bssl::UniquePtr<BIGNUM> y(BytesToBIGNUM(args[2]));
- bssl::UniquePtr<EC_POINT> point(EC_POINT_new(EC_KEY_get0_group(key.get())));
uint8_t reply[1];
- if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
- point.get(), x.get(), y.get(),
- /*ctx=*/nullptr) ||
- !EC_KEY_set_public_key(key.get(), point.get()) ||
+ if (!EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()) ||
!EC_KEY_check_fips(key.get())) {
reply[0] = 0;
} else {
@@ -1636,12 +1632,8 @@
return false;
}
- bssl::UniquePtr<EC_POINT> point(EC_POINT_new(EC_KEY_get0_group(key.get())));
uint8_t reply[1];
- if (!EC_POINT_set_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
- point.get(), x.get(), y.get(),
- /*ctx=*/nullptr) ||
- !EC_KEY_set_public_key(key.get(), point.get()) ||
+ if (!EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()) ||
!EC_KEY_check_fips(key.get()) ||
!ECDSA_do_verify(digest, digest_len, &sig, key.get())) {
reply[0] = 0;