Coverage Report

Created: 2020-02-14 15:38

/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
72
   {
31
72
   const AlgorithmIdentifier default_hash("SHA-160", AlgorithmIdentifier::USE_NULL_PARAM);
32
72
   const AlgorithmIdentifier default_mgf("MGF1", default_hash.BER_encode());
33
72
34
72
   Pss_params pss_parameter;
35
72
   BER_Decoder(encoded_pss_params)
36
72
      .start_cons(SEQUENCE)
37
72
         .decode_optional(pss_parameter.hash_algo, ASN1_Tag(0), PRIVATE, default_hash)
38
72
         .decode_optional(pss_parameter.mask_gen_algo, ASN1_Tag(1), PRIVATE, default_mgf)
39
72
         .decode_optional(pss_parameter.salt_len, ASN1_Tag(2), PRIVATE, size_t(20))
40
72
         .decode_optional(pss_parameter.trailer_field, ASN1_Tag(3), PRIVATE, size_t(1))
41
72
      .end_cons();
42
72
43
72
   BER_Decoder(pss_parameter.mask_gen_algo.get_parameters()).decode(pss_parameter.mask_gen_hash);
44
72
45
72
   return pss_parameter;
46
72
   }
47
}
48
49
/*
50
* Read a PEM or BER X.509 object
51
*/
52
void X509_Object::load_data(DataSource& in)
53
19.9k
   {
54
19.9k
   try {
55
19.9k
      if(ASN1::maybe_BER(in) && !PEM_Code::matches(in))
56
13.6k
         {
57
13.6k
         BER_Decoder dec(in);
58
13.6k
         decode_from(dec);
59
13.6k
         }
60
6.34k
      else
61
6.34k
         {
62
6.34k
         std::string got_label;
63
6.34k
         DataSource_Memory ber(PEM_Code::decode(in, got_label));
64
6.34k
65
6.34k
         if(got_label != PEM_label())
66
199
            {
67
199
            bool is_alternate = false;
68
199
            for(std::string alt_label : alternate_PEM_labels())
69
199
               {
70
199
               if(got_label == alt_label)
71
4
                  {
72
4
                  is_alternate = true;
73
4
                  break;
74
4
                  }
75
199
               }
76
199
77
199
            if(!is_alternate)
78
195
               throw Decoding_Error("Unexpected PEM label for " + PEM_label() + " of " + got_label);
79
6.15k
            }
80
6.15k
81
6.15k
         BER_Decoder dec(ber);
82
6.15k
         decode_from(dec);
83
6.15k
         }
84
19.9k
      }
85
19.9k
   catch(Decoding_Error& e)
86
19.9k
      {
87
6.90k
      throw Decoding_Error(PEM_label() + " decoding", e);
88
6.90k
      }
89
19.9k
   }
90
91
92
void X509_Object::encode_into(DER_Encoder& to) const
93
11.8k
   {
94
11.8k
   to.start_cons(SEQUENCE)
95
11.8k
         .start_cons(SEQUENCE)
96
11.8k
            .raw_bytes(signed_body())
97
11.8k
         .end_cons()
98
11.8k
         .encode(signature_algorithm())
99
11.8k
         .encode(signature(), BIT_STRING)
100
11.8k
      .end_cons();
101
11.8k
   }
102
103
/*
104
* Read a BER encoded X.509 object
105
*/
106
void X509_Object::decode_from(BER_Decoder& from)
107
18.9k
   {
108
18.9k
   from.start_cons(SEQUENCE)
109
18.9k
         .start_cons(SEQUENCE)
110
18.9k
            .raw_bytes(m_tbs_bits)
111
18.9k
         .end_cons()
112
18.9k
         .decode(m_sig_algo)
113
18.9k
         .decode(m_sig, BIT_STRING)
114
18.9k
      .end_cons();
115
18.9k
116
18.9k
   force_decode();
117
18.9k
   }
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
7.65k
   {
132
7.65k
   return ASN1::put_in_sequence(m_tbs_bits);
133
7.65k
   }
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
7.71k
   {
186
7.71k
   const std::vector<std::string> sig_info =
187
7.71k
      split_on(m_sig_algo.get_oid().to_formatted_string(), '/');
188
7.71k
189
7.71k
   if(sig_info.size() < 1 || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name())
190
49
      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
191
7.66k
192
7.66k
   std::string padding;
193
7.66k
   if(sig_info.size() == 2)
194
7.59k
      padding = sig_info[1];
195
73
   else if(sig_info[0] == "Ed25519" || sig_info[0] == "XMSS")
196
70
      padding = "Pure";
197
3
   else
198
3
      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
199
7.66k
200
7.66k
   const Signature_Format format = pub_key.default_x509_signature_format();
201
7.66k
202
7.66k
   if(padding == "EMSA4")
203
72
      {
204
72
      // "MUST contain RSASSA-PSS-params"
205
72
      if(signature_algorithm().get_parameters().empty())
206
0
         {
207
0
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
208
0
         }
209
72
210
72
      Pss_params pss_parameter = decode_pss_params(signature_algorithm().get_parameters());
211
72
212
72
      // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
213
72
      const std::string hash_algo = pss_parameter.hash_algo.get_oid().to_formatted_string();
214
72
      if(hash_algo != "SHA-160" &&
215
72
         hash_algo != "SHA-224" &&
216
72
         hash_algo != "SHA-256" &&
217
72
         hash_algo != "SHA-384" &&
218
72
         hash_algo != "SHA-512")
219
1
         {
220
1
         return Certificate_Status_Code::UNTRUSTED_HASH;
221
1
         }
222
71
223
71
      const std::string mgf_algo = pss_parameter.mask_gen_algo.get_oid().to_formatted_string();
224
71
      if(mgf_algo != "MGF1")
225
1
         {
226
1
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
227
1
         }
228
70
229
70
      // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm
230
70
      // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
231
70
      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
69
236
69
      if(pss_parameter.trailer_field != 1)
237
0
         {
238
0
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
239
0
         }
240
69
241
69
      padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")";
242
69
      }
243
7.66k
244
7.66k
   try
245
7.65k
      {
246
7.65k
      PK_Verifier verifier(pub_key, padding, format);
247
7.65k
      const bool valid = verifier.verify_message(tbs_data(), signature());
248
7.65k
249
7.65k
      if(valid)
250
5.33k
         return Certificate_Status_Code::VERIFIED;
251
2.32k
      else
252
2.32k
         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
24
   catch(...)
259
24
      {
260
24
      // This shouldn't happen, fallback to generic signature error
261
24
      return Certificate_Status_Code::SIGNATURE_ERROR;
262
24
      }
263
7.65k
   }
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
}