Coverage Report

Created: 2026-09-14 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/x509/x509_ext.cpp
Line
Count
Source
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
* (C) 2024 Anton Einax, Dominik Schricker
7
*
8
* Botan is released under the Simplified BSD License (see license.txt)
9
*/
10
11
#include <botan/x509_ext.h>
12
13
#include <botan/assert.h>
14
#include <botan/ber_dec.h>
15
#include <botan/der_enc.h>
16
#include <botan/hash.h>
17
#include <botan/pk_keys.h>
18
#include <botan/x509cert.h>
19
#include <botan/internal/fmt.h>
20
#include <botan/internal/int_utils.h>
21
#include <botan/internal/loadstor.h>
22
#include <botan/internal/x509_utils.h>
23
#include <algorithm>
24
#include <set>
25
#include <span>
26
27
namespace Botan {
28
29
namespace {
30
31
constexpr size_t MaximumKeyIdentifierLength = 64;
32
33
/*
34
* Encode an AlternativeName as `GeneralNames` but with an outer IMPLICIT
35
* context-specific tag rather than the universal SEQUENCE tag. Used for
36
* fullName [0] / cRLIssuer [2] / similar.
37
*/
38
0
void emit_general_names_implicit(DER_Encoder& der, const AlternativeName& names, uint32_t tag) {
39
   // RFC 5280 4.2.1.6: GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
40
0
   if(!names.has_items()) {
41
0
      throw Encoding_Error("Cannot encode empty GeneralNames");
42
0
   }
43
0
   if(std::ranges::any_of(names.directory_names(), [](const X509_DN& dn) { return dn.empty(); })) {
44
0
      throw Encoding_Error("GeneralNames must not contain an empty directoryName");
45
0
   }
46
0
   der.encode_implicit(names, ASN1_Type(tag));
47
0
}
48
49
template <std::derived_from<Certificate_Extension> T>
50
57.1k
auto make_extension([[maybe_unused]] const OID& oid) {
51
57.1k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
57.1k
   return std::make_unique<T>();
53
57.1k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension14Subject_Key_IDEEEDaRKNS_3OIDE
Line
Count
Source
50
8.80k
auto make_extension([[maybe_unused]] const OID& oid) {
51
8.80k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
8.80k
   return std::make_unique<T>();
53
8.80k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension9Key_UsageEEEDaRKNS_3OIDE
Line
Count
Source
50
3.85k
auto make_extension([[maybe_unused]] const OID& oid) {
51
3.85k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
3.85k
   return std::make_unique<T>();
53
3.85k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension24Subject_Alternative_NameEEEDaRKNS_3OIDE
Line
Count
Source
50
8.22k
auto make_extension([[maybe_unused]] const OID& oid) {
51
8.22k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
8.22k
   return std::make_unique<T>();
53
8.22k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension23Issuer_Alternative_NameEEEDaRKNS_3OIDE
Line
Count
Source
50
2.71k
auto make_extension([[maybe_unused]] const OID& oid) {
51
2.71k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
2.71k
   return std::make_unique<T>();
53
2.71k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension17Basic_ConstraintsEEEDaRKNS_3OIDE
Line
Count
Source
50
10.2k
auto make_extension([[maybe_unused]] const OID& oid) {
51
10.2k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
10.2k
   return std::make_unique<T>();
53
10.2k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension10CRL_NumberEEEDaRKNS_3OIDE
Line
Count
Source
50
51
auto make_extension([[maybe_unused]] const OID& oid) {
51
51
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
51
   return std::make_unique<T>();
53
51
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension14CRL_ReasonCodeEEEDaRKNS_3OIDE
Line
Count
Source
50
3.91k
auto make_extension([[maybe_unused]] const OID& oid) {
51
3.91k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
3.91k
   return std::make_unique<T>();
53
3.91k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension30CRL_Issuing_Distribution_PointEEEDaRKNS_3OIDE
Line
Count
Source
50
188
auto make_extension([[maybe_unused]] const OID& oid) {
51
188
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
188
   return std::make_unique<T>();
53
188
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension16Name_ConstraintsEEEDaRKNS_3OIDE
Line
Count
Source
50
690
auto make_extension([[maybe_unused]] const OID& oid) {
51
690
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
690
   return std::make_unique<T>();
53
690
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension23CRL_Distribution_PointsEEEDaRKNS_3OIDE
Line
Count
Source
50
1.55k
auto make_extension([[maybe_unused]] const OID& oid) {
51
1.55k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
1.55k
   return std::make_unique<T>();
53
1.55k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension20Certificate_PoliciesEEEDaRKNS_3OIDE
Line
Count
Source
50
846
auto make_extension([[maybe_unused]] const OID& oid) {
51
846
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
846
   return std::make_unique<T>();
53
846
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension16Authority_Key_IDEEEDaRKNS_3OIDE
Line
Count
Source
50
8.96k
auto make_extension([[maybe_unused]] const OID& oid) {
51
8.96k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
8.96k
   return std::make_unique<T>();
53
8.96k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension18Extended_Key_UsageEEEDaRKNS_3OIDE
Line
Count
Source
50
1.76k
auto make_extension([[maybe_unused]] const OID& oid) {
51
1.76k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
1.76k
   return std::make_unique<T>();
53
1.76k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension21NoRevocationAvailableEEEDaRKNS_3OIDE
Line
Count
Source
50
57
auto make_extension([[maybe_unused]] const OID& oid) {
51
57
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
57
   return std::make_unique<T>();
53
57
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension28Authority_Information_AccessEEEDaRKNS_3OIDE
Line
Count
Source
50
1.75k
auto make_extension([[maybe_unused]] const OID& oid) {
51
1.75k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
1.75k
   return std::make_unique<T>();
53
1.75k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension15IPAddressBlocksEEEDaRKNS_3OIDE
Line
Count
Source
50
1.28k
auto make_extension([[maybe_unused]] const OID& oid) {
51
1.28k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
1.28k
   return std::make_unique<T>();
53
1.28k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension8ASBlocksEEEDaRKNS_3OIDE
Line
Count
Source
50
2.03k
auto make_extension([[maybe_unused]] const OID& oid) {
51
2.03k
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
2.03k
   return std::make_unique<T>();
53
2.03k
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension10TNAuthListEEEDaRKNS_3OIDE
Line
Count
Source
50
218
auto make_extension([[maybe_unused]] const OID& oid) {
51
218
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
218
   return std::make_unique<T>();
53
218
}
x509_ext.cpp:_ZN5Botan12_GLOBAL__N_114make_extensionITkNSt3__112derived_fromINS_21Certificate_ExtensionEEENS_14Cert_Extension12OCSP_NoCheckEEEDaRKNS_3OIDE
Line
Count
Source
50
6
auto make_extension([[maybe_unused]] const OID& oid) {
51
6
   BOTAN_DEBUG_ASSERT(oid == T::static_oid());
52
6
   return std::make_unique<T>();
53
6
}
54
55
82.8k
std::unique_ptr<Certificate_Extension> extension_from_oid(const OID& oid) {
56
82.8k
   if(auto iso_ext = is_sub_element_of(oid, {2, 5, 29})) {
57
      // NOLINTNEXTLINE(*-switch-missing-default-case)
58
61.4k
      switch(*iso_ext) {
59
8.80k
         case 14:
60
8.80k
            return make_extension<Cert_Extension::Subject_Key_ID>(oid);
61
3.85k
         case 15:
62
3.85k
            return make_extension<Cert_Extension::Key_Usage>(oid);
63
8.22k
         case 17:
64
8.22k
            return make_extension<Cert_Extension::Subject_Alternative_Name>(oid);
65
2.71k
         case 18:
66
2.71k
            return make_extension<Cert_Extension::Issuer_Alternative_Name>(oid);
67
10.2k
         case 19:
68
10.2k
            return make_extension<Cert_Extension::Basic_Constraints>(oid);
69
51
         case 20:
70
51
            return make_extension<Cert_Extension::CRL_Number>(oid);
71
3.91k
         case 21:
72
3.91k
            return make_extension<Cert_Extension::CRL_ReasonCode>(oid);
73
188
         case 28:
74
188
            return make_extension<Cert_Extension::CRL_Issuing_Distribution_Point>(oid);
75
690
         case 30:
76
690
            return make_extension<Cert_Extension::Name_Constraints>(oid);
77
1.55k
         case 31:
78
1.55k
            return make_extension<Cert_Extension::CRL_Distribution_Points>(oid);
79
846
         case 32:
80
846
            return make_extension<Cert_Extension::Certificate_Policies>(oid);
81
8.96k
         case 35:
82
8.96k
            return make_extension<Cert_Extension::Authority_Key_ID>(oid);
83
1.76k
         case 37:
84
1.76k
            return make_extension<Cert_Extension::Extended_Key_Usage>(oid);
85
57
         case 56:
86
57
            return make_extension<Cert_Extension::NoRevocationAvailable>(oid);
87
61.4k
      }
88
61.4k
   }
89
90
30.9k
   if(auto pkix_ext = is_sub_element_of(oid, {1, 3, 6, 1, 5, 5, 7, 1})) {
91
      // NOLINTNEXTLINE(*-switch-missing-default-case)
92
5.62k
      switch(*pkix_ext) {
93
1.75k
         case 1:
94
1.75k
            return make_extension<Cert_Extension::Authority_Information_Access>(oid);
95
1.28k
         case 7:
96
1.28k
            return make_extension<Cert_Extension::IPAddressBlocks>(oid);
97
2.03k
         case 8:
98
2.03k
            return make_extension<Cert_Extension::ASBlocks>(oid);
99
218
         case 26:
100
218
            return make_extension<Cert_Extension::TNAuthList>(oid);
101
5.62k
      }
102
5.62k
   }
103
104
25.6k
   if(oid == Cert_Extension::OCSP_NoCheck::static_oid()) {
105
6
      return make_extension<Cert_Extension::OCSP_NoCheck>(oid);
106
6
   }
107
108
25.6k
   return nullptr;  // unknown
109
25.6k
}
110
111
118
bool is_valid_telephone_number(const ASN1_String& tn) {
112
   //TelephoneNumber ::= IA5String (SIZE (1..15)) (FROM ("0123456789#*"))
113
118
   const std::string valid_tn_chars("0123456789#*");
114
115
118
   if(tn.empty() || (tn.size() > 15)) {
116
23
      return false;
117
23
   }
118
119
95
   if(tn.value().find_first_not_of(valid_tn_chars) != std::string::npos) {
120
18
      return false;
121
18
   }
122
123
77
   return true;
124
95
}
125
126
}  // namespace
127
128
0
std::vector<OID> Extensions::critical_extensions() const {
129
0
   std::vector<OID> crit;
130
131
0
   for(const auto& oid : m_extension_oids) {
132
0
      auto ext_info = m_extension_info.find(oid);
133
0
      BOTAN_ASSERT_NOMSG(ext_info != m_extension_info.end());
134
0
      if(ext_info->second.is_critical()) {
135
0
         crit.push_back(oid);
136
0
      }
137
0
   }
138
139
0
   return crit;
140
0
}
141
142
/*
143
* Create a Certificate_Extension object of some kind to handle
144
*/
145
std::unique_ptr<Certificate_Extension> Extensions::create_extn_obj(const OID& oid,
146
                                                                   bool critical,
147
                                                                   const std::vector<uint8_t>& body,
148
82.8k
                                                                   std::optional<Extension_Context> context) {
149
82.8k
   auto extn = extension_from_oid(oid);
150
151
82.8k
   if(!extn) {
152
      // some other unknown extension type
153
25.6k
      extn = std::make_unique<Cert_Extension::Unknown_Extension>(oid, critical);
154
57.1k
   } else {
155
57.1k
      if(context.has_value() && !extn->is_appropriate_context(*context)) {
156
30
         throw Decoding_Error(fmt("Extension {} is not allowed in this context", extn->oid_name()));
157
30
      }
158
159
57.1k
      try {
160
57.1k
         extn->decode_inner(body);
161
57.1k
         return extn;
162
57.1k
      } catch(const Exception&) {
163
         // OID was recognized but contents failed to decode
164
20.8k
         extn = std::make_unique<Cert_Extension::Unknown_Extension>(oid, critical, /*failed_to_decode=*/true);
165
20.8k
      }
166
57.1k
   }
167
168
   // This is always Unknown_Extension:
169
46.5k
   extn->decode_inner(body);
170
46.5k
   return extn;
171
82.8k
}
172
173
43.4k
const Certificate_Extension& Extensions::Extensions_Info::obj() const {
174
43.4k
   BOTAN_ASSERT_NONNULL(m_obj.get());
175
43.4k
   return *m_obj;
176
43.4k
}
177
178
/*
179
* Validate the extension (the default implementation is a NOP)
180
*/
181
void Certificate_Extension::validate(const X509_Certificate& /*unused*/,
182
                                     const std::optional<X509_Certificate>& /*unused*/,
183
                                     const std::vector<X509_Certificate>& /*unused*/,
184
                                     std::vector<std::set<Certificate_Status_Code>>& /*unused*/,
185
7
                                     size_t /*unused*/) const {}
186
187
/*
188
* Add a new cert
189
*/
190
0
void Extensions::add(std::unique_ptr<Certificate_Extension> extn, bool critical) {
191
   // sanity check: we don't want to have the same extension more than once
192
0
   if(m_extension_info.contains(extn->oid_of())) {
193
0
      const std::string name = extn->oid_name();
194
0
      throw Invalid_Argument("Extension " + name + " already present in Extensions::add");
195
0
   }
196
197
0
   const OID oid = extn->oid_of();
198
0
   Extensions_Info info(critical, std::move(extn));
199
0
   m_extension_oids.push_back(oid);
200
0
   m_extension_info.emplace(oid, info);
201
0
}
202
203
0
bool Extensions::add_new(std::unique_ptr<Certificate_Extension> extn, bool critical) {
204
0
   if(m_extension_info.contains(extn->oid_of())) {
205
0
      return false;  // already exists
206
0
   }
207
208
0
   const OID oid = extn->oid_of();
209
0
   Extensions_Info info(critical, std::move(extn));
210
0
   m_extension_oids.push_back(oid);
211
0
   m_extension_info.emplace(oid, info);
212
0
   return true;
213
0
}
214
215
0
bool Extensions::remove(const OID& oid) {
216
0
   const bool erased = m_extension_info.erase(oid) > 0;
217
218
0
   if(erased) {
219
0
      m_extension_oids.erase(std::find(m_extension_oids.begin(), m_extension_oids.end(), oid));
220
0
   }
221
222
0
   return erased;
223
0
}
224
225
0
void Extensions::replace(std::unique_ptr<Certificate_Extension> extn, bool critical) {
226
   // Remove it if it existed
227
0
   remove(extn->oid_of());
228
229
0
   const OID oid = extn->oid_of();
230
0
   Extensions_Info info(critical, std::move(extn));
231
0
   m_extension_oids.push_back(oid);
232
0
   m_extension_info.emplace(oid, info);
233
0
}
234
235
54.3k
bool Extensions::extension_set(const OID& oid) const {
236
54.3k
   return m_extension_info.contains(oid);
237
54.3k
}
238
239
0
bool Extensions::critical_extension_set(const OID& oid) const {
240
0
   auto i = m_extension_info.find(oid);
241
0
   if(i != m_extension_info.end()) {
242
0
      return i->second.is_critical();
243
0
   }
244
0
   return false;
245
0
}
246
247
0
std::vector<uint8_t> Extensions::get_extension_bits(const OID& oid) const {
248
0
   auto i = m_extension_info.find(oid);
249
0
   if(i == m_extension_info.end()) {
250
0
      throw Invalid_Argument("Extensions::get_extension_bits no such extension set");
251
0
   }
252
253
0
   return i->second.bits();
254
0
}
255
256
206k
const Certificate_Extension* Extensions::get_extension_object(const OID& oid) const {
257
206k
   auto extn = m_extension_info.find(oid);
258
206k
   if(extn == m_extension_info.end()) {
259
163k
      return nullptr;
260
163k
   }
261
262
43.4k
   return &extn->second.obj();
263
206k
}
264
265
0
std::unique_ptr<Certificate_Extension> Extensions::get(const OID& oid) const {
266
0
   if(const Certificate_Extension* ext = this->get_extension_object(oid)) {
267
0
      return ext->copy();
268
0
   }
269
0
   return nullptr;
270
0
}
271
272
0
std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> Extensions::extensions() const {
273
0
   std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> exts;
274
0
   exts.reserve(m_extension_info.size());
275
0
   for(auto&& ext : m_extension_info) {
276
0
      exts.push_back(std::make_pair(ext.second.obj().copy(), ext.second.is_critical()));
277
0
   }
278
0
   return exts;
279
0
}
280
281
void Extensions::validate(const X509_Certificate& subject,
282
                          const std::optional<X509_Certificate>& issuer,
283
                          const std::vector<X509_Certificate>& cert_path,
284
                          std::vector<std::set<Certificate_Status_Code>>& cert_status,
285
3
                          size_t pos) const {
286
10
   for(const auto& ext : m_extension_info) {
287
10
      ext.second.obj().validate(subject, issuer, cert_path, cert_status, pos);
288
10
   }
289
3
}
290
291
0
std::map<OID, std::pair<std::vector<uint8_t>, bool>> Extensions::extensions_raw() const {
292
0
   std::map<OID, std::pair<std::vector<uint8_t>, bool>> out;
293
0
   for(auto&& ext : m_extension_info) {
294
0
      out.emplace(ext.first, std::make_pair(ext.second.bits(), ext.second.is_critical()));
295
0
   }
296
0
   return out;
297
0
}
298
299
/*
300
* Encode an Extensions list
301
*/
302
0
void Extensions::encode_into(DER_Encoder& to_object) const {
303
0
   for(const auto& [oid, extn] : m_extension_info) {
304
0
      const bool should_encode = extn.obj().should_encode();
305
306
0
      if(should_encode) {
307
0
         const auto is_critical = extn.is_critical() ? std::optional<bool>{true} : std::nullopt;
308
0
         const std::vector<uint8_t>& ext_value = extn.bits();
309
310
0
         to_object.start_sequence()
311
0
            .encode(oid)
312
0
            .encode_optional(is_critical)
313
0
            .encode(ext_value, ASN1_Type::OctetString)
314
0
            .end_cons();
315
0
      }
316
0
   }
317
0
}
318
319
/*
320
* Decode a list of Extensions
321
*/
322
0
void Extensions::decode_from(BER_Decoder& from_source) {
323
0
   decode_from(from_source, std::nullopt);
324
0
}
325
326
25.9k
void Extensions::decode_from(BER_Decoder& from_source, std::optional<Extension_Context> context) {
327
25.9k
   m_extension_oids.clear();
328
25.9k
   m_extension_info.clear();
329
25.9k
   m_has_unknown_critical_extension = false;
330
331
25.9k
   BER_Decoder sequence = from_source.start_sequence();
332
333
108k
   while(sequence.more_items()) {
334
85.0k
      OID oid;
335
85.0k
      bool critical = false;
336
85.0k
      std::vector<uint8_t> bits;
337
338
85.0k
      sequence.start_sequence()
339
85.0k
         .decode(oid)
340
85.0k
         .decode_optional(critical, ASN1_Type::Boolean, ASN1_Class::Universal, false)
341
85.0k
         .decode(bits, ASN1_Type::OctetString)
342
85.0k
         .end_cons();
343
344
85.0k
      auto obj = create_extn_obj(oid, critical, bits, context);
345
      // Unknown_Extension is the only Certificate_Extension with an empty oid_name
346
85.0k
      if(critical && obj->oid_name().empty()) {
347
4.73k
         m_has_unknown_critical_extension = true;
348
4.73k
      }
349
85.0k
      Extensions_Info info(critical, std::move(bits), std::move(obj));
350
351
85.0k
      m_extension_oids.push_back(oid);
352
353
      // RFC 5280 4.2: "A certificate MUST NOT include more than one
354
      // instance of a particular extension."
355
85.0k
      if(!m_extension_info.emplace(std::move(oid), std::move(info)).second) {
356
2.54k
         throw Decoding_Error("Duplicate certificate extension encountered");
357
2.54k
      }
358
85.0k
   }
359
23.4k
   sequence.verify_end();
360
23.4k
}
361
362
namespace Cert_Extension {
363
364
10.2k
bool Basic_Constraints::is_appropriate_context(Extension_Context context) const {
365
10.2k
   return context == Extension_Context::Certificate;
366
10.2k
}
367
368
3.85k
bool Key_Usage::is_appropriate_context(Extension_Context context) const {
369
3.85k
   return context == Extension_Context::Certificate;
370
3.85k
}
371
372
8.80k
bool Subject_Key_ID::is_appropriate_context(Extension_Context context) const {
373
8.80k
   return context == Extension_Context::Certificate;
374
8.80k
}
375
376
8.96k
bool Authority_Key_ID::is_appropriate_context(Extension_Context context) const {
377
8.96k
   return context == Extension_Context::Certificate || context == Extension_Context::CRL;
378
8.96k
}
379
380
8.22k
bool Subject_Alternative_Name::is_appropriate_context(Extension_Context context) const {
381
8.22k
   return context == Extension_Context::Certificate;
382
8.22k
}
383
384
2.71k
bool Issuer_Alternative_Name::is_appropriate_context(Extension_Context context) const {
385
2.71k
   return context == Extension_Context::Certificate || context == Extension_Context::CRL;
386
2.71k
}
387
388
1.76k
bool Extended_Key_Usage::is_appropriate_context(Extension_Context context) const {
389
1.76k
   return context == Extension_Context::Certificate;
390
1.76k
}
391
392
690
bool Name_Constraints::is_appropriate_context(Extension_Context context) const {
393
690
   return context == Extension_Context::Certificate;
394
690
}
395
396
846
bool Certificate_Policies::is_appropriate_context(Extension_Context context) const {
397
846
   return context == Extension_Context::Certificate;
398
846
}
399
400
1.75k
bool Authority_Information_Access::is_appropriate_context(Extension_Context context) const {
401
1.75k
   return context == Extension_Context::Certificate || context == Extension_Context::CRL;
402
1.75k
}
403
404
51
bool CRL_Number::is_appropriate_context(Extension_Context context) const {
405
51
   return context == Extension_Context::CRL;
406
51
}
407
408
3.91k
bool CRL_ReasonCode::is_appropriate_context(Extension_Context context) const {
409
   // RFC 6960 4.4.5: "All the extensions specified as CRL entry extensions
410
   // -- in Section 5.3 of [RFC5280] -- are also supported as singleExtensions."
411
3.91k
   return context == Extension_Context::CRL_Entry || context == Extension_Context::OCSP_Response;
412
3.91k
}
413
414
1.55k
bool CRL_Distribution_Points::is_appropriate_context(Extension_Context context) const {
415
1.55k
   return context == Extension_Context::Certificate;
416
1.55k
}
417
418
188
bool CRL_Issuing_Distribution_Point::is_appropriate_context(Extension_Context context) const {
419
188
   return context == Extension_Context::CRL;
420
188
}
421
422
6
bool OCSP_NoCheck::is_appropriate_context(Extension_Context context) const {
423
6
   return context == Extension_Context::Certificate;
424
6
}
425
426
57
bool NoRevocationAvailable::is_appropriate_context(Extension_Context context) const {
427
57
   return context == Extension_Context::Certificate;
428
57
}
429
430
218
bool TNAuthList::is_appropriate_context(Extension_Context context) const {
431
218
   return context == Extension_Context::Certificate;
432
218
}
433
434
1.28k
bool IPAddressBlocks::is_appropriate_context(Extension_Context context) const {
435
1.28k
   return context == Extension_Context::Certificate;
436
1.28k
}
437
438
2.03k
bool ASBlocks::is_appropriate_context(Extension_Context context) const {
439
2.03k
   return context == Extension_Context::Certificate;
440
2.03k
}
441
442
0
bool Unknown_Extension::is_appropriate_context(Extension_Context /*context*/) const {
443
0
   return true;
444
0
}
445
446
Basic_Constraints::Basic_Constraints(bool is_ca, size_t path_length_constraint) :
447
10.2k
      Basic_Constraints(is_ca, is_ca ? std::optional<size_t>(path_length_constraint) : std::nullopt) {}
448
449
Basic_Constraints::Basic_Constraints(bool is_ca, std::optional<size_t> path_length_constraint) :
450
10.2k
      m_is_ca(is_ca), m_path_length_constraint(path_length_constraint) {
451
10.2k
   if(!m_is_ca && m_path_length_constraint.has_value()) {
452
      // RFC 5280 Sec 4.2.1.9 "CAs MUST NOT include the pathLenConstraint field unless the cA boolean is asserted"
453
0
      throw Invalid_Argument(
454
0
         "Basic_Constraints nonsensical to set a path length constraint for a non-CA basicConstraints");
455
0
   }
456
10.2k
}
457
458
/*
459
* Checked accessor for the path_length_constraint member
460
*/
461
0
size_t Basic_Constraints::get_path_limit() const {
462
0
   if(m_is_ca) {
463
0
      return m_path_length_constraint.value_or(NO_CERT_PATH_LIMIT);
464
0
   } else {
465
0
      throw Invalid_State("Basic_Constraints::get_path_limit: Not a CA");
466
0
   }
467
0
}
468
469
/*
470
* Encode the extension
471
*/
472
0
std::vector<uint8_t> Basic_Constraints::encode_inner() const {
473
0
   std::vector<uint8_t> output;
474
475
0
   if(m_is_ca) {
476
0
      DER_Encoder(output).start_sequence().encode(m_is_ca).encode_optional(m_path_length_constraint).end_cons();
477
0
   } else {
478
0
      DER_Encoder(output).start_sequence().end_cons();
479
0
   }
480
481
0
   return output;
482
0
}
483
484
/*
485
* Decode the extension
486
*/
487
10.2k
void Basic_Constraints::decode_inner(const std::vector<uint8_t>& in) {
488
   /*
489
   * RFC 5280 Section 4.2.1.9
490
   *
491
   * BasicConstraints ::= SEQUENCE {
492
   *    cA                      BOOLEAN DEFAULT FALSE,
493
   *    pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
494
   */
495
10.2k
   BER_Decoder(in, BER_Decoder::Limits::DER())
496
10.2k
      .start_sequence()
497
10.2k
      .decode_optional(m_is_ca, ASN1_Type::Boolean, ASN1_Class::Universal, false)
498
10.2k
      .decode_optional(m_path_length_constraint, ASN1_Type::Integer, ASN1_Class::Universal)
499
10.2k
      .end_cons()
500
10.2k
      .verify_end();
501
502
   /* RFC 5280 Section 4.2.1.9:
503
   *  "CAs MUST NOT include the pathLenConstraint field unless the cA boolean
504
   *  is asserted and the key usage extension asserts the keyCertSign bit" */
505
10.2k
   if(!m_is_ca && m_path_length_constraint.has_value()) {
506
56
      throw Decoding_Error("BasicConstraints pathLenConstraint must not be present when cA is FALSE");
507
56
   }
508
10.2k
}
509
510
/*
511
* Encode the extension
512
*/
513
0
std::vector<uint8_t> Key_Usage::encode_inner() const {
514
0
   if(m_constraints.empty()) {
515
0
      throw Encoding_Error("Cannot encode empty PKIX key constraints");
516
0
   }
517
518
0
   std::vector<uint8_t> der;
519
0
   DER_Encoder(der).encode_named_bitstring(m_constraints.value(), 16);
520
0
   return der;
521
0
}
522
523
/*
524
* Decode the extension
525
*/
526
3.85k
void Key_Usage::decode_inner(const std::vector<uint8_t>& in) {
527
   /* RFC 5280 Section 4.2.1.3 - KeyUsage ::= BIT STRING */
528
3.85k
   uint64_t usage = 0;
529
3.85k
   BER_Decoder(in, BER_Decoder::Limits::DER())
530
3.85k
      .decode_named_bitstring(usage, 16, ASN1_Type::BitString, ASN1_Class::Universal)
531
3.85k
      .verify_end();
532
533
   /* RFC 5280 Section 4.2.1.3:
534
   *  "When the keyUsage extension appears in a certificate, at least one of
535
   *  the bits MUST be set to 1." */
536
3.85k
   if(usage == 0) {
537
0
      throw Decoding_Error("KeyUsage extension must have at least one bit set");
538
0
   }
539
540
3.85k
   m_constraints = Key_Constraints(static_cast<uint32_t>(usage));
541
3.85k
}
542
543
/*
544
* Encode the extension
545
*/
546
0
std::vector<uint8_t> Subject_Key_ID::encode_inner() const {
547
0
   std::vector<uint8_t> output;
548
0
   DER_Encoder(output).encode(m_key_id, ASN1_Type::OctetString);
549
0
   return output;
550
0
}
551
552
/*
553
* Decode the extension
554
*/
555
8.80k
void Subject_Key_ID::decode_inner(const std::vector<uint8_t>& in) {
556
   /* RFC 5280 Section 4.2.1.2 - SubjectKeyIdentifier ::= KeyIdentifier */
557
8.80k
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode(m_key_id, ASN1_Type::OctetString).verify_end();
558
559
8.80k
   if(m_key_id.empty()) {
560
3
      throw Decoding_Error("SubjectKeyIdentifier must not be empty");
561
3
   }
562
8.79k
   if(m_key_id.size() > MaximumKeyIdentifierLength) {
563
0
      throw Decoding_Error(
564
0
         fmt("SubjectKeyIdentifier length {} exceeds limit of {} bytes", m_key_id.size(), MaximumKeyIdentifierLength));
565
0
   }
566
8.79k
}
567
568
/*
569
* Subject_Key_ID Constructor
570
*/
571
0
Subject_Key_ID::Subject_Key_ID(const Public_Key& pub_key) {
572
   /*
573
   * RFC 5280 4.2.1.2:
574
   *    (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
575
   *    value of the BIT STRING subjectPublicKey (excluding the tag, length,
576
   *    and number of unused bits).
577
   */
578
0
   auto hash = HashFunction::create_or_throw("SHA-1");
579
580
0
   m_key_id.resize(hash->output_length());
581
582
0
   hash->update(pub_key.public_key_bits());
583
0
   hash->final(m_key_id.data());
584
0
}
585
586
/*
587
* Subject_Key_ID Constructor
588
*/
589
0
Subject_Key_ID::Subject_Key_ID(const std::vector<uint8_t>& pub_key, std::string_view hash_name) {
590
0
   auto hash = HashFunction::create_or_throw(hash_name);
591
592
0
   m_key_id.resize(hash->output_length());
593
594
0
   hash->update(pub_key);
595
0
   hash->final(m_key_id.data());
596
597
   // Truncate longer hashes, 192 bits here seems plenty
598
0
   const size_t max_skid_len = (192 / 8);
599
0
   if(m_key_id.size() > max_skid_len) {
600
0
      m_key_id.resize(max_skid_len);
601
0
   }
602
0
}
603
604
/*
605
* Encode the extension
606
*/
607
0
std::vector<uint8_t> Authority_Key_ID::encode_inner() const {
608
0
   std::vector<uint8_t> output;
609
0
   DER_Encoder der(output);
610
0
   der.start_sequence();
611
0
   if(!m_key_id.empty()) {
612
0
      der.encode(m_key_id, ASN1_Type::OctetString, ASN1_Type(0), ASN1_Class::ContextSpecific);
613
0
   }
614
0
   if(m_authority_cert.has_value()) {
615
0
      emit_general_names_implicit(der, m_authority_cert->issuer, 1);
616
0
      der.encode(m_authority_cert->serial_number.to_bigint(), ASN1_Type(2), ASN1_Class::ContextSpecific);
617
0
   }
618
0
   der.end_cons();
619
0
   return output;
620
0
}
621
622
/*
623
* Decode the extension
624
*/
625
8.95k
void Authority_Key_ID::decode_inner(const std::vector<uint8_t>& in) {
626
   /*
627
   * RFC 5280 Section 4.2.1.1
628
   *
629
   * AuthorityKeyIdentifier ::= SEQUENCE {
630
   *    keyIdentifier             [0] KeyIdentifier           OPTIONAL,
631
   *    authorityCertIssuer       [1] GeneralNames            OPTIONAL,
632
   *    authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
633
   */
634
8.95k
   BER_Decoder ber(in, BER_Decoder::Limits::DER());
635
8.95k
   BER_Decoder seq = ber.start_sequence();
636
637
8.95k
   m_key_id.clear();
638
8.95k
   m_authority_cert.reset();
639
640
8.95k
   bool key_id_present = false;
641
8.95k
   std::optional<AlternativeName> authority_cert_issuer;
642
8.95k
   std::optional<X509_Serial_Number> authority_cert_serial;
643
644
8.95k
   seq.decode_optional_field(0,
645
8.95k
                             ASN1_Class::ContextSpecific,
646
8.95k
                             [&](BER_Decoder& d) {
647
7.30k
                                d.decode(m_key_id, ASN1_Type::OctetString, ASN1_Type(0), ASN1_Class::ContextSpecific);
648
7.30k
                                key_id_present = true;
649
7.30k
                             })
650
8.95k
      .decode_optional_field(1,
651
8.95k
                             ASN1_Class::ContextSpecific | ASN1_Class::Constructed,
652
8.95k
                             [&](BER_Decoder& d) {
653
233
                                AlternativeName names;
654
233
                                d.decode_implicit(names,
655
233
                                                  ASN1_Type(1),
656
233
                                                  ASN1_Class::ContextSpecific | ASN1_Class::Constructed,
657
233
                                                  ASN1_Type::Sequence,
658
233
                                                  ASN1_Class::Constructed);
659
233
                                authority_cert_issuer = std::move(names);
660
233
                             })
661
8.95k
      .decode_optional_field(2, ASN1_Class::ContextSpecific, [&](BER_Decoder& d) {
662
126
         X509_Serial_Number serial;
663
126
         d.decode_implicit(
664
126
            serial, ASN1_Type(2), ASN1_Class::ContextSpecific, ASN1_Type::Integer, ASN1_Class::Universal);
665
126
         authority_cert_serial = std::move(serial);
666
126
      });
667
668
8.95k
   seq.end_cons();
669
8.95k
   ber.verify_end();
670
671
8.95k
   if(key_id_present) {
672
7.05k
      if(m_key_id.empty()) {
673
0
         throw Decoding_Error("AuthorityKeyIdentifier keyIdentifier must not be empty");
674
0
      }
675
7.05k
      if(m_key_id.size() > MaximumKeyIdentifierLength) {
676
6
         throw Decoding_Error(fmt("AuthorityKeyIdentifier keyIdentifier length {} exceeds limit of {} bytes",
677
6
                                  m_key_id.size(),
678
6
                                  MaximumKeyIdentifierLength));
679
6
      }
680
7.05k
   }
681
682
   // RFC 5280 4.2.1.6: GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
683
8.95k
   if(authority_cert_issuer.has_value() && authority_cert_issuer->is_empty()) {
684
5
      throw Decoding_Error("AuthorityKeyIdentifier authorityCertIssuer must contain at least one GeneralName");
685
5
   }
686
687
   /*
688
   * RFC 5280 Appendix A.2:
689
   *
690
   *    authorityCertIssuer and authorityCertSerialNumber MUST both be
691
   *    present or both be absent
692
   */
693
8.94k
   if(authority_cert_issuer.has_value() != authority_cert_serial.has_value()) {
694
32
      throw Decoding_Error(
695
32
         "AuthorityKeyIdentifier authorityCertIssuer and authorityCertSerialNumber must both be present or absent");
696
32
   }
697
698
8.91k
   if(authority_cert_issuer.has_value()) {
699
52
      m_authority_cert =
700
52
         Authority_Cert_Identifier{std::move(*authority_cert_issuer), std::move(*authority_cert_serial)};
701
52
   }
702
8.91k
}
703
704
/*
705
* Encode the extension
706
*/
707
0
std::vector<uint8_t> Subject_Alternative_Name::encode_inner() const {
708
0
   std::vector<uint8_t> output;
709
0
   DER_Encoder(output).encode(m_alt_name);
710
0
   return output;
711
0
}
712
713
/*
714
* Encode the extension
715
*/
716
0
std::vector<uint8_t> Issuer_Alternative_Name::encode_inner() const {
717
0
   std::vector<uint8_t> output;
718
0
   DER_Encoder(output).encode(m_alt_name);
719
0
   return output;
720
0
}
721
722
/*
723
* Decode the extension
724
*/
725
8.21k
void Subject_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) {
726
   /* RFC 5280 Section 4.2.1.6 - SubjectAltName ::= GeneralNames
727
   *  GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName */
728
8.21k
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode(m_alt_name).verify_end();
729
8.21k
   if(!m_alt_name.has_items()) {
730
95
      throw Decoding_Error("SubjectAlternativeName extension must contain at least one GeneralName");
731
95
   }
732
8.21k
}
733
734
/*
735
* Decode the extension
736
*/
737
2.71k
void Issuer_Alternative_Name::decode_inner(const std::vector<uint8_t>& in) {
738
   /* RFC 5280 Section 4.2.1.7 - IssuerAltName ::= GeneralNames
739
   *  GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName */
740
2.71k
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode(m_alt_name).verify_end();
741
2.71k
   if(!m_alt_name.has_items()) {
742
73
      throw Decoding_Error("IssuerAlternativeName extension must contain at least one GeneralName");
743
73
   }
744
2.71k
}
745
746
/*
747
* Encode the extension
748
*/
749
0
std::vector<uint8_t> Extended_Key_Usage::encode_inner() const {
750
0
   std::vector<uint8_t> output;
751
0
   DER_Encoder(output).start_sequence().encode_list(m_oids).end_cons();
752
0
   return output;
753
0
}
754
755
/*
756
* Decode the extension
757
*/
758
1.76k
void Extended_Key_Usage::decode_inner(const std::vector<uint8_t>& in) {
759
   /* RFC 5280 Section 4.2.1.12 - ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId */
760
1.76k
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode_list(m_oids).verify_end();
761
1.76k
   if(m_oids.empty()) {
762
40
      throw Decoding_Error("ExtendedKeyUsage extension must contain at least one KeyPurposeId");
763
40
   }
764
1.76k
}
765
766
/*
767
* Encode the extension
768
*/
769
0
std::vector<uint8_t> Name_Constraints::encode_inner() const {
770
0
   const auto& permitted = m_name_constraints.permitted();
771
0
   const auto& excluded = m_name_constraints.excluded();
772
773
0
   if(permitted.empty() && excluded.empty()) {
774
0
      throw Encoding_Error("Refusing to encode empty NameConstraints");
775
0
   }
776
777
0
   std::vector<uint8_t> output;
778
0
   DER_Encoder der(output);
779
0
   der.start_sequence();
780
0
   if(!permitted.empty()) {
781
0
      der.start_explicit_context_specific(0).encode_list(permitted).end_cons();
782
0
   }
783
0
   if(!excluded.empty()) {
784
0
      der.start_explicit_context_specific(1).encode_list(excluded).end_cons();
785
0
   }
786
0
   der.end_cons();
787
0
   return output;
788
0
}
789
790
/*
791
* Decode the extension
792
*/
793
689
void Name_Constraints::decode_inner(const std::vector<uint8_t>& in) {
794
   /*
795
   * RFC 5280 Section 4.2.1.10
796
   *
797
   * NameConstraints ::= SEQUENCE {
798
   *    permittedSubtrees       [0] GeneralSubtrees OPTIONAL,
799
   *    excludedSubtrees        [1] GeneralSubtrees OPTIONAL }
800
   */
801
689
   BER_Decoder ber(in, BER_Decoder::Limits::DER());
802
689
   BER_Decoder inner = ber.start_sequence();
803
804
689
   std::vector<GeneralSubtree> permitted;
805
689
   if(inner.decode_optional_list(permitted, ASN1_Type(0), ASN1_Class::ExplicitContextSpecific)) {
806
192
      if(permitted.empty()) {
807
11
         throw Decoding_Error("Empty NameConstraint permitted list");
808
11
      }
809
192
   }
810
811
678
   std::vector<GeneralSubtree> excluded;
812
678
   if(inner.decode_optional_list(excluded, ASN1_Type(1), ASN1_Class::ExplicitContextSpecific)) {
813
88
      if(excluded.empty()) {
814
6
         throw Decoding_Error("Empty NameConstraint excluded list");
815
6
      }
816
88
   }
817
818
672
   inner.end_cons();
819
672
   ber.verify_end();
820
821
672
   if(permitted.empty() && excluded.empty()) {
822
4
      throw Decoding_Error("Empty NameConstraint extension");
823
4
   }
824
825
668
   m_name_constraints = NameConstraints(std::move(permitted), std::move(excluded));
826
668
}
827
828
void Name_Constraints::validate(const X509_Certificate& subject,
829
                                const std::optional<X509_Certificate>& /*issuer*/,
830
                                const std::vector<X509_Certificate>& cert_path,
831
                                std::vector<std::set<Certificate_Status_Code>>& cert_status,
832
0
                                size_t pos) const {
833
0
   if(!m_name_constraints.permitted().empty() || !m_name_constraints.excluded().empty()) {
834
0
      if(!subject.is_CA_cert()) {
835
0
         cert_status.at(pos).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR);
836
0
      }
837
838
0
      const bool issuer_name_constraint_critical = subject.is_critical("X509v3.NameConstraints");
839
840
      // Check that all subordinate certs pass the name constraint
841
0
      for(size_t j = 0; j < pos; ++j) {
842
0
         const auto& cert = cert_path.at(j);
843
844
         // RFC 5280 6.1.4(b): "Name constraints are not applied to self-issued
845
         // certificates (unless the certificate is the final certificate in the path)"
846
         // Position 0 is the end entity (final certificate); skip self-issued intermediates.
847
0
         if(j > 0 && cert.issuer_dn() == cert.subject_dn()) {
848
0
            continue;
849
0
         }
850
851
0
         if(!m_name_constraints.is_permitted(cert, issuer_name_constraint_critical)) {
852
0
            cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR);
853
0
            continue;
854
0
         }
855
856
0
         if(m_name_constraints.is_excluded(cert, issuer_name_constraint_critical)) {
857
0
            cert_status.at(j).insert(Certificate_Status_Code::NAME_CONSTRAINT_ERROR);
858
0
            continue;
859
0
         }
860
0
      }
861
0
   }
862
0
}
863
864
namespace {
865
866
/*
867
* A policy specifier
868
*/
869
class Policy_Information final : public ASN1_Object {
870
   public:
871
1.68k
      Policy_Information() = default;
872
873
0
      explicit Policy_Information(const OID& oid) : m_oid(oid) {}
874
875
549
      const OID& oid() const { return m_oid; }
876
877
0
      void encode_into(DER_Encoder& codec) const override { codec.start_sequence().encode(m_oid).end_cons(); }
878
879
1.68k
      void decode_from(BER_Decoder& codec) override {
880
1.68k
         codec.start_sequence().decode(m_oid).discard_remaining().end_cons();
881
1.68k
      }
882
883
   private:
884
      OID m_oid;
885
};
886
887
103
bool policy_oids_have_duplicate(const std::vector<OID>& oids) {
888
103
   std::set<OID> seen;
889
508
   for(const auto& oid : oids) {
890
508
      if(!seen.insert(oid).second) {
891
10
         return true;
892
10
      }
893
508
   }
894
93
   return false;
895
103
}
896
897
}  // namespace
898
899
Certificate_Policies::Certificate_Policies(const std::vector<OID>& oids) :
900
0
      m_oids(oids), m_has_duplicate(policy_oids_have_duplicate(m_oids)) {}
901
902
/*
903
* Encode the extension
904
*/
905
0
std::vector<uint8_t> Certificate_Policies::encode_inner() const {
906
0
   std::vector<Policy_Information> policies;
907
908
0
   policies.reserve(m_oids.size());
909
0
   for(const auto& oid : m_oids) {
910
0
      policies.push_back(Policy_Information(oid));
911
0
   }
912
913
0
   std::vector<uint8_t> output;
914
0
   DER_Encoder(output).start_sequence().encode_list(policies).end_cons();
915
0
   return output;
916
0
}
917
918
/*
919
* Decode the extension
920
*/
921
844
void Certificate_Policies::decode_inner(const std::vector<uint8_t>& in) {
922
   /* RFC 5280 Section 4.2.1.4 - CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation */
923
844
   std::vector<Policy_Information> policies;
924
925
844
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode_list(policies).verify_end();
926
844
   if(policies.empty()) {
927
6
      throw Decoding_Error("CertificatePolicies extension must contain at least one PolicyInformation");
928
6
   }
929
838
   m_oids.clear();
930
838
   for(const auto& policy : policies) {
931
549
      m_oids.push_back(policy.oid());
932
549
   }
933
838
   m_has_duplicate = policy_oids_have_duplicate(m_oids);
934
838
}
935
936
void Certificate_Policies::validate(const X509_Certificate& /*subject*/,
937
                                    const std::optional<X509_Certificate>& /*issuer*/,
938
                                    const std::vector<X509_Certificate>& /*cert_path*/,
939
                                    std::vector<std::set<Certificate_Status_Code>>& cert_status,
940
0
                                    size_t pos) const {
941
0
   if(m_has_duplicate) {
942
0
      cert_status.at(pos).insert(Certificate_Status_Code::DUPLICATE_CERT_POLICY);
943
0
   }
944
0
}
945
946
namespace {
947
948
0
std::vector<URI> parse_aia_uris(const std::vector<std::string>& uris, const char* context) {
949
0
   std::vector<URI> out;
950
0
   out.reserve(uris.size());
951
0
   for(const auto& uri : uris) {
952
0
      if(auto parsed = URI::from_string(uri)) {
953
0
         out.push_back(std::move(*parsed));
954
0
      } else {
955
0
         throw Invalid_Argument(fmt("Invalid URI in {}", context));
956
0
      }
957
0
   }
958
0
   return out;
959
0
}
960
961
// Convert the application provided URIs into AccessDescription entries
962
std::vector<Authority_Information_Access::AccessDescription> uri_access_descriptions(
963
0
   const std::vector<URI>& ocsp_responders, const std::vector<URI>& ca_issuers) {
964
0
   std::vector<Authority_Information_Access::AccessDescription> out;
965
0
   out.reserve(ocsp_responders.size() + ca_issuers.size());
966
967
0
   const auto append = [&](const OID& method, const std::vector<URI>& uris) {
968
0
      for(const auto& uri : uris) {
969
0
         const ASN1_String value(uri.original_input(), ASN1_Type::Ia5String);
970
0
         out.emplace_back(method,
971
0
                          ASN1_Type(6),
972
0
                          ASN1_Class::ContextSpecific,
973
0
                          std::vector<uint8_t>(value.value().begin(), value.value().end()));
974
0
      }
975
0
   };
976
977
0
   append(OID::from_string("PKIX.OCSP"), ocsp_responders);
978
0
   append(OID::from_string("PKIX.CertificateAuthorityIssuers"), ca_issuers);
979
0
   return out;
980
0
}
981
982
}  // namespace
983
984
Authority_Information_Access::Authority_Information_Access(std::string_view ocsp,
985
                                                           const std::vector<std::string>& ca_issuers) :
986
0
      m_ca_issuers(parse_aia_uris(ca_issuers, "AuthorityInformationAccess CA issuers")) {
987
0
   if(!ocsp.empty()) {
988
0
      if(auto parsed = URI::from_string(ocsp)) {
989
0
         m_ocsp_responders.push_back(std::move(*parsed));
990
0
      } else {
991
0
         throw Invalid_Argument("Invalid URI in AuthorityInformationAccess OCSP responder");
992
0
      }
993
0
   }
994
0
   m_access_descriptions = uri_access_descriptions(m_ocsp_responders, m_ca_issuers);
995
0
}
996
997
Authority_Information_Access::Authority_Information_Access(const std::vector<std::string>& ocsp_responders,
998
                                                           const std::vector<std::string>& ca_issuers) :
999
0
      m_ocsp_responders(parse_aia_uris(ocsp_responders, "AuthorityInformationAccess OCSP responders")),
1000
0
      m_ca_issuers(parse_aia_uris(ca_issuers, "AuthorityInformationAccess CA issuers")),
1001
0
      m_access_descriptions(uri_access_descriptions(m_ocsp_responders, m_ca_issuers)) {}
1002
1003
Authority_Information_Access::Authority_Information_Access(std::vector<URI> ocsp_responders,
1004
                                                           std::vector<URI> ca_issuers) :
1005
0
      m_ocsp_responders(std::move(ocsp_responders)),
1006
0
      m_ca_issuers(std::move(ca_issuers)),
1007
0
      m_access_descriptions(uri_access_descriptions(m_ocsp_responders, m_ca_issuers)) {}
1008
1009
0
std::vector<std::string> Authority_Information_Access::ocsp_responders() const {
1010
0
   std::vector<std::string> out;
1011
0
   out.reserve(m_ocsp_responders.size());
1012
0
   for(const auto& uri : m_ocsp_responders) {
1013
0
      out.push_back(uri.original_input());
1014
0
   }
1015
0
   return out;
1016
0
}
1017
1018
0
std::unique_ptr<Certificate_Extension> Authority_Information_Access::copy() const {
1019
0
   return std::make_unique<Authority_Information_Access>(*this);
1020
0
}
1021
1022
namespace {
1023
1024
1.69k
void validate_general_name_encoding(ASN1_Type tag, ASN1_Class cls, std::span<const uint8_t> value) {
1025
   // AlternativeName decodes GeneralNames; AIA accessLocation is a single GeneralName.
1026
1.69k
   std::vector<uint8_t> wrapped_name;
1027
1.69k
   DER_Encoder(wrapped_name).start_sequence().add_object(tag, cls, value).end_cons();
1028
1029
1.69k
   AlternativeName decoded_name;
1030
1.69k
   BER_Decoder(wrapped_name, BER_Decoder::Limits::DER()).decode(decoded_name).verify_end();
1031
1032
1.69k
   if((tag == ASN1_Type(1) || tag == ASN1_Type(2) || tag == ASN1_Type(6)) && value.empty()) {
1033
12
      throw Decoding_Error("GeneralName IA5String value must not be empty");
1034
12
   }
1035
1.68k
   if(tag == ASN1_Type(4) &&
1036
7
      std::ranges::any_of(decoded_name.directory_names(), [](const X509_DN& dn) { return dn.empty(); })) {
1037
1
      throw Decoding_Error("GeneralName directoryName must not be empty");
1038
1
   }
1039
1.68k
}
1040
1041
// Construction-time validation for an AccessDescription entering
1042
// m_access_descriptions. encode_inner repeats this as a safety net; doing it
1043
// here means the throw lands where the caller is building the AIA.
1044
0
void validate_access_description(const Authority_Information_Access::AccessDescription& ad) {
1045
0
   try {
1046
0
      validate_general_name_encoding(ad.location_tag(), ad.location_class(), ad.location_value());
1047
0
   } catch(const Exception&) {
1048
0
      throw Invalid_Argument("AccessDescription accessLocation is not a valid GeneralName");
1049
0
   }
1050
0
}
1051
1052
// Mirror the decode-time logic that populates the typed URI accessors from
1053
// id-ad-ocsp / id-ad-caIssuers entries. Used by the AccessDescription-based
1054
// constructor and add_access_description so the two views stay consistent.
1055
// An id-ad-ocsp / id-ad-caIssuers entry whose URI fails to parse is rejected
1056
// here (mirroring decode_inner) so the typed accessors and m_access_descriptions
1057
// cannot disagree, and so the AIA cannot re-encode bytes that its own decoder
1058
// would reject.
1059
void populate_uri_view_from_access_description(const Authority_Information_Access::AccessDescription& ad,
1060
                                               std::vector<URI>& ocsp_responders,
1061
0
                                               std::vector<URI>& ca_issuers) {
1062
0
   const auto oid_ocsp_responders = OID::from_string("PKIX.OCSP");
1063
0
   const auto oid_ca_issuers = OID::from_string("PKIX.CertificateAuthorityIssuers");
1064
0
   if(const auto uri_str = ad.location_as_uri_string()) {
1065
0
      if(ad.access_method() == oid_ocsp_responders) {
1066
0
         if(auto uri = URI::from_string(*uri_str)) {
1067
0
            ocsp_responders.push_back(std::move(*uri));
1068
0
         } else {
1069
0
            throw Invalid_Argument("Invalid URI in AuthorityInformationAccess OCSP responder");
1070
0
         }
1071
0
      } else if(ad.access_method() == oid_ca_issuers) {
1072
0
         if(auto uri = URI::from_string(*uri_str)) {
1073
0
            ca_issuers.push_back(std::move(*uri));
1074
0
         } else {
1075
0
            throw Invalid_Argument("Invalid URI in AuthorityInformationAccess CA issuers");
1076
0
         }
1077
0
      }
1078
0
   }
1079
0
}
1080
1081
}  // namespace
1082
1083
Authority_Information_Access::Authority_Information_Access(std::vector<AccessDescription> access_descriptions) :
1084
0
      m_access_descriptions(std::move(access_descriptions)) {
1085
0
   for(const auto& ad : m_access_descriptions) {
1086
0
      validate_access_description(ad);
1087
0
      populate_uri_view_from_access_description(ad, m_ocsp_responders, m_ca_issuers);
1088
0
   }
1089
0
}
1090
1091
0
void Authority_Information_Access::add_access_description(AccessDescription ad) {
1092
0
   validate_access_description(ad);
1093
0
   populate_uri_view_from_access_description(ad, m_ocsp_responders, m_ca_issuers);
1094
0
   m_access_descriptions.push_back(std::move(ad));
1095
0
}
1096
1097
0
std::vector<std::string> Authority_Information_Access::ca_issuers() const {
1098
0
   std::vector<std::string> out;
1099
0
   out.reserve(m_ca_issuers.size());
1100
0
   for(const auto& uri : m_ca_issuers) {
1101
0
      out.push_back(uri.original_input());
1102
0
   }
1103
0
   return out;
1104
0
}
1105
1106
0
std::optional<std::string> Authority_Information_Access::AccessDescription::location_as_uri_string() const {
1107
0
   if(m_location_class == ASN1_Class::ContextSpecific && m_location_tag == ASN1_Type(6)) {
1108
0
      return std::string(m_location_value.begin(), m_location_value.end());
1109
0
   }
1110
0
   return std::nullopt;
1111
0
}
1112
1113
0
std::vector<uint8_t> Authority_Information_Access::encode_inner() const {
1114
0
   std::vector<uint8_t> output;
1115
0
   DER_Encoder der(output);
1116
1117
0
   der.start_sequence();
1118
1119
0
   for(const auto& ad : m_access_descriptions) {
1120
0
      try {
1121
0
         validate_general_name_encoding(ad.location_tag(), ad.location_class(), ad.location_value());
1122
0
      } catch(const Exception&) {
1123
0
         throw Encoding_Error("AccessDescription accessLocation is not a valid GeneralName");
1124
0
      }
1125
0
      der.start_sequence()
1126
0
         .encode(ad.access_method())
1127
0
         .add_object(ad.location_tag(), ad.location_class(), ad.location_value())
1128
0
         .end_cons();
1129
0
   }
1130
1131
0
   der.end_cons();
1132
0
   return output;
1133
0
}
1134
1135
1.75k
void Authority_Information_Access::decode_inner(const std::vector<uint8_t>& in) {
1136
   /*
1137
   * RFC 5280 Section 4.2.2.1
1138
   *
1139
   * AuthorityInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF AccessDescription
1140
   * AccessDescription ::= SEQUENCE {
1141
   *    accessMethod          OBJECT IDENTIFIER,
1142
   *    accessLocation        GeneralName }
1143
   */
1144
1.75k
   BER_Decoder outer(in, BER_Decoder::Limits::DER());
1145
1.75k
   BER_Decoder ber = outer.start_sequence();
1146
1147
1.75k
   const OID ocsp_responder = OID::from_string("PKIX.OCSP");
1148
1.75k
   const OID ca_issuer = OID::from_string("PKIX.CertificateAuthorityIssuers");
1149
1150
1.75k
   m_access_descriptions.clear();
1151
1.75k
   m_ocsp_responders.clear();
1152
1.75k
   m_ca_issuers.clear();
1153
1154
3.67k
   while(ber.more_items()) {
1155
1.91k
      OID oid;
1156
1157
1.91k
      BER_Decoder info = ber.start_sequence();
1158
1159
1.91k
      info.decode(oid);
1160
1.91k
      const BER_Object name = info.get_next_object();
1161
1162
      /* RFC 5280 4.2.2.1:
1163
      *    AccessDescription  ::=  SEQUENCE {
1164
      *         accessMethod          OBJECT IDENTIFIER,
1165
      *         accessLocation        GeneralName  }
1166
      */
1167
1.91k
      if(!name.is_set()) {
1168
3
         throw Decoding_Error("AuthorityInformationAccess AccessDescription missing accessLocation");
1169
3
      }
1170
1.91k
      validate_general_name_encoding(name.type_tag(), name.get_class(), name.data());
1171
1.91k
      info.end_cons();
1172
1173
1.91k
      m_access_descriptions.emplace_back(
1174
1.91k
         oid, name.type_tag(), name.get_class(), std::vector<uint8_t>(name.data().begin(), name.data().end()));
1175
1176
1.91k
      if(name.is_a(6, ASN1_Class::ContextSpecific)) {
1177
692
         if(oid == ocsp_responder) {
1178
209
            if(auto parsed = URI::from_string(ASN1::to_string(name))) {
1179
209
               m_ocsp_responders.push_back(std::move(*parsed));
1180
209
            } else {
1181
0
               throw Decoding_Error("Invalid URI in AuthorityInformationAccess OCSP responder");
1182
0
            }
1183
483
         } else if(oid == ca_issuer) {
1184
214
            if(auto parsed = URI::from_string(ASN1::to_string(name))) {
1185
214
               m_ca_issuers.push_back(std::move(*parsed));
1186
214
            } else {
1187
0
               throw Decoding_Error("Invalid URI in AuthorityInformationAccess CA issuers");
1188
0
            }
1189
214
         }
1190
692
      }
1191
1.91k
   }
1192
1193
1.75k
   ber.end_cons();
1194
1.75k
   outer.verify_end();
1195
1196
1.75k
   if(m_access_descriptions.empty()) {
1197
109
      throw Decoding_Error("AuthorityInformationAccess extension must contain at least one AccessDescription");
1198
109
   }
1199
1.75k
}
1200
1201
0
CRL_Number::CRL_Number(BigInt n) : m_has_value(true), m_crl_number(std::move(n)) {
1202
0
   BOTAN_ARG_CHECK(m_crl_number.signum() >= 0, "CRL number cannot be negative");
1203
0
}
1204
1205
18
const BigInt& CRL_Number::crl_number() const {
1206
   // This can only happen via a misuse of the CRL_Number default constructor
1207
18
   BOTAN_STATE_CHECK(m_has_value);
1208
18
   return m_crl_number;
1209
18
}
1210
1211
/*
1212
* Checked accessor for the crl_number member
1213
*/
1214
0
size_t CRL_Number::get_crl_number() const {
1215
   // This can only happen via a misuse of the CRL_Number default constructor
1216
0
   BOTAN_STATE_CHECK(m_has_value);
1217
0
   return m_crl_number.to_u32bit();
1218
0
}
1219
1220
/*
1221
* Copy a CRL_Number extension
1222
*/
1223
0
std::unique_ptr<Certificate_Extension> CRL_Number::copy() const {
1224
0
   return std::make_unique<CRL_Number>(*this);
1225
0
}
1226
1227
/*
1228
* Encode the extension
1229
*/
1230
0
std::vector<uint8_t> CRL_Number::encode_inner() const {
1231
0
   std::vector<uint8_t> output;
1232
0
   DER_Encoder(output).encode(m_crl_number);
1233
0
   return output;
1234
0
}
1235
1236
/*
1237
* Decode the extension
1238
*/
1239
47
void CRL_Number::decode_inner(const std::vector<uint8_t>& in) {
1240
   /* RFC 5280 Section 5.2.3 - CRLNumber ::= INTEGER (0..MAX) */
1241
47
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode(m_crl_number).verify_end();
1242
47
   if(m_crl_number.signum() < 0) {
1243
3
      throw Decoding_Error("CRL number cannot be negative");
1244
3
   }
1245
44
   m_has_value = true;
1246
44
}
1247
1248
/*
1249
* Encode the extension
1250
*/
1251
0
std::vector<uint8_t> CRL_ReasonCode::encode_inner() const {
1252
0
   std::vector<uint8_t> output;
1253
0
   DER_Encoder(output).encode(static_cast<size_t>(m_reason), ASN1_Type::Enumerated, ASN1_Class::Universal);
1254
0
   return output;
1255
0
}
1256
1257
/*
1258
* Decode the extension
1259
*/
1260
3.90k
void CRL_ReasonCode::decode_inner(const std::vector<uint8_t>& in) {
1261
   /*
1262
   * RFC 5280 Section 5.3.1
1263
   *
1264
   * CRLReason ::= ENUMERATED {
1265
   *      unspecified             (0),
1266
   *      keyCompromise           (1),
1267
   *      cACompromise            (2),
1268
   *      affiliationChanged      (3),
1269
   *      superseded              (4),
1270
   *      cessationOfOperation    (5),
1271
   *      certificateHold         (6),
1272
   *           -- value 7 is not used
1273
   *      removeFromCRL           (8),
1274
   *      privilegeWithdrawn      (9),
1275
   *      aACompromise           (10) }
1276
   */
1277
3.90k
   size_t reason_code = 0;
1278
3.90k
   BER_Decoder(in, BER_Decoder::Limits::DER())
1279
3.90k
      .decode(reason_code, ASN1_Type::Enumerated, ASN1_Class::Universal)
1280
3.90k
      .verify_end();
1281
1282
3.90k
   if(reason_code == 7 || reason_code > 10) {
1283
417
      throw Decoding_Error(fmt("CRLReason has unknown enumeration value {}", reason_code));
1284
417
   }
1285
1286
3.48k
   m_reason = static_cast<CRL_Code>(reason_code);
1287
3.48k
}
1288
1289
namespace {
1290
1291
constexpr size_t ReasonFlagsNamedBitWidth = 9;
1292
1293
0
void emit_reason_flags_implicit(DER_Encoder& der, uint32_t tag, ReasonFlags reasons) {
1294
0
   der.encode_named_bitstring(reasons.value(), ReasonFlagsNamedBitWidth, ASN1_Type(tag), ASN1_Class::ContextSpecific);
1295
0
}
1296
1297
67
ReasonFlags decode_reason_flags_implicit(BER_Decoder& decoder, uint32_t tag) {
1298
67
   uint64_t bits = 0;
1299
67
   decoder.decode_named_bitstring(bits, ReasonFlagsNamedBitWidth, ASN1_Type(tag), ASN1_Class::ContextSpecific);
1300
67
   return ReasonFlags(checked_cast_to<uint16_t>(bits));
1301
67
}
1302
1303
/*
1304
* RFC 5280 4.2.1.13: "If present, the cRLIssuer MUST only contain the
1305
* distinguished name (DN) from the issuer field of the CRL to which the
1306
* DistributionPoint is pointing."
1307
*
1308
* We don't know the value of the CRL issuer at this point so we can only
1309
* enforce that the cRLIssuer name is exactly one non-empty DN.
1310
*/
1311
2
bool crl_issuer_is_well_formed(const AlternativeName& crl_issuer) {
1312
2
   const auto& dn = crl_issuer.directory_names();
1313
2
   return crl_issuer.count() == 1 && dn.size() == 1 && !dn.begin()->empty();
1314
2
}
1315
1316
std::vector<URI> crl_distribution_point_uris_from_distribution_points(
1317
161
   const std::vector<CRL_Distribution_Points::Distribution_Point>& dps) {
1318
161
   std::vector<URI> out;
1319
328
   for(const auto& dp : dps) {
1320
328
      const auto& dpn = dp.distribution_point_name();
1321
328
      if(dpn.has_value() && dpn->full_name().has_value()) {
1322
523
         for(const auto& uri : dpn->full_name()->uri_names()) {
1323
523
            out.push_back(uri);
1324
523
         }
1325
328
      }
1326
328
   }
1327
161
   return out;
1328
161
}
1329
1330
}  // namespace
1331
1332
0
const AlternativeName& CRL_Distribution_Points::Distribution_Point::point() const {
1333
0
   BOTAN_STATE_CHECK(m_dp_name.has_value() && m_dp_name->full_name().has_value());
1334
0
   return *m_dp_name->full_name();
1335
0
}
1336
1337
CRL_Distribution_Points::CRL_Distribution_Points(const std::vector<Distribution_Point>& points) :
1338
0
      m_distribution_points(points),
1339
0
      m_crl_distribution_urls(crl_distribution_point_uris_from_distribution_points(m_distribution_points)) {}
1340
1341
0
const AlternativeName& CRL_Issuing_Distribution_Point::get_point() const {
1342
0
   BOTAN_STATE_CHECK(m_dp_name.has_value() && m_dp_name->full_name().has_value());
1343
0
   return *m_dp_name->full_name();
1344
0
}
1345
1346
0
void DistributionPointName::encode_into(DER_Encoder& der) const {
1347
0
   if(!m_full_name.has_value()) {
1348
0
      throw Encoding_Error("DistributionPointName has no fullName to encode");
1349
0
   }
1350
   // fullName [0] IMPLICIT GeneralNames. emit_general_names_implicit rejects
1351
   // empty AlternativeNames per RFC 5280 4.2.1.6: GeneralNames ::= SEQUENCE
1352
   // SIZE (1..MAX).
1353
0
   emit_general_names_implicit(der, *m_full_name, 0);
1354
0
}
1355
1356
1.55k
void DistributionPointName::decode_from(BER_Decoder& ber) {
1357
1.55k
   const BER_Object& obj = ber.peek_next_object();
1358
1.55k
   if(obj.is_a(0, ASN1_Class::ContextSpecific | ASN1_Class::Constructed)) {
1359
1.43k
      AlternativeName full_name;
1360
1.43k
      ber.decode_implicit(full_name,
1361
1.43k
                          ASN1_Type(0),
1362
1.43k
                          ASN1_Class::ContextSpecific | ASN1_Class::Constructed,
1363
1.43k
                          ASN1_Type::Sequence,
1364
1.43k
                          ASN1_Class::Constructed);
1365
      // RFC 5280 4.2.1.6: GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
1366
1.43k
      if(!full_name.has_items()) {
1367
19
         throw Decoding_Error("DistributionPointName fullName must contain at least one GeneralName");
1368
19
      }
1369
1.41k
      if(std::ranges::any_of(full_name.directory_names(), [](const X509_DN& dn) { return dn.empty(); })) {
1370
0
         throw Decoding_Error("DistributionPointName fullName must not contain an empty directoryName");
1371
0
      }
1372
1.41k
      m_full_name = std::move(full_name);
1373
1.41k
   } else if(obj.is_a(1, ASN1_Class::ContextSpecific | ASN1_Class::Constructed)) {
1374
7
      throw Decoding_Error("nameRelativeToCrlIssuer not supported in DistributionPointName");
1375
112
   } else {
1376
112
      throw Decoding_Error("DistributionPointName CHOICE is neither fullName nor nameRelativeToCRLIssuer");
1377
112
   }
1378
1.55k
}
1379
1380
0
std::vector<uint8_t> CRL_Distribution_Points::encode_inner() const {
1381
0
   std::vector<uint8_t> output;
1382
0
   DER_Encoder(output).start_sequence().encode_list(m_distribution_points).end_cons();
1383
0
   return output;
1384
0
}
1385
1386
1.55k
void CRL_Distribution_Points::decode_inner(const std::vector<uint8_t>& buf) {
1387
   /*
1388
   * RFC 5280 Section 4.2.1.13
1389
   *
1390
   * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
1391
   */
1392
1.55k
   BER_Decoder(buf, BER_Decoder::Limits::DER()).decode_list(m_distribution_points).verify_end();
1393
1394
1.55k
   if(m_distribution_points.empty()) {
1395
12
      throw Decoding_Error("CRLDistributionPoints extension must contain at least one DistributionPoint");
1396
12
   }
1397
1398
1.54k
   m_crl_distribution_urls = crl_distribution_point_uris_from_distribution_points(m_distribution_points);
1399
1.54k
}
1400
1401
0
std::vector<std::string> CRL_Distribution_Points::crl_distribution_urls() const {
1402
0
   std::vector<std::string> out;
1403
0
   out.reserve(m_crl_distribution_urls.size());
1404
0
   for(const auto& uri : m_crl_distribution_urls) {
1405
0
      out.push_back(uri.original_input());
1406
0
   }
1407
0
   return out;
1408
0
}
1409
1410
0
void CRL_Distribution_Points::Distribution_Point::encode_into(DER_Encoder& der) const {
1411
   /*
1412
   * DistributionPoint ::= SEQUENCE {
1413
   *      distributionPoint       [0]     DistributionPointName OPTIONAL,
1414
   *      reasons                 [1]     ReasonFlags OPTIONAL,
1415
   *      cRLIssuer               [2]     GeneralNames OPTIONAL }
1416
   *
1417
   * RFC 5280 4.2.1.13: "either distributionPoint or cRLIssuer MUST be present".
1418
   */
1419
0
   const bool has_dp_name = m_dp_name.has_value();
1420
0
   const bool has_crl_issuer = m_crl_issuer.has_value();
1421
0
   if(!has_dp_name && !has_crl_issuer) {
1422
0
      throw Encoding_Error("DistributionPoint must contain either distributionPoint or cRLIssuer");
1423
0
   }
1424
0
   if(has_crl_issuer && !crl_issuer_is_well_formed(*m_crl_issuer)) {
1425
      /* RFC 5280 4.2.1.13: "If present, the cRLIssuer MUST only contain the
1426
      * distinguished name (DN) from the issuer field of the CRL". */
1427
0
      throw Encoding_Error("cRLIssuer must contain exactly one non-empty directoryName GeneralName");
1428
0
   }
1429
1430
0
   der.start_sequence();
1431
1432
0
   if(has_dp_name) {
1433
      // distributionPoint [0] EXPLICIT DistributionPointName
1434
0
      der.start_explicit_context_specific(0).encode(*m_dp_name).end_cons();
1435
0
   }
1436
1437
0
   if(m_reasons) {
1438
0
      emit_reason_flags_implicit(der, 1, *m_reasons);
1439
0
   }
1440
1441
0
   if(has_crl_issuer) {
1442
0
      emit_general_names_implicit(der, *m_crl_issuer, 2);
1443
0
   }
1444
1445
0
   der.end_cons();
1446
0
}
1447
1448
1.74k
void CRL_Distribution_Points::Distribution_Point::decode_from(BER_Decoder& ber) {
1449
   /*
1450
   * DistributionPoint ::= SEQUENCE {
1451
   *      distributionPoint       [0]     DistributionPointName OPTIONAL,
1452
   *      reasons                 [1]     ReasonFlags OPTIONAL,
1453
   *      cRLIssuer               [2]     GeneralNames OPTIONAL }
1454
   */
1455
1.74k
   BER_Decoder dp = ber.start_sequence();
1456
1457
1.74k
   m_dp_name.reset();
1458
1.74k
   m_reasons.reset();
1459
1.74k
   m_crl_issuer.reset();
1460
1461
   // DER: these optional fields appear at most once and in increasing tag
1462
   // order. Decoding them in tag order and then rejecting anything left over
1463
   // (see end_cons below) catches out-of-order, duplicate, and unknown fields.
1464
1.74k
   dp.decode_optional_field(0,
1465
1.74k
                            ASN1_Class::ContextSpecific | ASN1_Class::Constructed,
1466
1.74k
                            [&](BER_Decoder& d) {
1467
1.51k
                               DistributionPointName name;
1468
1.51k
                               d.start_context_specific(0).decode(name).verify_end();
1469
1.51k
                               m_dp_name = std::move(name);
1470
1.51k
                            })
1471
1.74k
      .decode_optional_field(
1472
1.74k
         1, ASN1_Class::ContextSpecific, [&](BER_Decoder& d) { m_reasons = decode_reason_flags_implicit(d, 1); })
1473
1.74k
      .decode_optional_field(2, ASN1_Class::ContextSpecific | ASN1_Class::Constructed, [&](BER_Decoder& d) {
1474
19
         AlternativeName crl_issuer;
1475
19
         d.decode_implicit(crl_issuer,
1476
19
                           ASN1_Type(2),
1477
19
                           ASN1_Class::ContextSpecific | ASN1_Class::Constructed,
1478
19
                           ASN1_Type::Sequence,
1479
19
                           ASN1_Class::Constructed);
1480
19
         m_crl_issuer = std::move(crl_issuer);
1481
19
      });
1482
1483
1.74k
   dp.end_cons();
1484
1485
   // RFC 5280 4.2.1.6: GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
1486
1.74k
   if(m_crl_issuer.has_value() && m_crl_issuer->is_empty()) {
1487
2
      throw Decoding_Error("cRLIssuer GeneralNames must contain at least one GeneralName");
1488
2
   }
1489
1490
1.74k
   if(m_crl_issuer.has_value() && !crl_issuer_is_well_formed(*m_crl_issuer)) {
1491
      /* RFC 5280 4.2.1.13: "If present, the cRLIssuer MUST only contain the
1492
      * distinguished name (DN) from the issuer field of the CRL". */
1493
2
      throw Decoding_Error("cRLIssuer must contain exactly one non-empty directoryName GeneralName");
1494
2
   }
1495
1496
1.74k
   if(!m_dp_name.has_value() && !m_crl_issuer.has_value()) {
1497
8
      throw Decoding_Error("DistributionPoint must contain either distributionPoint or cRLIssuer");
1498
8
   }
1499
1.74k
}
1500
1501
0
std::vector<uint8_t> CRL_Issuing_Distribution_Point::encode_inner() const {
1502
   /* RFC 5280 Section 5.2.5
1503
   *
1504
   *    Conforming CRL issuers MUST NOT issue CRLs where the DER encoding of the
1505
   *    issuing distribution point extension is an empty sequence. [...] at most one
1506
   *    of onlyContainsUserCerts, onlyContainsCACerts, and onlyContainsAttributeCerts
1507
   *    may be set to TRUE
1508
   */
1509
0
   if(!should_encode()) {
1510
0
      throw Encoding_Error("Refusing to encode empty IssuingDistributionPoint");
1511
0
   }
1512
1513
0
   const size_t scope_set = static_cast<size_t>(m_only_contains_user_certs) +
1514
0
                            static_cast<size_t>(m_only_contains_ca_certs) +
1515
0
                            static_cast<size_t>(m_only_contains_attribute_certs);
1516
0
   if(scope_set > 1) {
1517
0
      throw Encoding_Error(
1518
0
         "At most one of onlyContainsUserCerts, onlyContainsCACerts, onlyContainsAttributeCerts may be TRUE");
1519
0
   }
1520
1521
0
   auto emit_optional_boolean_implicit = [](DER_Encoder& der, uint32_t tag, bool value) {
1522
      // All of the values encoded here are DEFAULT FALSE so skip encoding if false
1523
0
      if(value == true) {
1524
         // Encode a BOOLEAN TRUE (0xFF) as [tag] IMPLICIT BOOLEAN
1525
0
         const uint8_t val = 0xFF;
1526
0
         der.add_object(ASN1_Type(tag), ASN1_Class::ContextSpecific, &val, 1);
1527
0
      }
1528
0
   };
1529
1530
0
   std::vector<uint8_t> output;
1531
0
   DER_Encoder der(output);
1532
0
   der.start_sequence();
1533
1534
0
   if(m_dp_name.has_value()) {
1535
0
      der.start_explicit_context_specific(0).encode(*m_dp_name).end_cons();
1536
0
   }
1537
1538
0
   emit_optional_boolean_implicit(der, 1, m_only_contains_user_certs);
1539
0
   emit_optional_boolean_implicit(der, 2, m_only_contains_ca_certs);
1540
1541
0
   if(m_only_some_reasons) {
1542
0
      emit_reason_flags_implicit(der, 3, *m_only_some_reasons);
1543
0
   }
1544
1545
0
   emit_optional_boolean_implicit(der, 4, m_indirect_crl);
1546
0
   emit_optional_boolean_implicit(der, 5, m_only_contains_attribute_certs);
1547
1548
0
   der.end_cons();
1549
0
   return output;
1550
0
}
1551
1552
185
void CRL_Issuing_Distribution_Point::decode_inner(const std::vector<uint8_t>& buf) {
1553
   /*
1554
   * RFC 5280 Section 5.2.5
1555
   *
1556
   * IssuingDistributionPoint ::= SEQUENCE {
1557
   *      distributionPoint          [0] DistributionPointName OPTIONAL,
1558
   *      onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
1559
   *      onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
1560
   *      onlySomeReasons            [3] ReasonFlags OPTIONAL,
1561
   *      indirectCRL                [4] BOOLEAN DEFAULT FALSE,
1562
   *      onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
1563
   */
1564
185
   BER_Decoder outer(buf, BER_Decoder::Limits::DER());
1565
185
   BER_Decoder seq = outer.start_sequence();
1566
1567
185
   m_dp_name.reset();
1568
185
   m_only_contains_user_certs = false;
1569
185
   m_only_contains_ca_certs = false;
1570
185
   m_only_some_reasons = {};
1571
185
   m_indirect_crl = false;
1572
185
   m_only_contains_attribute_certs = false;
1573
1574
185
   auto decode_implicit_bool = [&](BER_Decoder& dec, uint32_t tag) -> bool {
1575
35
      bool value = false;
1576
35
      dec.decode(value, ASN1_Type(tag), ASN1_Class::ContextSpecific);
1577
35
      return value;
1578
35
   };
1579
1580
   // DER: these optional fields appear at most once and in increasing tag
1581
   // order. Decoding them in tag order and then rejecting anything left over
1582
   // (see end_cons below) catches out-of-order, duplicate, and unknown fields.
1583
185
   seq.decode_optional_field(0,
1584
185
                             ASN1_Class::ContextSpecific | ASN1_Class::Constructed,
1585
185
                             [&](BER_Decoder& d) {
1586
36
                                DistributionPointName name;
1587
36
                                d.start_context_specific(0).decode(name).verify_end();
1588
36
                                m_dp_name = std::move(name);
1589
36
                             })
1590
185
      .decode_optional_field(1,
1591
185
                             ASN1_Class::ContextSpecific,
1592
185
                             [&](BER_Decoder& d) { m_only_contains_user_certs = decode_implicit_bool(d, 1); })
1593
185
      .decode_optional_field(
1594
185
         2, ASN1_Class::ContextSpecific, [&](BER_Decoder& d) { m_only_contains_ca_certs = decode_implicit_bool(d, 2); })
1595
185
      .decode_optional_field(3,
1596
185
                             ASN1_Class::ContextSpecific,
1597
185
                             [&](BER_Decoder& d) { m_only_some_reasons = decode_reason_flags_implicit(d, 3); })
1598
185
      .decode_optional_field(
1599
185
         4, ASN1_Class::ContextSpecific, [&](BER_Decoder& d) { m_indirect_crl = decode_implicit_bool(d, 4); })
1600
185
      .decode_optional_field(5, ASN1_Class::ContextSpecific, [&](BER_Decoder& d) {
1601
6
         m_only_contains_attribute_certs = decode_implicit_bool(d, 5);
1602
6
      });
1603
1604
185
   seq.end_cons();
1605
185
   outer.verify_end();
1606
1607
   /* RFC 5280 5.2.5: "Conforming CRLs issuers MUST NOT issue CRLs where the
1608
   * DER encoding of the issuing distribution point extension is an empty
1609
   * sequence." Empty here means none of the fields above were present. */
1610
185
   if(!m_dp_name.has_value() && !m_only_contains_user_certs && !m_only_contains_ca_certs &&
1611
0
      !m_only_some_reasons.has_value() && !m_indirect_crl && !m_only_contains_attribute_certs) {
1612
0
      throw Decoding_Error("IssuingDistributionPoint must contain at least one field");
1613
0
   }
1614
1615
   /* RFC 5280 5.2.5: "at most one of onlyContainsUserCerts,
1616
   * onlyContainsCACerts, and onlyContainsAttributeCerts may be set to TRUE." */
1617
185
   const size_t scope_set = static_cast<size_t>(m_only_contains_user_certs) +
1618
185
                            static_cast<size_t>(m_only_contains_ca_certs) +
1619
185
                            static_cast<size_t>(m_only_contains_attribute_certs);
1620
185
   if(scope_set > 1) {
1621
0
      throw Decoding_Error(
1622
0
         "IssuingDistributionPoint sets more than one of onlyContainsUserCerts/CACerts/AttributeCerts");
1623
0
   }
1624
185
}
1625
1626
0
void TNAuthList::Entry::encode_into(DER_Encoder& /*to*/) const {
1627
0
   throw Not_Implemented("TNAuthList extension entry serialization is not supported");
1628
0
}
1629
1630
267
void TNAuthList::Entry::decode_from(class BER_Decoder& ber) {
1631
267
   const BER_Object obj = ber.get_next_object();
1632
1633
267
   if(obj.get_class() != (ASN1_Class::ContextSpecific | ASN1_Class::Constructed)) {
1634
32
      throw Decoding_Error(fmt("Unexpected TNEntry class tag {}", static_cast<uint32_t>(obj.get_class())));
1635
32
   }
1636
1637
235
   const uint32_t type_tag = static_cast<uint32_t>(obj.type_tag());
1638
1639
235
   if(type_tag == ServiceProviderCode) {
1640
76
      m_type = ServiceProviderCode;
1641
76
      ASN1_String spc_string;
1642
76
      BER_Decoder(obj, ber.limits()).decode(spc_string).verify_end();
1643
76
      m_data = std::move(spc_string);
1644
159
   } else if(type_tag == TelephoneNumberRange) {
1645
101
      m_type = TelephoneNumberRange;
1646
101
      m_data = RangeContainer();
1647
101
      auto& range_items = std::get<RangeContainer>(m_data);
1648
101
      BER_Decoder outer(obj, ber.limits());
1649
101
      BER_Decoder list = outer.start_sequence();
1650
209
      while(list.more_items()) {
1651
143
         TelephoneNumberRangeData entry;
1652
1653
143
         list.decode(entry.start);
1654
143
         if(!is_valid_telephone_number(entry.start)) {
1655
31
            throw Decoding_Error(fmt("Invalid TelephoneNumberRange start {}", entry.start.value()));
1656
31
         }
1657
1658
112
         list.decode(entry.count);
1659
112
         if(entry.count < 2) {
1660
4
            throw Decoding_Error(fmt("Invalid TelephoneNumberRange count {}", entry.count));
1661
4
         }
1662
1663
108
         range_items.emplace_back(std::move(entry));
1664
108
      }
1665
66
      list.end_cons();
1666
66
      outer.verify_end();
1667
1668
66
      if(range_items.empty()) {
1669
4
         throw Decoding_Error("TelephoneNumberRange is empty");
1670
4
      }
1671
66
   } else if(type_tag == TelephoneNumber) {
1672
32
      m_type = TelephoneNumber;
1673
32
      ASN1_String one_string;
1674
32
      BER_Decoder(obj, ber.limits()).decode(one_string).verify_end();
1675
32
      if(!is_valid_telephone_number(one_string)) {
1676
10
         throw Decoding_Error(fmt("Invalid TelephoneNumber {}", one_string.value()));
1677
10
      }
1678
22
      m_data = std::move(one_string);
1679
26
   } else {
1680
26
      throw Decoding_Error(fmt("Unexpected TNEntry type code {}", type_tag));
1681
160
   };
1682
160
}
1683
1684
0
std::vector<uint8_t> TNAuthList::encode_inner() const {
1685
0
   throw Not_Implemented("TNAuthList extension serialization is not supported");
1686
0
}
1687
1688
217
void TNAuthList::decode_inner(const std::vector<uint8_t>& in) {
1689
   /* RFC 8226 Section 9 - TNAuthorizationList ::= SEQUENCE SIZE (1..MAX) OF TNEntry */
1690
217
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode_list(m_tn_entries).verify_end();
1691
217
   if(m_tn_entries.empty()) {
1692
4
      throw Decoding_Error("TNAuthorizationList is empty");
1693
4
   }
1694
217
}
1695
1696
0
const std::string& TNAuthList::Entry::service_provider_code() const {
1697
0
   BOTAN_STATE_CHECK(type() == Type::ServiceProviderCode);
1698
0
   return std::get<ASN1_String>(m_data).value();
1699
0
}
1700
1701
0
const TNAuthList::Entry::RangeContainer& TNAuthList::Entry::telephone_number_range() const {
1702
0
   BOTAN_STATE_CHECK(type() == Type::TelephoneNumberRange);
1703
0
   return std::get<RangeContainer>(m_data);
1704
0
}
1705
1706
0
const std::string& TNAuthList::Entry::telephone_number() const {
1707
0
   BOTAN_STATE_CHECK(type() == Type::TelephoneNumber);
1708
0
   return std::get<ASN1_String>(m_data).value();
1709
0
}
1710
1711
0
std::vector<uint8_t> IPAddressBlocks::encode_inner() const {
1712
0
   std::vector<uint8_t> output;
1713
0
   DER_Encoder(output).start_sequence().encode_list(m_ip_addr_blocks).end_cons();
1714
0
   return output;
1715
0
}
1716
1717
1.27k
void IPAddressBlocks::decode_inner(const std::vector<uint8_t>& in) {
1718
   /* RFC 3779 Section 2.2.3.1 - IPAddrBlocks ::= SEQUENCE OF IPAddressFamily */
1719
1.27k
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode_list(m_ip_addr_blocks).verify_end();
1720
1.27k
   sort_and_merge();
1721
1.27k
}
1722
1723
0
void IPAddressBlocks::IPAddressFamily::encode_into(Botan::DER_Encoder& into) const {
1724
0
   into.start_sequence();
1725
1726
0
   std::vector<uint8_t> afam = {get_byte<0>(m_afi), get_byte<1>(m_afi)};
1727
1728
0
   if(m_safi.has_value()) {
1729
0
      afam.push_back(m_safi.value());
1730
0
   }
1731
1732
0
   into.add_object(ASN1_Type::OctetString, ASN1_Class::Universal, afam);
1733
1734
0
   if(std::holds_alternative<IPAddressChoice<Version::IPv4>>(m_ip_addr_choice)) {
1735
0
      into.encode(std::get<IPAddressChoice<Version::IPv4>>(m_ip_addr_choice));
1736
0
   } else {
1737
0
      into.encode(std::get<IPAddressChoice<Version::IPv6>>(m_ip_addr_choice));
1738
0
   }
1739
0
   into.end_cons();
1740
0
}
1741
1742
1.42k
void IPAddressBlocks::IPAddressFamily::decode_from(Botan::BER_Decoder& from) {
1743
1.42k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
1744
1.42k
   if(next_tag != ASN1_Type::Sequence) {
1745
79
      throw Decoding_Error(fmt("Unexpected type for IPAddressFamily {}", static_cast<uint32_t>(next_tag)));
1746
79
   }
1747
1748
1.34k
   BER_Decoder seq_dec = from.start_sequence();
1749
1750
1.34k
   std::vector<uint8_t> addr_family;
1751
1.34k
   seq_dec.decode(addr_family, ASN1_Type::OctetString);
1752
1.34k
   const size_t addr_family_length = addr_family.size();
1753
1754
1.34k
   if(addr_family_length != 2 && addr_family_length != 3) {
1755
13
      throw Decoding_Error("(S)AFI can only contain 2 or 3 bytes");
1756
13
   }
1757
1758
1.33k
   m_afi = (addr_family[0] << 8) | addr_family[1];
1759
1760
1.33k
   if(addr_family_length == 3) {
1761
867
      m_safi = addr_family[2];
1762
867
   }
1763
1764
1.33k
   if(m_afi == 1) {
1765
532
      IPAddressChoice<Version::IPv4> addr_choice;
1766
532
      seq_dec.decode(addr_choice);
1767
532
      m_ip_addr_choice = addr_choice;
1768
800
   } else if(m_afi == 2) {
1769
576
      IPAddressChoice<Version::IPv6> addr_choice;
1770
576
      seq_dec.decode(addr_choice);
1771
576
      m_ip_addr_choice = addr_choice;
1772
576
   } else {
1773
224
      throw Decoding_Error("Only AFI IPv4 and IPv6 are supported.");
1774
224
   }
1775
1776
1.10k
   seq_dec.end_cons();
1777
1.10k
}
1778
1779
3
void IPAddressBlocks::sort_and_merge() {
1780
   // Sort IPAddressFamilies by afi/safi values
1781
   //
1782
   // see: https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.3
1783
   //
1784
   // v4 families are ordered before v6 families (i.e. they are sorted by afis, primarily),
1785
   // families with no safis are ordered before families with safis
1786
   //
1787
   // families with the same afi/safi combination are then merged
1788
1789
   // std::map is ordered, so using a pair (afi, optional(safi)) here works - std::nullopt is sorted before any actual values
1790
3
   std::map<std::pair<uint16_t, std::optional<uint8_t>>, std::vector<IPAddressFamily>> afam_map;
1791
3
   for(const IPAddressFamily& block : m_ip_addr_blocks) {
1792
0
      auto key = std::make_pair(block.afi(), block.safi());
1793
0
      std::vector<IPAddressFamily>& fams = afam_map[key];
1794
0
      fams.push_back(block);
1795
0
   }
1796
1797
3
   std::vector<IPAddressFamily> merged_blocks;
1798
3
   size_t v4_count = 0;
1799
3
   size_t v6_count = 0;
1800
3
   for(auto& it : afam_map) {
1801
      // fams consists of families with the same afi/safi combination
1802
0
      std::vector<IPAddressFamily>& fams = it.second;
1803
      // since at least 1 block has to belong to a afi/safi combination for it to appear in the map,
1804
      // fams cannot be empty
1805
0
      BOTAN_ASSERT_NOMSG(!fams.empty());
1806
1807
      // fams[0] has to have the same choice type as the fams in the same bucket
1808
0
      if(std::holds_alternative<IPAddressChoice<Version::IPv4>>(fams[0].addr_choice())) {
1809
0
         merged_blocks.push_back(merge<Version::IPv4>(fams));
1810
0
         v4_count++;
1811
0
      } else {
1812
0
         merged_blocks.push_back(merge<Version::IPv6>(fams));
1813
0
         v6_count++;
1814
0
      }
1815
0
   }
1816
3
   BOTAN_ASSERT_NOMSG(v4_count + v6_count == merged_blocks.size());
1817
3
   m_ip_addr_blocks = merged_blocks;
1818
3
   m_v4_count = v4_count;
1819
3
   m_v6_count = v6_count;
1820
3
}
1821
1822
template <IPAddressBlocks::Version V>
1823
0
IPAddressBlocks::IPAddressFamily IPAddressBlocks::merge(std::vector<IPAddressFamily>& blocks) {
1824
   // Merge IPAddressFamilies that have the same afi/safi combination
1825
   //
1826
   // see: https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.3
1827
1828
0
   BOTAN_ASSERT(!blocks.empty(), "Cannot merge an empty set of IP address blocks into a single family");
1829
1830
   // nothing to merge
1831
0
   if(blocks.size() == 1) {
1832
0
      return blocks[0];
1833
0
   }
1834
1835
0
   bool all_inherit = true;
1836
0
   bool none_inherit = true;
1837
0
   for(const IPAddressFamily& block : blocks) {
1838
0
      const IPAddressChoice<V> choice = std::get<IPAddressChoice<V>>(block.addr_choice());
1839
0
      all_inherit = !choice.ranges().has_value() && all_inherit;  // all the blocks have the 'inherit' value
1840
0
      none_inherit = choice.ranges().has_value() && none_inherit;
1841
0
   }
1842
1843
   // they are all 'inherit', short-circuit using default constructor for nullopt
1844
0
   if(all_inherit) {
1845
0
      return IPAddressFamily(IPAddressChoice<V>(), blocks[0].safi());
1846
0
   }
1847
1848
   // some are inherit, and some have values - no sensible way to merge them
1849
0
   if(!all_inherit && !none_inherit) {
1850
0
      throw Decoding_Error("Invalid IPAddressBlocks: Only one of 'inherit' or 'do not inherit' is allowed per family");
1851
0
   }
1852
1853
0
   std::vector<IPAddressOrRange<V>> merged_ranges;
1854
0
   for(const IPAddressFamily& block : blocks) {
1855
0
      const IPAddressChoice<V> choice = std::get<IPAddressChoice<V>>(block.addr_choice());
1856
0
      const std::vector<IPAddressOrRange<V>> ranges = choice.ranges().value();
1857
0
      for(const IPAddressOrRange<V>& r : ranges) {
1858
0
         merged_ranges.push_back(r);
1859
0
      }
1860
0
   }
1861
1862
   // we have extracted all the ranges, and now rely on the constructor of IPAddressChoice to merge them
1863
0
   IPAddressChoice<V> choice(merged_ranges);
1864
0
   IPAddressFamily fam(choice, blocks[0].safi());
1865
0
   return fam;
1866
0
}
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily Botan::Cert_Extension::IPAddressBlocks::merge<(Botan::Cert_Extension::IPAddressBlocks::Version)4>(std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily> >&)
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily Botan::Cert_Extension::IPAddressBlocks::merge<(Botan::Cert_Extension::IPAddressBlocks::Version)16>(std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressFamily> >&)
1867
1868
namespace {
1869
1870
constexpr auto IPv4 = IPAddressBlocks::Version::IPv4;
1871
constexpr auto IPv6 = IPAddressBlocks::Version::IPv6;
1872
1873
template <IPAddressBlocks::Version V>
1874
using IPRangeVec = std::vector<IPAddressBlocks::IPAddressOrRange<V>>;
1875
1876
// (S)AFI -> (needs_check, ptr to IPRangeVec)
1877
// the pointer can be null, in which case the boolean will be false, as such the pointer's value will never be looked at
1878
template <IPAddressBlocks::Version V>
1879
using IPValidationMap = std::map<uint32_t, std::pair<bool, const IPRangeVec<V>*>>;
1880
1881
template <typename T>
1882
1.90k
std::optional<std::vector<T>> sort_and_merge_ranges(std::optional<std::span<const T>> ranges) {
1883
   // Sort and merge overlapping/adjacent IPAddressOrRange or ASIdOrRange objects.
1884
   // cf. https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.6 and https://www.rfc-editor.org/rfc/rfc3779.html#section-3.2.3.4
1885
   // This implementation uses only min-max ranges internally, so sorting by the prefix length is not necessary / impossible here.
1886
1887
1.90k
   if(!ranges.has_value()) {
1888
0
      return std::nullopt;
1889
0
   }
1890
1891
1.90k
   std::vector<T> sorted(ranges.value().begin(), ranges.value().end());
1892
1893
1.90k
   if(sorted.empty()) {
1894
73
      return sorted;
1895
73
   }
1896
1897
   // sort by the min value
1898
10.0k
   std::sort(sorted.begin(), sorted.end(), [](T& a, T& b) { return a.min() < b.min(); });
x509_ext.cpp:Botan::Cert_Extension::(anonymous namespace)::sort_and_merge_ranges<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> >(std::__1::optional<std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> const, 18446744073709551615ul> >)::{lambda(Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>&, Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>&)#1}::operator()(Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>&, Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>&) const
Line
Count
Source
1898
1.12k
   std::sort(sorted.begin(), sorted.end(), [](T& a, T& b) { return a.min() < b.min(); });
x509_ext.cpp:Botan::Cert_Extension::(anonymous namespace)::sort_and_merge_ranges<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> >(std::__1::optional<std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> const, 18446744073709551615ul> >)::{lambda(Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>&, Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>&)#1}::operator()(Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>&, Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>&) const
Line
Count
Source
1898
1.48k
   std::sort(sorted.begin(), sorted.end(), [](T& a, T& b) { return a.min() < b.min(); });
x509_ext.cpp:Botan::Cert_Extension::(anonymous namespace)::sort_and_merge_ranges<Botan::Cert_Extension::ASBlocks::ASIdOrRange>(std::__1::optional<std::__1::span<Botan::Cert_Extension::ASBlocks::ASIdOrRange const, 18446744073709551615ul> >)::{lambda(Botan::Cert_Extension::ASBlocks::ASIdOrRange&, Botan::Cert_Extension::ASBlocks::ASIdOrRange&)#1}::operator()(Botan::Cert_Extension::ASBlocks::ASIdOrRange&, Botan::Cert_Extension::ASBlocks::ASIdOrRange&) const
Line
Count
Source
1898
7.48k
   std::sort(sorted.begin(), sorted.end(), [](T& a, T& b) { return a.min() < b.min(); });
1899
1900
   // Single-pass merge: extend the last merged range or start a new one
1901
1.83k
   std::vector<T> merged;
1902
1.83k
   merged.reserve(sorted.size());
1903
1.83k
   merged.push_back(sorted[0]);
1904
1905
7.49k
   for(size_t i = 1; i < sorted.size(); ++i) {
1906
5.65k
      auto& back = merged.back();
1907
      // they either overlap or are adjacent
1908
5.65k
      if(sorted[i].min() <= back.max() || sorted[i].min() == (back.max() + 1)) {
1909
996
         back = T(back.min(), std::max(back.max(), sorted[i].max()));
1910
4.66k
      } else {
1911
4.66k
         merged.push_back(sorted[i]);
1912
4.66k
      }
1913
5.65k
   }
1914
1915
1.83k
   return merged;
1916
1.90k
}
x509_ext.cpp:std::__1::optional<std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > > Botan::Cert_Extension::(anonymous namespace)::sort_and_merge_ranges<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> >(std::__1::optional<std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> const, 18446744073709551615ul> >)
Line
Count
Source
1882
241
std::optional<std::vector<T>> sort_and_merge_ranges(std::optional<std::span<const T>> ranges) {
1883
   // Sort and merge overlapping/adjacent IPAddressOrRange or ASIdOrRange objects.
1884
   // cf. https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.6 and https://www.rfc-editor.org/rfc/rfc3779.html#section-3.2.3.4
1885
   // This implementation uses only min-max ranges internally, so sorting by the prefix length is not necessary / impossible here.
1886
1887
241
   if(!ranges.has_value()) {
1888
0
      return std::nullopt;
1889
0
   }
1890
1891
241
   std::vector<T> sorted(ranges.value().begin(), ranges.value().end());
1892
1893
241
   if(sorted.empty()) {
1894
29
      return sorted;
1895
29
   }
1896
1897
   // sort by the min value
1898
212
   std::sort(sorted.begin(), sorted.end(), [](T& a, T& b) { return a.min() < b.min(); });
1899
1900
   // Single-pass merge: extend the last merged range or start a new one
1901
212
   std::vector<T> merged;
1902
212
   merged.reserve(sorted.size());
1903
212
   merged.push_back(sorted[0]);
1904
1905
846
   for(size_t i = 1; i < sorted.size(); ++i) {
1906
634
      auto& back = merged.back();
1907
      // they either overlap or are adjacent
1908
634
      if(sorted[i].min() <= back.max() || sorted[i].min() == (back.max() + 1)) {
1909
351
         back = T(back.min(), std::max(back.max(), sorted[i].max()));
1910
351
      } else {
1911
283
         merged.push_back(sorted[i]);
1912
283
      }
1913
634
   }
1914
1915
212
   return merged;
1916
241
}
x509_ext.cpp:std::__1::optional<std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > > Botan::Cert_Extension::(anonymous namespace)::sort_and_merge_ranges<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> >(std::__1::optional<std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> const, 18446744073709551615ul> >)
Line
Count
Source
1882
304
std::optional<std::vector<T>> sort_and_merge_ranges(std::optional<std::span<const T>> ranges) {
1883
   // Sort and merge overlapping/adjacent IPAddressOrRange or ASIdOrRange objects.
1884
   // cf. https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.6 and https://www.rfc-editor.org/rfc/rfc3779.html#section-3.2.3.4
1885
   // This implementation uses only min-max ranges internally, so sorting by the prefix length is not necessary / impossible here.
1886
1887
304
   if(!ranges.has_value()) {
1888
0
      return std::nullopt;
1889
0
   }
1890
1891
304
   std::vector<T> sorted(ranges.value().begin(), ranges.value().end());
1892
1893
304
   if(sorted.empty()) {
1894
31
      return sorted;
1895
31
   }
1896
1897
   // sort by the min value
1898
273
   std::sort(sorted.begin(), sorted.end(), [](T& a, T& b) { return a.min() < b.min(); });
1899
1900
   // Single-pass merge: extend the last merged range or start a new one
1901
273
   std::vector<T> merged;
1902
273
   merged.reserve(sorted.size());
1903
273
   merged.push_back(sorted[0]);
1904
1905
1.11k
   for(size_t i = 1; i < sorted.size(); ++i) {
1906
839
      auto& back = merged.back();
1907
      // they either overlap or are adjacent
1908
839
      if(sorted[i].min() <= back.max() || sorted[i].min() == (back.max() + 1)) {
1909
349
         back = T(back.min(), std::max(back.max(), sorted[i].max()));
1910
490
      } else {
1911
490
         merged.push_back(sorted[i]);
1912
490
      }
1913
839
   }
1914
1915
273
   return merged;
1916
304
}
x509_ext.cpp:std::__1::optional<std::__1::vector<Botan::Cert_Extension::ASBlocks::ASIdOrRange, std::__1::allocator<Botan::Cert_Extension::ASBlocks::ASIdOrRange> > > Botan::Cert_Extension::(anonymous namespace)::sort_and_merge_ranges<Botan::Cert_Extension::ASBlocks::ASIdOrRange>(std::__1::optional<std::__1::span<Botan::Cert_Extension::ASBlocks::ASIdOrRange const, 18446744073709551615ul> >)
Line
Count
Source
1882
1.36k
std::optional<std::vector<T>> sort_and_merge_ranges(std::optional<std::span<const T>> ranges) {
1883
   // Sort and merge overlapping/adjacent IPAddressOrRange or ASIdOrRange objects.
1884
   // cf. https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.6 and https://www.rfc-editor.org/rfc/rfc3779.html#section-3.2.3.4
1885
   // This implementation uses only min-max ranges internally, so sorting by the prefix length is not necessary / impossible here.
1886
1887
1.36k
   if(!ranges.has_value()) {
1888
0
      return std::nullopt;
1889
0
   }
1890
1891
1.36k
   std::vector<T> sorted(ranges.value().begin(), ranges.value().end());
1892
1893
1.36k
   if(sorted.empty()) {
1894
13
      return sorted;
1895
13
   }
1896
1897
   // sort by the min value
1898
1.35k
   std::sort(sorted.begin(), sorted.end(), [](T& a, T& b) { return a.min() < b.min(); });
1899
1900
   // Single-pass merge: extend the last merged range or start a new one
1901
1.35k
   std::vector<T> merged;
1902
1.35k
   merged.reserve(sorted.size());
1903
1.35k
   merged.push_back(sorted[0]);
1904
1905
5.53k
   for(size_t i = 1; i < sorted.size(); ++i) {
1906
4.18k
      auto& back = merged.back();
1907
      // they either overlap or are adjacent
1908
4.18k
      if(sorted[i].min() <= back.max() || sorted[i].min() == (back.max() + 1)) {
1909
296
         back = T(back.min(), std::max(back.max(), sorted[i].max()));
1910
3.89k
      } else {
1911
3.89k
         merged.push_back(sorted[i]);
1912
3.89k
      }
1913
4.18k
   }
1914
1915
1.35k
   return merged;
1916
1.36k
}
1917
1918
template <typename T>
1919
0
bool validate_subject_in_issuer(std::span<const T> subject, std::span<const T> issuer) {
1920
   // ensures that the subject ranges are enclosed by the issuer ranges
1921
   // both vectors are already sorted, so we can do this in O(n+m)
1922
1923
   // the issuer has 0 ranges to validate against, so this can only work if the subject also has none
1924
0
   if(issuer.empty()) {
1925
0
      return subject.empty();
1926
0
   }
1927
0
   for(auto subj = subject.begin(), issu = issuer.begin(); subj != subject.end();) {
1928
      // the issuer range is smaller than the subject range, step to the next issuer range to check next round
1929
0
      if(subj->min() > issu->max()) {
1930
0
         issu++;
1931
         // we have run out of issuer ranges, but still have subject ranges left to validate
1932
0
         if(issu == issuer.end() && subj != subject.end()) {
1933
0
            return false;
1934
0
         }
1935
0
      } else {
1936
         // the subject is outside of the closest issuer range on the left (min) side
1937
0
         if(subj->min() < issu->min()) {
1938
0
            return false;
1939
0
         }
1940
         // the subject is outside of the closest issuer range on the right (max) side
1941
0
         if(subj->max() > issu->max()) {
1942
0
            return false;
1943
0
         }
1944
         // this range is contained within the issuer, advance to the next subject range
1945
0
         subj++;
1946
0
      }
1947
0
   }
1948
0
   return true;
1949
0
}
Unexecuted instantiation: x509_ext.cpp:bool Botan::Cert_Extension::(anonymous namespace)::validate_subject_in_issuer<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> >(std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> const, 18446744073709551615ul>, std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> const, 18446744073709551615ul>)
Unexecuted instantiation: x509_ext.cpp:bool Botan::Cert_Extension::(anonymous namespace)::validate_subject_in_issuer<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> >(std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> const, 18446744073709551615ul>, std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> const, 18446744073709551615ul>)
Unexecuted instantiation: x509_ext.cpp:bool Botan::Cert_Extension::(anonymous namespace)::validate_subject_in_issuer<Botan::Cert_Extension::ASBlocks::ASIdOrRange>(std::__1::span<Botan::Cert_Extension::ASBlocks::ASIdOrRange const, 18446744073709551615ul>, std::__1::span<Botan::Cert_Extension::ASBlocks::ASIdOrRange const, 18446744073709551615ul>)
1950
1951
template <IPAddressBlocks::Version V>
1952
void populate_validation_map(uint32_t afam,
1953
                             const IPAddressBlocks::IPAddressFamily::AddrChoice& choice,
1954
0
                             IPValidationMap<V>& map) {
1955
0
   const std::optional<IPRangeVec<V>>& ranges = std::get<IPAddressBlocks::IPAddressChoice<V>>(choice).ranges();
1956
0
   const bool has_value = ranges.has_value();
1957
0
   const IPRangeVec<V>* value = has_value ? &ranges.value() : nullptr;
1958
0
   map.emplace(afam, std::make_pair(has_value, std::move(value)));
1959
0
}
Unexecuted instantiation: x509_ext.cpp:void Botan::Cert_Extension::(anonymous namespace)::populate_validation_map<(Botan::Cert_Extension::IPAddressBlocks::Version)4>(unsigned int, std::__1::variant<Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > const&, std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > >&)
Unexecuted instantiation: x509_ext.cpp:void Botan::Cert_Extension::(anonymous namespace)::populate_validation_map<(Botan::Cert_Extension::IPAddressBlocks::Version)16>(unsigned int, std::__1::variant<Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > const&, std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > >&)
1960
1961
std::pair<IPValidationMap<IPv4>, IPValidationMap<IPv6>> create_validation_map(
1962
0
   const std::vector<IPAddressBlocks::IPAddressFamily>& addr_blocks) {
1963
0
   IPValidationMap<IPv4> v4_map;
1964
0
   IPValidationMap<IPv6> v6_map;
1965
1966
0
   for(const IPAddressBlocks::IPAddressFamily& block : addr_blocks) {
1967
0
      uint32_t afam = block.afi();
1968
0
      if(block.safi().has_value()) {
1969
0
         afam = static_cast<uint32_t>(afam << 8) | block.safi().value();
1970
0
      }
1971
1972
0
      const IPAddressBlocks::IPAddressFamily::AddrChoice& a_choice = block.addr_choice();
1973
0
      if(std::holds_alternative<IPAddressBlocks::IPAddressChoice<IPv4>>(a_choice)) {
1974
0
         populate_validation_map(afam, a_choice, v4_map);
1975
0
      } else {
1976
0
         populate_validation_map(afam, a_choice, v6_map);
1977
0
      }
1978
0
   }
1979
1980
0
   return std::make_pair(v4_map, v6_map);
1981
0
}
1982
1983
}  // namespace
1984
1985
template <IPAddressBlocks::Version V>
1986
IPAddressBlocks::IPAddressChoice<V>::IPAddressChoice(
1987
0
   std::optional<std::span<const IPAddressBlocks::IPAddressOrRange<V>>> ranges) {
1988
   // NOLINTNEXTLINE(*-prefer-member-initializer)
1989
0
   m_ip_addr_ranges = sort_and_merge_ranges<IPAddressOrRange<V>>(ranges);
1990
0
}
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)4>::IPAddressChoice(std::__1::optional<std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> const, 18446744073709551615ul> >)
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)16>::IPAddressChoice(std::__1::optional<std::__1::span<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> const, 18446744073709551615ul> >)
1991
1992
template <IPAddressBlocks::Version V>
1993
0
void IPAddressBlocks::IPAddressChoice<V>::encode_into(Botan::DER_Encoder& into) const {
1994
0
   if(m_ip_addr_ranges.has_value()) {
1995
0
      into.start_sequence().encode_list(m_ip_addr_ranges.value()).end_cons();
1996
0
   } else {
1997
0
      into.encode_null();
1998
0
   }
1999
0
}
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)4>::encode_into(Botan::DER_Encoder&) const
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)16>::encode_into(Botan::DER_Encoder&) const
2000
2001
template <IPAddressBlocks::Version V>
2002
1.10k
void IPAddressBlocks::IPAddressChoice<V>::decode_from(Botan::BER_Decoder& from) {
2003
1.10k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2004
2005
1.10k
   if(next_tag == ASN1_Type::Null) {
2006
51
      from.decode_null();
2007
51
      m_ip_addr_ranges = std::nullopt;
2008
1.05k
   } else if(next_tag == ASN1_Type::Sequence) {
2009
899
      std::vector<IPAddressOrRange<V>> ip_ranges;
2010
899
      from.decode_list(ip_ranges);
2011
899
      m_ip_addr_ranges = sort_and_merge_ranges<IPAddressOrRange<V>>(ip_ranges);
2012
899
   } else {
2013
158
      throw Decoding_Error(fmt("Unexpected type for IPAddressChoice {}", static_cast<uint32_t>(next_tag)));
2014
158
   }
2015
1.10k
}
Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)4>::decode_from(Botan::BER_Decoder&)
Line
Count
Source
2002
532
void IPAddressBlocks::IPAddressChoice<V>::decode_from(Botan::BER_Decoder& from) {
2003
532
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2004
2005
532
   if(next_tag == ASN1_Type::Null) {
2006
23
      from.decode_null();
2007
23
      m_ip_addr_ranges = std::nullopt;
2008
509
   } else if(next_tag == ASN1_Type::Sequence) {
2009
413
      std::vector<IPAddressOrRange<V>> ip_ranges;
2010
413
      from.decode_list(ip_ranges);
2011
413
      m_ip_addr_ranges = sort_and_merge_ranges<IPAddressOrRange<V>>(ip_ranges);
2012
413
   } else {
2013
96
      throw Decoding_Error(fmt("Unexpected type for IPAddressChoice {}", static_cast<uint32_t>(next_tag)));
2014
96
   }
2015
532
}
Botan::Cert_Extension::IPAddressBlocks::IPAddressChoice<(Botan::Cert_Extension::IPAddressBlocks::Version)16>::decode_from(Botan::BER_Decoder&)
Line
Count
Source
2002
576
void IPAddressBlocks::IPAddressChoice<V>::decode_from(Botan::BER_Decoder& from) {
2003
576
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2004
2005
576
   if(next_tag == ASN1_Type::Null) {
2006
28
      from.decode_null();
2007
28
      m_ip_addr_ranges = std::nullopt;
2008
548
   } else if(next_tag == ASN1_Type::Sequence) {
2009
486
      std::vector<IPAddressOrRange<V>> ip_ranges;
2010
486
      from.decode_list(ip_ranges);
2011
486
      m_ip_addr_ranges = sort_and_merge_ranges<IPAddressOrRange<V>>(ip_ranges);
2012
486
   } else {
2013
62
      throw Decoding_Error(fmt("Unexpected type for IPAddressChoice {}", static_cast<uint32_t>(next_tag)));
2014
62
   }
2015
576
}
2016
2017
template <IPAddressBlocks::Version V>
2018
0
void IPAddressBlocks::IPAddressOrRange<V>::encode_into(Botan::DER_Encoder& into) const {
2019
   // Compress IPAddressOrRange as much as possible
2020
   // cf. https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.7 - https://www.rfc-editor.org/rfc/rfc3779.html#section-2.2.3.9
2021
   //
2022
   // If possible encode as a prefix x.x.x.x/x, else encode as a range of min-max.
2023
   // Single addresses are encoded as is (technically a /32 or /128 prefix).
2024
   //
2025
   // A range can be encoded as a prefix if the lowest n bits of the min address are 0
2026
   // and the highest n bits of the max address are 1, or in other words, contiguous sequences of 0s and 1s are omitted.
2027
   // To make reconstruction possible, an 'unused' octet is included at the start, since in the case of e.g. /25 only
2028
   // the highest bit of the last octet is actually meaningful.
2029
   //
2030
   // If encoding requires a range, the individual elements can still be compressed using the above method,
2031
   // but the number of used bits varies between them.
2032
2033
0
   const size_t version_octets = static_cast<size_t>(V);
2034
2035
0
   std::array<uint8_t, version_octets> min = m_min.value();
2036
0
   std::array<uint8_t, version_octets> max = m_max.value();
2037
2038
0
   uint8_t zeros = 0;
2039
0
   uint8_t ones = 0;
2040
2041
0
   bool zeros_done = false;
2042
0
   bool ones_done = false;
2043
2044
   // count contiguous 0s/1s from the right of the min/max addresses
2045
0
   for(size_t i = version_octets; i > 0; i--) {
2046
0
      if(!zeros_done) {
2047
0
         const uint8_t local_zeros = static_cast<uint8_t>(std::countr_zero(min[i - 1]));
2048
0
         zeros += local_zeros;
2049
0
         zeros_done = (local_zeros != 8);
2050
0
      }
2051
2052
0
      if(!ones_done) {
2053
0
         const uint8_t local_ones = static_cast<uint8_t>(std::countr_one(max[i - 1]));
2054
0
         ones += local_ones;
2055
0
         ones_done = (local_ones != 8);
2056
0
      }
2057
2058
0
      if(zeros_done && ones_done) {
2059
0
         break;
2060
0
      }
2061
0
   }
2062
2063
   // the part we want to compress
2064
0
   const uint8_t host = std::min(zeros, ones);
2065
2066
   // these we can outright drop
2067
0
   const uint8_t discarded_octets = host / 8;
2068
   // in a partially used octet
2069
0
   const uint8_t unused_bits = host % 8;
2070
2071
0
   bool octets_match = true;
2072
0
   bool used_bits_match = true;
2073
2074
   // we have octets to check
2075
0
   if(discarded_octets < version_octets) {
2076
      // check all but the last octet
2077
0
      for(size_t i = 0; i < static_cast<uint8_t>(version_octets - discarded_octets - 1); i++) {
2078
0
         if(min[i] != max[i]) {
2079
0
            octets_match = false;
2080
0
            break;
2081
0
         }
2082
0
      }
2083
      // check the last significant octet if we have matched so far
2084
0
      if(octets_match) {
2085
0
         const uint8_t shifted_min = (min[version_octets - 1 - discarded_octets] >> unused_bits);
2086
0
         const uint8_t shifted_max = (max[version_octets - 1 - discarded_octets] >> unused_bits);
2087
0
         used_bits_match = (shifted_min == shifted_max);
2088
0
      }
2089
0
   }
2090
2091
   // both the full octets and the partially used one match
2092
0
   if(octets_match && used_bits_match) {
2093
      // at this point the range can be encoded as a prefix
2094
0
      into.encode_bitstring(std::span{min}.first(version_octets - discarded_octets), unused_bits);
2095
0
   } else {
2096
0
      const uint8_t discarded_octets_min = zeros / 8;
2097
0
      const uint8_t unused_bits_min = zeros % 8;
2098
2099
0
      const uint8_t discarded_octets_max = ones / 8;
2100
0
      const uint8_t unused_bits_max = ones % 8;
2101
2102
      // compress the max address by setting unused bits to 0, for the min address these are already 0
2103
0
      if(unused_bits_max != 0) {
2104
0
         BOTAN_ASSERT_NOMSG(discarded_octets_max < version_octets);
2105
0
         max[version_octets - 1 - discarded_octets_max] >>= unused_bits_max;
2106
0
         max[version_octets - 1 - discarded_octets_max] <<= unused_bits_max;
2107
0
      }
2108
2109
0
      into.start_sequence()
2110
0
         .encode_bitstring(std::span{min}.first(version_octets - discarded_octets_min), unused_bits_min)
2111
0
         .encode_bitstring(std::span{max}.first(version_octets - discarded_octets_max), unused_bits_max)
2112
0
         .end_cons();
2113
0
   }
2114
0
}
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>::encode_into(Botan::DER_Encoder&) const
Unexecuted instantiation: Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>::encode_into(Botan::DER_Encoder&) const
2115
2116
template <IPAddressBlocks::Version V>
2117
2.56k
void IPAddressBlocks::IPAddressOrRange<V>::decode_from(Botan::BER_Decoder& from) {
2118
2.56k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2119
2120
   // this can either be a prefix or a single address
2121
2.56k
   if(next_tag == ASN1_Type::BitString) {
2122
      // construct a min and a max address from the prefix
2123
2124
2.08k
      ASN1_BitString prefix;
2125
2.08k
      from.decode_bitstring(prefix);
2126
2127
      // min address gets filled with 0's
2128
2.08k
      m_min = decode_single_address(prefix, true);
2129
      // max address with 1's
2130
2.08k
      m_max = decode_single_address(prefix, false);
2131
2.08k
   } else if(next_tag == ASN1_Type::Sequence) {
2132
      // this is a range
2133
2134
257
      ASN1_BitString addr_min;
2135
257
      ASN1_BitString addr_max;
2136
2137
257
      from.start_sequence().decode_bitstring(addr_min).decode_bitstring(addr_max).end_cons();
2138
2139
257
      m_min = decode_single_address(addr_min, true);
2140
257
      m_max = decode_single_address(addr_max, false);
2141
2142
257
      if(m_min > m_max) {
2143
18
         throw Decoding_Error("IP address ranges must be sorted.");
2144
18
      }
2145
257
   } else {
2146
225
      throw Decoding_Error(fmt("Unexpected type for IPAddressOrRange {}", static_cast<uint32_t>(next_tag)));
2147
225
   }
2148
2.56k
}
Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>::decode_from(Botan::BER_Decoder&)
Line
Count
Source
2117
1.12k
void IPAddressBlocks::IPAddressOrRange<V>::decode_from(Botan::BER_Decoder& from) {
2118
1.12k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2119
2120
   // this can either be a prefix or a single address
2121
1.12k
   if(next_tag == ASN1_Type::BitString) {
2122
      // construct a min and a max address from the prefix
2123
2124
859
      ASN1_BitString prefix;
2125
859
      from.decode_bitstring(prefix);
2126
2127
      // min address gets filled with 0's
2128
859
      m_min = decode_single_address(prefix, true);
2129
      // max address with 1's
2130
859
      m_max = decode_single_address(prefix, false);
2131
859
   } else if(next_tag == ASN1_Type::Sequence) {
2132
      // this is a range
2133
2134
156
      ASN1_BitString addr_min;
2135
156
      ASN1_BitString addr_max;
2136
2137
156
      from.start_sequence().decode_bitstring(addr_min).decode_bitstring(addr_max).end_cons();
2138
2139
156
      m_min = decode_single_address(addr_min, true);
2140
156
      m_max = decode_single_address(addr_max, false);
2141
2142
156
      if(m_min > m_max) {
2143
11
         throw Decoding_Error("IP address ranges must be sorted.");
2144
11
      }
2145
156
   } else {
2146
106
      throw Decoding_Error(fmt("Unexpected type for IPAddressOrRange {}", static_cast<uint32_t>(next_tag)));
2147
106
   }
2148
1.12k
}
Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>::decode_from(Botan::BER_Decoder&)
Line
Count
Source
2117
1.44k
void IPAddressBlocks::IPAddressOrRange<V>::decode_from(Botan::BER_Decoder& from) {
2118
1.44k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2119
2120
   // this can either be a prefix or a single address
2121
1.44k
   if(next_tag == ASN1_Type::BitString) {
2122
      // construct a min and a max address from the prefix
2123
2124
1.22k
      ASN1_BitString prefix;
2125
1.22k
      from.decode_bitstring(prefix);
2126
2127
      // min address gets filled with 0's
2128
1.22k
      m_min = decode_single_address(prefix, true);
2129
      // max address with 1's
2130
1.22k
      m_max = decode_single_address(prefix, false);
2131
1.22k
   } else if(next_tag == ASN1_Type::Sequence) {
2132
      // this is a range
2133
2134
101
      ASN1_BitString addr_min;
2135
101
      ASN1_BitString addr_max;
2136
2137
101
      from.start_sequence().decode_bitstring(addr_min).decode_bitstring(addr_max).end_cons();
2138
2139
101
      m_min = decode_single_address(addr_min, true);
2140
101
      m_max = decode_single_address(addr_max, false);
2141
2142
101
      if(m_min > m_max) {
2143
7
         throw Decoding_Error("IP address ranges must be sorted.");
2144
7
      }
2145
119
   } else {
2146
119
      throw Decoding_Error(fmt("Unexpected type for IPAddressOrRange {}", static_cast<uint32_t>(next_tag)));
2147
119
   }
2148
1.44k
}
2149
2150
template <IPAddressBlocks::Version V>
2151
IPAddressBlocks::IPAddress<V> IPAddressBlocks::IPAddressOrRange<V>::decode_single_address(const ASN1_BitString& decoded,
2152
4.47k
                                                                                          bool min) {
2153
4.47k
   const size_t version_octets = static_cast<size_t>(V);
2154
2155
   // decode a single address according to https://datatracker.ietf.org/doc/html/rfc3779#section-2.1.1 and following
2156
2157
4.47k
   if(decoded.bytes().size() > version_octets) {
2158
15
      throw Decoding_Error(fmt("IP address range entries must have a length between 0 and {} bytes.", version_octets));
2159
15
   }
2160
2161
4.46k
   const uint8_t unused = static_cast<uint8_t>(decoded.unused_bits());
2162
4.46k
   const uint8_t discarded_octets = version_octets - static_cast<uint8_t>(decoded.bytes().size());
2163
2164
4.46k
   std::vector<uint8_t> address(decoded.bytes().begin(), decoded.bytes().end());
2165
2166
4.46k
   if(address.empty() && unused != 0) {
2167
0
      throw Decoding_Error("IP address range entry specified unused bits, but did not provide any octets.");
2168
0
   }
2169
2170
   // pad to version length with 0's for min addresses, 255's (0xff) for max addresses
2171
4.46k
   const uint8_t fill_discarded = min ? 0 : 0xff;
2172
39.0k
   for(size_t i = 0; i < discarded_octets; i++) {
2173
34.5k
      address.push_back(fill_discarded);
2174
34.5k
   }
2175
2176
   // for min addresses they should already be 0, but we set them to zero regardless
2177
   // for max addresses this turns the unused bits to 1
2178
12.6k
   for(size_t i = 0; i < unused; i++) {
2179
8.15k
      if(min) {
2180
3.90k
         address[version_octets - 1 - discarded_octets] &= ~(1 << i);
2181
4.24k
      } else {
2182
4.24k
         address[version_octets - 1 - discarded_octets] |= (1 << i);
2183
4.24k
      }
2184
8.15k
   }
2185
2186
4.46k
   return IPAddressBlocks::IPAddress<V>(address);
2187
4.46k
}
Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>::decode_single_address(Botan::ASN1_BitString const&, bool)
Line
Count
Source
2152
1.93k
                                                                                          bool min) {
2153
1.93k
   const size_t version_octets = static_cast<size_t>(V);
2154
2155
   // decode a single address according to https://datatracker.ietf.org/doc/html/rfc3779#section-2.1.1 and following
2156
2157
1.93k
   if(decoded.bytes().size() > version_octets) {
2158
10
      throw Decoding_Error(fmt("IP address range entries must have a length between 0 and {} bytes.", version_octets));
2159
10
   }
2160
2161
1.92k
   const uint8_t unused = static_cast<uint8_t>(decoded.unused_bits());
2162
1.92k
   const uint8_t discarded_octets = version_octets - static_cast<uint8_t>(decoded.bytes().size());
2163
2164
1.92k
   std::vector<uint8_t> address(decoded.bytes().begin(), decoded.bytes().end());
2165
2166
1.92k
   if(address.empty() && unused != 0) {
2167
0
      throw Decoding_Error("IP address range entry specified unused bits, but did not provide any octets.");
2168
0
   }
2169
2170
   // pad to version length with 0's for min addresses, 255's (0xff) for max addresses
2171
1.92k
   const uint8_t fill_discarded = min ? 0 : 0xff;
2172
4.47k
   for(size_t i = 0; i < discarded_octets; i++) {
2173
2.55k
      address.push_back(fill_discarded);
2174
2.55k
   }
2175
2176
   // for min addresses they should already be 0, but we set them to zero regardless
2177
   // for max addresses this turns the unused bits to 1
2178
5.31k
   for(size_t i = 0; i < unused; i++) {
2179
3.39k
      if(min) {
2180
1.59k
         address[version_octets - 1 - discarded_octets] &= ~(1 << i);
2181
1.80k
      } else {
2182
1.80k
         address[version_octets - 1 - discarded_octets] |= (1 << i);
2183
1.80k
      }
2184
3.39k
   }
2185
2186
1.92k
   return IPAddressBlocks::IPAddress<V>(address);
2187
1.92k
}
Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>::decode_single_address(Botan::ASN1_BitString const&, bool)
Line
Count
Source
2152
2.54k
                                                                                          bool min) {
2153
2.54k
   const size_t version_octets = static_cast<size_t>(V);
2154
2155
   // decode a single address according to https://datatracker.ietf.org/doc/html/rfc3779#section-2.1.1 and following
2156
2157
2.54k
   if(decoded.bytes().size() > version_octets) {
2158
5
      throw Decoding_Error(fmt("IP address range entries must have a length between 0 and {} bytes.", version_octets));
2159
5
   }
2160
2161
2.54k
   const uint8_t unused = static_cast<uint8_t>(decoded.unused_bits());
2162
2.54k
   const uint8_t discarded_octets = version_octets - static_cast<uint8_t>(decoded.bytes().size());
2163
2164
2.54k
   std::vector<uint8_t> address(decoded.bytes().begin(), decoded.bytes().end());
2165
2166
2.54k
   if(address.empty() && unused != 0) {
2167
0
      throw Decoding_Error("IP address range entry specified unused bits, but did not provide any octets.");
2168
0
   }
2169
2170
   // pad to version length with 0's for min addresses, 255's (0xff) for max addresses
2171
2.54k
   const uint8_t fill_discarded = min ? 0 : 0xff;
2172
34.5k
   for(size_t i = 0; i < discarded_octets; i++) {
2173
32.0k
      address.push_back(fill_discarded);
2174
32.0k
   }
2175
2176
   // for min addresses they should already be 0, but we set them to zero regardless
2177
   // for max addresses this turns the unused bits to 1
2178
7.29k
   for(size_t i = 0; i < unused; i++) {
2179
4.75k
      if(min) {
2180
2.30k
         address[version_octets - 1 - discarded_octets] &= ~(1 << i);
2181
2.44k
      } else {
2182
2.44k
         address[version_octets - 1 - discarded_octets] |= (1 << i);
2183
2.44k
      }
2184
4.75k
   }
2185
2186
2.54k
   return IPAddressBlocks::IPAddress<V>(address);
2187
2.54k
}
2188
2189
template <IPAddressBlocks::Version V>
2190
4.46k
IPAddressBlocks::IPAddress<V>::IPAddress(std::span<const uint8_t> v) {
2191
4.46k
   if(v.size() != Length) {
2192
0
      throw Decoding_Error("number of bytes does not match IP version used");
2193
0
   }
2194
2195
52.7k
   for(size_t i = 0; i < Length; i++) {
2196
48.3k
      m_value[i] = v[i];
2197
48.3k
   }
2198
4.46k
}
Botan::Cert_Extension::IPAddressBlocks::IPAddress<(Botan::Cert_Extension::IPAddressBlocks::Version)4>::IPAddress(std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
2190
1.92k
IPAddressBlocks::IPAddress<V>::IPAddress(std::span<const uint8_t> v) {
2191
1.92k
   if(v.size() != Length) {
2192
0
      throw Decoding_Error("number of bytes does not match IP version used");
2193
0
   }
2194
2195
9.60k
   for(size_t i = 0; i < Length; i++) {
2196
7.68k
      m_value[i] = v[i];
2197
7.68k
   }
2198
1.92k
}
Botan::Cert_Extension::IPAddressBlocks::IPAddress<(Botan::Cert_Extension::IPAddressBlocks::Version)16>::IPAddress(std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
2190
2.54k
IPAddressBlocks::IPAddress<V>::IPAddress(std::span<const uint8_t> v) {
2191
2.54k
   if(v.size() != Length) {
2192
0
      throw Decoding_Error("number of bytes does not match IP version used");
2193
0
   }
2194
2195
43.1k
   for(size_t i = 0; i < Length; i++) {
2196
40.6k
      m_value[i] = v[i];
2197
40.6k
   }
2198
2.54k
}
2199
2200
void IPAddressBlocks::validate(const X509_Certificate& /* unused */,
2201
                               const std::optional<X509_Certificate>& /* unused */,
2202
                               const std::vector<X509_Certificate>& cert_path,
2203
                               std::vector<std::set<Certificate_Status_Code>>& cert_status,
2204
0
                               size_t pos) const {
2205
   // maps in the form of (s)afi -> (needs_checking, ranges)
2206
0
   auto [v4_needs_check, v6_needs_check] = create_validation_map(m_ip_addr_blocks);
2207
2208
0
   if(pos == cert_path.size() - 1) {
2209
      // checks if any range / family has 'inherit' as a value somewhere, not allowed for the root cert
2210
0
      auto validate_root_cert_ext = [&](const auto& map) {
2211
         // check if any range has a value of 'false', indicating 'inherit'
2212
0
         return std::any_of(map.begin(), map.end(), [&](const auto& it) {
2213
0
            const auto& [_1, validation_info] = it;
2214
0
            const auto& [needs_checking, _2] = validation_info;
2215
0
            return !needs_checking;
2216
0
         });
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_0::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > const&) const::{lambda(auto:1 const&)#1}::operator()<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > >(std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > const&) const
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_0::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > const&) const::{lambda(auto:1 const&)#1}::operator()<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > >(std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > const&) const
2217
0
      };
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_0::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > const&) const
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_0::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > const&) const
2218
0
      if(validate_root_cert_ext(v4_needs_check) || validate_root_cert_ext(v6_needs_check)) {
2219
0
         cert_status.at(pos).insert(Certificate_Status_Code::IPADDR_BLOCKS_ERROR);
2220
0
      }
2221
0
      return;
2222
0
   }
2223
2224
   // traverse the chain until we find a cert with concrete values for the extension (so not 'inherit')
2225
0
   for(auto cert_path_it = cert_path.begin() + pos + 1; cert_path_it != cert_path.end(); cert_path_it++) {
2226
0
      const IPAddressBlocks* const parent_ip = cert_path_it->v3_extensions().get_extension_object_as<IPAddressBlocks>();
2227
      // extension not present for parent
2228
0
      if(parent_ip == nullptr) {
2229
0
         cert_status.at(pos).insert(Certificate_Status_Code::IPADDR_BLOCKS_ERROR);
2230
0
         return;
2231
0
      }
2232
0
      auto [issuer_v4, issuer_v6] = create_validation_map(parent_ip->addr_blocks());
2233
2234
0
      auto validate_against_issuer = [&](auto& subject_map, const auto& issuer_map) {
2235
0
         for(auto map_it = subject_map.begin(); map_it != subject_map.end(); map_it++) {
2236
0
            auto& [afam, validation_info] = *map_it;
2237
2238
            // the issuer does not have this combination of afi/safi
2239
0
            if(issuer_map.count(afam) == 0) {
2240
0
               cert_status.at(pos).insert(Certificate_Status_Code::IPADDR_BLOCKS_ERROR);
2241
0
               return false;
2242
0
            }
2243
2244
0
            auto& [needs_check, subject_value] = validation_info;
2245
0
            const auto& [issuer_has_value, issuer_value] = issuer_map.at(afam);
2246
0
            BOTAN_ASSERT_NOMSG(!needs_check || subject_value != nullptr);
2247
0
            BOTAN_ASSERT_NOMSG(!issuer_has_value || issuer_value != nullptr);
2248
2249
            // we still need to check this range and the issuer has an actual value for it (so not 'inherit')
2250
0
            if(needs_check && issuer_has_value) {
2251
0
               if(!validate_subject_in_issuer(std::span(*subject_value), std::span(*issuer_value))) {
2252
0
                  cert_status.at(pos).insert(Certificate_Status_Code::IPADDR_BLOCKS_ERROR);
2253
0
                  return false;
2254
0
               }
2255
0
               needs_check = false;
2256
0
            }
2257
0
         }
2258
0
         return true;
2259
0
      };
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_1::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > >, std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > >&, std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > const&) const
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_1::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > >, std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > >&, std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > const&) const
2260
2261
0
      if(!validate_against_issuer(v4_needs_check, issuer_v4) || !validate_against_issuer(v6_needs_check, issuer_v6)) {
2262
0
         return;
2263
0
      }
2264
2265
0
      auto validate_no_checks_left = [&](const auto& map) {
2266
         // check if all ranges have been checked, either by comparing their ranges if they have any,
2267
         // or if they are inherit, their parent(s) will be validated later
2268
0
         return std::all_of(map.begin(), map.end(), [&](const auto& it) {
2269
0
            const auto& [_1, validation_info] = it;
2270
0
            const auto& [needs_checking, _2] = validation_info;
2271
0
            return !needs_checking;
2272
0
         });
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_2::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > const&) const::{lambda(auto:1 const&)#1}::operator()<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > >(std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > const&) const
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_2::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > const&) const::{lambda(auto:1 const&)#1}::operator()<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > >(std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > const&) const
2273
0
      };
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_2::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)4> > > const*> > > > const&) const
Unexecuted instantiation: x509_ext.cpp:auto Botan::Cert_Extension::IPAddressBlocks::validate(Botan::X509_Certificate const&, std::__1::optional<Botan::X509_Certificate> const&, std::__1::vector<Botan::X509_Certificate, std::__1::allocator<Botan::X509_Certificate> > const&, std::__1::vector<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> >, std::__1::allocator<std::__1::set<Botan::Certificate_Status_Code, std::__1::less<Botan::Certificate_Status_Code>, std::__1::allocator<Botan::Certificate_Status_Code> > > >&, unsigned long) const::$_2::operator()<std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > >(std::__1::map<unsigned int, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*>, std::__1::less<unsigned int>, std::__1::allocator<std::__1::pair<unsigned int const, std::__1::pair<bool, std::__1::vector<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16>, std::__1::allocator<Botan::Cert_Extension::IPAddressBlocks::IPAddressOrRange<(Botan::Cert_Extension::IPAddressBlocks::Version)16> > > const*> > > > const&) const
2274
2275
0
      if(validate_no_checks_left(v4_needs_check) && validate_no_checks_left(v6_needs_check)) {
2276
         // we've validated what we need to and can stop traversing the cert chain
2277
0
         return;
2278
0
      }
2279
0
   }
2280
0
}
2281
2282
template class IPAddressBlocks::IPAddress<IPAddressBlocks::Version::IPv4>;
2283
template class IPAddressBlocks::IPAddress<IPAddressBlocks::Version::IPv6>;
2284
template class IPAddressBlocks::IPAddressOrRange<IPAddressBlocks::Version::IPv4>;
2285
template class IPAddressBlocks::IPAddressOrRange<IPAddressBlocks::Version::IPv6>;
2286
template class IPAddressBlocks::IPAddressChoice<IPAddressBlocks::Version::IPv4>;
2287
template class IPAddressBlocks::IPAddressChoice<IPAddressBlocks::Version::IPv6>;
2288
2289
0
std::vector<uint8_t> ASBlocks::encode_inner() const {
2290
0
   std::vector<uint8_t> output;
2291
0
   DER_Encoder(output).encode(m_as_identifiers);
2292
0
   return output;
2293
0
}
2294
2295
2.03k
void ASBlocks::decode_inner(const std::vector<uint8_t>& in) {
2296
   /* RFC 3779 Section 3.2.3.1 - ASIdentifiers ::= SEQUENCE { ... } */
2297
2.03k
   BER_Decoder(in, BER_Decoder::Limits::DER()).decode(m_as_identifiers).verify_end();
2298
2.03k
}
2299
2300
0
ASBlocks::ASIdentifierChoice ASBlocks::add_new(const std::optional<ASIdentifierChoice>& old, asnum_t min, asnum_t max) {
2301
0
   std::vector<ASIdOrRange> range;
2302
0
   if(!old.has_value() || !old.value().ranges().has_value()) {
2303
0
      range = {ASIdOrRange(min, max)};
2304
0
   } else {
2305
0
      range = old.value().ranges().value();
2306
0
      range.push_back(ASIdOrRange(min, max));
2307
0
   }
2308
0
   return ASIdentifierChoice(range);
2309
0
}
2310
2311
0
void ASBlocks::ASIdentifiers::encode_into(Botan::DER_Encoder& into) const {
2312
0
   into.start_sequence();
2313
2314
0
   if(!m_asnum.has_value() && !m_rdi.has_value()) {
2315
0
      throw Encoding_Error("One of asnum, rdi must be present");
2316
0
   }
2317
2318
0
   if(m_asnum.has_value()) {
2319
0
      into.start_explicit(0);
2320
0
      into.encode(m_asnum.value());
2321
0
      into.end_explicit();
2322
0
   }
2323
2324
0
   if(m_rdi.has_value()) {
2325
0
      into.start_explicit(1);
2326
0
      into.encode(m_rdi.value());
2327
0
      into.end_explicit();
2328
0
   }
2329
2330
0
   into.end_cons();
2331
0
}
2332
2333
2.03k
void ASBlocks::ASIdentifiers::decode_from(Botan::BER_Decoder& from) {
2334
2.03k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2335
2.03k
   if(next_tag != ASN1_Type::Sequence) {
2336
120
      throw Decoding_Error(fmt("Unexpected type for ASIdentifiers {}", static_cast<uint32_t>(next_tag)));
2337
120
   }
2338
2339
1.91k
   BER_Decoder seq_dec = from.start_sequence();
2340
2341
1.91k
   const BER_Object elem_obj = seq_dec.get_next_object();
2342
1.91k
   const uint32_t elem_type_tag = static_cast<uint32_t>(elem_obj.type_tag());
2343
2344
   // asnum, potentially followed by an rdi
2345
1.91k
   if(elem_type_tag == 0) {
2346
882
      BER_Decoder as_obj_ber = BER_Decoder(elem_obj, seq_dec.limits());
2347
882
      ASIdentifierChoice asnum;
2348
882
      as_obj_ber.decode(asnum).verify_end();
2349
882
      m_asnum = asnum;
2350
2351
882
      const BER_Object rdi_obj = seq_dec.get_next_object();
2352
882
      const ASN1_Type rdi_type_tag = rdi_obj.type_tag();
2353
882
      if(static_cast<uint32_t>(rdi_type_tag) == 1) {
2354
96
         BER_Decoder rdi_obj_ber = BER_Decoder(rdi_obj, seq_dec.limits());
2355
96
         ASIdentifierChoice rdi;
2356
96
         rdi_obj_ber.decode(rdi).verify_end();
2357
96
         m_rdi = rdi;
2358
786
      } else if(rdi_type_tag != ASN1_Type::NoObject) {
2359
102
         throw Decoding_Error(fmt("Unexpected type for ASIdentifiers rdi: {}", static_cast<uint32_t>(rdi_type_tag)));
2360
102
      }
2361
882
   }
2362
2363
   // just an rdi
2364
1.81k
   if(elem_type_tag == 1) {
2365
890
      BER_Decoder rdi_obj_ber = BER_Decoder(elem_obj, seq_dec.limits());
2366
890
      ASIdentifierChoice rdi;
2367
890
      rdi_obj_ber.decode(rdi).verify_end();
2368
890
      m_rdi = rdi;
2369
890
      const BER_Object end = seq_dec.get_next_object();
2370
890
      const ASN1_Type end_type_tag = end.type_tag();
2371
890
      if(end_type_tag != ASN1_Type::NoObject) {
2372
129
         throw Decoding_Error(
2373
129
            fmt("Unexpected element with type {} in ASIdentifiers", static_cast<uint32_t>(end_type_tag)));
2374
129
      }
2375
890
   }
2376
2377
1.68k
   seq_dec.end_cons();
2378
2379
1.68k
   if(!m_asnum.has_value() && !m_rdi.has_value()) {
2380
63
      throw Decoding_Error("Invalid encoding for ASIdentifiers");
2381
63
   }
2382
1.68k
}
2383
2384
0
void ASBlocks::ASIdentifierChoice::encode_into(Botan::DER_Encoder& into) const {
2385
0
   if(m_as_ranges.has_value()) {
2386
0
      into.start_sequence().encode_list(m_as_ranges.value()).end_cons();
2387
0
   } else {
2388
0
      into.encode_null();
2389
0
   }
2390
0
}
2391
2392
0
ASBlocks::ASIdentifierChoice::ASIdentifierChoice(const std::optional<std::vector<ASIdOrRange>>& ranges) {
2393
0
   m_as_ranges = sort_and_merge_ranges<ASIdOrRange>(ranges);
2394
0
}
2395
2396
1.86k
void ASBlocks::ASIdentifierChoice::decode_from(Botan::BER_Decoder& from) {
2397
1.86k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2398
2399
1.86k
   if(next_tag == ASN1_Type::Null) {
2400
27
      from.decode_null();
2401
27
      m_as_ranges = std::nullopt;
2402
1.84k
   } else if(next_tag == ASN1_Type::Sequence) {
2403
1.66k
      std::vector<ASIdOrRange> as_ranges;
2404
1.66k
      from.decode_list(as_ranges);
2405
2406
1.66k
      m_as_ranges = sort_and_merge_ranges<ASIdOrRange>(as_ranges);
2407
1.66k
   } else {
2408
176
      throw Decoding_Error(fmt("Unexpected type for ASIdentifierChoice {}", static_cast<uint32_t>(next_tag)));
2409
176
   }
2410
1.86k
}
2411
2412
0
void ASBlocks::ASIdOrRange::encode_into(Botan::DER_Encoder& into) const {
2413
0
   if(m_min == m_max) {
2414
0
      into.encode(static_cast<size_t>(m_min));
2415
0
   } else {
2416
0
      if(m_min >= m_max) {
2417
0
         throw Encoding_Error("AS range numbers must be sorted");
2418
0
      }
2419
0
      into.start_sequence().encode(static_cast<size_t>(m_min)).encode(static_cast<size_t>(m_max)).end_cons();
2420
0
   }
2421
0
}
2422
2423
6.27k
void ASBlocks::ASIdOrRange::decode_from(BER_Decoder& from) {
2424
6.27k
   const ASN1_Type next_tag = from.peek_next_object().type_tag();
2425
2426
6.27k
   size_t min = 0;
2427
6.27k
   size_t max = 0;
2428
2429
6.27k
   if(next_tag == ASN1_Type::Integer) {
2430
5.83k
      from.decode(min);
2431
5.83k
      m_min = checked_cast_to<asnum_t>(min);
2432
5.83k
      m_max = m_min;
2433
5.83k
   } else if(next_tag == ASN1_Type::Sequence) {
2434
223
      from.start_sequence().decode(min).decode(max).end_cons();
2435
223
      m_min = checked_cast_to<asnum_t>(min);
2436
223
      m_max = checked_cast_to<asnum_t>(max);
2437
223
      if(m_min >= m_max) {
2438
8
         throw Decoding_Error("ASIdOrRange has min greater than max");
2439
8
      }
2440
223
   } else {
2441
220
      throw Decoding_Error(fmt("Unexpected type for ASIdOrRange {}", static_cast<uint32_t>(next_tag)));
2442
220
   }
2443
6.27k
}
2444
2445
void ASBlocks::validate(const X509_Certificate& /* unused */,
2446
                        const std::optional<X509_Certificate>& /* unused */,
2447
                        const std::vector<X509_Certificate>& cert_path,
2448
                        std::vector<std::set<Certificate_Status_Code>>& cert_status,
2449
0
                        size_t pos) const {
2450
   // the extension may not contain asnums or rdis, but one of them is always present
2451
0
   const bool asnum_present = m_as_identifiers.asnum().has_value();
2452
0
   const bool rdi_present = m_as_identifiers.rdi().has_value();
2453
2454
0
   if(!asnum_present && !rdi_present) {
2455
      // Invalid, should have been caught during decoding
2456
0
      cert_status.at(pos).insert(Certificate_Status_Code::AS_BLOCKS_ERROR);
2457
0
      return;
2458
0
   }
2459
2460
0
   bool asnum_needs_check = asnum_present ? m_as_identifiers.asnum().value().ranges().has_value() : false;
2461
0
   bool rdi_needs_check = rdi_present ? m_as_identifiers.rdi().value().ranges().has_value() : false;
2462
2463
   // we are at the (trusted) root cert, there is no parent to verify against
2464
0
   if(pos == cert_path.size() - 1) {
2465
      // asnum / rdi is present, but has 'inherit' value, but there is nothing to inherit from
2466
0
      if((asnum_present && !asnum_needs_check) || (rdi_present && !rdi_needs_check)) {
2467
0
         cert_status.at(pos).insert(Certificate_Status_Code::AS_BLOCKS_ERROR);
2468
0
      }
2469
0
      return;
2470
0
   }
2471
2472
   // traverse the chain until we find a cert with concrete values for the extension (so not 'inherit')
2473
0
   for(auto it = cert_path.begin() + pos + 1; it != cert_path.end(); it++) {
2474
0
      const ASBlocks* const parent_as = it->v3_extensions().get_extension_object_as<ASBlocks>();
2475
      // no extension at all or no asnums or no rdis (if needed)
2476
0
      if(parent_as == nullptr || (asnum_present && !parent_as->as_identifiers().asnum().has_value()) ||
2477
0
         (rdi_present && !parent_as->as_identifiers().rdi().has_value())) {
2478
0
         cert_status.at(pos).insert(Certificate_Status_Code::AS_BLOCKS_ERROR);
2479
0
         return;
2480
0
      }
2481
0
      const auto as_identifiers = parent_as->as_identifiers();
2482
2483
      // only something to validate if the subject does not have 'inherit' as a value
2484
0
      if(asnum_needs_check && as_identifiers.asnum().value().ranges().has_value()) {
2485
0
         const std::vector<ASBlocks::ASIdOrRange>& subject_asnums = m_as_identifiers.asnum()->ranges().value();
2486
0
         const std::vector<ASBlocks::ASIdOrRange>& issuer_asnums = as_identifiers.asnum()->ranges().value();
2487
2488
0
         if(!validate_subject_in_issuer<ASBlocks::ASIdOrRange>(subject_asnums, issuer_asnums)) {
2489
0
            cert_status.at(pos).insert(Certificate_Status_Code::AS_BLOCKS_ERROR);
2490
0
            return;
2491
0
         }
2492
         // successfully validated the asnums, but we may need to step further for rdis
2493
0
         asnum_needs_check = false;
2494
0
      }
2495
2496
0
      if(rdi_needs_check && as_identifiers.rdi().value().ranges().has_value()) {
2497
0
         const std::vector<ASBlocks::ASIdOrRange>& subject_rdis = m_as_identifiers.rdi()->ranges().value();
2498
0
         const std::vector<ASBlocks::ASIdOrRange>& issuer_rdis = as_identifiers.rdi()->ranges().value();
2499
2500
0
         if(!validate_subject_in_issuer<ASBlocks::ASIdOrRange>(subject_rdis, issuer_rdis)) {
2501
0
            cert_status.at(pos).insert(Certificate_Status_Code::AS_BLOCKS_ERROR);
2502
0
            return;
2503
0
         }
2504
         // successfully validated the rdis, but we may need to step further for asnums
2505
0
         rdi_needs_check = false;
2506
0
      }
2507
2508
0
      if(!asnum_needs_check && !rdi_needs_check) {
2509
         // we've validated what we need to and can stop traversing the cert chain
2510
0
         return;
2511
0
      }
2512
0
   }
2513
0
}
2514
2515
void OCSP_NoCheck::validate(const X509_Certificate& subject,
2516
                            const std::optional<X509_Certificate>& /*issuer*/,
2517
                            const std::vector<X509_Certificate>& /*cert_path*/,
2518
                            std::vector<std::set<Certificate_Status_Code>>& cert_status,
2519
0
                            size_t pos) const {
2520
   /*
2521
   * RFC 6960 is not particularly explicit about when id-pkix-ocsp-nocheck can
2522
   * or cannot be included in a certificate, but reasonably we should require
2523
   * that id-pkix-ocsp-nocheck is only included for certificates that are marked
2524
   * as OCSP responders. This checks for compatible key usage and also the OCSP
2525
   * signer extended key usage.
2526
   */
2527
0
   if(!subject.allowed_usage(Usage_Type::OCSP_RESPONDER)) {
2528
0
      cert_status.at(pos).insert(Certificate_Status_Code::INVALID_OCSP_NOCHECK);
2529
0
   }
2530
0
}
2531
2532
0
std::vector<uint8_t> OCSP_NoCheck::encode_inner() const {
2533
0
   return {0x05, 0x00};  // NULL
2534
0
}
2535
2536
6
void OCSP_NoCheck::decode_inner(const std::vector<uint8_t>& buf) {
2537
   /* RFC 6960 Section 4.2.2.2.1 - id-pkix-ocsp-nocheck (value SHALL be NULL) */
2538
6
   BER_Decoder(buf, BER_Decoder::Limits::DER()).decode_null().verify_end();
2539
6
}
2540
2541
0
std::vector<uint8_t> NoRevocationAvailable::encode_inner() const {
2542
0
   return {0x05, 0x00};  // NULL
2543
0
}
2544
2545
56
void NoRevocationAvailable::decode_inner(const std::vector<uint8_t>& buf) {
2546
   // RFC 9608 Section 2, it's just a NULL
2547
56
   BER_Decoder(buf, BER_Decoder::Limits::DER()).decode_null().verify_end();
2548
56
}
2549
2550
void NoRevocationAvailable::validate(const X509_Certificate& subject,
2551
                                     const std::optional<X509_Certificate>& /*issuer*/,
2552
                                     const std::vector<X509_Certificate>& /*cert_path*/,
2553
                                     std::vector<std::set<Certificate_Status_Code>>& cert_status,
2554
0
                                     size_t pos) const {
2555
   // RFC 9608 Section 2:
2556
   //    This extension MUST NOT be present in CA public key certificates.
2557
   //
2558
   // RFC 9608 Section 3:
2559
   //    Certificates that include the noRevAvail extension MUST NOT include
2560
   //    certificate extensions that point to CRL repositories or provide
2561
   //    locations of OCSP responders.
2562
   //
2563
   // Additionally (and unusually) the requirements of RFC 9608 Section 3
2564
   // are not just on issuing parties but also on verifiers:
2565
   //
2566
   //   If any of the above are violated in a certificate, then the relying
2567
   //   party MUST consider the certificate invalid.
2568
2569
0
   const Extensions& exts = subject.v3_extensions();
2570
2571
0
   if(const auto* bc = exts.get_extension_object_as<Basic_Constraints>(); bc != nullptr && bc->is_ca()) {
2572
      // RFC 9608 Section 3:
2573
      //    The certificate MUST NOT also include the basic constraints
2574
      //    certificate extension with the cA BOOLEAN set to TRUE
2575
0
      cert_status.at(pos).insert(Certificate_Status_Code::NO_REV_AVAIL_INVALID_USE);
2576
0
   }
2577
2578
   // RFC 9608 Section 3:
2579
   //    The certificate MUST NOT also include the CRL Distribution Points
2580
   //    certificate extension
2581
0
   if(exts.extension_set(CRL_Distribution_Points::static_oid())) {
2582
0
      cert_status.at(pos).insert(Certificate_Status_Code::NO_REV_AVAIL_INVALID_USE);
2583
0
   }
2584
2585
   // RFC 9608 Section 3:
2586
   //    The certificate MUST NOT also include the Freshest CRL certificate
2587
   //    extension
2588
0
   if(exts.extension_set(OID({2, 5, 29, 46}))) {
2589
0
      cert_status.at(pos).insert(Certificate_Status_Code::NO_REV_AVAIL_INVALID_USE);
2590
0
   }
2591
2592
   // RFC 9608 Section 3:
2593
   //    The Authority Information Access certificate extension, if
2594
   //    present, MUST NOT include an id-ad-ocsp accessMethod
2595
   //
2596
   // Walk the raw AccessDescription list rather than the URI-only typed
2597
   // accessor so a non-URI OCSP accessLocation also triggers the rejection.
2598
0
   if(const auto* aia = exts.get_extension_object_as<Authority_Information_Access>(); aia != nullptr) {
2599
0
      const OID id_ad_ocsp = OID::from_string("PKIX.OCSP");
2600
0
      const bool has_ocsp = !aia->ocsp_responder_uris().empty() ||
2601
0
                            std::ranges::any_of(aia->access_descriptions(),
2602
0
                                                [&](const auto& ad) { return ad.access_method() == id_ad_ocsp; });
2603
0
      if(has_ocsp) {
2604
0
         cert_status.at(pos).insert(Certificate_Status_Code::NO_REV_AVAIL_INVALID_USE);
2605
0
      }
2606
0
   }
2607
0
}
2608
2609
0
std::vector<uint8_t> Unknown_Extension::encode_inner() const {
2610
0
   return m_bytes;
2611
0
}
2612
2613
46.5k
void Unknown_Extension::decode_inner(const std::vector<uint8_t>& bytes) {
2614
   // Just treat as an opaque blob at this level
2615
46.5k
   m_bytes = bytes;
2616
46.5k
}
2617
2618
}  // namespace Cert_Extension
2619
2620
}  // namespace Botan