Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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/internal/pk_ops_impl.h>
14 #endif
15
16 #if defined(BOTAN_HAS_ECDSA)
17 #include <botan/ecdsa.h>
18 #endif
19
20 #if defined(BOTAN_HAS_ECDH)
21 #include <botan/ecdh.h>
22 #endif
23
24 #include <openssl/x509.h>
25 #include <openssl/objects.h>
26
27 #if !defined(OPENSSL_NO_EC)
28 #include <openssl/ec.h>
29 #endif
30
31 #if !defined(OPENSSL_NO_ECDSA)
32 #include <openssl/ecdsa.h>
33 #endif
34
35 #if !defined(OPENSSL_NO_ECDH)
36 #include <openssl/ecdh.h>
37 #endif
38
39 namespace Botan {
40
41 #if defined(BOTAN_HAS_ECC_PUBLIC_KEY_CRYPTO)
42
43 namespace {
44
45 secure_vector<uint8_t> PKCS8_for_openssl(const EC_PrivateKey& ec)
46 {
47 const PointGFp& pub_key = ec.public_point();
48 const BigInt& priv_key = ec.private_value();
49
50 return DER_Encoder()
51 .start_cons(SEQUENCE)
52 .encode(static_cast<size_t>(1))
53 .encode(BigInt::encode_1363(priv_key, priv_key.bytes()), OCTET_STRING)
54 .start_cons(ASN1_Tag(0), PRIVATE)
55 .raw_bytes(ec.domain().DER_encode(EC_DOMPAR_ENC_OID))
56 .end_cons()
57 .start_cons(ASN1_Tag(1), PRIVATE)
58 .encode(pub_key.encode(PointGFp::UNCOMPRESSED), BIT_STRING)
59 .end_cons()
60 .end_cons()
61 .get_contents();
62 }
63
64 int OpenSSL_EC_curve_builtin(int nid)
65 {
66 // the NID macro is still defined even though the curve may not be
67 // supported, so we need to check the list of builtin curves at runtime
68 EC_builtin_curve builtin_curves[100];
69 size_t num = 0;
70
71 if (!(num = EC_get_builtin_curves(builtin_curves, sizeof(builtin_curves))))
72 {
73 return -1;
74 }
75
76 for(size_t i = 0; i < num; ++i)
77 {
78 if(builtin_curves[i].nid == nid)
79 {
80 return nid;
81 }
82 }
83
84 return -1;
85 }
86
87 int OpenSSL_EC_nid_for(const OID& oid)
88 {
89 if(oid.empty())
90 return -1;
91
92 const std::string name = oid.to_formatted_string();
93
94 if(name == "secp192r1")
95 return OpenSSL_EC_curve_builtin(NID_X9_62_prime192v1);
96 if(name == "secp224r1")
97 return OpenSSL_EC_curve_builtin(NID_secp224r1);
98 if(name == "secp256r1")
99 return OpenSSL_EC_curve_builtin(NID_X9_62_prime256v1);
100 if(name == "secp384r1")
101 return OpenSSL_EC_curve_builtin(NID_secp384r1);
102 if(name == "secp521r1")
103 return OpenSSL_EC_curve_builtin(NID_secp521r1);
104
105 // OpenSSL 1.0.2 added brainpool curves
106 #if OPENSSL_VERSION_NUMBER >= 0x1000200fL
107 if(name == "brainpool160r1")
108 return OpenSSL_EC_curve_builtin(NID_brainpoolP160r1);
109 if(name == "brainpool192r1")
110 return OpenSSL_EC_curve_builtin(NID_brainpoolP192r1);
111 if(name == "brainpool224r1")
112 return OpenSSL_EC_curve_builtin(NID_brainpoolP224r1);
113 if(name == "brainpool256r1")
114 return OpenSSL_EC_curve_builtin(NID_brainpoolP256r1);
115 if(name == "brainpool320r1")
116 return OpenSSL_EC_curve_builtin(NID_brainpoolP320r1);
117 if(name == "brainpool384r1")
118 return OpenSSL_EC_curve_builtin(NID_brainpoolP384r1);
119 if(name == "brainpool512r1")
120 return OpenSSL_EC_curve_builtin(NID_brainpoolP512r1);
121 #endif
122
123 return -1;
124 }
125
126 }
127
128 #endif
129
130 #if defined(BOTAN_HAS_ECDSA) && !defined(OPENSSL_NO_ECDSA)
131
132 namespace {
133
134 class OpenSSL_ECDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA
135 {
136 public:
137 OpenSSL_ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa, const std::string& emsa, int nid) :
138 PK_Ops::Verification_with_EMSA(emsa), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free)
139 {
140 std::unique_ptr<::EC_GROUP, std::function<void (::EC_GROUP*)>> grp(::EC_GROUP_new_by_curve_name(nid),
141 ::EC_GROUP_free);
142
143 if(!grp)
144 throw OpenSSL_Error("EC_GROUP_new_by_curve_name", ERR_get_error());
145
146 if(!::EC_KEY_set_group(m_ossl_ec.get(), grp.get()))
147 throw OpenSSL_Error("EC_KEY_set_group", ERR_get_error());
148
149 const std::vector<uint8_t> enc = ecdsa.public_point().encode(PointGFp::UNCOMPRESSED);
150 const uint8_t* enc_ptr = enc.data();
151 EC_KEY* key_ptr = m_ossl_ec.get();
152 if(!::o2i_ECPublicKey(&key_ptr, &enc_ptr, enc.size()))
153 throw OpenSSL_Error("o2i_ECPublicKey", ERR_get_error());
154
155 const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
156 m_order_bits = ::EC_GROUP_get_degree(group);
157 }
158
159 size_t max_input_bits() const override { return m_order_bits; }
160
161 bool with_recovery() const override { return false; }
162
163 bool verify(const uint8_t msg[], size_t msg_len,
164 const uint8_t sig_bytes[], size_t sig_len) override
165 {
166 const size_t order_bytes = (m_order_bits + 7) / 8;
167 if(sig_len != 2 * order_bytes)
168 return false;
169
170 std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
171 sig.reset(::ECDSA_SIG_new());
172
173 #if OPENSSL_VERSION_NUMBER < 0x10100000L
174 sig->r = BN_bin2bn(sig_bytes , sig_len / 2, sig->r);
175 sig->s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, sig->s);
176 #else
177 BIGNUM* r = BN_bin2bn(sig_bytes , sig_len / 2, nullptr);
178 BIGNUM* s = BN_bin2bn(sig_bytes + sig_len / 2, sig_len / 2, nullptr);
179 if(r == nullptr || s == nullptr)
180 throw OpenSSL_Error("BN_bin2bn sig s", ERR_get_error());
181
182 ECDSA_SIG_set0(sig.get(), r, s);
183 #endif
184
185 const int res = ECDSA_do_verify(msg, msg_len, sig.get(), m_ossl_ec.get());
186 if(res < 0)
187 {
188 int err = ERR_get_error();
189
190 bool hard_error = true;
191
192 #if defined(EC_R_BAD_SIGNATURE)
193 if(ERR_GET_REASON(err) == EC_R_BAD_SIGNATURE)
194 hard_error = false;
195 #endif
196 #if defined(EC_R_POINT_AT_INFINITY)
197 if(ERR_GET_REASON(err) == EC_R_POINT_AT_INFINITY)
198 hard_error = false;
199 #endif
200 #if defined(ECDSA_R_BAD_SIGNATURE)
201 if(ERR_GET_REASON(err) == ECDSA_R_BAD_SIGNATURE)
202 hard_error = false;
203 #endif
204
205 if(hard_error)
206 throw OpenSSL_Error("ECDSA_do_verify", err);
207 }
208 return (res == 1);
209 }
210
211 private:
212 std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
213 size_t m_order_bits = 0;
214 };
215
216 class OpenSSL_ECDSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA
217 {
218 public:
219 OpenSSL_ECDSA_Signing_Operation(const ECDSA_PrivateKey& ecdsa, const std::string& emsa) :
220 PK_Ops::Signature_with_EMSA(emsa),
221 m_ossl_ec(nullptr, ::EC_KEY_free)
222 {
223 const secure_vector<uint8_t> der = PKCS8_for_openssl(ecdsa);
224 const uint8_t* der_ptr = der.data();
225 m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size()));
226 if(!m_ossl_ec)
227 throw OpenSSL_Error("d2i_ECPrivateKey", ERR_get_error());
228
229 const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
230 m_order_bits = ::EC_GROUP_get_degree(group);
231 m_order_bytes = (m_order_bits + 7) / 8;
232 }
233
234 size_t signature_length() const override { return 2*m_order_bytes; }
235
236 secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
237 RandomNumberGenerator&) override
238 {
239 std::unique_ptr<ECDSA_SIG, std::function<void (ECDSA_SIG*)>> sig(nullptr, ECDSA_SIG_free);
240 sig.reset(::ECDSA_do_sign(msg, msg_len, m_ossl_ec.get()));
241
242 if(!sig)
243 throw OpenSSL_Error("ECDSA_do_sign", ERR_get_error());
244
245 #if OPENSSL_VERSION_NUMBER < 0x10100000L
246 const BIGNUM* r = sig->r;
247 const BIGNUM* s = sig->s;
248 #else
249 const BIGNUM* r;
250 const BIGNUM* s;
251 ECDSA_SIG_get0(sig.get(), &r, &s);
252 #endif
253
254 const size_t r_bytes = BN_num_bytes(r);
255 const size_t s_bytes = BN_num_bytes(s);
256 secure_vector<uint8_t> sigval(2*m_order_bytes);
257 BN_bn2bin(r, &sigval[m_order_bytes - r_bytes]);
258 BN_bn2bin(s, &sigval[2*m_order_bytes - s_bytes]);
259 return sigval;
260 }
261
262 size_t max_input_bits() const override { return m_order_bits; }
263
264 private:
265 std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
266 size_t m_order_bits;
267 size_t m_order_bytes;
268 };
269
270 }
271
272 std::unique_ptr<PK_Ops::Verification>
273 make_openssl_ecdsa_ver_op(const ECDSA_PublicKey& key, const std::string& params)
274 {
275 const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid());
276 if(nid < 0)
277 {
278 throw Lookup_Error("OpenSSL ECDSA does not support this curve");
279 }
280
281 try
282 {
283 return std::unique_ptr<PK_Ops::Verification>(new OpenSSL_ECDSA_Verification_Operation(key, params, nid));
284 }
285 catch(OpenSSL_Error&)
286 {
287 throw Lookup_Error("OpenSSL ECDSA does not support this key");
288 }
289 }
290
291 std::unique_ptr<PK_Ops::Signature>
292 make_openssl_ecdsa_sig_op(const ECDSA_PrivateKey& key, const std::string& params)
293 {
294 const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid());
295 if(nid < 0)
296 {
297 throw Lookup_Error("OpenSSL ECDSA does not support this curve");
298 }
299 return std::unique_ptr<PK_Ops::Signature>(new OpenSSL_ECDSA_Signing_Operation(key, params));
300 }
301
302 #endif
303
304 #if defined(BOTAN_HAS_ECDH) && !defined(OPENSSL_NO_ECDH)
305
306 namespace {
307
308 class OpenSSL_ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF
309 {
310 public:
311
312 OpenSSL_ECDH_KA_Operation(const ECDH_PrivateKey& ecdh, const std::string& kdf) :
313 PK_Ops::Key_Agreement_with_KDF(kdf), m_ossl_ec(::EC_KEY_new(), ::EC_KEY_free)
314 {
315 m_value_size = ecdh.domain().get_p_bytes();
316 const secure_vector<uint8_t> der = PKCS8_for_openssl(ecdh);
317 const uint8_t* der_ptr = der.data();
318 m_ossl_ec.reset(d2i_ECPrivateKey(nullptr, &der_ptr, der.size()));
319 if(!m_ossl_ec)
320 throw OpenSSL_Error("d2i_ECPrivateKey", ERR_get_error());
321 }
322
323 size_t agreed_value_size() const override { return m_value_size; }
324
325 secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override
326 {
327 const EC_GROUP* group = ::EC_KEY_get0_group(m_ossl_ec.get());
328 const size_t out_len = (::EC_GROUP_get_degree(group) + 7) / 8;
329 secure_vector<uint8_t> out(out_len);
330
331 std::unique_ptr<EC_POINT, std::function<void (EC_POINT*)>> pub_key(
332 ::EC_POINT_new(group), ::EC_POINT_free);
333
334 if(!pub_key)
335 throw OpenSSL_Error("EC_POINT_new", ERR_get_error());
336
337 const int os2ecp_rc =
338 ::EC_POINT_oct2point(group, pub_key.get(), w, w_len, nullptr);
339
340 if(os2ecp_rc != 1)
341 throw OpenSSL_Error("EC_POINT_oct2point", ERR_get_error());
342
343 const int ecdh_rc = ::ECDH_compute_key(out.data(),
344 out.size(),
345 pub_key.get(),
346 m_ossl_ec.get(),
347 /*KDF*/nullptr);
348
349 if(ecdh_rc <= 0)
350 throw OpenSSL_Error("ECDH_compute_key", ERR_get_error());
351
352 const size_t ecdh_sz = static_cast<size_t>(ecdh_rc);
353
354 if(ecdh_sz > out.size())
355 throw Internal_Error("OpenSSL ECDH returned more than requested");
356
357 out.resize(ecdh_sz);
358 return out;
359 }
360
361 private:
362 std::unique_ptr<EC_KEY, std::function<void (EC_KEY*)>> m_ossl_ec;
363 size_t m_value_size;
364 };
365
366 }
367
368 std::unique_ptr<PK_Ops::Key_Agreement>
369 make_openssl_ecdh_ka_op(const ECDH_PrivateKey& key, const std::string& params)
370 {
371 const int nid = OpenSSL_EC_nid_for(key.domain().get_curve_oid());
372 if(nid < 0)
373 {
374 throw Lookup_Error("OpenSSL ECDH does not support this curve");
375 }
376
377 return std::unique_ptr<PK_Ops::Key_Agreement>(new OpenSSL_ECDH_KA_Operation(key, params));
378 }
379
380 #endif
381
382 }
383
Botan::PointGFp::UNCOMPRESSED
Definition: point_gfp.h:51
final
int(* final)(unsigned char *, CTX *)
Definition: commoncrypto_hash.cpp:28
Botan::PRIVATE
Definition: asn1_obj.h:30
Botan::ASN1_Tag
ASN1_Tag
Definition: asn1_obj.h:23
Botan::SEQUENCE
Definition: asn1_obj.h:40
name
std::string name
Definition: commoncrypto_hash.cpp:23
Botan
Definition: alg_id.cpp:13
Botan::EC_DOMPAR_ENC_OID
Definition: ec_group.h:26
Botan::OCTET_STRING
Definition: asn1_obj.h:36
Botan::BIT_STRING
Definition: asn1_obj.h:35
Botan::BigInt::encode_1363
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
Definition: big_code.cpp:111
Botan::OCSP::Response_Status_Code::Internal_Error