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