• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 19012754211

02 Nov 2025 01:10PM UTC coverage: 90.677% (+0.006%) from 90.671%
19012754211

push

github

web-flow
Merge pull request #5137 from randombit/jack/clang-tidy-includes

Remove various unused includes flagged by clang-tidy misc-include-cleaner

100457 of 110786 relevant lines covered (90.68%)

12189873.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.65
/src/lib/x509/x509_obj.cpp
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/der_enc.h>
13
#include <botan/pem.h>
14
#include <botan/pubkey.h>
15
#include <botan/internal/fmt.h>
16
#include <sstream>
17

18
namespace Botan {
19

20
/*
21
* Read a PEM or BER X.509 object
22
*/
23
void X509_Object::load_data(DataSource& in) {
29,931✔
24
   try {
29,931✔
25
      if(ASN1::maybe_BER(in) && !PEM_Code::matches(in)) {
29,931✔
26
         BER_Decoder dec(in);
23,985✔
27
         decode_from(dec);
23,985✔
28
      } else {
23,985✔
29
         std::string got_label;
5,742✔
30
         DataSource_Memory ber(PEM_Code::decode(in, got_label));
5,819✔
31

32
         if(got_label != PEM_label()) {
4,562✔
33
            bool is_alternate = false;
72✔
34
            for(std::string_view alt_label : alternate_PEM_labels()) {
142✔
35
               if(got_label == alt_label) {
74✔
36
                  is_alternate = true;
37
                  break;
38
               }
39
            }
72✔
40

41
            if(!is_alternate) {
72✔
42
               throw Decoding_Error("Unexpected PEM label for " + PEM_label() + " of " + got_label);
350✔
43
            }
44
         }
45

46
         BER_Decoder dec(ber);
4,415✔
47
         decode_from(dec);
4,415✔
48
      }
10,234✔
49
   } catch(Decoding_Error& e) {
8,127✔
50
      throw Decoding_Error(PEM_label() + " decoding", e);
22,572✔
51
   }
7,524✔
52
}
21,600✔
53

54
void X509_Object::encode_into(DER_Encoder& to) const {
22,329✔
55
   to.start_sequence()
22,329✔
56
      .start_sequence()
22,329✔
57
      .raw_bytes(signed_body())
22,329✔
58
      .end_cons()
22,329✔
59
      .encode(signature_algorithm())
22,329✔
60
      .encode(signature(), ASN1_Type::BitString)
22,329✔
61
      .end_cons();
22,329✔
62
}
22,329✔
63

64
/*
65
* Read a BER encoded X.509 object
66
*/
67
void X509_Object::decode_from(BER_Decoder& from) {
29,644✔
68
   from.start_sequence()
58,584✔
69
      .start_sequence()
28,940✔
70
      .raw_bytes(m_tbs_bits)
28,940✔
71
      .end_cons()
28,940✔
72
      .decode(m_sig_algo)
28,940✔
73
      .decode(m_sig, ASN1_Type::BitString)
26,891✔
74
      .end_cons();
26,825✔
75

76
   force_decode();
26,536✔
77
}
22,464✔
78

79
/*
80
* Return a PEM encoded X.509 object
81
*/
82
std::string X509_Object::PEM_encode() const {
181✔
83
   return PEM_Code::encode(BER_encode(), PEM_label());
362✔
84
}
85

86
/*
87
* Return the TBS data
88
*/
89
std::vector<uint8_t> X509_Object::tbs_data() const {
17,675✔
90
   return ASN1::put_in_sequence(m_tbs_bits);
17,675✔
91
}
92

93
/*
94
* Check the signature on an object
95
*/
96
bool X509_Object::check_signature(const Public_Key& pub_key) const {
2,372✔
97
   const auto result = this->verify_signature(pub_key);
2,372✔
98
   return (result.first == Certificate_Status_Code::VERIFIED);
2,372✔
99
}
2,372✔
100

101
std::pair<Certificate_Status_Code, std::string> X509_Object::verify_signature(const Public_Key& pub_key) const {
17,720✔
102
   try {
17,720✔
103
      PK_Verifier verifier(pub_key, signature_algorithm());
17,720✔
104
      const bool valid = verifier.verify_message(tbs_data(), signature());
17,675✔
105

106
      if(valid) {
17,675✔
107
         return std::make_pair(Certificate_Status_Code::VERIFIED, verifier.hash_function());
17,314✔
108
      } else {
109
         return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
361✔
110
      }
111
   } catch(Decoding_Error&) {
17,720✔
112
      return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
44✔
113
   } catch(Algorithm_Not_Found&) {
44✔
114
      return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN, "");
×
115
   } catch(...) {
1✔
116
      // This shouldn't happen, fallback to generic signature error
117
      return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
1✔
118
   }
1✔
119
}
120

121
/*
122
* Apply the X.509 SIGNED macro
123
*/
124
std::vector<uint8_t> X509_Object::make_signed(PK_Signer& signer,
3,386✔
125
                                              RandomNumberGenerator& rng,
126
                                              const AlgorithmIdentifier& algo,
127
                                              const secure_vector<uint8_t>& tbs_bits) {
128
   const std::vector<uint8_t> signature = signer.sign_message(tbs_bits, rng);
3,386✔
129

130
   std::vector<uint8_t> output;
3,386✔
131
   DER_Encoder(output)
6,772✔
132
      .start_sequence()
3,386✔
133
      .raw_bytes(tbs_bits)
3,386✔
134
      .encode(algo)
3,386✔
135
      .encode(signature, ASN1_Type::BitString)
3,386✔
136
      .end_cons();
3,386✔
137

138
   return output;
3,386✔
139
}
3,386✔
140

141
namespace {
142

143
std::string x509_signature_padding_for(const std::string& algo_name,
1,896✔
144
                                       std::string_view hash_fn,
145
                                       std::string_view user_specified_padding) {
146
   if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA" ||
1,876✔
147
      algo_name == "GOST-34.10" || algo_name == "GOST-34.10-2012-256" || algo_name == "GOST-34.10-2012-512") {
2,106✔
148
      BOTAN_ARG_CHECK(user_specified_padding.empty() || user_specified_padding == "EMSA1",
1,706✔
149
                      "Invalid padding scheme for DSA-like scheme");
150

151
      return hash_fn.empty() ? "SHA-256" : std::string(hash_fn);
3,397✔
152
   } else if(algo_name == "RSA") {
190✔
153
      // set to PKCSv1.5 for compatibility reasons, originally it was the only option
154

155
      if(user_specified_padding.empty()) {
43✔
156
         if(hash_fn.empty()) {
40✔
157
            return "PKCS1v15(SHA-256)";
6✔
158
         } else {
159
            return fmt("PKCS1v15({})", hash_fn);
34✔
160
         }
161
      } else {
162
         if(hash_fn.empty()) {
3✔
163
            return fmt("{}(SHA-256)", user_specified_padding);
×
164
         } else {
165
            return fmt("{}({})", user_specified_padding, hash_fn);
3✔
166
         }
167
      }
168
   } else if(algo_name == "Ed25519" || algo_name == "Ed448") {
147✔
169
      return user_specified_padding.empty() ? "Pure" : std::string(user_specified_padding);
40✔
170
   } else if(algo_name.starts_with("Dilithium-") || algo_name == "ML-DSA") {
107✔
171
      return user_specified_padding.empty() ? "Randomized" : std::string(user_specified_padding);
47✔
172
   } else if(algo_name == "XMSS" || algo_name == "HSS-LMS" || algo_name == "SLH-DSA") {
60✔
173
      // These algorithms do not take any padding, but if the user insists, we pass it along
174
      return std::string(user_specified_padding);
60✔
175
   } else {
176
      throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
×
177
   }
178
}
179

180
std::string format_padding_error_message(std::string_view key_name,
1✔
181
                                         std::string_view signer_hash_fn,
182
                                         std::string_view user_hash_fn,
183
                                         std::string_view chosen_padding,
184
                                         std::string_view user_specified_padding) {
185
   std::ostringstream oss;
1✔
186

187
   oss << "Specified hash function " << user_hash_fn << " is incompatible with " << key_name;
1✔
188

189
   if(!signer_hash_fn.empty()) {
1✔
190
      oss << " chose hash function " << signer_hash_fn;
1✔
191
   }
192

193
   if(!chosen_padding.empty()) {
1✔
194
      oss << " chose padding " << chosen_padding;
×
195
   }
196
   if(!user_specified_padding.empty()) {
1✔
197
      oss << " with user specified padding " << user_specified_padding;
1✔
198
   }
199

200
   return oss.str();
2✔
201
}
1✔
202

203
}  // namespace
204

205
/*
206
* Choose a signing format for the key
207
*/
208
std::unique_ptr<PK_Signer> X509_Object::choose_sig_format(const Private_Key& key,
2,070✔
209
                                                          RandomNumberGenerator& rng,
210
                                                          std::string_view hash_fn,
211
                                                          std::string_view user_specified_padding) {
212
   const Signature_Format format = key._default_x509_signature_format();
2,070✔
213

214
   if(!user_specified_padding.empty()) {
2,070✔
215
      try {
177✔
216
         auto pk_signer = std::make_unique<PK_Signer>(key, rng, user_specified_padding, format);
177✔
217
         if(!hash_fn.empty() && pk_signer->hash_function() != hash_fn) {
522✔
218
            throw Invalid_Argument(format_padding_error_message(
3✔
219
               key.algo_name(), pk_signer->hash_function(), hash_fn, "", user_specified_padding));
3✔
220
         }
221
         return pk_signer;
173✔
222
      } catch(Lookup_Error&) {}
178✔
223
   }
224

225
   const std::string padding = x509_signature_padding_for(key.algo_name(), hash_fn, user_specified_padding);
1,896✔
226

227
   try {
1,896✔
228
      auto pk_signer = std::make_unique<PK_Signer>(key, rng, padding, format);
1,896✔
229
      if(!hash_fn.empty() && pk_signer->hash_function() != hash_fn) {
5,626✔
230
         throw Invalid_Argument(format_padding_error_message(
×
231
            key.algo_name(), pk_signer->hash_function(), hash_fn, padding, user_specified_padding));
×
232
      }
233
      return pk_signer;
1,896✔
234
   } catch(Not_Implemented&) {
1,896✔
235
      throw Invalid_Argument("Signatures using " + key.algo_name() + "/" + padding + " are not supported");
×
236
   }
×
237
}
1,896✔
238

239
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc