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

randombit / botan / 14081961251

26 Mar 2025 11:17AM UTC coverage: 91.535% (+0.009%) from 91.526%
14081961251

Pull #4788

github

web-flow
Merge c599720aa into ef188846f
Pull Request #4788: Faster X.509 extension lookup

95366 of 104185 relevant lines covered (91.54%)

11783612.77 hits per line

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

88.13
/src/lib/x509/x509_ext.cpp
1
/*
2
* X.509 Certificate Extensions
3
* (C) 1999-2010,2012 Jack Lloyd
4
* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
5
* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include <botan/x509_ext.h>
11

12
#include <botan/assert.h>
13
#include <botan/ber_dec.h>
14
#include <botan/der_enc.h>
15
#include <botan/hash.h>
16
#include <botan/x509cert.h>
17
#include <botan/internal/bit_ops.h>
18
#include <botan/internal/fmt.h>
19
#include <botan/internal/loadstor.h>
20
#include <algorithm>
21
#include <set>
22
#include <sstream>
23

24
namespace Botan {
25

26
namespace {
27

28
std::optional<uint32_t> is_sub_element_of(const OID& oid, std::initializer_list<uint32_t> prefix) {
72,216✔
29
   const auto& c = oid.get_components();
72,216✔
30

31
   if(c.size() != prefix.size() + 1) {
72,216✔
32
      return {};
6,188✔
33
   }
34

35
   if(!std::equal(c.begin(), c.end() - 1, prefix.begin(), prefix.end())) {
132,056✔
36
      return {};
1,548✔
37
   }
38

39
   return c[c.size() - 1];
64,480✔
40
}
41

42
template <std::derived_from<Certificate_Extension> T>
43
auto make_extension([[maybe_unused]] const OID& oid) {
63,050✔
44
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
63,050✔
45
   return std::make_unique<T>();
34,138✔
46
}
47

48
std::unique_ptr<Certificate_Extension> extension_from_oid(const OID& oid) {
67,358✔
49
   if(auto iso_ext = is_sub_element_of(oid, {2, 5, 29})) {
67,358✔
50
      // NOLINTNEXTLINE(*-switch-missing-default-case)
51
      switch(*iso_ext) {
63,760✔
52
         case 14:
16,273✔
53
            return make_extension<Cert_Extension::Subject_Key_ID>(oid);
16,273✔
54
         case 15:
11,076✔
55
            return make_extension<Cert_Extension::Key_Usage>(oid);
11,076✔
56
         case 17:
6,405✔
57
            return make_extension<Cert_Extension::Subject_Alternative_Name>(oid);
6,405✔
58
         case 18:
272✔
59
            return make_extension<Cert_Extension::Issuer_Alternative_Name>(oid);
272✔
60
         case 19:
16,640✔
61
            return make_extension<Cert_Extension::Basic_Constraints>(oid);
16,640✔
62
         case 20:
415✔
63
            return make_extension<Cert_Extension::CRL_Number>(oid);
415✔
64
         case 21:
781✔
65
            return make_extension<Cert_Extension::CRL_ReasonCode>(oid);
781✔
66
         case 28:
74✔
67
            return make_extension<Cert_Extension::CRL_Issuing_Distribution_Point>(oid);
74✔
68
         case 30:
423✔
69
            return make_extension<Cert_Extension::Name_Constraints>(oid);
423✔
70
         case 31:
1,414✔
71
            return make_extension<Cert_Extension::CRL_Distribution_Points>(oid);
1,414✔
72
         case 32:
1,810✔
73
            return make_extension<Cert_Extension::Certificate_Policies>(oid);
1,810✔
74
         case 35:
6,172✔
75
            return make_extension<Cert_Extension::Authority_Key_ID>(oid);
6,172✔
76
         case 37:
745✔
77
            return make_extension<Cert_Extension::Extended_Key_Usage>(oid);
745✔
78
      }
79
   }
80

81
   if(auto pkix_ext = is_sub_element_of(oid, {1, 3, 6, 1, 5, 5, 7, 1})) {
4,858✔
82
      // NOLINTNEXTLINE(*-switch-missing-default-case)
83
      switch(*pkix_ext) {
720✔
84
         case 1:
549✔
85
            return make_extension<Cert_Extension::Authority_Information_Access>(oid);
549✔
86
         case 26:
1✔
87
            return make_extension<Cert_Extension::TNAuthList>(oid);
1✔
88
      }
89
   }
90

91
   return nullptr;  // unknown
4,308✔
92
}
93

94
bool is_valid_telephone_number(const ASN1_String& tn) {
3✔
95
   //TelephoneNumber ::= IA5String (SIZE (1..15)) (FROM ("0123456789#*"))
96
   const std::string valid_tn_chars("0123456789#*");
3✔
97

98
   if(tn.empty() || (tn.size() > 15)) {
3✔
99
      return false;
100
   }
101

102
   if(tn.value().find_first_not_of(valid_tn_chars) != std::string::npos) {
3✔
103
      return false;
×
104
   }
105

106
   return true;
107
}
3✔
108

109
}  // namespace
110

111
/*
112
* Create a Certificate_Extension object of some kind to handle
113
*/
114
std::unique_ptr<Certificate_Extension> Extensions::create_extn_obj(const OID& oid,
67,358✔
115
                                                                   bool critical,
116
                                                                   const std::vector<uint8_t>& body) {
117
   auto extn = extension_from_oid(oid);
67,358✔
118

119
   if(!extn) {
67,358✔
120
      // some other unknown extension type
121
      extn = std::make_unique<Cert_Extension::Unknown_Extension>(oid, critical);
8,649✔
122
   }
123

124
   try {
67,358✔
125
      extn->decode_inner(body);
67,358✔
126
   } catch(Decoding_Error&) {
852✔
127
      extn = std::make_unique<Cert_Extension::Unknown_Extension>(oid, critical);
1,638✔
128
      extn->decode_inner(body);
819✔
129
   }
819✔
130
   return extn;
67,325✔
131
}
33✔
132

133
const Certificate_Extension& Extensions::Extensions_Info::obj() const {
80,851✔
134
   BOTAN_ASSERT_NONNULL(m_obj.get());
80,851✔
135
   return *m_obj;
80,851✔
136
}
137

138
/*
139
* Validate the extension (the default implementation is a NOP)
140
*/
141
void Certificate_Extension::validate(const X509_Certificate& /*unused*/,
14,591✔
142
                                     const X509_Certificate& /*unused*/,
143
                                     const std::vector<X509_Certificate>& /*unused*/,
144
                                     std::vector<std::set<Certificate_Status_Code>>& /*unused*/,
145
                                     size_t /*unused*/) {}
14,591✔
146

147
/*
148
* Add a new cert
149
*/
150
void Extensions::add(std::unique_ptr<Certificate_Extension> extn, bool critical) {
154✔
151
   // sanity check: we don't want to have the same extension more than once
152
   if(m_extension_info.contains(extn->oid_of())) {
308✔
153
      const std::string name = extn->oid_name();
1✔
154
      throw Invalid_Argument("Extension " + name + " already present in Extensions::add");
3✔
155
   }
1✔
156

157
   const OID oid = extn->oid_of();
153✔
158
   Extensions_Info info(critical, std::move(extn));
153✔
159
   m_extension_oids.push_back(oid);
153✔
160
   m_extension_info.emplace(oid, info);
153✔
161
}
154✔
162

163
bool Extensions::add_new(std::unique_ptr<Certificate_Extension> extn, bool critical) {
1,060✔
164
   if(m_extension_info.contains(extn->oid_of())) {
2,120✔
165
      return false;  // already exists
166
   }
167

168
   const OID oid = extn->oid_of();
1,059✔
169
   Extensions_Info info(critical, std::move(extn));
1,059✔
170
   m_extension_oids.push_back(oid);
1,059✔
171
   m_extension_info.emplace(oid, info);
1,059✔
172
   return true;
1,059✔
173
}
1,059✔
174

175
bool Extensions::remove(const OID& oid) {
1,442✔
176
   const bool erased = m_extension_info.erase(oid) > 0;
1,442✔
177

178
   if(erased) {
1,442✔
179
      m_extension_oids.erase(std::find(m_extension_oids.begin(), m_extension_oids.end(), oid));
350✔
180
   }
181

182
   return erased;
1,442✔
183
}
184

185
void Extensions::replace(std::unique_ptr<Certificate_Extension> extn, bool critical) {
1,440✔
186
   // Remove it if it existed
187
   remove(extn->oid_of());
1,440✔
188

189
   const OID oid = extn->oid_of();
1,440✔
190
   Extensions_Info info(critical, std::move(extn));
1,440✔
191
   m_extension_oids.push_back(oid);
1,440✔
192
   m_extension_info.emplace(oid, info);
1,440✔
193
}
1,440✔
194

195
bool Extensions::extension_set(const OID& oid) const {
18,611✔
196
   return (m_extension_info.find(oid) != m_extension_info.end());
18,611✔
197
}
198

199
bool Extensions::critical_extension_set(const OID& oid) const {
59✔
200
   auto i = m_extension_info.find(oid);
59✔
201
   if(i != m_extension_info.end()) {
59✔
202
      return i->second.is_critical();
57✔
203
   }
204
   return false;
205
}
206

207
std::vector<uint8_t> Extensions::get_extension_bits(const OID& oid) const {
4✔
208
   auto i = m_extension_info.find(oid);
4✔
209
   if(i == m_extension_info.end()) {
4✔
210
      throw Invalid_Argument("Extensions::get_extension_bits no such extension set");
1✔
211
   }
212

213
   return i->second.bits();
3✔
214
}
215

216
const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const {
208,077✔
217
   auto extn = m_extension_info.find(oid);
208,077✔
218
   if(extn == m_extension_info.end()) {
208,077✔
219
      return nullptr;
220
   }
221

222
   return &extn->second.obj();
60,772✔
223
}
224

225
std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const {
1,027✔
226
   if(const Certificate_Extension* ext = this->get_extension_object(oid)) {
1,027✔
227
      return ext->copy();
664✔
228
   }
229
   return nullptr;
363✔
230
}
231

232
std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> Extensions::extensions() const {
4,467✔
233
   std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> exts;
4,467✔
234
   exts.reserve(m_extension_info.size());
4,467✔
235
   for(auto&& ext : m_extension_info) {
21,826✔
236
      exts.push_back(std::make_pair(ext.second.obj().copy(), ext.second.is_critical()));
17,359✔
237
   }
238
   return exts;
4,467✔
239
}
×
240

241
std::map<OID, std::pair<std::vector<uint8_t>, bool>> Extensions::extensions_raw() const {
×
242
   std::map<OID, std::pair<std::vector<uint8_t>, bool>> out;
×
243
   for(auto&& ext : m_extension_info) {
×
244
      out.emplace(ext.first, std::make_pair(ext.second.bits(), ext.second.is_critical()));
×
245
   }
246
   return out;
×
247
}
×
248

249
/*
250
* Encode an Extensions list
251
*/
252
void Extensions::encode_into(DER_Encoder& to_object) const {
668✔
253
   for(const auto& ext_info : m_extension_info) {
3,364✔
254
      const OID& oid = ext_info.first;
2,696✔
255
      const bool should_encode = ext_info.second.obj().should_encode();
2,696✔
256

257
      if(should_encode) {
2,696✔
258
         const bool is_critical = ext_info.second.is_critical();
1,993✔
259
         const std::vector<uint8_t>& ext_value = ext_info.second.bits();
1,993✔
260

261
         to_object.start_sequence()
1,993✔
262
            .encode(oid)
1,993✔
263
            .encode_optional(is_critical, false)
2,580✔
264
            .encode(ext_value, ASN1_Type::OctetString)
1,993✔
265
            .end_cons();
1,993✔
266
      }
267
   }
268
}
668✔
269

270
/*
271
* Decode a list of Extensions
272
*/
273
void Extensions::decode_from(BER_Decoder& from_source) {
19,672✔
274
   m_extension_oids.clear();
19,672✔
275
   m_extension_info.clear();
19,672✔
276

277
   BER_Decoder sequence = from_source.start_sequence();
19,672✔
278

279
   while(sequence.more_items()) {
86,994✔
280
      OID oid;
68,119✔
281
      bool critical;
68,119✔
282
      std::vector<uint8_t> bits;
68,119✔
283

284
      sequence.start_sequence()
68,119✔
285
         .decode(oid)
67,880✔
286
         .decode_optional(critical, ASN1_Type::Boolean, ASN1_Class::Universal, false)
135,242✔
287
         .decode(bits, ASN1_Type::OctetString)
67,362✔
288
         .end_cons();
67,362✔
289

290
      auto obj = create_extn_obj(oid, critical, bits);
67,358✔
291
      Extensions_Info info(critical, bits, std::move(obj));
67,325✔
292

293
      m_extension_oids.push_back(oid);
67,325✔
294
      m_extension_info.emplace(oid, info);
67,325✔
295
   }
68,913✔
296
   sequence.verify_end();
18,875✔
297
}
19,669✔
298

299
namespace Cert_Extension {
300

301
/*
302
* Checked accessor for the path_limit member
303
*/
304
size_t Basic_Constraints::get_path_limit() const {
14,005✔
305
   if(!m_is_ca) {
14,005✔
306
      throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA");
×
307
   }
308
   return m_path_limit;
14,005✔
309
}
310

311
/*
312
* Encode the extension
313
*/
314
std::vector<uint8_t> Basic_Constraints::encode_inner() const {
556✔
315
   std::vector<uint8_t> output;
556✔
316
   DER_Encoder(output)
556✔
317
      .start_sequence()
556✔
318
      .encode_if(m_is_ca, DER_Encoder().encode(m_is_ca).encode_optional(m_path_limit, NO_CERT_PATH_LIMIT))
1,668✔
319
      .end_cons();
556✔
320
   return output;
556✔
321
}
×
322

323
/*
324
* Decode the extension
325
*/
326
void Basic_Constraints::decode_inner(const std::vector<uint8_t>& in) {
16,640✔
327
   BER_Decoder(in)
33,280✔
328
      .start_sequence()
49,893✔
329
      .decode_optional(m_is_ca, ASN1_Type::Boolean, ASN1_Class::Universal, false)
33,271✔
330
      .decode_optional(m_path_limit, ASN1_Type::Integer, ASN1_Class::Universal, NO_CERT_PATH_LIMIT)
16,633✔
331
      .end_cons();
16,624✔
332

333
   if(m_is_ca == false) {
16,617✔
334
      m_path_limit = 0;
2,514✔
335
   }
336
}
16,617✔
337

338
/*
339
* Encode the extension
340
*/
341
std::vector<uint8_t> Key_Usage::encode_inner() const {
286✔
342
   if(m_constraints.empty()) {
286✔
343
      throw Encoding_Error("Cannot encode empty PKIX key constraints");
×
344
   }
345

346
   const size_t constraint_bits = m_constraints.value();
286✔
347
   const size_t unused_bits = ctz(static_cast<uint32_t>(constraint_bits));
286✔
348

349
   std::vector<uint8_t> der;
286✔
350
   der.push_back(static_cast<uint8_t>(ASN1_Type::BitString));
286✔
351
   der.push_back(2 + ((unused_bits < 8) ? 1 : 0));
572✔
352
   der.push_back(unused_bits % 8);
286✔
353
   der.push_back((constraint_bits >> 8) & 0xFF);
286✔
354
   if(constraint_bits & 0xFF) {
286✔
355
      der.push_back(constraint_bits & 0xFF);
×
356
   }
357

358
   return der;
286✔
359
}
×
360

361
/*
362
* Decode the extension
363
*/
364
void Key_Usage::decode_inner(const std::vector<uint8_t>& in) {
11,076✔
365
   BER_Decoder ber(in);
11,076✔
366

367
   BER_Object obj = ber.get_next_object();
11,076✔
368

369
   obj.assert_is_a(ASN1_Type::BitString, ASN1_Class::Universal, "usage constraint");
11,078✔
370

371
   if(obj.length() == 2 || obj.length() == 3) {
11,068✔
372
      uint16_t usage = 0;
11,066✔
373

374
      const uint8_t* bits = obj.bits();
11,066✔
375

376
      if(bits[0] >= 8) {
11,066✔
377
         throw BER_Decoding_Error("Invalid unused bits in usage constraint");
4✔
378
      }
379

380
      const uint8_t mask = static_cast<uint8_t>(0xFF << bits[0]);
11,062✔
381

382
      if(obj.length() == 2) {
11,062✔
383
         usage = make_uint16(bits[1] & mask, 0);
10,880✔
384
      } else if(obj.length() == 3) {
182✔
385
         usage = make_uint16(bits[1], bits[2] & mask);
182✔
386
      }
387

388
      m_constraints = Key_Constraints(usage);
11,062✔
389
   } else {
390
      m_constraints = Key_Constraints(0);
2✔
391
   }
392
}
11,076✔
393

394
/*
395
* Encode the extension
396
*/
397
std::vector<uint8_t> Subject_Key_ID::encode_inner() const {
364✔
398
   std::vector<uint8_t> output;
364✔
399
   DER_Encoder(output).encode(m_key_id, ASN1_Type::OctetString);
364✔
400
   return output;
364✔
401
}
×
402

403
/*
404
* Decode the extension
405
*/
406
void Subject_Key_ID::decode_inner(const std::vector<uint8_t>& in) {
16,273✔
407
   BER_Decoder(in).decode(m_key_id, ASN1_Type::OctetString).verify_end();
16,273✔
408
}
16,257✔
409

410
/*
411
* Subject_Key_ID Constructor
412
*/
413
Subject_Key_ID::Subject_Key_ID(const std::vector<uint8_t>& pub_key, std::string_view hash_name) {
364✔
414
   auto hash = HashFunction::create_or_throw(hash_name);
364✔
415

416
   m_key_id.resize(hash->output_length());
364✔
417

418
   hash->update(pub_key);
364✔
419
   hash->final(m_key_id.data());
364✔
420

421
   // Truncate longer hashes, 192 bits here seems plenty
422
   const size_t max_skid_len = (192 / 8);
364✔
423
   if(m_key_id.size() > max_skid_len) {
364✔
424
      m_key_id.resize(max_skid_len);
364✔
425
   }
426
}
364✔
427

428
/*
429
* Encode the extension
430
*/
431
std::vector<uint8_t> Authority_Key_ID::encode_inner() const {
406✔
432
   std::vector<uint8_t> output;
406✔
433
   DER_Encoder(output)
812✔
434
      .start_sequence()
406✔
435
      .encode(m_key_id, ASN1_Type::OctetString, ASN1_Type(0), ASN1_Class::ContextSpecific)
406✔
436
      .end_cons();
406✔
437
   return output;
406✔
438
}
×
439

440
/*
441
* Decode the extension
442
*/
443
void Authority_Key_ID::decode_inner(const std::vector<uint8_t>& in) {
6,172✔
444
   BER_Decoder(in).start_sequence().decode_optional_string(m_key_id, ASN1_Type::OctetString, 0);
12,347✔
445
}
6,165✔
446

447
/*
448
* Encode the extension
449
*/
450
std::vector<uint8_t> Subject_Alternative_Name::encode_inner() const {
566✔
451
   std::vector<uint8_t> output;
566✔
452
   DER_Encoder(output).encode(m_alt_name);
566✔
453
   return output;
566✔
454
}
×
455

456
/*
457
* Encode the extension
458
*/
459
std::vector<uint8_t> Issuer_Alternative_Name::encode_inner() const {
×
460
   std::vector<uint8_t> output;
×
461
   DER_Encoder(output).encode(m_alt_name);
×
462
   return output;
×
463
}
×
464

465
/*
466
* Decode the extension
467
*/
468
void Subject_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) {
6,405✔
469
   BER_Decoder(in).decode(m_alt_name);
6,405✔
470
}
6,184✔
471

472
/*
473
* Decode the extension
474
*/
475
void Issuer_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) {
272✔
476
   BER_Decoder(in).decode(m_alt_name);
272✔
477
}
199✔
478

479
/*
480
* Encode the extension
481
*/
482
std::vector<uint8_t> Extended_Key_Usage::encode_inner() const {
376✔
483
   std::vector<uint8_t> output;
376✔
484
   DER_Encoder(output).start_sequence().encode_list(m_oids).end_cons();
776✔
485
   return output;
376✔
486
}
×
487

488
/*
489
* Decode the extension
490
*/
491
void Extended_Key_Usage::decode_inner(const std::vector<uint8_t>& in) {
745✔
492
   BER_Decoder(in).decode_list(m_oids);
745✔
493
}
679✔
494

495
/*
496
* Encode the extension
497
*/
498
std::vector<uint8_t> Name_Constraints::encode_inner() const {
×
499
   throw Not_Implemented("Name_Constraints encoding");
×
500
}
501

502
/*
503
* Decode the extension
504
*/
505
void Name_Constraints::decode_inner(const std::vector<uint8_t>& in) {
423✔
506
   BER_Decoder ber(in);
423✔
507
   BER_Decoder inner = ber.start_sequence();
423✔
508

509
   std::vector<GeneralSubtree> permitted;
418✔
510
   if(inner.decode_optional_list(permitted, ASN1_Type(0), ASN1_Class::ExplicitContextSpecific)) {
418✔
511
      if(permitted.empty()) {
142✔
512
         throw Decoding_Error("Empty NameConstraint permitted list");
2✔
513
      }
514
   }
515

516
   std::vector<GeneralSubtree> excluded;
384✔
517
   if(inner.decode_optional_list(excluded, ASN1_Type(1), ASN1_Class::ExplicitContextSpecific)) {
384✔
518
      if(excluded.empty()) {
217✔
519
         throw Decoding_Error("Empty NameConstraint excluded list");
×
520
      }
521
   }
522

523
   inner.end_cons();
363✔
524

525
   if(permitted.empty() && excluded.empty()) {
354✔
526
      throw Decoding_Error("Empty NameConstraint extension");
11✔
527
   }
528

529
   m_name_constraints = NameConstraints(std::move(permitted), std::move(excluded));
343✔
530
}
614✔
531

532
void Name_Constraints::validate(const X509_Certificate& subject,
54✔
533
                                const X509_Certificate& /*issuer*/,
534
                                const std::vector<X509_Certificate>& cert_path,
535
                                std::vector<std::set<Certificate_Status_Code>>& cert_status,
536
                                size_t pos) {
537
   if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty()) {
54✔
538
      if(!subject.is_CA_cert()) {
54✔
539
         cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR);
16✔
540
      }
541

542
      const bool issuer_name_constraint_critical = subject.is_critical("X509v3.NameConstraints");
54✔
543

544
      // Check that all subordinate certs pass the name constraint
545
      for(size_t j = 0; j < pos; ++j) {
104✔
546
         const auto& cert = cert_path.at(j);
50✔
547

548
         if(!m_name_constraints.is_permitted(cert, issuer_name_constraint_critical)) {
50✔
549
            cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR);
8✔
550
            continue;
8✔
551
         }
552

553
         if(m_name_constraints.is_excluded(cert, issuer_name_constraint_critical)) {
42✔
554
            cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR);
3✔
555
            continue;
3✔
556
         }
557
      }
558
   }
559
}
54✔
560

561
namespace {
562

563
/*
564
* A policy specifier
565
*/
566
class Policy_Information final : public ASN1_Object {
4,652✔
567
   public:
568
      Policy_Information() = default;
569

570
      explicit Policy_Information(const OID& oid) : m_oid(oid) {}
×
571

572
      const OID& oid() const { return m_oid; }
1,991✔
573

574
      void encode_into(DER_Encoder& codec) const override { codec.start_sequence().encode(m_oid).end_cons(); }
×
575

576
      void decode_from(BER_Decoder& codec) override {
2,112✔
577
         codec.start_sequence().decode(m_oid).discard_remaining().end_cons();
2,112✔
578
      }
2,052✔
579

580
   private:
581
      OID m_oid;
582
};
583

584
}  // namespace
585

586
/*
587
* Encode the extension
588
*/
589
std::vector<uint8_t> Certificate_Policies::encode_inner() const {
×
590
   std::vector<Policy_Information> policies;
×
591

592
   policies.reserve(m_oids.size());
×
593
   for(const auto& oid : m_oids) {
×
594
      policies.push_back(Policy_Information(oid));
×
595
   }
596

597
   std::vector<uint8_t> output;
×
598
   DER_Encoder(output).start_sequence().encode_list(policies).end_cons();
×
599
   return output;
×
600
}
×
601

602
/*
603
* Decode the extension
604
*/
605
void Certificate_Policies::decode_inner(const std::vector<uint8_t>& in) {
1,810✔
606
   std::vector<Policy_Information> policies;
1,810✔
607

608
   BER_Decoder(in).decode_list(policies);
1,810✔
609
   m_oids.clear();
1,748✔
610
   for(const auto& policy : policies) {
3,739✔
611
      m_oids.push_back(policy.oid());
1,991✔
612
   }
613
}
1,810✔
614

615
void Certificate_Policies::validate(const X509_Certificate& /*subject*/,
684✔
616
                                    const X509_Certificate& /*issuer*/,
617
                                    const std::vector<X509_Certificate>& /*cert_path*/,
618
                                    std::vector<std::set<Certificate_Status_Code>>& cert_status,
619
                                    size_t pos) {
620
   std::set<OID> oid_set(m_oids.begin(), m_oids.end());
684✔
621
   if(oid_set.size() != m_oids.size()) {
684✔
622
      cert_status.at(pos).insert(Certificate_Status_Code::DUPLICATE_CERT_POLICY);
16✔
623
   }
624
}
684✔
625

626
std::vector<uint8_t> Authority_Information_Access::encode_inner() const {
3✔
627
   std::vector<uint8_t> output;
3✔
628
   DER_Encoder der(output);
3✔
629

630
   der.start_sequence();
3✔
631
   // OCSP
632
   if(!m_ocsp_responder.empty()) {
3✔
633
      ASN1_String url(m_ocsp_responder, ASN1_Type::Ia5String);
2✔
634
      der.start_sequence()
2✔
635
         .encode(OID::from_string("PKIX.OCSP"))
4✔
636
         .add_object(ASN1_Type(6), ASN1_Class::ContextSpecific, url.value())
2✔
637
         .end_cons();
2✔
638
   }
2✔
639

640
   // CA Issuers
641
   for(const auto& ca_isser : m_ca_issuers) {
7✔
642
      ASN1_String asn1_ca_issuer(ca_isser, ASN1_Type::Ia5String);
4✔
643
      der.start_sequence()
4✔
644
         .encode(OID::from_string("PKIX.CertificateAuthorityIssuers"))
8✔
645
         .add_object(ASN1_Type(6), ASN1_Class::ContextSpecific, asn1_ca_issuer.value())
4✔
646
         .end_cons();
4✔
647
   }
4✔
648

649
   der.end_cons();
3✔
650
   return output;
3✔
651
}
3✔
652

653
void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in) {
549✔
654
   BER_Decoder ber = BER_Decoder(in).start_sequence();
1,098✔
655

656
   while(ber.more_items()) {
1,467✔
657
      OID oid;
959✔
658

659
      BER_Decoder info = ber.start_sequence();
959✔
660

661
      info.decode(oid);
941✔
662

663
      if(oid == OID::from_string("PKIX.OCSP")) {
925✔
664
         BER_Object name = info.get_next_object();
437✔
665

666
         if(name.is_a(6, ASN1_Class::ContextSpecific)) {
433✔
667
            m_ocsp_responder = ASN1::to_string(name);
338✔
668
         }
669
      }
433✔
670
      if(oid == OID::from_string("PKIX.CertificateAuthorityIssuers")) {
921✔
671
         BER_Object name = info.get_next_object();
439✔
672

673
         if(name.is_a(6, ASN1_Class::ContextSpecific)) {
438✔
674
            m_ca_issuers.push_back(ASN1::to_string(name));
868✔
675
         }
676
      }
438✔
677
   }
980✔
678
}
547✔
679

680
/*
681
* Checked accessor for the crl_number member
682
*/
683
size_t CRL_Number::get_crl_number() const {
261✔
684
   if(!m_has_value) {
261✔
685
      throw Invalid_State("CRL_Number::get_crl_number: Not set");
×
686
   }
687
   return m_crl_number;
261✔
688
}
689

690
/*
691
* Copy a CRL_Number extension
692
*/
693
std::unique_ptr<Certificate_Extension> CRL_Number::copy() const {
770✔
694
   if(!m_has_value) {
770✔
695
      throw Invalid_State("CRL_Number::copy: Not set");
×
696
   }
697
   return std::make_unique<CRL_Number>(m_crl_number);
770✔
698
}
699

700
/*
701
* Encode the extension
702
*/
703
std::vector<uint8_t> CRL_Number::encode_inner() const {
42✔
704
   std::vector<uint8_t> output;
42✔
705
   DER_Encoder(output).encode(m_crl_number);
42✔
706
   return output;
42✔
707
}
×
708

709
/*
710
* Decode the extension
711
*/
712
void CRL_Number::decode_inner(const std::vector<uint8_t>& in) {
415✔
713
   BER_Decoder(in).decode(m_crl_number);
415✔
714
   m_has_value = true;
401✔
715
}
401✔
716

717
/*
718
* Encode the extension
719
*/
720
std::vector<uint8_t> CRL_ReasonCode::encode_inner() const {
29✔
721
   std::vector<uint8_t> output;
29✔
722
   DER_Encoder(output).encode(static_cast<size_t>(m_reason), ASN1_Type::Enumerated, ASN1_Class::Universal);
29✔
723
   return output;
29✔
724
}
×
725

726
/*
727
* Decode the extension
728
*/
729
void CRL_ReasonCode::decode_inner(const std::vector<uint8_t>& in) {
781✔
730
   size_t reason_code = 0;
781✔
731
   BER_Decoder(in).decode(reason_code, ASN1_Type::Enumerated, ASN1_Class::Universal);
781✔
732
   m_reason = static_cast<CRL_Code>(reason_code);
774✔
733
}
774✔
734

735
std::vector<uint8_t> CRL_Distribution_Points::encode_inner() const {
12✔
736
   std::vector<uint8_t> output;
12✔
737
   DER_Encoder(output).start_sequence().encode_list(m_distribution_points).end_cons();
48✔
738
   return output;
12✔
739
}
×
740

741
void CRL_Distribution_Points::decode_inner(const std::vector<uint8_t>& buf) {
1,414✔
742
   BER_Decoder(buf).decode_list(m_distribution_points).verify_end();
1,414✔
743

744
   std::stringstream ss;
1,236✔
745

746
   for(const auto& distribution_point : m_distribution_points) {
2,927✔
747
      auto contents = distribution_point.point().contents();
1,691✔
748

749
      for(const auto& pair : contents) {
3,775✔
750
         ss << pair.first << ": " << pair.second << " ";
2,084✔
751
      }
752
   }
1,691✔
753

754
   m_crl_distribution_urls.push_back(ss.str());
1,236✔
755
}
1,236✔
756

757
void CRL_Distribution_Points::Distribution_Point::encode_into(DER_Encoder& der) const {
24✔
758
   const auto uris = m_point.uris();
24✔
759

760
   if(uris.empty()) {
24✔
761
      throw Not_Implemented("Empty CRL_Distribution_Point encoding not implemented");
×
762
   }
763

764
   for(const auto& uri : uris) {
48✔
765
      der.start_sequence()
24✔
766
         .start_cons(ASN1_Type(0), ASN1_Class::ContextSpecific)
24✔
767
         .start_cons(ASN1_Type(0), ASN1_Class::ContextSpecific)
24✔
768
         .add_object(ASN1_Type(6), ASN1_Class::ContextSpecific, uri)
24✔
769
         .end_cons()
24✔
770
         .end_cons()
24✔
771
         .end_cons();
24✔
772
   }
773
}
24✔
774

775
void CRL_Distribution_Points::Distribution_Point::decode_from(BER_Decoder& ber) {
1,986✔
776
   ber.start_sequence()
3,905✔
777
      .start_context_specific(0)
1,919✔
778
      .decode_optional_implicit(m_point,
3,857✔
779
                                ASN1_Type(0),
780
                                ASN1_Class::ContextSpecific | ASN1_Class::Constructed,
781
                                ASN1_Type::Sequence,
782
                                ASN1_Class::Constructed)
783
      .end_cons()
1,781✔
784
      .end_cons();
1,774✔
785
}
1,762✔
786

787
std::vector<uint8_t> CRL_Issuing_Distribution_Point::encode_inner() const {
×
788
   throw Not_Implemented("CRL_Issuing_Distribution_Point encoding");
×
789
}
790

791
void CRL_Issuing_Distribution_Point::decode_inner(const std::vector<uint8_t>& buf) {
74✔
792
   BER_Decoder(buf).decode(m_distribution_point).verify_end();
74✔
793
}
22✔
794

795
void TNAuthList::Entry::encode_into(DER_Encoder&) const {
×
796
   throw Not_Implemented("TNAuthList extension entry serialization is not supported");
×
797
}
798

799
void TNAuthList::Entry::decode_from(class BER_Decoder& ber) {
3✔
800
   BER_Object obj = ber.get_next_object();
3✔
801

802
   const uint32_t type_tag = static_cast<Type>(obj.type_tag());
3✔
803

804
   if(type_tag == ServiceProviderCode) {
3✔
805
      m_type = ServiceProviderCode;
1✔
806
      ASN1_String spc_string;
1✔
807
      BER_Decoder(obj).decode(spc_string);
1✔
808
      m_data = std::move(spc_string);
1✔
809
   } else if(type_tag == TelephoneNumberRange) {
3✔
810
      m_type = TelephoneNumberRange;
1✔
811
      m_data = RangeContainer();
1✔
812
      auto& range_items = std::get<RangeContainer>(m_data);
1✔
813
      BER_Decoder list = BER_Decoder(obj).start_sequence();
1✔
814
      while(list.more_items()) {
3✔
815
         TelephoneNumberRangeData entry;
2✔
816

817
         list.decode(entry.start);
2✔
818
         if(!is_valid_telephone_number(entry.start)) {
2✔
819
            throw Decoding_Error(fmt("Invalid TelephoneNumberRange start {}", entry.start.value()));
×
820
         }
821

822
         list.decode(entry.count);
2✔
823
         if(entry.count < 2) {
2✔
824
            throw Decoding_Error(fmt("Invalid TelephoneNumberRange count {}", entry.count));
×
825
         }
826

827
         range_items.emplace_back(std::move(entry));
2✔
828
      }
2✔
829
      list.end_cons();
1✔
830

831
      if(range_items.empty()) {
1✔
832
         throw Decoding_Error("TelephoneNumberRange is empty");
×
833
      }
834
   } else if(type_tag == TelephoneNumber) {
2✔
835
      m_type = TelephoneNumber;
1✔
836
      ASN1_String one_string;
1✔
837
      BER_Decoder(obj).decode(one_string);
1✔
838
      if(!is_valid_telephone_number(one_string)) {
1✔
839
         throw Decoding_Error(fmt("Invalid TelephoneNumber {}", one_string.value()));
×
840
      }
841
      m_data = std::move(one_string);
1✔
842
   } else {
1✔
843
      throw Decoding_Error(fmt("Unexpected TNEntry type code {}", type_tag));
×
844
   };
3✔
845
}
3✔
846

847
std::vector<uint8_t> TNAuthList::encode_inner() const {
×
848
   throw Not_Implemented("TNAuthList extension serialization is not supported");
×
849
}
850

851
void TNAuthList::decode_inner(const std::vector<uint8_t>& in) {
1✔
852
   BER_Decoder(in).decode_list(m_tn_entries).verify_end();
1✔
853
   if(m_tn_entries.empty()) {
1✔
854
      throw Decoding_Error("TNAuthorizationList is empty");
×
855
   }
856
}
1✔
857

858
const std::string& TNAuthList::Entry::service_provider_code() const {
2✔
859
   BOTAN_STATE_CHECK(type() == Type::ServiceProviderCode);
2✔
860
   return std::get<ASN1_String>(m_data).value();
1✔
861
}
862

863
const TNAuthList::Entry::RangeContainer& TNAuthList::Entry::telephone_number_range() const {
2✔
864
   BOTAN_STATE_CHECK(type() == Type::TelephoneNumberRange);
2✔
865
   return std::get<RangeContainer>(m_data);
1✔
866
}
867

868
const std::string& TNAuthList::Entry::telephone_number() const {
2✔
869
   BOTAN_STATE_CHECK(type() == Type::TelephoneNumber);
2✔
870
   return std::get<ASN1_String>(m_data).value();
1✔
871
}
872

873
void OCSP_NoCheck::decode_inner(const std::vector<uint8_t>& buf) {
×
874
   BER_Decoder(buf).verify_end();
×
875
}
×
876

877
std::vector<uint8_t> Unknown_Extension::encode_inner() const {
×
878
   return m_bytes;
×
879
}
880

881
void Unknown_Extension::decode_inner(const std::vector<uint8_t>& bytes) {
5,127✔
882
   // Just treat as an opaque blob at this level
883
   m_bytes = bytes;
5,127✔
884
}
5,127✔
885

886
}  // namespace Cert_Extension
887

888
}  // 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