1 /* Copyright (c) 2015, Google Inc. 2 * 3 * Permission to use, copy, modify, and/or distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 14 15 #include <openssl/ssl.h> 16 17 #include <assert.h> 18 #include <string.h> 19 20 #include <utility> 21 22 #include <openssl/bn.h> 23 #include <openssl/bytestring.h> 24 #include <openssl/curve25519.h> 25 #include <openssl/ec.h> 26 #include <openssl/err.h> 27 #include <openssl/mem.h> 28 #include <openssl/nid.h> 29 30 #include "internal.h" 31 #include "../crypto/internal.h" 32 33 34 namespace bssl { 35 36 namespace { 37 38 class ECKeyShare : public SSLKeyShare { 39 public: 40 ECKeyShare(int nid, uint16_t group_id) : nid_(nid), group_id_(group_id) {} 41 ~ECKeyShare() override {} 42 43 uint16_t GroupID() const override { return group_id_; } 44 45 bool Offer(CBB *out) override { 46 assert(!private_key_); 47 // Set up a shared |BN_CTX| for all operations. 48 UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); 49 if (!bn_ctx) { 50 return false; 51 } 52 BN_CTXScope scope(bn_ctx.get()); 53 54 // Generate a private key. 55 UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_)); 56 private_key_.reset(BN_new()); 57 if (!group || !private_key_ || 58 !BN_rand_range_ex(private_key_.get(), 1, 59 EC_GROUP_get0_order(group.get()))) { 60 return false; 61 } 62 63 // Compute the corresponding public key and serialize it. 64 UniquePtr<EC_POINT> public_key(EC_POINT_new(group.get())); 65 if (!public_key || 66 !EC_POINT_mul(group.get(), public_key.get(), private_key_.get(), NULL, 67 NULL, bn_ctx.get()) || 68 !EC_POINT_point2cbb(out, group.get(), public_key.get(), 69 POINT_CONVERSION_UNCOMPRESSED, bn_ctx.get())) { 70 return false; 71 } 72 73 return true; 74 } 75 76 bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, 77 Span<const uint8_t> peer_key) override { 78 assert(private_key_); 79 *out_alert = SSL_AD_INTERNAL_ERROR; 80 81 // Set up a shared |BN_CTX| for all operations. 82 UniquePtr<BN_CTX> bn_ctx(BN_CTX_new()); 83 if (!bn_ctx) { 84 return false; 85 } 86 BN_CTXScope scope(bn_ctx.get()); 87 88 UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_)); 89 if (!group) { 90 return false; 91 } 92 93 UniquePtr<EC_POINT> peer_point(EC_POINT_new(group.get())); 94 UniquePtr<EC_POINT> result(EC_POINT_new(group.get())); 95 BIGNUM *x = BN_CTX_get(bn_ctx.get()); 96 if (!peer_point || !result || !x) { 97 return false; 98 } 99 100 if (!EC_POINT_oct2point(group.get(), peer_point.get(), peer_key.data(), 101 peer_key.size(), bn_ctx.get())) { 102 *out_alert = SSL_AD_DECODE_ERROR; 103 return false; 104 } 105 106 // Compute the x-coordinate of |peer_key| * |private_key_|. 107 if (!EC_POINT_mul(group.get(), result.get(), NULL, peer_point.get(), 108 private_key_.get(), bn_ctx.get()) || 109 !EC_POINT_get_affine_coordinates_GFp(group.get(), result.get(), x, NULL, 110 bn_ctx.get())) { 111 return false; 112 } 113 114 // Encode the x-coordinate left-padded with zeros. 115 Array<uint8_t> secret; 116 if (!secret.Init((EC_GROUP_get_degree(group.get()) + 7) / 8) || 117 !BN_bn2bin_padded(secret.data(), secret.size(), x)) { 118 return false; 119 } 120 121 *out_secret = std::move(secret); 122 return true; 123 } 124 125 private: 126 UniquePtr<BIGNUM> private_key_; 127 int nid_; 128 uint16_t group_id_; 129 }; 130 131 class X25519KeyShare : public SSLKeyShare { 132 public: 133 X25519KeyShare() {} 134 ~X25519KeyShare() override { 135 OPENSSL_cleanse(private_key_, sizeof(private_key_)); 136 } 137 138 uint16_t GroupID() const override { return SSL_CURVE_X25519; } 139 140 bool Offer(CBB *out) override { 141 uint8_t public_key[32]; 142 X25519_keypair(public_key, private_key_); 143 return !!CBB_add_bytes(out, public_key, sizeof(public_key)); 144 } 145 146 bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, 147 Span<const uint8_t> peer_key) override { 148 *out_alert = SSL_AD_INTERNAL_ERROR; 149 150 Array<uint8_t> secret; 151 if (!secret.Init(32)) { 152 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); 153 return false; 154 } 155 156 if (peer_key.size() != 32 || 157 !X25519(secret.data(), private_key_, peer_key.data())) { 158 *out_alert = SSL_AD_DECODE_ERROR; 159 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); 160 return false; 161 } 162 163 *out_secret = std::move(secret); 164 return true; 165 } 166 167 private: 168 uint8_t private_key_[32]; 169 }; 170 171 CONSTEXPR_ARRAY struct { 172 int nid; 173 uint16_t group_id; 174 const char name[8], alias[11]; 175 } kNamedGroups[] = { 176 {NID_secp224r1, SSL_CURVE_SECP224R1, "P-224", "secp224r1"}, 177 {NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256", "prime256v1"}, 178 {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, 179 {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, 180 {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, 181 }; 182 183 } // namespace 184 185 UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) { 186 switch (group_id) { 187 case SSL_CURVE_SECP224R1: 188 return UniquePtr<SSLKeyShare>( 189 New<ECKeyShare>(NID_secp224r1, SSL_CURVE_SECP224R1)); 190 case SSL_CURVE_SECP256R1: 191 return UniquePtr<SSLKeyShare>( 192 New<ECKeyShare>(NID_X9_62_prime256v1, SSL_CURVE_SECP256R1)); 193 case SSL_CURVE_SECP384R1: 194 return UniquePtr<SSLKeyShare>( 195 New<ECKeyShare>(NID_secp384r1, SSL_CURVE_SECP384R1)); 196 case SSL_CURVE_SECP521R1: 197 return UniquePtr<SSLKeyShare>( 198 New<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1)); 199 case SSL_CURVE_X25519: 200 return UniquePtr<SSLKeyShare>(New<X25519KeyShare>()); 201 default: 202 return nullptr; 203 } 204 } 205 206 bool SSLKeyShare::Accept(CBB *out_public_key, Array<uint8_t> *out_secret, 207 uint8_t *out_alert, Span<const uint8_t> peer_key) { 208 *out_alert = SSL_AD_INTERNAL_ERROR; 209 return Offer(out_public_key) && 210 Finish(out_secret, out_alert, peer_key); 211 } 212 213 int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { 214 for (const auto &group : kNamedGroups) { 215 if (group.nid == nid) { 216 *out_group_id = group.group_id; 217 return 1; 218 } 219 } 220 return 0; 221 } 222 223 int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) { 224 for (const auto &group : kNamedGroups) { 225 if (len == strlen(group.name) && 226 !strncmp(group.name, name, len)) { 227 *out_group_id = group.group_id; 228 return 1; 229 } 230 if (len == strlen(group.alias) && 231 !strncmp(group.alias, name, len)) { 232 *out_group_id = group.group_id; 233 return 1; 234 } 235 } 236 return 0; 237 } 238 239 } // namespace bssl 240 241 using namespace bssl; 242 243 const char* SSL_get_curve_name(uint16_t group_id) { 244 for (const auto &group : kNamedGroups) { 245 if (group.group_id == group_id) { 246 return group.name; 247 } 248 } 249 return nullptr; 250 } 251