Coverage Report

Created: 2021-05-04 09:02

/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