ecdh_test.cc revision f0c4a6c4bbde5229ceb86740703243fe5c436aad
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
17f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <vector>
18f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
19f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/bn.h>
20f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/crypto.h>
21f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/ec.h>
22f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/ec_key.h>
23f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/ecdh.h>
24f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/nid.h>
25f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
26f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include "../test/file_test.h"
27f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
28f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
29f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjaminstatic bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
30f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  std::string curve_name;
31f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (!t->GetAttribute(&curve_name, key)) {
32f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return nullptr;
33f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
34f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
35f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-224") {
36f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
37f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
38f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-256") {
39f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
40f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin        NID_X9_62_prime256v1));
41f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
42f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-384") {
43f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
44f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
45f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (curve_name == "P-521") {
46f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
47f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
48f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
49f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  t->PrintLine("Unknown curve '%s'", curve_name.c_str());
50f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  return nullptr;
51f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin}
52f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
53f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjaminstatic bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
54f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  std::vector<uint8_t> bytes;
55f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (!t->GetBytes(&bytes, key)) {
56f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return nullptr;
57f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
58f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
59f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  return bssl::UniquePtr<BIGNUM>(BN_bin2bn(bytes.data(), bytes.size(), nullptr));
60f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin}
61f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
62f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjaminstatic bool TestECDH(FileTest *t, void *arg) {
63f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
64f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> priv_key = GetBIGNUM(t, "Private");
65f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
66f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
67f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> peer_x = GetBIGNUM(t, "PeerX");
68f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> peer_y = GetBIGNUM(t, "PeerY");
69f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  std::vector<uint8_t> z;
70f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (!group || !priv_key || !x || !y || !peer_x || !peer_y ||
71f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !t->GetBytes(&z, "Z")) {
72f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return false;
73f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
74f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
75f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
76f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_POINT> pub_key(EC_POINT_new(group.get()));
77f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_POINT> peer_pub_key(EC_POINT_new(group.get()));
78f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (!key || !pub_key || !peer_pub_key ||
79f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !EC_KEY_set_group(key.get(), group.get()) ||
80f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !EC_KEY_set_private_key(key.get(), priv_key.get()) ||
81f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !EC_POINT_set_affine_coordinates_GFp(group.get(), pub_key.get(), x.get(),
82f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                                           y.get(), nullptr) ||
83f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !EC_POINT_set_affine_coordinates_GFp(group.get(), peer_pub_key.get(),
84f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                                           peer_x.get(), peer_y.get(),
85f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                                           nullptr) ||
86f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !EC_KEY_set_public_key(key.get(), pub_key.get()) ||
87f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !EC_KEY_check_key(key.get())) {
88f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return false;
89f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
90f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
91f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  std::vector<uint8_t> actual_z;
92f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  // Make |actual_z| larger than expected to ensure |ECDH_compute_key| returns
93f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  // the right amount of data.
94f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  actual_z.resize(z.size() + 1);
95f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  int ret = ECDH_compute_key(actual_z.data(), actual_z.size(),
96f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                             peer_pub_key.get(), key.get(), nullptr);
97f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (ret < 0 ||
98f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !t->ExpectBytesEqual(z.data(), z.size(), actual_z.data(),
99f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                           static_cast<size_t>(ret))) {
100f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return false;
101f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
102f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
103f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  // Test |ECDH_compute_key| truncates.
104f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  actual_z.resize(z.size() - 1);
105f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  ret = ECDH_compute_key(actual_z.data(), actual_z.size(), peer_pub_key.get(),
106f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                         key.get(), nullptr);
107f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (ret < 0 ||
108f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin      !t->ExpectBytesEqual(z.data(), z.size() - 1, actual_z.data(),
109f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                           static_cast<size_t>(ret))) {
110f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return false;
111f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
112f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
113f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  return true;
114f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin}
115f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
116f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjaminint main(int argc, char *argv[]) {
117f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  CRYPTO_library_init();
118f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
119f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  if (argc != 2) {
120f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    fprintf(stderr, "%s <test file.txt>\n", argv[0]);
121f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin    return 1;
122f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  }
123f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin
124f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  return FileTestMain(TestECDH, nullptr, argv[1]);
125f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin}
126