Botan 3.0.0
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/pem.h>
13#include <botan/internal/emsa.h>
14#include <botan/internal/fmt.h>
15#include <algorithm>
16#include <sstream>
17
18namespace Botan {
19
20/*
21* Read a PEM or BER X.509 object
22*/
24 {
25 try {
27 {
28 BER_Decoder dec(in);
29 decode_from(dec);
30 }
31 else
32 {
33 std::string got_label;
34 DataSource_Memory ber(PEM_Code::decode(in, got_label));
35
36 if(got_label != PEM_label())
37 {
38 bool is_alternate = false;
39 for(std::string_view alt_label : alternate_PEM_labels())
40 {
41 if(got_label == alt_label)
42 {
43 is_alternate = true;
44 break;
45 }
46 }
47
48 if(!is_alternate)
49 throw Decoding_Error("Unexpected PEM label for " + PEM_label() + " of " + got_label);
50 }
51
52 BER_Decoder dec(ber);
53 decode_from(dec);
54 }
55 }
56 catch(Decoding_Error& e)
57 {
58 throw Decoding_Error(PEM_label() + " decoding", e);
59 }
60 }
61
62
64 {
68 .end_cons()
71 .end_cons();
72 }
73
74/*
75* Read a BER encoded X.509 object
76*/
78 {
79 from.start_sequence()
81 .raw_bytes(m_tbs_bits)
82 .end_cons()
83 .decode(m_sig_algo)
85 .end_cons();
86
87 force_decode();
88 }
89
90/*
91* Return a PEM encoded X.509 object
92*/
93std::string X509_Object::PEM_encode() const
94 {
96 }
97
98/*
99* Return the TBS data
100*/
101std::vector<uint8_t> X509_Object::tbs_data() const
102 {
103 return ASN1::put_in_sequence(m_tbs_bits);
104 }
105
106/*
107* Check the signature on an object
108*/
109bool X509_Object::check_signature(const Public_Key& pub_key) const
110 {
111 const auto result = this->verify_signature(pub_key);
112 return (result.first == Certificate_Status_Code::VERIFIED);
113 }
114
115std::pair<Certificate_Status_Code, std::string>
117 {
118 try
119 {
120 PK_Verifier verifier(pub_key, signature_algorithm());
121 const bool valid = verifier.verify_message(tbs_data(), signature());
122
123 if(valid)
124 return std::make_pair(Certificate_Status_Code::VERIFIED, verifier.hash_function());
125 else
126 return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
127 }
128 catch(Decoding_Error&)
129 {
131 }
132 catch(Algorithm_Not_Found&)
133 {
134 return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN, "");
135 }
136 catch(...)
137 {
138 // This shouldn't happen, fallback to generic signature error
139 return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
140 }
141 }
142
143/*
144* Apply the X.509 SIGNED macro
145*/
146std::vector<uint8_t> X509_Object::make_signed(PK_Signer& signer,
148 const AlgorithmIdentifier& algo,
149 const secure_vector<uint8_t>& tbs_bits)
150 {
151 const std::vector<uint8_t> signature = signer.sign_message(tbs_bits, rng);
152
153 std::vector<uint8_t> output;
154 DER_Encoder(output)
156 .raw_bytes(tbs_bits)
157 .encode(algo)
159 .end_cons();
160
161 return output;
162 }
163
164namespace {
165
166std::string x509_signature_padding_for(
167 const std::string& algo_name,
168 std::string_view hash_fn,
169 std::string_view user_specified_padding)
170 {
171 if(algo_name == "DSA" ||
172 algo_name == "ECDSA" ||
173 algo_name == "ECGDSA" ||
174 algo_name == "ECKCDSA" ||
175 algo_name == "GOST-34.10" ||
176 algo_name == "GOST-34.10-2012-256" ||
177 algo_name == "GOST-34.10-2012-512")
178 {
179 BOTAN_ARG_CHECK(user_specified_padding.empty() || user_specified_padding == "EMSA1",
180 "Invalid padding scheme for DSA-like scheme");
181
182 return hash_fn.empty() ? "SHA-256" : std::string(hash_fn);
183 }
184 else if(algo_name == "RSA")
185 {
186 // set to PKCSv1.5 for compatibility reasons, originally it was the only option
187
188 if(user_specified_padding.empty())
189 {
190 if(hash_fn.empty())
191 return "EMSA3(SHA-256)";
192 else
193 return fmt("EMSA3({})", hash_fn);
194 }
195 else
196 {
197 if(hash_fn.empty())
198 return fmt("{}(SHA-256)", user_specified_padding);
199 else
200 return fmt("{}({})", user_specified_padding, hash_fn);
201 }
202 }
203 else if(algo_name == "Ed25519")
204 {
205 return user_specified_padding.empty() ? "Pure" : std::string(user_specified_padding);
206 }
207 else if(algo_name.starts_with("Dilithium-"))
208 {
209 return user_specified_padding.empty() ? "Randomized" : std::string(user_specified_padding);
210 }
211 else
212 {
213 throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
214 }
215 }
216
217std::string format_padding_error_message(std::string_view key_name,
218 std::string_view signer_hash_fn,
219 std::string_view user_hash_fn,
220 std::string_view chosen_padding,
221 std::string_view user_specified_padding)
222 {
223 std::ostringstream oss;
224
225 oss << "Specified hash function " << user_hash_fn
226 << " is incompatible with " << key_name;
227
228 if(!signer_hash_fn.empty())
229 oss << " chose hash function " << signer_hash_fn;
230
231 if(!chosen_padding.empty())
232 oss << " chose padding " << chosen_padding;
233 if(!user_specified_padding.empty())
234 oss << " with user specified padding " << user_specified_padding;
235
236 return oss.str();
237 }
238
239}
240
241/*
242* Choose a signing format for the key
243*/
244std::unique_ptr<PK_Signer> X509_Object::choose_sig_format(
245 const Private_Key& key,
247 std::string_view hash_fn,
248 std::string_view user_specified_padding)
249 {
251
252 if(!user_specified_padding.empty())
253 {
254 try
255 {
256 auto pk_signer = std::make_unique<PK_Signer>(key, rng, user_specified_padding, format);
257 if(!hash_fn.empty() && pk_signer->hash_function() != hash_fn)
258 {
259 throw Invalid_Argument(
260 format_padding_error_message(key.algo_name(), pk_signer->hash_function(),
261 hash_fn, "", user_specified_padding)
262 );
263 }
264 return pk_signer;
265 }
266 catch(Lookup_Error&) {}
267 }
268
269 const std::string padding = x509_signature_padding_for(key.algo_name(), hash_fn, user_specified_padding);
270
271 try
272 {
273 auto pk_signer = std::make_unique<PK_Signer>(key, rng, padding, format);
274 if(!hash_fn.empty() && pk_signer->hash_function() != hash_fn)
275 {
276 throw Invalid_Argument(
277 format_padding_error_message(key.algo_name(), pk_signer->hash_function(),
278 hash_fn, padding, user_specified_padding));
279 }
280 return pk_signer;
281 }
282 catch(Not_Implemented&)
283 {
284 throw Invalid_Argument("Signatures using " + key.algo_name() + "/" + padding + " are not supported");
285 }
286 }
287
288}
#define BOTAN_ARG_CHECK(expr, msg)
Definition: assert.h:36
std::vector< uint8_t > BER_encode() const
Definition: asn1_obj.cpp:17
virtual std::string algo_name() const =0
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:193
BER_Decoder & end_cons()
Definition: ber_dec.cpp:304
BER_Decoder start_sequence()
Definition: ber_dec.h:117
DER_Encoder & start_sequence()
Definition: der_enc.h:66
DER_Encoder & raw_bytes(const uint8_t val[], size_t len)
Definition: der_enc.cpp:233
DER_Encoder & end_cons()
Definition: der_enc.cpp:196
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:290
std::vector< uint8_t > sign_message(const uint8_t in[], size_t length, RandomNumberGenerator &rng)
Definition: pubkey.h:198
bool verify_message(const uint8_t msg[], size_t msg_length, const uint8_t sig[], size_t sig_length)
Definition: pubkey.cpp:385
std::string hash_function() const
Definition: pubkey.cpp:374
virtual Signature_Format default_x509_signature_format() const
Definition: pk_keys.h:184
const std::vector< uint8_t > & signed_body() const
Definition: x509_obj.h:43
void decode_from(BER_Decoder &from) override
Definition: x509_obj.cpp:77
std::string PEM_encode() const
Definition: x509_obj.cpp:93
const AlgorithmIdentifier & signature_algorithm() const
Definition: x509_obj.h:48
virtual std::vector< std::string > alternate_PEM_labels() const
Definition: x509_obj.h:102
static std::unique_ptr< PK_Signer > choose_sig_format(const Private_Key &key, RandomNumberGenerator &rng, std::string_view hash_fn, std::string_view padding_algo)
Definition: x509_obj.cpp:244
std::vector< uint8_t > tbs_data() const
Definition: x509_obj.cpp:101
const std::vector< uint8_t > & signature() const
Definition: x509_obj.h:38
static std::vector< uint8_t > make_signed(PK_Signer &signer, RandomNumberGenerator &rng, const AlgorithmIdentifier &alg_id, const secure_vector< uint8_t > &tbs)
Definition: x509_obj.cpp:146
void encode_into(DER_Encoder &to) const override
Definition: x509_obj.cpp:63
std::pair< Certificate_Status_Code, std::string > verify_signature(const Public_Key &key) const
Definition: x509_obj.cpp:116
void load_data(DataSource &src)
Definition: x509_obj.cpp:23
virtual std::string PEM_label() const =0
bool check_signature(const Public_Key &key) const
Definition: x509_obj.cpp:109
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
Definition: asn1_obj.cpp:192
bool maybe_BER(DataSource &source)
Definition: asn1_obj.cpp:219
std::string encode(const uint8_t der[], size_t length, std::string_view label, size_t width)
Definition: pem.cpp:42
bool matches(DataSource &source, std::string_view extra, size_t search_range)
Definition: pem.cpp:144
secure_vector< uint8_t > decode(DataSource &source, std::string &label)
Definition: pem.cpp:70
Definition: alg_id.cpp:12
std::string fmt(std::string_view format, const T &... args)
Definition: fmt.h:60
Signature_Format
Definition: pk_keys.h:29
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:64