/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 | 39.9k | 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 | 19.8k | 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 | 4.48k | 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 | 5.98k | 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 | 5.98k | {} |
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 | 14.6k | 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 | 843 | {} |
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 | | |
370 | | virtual std::unique_ptr<Certificate_Extension> copy() const = 0; |
371 | | |
372 | | /* |
373 | | * Callback visited during path validation. |
374 | | * |
375 | | * An extension can implement this callback to inspect |
376 | | * the path during path validation. |
377 | | * |
378 | | * If an error occurs during validation of this extension, |
379 | | * an appropriate status code shall be added to cert_status. |
380 | | * |
381 | | * @param subject Subject certificate that contains this extension |
382 | | * @param issuer Issuer certificate |
383 | | * @param status Certificate validation status codes for subject certificate |
384 | | * @param cert_path Certificate path which is currently validated |
385 | | * @param pos Position of subject certificate in cert_path |
386 | | */ |
387 | | virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer, |
388 | | const std::vector<X509_Certificate>& cert_path, |
389 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
390 | | size_t pos); |
391 | | |
392 | 60.1k | virtual ~Certificate_Extension() = default; |
393 | | protected: |
394 | | friend class Extensions; |
395 | 0 | virtual bool should_encode() const { return true; } |
396 | | virtual std::vector<uint8_t> encode_inner() const = 0; |
397 | | virtual void decode_inner(const std::vector<uint8_t>&) = 0; |
398 | | }; |
399 | | |
400 | | /** |
401 | | * X.509 Certificate Extension List |
402 | | */ |
403 | | class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object |
404 | | { |
405 | | public: |
406 | | /** |
407 | | * Look up an object in the extensions, based on OID Returns |
408 | | * nullptr if not set, if the extension was either absent or not |
409 | | * handled. The pointer returned is owned by the Extensions |
410 | | * object. |
411 | | * This would be better with an optional<T> return value |
412 | | */ |
413 | | const Certificate_Extension* get_extension_object(const OID& oid) const; |
414 | | |
415 | | template<typename T> |
416 | | const T* get_extension_object_as(const OID& oid = T::static_oid()) const |
417 | 104k | { |
418 | 104k | if(const Certificate_Extension* extn = get_extension_object(oid)) |
419 | 2.89k | { |
420 | | // Unknown_Extension oid_name is empty |
421 | 2.89k | if(extn->oid_name().empty()) |
422 | 1.95k | { |
423 | 1.95k | return nullptr; |
424 | 1.95k | } |
425 | 942 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) |
426 | 942 | { |
427 | 942 | return extn_as_T; |
428 | 942 | } |
429 | 0 | else |
430 | 0 | { |
431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); |
432 | 0 | } |
433 | 101k | } |
434 | | |
435 | 101k | return nullptr; |
436 | 101k | } Botan::Cert_Extension::Key_Usage const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Key_Usage>(Botan::OID const&) const Line | Count | Source | 417 | 8.93k | { | 418 | 8.93k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 90 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 90 | if(extn->oid_name().empty()) | 422 | 57 | { | 423 | 57 | return nullptr; | 424 | 57 | } | 425 | 33 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 33 | { | 427 | 33 | return extn_as_T; | 428 | 33 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.84k | } | 434 | | | 435 | 8.84k | return nullptr; | 436 | 8.84k | } |
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 | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 49 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 49 | if(extn->oid_name().empty()) | 422 | 45 | { | 423 | 45 | return nullptr; | 424 | 45 | } | 425 | 4 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 4 | { | 427 | 4 | return extn_as_T; | 428 | 4 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.87k | } | 434 | | | 435 | 8.87k | return nullptr; | 436 | 8.87k | } |
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 | 417 | 9.42k | { | 418 | 9.42k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 138 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 138 | if(extn->oid_name().empty()) | 422 | 112 | { | 423 | 112 | return nullptr; | 424 | 112 | } | 425 | 26 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 26 | { | 427 | 26 | return extn_as_T; | 428 | 26 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 9.29k | } | 434 | | | 435 | 9.29k | return nullptr; | 436 | 9.29k | } |
Botan::Cert_Extension::Name_Constraints const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Name_Constraints>(Botan::OID const&) const Line | Count | Source | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 63 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 63 | if(extn->oid_name().empty()) | 422 | 50 | { | 423 | 50 | return nullptr; | 424 | 50 | } | 425 | 13 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 13 | { | 427 | 13 | return extn_as_T; | 428 | 13 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.86k | } | 434 | | | 435 | 8.86k | return nullptr; | 436 | 8.86k | } |
Botan::Cert_Extension::Basic_Constraints const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Basic_Constraints>(Botan::OID const&) const Line | Count | Source | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 92 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 92 | if(extn->oid_name().empty()) | 422 | 65 | { | 423 | 65 | return nullptr; | 424 | 65 | } | 425 | 27 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 27 | { | 427 | 27 | return extn_as_T; | 428 | 27 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.83k | } | 434 | | | 435 | 8.83k | return nullptr; | 436 | 8.83k | } |
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 | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 86 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 86 | if(extn->oid_name().empty()) | 422 | 44 | { | 423 | 44 | return nullptr; | 424 | 44 | } | 425 | 42 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 42 | { | 427 | 42 | return extn_as_T; | 428 | 42 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.84k | } | 434 | | | 435 | 8.84k | return nullptr; | 436 | 8.84k | } |
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 | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 399 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 399 | if(extn->oid_name().empty()) | 422 | 284 | { | 423 | 284 | return nullptr; | 424 | 284 | } | 425 | 115 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 115 | { | 427 | 115 | return extn_as_T; | 428 | 115 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.52k | } | 434 | | | 435 | 8.52k | return nullptr; | 436 | 8.52k | } |
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 | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 83 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 83 | if(extn->oid_name().empty()) | 422 | 51 | { | 423 | 51 | return nullptr; | 424 | 51 | } | 425 | 32 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 32 | { | 427 | 32 | return extn_as_T; | 428 | 32 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.84k | } | 434 | | | 435 | 8.84k | return nullptr; | 436 | 8.84k | } |
Botan::Cert_Extension::Certificate_Policies const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Certificate_Policies>(Botan::OID const&) const Line | Count | Source | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 43 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 43 | if(extn->oid_name().empty()) | 422 | 24 | { | 423 | 24 | return nullptr; | 424 | 24 | } | 425 | 19 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 19 | { | 427 | 19 | return extn_as_T; | 428 | 19 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.88k | } | 434 | | | 435 | 8.88k | return nullptr; | 436 | 8.88k | } |
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 | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 31 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 31 | if(extn->oid_name().empty()) | 422 | 16 | { | 423 | 16 | return nullptr; | 424 | 16 | } | 425 | 15 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 15 | { | 427 | 15 | return extn_as_T; | 428 | 15 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.89k | } | 434 | | | 435 | 8.89k | return nullptr; | 436 | 8.89k | } |
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 | 417 | 8.92k | { | 418 | 8.92k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 216 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 216 | if(extn->oid_name().empty()) | 422 | 182 | { | 423 | 182 | return nullptr; | 424 | 182 | } | 425 | 34 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 34 | { | 427 | 34 | return extn_as_T; | 428 | 34 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 8.71k | } | 434 | | | 435 | 8.71k | return nullptr; | 436 | 8.71k | } |
Botan::Cert_Extension::CRL_Number const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_Number>(Botan::OID const&) const Line | Count | Source | 417 | 500 | { | 418 | 500 | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 22 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 22 | if(extn->oid_name().empty()) | 422 | 19 | { | 423 | 19 | return nullptr; | 424 | 19 | } | 425 | 3 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 3 | { | 427 | 3 | return extn_as_T; | 428 | 3 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 478 | } | 434 | | | 435 | 478 | return nullptr; | 436 | 478 | } |
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 | 417 | 500 | { | 418 | 500 | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 24 | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 24 | if(extn->oid_name().empty()) | 422 | 22 | { | 423 | 22 | return nullptr; | 424 | 22 | } | 425 | 2 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 2 | { | 427 | 2 | return extn_as_T; | 428 | 2 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 476 | } | 434 | | | 435 | 476 | return nullptr; | 436 | 476 | } |
Botan::Cert_Extension::CRL_ReasonCode const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_ReasonCode>(Botan::OID const&) const Line | Count | Source | 417 | 4.46k | { | 418 | 4.46k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 419 | 1.55k | { | 420 | | // Unknown_Extension oid_name is empty | 421 | 1.55k | if(extn->oid_name().empty()) | 422 | 981 | { | 423 | 981 | return nullptr; | 424 | 981 | } | 425 | 577 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 426 | 577 | { | 427 | 577 | return extn_as_T; | 428 | 577 | } | 429 | 0 | else | 430 | 0 | { | 431 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 432 | 0 | } | 433 | 2.90k | } | 434 | | | 435 | 2.90k | return nullptr; | 436 | 2.90k | } |
|
437 | | |
438 | | /** |
439 | | * Return the set of extensions in the order they appeared in the certificate |
440 | | * (or as they were added, if constructed) |
441 | | */ |
442 | | const std::vector<OID>& get_extension_oids() const |
443 | 0 | { |
444 | 0 | return m_extension_oids; |
445 | 0 | } |
446 | | |
447 | | /** |
448 | | * Return true if an extension was set |
449 | | */ |
450 | | bool extension_set(const OID& oid) const; |
451 | | |
452 | | /** |
453 | | * Return true if an extesion was set and marked critical |
454 | | */ |
455 | | bool critical_extension_set(const OID& oid) const; |
456 | | |
457 | | /** |
458 | | * Return the raw bytes of the extension |
459 | | * Will throw if OID was not set as an extension. |
460 | | */ |
461 | | std::vector<uint8_t> get_extension_bits(const OID& oid) const; |
462 | | |
463 | | void encode_into(class DER_Encoder&) const override; |
464 | | void decode_from(class BER_Decoder&) override; |
465 | | |
466 | | /** |
467 | | * Adds a new extension to the list. |
468 | | * @param extn pointer to the certificate extension (Extensions takes ownership) |
469 | | * @param critical whether this extension should be marked as critical |
470 | | * @throw Invalid_Argument if the extension is already present in the list |
471 | | */ |
472 | | void add(std::unique_ptr<Certificate_Extension> extn, bool critical = false); |
473 | | |
474 | | /** |
475 | | * Adds a new extension to the list unless it already exists. If the extension |
476 | | * already exists within the Extensions object, the extn pointer will be deleted. |
477 | | * |
478 | | * @param extn pointer to the certificate extension (Extensions takes ownership) |
479 | | * @param critical whether this extension should be marked as critical |
480 | | * @return true if the object was added false if the extension was already used |
481 | | */ |
482 | | bool add_new(std::unique_ptr<Certificate_Extension> extn, bool critical = false); |
483 | | |
484 | | /** |
485 | | * Adds an extension to the list or replaces it. |
486 | | * @param extn the certificate extension |
487 | | * @param critical whether this extension should be marked as critical |
488 | | */ |
489 | | void replace(std::unique_ptr<Certificate_Extension> extn, bool critical = false); |
490 | | |
491 | | /** |
492 | | * Remove an extension from the list. Returns true if the |
493 | | * extension had been set, false otherwise. |
494 | | */ |
495 | | bool remove(const OID& oid); |
496 | | |
497 | | /** |
498 | | * Searches for an extension by OID and returns the result. |
499 | | * Only the known extensions types declared in this header |
500 | | * are searched for by this function. |
501 | | * @return Copy of extension with oid, nullptr if not found. |
502 | | * Can avoid creating a copy by using get_extension_object function |
503 | | */ |
504 | | std::unique_ptr<Certificate_Extension> get(const OID& oid) const; |
505 | | |
506 | | /** |
507 | | * Searches for an extension by OID and returns the result decoding |
508 | | * it to some arbitrary extension type chosen by the application. |
509 | | * |
510 | | * Only the unknown extensions, that is, extensions types that |
511 | | * are not declared in this header, are searched for by this |
512 | | * function. |
513 | | * |
514 | | * @return Pointer to new extension with oid, nullptr if not found. |
515 | | */ |
516 | | template<typename T> |
517 | | std::unique_ptr<T> get_raw(const OID& oid) const |
518 | | { |
519 | | auto extn_info = m_extension_info.find(oid); |
520 | | |
521 | | if(extn_info != m_extension_info.end()) |
522 | | { |
523 | | // Unknown_Extension oid_name is empty |
524 | | if(extn_info->second.obj().oid_name() == "") |
525 | | { |
526 | | auto ext = std::make_unique<T>(); |
527 | | ext->decode_inner(extn_info->second.bits()); |
528 | | return ext; |
529 | | } |
530 | | } |
531 | | return nullptr; |
532 | | } |
533 | | |
534 | | /** |
535 | | * Returns a copy of the list of extensions together with the corresponding |
536 | | * criticality flag. All extensions are encoded as some object, falling back |
537 | | * to Unknown_Extension class which simply allows reading the bytes as well |
538 | | * as the criticality flag. |
539 | | */ |
540 | | std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const; |
541 | | |
542 | | /** |
543 | | * Returns the list of extensions as raw, encoded bytes |
544 | | * together with the corresponding criticality flag. |
545 | | * Contains all extensions, including any extensions encoded as Unknown_Extension |
546 | | */ |
547 | | std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const; |
548 | | |
549 | 29.5k | Extensions() {} |
550 | | |
551 | 0 | Extensions(const Extensions&) = default; |
552 | 17 | Extensions& operator=(const Extensions&) = default; |
553 | | |
554 | | Extensions(Extensions&&) = default; |
555 | | Extensions& operator=(Extensions&&) = default; |
556 | | |
557 | | private: |
558 | | static std::unique_ptr<Certificate_Extension> |
559 | | create_extn_obj(const OID& oid, |
560 | | bool critical, |
561 | | const std::vector<uint8_t>& body); |
562 | | |
563 | | class Extensions_Info |
564 | | { |
565 | | public: |
566 | | Extensions_Info(bool critical, |
567 | | std::unique_ptr<Certificate_Extension> ext) : |
568 | | m_obj(std::move(ext)), |
569 | | m_bits(m_obj->encode_inner()), |
570 | | m_critical(critical) |
571 | 0 | { |
572 | 0 | } |
573 | | |
574 | | Extensions_Info(bool critical, |
575 | | const std::vector<uint8_t>& encoding, |
576 | | std::unique_ptr<Certificate_Extension> ext) : |
577 | | m_obj(std::move(ext)), |
578 | | m_bits(encoding), |
579 | | m_critical(critical) |
580 | 42.4k | { |
581 | 42.4k | } |
582 | | |
583 | 0 | bool is_critical() const { return m_critical; } |
584 | 0 | const std::vector<uint8_t>& bits() const { return m_bits; } |
585 | | const Certificate_Extension& obj() const |
586 | 2.89k | { |
587 | 2.89k | BOTAN_ASSERT_NONNULL(m_obj.get()); |
588 | 2.89k | return *m_obj.get(); |
589 | 2.89k | } |
590 | | |
591 | | private: |
592 | | std::shared_ptr<Certificate_Extension> m_obj; |
593 | | std::vector<uint8_t> m_bits; |
594 | | bool m_critical = false; |
595 | | }; |
596 | | |
597 | | std::vector<OID> m_extension_oids; |
598 | | std::map<OID, Extensions_Info> m_extension_info; |
599 | | }; |
600 | | |
601 | | } |
602 | | |
603 | | #endif |