Coverage Report

Created: 2021-06-10 10:30

/src/botan/src/lib/pubkey/ecdsa/ecdsa.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* ECDSA implemenation
3
* (C) 2007 Manuel Hartl, FlexSecure GmbH
4
*     2007 Falko Strenzke, FlexSecure GmbH
5
*     2008-2010,2015,2016,2018 Jack Lloyd
6
*     2016 René Korthaus
7
*
8
* Botan is released under the Simplified BSD License (see license.txt)
9
*/
10
11
#include <botan/ecdsa.h>
12
#include <botan/internal/pk_ops_impl.h>
13
#include <botan/internal/point_mul.h>
14
#include <botan/internal/keypair.h>
15
#include <botan/reducer.h>
16
#include <botan/internal/emsa.h>
17
18
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
19
  #include <botan/internal/rfc6979.h>
20
#endif
21
22
#if defined(BOTAN_HAS_OPENSSL)
23
  #include <botan/internal/openssl.h>
24
#endif
25
26
namespace Botan {
27
28
namespace {
29
30
PointGFp recover_ecdsa_public_key(const EC_Group& group,
31
                                  const std::vector<uint8_t>& msg,
32
                                  const BigInt& r,
33
                                  const BigInt& s,
34
                                  uint8_t v)
35
0
   {
36
0
   if(group.get_cofactor() != 1)
37
0
      throw Invalid_Argument("ECDSA public key recovery only supported for prime order groups");
38
39
0
   if(v >= 4)
40
0
      throw Invalid_Argument("Unexpected v param for ECDSA public key recovery");
41
42
0
   const BigInt& group_order = group.get_order();
43
44
0
   if(r <= 0 || r >= group_order || s <= 0 || s >= group_order)
45
0
      {
46
0
      throw Invalid_Argument("Out of range r/s cannot recover ECDSA public key");
47
0
      }
48
49
0
   const uint8_t y_odd = v % 2;
50
0
   const uint8_t add_order = v >> 1;
51
0
   const size_t p_bytes = group.get_p_bytes();
52
53
0
   try
54
0
      {
55
0
      const BigInt e = BigInt::from_bytes_with_max_bits(msg.data(), msg.size(), group.get_order_bits());
56
0
      const BigInt r_inv = group.inverse_mod_order(r);
57
58
0
      BigInt x = r + add_order*group_order;
59
60
0
      std::vector<uint8_t> X(p_bytes + 1);
61
62
0
      X[0] = 0x02 | y_odd;
63
0
      BigInt::encode_1363(&X[1], p_bytes, x);
64
65
0
      const PointGFp R = group.OS2ECP(X);
66
67
0
      if((R*group_order).is_zero() == false)
68
0
         throw Decoding_Error("Unable to recover ECDSA public key");
69
70
      // Compute r_inv * (s*R - eG)
71
0
      PointGFp_Multi_Point_Precompute RG_mul(R, group.get_base_point());
72
0
      const BigInt ne = group.mod_order(group_order - e);
73
0
      return r_inv * RG_mul.multi_exp(s, ne);
74
0
      }
75
0
   catch(...)
76
0
      {
77
      // continue on and throw
78
0
      }
79
80
0
   throw Decoding_Error("Failed to recover ECDSA public key from signature/msg pair");
81
0
   }
82
83
}
84
85
ECDSA_PublicKey::ECDSA_PublicKey(const EC_Group& group,
86
                                 const std::vector<uint8_t>& msg,
87
                                 const BigInt& r,
88
                                 const BigInt& s,
89
                                 uint8_t v) :
90
0
   EC_PublicKey(group, recover_ecdsa_public_key(group, msg, r, s, v)) {}
Unexecuted instantiation: Botan::ECDSA_PublicKey::ECDSA_PublicKey(Botan::EC_Group const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, Botan::BigInt const&, Botan::BigInt const&, unsigned char)
Unexecuted instantiation: Botan::ECDSA_PublicKey::ECDSA_PublicKey(Botan::EC_Group const&, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const&, Botan::BigInt const&, Botan::BigInt const&, unsigned char)
91
92
93
uint8_t ECDSA_PublicKey::recovery_param(const std::vector<uint8_t>& msg,
94
                                        const BigInt& r,
95
                                        const BigInt& s) const
96
0
   {
97
0
   for(uint8_t v = 0; v != 4; ++v)
98
0
      {
99
0
      try
100
0
         {
101
0
         PointGFp R = recover_ecdsa_public_key(this->domain(), msg, r, s, v);
102
103
0
         if(R == this->public_point())
104
0
            {
105
0
            return v;
106
0
            }
107
0
         }
108
0
      catch(Decoding_Error&)
109
0
         {
110
         // try the next v
111
0
         }
112
0
      }
113
114
0
   throw Internal_Error("Could not determine ECDSA recovery parameter");
115
0
   }
116
117
std::unique_ptr<Public_Key> ECDSA_PrivateKey::public_key() const
118
0
   {
119
0
   return std::make_unique<ECDSA_PublicKey>(domain(), public_point());
120
0
   }
121
122
bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
123
                                 bool strong) const
124
0
   {
125
0
   if(!public_point().on_the_curve())
126
0
      return false;
127
128
0
   if(!strong)
129
0
      return true;
130
131
0
   return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
132
0
   }
133
134
namespace {
135
136
/**
137
* ECDSA signature operation
138
*/
139
class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA
140
   {
141
   public:
142
143
      ECDSA_Signature_Operation(const ECDSA_PrivateKey& ecdsa,
144
                                const std::string& emsa,
145
                                RandomNumberGenerator& rng) :
146
         PK_Ops::Signature_with_EMSA(emsa),
147
         m_group(ecdsa.domain()),
148
         m_x(ecdsa.private_value())
149
0
         {
150
0
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
151
0
         m_rfc6979.reset(new RFC6979_Nonce_Generator(this->hash_for_signature(), m_group.get_order(), m_x));
152
0
#endif
153
154
0
         m_b = m_group.random_scalar(rng);
155
0
         m_b_inv = m_group.inverse_mod_order(m_b);
156
0
         }
157
158
0
      size_t signature_length() const override { return 2*m_group.get_order_bytes(); }
159
160
0
      size_t max_input_bits() const override { return m_group.get_order_bits(); }
161
162
      secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
163
                                      RandomNumberGenerator& rng) override;
164
165
   private:
166
      const EC_Group m_group;
167
      const BigInt& m_x;
168
169
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
170
      std::unique_ptr<RFC6979_Nonce_Generator> m_rfc6979;
171
#endif
172
173
      std::vector<BigInt> m_ws;
174
175
      BigInt m_b, m_b_inv;
176
   };
177
178
secure_vector<uint8_t>
179
ECDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len,
180
                                    RandomNumberGenerator& rng)
181
0
   {
182
0
   BigInt m = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
183
184
0
#if defined(BOTAN_HAS_RFC6979_GENERATOR)
185
0
   const BigInt k = m_rfc6979->nonce_for(m);
186
#else
187
   const BigInt k = m_group.random_scalar(rng);
188
#endif
189
190
0
   const BigInt r = m_group.mod_order(
191
0
      m_group.blinded_base_point_multiply_x(k, rng, m_ws));
192
193
0
   const BigInt k_inv = m_group.inverse_mod_order(k);
194
195
   /*
196
   * Blind the input message and compute x*r+m as (x*r*b + m*b)/b
197
   */
198
0
   m_b = m_group.square_mod_order(m_b);
199
0
   m_b_inv = m_group.square_mod_order(m_b_inv);
200
201
0
   m = m_group.multiply_mod_order(m_b, m_group.mod_order(m));
202
0
   const BigInt xr_m = m_group.mod_order(m_group.multiply_mod_order(m_x, m_b, r) + m);
203
204
0
   const BigInt s = m_group.multiply_mod_order(k_inv, xr_m, m_b_inv);
205
206
   // With overwhelming probability, a bug rather than actual zero r/s
207
0
   if(r.is_zero() || s.is_zero())
208
0
      throw Internal_Error("During ECDSA signature generated zero r/s");
209
210
0
   return BigInt::encode_fixed_length_int_pair(r, s, m_group.get_order_bytes());
211
0
   }
212
213
/**
214
* ECDSA verification operation
215
*/
216
class ECDSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA
217
   {
218
   public:
219
      ECDSA_Verification_Operation(const ECDSA_PublicKey& ecdsa,
220
                                   const std::string& emsa) :
221
         PK_Ops::Verification_with_EMSA(emsa),
222
         m_group(ecdsa.domain()),
223
         m_gy_mul(m_group.get_base_point(), ecdsa.public_point())
224
274
         {
225
274
         }
226
227
200
      size_t max_input_bits() const override { return m_group.get_order_bits(); }
228
229
200
      bool with_recovery() const override { return false; }
230
231
      bool verify(const uint8_t msg[], size_t msg_len,
232
                  const uint8_t sig[], size_t sig_len) override;
233
   private:
234
      const EC_Group m_group;
235
      const PointGFp_Multi_Point_Precompute m_gy_mul;
236
   };
237
238
bool ECDSA_Verification_Operation::verify(const uint8_t msg[], size_t msg_len,
239
                                          const uint8_t sig[], size_t sig_len)
240
200
   {
241
200
   if(sig_len != m_group.get_order_bytes() * 2)
242
0
      return false;
243
244
200
   const BigInt e = BigInt::from_bytes_with_max_bits(msg, msg_len, m_group.get_order_bits());
245
246
200
   const BigInt r(sig, sig_len / 2);
247
200
   const BigInt s(sig + sig_len / 2, sig_len / 2);
248
249
   // Cannot be negative here since we just decoded from binary
250
200
   if(r.is_zero() || s.is_zero())
251
2
      return false;
252
253
198
   if(r >= m_group.get_order() || s >= m_group.get_order())
254
2
      return false;
255
256
196
   const BigInt w = m_group.inverse_mod_order(s);
257
258
196
   const BigInt u1 = m_group.multiply_mod_order(m_group.mod_order(e), w);
259
196
   const BigInt u2 = m_group.multiply_mod_order(r, w);
260
196
   const PointGFp R = m_gy_mul.multi_exp(u1, u2);
261
262
196
   if(R.is_zero())
263
0
      return false;
264
265
196
   const BigInt v = m_group.mod_order(R.get_affine_x());
266
196
   return (v == r);
267
196
   }
268
269
}
270
271
std::unique_ptr<PK_Ops::Verification>
272
ECDSA_PublicKey::create_verification_op(const std::string& params,
273
                                        const std::string& provider) const
274
274
   {
275
#if defined(BOTAN_HAS_OPENSSL)
276
   if(provider == "openssl" || provider.empty())
277
      {
278
      try
279
         {
280
         return make_openssl_ecdsa_ver_op(*this, params);
281
         }
282
      catch(Lookup_Error& e)
283
         {
284
         if(provider == "openssl")
285
            throw;
286
         }
287
      }
288
#endif
289
290
274
   if(provider == "base" || provider.empty())
291
274
      return std::make_unique<ECDSA_Verification_Operation>(*this, params);
292
293
0
   throw Provider_Not_Found(algo_name(), provider);
294
0
   }
295
296
std::unique_ptr<PK_Ops::Signature>
297
ECDSA_PrivateKey::create_signature_op(RandomNumberGenerator& rng,
298
                                      const std::string& params,
299
                                      const std::string& provider) const
300
0
   {
301
#if defined(BOTAN_HAS_OPENSSL)
302
   if(provider == "openssl" || provider.empty())
303
      {
304
      try
305
         {
306
         return make_openssl_ecdsa_sig_op(*this, params);
307
         }
308
      catch(Lookup_Error& e)
309
         {
310
         if(provider == "openssl")
311
            throw;
312
         }
313
      }
314
#endif
315
316
0
   if(provider == "base" || provider.empty())
317
0
      return std::make_unique<ECDSA_Signature_Operation>(*this, params, rng);
318
319
0
   throw Provider_Not_Found(algo_name(), provider);
320
0
   }
321
322
}