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

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

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

93.33
/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/ber_dec.h>
11
#include <botan/der_enc.h>
12
#include <botan/pem.h>
13
#include <botan/pubkey.h>
14
#include <botan/internal/emsa.h>
15
#include <botan/internal/fmt.h>
16
#include <algorithm>
17
#include <sstream>
18

19
namespace Botan {
20

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

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

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

46
         BER_Decoder dec(ber);
2,838✔
47
         decode_from(dec);
2,838✔
48
      }
7,028✔
49
   } catch(Decoding_Error& e) { throw Decoding_Error(PEM_label() + " decoding", e); }
13,998✔
50
}
14,621✔
51

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

62
/*
63
* Read a BER encoded X.509 object
64
*/
65
void X509_Object::decode_from(BER_Decoder& from) {
20,963✔
66
   from.start_sequence()
20,963✔
67
      .start_sequence()
21,691✔
68
      .raw_bytes(m_tbs_bits)
18,600✔
69
      .end_cons()
18,600✔
70
      .decode(m_sig_algo)
18,600✔
71
      .decode(m_sig, ASN1_Type::BitString)
17,401✔
72
      .end_cons();
17,328✔
73

74
   force_decode();
17,320✔
75
}
14,876✔
76

77
/*
78
* Return a PEM encoded X.509 object
79
*/
80
std::string X509_Object::PEM_encode() const { return PEM_Code::encode(BER_encode(), PEM_label()); }
480✔
81

82
/*
83
* Return the TBS data
84
*/
85
std::vector<uint8_t> X509_Object::tbs_data() const { return ASN1::put_in_sequence(m_tbs_bits); }
10,835✔
86

87
/*
88
* Check the signature on an object
89
*/
90
bool X509_Object::check_signature(const Public_Key& pub_key) const {
924✔
91
   const auto result = this->verify_signature(pub_key);
924✔
92
   return (result.first == Certificate_Status_Code::VERIFIED);
924✔
93
}
924✔
94

95
std::pair<Certificate_Status_Code, std::string> X509_Object::verify_signature(const Public_Key& pub_key) const {
10,891✔
96
   try {
10,891✔
97
      PK_Verifier verifier(pub_key, signature_algorithm());
10,891✔
98
      const bool valid = verifier.verify_message(tbs_data(), signature());
10,835✔
99

100
      if(valid)
10,835✔
101
         return std::make_pair(Certificate_Status_Code::VERIFIED, verifier.hash_function());
20,346✔
102
      else
103
         return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
662✔
104
   } catch(Decoding_Error&) {
10,891✔
105
      return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS, "");
55✔
106
   } catch(Algorithm_Not_Found&) {
55✔
107
      return std::make_pair(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN, "");
×
108
   } catch(...) {
1✔
109
      // This shouldn't happen, fallback to generic signature error
110
      return std::make_pair(Certificate_Status_Code::SIGNATURE_ERROR, "");
1✔
111
   }
1✔
112
}
113

114
/*
115
* Apply the X.509 SIGNED macro
116
*/
117
std::vector<uint8_t> X509_Object::make_signed(PK_Signer& signer,
441✔
118
                                              RandomNumberGenerator& rng,
119
                                              const AlgorithmIdentifier& algo,
120
                                              const secure_vector<uint8_t>& tbs_bits) {
121
   const std::vector<uint8_t> signature = signer.sign_message(tbs_bits, rng);
441✔
122

123
   std::vector<uint8_t> output;
441✔
124
   DER_Encoder(output)
882✔
125
      .start_sequence()
441✔
126
      .raw_bytes(tbs_bits)
441✔
127
      .encode(algo)
441✔
128
      .encode(signature, ASN1_Type::BitString)
441✔
129
      .end_cons();
441✔
130

131
   return output;
441✔
132
}
441✔
133

134
namespace {
135

136
std::string x509_signature_padding_for(const std::string& algo_name,
210✔
137
                                       std::string_view hash_fn,
138
                                       std::string_view user_specified_padding) {
139
   if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA" ||
210✔
140
      algo_name == "GOST-34.10" || algo_name == "GOST-34.10-2012-256" || algo_name == "GOST-34.10-2012-512") {
315✔
141
      BOTAN_ARG_CHECK(user_specified_padding.empty() || user_specified_padding == "EMSA1",
125✔
142
                      "Invalid padding scheme for DSA-like scheme");
143

144
      return hash_fn.empty() ? "SHA-256" : std::string(hash_fn);
235✔
145
   } else if(algo_name == "RSA") {
85✔
146
      // set to PKCSv1.5 for compatibility reasons, originally it was the only option
147

148
      if(user_specified_padding.empty()) {
38✔
149
         if(hash_fn.empty())
36✔
150
            return "EMSA3(SHA-256)";
6✔
151
         else
152
            return fmt("EMSA3({})", hash_fn);
30✔
153
      } else {
154
         if(hash_fn.empty())
2✔
155
            return fmt("{}(SHA-256)", user_specified_padding);
×
156
         else
157
            return fmt("{}({})", user_specified_padding, hash_fn);
2✔
158
      }
159
   } else if(algo_name == "Ed25519") {
47✔
160
      return user_specified_padding.empty() ? "Pure" : std::string(user_specified_padding);
20✔
161
   } else if(algo_name.starts_with("Dilithium-")) {
27✔
162
      return user_specified_padding.empty() ? "Randomized" : std::string(user_specified_padding);
27✔
163
   } else {
164
      throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
×
165
   }
166
}
167

168
std::string format_padding_error_message(std::string_view key_name,
1✔
169
                                         std::string_view signer_hash_fn,
170
                                         std::string_view user_hash_fn,
171
                                         std::string_view chosen_padding,
172
                                         std::string_view user_specified_padding) {
173
   std::ostringstream oss;
1✔
174

175
   oss << "Specified hash function " << user_hash_fn << " is incompatible with " << key_name;
1✔
176

177
   if(!signer_hash_fn.empty())
1✔
178
      oss << " chose hash function " << signer_hash_fn;
1✔
179

180
   if(!chosen_padding.empty())
1✔
181
      oss << " chose padding " << chosen_padding;
×
182
   if(!user_specified_padding.empty())
1✔
183
      oss << " with user specified padding " << user_specified_padding;
1✔
184

185
   return oss.str();
2✔
186
}
1✔
187

188
}
189

190
/*
191
* Choose a signing format for the key
192
*/
193
std::unique_ptr<PK_Signer> X509_Object::choose_sig_format(const Private_Key& key,
366✔
194
                                                          RandomNumberGenerator& rng,
195
                                                          std::string_view hash_fn,
196
                                                          std::string_view user_specified_padding) {
197
   const Signature_Format format = key.default_x509_signature_format();
366✔
198

199
   if(!user_specified_padding.empty()) {
366✔
200
      try {
158✔
201
         auto pk_signer = std::make_unique<PK_Signer>(key, rng, user_specified_padding, format);
158✔
202
         if(!hash_fn.empty() && pk_signer->hash_function() != hash_fn) {
468✔
203
            throw Invalid_Argument(format_padding_error_message(
3✔
204
               key.algo_name(), pk_signer->hash_function(), hash_fn, "", user_specified_padding));
2✔
205
         }
206
         return pk_signer;
155✔
207
      } catch(Lookup_Error&) {}
159✔
208
   }
209

210
   const std::string padding = x509_signature_padding_for(key.algo_name(), hash_fn, user_specified_padding);
210✔
211

212
   try {
210✔
213
      auto pk_signer = std::make_unique<PK_Signer>(key, rng, padding, format);
210✔
214
      if(!hash_fn.empty() && pk_signer->hash_function() != hash_fn) {
574✔
215
         throw Invalid_Argument(format_padding_error_message(
×
216
            key.algo_name(), pk_signer->hash_function(), hash_fn, padding, user_specified_padding));
×
217
      }
218
      return pk_signer;
210✔
219
   } catch(Not_Implemented&) {
210✔
220
      throw Invalid_Argument("Signatures using " + key.algo_name() + "/" + padding + " are not supported");
×
221
   }
×
222
}
365✔
223

224
}
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