/src/botan/build/include/botan/pkix_types.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * (C) 1999-2010,2012,2018,2020 Jack Lloyd |
3 | | * (C) 2007 Yves Jerschow |
4 | | * (C) 2015 Kai Michaelis |
5 | | * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity |
6 | | * (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity |
7 | | * |
8 | | * Botan is released under the Simplified BSD License (see license.txt) |
9 | | */ |
10 | | |
11 | | #ifndef BOTAN_PKIX_TYPES_H_ |
12 | | #define BOTAN_PKIX_TYPES_H_ |
13 | | |
14 | | #include <botan/asn1_obj.h> |
15 | | #include <botan/pkix_enums.h> |
16 | | #include <vector> |
17 | | #include <string> |
18 | | #include <iosfwd> |
19 | | #include <map> |
20 | | #include <set> |
21 | | |
22 | | namespace Botan { |
23 | | |
24 | | class X509_Certificate; |
25 | | class Public_Key; |
26 | | |
27 | | /** |
28 | | * Check that key constraints are permitted for a specific public key. |
29 | | * @param pub_key the public key on which the constraints shall be enforced on |
30 | | * @param constraints the constraints that shall be enforced on the key |
31 | | * @throw Invalid_Argument if the given constraints are not permitted for this key |
32 | | */ |
33 | | BOTAN_PUBLIC_API(2,0) void verify_cert_constraints_valid_for_key_type(const Public_Key& pub_key, |
34 | | Key_Constraints constraints); |
35 | | |
36 | | std::string BOTAN_PUBLIC_API(2,0) key_constraints_to_string(Key_Constraints); |
37 | | |
38 | | /** |
39 | | * Distinguished Name |
40 | | */ |
41 | | class BOTAN_PUBLIC_API(2,0) X509_DN final : public ASN1_Object |
42 | | { |
43 | | public: |
44 | 53.0k | X509_DN() = default; |
45 | | |
46 | | explicit X509_DN(const std::multimap<OID, std::string>& args) |
47 | 0 | { |
48 | 0 | for(auto i : args) |
49 | 0 | add_attribute(i.first, i.second); |
50 | 0 | } |
51 | | |
52 | | explicit X509_DN(const std::multimap<std::string, std::string>& args) |
53 | 0 | { |
54 | 0 | for(auto i : args) |
55 | 0 | add_attribute(i.first, i.second); |
56 | 0 | } |
57 | | |
58 | | void encode_into(DER_Encoder&) const override; |
59 | | void decode_from(BER_Decoder&) override; |
60 | | |
61 | | bool has_field(const OID& oid) const; |
62 | | ASN1_String get_first_attribute(const OID& oid) const; |
63 | | |
64 | | /* |
65 | | * Return the BER encoded data, if any |
66 | | */ |
67 | 26.1k | const std::vector<uint8_t>& get_bits() const { return m_dn_bits; } |
68 | | |
69 | | std::vector<uint8_t> DER_encode() const; |
70 | | |
71 | 0 | bool empty() const { return m_rdn.empty(); } |
72 | | |
73 | | std::string to_string() const; |
74 | | |
75 | 3.75k | const std::vector<std::pair<OID,ASN1_String>>& dn_info() const { return m_rdn; } |
76 | | |
77 | | std::multimap<OID, std::string> get_attributes() const; |
78 | | std::multimap<std::string, std::string> contents() const; |
79 | | |
80 | | bool has_field(const std::string& attr) const; |
81 | | std::vector<std::string> get_attribute(const std::string& attr) const; |
82 | | std::string get_first_attribute(const std::string& attr) const; |
83 | | |
84 | | void add_attribute(const std::string& key, const std::string& val); |
85 | | |
86 | | void add_attribute(const OID& oid, const std::string& val) |
87 | 0 | { |
88 | 0 | add_attribute(oid, ASN1_String(val)); |
89 | 0 | } |
90 | | |
91 | | void add_attribute(const OID& oid, const ASN1_String& val); |
92 | | |
93 | | static std::string deref_info_field(const std::string& key); |
94 | | |
95 | | /** |
96 | | * Lookup upper bounds in characters for the length of distinguished name fields |
97 | | * as given in RFC 5280, Appendix A. |
98 | | * |
99 | | * @param oid the oid of the DN to lookup |
100 | | * @return the upper bound, or zero if no ub is known to Botan |
101 | | */ |
102 | | static size_t lookup_ub(const OID& oid); |
103 | | |
104 | | private: |
105 | | std::vector<std::pair<OID,ASN1_String>> m_rdn; |
106 | | std::vector<uint8_t> m_dn_bits; |
107 | | }; |
108 | | |
109 | | bool BOTAN_PUBLIC_API(2,0) operator==(const X509_DN& dn1, const X509_DN& dn2); |
110 | | bool BOTAN_PUBLIC_API(2,0) operator!=(const X509_DN& dn1, const X509_DN& dn2); |
111 | | |
112 | | /* |
113 | | The ordering here is arbitrary and may change from release to release. |
114 | | It is intended for allowing DNs as keys in std::map and similiar containers |
115 | | */ |
116 | | bool BOTAN_PUBLIC_API(2,0) operator<(const X509_DN& dn1, const X509_DN& dn2); |
117 | | |
118 | | BOTAN_PUBLIC_API(2,0) std::ostream& operator<<(std::ostream& out, const X509_DN& dn); |
119 | | BOTAN_PUBLIC_API(2,0) std::istream& operator>>(std::istream& in, X509_DN& dn); |
120 | | |
121 | | /** |
122 | | * Alternative Name |
123 | | */ |
124 | | class BOTAN_PUBLIC_API(2,0) AlternativeName final : public ASN1_Object |
125 | | { |
126 | | public: |
127 | | void encode_into(DER_Encoder&) const override; |
128 | | void decode_from(BER_Decoder&) override; |
129 | | |
130 | | std::multimap<std::string, std::string> contents() const; |
131 | | |
132 | | bool has_field(const std::string& attr) const; |
133 | | std::vector<std::string> get_attribute(const std::string& attr) const; |
134 | | |
135 | | std::string get_first_attribute(const std::string& attr) const; |
136 | | |
137 | | void add_attribute(const std::string& type, const std::string& value); |
138 | | void add_othername(const OID& oid, const std::string& value, ASN1_Type type); |
139 | | |
140 | | const std::multimap<std::string, std::string>& get_attributes() const |
141 | 0 | { |
142 | 0 | return m_alt_info; |
143 | 0 | } |
144 | | |
145 | | const std::multimap<OID, ASN1_String>& get_othernames() const |
146 | 0 | { |
147 | 0 | return m_othernames; |
148 | 0 | } |
149 | | |
150 | | X509_DN dn() const; |
151 | | |
152 | | bool has_items() const; |
153 | | |
154 | | AlternativeName(const std::string& email_addr = "", |
155 | | const std::string& uri = "", |
156 | | const std::string& dns = "", |
157 | | const std::string& ip_address = ""); |
158 | | private: |
159 | | std::multimap<std::string, std::string> m_alt_info; |
160 | | std::multimap<OID, ASN1_String> m_othernames; |
161 | | }; |
162 | | |
163 | | /** |
164 | | * Attribute |
165 | | */ |
166 | | class BOTAN_PUBLIC_API(2,0) Attribute final : public ASN1_Object |
167 | | { |
168 | | public: |
169 | | void encode_into(DER_Encoder& to) const override; |
170 | | void decode_from(BER_Decoder& from) override; |
171 | | |
172 | | Attribute() = default; |
173 | | Attribute(const OID& oid, const std::vector<uint8_t>& params); |
174 | | Attribute(const std::string& oid_str, const std::vector<uint8_t>& params); |
175 | | |
176 | 0 | const OID& oid() const { return m_oid; } |
177 | 0 | const std::vector<uint8_t>& parameters() const { return m_parameters; } |
178 | | |
179 | 0 | const OID& get_oid() const { return m_oid; } |
180 | 0 | const std::vector<uint8_t>& get_parameters() const { return m_parameters; } |
181 | | |
182 | | private: |
183 | | OID m_oid; |
184 | | std::vector<uint8_t> m_parameters; |
185 | | }; |
186 | | |
187 | | /** |
188 | | * @brief X.509 GeneralName Type |
189 | | * |
190 | | * Handles parsing GeneralName types in their BER and canonical string |
191 | | * encoding. Allows matching GeneralNames against each other using |
192 | | * the rules laid out in the RFC 5280, sec. 4.2.1.10 (Name Contraints). |
193 | | */ |
194 | | class BOTAN_PUBLIC_API(2,0) GeneralName final : public ASN1_Object |
195 | | { |
196 | | public: |
197 | | enum MatchResult : int |
198 | | { |
199 | | All, |
200 | | Some, |
201 | | None, |
202 | | NotFound, |
203 | | UnknownType, |
204 | | }; |
205 | | |
206 | | /** |
207 | | * Creates an empty GeneralName. |
208 | | */ |
209 | 6.25k | GeneralName() = default; |
210 | | |
211 | | /** |
212 | | * Creates a new GeneralName for its string format. |
213 | | * @param str type and name, colon-separated, e.g., "DNS:google.com" |
214 | | */ |
215 | | GeneralName(const std::string& str); |
216 | | |
217 | | void encode_into(DER_Encoder&) const override; |
218 | | |
219 | | void decode_from(BER_Decoder&) override; |
220 | | |
221 | | /** |
222 | | * @return Type of the name. Can be DN, DNS, IP, RFC822 or URI. |
223 | | */ |
224 | 0 | const std::string& type() const { return m_type; } |
225 | | |
226 | | /** |
227 | | * @return The name as string. Format depends on type. |
228 | | */ |
229 | 0 | const std::string& name() const { return m_name; } |
230 | | |
231 | | /** |
232 | | * Checks whether a given certificate (partially) matches this name. |
233 | | * @param cert certificate to be matched |
234 | | * @return the match result |
235 | | */ |
236 | | MatchResult matches(const X509_Certificate& cert) const; |
237 | | |
238 | | private: |
239 | | std::string m_type; |
240 | | std::string m_name; |
241 | | |
242 | | bool matches_dns(const std::string&) const; |
243 | | bool matches_dn(const std::string&) const; |
244 | | bool matches_ip(const std::string&) const; |
245 | | }; |
246 | | |
247 | | std::ostream& operator<<(std::ostream& os, const GeneralName& gn); |
248 | | |
249 | | /** |
250 | | * @brief A single Name Constraint |
251 | | * |
252 | | * The Name Constraint extension adds a minimum and maximum path |
253 | | * length to a GeneralName to form a constraint. The length limits |
254 | | * are currently unused. |
255 | | */ |
256 | | class BOTAN_PUBLIC_API(2,0) GeneralSubtree final : public ASN1_Object |
257 | | { |
258 | | public: |
259 | | /** |
260 | | * Creates an empty name constraint. |
261 | | */ |
262 | | GeneralSubtree() : m_base(), m_minimum(0), m_maximum(std::numeric_limits<std::size_t>::max()) |
263 | 6.25k | {} |
264 | | |
265 | | /*** |
266 | | * Creates a new name constraint. |
267 | | * @param base name |
268 | | * @param min minimum path length |
269 | | * @param max maximum path length |
270 | | */ |
271 | | GeneralSubtree(const GeneralName& base, size_t min, size_t max) |
272 | | : m_base(base), m_minimum(min), m_maximum(max) |
273 | 0 | {} |
274 | | |
275 | | /** |
276 | | * Creates a new name constraint for its string format. |
277 | | * @param str name constraint |
278 | | */ |
279 | | GeneralSubtree(const std::string& str); |
280 | | |
281 | | void encode_into(DER_Encoder&) const override; |
282 | | |
283 | | void decode_from(BER_Decoder&) override; |
284 | | |
285 | | /** |
286 | | * @return name |
287 | | */ |
288 | 0 | const GeneralName& base() const { return m_base; } |
289 | | |
290 | | /** |
291 | | * @return minimum path length |
292 | | */ |
293 | 0 | size_t minimum() const { return m_minimum; } |
294 | | |
295 | | /** |
296 | | * @return maximum path length |
297 | | */ |
298 | 0 | size_t maximum() const { return m_maximum; } |
299 | | |
300 | | private: |
301 | | GeneralName m_base; |
302 | | size_t m_minimum; |
303 | | size_t m_maximum; |
304 | | }; |
305 | | |
306 | | std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs); |
307 | | |
308 | | /** |
309 | | * @brief Name Constraints |
310 | | * |
311 | | * Wraps the Name Constraints associated with a certificate. |
312 | | */ |
313 | | class BOTAN_PUBLIC_API(2,0) NameConstraints final |
314 | | { |
315 | | public: |
316 | | /** |
317 | | * Creates an empty name NameConstraints. |
318 | | */ |
319 | 18.9k | NameConstraints() : m_permitted_subtrees(), m_excluded_subtrees() {} |
320 | | |
321 | | /** |
322 | | * Creates NameConstraints from a list of permitted and excluded subtrees. |
323 | | * @param permitted_subtrees names for which the certificate is permitted |
324 | | * @param excluded_subtrees names for which the certificate is not permitted |
325 | | */ |
326 | | NameConstraints(std::vector<GeneralSubtree>&& permitted_subtrees, |
327 | | std::vector<GeneralSubtree>&& excluded_subtrees) |
328 | | : m_permitted_subtrees(permitted_subtrees), m_excluded_subtrees(excluded_subtrees) |
329 | 913 | {} |
330 | | |
331 | | /** |
332 | | * @return permitted names |
333 | | */ |
334 | 0 | const std::vector<GeneralSubtree>& permitted() const { return m_permitted_subtrees; } |
335 | | |
336 | | /** |
337 | | * @return excluded names |
338 | | */ |
339 | 0 | const std::vector<GeneralSubtree>& excluded() const { return m_excluded_subtrees; } |
340 | | |
341 | | private: |
342 | | std::vector<GeneralSubtree> m_permitted_subtrees; |
343 | | std::vector<GeneralSubtree> m_excluded_subtrees; |
344 | | }; |
345 | | |
346 | | /** |
347 | | * X.509 Certificate Extension |
348 | | */ |
349 | | class BOTAN_PUBLIC_API(2,0) Certificate_Extension |
350 | | { |
351 | | public: |
352 | | /** |
353 | | * @return OID representing this extension |
354 | | */ |
355 | | virtual OID oid_of() const = 0; |
356 | | |
357 | | /* |
358 | | * @return specific OID name |
359 | | * If possible OIDS table should match oid_name to OIDS, ie |
360 | | * OID::from_string(ext->oid_name()) == ext->oid_of() |
361 | | * Should return empty string if OID is not known |
362 | | */ |
363 | | virtual std::string oid_name() const = 0; |
364 | | |
365 | | /** |
366 | | * Make a copy of this extension |
367 | | * @return copy of this |
368 | | */ |
369 | | virtual Certificate_Extension* copy() const = 0; |
370 | | |
371 | | /* |
372 | | * Callback visited during path validation. |
373 | | * |
374 | | * An extension can implement this callback to inspect |
375 | | * the path during path validation. |
376 | | * |
377 | | * If an error occurs during validation of this extension, |
378 | | * an appropriate status code shall be added to cert_status. |
379 | | * |
380 | | * @param subject Subject certificate that contains this extension |
381 | | * @param issuer Issuer certificate |
382 | | * @param status Certificate validation status codes for subject certificate |
383 | | * @param cert_path Certificate path which is currently validated |
384 | | * @param pos Position of subject certificate in cert_path |
385 | | */ |
386 | | virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer, |
387 | | const std::vector<X509_Certificate>& cert_path, |
388 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
389 | | size_t pos); |
390 | | |
391 | 64.5k | virtual ~Certificate_Extension() = default; |
392 | | protected: |
393 | | friend class Extensions; |
394 | 0 | virtual bool should_encode() const { return true; } |
395 | | virtual std::vector<uint8_t> encode_inner() const = 0; |
396 | | virtual void decode_inner(const std::vector<uint8_t>&) = 0; |
397 | | }; |
398 | | |
399 | | /** |
400 | | * X.509 Certificate Extension List |
401 | | */ |
402 | | class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object |
403 | | { |
404 | | public: |
405 | | /** |
406 | | * Look up an object in the extensions, based on OID Returns |
407 | | * nullptr if not set, if the extension was either absent or not |
408 | | * handled. The pointer returned is owned by the Extensions |
409 | | * object. |
410 | | * This would be better with an optional<T> return value |
411 | | */ |
412 | | const Certificate_Extension* get_extension_object(const OID& oid) const; |
413 | | |
414 | | template<typename T> |
415 | | const T* get_extension_object_as(const OID& oid = T::static_oid()) const |
416 | 132k | { |
417 | 132k | if(const Certificate_Extension* extn = get_extension_object(oid)) |
418 | 5.74k | { |
419 | | // Unknown_Extension oid_name is empty |
420 | 5.74k | if(extn->oid_name().empty()) |
421 | 3.59k | { |
422 | 3.59k | return nullptr; |
423 | 3.59k | } |
424 | 2.14k | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) |
425 | 2.14k | { |
426 | 2.14k | return extn_as_T; |
427 | 2.14k | } |
428 | 0 | else |
429 | 0 | { |
430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); |
431 | 0 | } |
432 | 127k | } |
433 | | |
434 | 127k | return nullptr; |
435 | 127k | } Botan::Cert_Extension::Key_Usage const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Key_Usage>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 440 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 440 | if(extn->oid_name().empty()) | 421 | 363 | { | 422 | 363 | return nullptr; | 423 | 363 | } | 424 | 77 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 77 | { | 426 | 77 | return extn_as_T; | 427 | 77 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.1k | } | 433 | | | 434 | 11.1k | return nullptr; | 435 | 11.1k | } |
Botan::Cert_Extension::Subject_Key_ID const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Subject_Key_ID>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 498 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 498 | if(extn->oid_name().empty()) | 421 | 229 | { | 422 | 229 | return nullptr; | 423 | 229 | } | 424 | 269 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 269 | { | 426 | 269 | return extn_as_T; | 427 | 269 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.1k | } | 433 | | | 434 | 11.1k | return nullptr; | 435 | 11.1k | } |
Botan::Cert_Extension::Authority_Key_ID const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Authority_Key_ID>(Botan::OID const&) const Line | Count | Source | 416 | 12.0k | { | 417 | 12.0k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 777 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 777 | if(extn->oid_name().empty()) | 421 | 349 | { | 422 | 349 | return nullptr; | 423 | 349 | } | 424 | 428 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 428 | { | 426 | 428 | return extn_as_T; | 427 | 428 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.2k | } | 433 | | | 434 | 11.2k | return nullptr; | 435 | 11.2k | } |
Botan::Cert_Extension::Name_Constraints const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Name_Constraints>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 215 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 215 | if(extn->oid_name().empty()) | 421 | 170 | { | 422 | 170 | return nullptr; | 423 | 170 | } | 424 | 45 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 45 | { | 426 | 45 | return extn_as_T; | 427 | 45 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.3k | } | 433 | | | 434 | 11.3k | return nullptr; | 435 | 11.3k | } |
Botan::Cert_Extension::Basic_Constraints const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Basic_Constraints>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 385 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 385 | if(extn->oid_name().empty()) | 421 | 235 | { | 422 | 235 | return nullptr; | 423 | 235 | } | 424 | 150 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 150 | { | 426 | 150 | return extn_as_T; | 427 | 150 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.2k | } | 433 | | | 434 | 11.2k | return nullptr; | 435 | 11.2k | } |
Botan::Cert_Extension::Issuer_Alternative_Name const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Issuer_Alternative_Name>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 415 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 415 | if(extn->oid_name().empty()) | 421 | 252 | { | 422 | 252 | return nullptr; | 423 | 252 | } | 424 | 163 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 163 | { | 426 | 163 | return extn_as_T; | 427 | 163 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.1k | } | 433 | | | 434 | 11.1k | return nullptr; | 435 | 11.1k | } |
Botan::Cert_Extension::Subject_Alternative_Name const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Subject_Alternative_Name>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 537 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 537 | if(extn->oid_name().empty()) | 421 | 371 | { | 422 | 371 | return nullptr; | 423 | 371 | } | 424 | 166 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 166 | { | 426 | 166 | return extn_as_T; | 427 | 166 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.0k | } | 433 | | | 434 | 11.0k | return nullptr; | 435 | 11.0k | } |
Botan::Cert_Extension::Extended_Key_Usage const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Extended_Key_Usage>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 335 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 335 | if(extn->oid_name().empty()) | 421 | 247 | { | 422 | 247 | return nullptr; | 423 | 247 | } | 424 | 88 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 88 | { | 426 | 88 | return extn_as_T; | 427 | 88 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.2k | } | 433 | | | 434 | 11.2k | return nullptr; | 435 | 11.2k | } |
Botan::Cert_Extension::Certificate_Policies const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Certificate_Policies>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 363 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 363 | if(extn->oid_name().empty()) | 421 | 289 | { | 422 | 289 | return nullptr; | 423 | 289 | } | 424 | 74 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 74 | { | 426 | 74 | return extn_as_T; | 427 | 74 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.2k | } | 433 | | | 434 | 11.2k | return nullptr; | 435 | 11.2k | } |
Botan::Cert_Extension::Authority_Information_Access const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Authority_Information_Access>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 133 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 133 | if(extn->oid_name().empty()) | 421 | 90 | { | 422 | 90 | return nullptr; | 423 | 90 | } | 424 | 43 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 43 | { | 426 | 43 | return extn_as_T; | 427 | 43 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.4k | } | 433 | | | 434 | 11.4k | return nullptr; | 435 | 11.4k | } |
Botan::Cert_Extension::CRL_Distribution_Points const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_Distribution_Points>(Botan::OID const&) const Line | Count | Source | 416 | 11.6k | { | 417 | 11.6k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 221 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 221 | if(extn->oid_name().empty()) | 421 | 140 | { | 422 | 140 | return nullptr; | 423 | 140 | } | 424 | 81 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 81 | { | 426 | 81 | return extn_as_T; | 427 | 81 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 11.3k | } | 433 | | | 434 | 11.3k | return nullptr; | 435 | 11.3k | } |
Botan::Cert_Extension::CRL_Number const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_Number>(Botan::OID const&) const Line | Count | Source | 416 | 459 | { | 417 | 459 | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 18 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 18 | if(extn->oid_name().empty()) | 421 | 13 | { | 422 | 13 | return nullptr; | 423 | 13 | } | 424 | 5 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 5 | { | 426 | 5 | return extn_as_T; | 427 | 5 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 441 | } | 433 | | | 434 | 441 | return nullptr; | 435 | 441 | } |
Botan::Cert_Extension::CRL_Issuing_Distribution_Point const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_Issuing_Distribution_Point>(Botan::OID const&) const Line | Count | Source | 416 | 459 | { | 417 | 459 | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 17 | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 17 | if(extn->oid_name().empty()) | 421 | 14 | { | 422 | 14 | return nullptr; | 423 | 14 | } | 424 | 3 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 3 | { | 426 | 3 | return extn_as_T; | 427 | 3 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 442 | } | 433 | | | 434 | 442 | return nullptr; | 435 | 442 | } |
Botan::Cert_Extension::CRL_ReasonCode const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_ReasonCode>(Botan::OID const&) const Line | Count | Source | 416 | 3.76k | { | 417 | 3.76k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 418 | 1.39k | { | 419 | | // Unknown_Extension oid_name is empty | 420 | 1.39k | if(extn->oid_name().empty()) | 421 | 834 | { | 422 | 834 | return nullptr; | 423 | 834 | } | 424 | 557 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 425 | 557 | { | 426 | 557 | return extn_as_T; | 427 | 557 | } | 428 | 0 | else | 429 | 0 | { | 430 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 431 | 0 | } | 432 | 2.37k | } | 433 | | | 434 | 2.37k | return nullptr; | 435 | 2.37k | } |
|
436 | | |
437 | | /** |
438 | | * Return the set of extensions in the order they appeared in the certificate |
439 | | * (or as they were added, if constructed) |
440 | | */ |
441 | | const std::vector<OID>& get_extension_oids() const |
442 | 0 | { |
443 | 0 | return m_extension_oids; |
444 | 0 | } |
445 | | |
446 | | /** |
447 | | * Return true if an extension was set |
448 | | */ |
449 | | bool extension_set(const OID& oid) const; |
450 | | |
451 | | /** |
452 | | * Return true if an extesion was set and marked critical |
453 | | */ |
454 | | bool critical_extension_set(const OID& oid) const; |
455 | | |
456 | | /** |
457 | | * Return the raw bytes of the extension |
458 | | * Will throw if OID was not set as an extension. |
459 | | */ |
460 | | std::vector<uint8_t> get_extension_bits(const OID& oid) const; |
461 | | |
462 | | void encode_into(class DER_Encoder&) const override; |
463 | | void decode_from(class BER_Decoder&) override; |
464 | | |
465 | | /** |
466 | | * Adds a new extension to the list. |
467 | | * @param extn pointer to the certificate extension (Extensions takes ownership) |
468 | | * @param critical whether this extension should be marked as critical |
469 | | * @throw Invalid_Argument if the extension is already present in the list |
470 | | */ |
471 | | void add(Certificate_Extension* extn, bool critical = false); |
472 | | |
473 | | /** |
474 | | * Adds a new extension to the list unless it already exists. If the extension |
475 | | * already exists within the Extensions object, the extn pointer will be deleted. |
476 | | * |
477 | | * @param extn pointer to the certificate extension (Extensions takes ownership) |
478 | | * @param critical whether this extension should be marked as critical |
479 | | * @return true if the object was added false if the extension was already used |
480 | | */ |
481 | | bool add_new(Certificate_Extension* extn, bool critical = false); |
482 | | |
483 | | /** |
484 | | * Adds an extension to the list or replaces it. |
485 | | * @param extn the certificate extension |
486 | | * @param critical whether this extension should be marked as critical |
487 | | */ |
488 | | void replace(Certificate_Extension* extn, bool critical = false); |
489 | | |
490 | | /** |
491 | | * Remove an extension from the list. Returns true if the |
492 | | * extension had been set, false otherwise. |
493 | | */ |
494 | | bool remove(const OID& oid); |
495 | | |
496 | | /** |
497 | | * Searches for an extension by OID and returns the result. |
498 | | * Only the known extensions types declared in this header |
499 | | * are searched for by this function. |
500 | | * @return Copy of extension with oid, nullptr if not found. |
501 | | * Can avoid creating a copy by using get_extension_object function |
502 | | */ |
503 | | std::unique_ptr<Certificate_Extension> get(const OID& oid) const; |
504 | | |
505 | | /** |
506 | | * Searches for an extension by OID and returns the result decoding |
507 | | * it to some arbitrary extension type chosen by the application. |
508 | | * |
509 | | * Only the unknown extensions, that is, extensions types that |
510 | | * are not declared in this header, are searched for by this |
511 | | * function. |
512 | | * |
513 | | * @return Pointer to new extension with oid, nullptr if not found. |
514 | | */ |
515 | | template<typename T> |
516 | | std::unique_ptr<T> get_raw(const OID& oid) const |
517 | | { |
518 | | auto extn_info = m_extension_info.find(oid); |
519 | | |
520 | | if(extn_info != m_extension_info.end()) |
521 | | { |
522 | | // Unknown_Extension oid_name is empty |
523 | | if(extn_info->second.obj().oid_name() == "") |
524 | | { |
525 | | std::unique_ptr<T> ext(new T); |
526 | | ext->decode_inner(extn_info->second.bits()); |
527 | | return ext; |
528 | | } |
529 | | } |
530 | | return nullptr; |
531 | | } |
532 | | |
533 | | /** |
534 | | * Returns a copy of the list of extensions together with the corresponding |
535 | | * criticality flag. All extensions are encoded as some object, falling back |
536 | | * to Unknown_Extension class which simply allows reading the bytes as well |
537 | | * as the criticality flag. |
538 | | */ |
539 | | std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const; |
540 | | |
541 | | /** |
542 | | * Returns the list of extensions as raw, encoded bytes |
543 | | * together with the corresponding criticality flag. |
544 | | * Contains all extensions, including any extensions encoded as Unknown_Extension |
545 | | */ |
546 | | std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const; |
547 | | |
548 | 31.4k | Extensions() {} |
549 | | |
550 | 0 | Extensions(const Extensions&) = default; |
551 | 17 | Extensions& operator=(const Extensions&) = default; |
552 | | |
553 | | Extensions(Extensions&&) = default; |
554 | | Extensions& operator=(Extensions&&) = default; |
555 | | |
556 | | private: |
557 | | static std::unique_ptr<Certificate_Extension> |
558 | | create_extn_obj(const OID& oid, |
559 | | bool critical, |
560 | | const std::vector<uint8_t>& body); |
561 | | |
562 | | class Extensions_Info |
563 | | { |
564 | | public: |
565 | | Extensions_Info(bool critical, |
566 | | Certificate_Extension* ext) : |
567 | | m_obj(ext), |
568 | | m_bits(m_obj->encode_inner()), |
569 | | m_critical(critical) |
570 | 0 | { |
571 | 0 | } |
572 | | |
573 | | Extensions_Info(bool critical, |
574 | | const std::vector<uint8_t>& encoding, |
575 | | Certificate_Extension* ext) : |
576 | | m_obj(ext), |
577 | | m_bits(encoding), |
578 | | m_critical(critical) |
579 | 45.9k | { |
580 | 45.9k | } |
581 | | |
582 | 0 | bool is_critical() const { return m_critical; } |
583 | 0 | const std::vector<uint8_t>& bits() const { return m_bits; } |
584 | | const Certificate_Extension& obj() const |
585 | 5.74k | { |
586 | 5.74k | BOTAN_ASSERT_NONNULL(m_obj.get()); |
587 | 5.74k | return *m_obj.get(); |
588 | 5.74k | } |
589 | | |
590 | | private: |
591 | | std::shared_ptr<Certificate_Extension> m_obj; |
592 | | std::vector<uint8_t> m_bits; |
593 | | bool m_critical = false; |
594 | | }; |
595 | | |
596 | | std::vector<OID> m_extension_oids; |
597 | | std::map<OID, Extensions_Info> m_extension_info; |
598 | | }; |
599 | | |
600 | | } |
601 | | |
602 | | #endif |