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