Coverage Report

Created: 2021-02-21 07:20

/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