Coverage Report

Created: 2020-05-23 13:54

/src/botan/src/lib/x509/x509_obj.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* X.509 SIGNED Object
3
* (C) 1999-2007 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/x509_obj.h>
9
#include <botan/pubkey.h>
10
#include <botan/der_enc.h>
11
#include <botan/ber_dec.h>
12
#include <botan/parsing.h>
13
#include <botan/pem.h>
14
#include <botan/emsa.h>
15
#include <algorithm>
16
17
namespace Botan {
18
19
namespace {
20
struct Pss_params
21
   {
22
   AlgorithmIdentifier hash_algo;
23
   AlgorithmIdentifier mask_gen_algo;
24
   AlgorithmIdentifier mask_gen_hash;  // redundant: decoded mask_gen_algo.parameters
25
   size_t salt_len;
26
   size_t trailer_field;
27
   };
28
29
Pss_params decode_pss_params(const std::vector<uint8_t>& encoded_pss_params)
30
54
   {
31
54
   const AlgorithmIdentifier default_hash("SHA-160", AlgorithmIdentifier::USE_NULL_PARAM);
32
54
   const AlgorithmIdentifier default_mgf("MGF1", default_hash.BER_encode());
33
54
34
54
   Pss_params pss_parameter;
35
54
   BER_Decoder(encoded_pss_params)
36
54
      .start_cons(SEQUENCE)
37
54
         .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, default_hash)
38
54
         .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE, default_mgf)
39
54
         .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20))
40
54
         .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1))
41
54
      .end_cons();
42
54
43
54
   BER_Decoder(pss_parameter.mask_gen_algo.get_parameters()).decode(pss_parameter.mask_gen_hash);
44
54
45
54
   return pss_parameter;
46
54
   }
47
}
48
49
/*
50
* Read a PEM or BER X.509 object
51
*/
52
void X509_Object::load_data(DataSource& in)
53
17.7k
   {
54
17.7k
   try {
55
17.7k
      if(ASN1::maybe_BER(in) && !PEM_Code::matches(in))
56
11.8k
         {
57
11.8k
         BER_Decoder dec(in);
58
11.8k
         decode_from(dec);
59
11.8k
         }
60
5.91k
      else
61
5.91k
         {
62
5.91k
         std::string got_label;
63
5.91k
         DataSource_Memory ber(PEM_Code::decode(in, got_label));
64
5.91k
65
5.91k
         if(got_label != PEM_label())
66
182
            {
67
182
            bool is_alternate = false;
68
182
            for(std::string alt_label : alternate_PEM_labels())
69
182
               {
70
182
               if(got_label == alt_label)
71
4
                  {
72
4
                  is_alternate = true;
73
4
                  break;
74
4
                  }
75
182
               }
76
182
77
182
            if(!is_alternate)
78
178
               throw Decoding_Error("Unexpected PEM label for " + PEM_label() + " of " + got_label);
79
5.73k
            }
80
5.73k
81
5.73k
         BER_Decoder dec(ber);
82
5.73k
         decode_from(dec);
83
5.73k
         }
84
17.7k
      }
85
17.7k
   catch(Decoding_Error& e)
86
17.7k
      {
87
6.26k
      throw Decoding_Error(PEM_label() + " decoding", e);
88
6.26k
      }
89
17.7k
   }
90
91
92
void X509_Object::encode_into(DER_Encoder& to) const
93
10.3k
   {
94
10.3k
   to.start_cons(SEQUENCE)
95
10.3k
         .start_cons(SEQUENCE)
96
10.3k
            .raw_bytes(signed_body())
97
10.3k
         .end_cons()
98
10.3k
         .encode(signature_algorithm())
99
10.3k
         .encode(signature(), BIT_STRING)
100
10.3k
      .end_cons();
101
10.3k
   }
102
103
/*
104
* Read a BER encoded X.509 object
105
*/
106
void X509_Object::decode_from(BER_Decoder& from)
107
16.7k
   {
108
16.7k
   from.start_cons(SEQUENCE)
109
16.7k
         .start_cons(SEQUENCE)
110
16.7k
            .raw_bytes(m_tbs_bits)
111
16.7k
         .end_cons()
112
16.7k
         .decode(m_sig_algo)
113
16.7k
         .decode(m_sig, BIT_STRING)
114
16.7k
      .end_cons();
115
16.7k
116
16.7k
   force_decode();
117
16.7k
   }
118
119
/*
120
* Return a PEM encoded X.509 object
121
*/
122
std::string X509_Object::PEM_encode() const
123
0
   {
124
0
   return PEM_Code::encode(BER_encode(), PEM_label());
125
0
   }
126
127
/*
128
* Return the TBS data
129
*/
130
std::vector<uint8_t> X509_Object::tbs_data() const
131
6.74k
   {
132
6.74k
   return ASN1::put_in_sequence(m_tbs_bits);
133
6.74k
   }
134
135
/*
136
* Return the hash used in generating the signature
137
*/
138
std::string X509_Object::hash_used_for_signature() const
139
0
   {
140
0
   const OID& oid = m_sig_algo.get_oid();
141
0
   const std::vector<std::string> sig_info = split_on(oid.to_formatted_string(), '/');
142
0
143
0
   if(sig_info.size() == 1 && sig_info[0] == "Ed25519")
144
0
      return "SHA-512";
145
0
   else if(sig_info.size() != 2)
146
0
      throw Internal_Error("Invalid name format found for " + oid.to_string());
147
0
148
0
   if(sig_info[1] == "EMSA4")
149
0
      {
150
0
      const OID hash_oid = decode_pss_params(signature_algorithm().get_parameters()).hash_algo.get_oid();
151
0
      return hash_oid.to_formatted_string();
152
0
      }
153
0
   else
154
0
      {
155
0
      const std::vector<std::string> pad_and_hash =
156
0
         parse_algorithm_name(sig_info[1]);
157
0
158
0
      if(pad_and_hash.size() != 2)
159
0
         {
160
0
         throw Internal_Error("Invalid name format " + sig_info[1]);
161
0
         }
162
0
163
0
      return pad_and_hash[1];
164
0
      }
165
0
   }
166
167
/*
168
* Check the signature on an object
169
*/
170
bool X509_Object::check_signature(const Public_Key* pub_key) const
171
0
   {
172
0
   if(!pub_key)
173
0
      throw Invalid_Argument("No key provided for " + PEM_label() + " signature check");
174
0
   std::unique_ptr<const Public_Key> key(pub_key);
175
0
   return check_signature(*key);
176
0
   }
177
178
bool X509_Object::check_signature(const Public_Key& pub_key) const
179
0
   {
180
0
   const Certificate_Status_Code code = verify_signature(pub_key);
181
0
   return (code == Certificate_Status_Code::VERIFIED);
182
0
   }
183
184
Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const
185
6.79k
   {
186
6.79k
   const std::vector<std::string> sig_info =
187
6.79k
      split_on(m_sig_algo.get_oid().to_formatted_string(), '/');
188
6.79k
189
6.79k
   if(sig_info.size() < 1 || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name())
190
41
      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
191
6.75k
192
6.75k
   std::string padding;
193
6.75k
   if(sig_info.size() == 2)
194
6.69k
      padding = sig_info[1];
195
59
   else if(sig_info[0] == "Ed25519" || sig_info[0] == "XMSS")
196
56
      padding = "Pure";
197
3
   else
198
3
      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
199
6.75k
200
6.75k
   const Signature_Format format = pub_key.default_x509_signature_format();
201
6.75k
202
6.75k
   if(padding == "EMSA4")
203
54
      {
204
54
      // "MUST contain RSASSA-PSS-params"
205
54
      if(signature_algorithm().get_parameters().empty())
206
0
         {
207
0
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
208
0
         }
209
54
210
54
      Pss_params pss_parameter = decode_pss_params(signature_algorithm().get_parameters());
211
54
212
54
      // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
213
54
      const std::string hash_algo = pss_parameter.hash_algo.get_oid().to_formatted_string();
214
54
      if(hash_algo != "SHA-160" &&
215
54
         hash_algo != "SHA-224" &&
216
54
         hash_algo != "SHA-256" &&
217
54
         hash_algo != "SHA-384" &&
218
54
         hash_algo != "SHA-512")
219
1
         {
220
1
         return Certificate_Status_Code::UNTRUSTED_HASH;
221
1
         }
222
53
223
53
      const std::string mgf_algo = pss_parameter.mask_gen_algo.get_oid().to_formatted_string();
224
53
      if(mgf_algo != "MGF1")
225
1
         {
226
1
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
227
1
         }
228
52
229
52
      // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm
230
52
      // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
231
52
      if(pss_parameter.mask_gen_hash.get_oid() != pss_parameter.hash_algo.get_oid())
232
1
         {
233
1
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
234
1
         }
235
51
236
51
      if(pss_parameter.trailer_field != 1)
237
0
         {
238
0
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
239
0
         }
240
51
241
51
      padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")";
242
51
      }
243
6.75k
244
6.75k
   try
245
6.74k
      {
246
6.74k
      PK_Verifier verifier(pub_key, padding, format);
247
6.74k
      const bool valid = verifier.verify_message(tbs_data(), signature());
248
6.74k
249
6.74k
      if(valid)
250
4.95k
         return Certificate_Status_Code::VERIFIED;
251
1.79k
      else
252
1.79k
         return Certificate_Status_Code::SIGNATURE_ERROR;
253
2
      }
254
2
   catch(Algorithm_Not_Found&)
255
2
      {
256
2
      return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN;
257
2
      }
258
25
   catch(...)
259
25
      {
260
25
      // This shouldn't happen, fallback to generic signature error
261
25
      return Certificate_Status_Code::SIGNATURE_ERROR;
262
25
      }
263
6.74k
   }
264
265
/*
266
* Apply the X.509 SIGNED macro
267
*/
268
std::vector<uint8_t> X509_Object::make_signed(PK_Signer* signer,
269
                                            RandomNumberGenerator& rng,
270
                                            const AlgorithmIdentifier& algo,
271
                                            const secure_vector<uint8_t>& tbs_bits)
272
0
   {
273
0
   const std::vector<uint8_t> signature = signer->sign_message(tbs_bits, rng);
274
0
275
0
   std::vector<uint8_t> output;
276
0
   DER_Encoder(output)
277
0
      .start_cons(SEQUENCE)
278
0
         .raw_bytes(tbs_bits)
279
0
         .encode(algo)
280
0
         .encode(signature, BIT_STRING)
281
0
      .end_cons();
282
0
283
0
   return output;
284
0
   }
285
286
namespace {
287
288
std::string choose_sig_algo(AlgorithmIdentifier& sig_algo,
289
                            const Private_Key& key,
290
                            const std::string& hash_fn,
291
                            const std::string& user_specified)
292
0
   {
293
0
   const std::string algo_name = key.algo_name();
294
0
   std::string padding;
295
0
296
0
   // check algo_name and set default
297
0
   if(algo_name == "RSA")
298
0
      {
299
0
      // set to EMSA3 for compatibility reasons, originally it was the only option
300
0
      padding = "EMSA3(" + hash_fn + ")";
301
0
      }
302
0
   else if(algo_name == "DSA" ||
303
0
           algo_name == "ECDSA" ||
304
0
           algo_name == "ECGDSA" ||
305
0
           algo_name == "ECKCDSA" ||
306
0
           algo_name == "GOST-34.10" ||
307
0
           algo_name == "GOST-34.10-2012-256" ||
308
0
           algo_name == "GOST-34.10-2012-512")
309
0
      {
310
0
      padding = "EMSA1(" + hash_fn + ")";
311
0
      }
312
0
   else if(algo_name == "Ed25519")
313
0
      {
314
0
      padding = "Pure";
315
0
      }
316
0
   else if(algo_name == "XMSS")
317
0
      {
318
0
      if(user_specified.empty() == true)
319
0
         {
320
0
         throw Invalid_Argument("XMSS requires padding scheme");
321
0
         }
322
0
      padding = user_specified;
323
0
      sig_algo = AlgorithmIdentifier(OID::from_string("XMSS"), AlgorithmIdentifier::USE_EMPTY_PARAM);
324
0
      return padding;
325
0
      }
326
0
   else
327
0
      {
328
0
      throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
329
0
      }
330
0
331
0
   if(user_specified.empty() == false)
332
0
      {
333
0
      padding = user_specified;
334
0
      }
335
0
336
0
   if(padding != "Pure")
337
0
      {
338
0
      // try to construct an EMSA object from the padding options or default
339
0
      std::unique_ptr<EMSA> emsa;
340
0
      try
341
0
         {
342
0
         emsa.reset(get_emsa(padding));
343
0
         }
344
0
      /*
345
0
      * get_emsa will throw if opts contains {"padding",<valid_padding>} but
346
0
      * <valid_padding> does not specify a hash function.
347
0
      * Omitting it is valid since it needs to be identical to hash_fn.
348
0
      * If it still throws, something happened that we cannot repair here,
349
0
      * e.g. the algorithm/padding combination is not supported.
350
0
      */
351
0
      catch(...)
352
0
         {
353
0
         emsa.reset(get_emsa(padding + "(" + hash_fn + ")"));
354
0
         }
355
0
356
0
      if(!emsa)
357
0
         {
358
0
         throw Invalid_Argument("Could not parse padding scheme " + padding);
359
0
         }
360
0
361
0
      sig_algo = emsa->config_for_x509(key, hash_fn);
362
0
      return emsa->name();
363
0
      }
364
0
   else
365
0
      {
366
0
      sig_algo = AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM);
367
0
      return "Pure";
368
0
      }
369
0
   }
370
371
}
372
373
/*
374
* Choose a signing format for the key
375
*/
376
std::unique_ptr<PK_Signer> X509_Object::choose_sig_format(AlgorithmIdentifier& sig_algo,
377
                                                          const Private_Key& key,
378
                                                          RandomNumberGenerator& rng,
379
                                                          const std::string& hash_fn,
380
                                                          const std::string& padding_algo)
381
0
   {
382
0
   const Signature_Format format = key.default_x509_signature_format();
383
0
384
0
   const std::string emsa = choose_sig_algo(sig_algo, key, hash_fn, padding_algo);
385
0
386
0
   return std::unique_ptr<PK_Signer>(new PK_Signer(key, rng, emsa, format));
387
0
   }
388
389
}