Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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 */
52 void X509_Object::load_data(DataSource& in)
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
92 void X509_Object::encode_into(DER_Encoder& to) const
93 {
94 to.start_cons(SEQUENCE)
95 .start_cons(SEQUENCE)
96 .raw_bytes(signed_body())
97 .end_cons()
98 .encode(signature_algorithm())
99 .encode(signature(), BIT_STRING)
100 .end_cons();
101 }
102
103 /*
104 * Read a BER encoded X.509 object
105 */
106 void X509_Object::decode_from(BER_Decoder& from)
107 {
108 from.start_cons(SEQUENCE)
109 .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 {
124 return PEM_Code::encode(BER_encode(), PEM_label());
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 */
138 std::string X509_Object::hash_used_for_signature() const
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
184 Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const
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())
190 return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
191
192 std::string padding;
193 if(sig_info.size() == 2)
194 padding = sig_info[1];
195 else if(sig_info[0] == "Ed25519" || sig_info[0] == "XMSS")
196 padding = "Pure";
197 else
198 return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
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 {
207 return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
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 {
220 return Certificate_Status_Code::UNTRUSTED_HASH;
221 }
222
223 const std::string mgf_algo = pss_parameter.mask_gen_algo.get_oid().to_formatted_string();
224 if(mgf_algo != "MGF1")
225 {
226 return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
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 {
233 return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
234 }
235
236 if(pss_parameter.trailer_field != 1)
237 {
238 return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
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)
250 return Certificate_Status_Code::VERIFIED;
251 else
252 return Certificate_Status_Code::SIGNATURE_ERROR;
253 }
254 catch(Algorithm_Not_Found&)
255 {
256 return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN;
257 }
258 catch(...)
259 {
260 // This shouldn't happen, fallback to generic signature error
261 return Certificate_Status_Code::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,
269 RandomNumberGenerator& rng,
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)
277 .start_cons(SEQUENCE)
278 .raw_bytes(tbs_bits)
279 .encode(algo)
280 .encode(signature, BIT_STRING)
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 if(algo_name == "XMSS")
317 {
318 if(user_specified.empty() == true)
319 {
320 throw Invalid_Argument("XMSS requires padding scheme");
321 }
322 padding = user_specified;
323 sig_algo = AlgorithmIdentifier(OID::from_string("XMSS"), AlgorithmIdentifier::USE_EMPTY_PARAM);
324 return padding;
325 }
326 else
327 {
328 throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
329 }
330
331 if(user_specified.empty() == false)
332 {
333 padding = user_specified;
334 }
335
336 if(padding != "Pure")
337 {
338 // try to construct an EMSA object from the padding options or default
339 std::unique_ptr<EMSA> emsa;
340 try
341 {
342 emsa.reset(get_emsa(padding));
343 }
344 /*
345 * get_emsa will throw if opts contains {"padding",<valid_padding>} but
346 * <valid_padding> does not specify a hash function.
347 * Omitting it is valid since it needs to be identical to hash_fn.
348 * If it still throws, something happened that we cannot repair here,
349 * e.g. the algorithm/padding combination is not supported.
350 */
351 catch(...)
352 {
353 emsa.reset(get_emsa(padding + "(" + hash_fn + ")"));
354 }
355
356 if(!emsa)
357 {
358 throw Invalid_Argument("Could not parse padding scheme " + padding);
359 }
360
361 sig_algo = emsa->config_for_x509(key, hash_fn);
362 return emsa->name();
363 }
364 else
365 {
366 sig_algo = AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM);
367 return "Pure";
368 }
369 }
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 {
382 const Signature_Format format = key.default_x509_signature_format();
383
384 const std::string emsa = choose_sig_algo(sig_algo, key, hash_fn, padding_algo);
385
386 return std::unique_ptr<PK_Signer>(new PK_Signer(key, rng, emsa, format));
387 }
388
389 }
Botan::Invalid_Argument
Definition: exceptn.h:136
Botan::X509_Object::hash_used_for_signature
std::string hash_used_for_signature() const
Definition: x509_obj.cpp:138
Botan::X509_Object::signed_body
const std::vector< uint8_t > & signed_body() const
Definition: x509_obj.h:43
Botan::X509_Object::verify_signature
Certificate_Status_Code verify_signature(const Public_Key &key) const
Definition: x509_obj.cpp:184
Botan::PK_Verifier::verify_message
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
Definition: pubkey.cpp:324
Botan::RandomNumberGenerator
Definition: rng.h:24
Botan::Private_Key
Definition: pk_keys.h:181
Botan::split_on
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:148
Botan::X509_Object::encode_into
void encode_into(class DER_Encoder &to) const override
Definition: x509_obj.cpp:92
Botan::X509_Object::make_signed
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
mask_gen_hash
AlgorithmIdentifier mask_gen_hash
Definition: x509_obj.cpp:24
Botan::Signature_Format
Signature_Format
Definition: pk_keys.h:24
Botan::X509_Object::PEM_label
virtual std::string PEM_label() const =0
mask_gen_algo
AlgorithmIdentifier mask_gen_algo
Definition: x509_obj.cpp:23
Botan::Public_Key::algo_name
virtual std::string algo_name() const =0
Botan::Internal_Error
Definition: exceptn.h:341
Botan::ASN1::maybe_BER
bool maybe_BER(DataSource &source)
Definition: asn1_obj.cpp:222
Botan::PRIVATE
Definition: asn1_obj.h:30
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan::OID::to_formatted_string
std::string to_formatted_string() const
Definition: asn1_oid.cpp:110
Botan::ASN1_Tag
ASN1_Tag
Definition: asn1_obj.h:23
Botan::BER_Decoder::raw_bytes
BER_Decoder & raw_bytes(std::vector< uint8_t, Alloc > &out)
Definition: ber_dec.h:156
Botan::DER_Encoder::end_cons
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
Botan::DataSource
Definition: data_src.h:21
Botan::BER_Decoder::decode
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
Botan::X509_Object::signature_algorithm
const AlgorithmIdentifier & signature_algorithm() const
Definition: x509_obj.h:48
Botan::Certificate_Status_Code::SIGNATURE_ERROR
Botan::PK_Signer::sign_message
std::vector< uint8_t > sign_message(const uint8_t in[], size_t length, RandomNumberGenerator &rng)
Definition: pubkey.h:214
Botan::DER_Encoder::raw_bytes
DER_Encoder & raw_bytes(const uint8_t val[], size_t len)
Definition: der_enc.cpp:228
Botan::X509_Object::alternate_PEM_labels
virtual std::vector< std::string > alternate_PEM_labels() const
Definition: x509_obj.h:114
Botan::Decoding_Error
Definition: exceptn.h:199
Botan::X509_Object::decode_from
void decode_from(class BER_Decoder &from) override
Definition: x509_obj.cpp:106
Botan::X509_Object::signature
const std::vector< uint8_t > & signature() const
Definition: x509_obj.h:38
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
Botan::SEQUENCE
Definition: asn1_obj.h:40
Botan::DER_Encoder
Definition: der_enc.h:23
Botan::X509_Object::PEM_encode
std::string PEM_encode() const
Definition: x509_obj.cpp:122
Botan::X509_Object::choose_sig_format
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:376
Botan::secure_vector
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:65
Botan::PEM_Code::encode
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
Botan::BER_Decoder::end_cons
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
Botan::PEM_Code::matches
bool matches(DataSource &source, const std::string &extra, size_t search_range)
Definition: pem.cpp:142
Botan::OID::to_string
std::string to_string() const
Definition: asn1_oid.cpp:98
Botan::Certificate_Status_Code::UNTRUSTED_HASH
Botan::PEM_Code::decode
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:68
Botan::ASN1_Object::BER_encode
std::vector< uint8_t > BER_encode() const
Definition: asn1_obj.cpp:16
salt_len
size_t salt_len
Definition: x509_obj.cpp:25
Botan::X509_Object::load_data
void load_data(DataSource &src)
Definition: x509_obj.cpp:52
Botan::BER_Decoder::start_cons
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
Botan::AlgorithmIdentifier::USE_EMPTY_PARAM
Definition: alg_id.h:24
Botan::parse_algorithm_name
std::vector< std::string > parse_algorithm_name(const std::string &namex)
Definition: parsing.cpp:95
Botan
Definition: alg_id.cpp:13
Botan::PK_Verifier
Definition: pubkey.h:298
Botan::AlgorithmIdentifier::get_oid
const OID & get_oid() const
Definition: alg_id.h:37
hash_algo
AlgorithmIdentifier hash_algo
Definition: x509_obj.cpp:22
Botan::Public_Key
Definition: pk_keys.h:29
Botan::ASN1::put_in_sequence
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
Definition: asn1_obj.cpp:195
trailer_field
size_t trailer_field
Definition: x509_obj.cpp:26
Botan::Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS
Botan::X509_Object::tbs_data
std::vector< uint8_t > tbs_data() const
Definition: x509_obj.cpp:130
Botan::X509_Object::check_signature
bool check_signature(const Public_Key &key) const
Definition: x509_obj.cpp:178
Botan::DataSource_Memory
Definition: data_src.h:98
Botan::BIT_STRING
Definition: asn1_obj.h:35
Botan::AlgorithmIdentifier
Definition: alg_id.h:21
Botan::DER_Encoder::start_cons
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
Botan::Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN
Botan::get_emsa
EMSA * get_emsa(const std::string &algo_spec)
Definition: emsa.cpp:44
Botan::AlgorithmIdentifier::USE_NULL_PARAM
Definition: alg_id.h:24
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: cert_status.h:19
Botan::PK_Signer
Definition: pubkey.h:166
Botan::OID
Definition: asn1_oid.h:20
Botan::BER_Decoder
Definition: ber_dec.h:21
Botan::Certificate_Status_Code::VERIFIED
Botan::Public_Key::default_x509_signature_format
virtual Signature_Format default_x509_signature_format() const
Definition: pk_keys.h:126
Botan::Algorithm_Not_Found
Definition: exceptn.h:265
Botan::OID::from_string
static OID from_string(const std::string &str)
Definition: asn1_oid.cpp:62