1f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin/* Copyright (c) 2016, Google Inc.
2f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin *
3f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * Permission to use, copy, modify, and/or distribute this software for any
4f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * purpose with or without fee is hereby granted, provided that the above
5f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * copyright notice and this permission notice appear in all copies.
6f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin *
7f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
15f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <stdio.h>
16f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
1729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan#include <utility>
18f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <vector>
19f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
208ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan#include <gtest/gtest.h>
218ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan
22f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/bn.h>
23f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/crypto.h>
24f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/ec.h>
25f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/ec_key.h>
26f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/ecdh.h>
2729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan#include <openssl/err.h>
28f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/nid.h>
29f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
30f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include "../test/file_test.h"
318ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan#include "../test/test_util.h"
32f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
33f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
34f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjaminstatic bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
35f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  std::string curve_name;
36f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (!t->GetAttribute(&curve_name, key)) {
37f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return nullptr;
38f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
39f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
40f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-224") {
41f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
42f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
43f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-256") {
44f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
45f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin        NID_X9_62_prime256v1));
46f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
47f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-384") {
48f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
49f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
50f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-521") {
51f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
52f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
53f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
54f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  t->PrintLine("Unknown curve '%s'", curve_name.c_str());
55f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  return nullptr;
56f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin}
57f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
58f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjaminstatic bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
59f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  std::vector<uint8_t> bytes;
60f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (!t->GetBytes(&bytes, key)) {
61f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return nullptr;
62f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
63f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
64f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  return bssl::UniquePtr<BIGNUM>(BN_bin2bn(bytes.data(), bytes.size(), nullptr));
65f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin}
66f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
678ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert SloanTEST(ECDHTest, TestVectors) {
688ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan  FileTestGTest("crypto/ecdh/ecdh_tests.txt", [](FileTest *t) {
698ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
708ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(group);
718ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
728ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(priv_key);
738ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
748ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(x);
758ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
768ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(y);
778ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<BIGNUM> peer_x = GetBIGNUM(t, "PeerX");
788ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(peer_x);
798ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<BIGNUM> peer_y = GetBIGNUM(t, "PeerY");
808ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(peer_y);
818ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    std::vector<uint8_t> z;
828ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(t->GetBytes(&z, "Z"));
838ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan
848ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
858ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(key);
868ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
878ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(pub_key);
888ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    bssl::UniquePtr<EC_POINT> peer_pub_key(EC_POINT_new(group.get()));
898ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(peer_pub_key);
908ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(EC_KEY_set_group(key.get(), group.get()));
918ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(EC_KEY_set_private_key(key.get(), priv_key.get()));
928ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(),
938ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan                                                    x.get(), y.get(), nullptr));
948ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
958ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan        group.get(), peer_pub_key.get(), peer_x.get(), peer_y.get(), nullptr));
968ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(EC_KEY_set_public_key(key.get(), pub_key.get()));
978ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_TRUE(EC_KEY_check_key(key.get()));
988ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan
998ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    std::vector<uint8_t> actual_z;
1008ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    // Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns
1018ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    // the right amount of data.
1028ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    actual_z.resize(z.size() + 1);
1038ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    int ret = ECDH_compute_key(actual_z.data(), actual_z.size(),
1048ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan                               peer_pub_key.get(), key.get(), nullptr);
1058ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_GE(ret, 0);
1068ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    EXPECT_EQ(Bytes(z), Bytes(actual_z.data(), static_cast<size_t>(ret)));
1078ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan
1088ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    // Test |ECDH_compute_key| truncates.
1098ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    actual_z.resize(z.size() - 1);
1108ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(),
1118ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan                           key.get(), nullptr);
1128ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    ASSERT_GE(ret, 0);
1138ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan    EXPECT_EQ(Bytes(z.data(), z.size() - 1),
1148ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan              Bytes(actual_z.data(), static_cast<size_t>(ret)));
1158ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan  });
116f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin}
11729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
11829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan// MakeCustomGroup returns an |EC_GROUP| containing a non-standard group. (P-256
11929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan// with the wrong generator.)
12029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloanstatic bssl::UniquePtr<EC_GROUP> MakeCustomGroup() {
12129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  static const uint8_t kP[] = {
12229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
12329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
12429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
12529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  };
12629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  static const uint8_t kA[] = {
12729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
12829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
12929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
13029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  };
13129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  static const uint8_t kB[] = {
13229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
13329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
13429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
13529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  };
13629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  static const uint8_t kX[] = {
13729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xe6, 0x2b, 0x69, 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e,
13829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x0d, 0x94, 0x8a, 0x4c, 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d,
13929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x46, 0xfb, 0xdd, 0xa9, 0xa9, 0x1e, 0x9d, 0xdc, 0xba, 0x5a,
14029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  };
14129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  static const uint8_t kY[] = {
14229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, 0xf9, 0xc3, 0xc4, 0xa3,
14329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, 0x1a, 0x1c, 0xf5,
14429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, 0xc1,
14529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  };
14629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  static const uint8_t kOrder[] = {
14729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
14829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
14929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
15029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  };
15129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
15229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
15329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
15429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
15529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<BIGNUM> x(BN_bin2bn(kX, sizeof(kX), nullptr));
15629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<BIGNUM> y(BN_bin2bn(kY, sizeof(kY), nullptr));
15729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
15829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  if (!ctx || !p || !a || !b || !x || !y || !order) {
15929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan    return nullptr;
16029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  }
16129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<EC_GROUP> group(
16229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
16329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  if (!group) {
16429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan    return nullptr;
16529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  }
16629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
16729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  if (!generator ||
16829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      !EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(),
16929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan                                           x.get(), y.get(), ctx.get()) ||
17029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      !EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
17129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan                              BN_value_one())) {
17229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan    return nullptr;
17329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  }
17429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  return group;
17529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan}
17629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
17729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert SloanTEST(ECDHTest, GroupMismatch) {
17829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
17929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  std::vector<EC_builtin_curve> curves(num_curves);
18029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  EC_get_builtin_curves(curves.data(), num_curves);
18129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
18229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  // Instantiate all the built-in curves.
18329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  std::vector<bssl::UniquePtr<EC_GROUP>> groups;
18429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  for (const auto &curve : curves) {
18529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan    groups.emplace_back(EC_GROUP_new_by_curve_name(curve.nid));
18629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan    ASSERT_TRUE(groups.back());
18729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  }
18829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
18929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  // Also create some arbitrary group. (This is P-256 with the wrong generator.)
19029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  groups.push_back(MakeCustomGroup());
19129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(groups.back());
19229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
19329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  for (const auto &a : groups) {
19429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan    for (const auto &b : groups) {
19529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      if (a.get() == b.get()) {
19629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan        continue;
19729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      }
19829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
19929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
20029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      ASSERT_TRUE(EC_KEY_set_group(key.get(), a.get()));
20129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      ASSERT_TRUE(EC_KEY_generate_key(key.get()));
20229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
20329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      // ECDH across the groups should not work.
20429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      char out[64];
20529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      const EC_POINT *peer = EC_GROUP_get0_generator(b.get());
20629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      EXPECT_EQ(-1,
20729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan                ECDH_compute_key(out, sizeof(out), peer, key.get(), nullptr));
20829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      ERR_clear_error();
20929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan    }
21029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  }
21129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan}
212