Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for EC_POINT_bn2point #1645

Merged
merged 3 commits into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions crypto/ec_extra/ec_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,3 +614,52 @@ 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) {
if (group == NULL || bn == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}

// Allocate buffer and length.
size_t buf_len = BN_num_bytes(bn);
dkostic marked this conversation as resolved.
Show resolved Hide resolved
if (buf_len == 0) {
samuel40791765 marked this conversation as resolved.
Show resolved Hide resolved
// See https://github.com/openssl/openssl/issues/10258.
buf_len = 1;
}
uint8_t *buf = OPENSSL_malloc(buf_len);
if (buf == NULL) {
return NULL;
}

if (BN_bn2bin_padded(buf, buf_len, bn) < 0) {
OPENSSL_free(buf);
return NULL;
}

// Use the user-provided |point| if there is one. Otherwise, we allocate a new
// |EC_POINT| if |point| is NULL.
EC_POINT *ret;
if (point != NULL) {
ret = point;
} else {
ret = EC_POINT_new(group);
if (ret == NULL) {
OPENSSL_free(buf);
return NULL;
}
}

if (!EC_POINT_oct2point(group, ret, buf, buf_len, ctx)) {
if (ret != point) {
// If the user did not provide a |point|, we free the |EC_POINT| we
// allocated.
EC_POINT_free(ret);
}
}

OPENSSL_free(buf);
return ret;
}

193 changes: 135 additions & 58 deletions crypto/fipsmodule/ec/ec_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -938,56 +938,58 @@ TEST(ECTest, SpecifiedCurve) {
EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
}

// An arbitrary curve which is identical to P-256.
static const uint8_t kP256P[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const uint8_t kP256A[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
};
static const uint8_t kP256B[] = {
0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
};
static const uint8_t kP256X[] = {
0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6,
0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96,
};
static const uint8_t kP256Y[] = {
0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb,
0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
};
static const uint8_t kP256Order[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
};

TEST(ECTest, ArbitraryCurve) {
// Make a P-256 key and extract the affine coordinates.
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
ASSERT_TRUE(key);
ASSERT_TRUE(EC_KEY_generate_key(key.get()));

// Make an arbitrary curve which is identical to P-256.
static const uint8_t kP[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const uint8_t kA[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
};
static const uint8_t kB[] = {
0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
};
static const uint8_t kX[] = {
0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6,
0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96,
};
static const uint8_t kY[] = {
0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb,
0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
};
static const uint8_t kOrder[] = {
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
};
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
ASSERT_TRUE(ctx);
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP256P, sizeof(kP256P), nullptr));
ASSERT_TRUE(p);
bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kP256A, sizeof(kP256A), nullptr));
ASSERT_TRUE(a);
bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kP256B, sizeof(kP256B), nullptr));
ASSERT_TRUE(b);
bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kX, sizeof(kX), nullptr));
bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kP256X, sizeof(kP256X), nullptr));
ASSERT_TRUE(gx);
bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kY, sizeof(kY), nullptr));
bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kP256Y, sizeof(kP256Y), nullptr));
ASSERT_TRUE(gy);
bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
bssl::UniquePtr<BIGNUM> order(
BN_bin2bn(kP256Order, sizeof(kP256Order), nullptr));
ASSERT_TRUE(order);

bssl::UniquePtr<EC_GROUP> group(
Expand Down Expand Up @@ -1034,27 +1036,8 @@ 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<BIGNUM> converted_generator1(EC_POINT_point2bn(
group.get(), generator.get(), POINT_CONVERSION_UNCOMPRESSED, NULL, NULL));
ASSERT_TRUE(converted_generator1);

bssl::UniquePtr<BIGNUM> converted_generator2(EC_POINT_point2bn(
group2.get(), generator2.get(), POINT_CONVERSION_UNCOMPRESSED, NULL, NULL));
ASSERT_TRUE(converted_generator2);
EXPECT_EQ(0, BN_cmp(converted_generator1.get(), converted_generator2.get()));

bssl::UniquePtr<BIGNUM> converted_generator3(EC_POINT_point2bn(
group.get(), generator.get(), POINT_CONVERSION_COMPRESSED, NULL, NULL));
ASSERT_TRUE(converted_generator3);

bssl::UniquePtr<BIGNUM> 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_GROUP_cmp(group.get(), group.get(), nullptr));
EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), nullptr));

// group3 uses the wrong generator.
bssl::UniquePtr<EC_GROUP> group3(
Expand Down Expand Up @@ -1110,6 +1093,100 @@ TEST(ECTest, ArbitraryCurve) {
EXPECT_EQ(0, EC_GROUP_cmp(group5.get(), group.get(), NULL));
}

TEST(ECTest, BIGNUMConvert) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
ASSERT_TRUE(ctx);
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP256P, sizeof(kP256P), nullptr));
ASSERT_TRUE(p);
bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kP256A, sizeof(kP256A), nullptr));
ASSERT_TRUE(a);
bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kP256B, sizeof(kP256B), nullptr));
ASSERT_TRUE(b);
bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kP256X, sizeof(kP256X), nullptr));
ASSERT_TRUE(gx);
bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kP256Y, sizeof(kP256Y), nullptr));
ASSERT_TRUE(gy);
bssl::UniquePtr<BIGNUM> order(
BN_bin2bn(kP256Order, sizeof(kP256Order), nullptr));
ASSERT_TRUE(order);

bssl::UniquePtr<EC_GROUP> group(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
ASSERT_TRUE(group);
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
ASSERT_TRUE(generator);
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
group.get(), generator.get(), gx.get(), gy.get(), ctx.get()));
ASSERT_TRUE(EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
BN_value_one()));

// Make a second instance of |group|.
bssl::UniquePtr<EC_GROUP> group2(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
ASSERT_TRUE(group2);
bssl::UniquePtr<EC_POINT> generator2(EC_POINT_new(group2.get()));
ASSERT_TRUE(generator2);
ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
group2.get(), generator2.get(), gx.get(), gy.get(), ctx.get()));
ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(),
order.get(), BN_value_one()));

// Convert |EC_POINT| to |BIGNUM| in uncompressed format with
// |EC_POINT_point2bn| and ensure results are the same.
bssl::UniquePtr<BIGNUM> converted_bignum(
EC_POINT_point2bn(group.get(), generator.get(),
POINT_CONVERSION_UNCOMPRESSED, nullptr, nullptr));
ASSERT_TRUE(converted_bignum);
bssl::UniquePtr<BIGNUM> 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<EC_POINT> 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<EC_POINT> converted_generator2(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));

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

// Test specific openssl/openssl#10258 case for |BN_zero|.
bssl::UniquePtr<BIGNUM> zero(BN_new());
BN_zero(zero.get());
EXPECT_TRUE(EC_POINT_bn2point(group.get(), zero.get(), nullptr, nullptr));
}

TEST(ECTest, SetKeyWithoutGroup) {
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
ASSERT_TRUE(key);
Expand Down
25 changes: 20 additions & 5 deletions include/openssl/ec.h
Original file line number Diff line number Diff line change
Expand Up @@ -391,15 +391,30 @@ OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group,
const BIGNUM *cofactor);


// 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.
// 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.
// EC_POINT_point2bn calls |EC_POINT_point2oct| to serialize |point| into the
// X9.62 form given by |form| and returns the serialized output as a |BIGNUM|.
// The returned |BIGNUM| is a representation of serialized bytes. 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.
//
// Note: |EC_POINT|s are not individual |BIGNUM| integers, so these aren't
// particularly useful. Use |EC_POINT_point2oct| directly instead.
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 calls |EC_POINT_oct2point|
// to de-serialize the |BIGNUM| representation of bytes back to an |EC_POINT|.
// 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.
//
// Note: |EC_POINT|s are not individual |BIGNUM| integers, so these aren't
// particularly useful. Use |EC_POINT_oct2point| directly instead.
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.
Expand Down
Loading