proxygen
OpenSSLKeyUtils.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
10 
11 #include <openssl/err.h>
12 
13 namespace fizz {
14 namespace detail {
15 
16 void validateECKey(const folly::ssl::EvpPkeyUniquePtr& key, int curveNid) {
17  folly::ssl::EcKeyUniquePtr ecKey(EVP_PKEY_get1_EC_KEY(key.get()));
18  if (!ecKey) {
19  throw std::runtime_error("Wrong key type");
20  }
21  if (EC_KEY_check_key(ecKey.get()) != 1) {
22  throw std::runtime_error("Private key not valid");
23  }
24  folly::ssl::EcGroupUniquePtr curve(EC_GROUP_new_by_curve_name(curveNid));
25  if (!curve) {
26  throw std::runtime_error("Failed to create curve");
27  }
28  auto keyGroup = EC_KEY_get0_group(ecKey.get());
29  if (EC_GROUP_cmp(keyGroup, curve.get(), nullptr) != 0) {
30  throw std::runtime_error("Invalid group");
31  }
32 }
33 
34 std::unique_ptr<folly::IOBuf> generateEvpSharedSecret(
36  const folly::ssl::EvpPkeyUniquePtr& peerKey) {
37  folly::ssl::EvpPkeyCtxUniquePtr ctx(EVP_PKEY_CTX_new(key.get(), nullptr));
38  if (EVP_PKEY_derive_init(ctx.get()) != 1) {
39  throw std::runtime_error("Initializing derive context failed");
40  }
41  // Start deriving the key.
42  if (EVP_PKEY_derive_set_peer(ctx.get(), peerKey.get()) != 1) {
43  throw std::runtime_error("Error setting peer key");
44  }
45  size_t secretLen = 0;
46  if (EVP_PKEY_derive(ctx.get(), nullptr, &secretLen) != 1) {
47  throw std::runtime_error("Error deriving key");
48  }
49  // secretLen is now the maximum secret length.
50  auto buf = folly::IOBuf::create(secretLen);
51  if (EVP_PKEY_derive(ctx.get(), buf->writableData(), &secretLen) != 1) {
52  throw std::runtime_error("Error deriving key");
53  }
54  buf->append(secretLen);
55  return buf;
56 }
57 
59  folly::ssl::EcKeyUniquePtr ecParamKey(EC_KEY_new_by_curve_name(curveNid));
60  folly::ssl::EvpPkeyUniquePtr params(EVP_PKEY_new());
61  if (!ecParamKey || !params) {
62  throw std::runtime_error("Error initializing params");
63  }
64  if (EVP_PKEY_set1_EC_KEY(params.get(), ecParamKey.get()) != 1) {
65  throw std::runtime_error("Error setting ec key for params");
66  }
67  folly::ssl::EvpPkeyCtxUniquePtr kctx(EVP_PKEY_CTX_new(params.get(), nullptr));
68  if (!kctx) {
69  throw std::runtime_error("Error creating kctx");
70  }
71  if (EVP_PKEY_keygen_init(kctx.get()) != 1) {
72  throw std::runtime_error("Error initializing ctx");
73  }
74  EVP_PKEY* pkey = nullptr;
75  if (EVP_PKEY_keygen(kctx.get(), &pkey) != 1) {
76  throw std::runtime_error("Error generating key");
77  }
78  folly::ssl::EvpPkeyUniquePtr evpKey(pkey);
79  folly::ssl::EcKeyUniquePtr ecKey(EVP_PKEY_get1_EC_KEY(evpKey.get()));
80  validateECKey(evpKey, curveNid);
81  return evpKey;
82 }
83 
86  int curveNid) {
87  // Get the peer key.
88  folly::ssl::EcGroupUniquePtr curve(EC_GROUP_new_by_curve_name(curveNid));
89  folly::ssl::EcKeyUniquePtr peerKey(EC_KEY_new_by_curve_name(curveNid));
90  if (!curve || !peerKey) {
91  throw std::runtime_error("Error initializing peer key");
92  }
93  folly::ssl::EcPointUniquePtr point(EC_POINT_new(curve.get()));
94  if (!point) {
95  throw std::runtime_error("Error initializing point");
96  }
97  if (EC_POINT_oct2point(
98  curve.get(), point.get(), range.data(), range.size(), nullptr) != 1) {
99  throw std::runtime_error("Error decoding peer key");
100  }
101  if (EC_POINT_is_on_curve(curve.get(), point.get(), nullptr) != 1) {
102  throw std::runtime_error("Peer key is not on curve");
103  }
104  if (!EC_KEY_set_public_key(peerKey.get(), point.get())) {
105  throw std::runtime_error("Error setting public key");
106  }
107  folly::ssl::EvpPkeyUniquePtr peerPkey(EVP_PKEY_new());
108  if (EVP_PKEY_assign_EC_KEY(peerPkey.get(), peerKey.release()) != 1) {
109  throw std::runtime_error("Error assigning EC key");
110  }
111  return peerPkey;
112 }
113 
114 std::unique_ptr<folly::IOBuf> encodeECPublicKey(
115  const folly::ssl::EvpPkeyUniquePtr& key) {
116  folly::ssl::EcKeyUniquePtr ecKey(EVP_PKEY_get1_EC_KEY(key.get()));
117  if (!ecKey) {
118  throw std::runtime_error("Wrong key type");
119  }
120  return encodeECPublicKey(ecKey);
121 }
122 
123 std::unique_ptr<folly::IOBuf> encodeECPublicKey(
124  const folly::ssl::EcKeyUniquePtr& ecKey) {
125  auto point = EC_KEY_get0_public_key(ecKey.get());
126  auto group = EC_KEY_get0_group(ecKey.get());
127 
128  size_t len = EC_POINT_point2oct(
129  group, point, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
130  auto buf = folly::IOBuf::create(len);
131  // TLS 1.3 only allows uncompressed point formats, so we only support that
132  // for now.
133  len = EC_POINT_point2oct(
134  group,
135  point,
136  POINT_CONVERSION_UNCOMPRESSED,
137  buf->writableData(),
138  len,
139  nullptr);
140  if (len == 0) {
141  throw std::runtime_error("Failed to encode key");
142  }
143  buf->append(len);
144  return buf;
145 }
146 
148  auto err = ERR_get_error();
149  if (err == 0) {
150  return "";
151  }
152  char errMsg[256];
153  ERR_error_string_n(ERR_get_error(), errMsg, sizeof(errMsg));
154  return std::string(errMsg);
155 }
156 } // namespace detail
157 } // namespace fizz
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
std::unique_ptr< EC_POINT, EcPointDeleter > EcPointUniquePtr
constexpr size_type size() const
Definition: Range.h:431
std::unique_ptr< EVP_PKEY, EvpPkeyDeleter > EvpPkeyUniquePtr
folly::ssl::EvpPkeyUniquePtr decodeECPublicKey(folly::ByteRange range, int curveNid)
Gen range(Value begin, Value end)
Definition: Base.h:467
std::unique_ptr< EC_KEY, EcKeyDeleter > EcKeyUniquePtr
constexpr Params params[]
std::unique_ptr< EC_GROUP, EcGroupDeleter > EcGroupUniquePtr
void validateECKey(const folly::ssl::EvpPkeyUniquePtr &key, int curveNid)
constexpr Iter data() const
Definition: Range.h:446
Definition: Actions.h:16
std::string getOpenSSLError()
std::unique_ptr< folly::IOBuf > generateEvpSharedSecret(const folly::ssl::EvpPkeyUniquePtr &key, const folly::ssl::EvpPkeyUniquePtr &peerKey)
Optional< NamedGroup > group
const char * string
Definition: Conv.cpp:212
std::unique_ptr< folly::IOBuf > encodeECPublicKey(const folly::ssl::EvpPkeyUniquePtr &key)
folly::ssl::EvpPkeyUniquePtr generateECKeyPair(int curveNid)