diff --git a/crypto/ec_extra/ec_asn1.c b/crypto/ec_extra/ec_asn1.c index 55737945deb..84eb31ae016 100644 --- a/crypto/ec_extra/ec_asn1.c +++ b/crypto/ec_extra/ec_asn1.c @@ -614,3 +614,44 @@ BIGNUM *EC_POINT_point2bn(const EC_GROUP *group, const EC_POINT *point, return ret; } + +EC_POINT *EC_POINT_bn2point(const EC_GROUP *group, + const BIGNUM *bn, EC_POINT *point, BN_CTX *ctx) { + EC_POINT *ret = NULL; + + // Allocate buffer and length. + size_t buf_len = BN_num_bytes(bn); + if (buf_len == 0) { + buf_len = 1; + } + uint8_t *buf = OPENSSL_malloc(buf_len); + if (buf == NULL) { + return NULL; + } + + if (BN_bn2bin_padded(buf, buf_len,bn) < 0) { + goto end; + } + + // Allocate new |EC_POINT| if |point| is NULL. Otherwise, use |point|. + if (point == NULL) { + ret = EC_POINT_new(group); + if (ret == NULL) { + goto end; + } + } else { + ret = point; + } + + if (!EC_POINT_oct2point(group, ret, buf, buf_len, ctx)) { + if (ret != point) { + // Free the newly allocated |EC_POINT| on failure. + EC_POINT_free(ret); + } + goto end; + } + +end: + OPENSSL_free(buf); + return ret; +} diff --git a/crypto/fipsmodule/ec/ec_test.cc b/crypto/fipsmodule/ec/ec_test.cc index 6e1ecaeb149..dc70464a845 100644 --- a/crypto/fipsmodule/ec/ec_test.cc +++ b/crypto/fipsmodule/ec/ec_test.cc @@ -1034,27 +1034,58 @@ TEST(ECTest, ArbitraryCurve) { ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(), order.get(), BN_value_one())); - EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), NULL)); - EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), NULL)); - - bssl::UniquePtr converted_generator1(EC_POINT_point2bn( - group.get(), generator.get(), POINT_CONVERSION_UNCOMPRESSED, NULL, NULL)); - ASSERT_TRUE(converted_generator1); - - bssl::UniquePtr converted_generator2(EC_POINT_point2bn( - group2.get(), generator2.get(), POINT_CONVERSION_UNCOMPRESSED, NULL, NULL)); + EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), nullptr)); + EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), nullptr)); + + // Convert |EC_POINT| to |BIGNUM| in uncompressed format with + // |EC_POINT_point2bn| and ensure results are the same. + bssl::UniquePtr converted_bignum( + EC_POINT_point2bn(group.get(), generator.get(), + POINT_CONVERSION_UNCOMPRESSED, nullptr, nullptr)); + ASSERT_TRUE(converted_bignum); + bssl::UniquePtr converted_bignum2( + EC_POINT_point2bn(group2.get(), generator2.get(), + POINT_CONVERSION_UNCOMPRESSED, nullptr, nullptr)); + ASSERT_TRUE(converted_bignum2); + EXPECT_EQ(0, BN_cmp(converted_bignum.get(), converted_bignum2.get())); + + // Convert |BIGNUM| back to |EC_POINTS| with |EC_POINT_bn2point| and ensure + // output is identical to the original. + bssl::UniquePtr converted_generator( + EC_POINT_bn2point(group.get(), converted_bignum.get(), nullptr, nullptr)); + ASSERT_TRUE(converted_generator); + EXPECT_EQ(0, EC_POINT_cmp(group.get(), generator.get(), + converted_generator.get(), nullptr)); + bssl::UniquePtr converted_generator2(EC_POINT_bn2point( + group2.get(), converted_bignum2.get(), nullptr, nullptr)); ASSERT_TRUE(converted_generator2); - EXPECT_EQ(0, BN_cmp(converted_generator1.get(), converted_generator2.get())); - - bssl::UniquePtr converted_generator3(EC_POINT_point2bn( - group.get(), generator.get(), POINT_CONVERSION_COMPRESSED, NULL, NULL)); - ASSERT_TRUE(converted_generator3); - - bssl::UniquePtr converted_generator4(EC_POINT_point2bn( - group2.get(), generator2.get(), POINT_CONVERSION_COMPRESSED, NULL, NULL)); - ASSERT_TRUE(converted_generator4); - EXPECT_EQ(0, BN_cmp(converted_generator3.get(), converted_generator4.get())); - + EXPECT_EQ(0, EC_POINT_cmp(group2.get(), generator2.get(), + converted_generator2.get(), nullptr)); + + // Convert |EC_POINT|s in compressed format with |EC_POINT_point2bn| and + // ensure results are the same. + converted_bignum.reset(EC_POINT_point2bn(group.get(), generator.get(), + POINT_CONVERSION_COMPRESSED, nullptr, + nullptr)); + ASSERT_TRUE(converted_bignum); + converted_bignum2.reset(EC_POINT_point2bn(group2.get(), generator2.get(), + POINT_CONVERSION_COMPRESSED, + nullptr, nullptr)); + ASSERT_TRUE(converted_bignum2); + EXPECT_EQ(0, BN_cmp(converted_bignum.get(), converted_bignum2.get())); + + // Convert |BIGNUM| back to |EC_POINTS| with |EC_POINT_bn2point| and ensure + // output is identical to the original. + converted_generator.reset( + EC_POINT_bn2point(group.get(), converted_bignum.get(), nullptr, nullptr)); + ASSERT_TRUE(converted_generator); + EXPECT_EQ(0, EC_POINT_cmp(group.get(), generator.get(), + converted_generator.get(), nullptr)); + converted_generator2.reset(EC_POINT_bn2point( + group2.get(), converted_bignum2.get(), nullptr, nullptr)); + ASSERT_TRUE(converted_generator2); + EXPECT_EQ(0, EC_POINT_cmp(group2.get(), generator2.get(), + converted_generator2.get(), nullptr)); // group3 uses the wrong generator. bssl::UniquePtr group3( diff --git a/include/openssl/ec.h b/include/openssl/ec.h index f1b9a6b2d07..64b2ecb7894 100644 --- a/include/openssl/ec.h +++ b/include/openssl/ec.h @@ -393,7 +393,7 @@ OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group, // EC_POINT_point2bn converts an |EC_POINT| to a |BIGNUM| by serializing the -// point into the X9.62 form given by |form| then interpretting it as a BIGNUM. +// point into the X9.62 form given by |form| then interpreting it as a BIGNUM. // On success, it returns the BIGNUM pointer supplied or, if |ret| is NULL, // allocates and returns a fresh |BIGNUM|. On error, it returns NULL. The |ctx| // argument may be used if not NULL. @@ -401,6 +401,13 @@ OPENSSL_EXPORT OPENSSL_DEPRECATED BIGNUM *EC_POINT_point2bn( const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form, BIGNUM *ret, BN_CTX *ctx); +// EC_POINT_bn2point is like |EC_POINT_point2bn|, but converts a |BIGNUM| to an +// |EC_POINT| instead. On success, it returns the EC_POINT pointer supplied or, +// if |ret| is NULL, allocates and returns a fresh |EC_POINT|. On error, it +// returns NULL. The |ctx| argument may be used if not NULL. +OPENSSL_EXPORT OPENSSL_DEPRECATED EC_POINT *EC_POINT_bn2point( + const EC_GROUP *group, const BIGNUM *bn, EC_POINT *point, BN_CTX *ctx); + // EC_GROUP_get_order sets |*order| to the order of |group|, if it's not // NULL. It returns one on success and zero otherwise. |ctx| is ignored. Use // |EC_GROUP_get0_order| instead.