Botan  2.1.0
Crypto and TLS for C++11
openssl_ec.cpp
Go to the documentation of this file.
1 /*
2 * ECDSA and ECDH via OpenSSL
3 * (C) 2015,2016 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/internal/openssl.h>
9 
10 #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
11  #include <botan/der_enc.h>
12  #include <botan/pkcs8.h>
13  #include <botan/oids.h>
14  #include <botan/internal/pk_ops_impl.h>
15 #endif
16 
17 #if defined(BOTAN_HAS_ECDSA)
18  #include <botan/ecdsa.h>
19 #endif
20 
21 #if defined(BOTAN_HAS_ECDH)
22  #include <botan/ecdh.h>
23 #endif
24 
25 #include <openssl/x509.h>
26 #include <openssl/objects.h>
27 
28 #if !defined(OPENSSL_NO_EC)
29  #include <openssl/ec.h>
30 #endif
31 
32 #if !defined(OPENSSL_NO_ECDSA)
33  #include <openssl/ecdsa.h>
34 #endif
35 
36 #if !defined(OPENSSL_NO_ECDH)
37  #include <openssl/ecdh.h>
38 #endif
39 
40 namespace Botan {
41 
42 #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
43 
44 namespace {
45 
46 secure_vector<uint8_t> PKCS8_for_openssl(const EC_PrivateKey& ec)
47  {
48  const PointGFp& pub_key = ec.public_point();
49  const BigInt& priv_key = ec.private_value();
50 
51  return DER_Encoder()
52  .start_cons(SEQUENCE)
53  .encode(static_cast<size_t>(1))
54  .encode(BigInt::encode_1363(priv_key, priv_key.bytes()), OCTET_STRING)
55  .start_cons(ASN1_Tag(0), PRIVATE)
56  .raw_bytes(ec.domain().DER_encode(EC_DOMPAR_ENC_OID))
57  .end_cons()
58  .start_cons(ASN1_Tag(1), PRIVATE)
59  .encode(EC2OSP(pub_key, PointGFp::UNCOMPRESSED), BIT_STRING)
60  .end_cons()
61  .end_cons()
62  .get_contents();
63  }
64 
65 int OpenSSL_EC_nid_for(const OID& oid)
66  {
67  if(oid.empty())
68  return -1;
69 
70  const std::string name = OIDS::lookup(oid);
71 
72  if(name == "secp192r1")
73  return NID_X9_62_prime192v1;
74  if(name == "secp224r1")
75  return NID_secp224r1;
76  if(name == "secp256r1")
77  return NID_X9_62_prime256v1;
78  if(name == "secp384r1")
79  return NID_secp384r1;
80  if(name == "secp521r1")
81  return NID_secp521r1;
82 
83  // OpenSSL 1.0.2 added brainpool curves
84 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
85  if(name == "brainpool160r1")
86  return NID_brainpoolP160r1;
87  if(name == "brainpool192r1")
88  return NID_brainpoolP192r1;
89  if(name == "brainpool224r1")
90  return NID_brainpoolP224r1;
91  if(name == "brainpool256r1")
92  return NID_brainpoolP256r1;
93  if(name == "brainpool320r1")
94  return NID_brainpoolP320r1;
95  if(name == "brainpool384r1")
96  return NID_brainpoolP384r1;
97  if(name == "brainpool512r1")
98  return NID_brainpoolP512r1;
99 #endif
100 
101  return -1;
102  }
103 
104 }
105 
106 #endif
107 
108 #if defined(BOTAN_HAS_ECDSA) && !defined(OPENSSL_NO_ECDSA)
109 
110 namespace {
111 
112 class OpenSSL_ECDSA_Verification_Operation : public PK_Ops::Verification_with_EMSA
113  {
114  public:
115  OpenSSL_ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const std::string& emsa, int nid) :
116  PK_Ops::Verification_with_EMSA(emsa), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free)
117  {
118  std::unique_ptr<::EC_GROUP, std::function<void (::EC_GROUP*)>> grp(::EC_GROUP_new_by_curve_name(nid),
119  ::EC_GROUP_free);
120 
121  if(!grp)
122  throw OpenSSL_Error("EC_GROUP_new_by_curve_name");
123 
124  ::EC_KEY_set_group(m_ossl_ec.get(), grp.get());
125 
126  const secure_vector<uint8_t> enc = EC2OSP(ecdsa.public_point(), PointGFp::UNCOMPRESSED);
127  const uint8_t* enc_ptr = enc.data();
128  EC_KEY* key_ptr = m_ossl_ec.get();
129  if(!::o2i_ECPublicKey(&key_ptr, &enc_ptr, enc.size()))
130  throw OpenSSL_Error("o2i_ECPublicKey");
131 
132  const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
133  m_order_bits = ::EC_GROUP_get_degree(group);
134  }
135 
136  size_t max_input_bits() const override { return m_order_bits; }
137 
138  bool with_recovery() const override { return false; }
139 
140  bool verify(const uint8_t msg[], size_t msg_len,
141  const uint8_t sig_bytes[], size_t sig_len) override
142  {
143  const size_t order_bytes = (m_order_bits + 7) / 8;
144  if(sig_len != 2 * order_bytes)
145  return false;
146 
147  std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
148  sig.reset(::ECDSA_SIG_new());
149 
150  sig->r = BN_bin2bn(sig_bytes , sig_len / 2, nullptr);
151  sig->s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, nullptr);
152 
153  const int res = ECDSA_do_verify(msg, msg_len, sig.get(), m_ossl_ec.get());
154  if(res < 0)
155  throw OpenSSL_Error("ECDSA_do_verify");
156  return (res == 1);
157  }
158 
159  private:
160  std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
161  size_t m_order_bits = 0;
162  };
163 
164 class OpenSSL_ECDSA_Signing_Operation : public PK_Ops::Signature_with_EMSA
165  {
166  public:
167  OpenSSL_ECDSA_Signing_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa) :
168  PK_Ops::Signature_with_EMSA(emsa),
169  m_ossl_ec(nullptr, ::EC_KEY_free)
170  {
171  const secure_vector<uint8_t> der = PKCS8_for_openssl(ecdsa);
172  const uint8_t* der_ptr = der.data();
173  m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size()));
174  if(!m_ossl_ec)
175  throw OpenSSL_Error("d2i_ECPrivateKey");
176 
177  const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
178  m_order_bits = ::EC_GROUP_get_degree(group);
179  }
180 
181  secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
182  RandomNumberGenerator&) override
183  {
184  std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
185  sig.reset(::ECDSA_do_sign(msg, msg_len, m_ossl_ec.get()));
186 
187  if(!sig)
188  throw OpenSSL_Error("ECDSA_do_sign");
189 
190  const size_t order_bytes = (m_order_bits + 7) / 8;
191  const size_t r_bytes = BN_num_bytes(sig->r);
192  const size_t s_bytes = BN_num_bytes(sig->s);
193  secure_vector<uint8_t> sigval(2*order_bytes);
194  BN_bn2bin(sig->r, &sigval[order_bytes - r_bytes]);
195  BN_bn2bin(sig->s, &sigval[2*order_bytes - s_bytes]);
196  return sigval;
197  }
198 
199  size_t max_input_bits() const override { return m_order_bits; }
200 
201  private:
202  std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
203  size_t m_order_bits = 0;
204  };
205 
206 }
207 
208 std::unique_ptr<PK_Ops::Verification>
209 make_openssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params)
210  {
211  const int nid = OpenSSL_EC_nid_for(key.domain().get_oid());
212  if(nid < 0)
213  {
214  throw Lookup_Error("OpenSSL ECDSA does not support this curve");
215  }
216  return std::unique_ptr<PK_Ops::Verification>(new OpenSSL_ECDSA_Verification_Operation(key, params, nid));
217  }
218 
219 std::unique_ptr<PK_Ops::Signature>
220 make_openssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params)
221  {
222  const int nid = OpenSSL_EC_nid_for(key.domain().get_oid());
223  if(nid < 0)
224  {
225  throw Lookup_Error("OpenSSL ECDSA does not support this curve");
226  }
227  return std::unique_ptr<PK_Ops::Signature>(new OpenSSL_ECDSA_Signing_Operation(key, params));
228  }
229 
230 #endif
231 
232 #if defined(BOTAN_HAS_ECDH) && !defined(OPENSSL_NO_ECDH)
233 
234 namespace {
235 
236 class OpenSSL_ECDH_KA_Operation : public PK_Ops::Key_Agreement_with_KDF
237  {
238  public:
239 
240  OpenSSL_ECDH_KA_Operation(const ECDH_PrivateKey& ecdh, const std::string& kdf) :
241  PK_Ops::Key_Agreement_with_KDF(kdf), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free)
242  {
243  const secure_vector<uint8_t> der = PKCS8_for_openssl(ecdh);
244  const uint8_t* der_ptr = der.data();
245  m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size()));
246  if(!m_ossl_ec)
247  throw OpenSSL_Error("d2i_ECPrivateKey");
248  }
249 
250  secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override
251  {
252  const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
253  const size_t out_len = (::EC_GROUP_get_degree(group) + 7) / 8;
254  secure_vector<uint8_t> out(out_len);
255  EC_POINT* pub_key = ::EC_POINT_new(group);
256 
257  if(!pub_key)
258  throw OpenSSL_Error("EC_POINT_new");
259 
260  const int os2ecp_rc =
261  ::EC_POINT_oct2point(group, pub_key, w, w_len, nullptr);
262 
263  if(os2ecp_rc != 1)
264  throw OpenSSL_Error("EC_POINT_oct2point");
265 
266  const int ecdh_rc = ::ECDH_compute_key(out.data(),
267  out.size(),
268  pub_key,
269  m_ossl_ec.get(),
270  /*KDF*/nullptr);
271 
272  if(ecdh_rc <= 0)
273  throw OpenSSL_Error("ECDH_compute_key");
274 
275  const size_t ecdh_sz = static_cast<size_t>(ecdh_rc);
276 
277  if(ecdh_sz > out.size())
278  throw Internal_Error("OpenSSL ECDH returned more than requested");
279 
280  out.resize(ecdh_sz);
281  return out;
282  }
283 
284  private:
285  std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
286  };
287 
288 }
289 
290 std::unique_ptr<PK_Ops::Key_Agreement>
291 make_openssl_ecdh_ka_op(const ECDH_PrivateKey& key, const std::string& params)
292  {
293  const int nid = OpenSSL_EC_nid_for(key.domain().get_oid());
294  if(nid < 0)
295  {
296  throw Lookup_Error("OpenSSL ECDH does not support this curve");
297  }
298 
299  return std::unique_ptr<PK_Ops::Key_Agreement>(new OpenSSL_ECDH_KA_Operation(key, params));
300  }
301 
302 #endif
303 
304 }
305 
secure_vector< uint8_t > EC2OSP(const PointGFp &point, uint8_t format)
Definition: point_gfp.cpp:470
std::string lookup(const OID &oid)
Definition: oids.cpp:18
ASN1_Tag
Definition: asn1_obj.h:22
Definition: alg_id.cpp:13
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
Definition: big_code.cpp:82