Botan 2.19.2
Crypto and TLS for C&
x509_obj.cpp
Go to the documentation of this file.
1/*
2* X.509 SIGNED Object
3* (C) 1999-2007,2020 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
17namespace Botan {
18
19namespace {
20struct 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;
27 };
28
29Pss_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 {
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*/
122std::string X509_Object::PEM_encode() const
123 {
125 }
126
127/*
128* Return the TBS data
129*/
130std::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*/
170bool 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
178bool 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 const std::string pub_key_algo = sig_info[0];
193 std::string padding;
194 if(sig_info.size() == 2)
195 padding = sig_info[1];
196 else if(pub_key_algo == "Ed25519" || pub_key_algo == "XMSS")
197 padding = "Pure";
198 else
200
201 const Signature_Format format = pub_key.default_x509_signature_format();
202
203 if(padding == "EMSA4")
204 {
205 // "MUST contain RSASSA-PSS-params"
206 if(signature_algorithm().get_parameters().empty())
207 {
209 }
210
211 Pss_params pss_parameter = decode_pss_params(signature_algorithm().get_parameters());
212
213 // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
214 const std::string hash_algo = pss_parameter.hash_algo.get_oid().to_formatted_string();
215 if(hash_algo != "SHA-160" &&
216 hash_algo != "SHA-224" &&
217 hash_algo != "SHA-256" &&
218 hash_algo != "SHA-384" &&
219 hash_algo != "SHA-512")
220 {
222 }
223
224 const std::string mgf_algo = pss_parameter.mask_gen_algo.get_oid().to_formatted_string();
225 if(mgf_algo != "MGF1")
226 {
228 }
229
230 // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm
231 // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
232 if(pss_parameter.mask_gen_hash.get_oid() != pss_parameter.hash_algo.get_oid())
233 {
235 }
236
237 if(pss_parameter.trailer_field != 1)
238 {
240 }
241
242 padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")";
243 }
244 else
245 {
246 /*
247 * For all other signature types the signature parameters should
248 * be either NULL or empty. In theory there is some distinction between
249 * these but in practice they seem to be used somewhat interchangeably.
250 *
251 * The various RFCs all have prescriptions of what is allowed:
252 * RSA - NULL (RFC 3279)
253 * DSA - empty (RFC 3279)
254 * ECDSA - empty (RFC 3279)
255 * GOST - empty (RFC 4491)
256 * Ed25519 - empty (RFC 8410)
257 * XMSS - empty (draft-vangeest-x509-hash-sigs)
258 *
259 * But in practice we find RSA with empty and ECDSA will NULL all
260 * over the place so it's not really possible to enforce. For Ed25519
261 * and XMSS because they are new we attempt to enforce.
262 */
263 if(pub_key_algo == "Ed25519" || pub_key_algo == "XMSS")
264 {
265 if(!signature_algorithm().parameters_are_empty())
266 {
268 }
269 }
270 else
271 {
272 if(!signature_algorithm().parameters_are_null_or_empty())
273 {
275 }
276 }
277 }
278
279 try
280 {
281 PK_Verifier verifier(pub_key, padding, format);
282 const bool valid = verifier.verify_message(tbs_data(), signature());
283
284 if(valid)
286 else
288 }
289 catch(Algorithm_Not_Found&)
290 {
292 }
293 catch(...)
294 {
295 // This shouldn't happen, fallback to generic signature error
297 }
298 }
299
300/*
301* Apply the X.509 SIGNED macro
302*/
303std::vector<uint8_t> X509_Object::make_signed(PK_Signer* signer,
305 const AlgorithmIdentifier& algo,
306 const secure_vector<uint8_t>& tbs_bits)
307 {
308 const std::vector<uint8_t> signature = signer->sign_message(tbs_bits, rng);
309
310 std::vector<uint8_t> output;
311 DER_Encoder(output)
313 .raw_bytes(tbs_bits)
314 .encode(algo)
316 .end_cons();
317
318 return output;
319 }
320
321namespace {
322
323std::string choose_sig_algo(AlgorithmIdentifier& sig_algo,
324 const Private_Key& key,
325 const std::string& hash_fn,
326 const std::string& user_specified)
327 {
328 const std::string algo_name = key.algo_name();
329 std::string padding;
330
331 // check algo_name and set default
332 if(algo_name == "RSA")
333 {
334 // set to EMSA3 for compatibility reasons, originally it was the only option
335 padding = "EMSA3(" + hash_fn + ")";
336 }
337 else if(algo_name == "DSA" ||
338 algo_name == "ECDSA" ||
339 algo_name == "ECGDSA" ||
340 algo_name == "ECKCDSA" ||
341 algo_name == "GOST-34.10" ||
342 algo_name == "GOST-34.10-2012-256" ||
343 algo_name == "GOST-34.10-2012-512")
344 {
345 padding = "EMSA1(" + hash_fn + ")";
346 }
347 else if(algo_name == "Ed25519")
348 {
349 padding = "Pure";
350 }
351 else if(algo_name == "XMSS")
352 {
353 if(user_specified.empty() == true)
354 {
355 throw Invalid_Argument("XMSS requires padding scheme");
356 }
357 padding = user_specified;
358 sig_algo = AlgorithmIdentifier(OID::from_string("XMSS"), AlgorithmIdentifier::USE_EMPTY_PARAM);
359 return padding;
360 }
361 else
362 {
363 throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
364 }
365
366 if(user_specified.empty() == false)
367 {
368 padding = user_specified;
369 }
370
371 if(padding != "Pure")
372 {
373 // try to construct an EMSA object from the padding options or default
374 std::unique_ptr<EMSA> emsa;
375 try
376 {
377 emsa.reset(get_emsa(padding));
378 }
379 /*
380 * get_emsa will throw if opts contains {"padding",<valid_padding>} but
381 * <valid_padding> does not specify a hash function.
382 * Omitting it is valid since it needs to be identical to hash_fn.
383 * If it still throws, something happened that we cannot repair here,
384 * e.g. the algorithm/padding combination is not supported.
385 */
386 catch(...)
387 {
388 emsa.reset(get_emsa(padding + "(" + hash_fn + ")"));
389 }
390
391 if(!emsa)
392 {
393 throw Invalid_Argument("Could not parse padding scheme " + padding);
394 }
395
396 sig_algo = emsa->config_for_x509(key, hash_fn);
397 return emsa->name();
398 }
399 else
400 {
401 sig_algo = AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM);
402 return "Pure";
403 }
404 }
405
406}
407
408/*
409* Choose a signing format for the key
410*/
411std::unique_ptr<PK_Signer> X509_Object::choose_sig_format(AlgorithmIdentifier& sig_algo,
412 const Private_Key& key,
414 const std::string& hash_fn,
415 const std::string& padding_algo)
416 {
418
419 const std::string emsa = choose_sig_algo(sig_algo, key, hash_fn, padding_algo);
420
421 return std::unique_ptr<PK_Signer>(new PK_Signer(key, rng, emsa, format));
422 }
423
424}
std::vector< uint8_t > BER_encode() const
Definition: asn1_obj.cpp:16
const OID & get_oid() const
Definition: asn1_obj.h:445
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
BER_Decoder & raw_bytes(std::vector< uint8_t, Alloc > &out)
Definition: ber_dec.h:156
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
DER_Encoder & raw_bytes(const uint8_t val[], size_t len)
Definition: der_enc.cpp:228
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
std::string to_formatted_string() const
Definition: asn1_oid.cpp:111
static OID from_string(const std::string &str)
Definition: asn1_oid.cpp:62
std::string to_string() const
Definition: asn1_oid.cpp:98
std::vector< uint8_t > sign_message(const uint8_t in[], size_t length, RandomNumberGenerator &rng)
Definition: pubkey.h:214
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
Definition: pubkey.cpp:331
virtual Signature_Format default_x509_signature_format() const
Definition: pk_keys.h:125
virtual std::string algo_name() const =0
void decode_from(class BER_Decoder &from) override
Definition: x509_obj.cpp:106
std::string hash_used_for_signature() const
Definition: x509_obj.cpp:138
Certificate_Status_Code verify_signature(const Public_Key &key) const
Definition: x509_obj.cpp:184
const std::vector< uint8_t > & signed_body() const
Definition: x509_obj.h:42
std::string PEM_encode() const
Definition: x509_obj.cpp:122
const AlgorithmIdentifier & signature_algorithm() const
Definition: x509_obj.h:47
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:411
virtual std::vector< std::string > alternate_PEM_labels() const
Definition: x509_obj.h:113
std::vector< uint8_t > tbs_data() const
Definition: x509_obj.cpp:130
const std::vector< uint8_t > & signature() const
Definition: x509_obj.h:37
void load_data(DataSource &src)
Definition: x509_obj.cpp:52
virtual std::string PEM_label() const =0
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:303
bool check_signature(const Public_Key &key) const
Definition: x509_obj.cpp:178
void encode_into(class DER_Encoder &to) const override
Definition: x509_obj.cpp:92
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
Definition: asn1_obj.cpp:195
bool maybe_BER(DataSource &source)
Definition: asn1_obj.cpp:222
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition: pem.cpp:142
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
Definition: alg_id.cpp:13
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:148
EMSA * get_emsa(const std::string &algo_spec)
Definition: emsa.cpp:44
ASN1_Tag
Definition: asn1_obj.h:25
@ BIT_STRING
Definition: asn1_obj.h:37
@ SEQUENCE
Definition: asn1_obj.h:42
@ PRIVATE
Definition: asn1_obj.h:32
std::vector< std::string > parse_algorithm_name(const std::string &namex)
Definition: parsing.cpp:95
Signature_Format
Definition: pk_keys.h:23
Certificate_Status_Code
Definition: pkix_enums.h:17
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
AlgorithmIdentifier mask_gen_hash
Definition: x509_obj.cpp:24
AlgorithmIdentifier mask_gen_algo
Definition: x509_obj.cpp:23
AlgorithmIdentifier hash_algo
Definition: x509_obj.cpp:22
size_t trailer_field
Definition: x509_obj.cpp:26
size_t salt_len
Definition: x509_obj.cpp:25