/src/botan/build/include/botan/x509_ext.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * X.509 Certificate Extensions |
3 | | * (C) 1999-2007,2012 Jack Lloyd |
4 | | * |
5 | | * Botan is released under the Simplified BSD License (see license.txt) |
6 | | */ |
7 | | |
8 | | #ifndef BOTAN_X509_EXTENSIONS_H_ |
9 | | #define BOTAN_X509_EXTENSIONS_H_ |
10 | | |
11 | | #include <botan/asn1_obj.h> |
12 | | #include <botan/asn1_oid.h> |
13 | | #include <botan/asn1_alt_name.h> |
14 | | #include <botan/cert_status.h> |
15 | | #include <botan/name_constraint.h> |
16 | | #include <botan/key_constraint.h> |
17 | | #include <botan/crl_ent.h> |
18 | | #include <set> |
19 | | |
20 | | namespace Botan { |
21 | | |
22 | | class Data_Store; |
23 | | class X509_Certificate; |
24 | | |
25 | | /** |
26 | | * X.509 Certificate Extension |
27 | | */ |
28 | | class BOTAN_PUBLIC_API(2,0) Certificate_Extension |
29 | | { |
30 | | public: |
31 | | /** |
32 | | * @return OID representing this extension |
33 | | */ |
34 | | virtual OID oid_of() const = 0; |
35 | | |
36 | | /* |
37 | | * @return specific OID name |
38 | | * If possible OIDS table should match oid_name to OIDS, ie |
39 | | * OID::from_string(ext->oid_name()) == ext->oid_of() |
40 | | * Should return empty string if OID is not known |
41 | | */ |
42 | | virtual std::string oid_name() const = 0; |
43 | | |
44 | | /** |
45 | | * Make a copy of this extension |
46 | | * @return copy of this |
47 | | */ |
48 | | virtual Certificate_Extension* copy() const = 0; |
49 | | |
50 | | /* |
51 | | * Add the contents of this extension into the information |
52 | | * for the subject and/or issuer, as necessary. |
53 | | * @param subject the subject info |
54 | | * @param issuer the issuer info |
55 | | */ |
56 | | virtual void contents_to(Data_Store& subject, |
57 | | Data_Store& issuer) const = 0; |
58 | | |
59 | | /* |
60 | | * Callback visited during path validation. |
61 | | * |
62 | | * An extension can implement this callback to inspect |
63 | | * the path during path validation. |
64 | | * |
65 | | * If an error occurs during validation of this extension, |
66 | | * an appropriate status code shall be added to cert_status. |
67 | | * |
68 | | * @param subject Subject certificate that contains this extension |
69 | | * @param issuer Issuer certificate |
70 | | * @param status Certificate validation status codes for subject certificate |
71 | | * @param cert_path Certificate path which is currently validated |
72 | | * @param pos Position of subject certificate in cert_path |
73 | | */ |
74 | | virtual void validate(const X509_Certificate& subject, const X509_Certificate& issuer, |
75 | | const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, |
76 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
77 | | size_t pos); |
78 | | |
79 | 53.6k | virtual ~Certificate_Extension() = default; |
80 | | protected: |
81 | | friend class Extensions; |
82 | 0 | virtual bool should_encode() const { return true; } |
83 | | virtual std::vector<uint8_t> encode_inner() const = 0; |
84 | | virtual void decode_inner(const std::vector<uint8_t>&) = 0; |
85 | | }; |
86 | | |
87 | | /** |
88 | | * X.509 Certificate Extension List |
89 | | */ |
90 | | class BOTAN_PUBLIC_API(2,0) Extensions final : public ASN1_Object |
91 | | { |
92 | | public: |
93 | | /** |
94 | | * Look up an object in the extensions, based on OID Returns |
95 | | * nullptr if not set, if the extension was either absent or not |
96 | | * handled. The pointer returned is owned by the Extensions |
97 | | * object. |
98 | | * This would be better with an optional<T> return value |
99 | | */ |
100 | | const Certificate_Extension* get_extension_object(const OID& oid) const; |
101 | | |
102 | | template<typename T> |
103 | | const T* get_extension_object_as(const OID& oid = T::static_oid()) const |
104 | 134k | { |
105 | 134k | if(const Certificate_Extension* extn = get_extension_object(oid)) |
106 | 6.94k | { |
107 | 6.94k | // Unknown_Extension oid_name is empty |
108 | 6.94k | if(extn->oid_name().empty()) |
109 | 3.08k | { |
110 | 3.08k | return nullptr; |
111 | 3.08k | } |
112 | 3.86k | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) |
113 | 3.86k | { |
114 | 3.86k | return extn_as_T; |
115 | 3.86k | } |
116 | 0 | else |
117 | 0 | { |
118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); |
119 | 0 | } |
120 | 127k | } |
121 | 127k | |
122 | 127k | return nullptr; |
123 | 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 | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 323 | { | 107 | 323 | // Unknown_Extension oid_name is empty | 108 | 323 | if(extn->oid_name().empty()) | 109 | 201 | { | 110 | 201 | return nullptr; | 111 | 201 | } | 112 | 122 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 122 | { | 114 | 122 | return extn_as_T; | 115 | 122 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.4k | } | 121 | 11.4k | | 122 | 11.4k | return nullptr; | 123 | 11.4k | } |
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 | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 866 | { | 107 | 866 | // Unknown_Extension oid_name is empty | 108 | 866 | if(extn->oid_name().empty()) | 109 | 266 | { | 110 | 266 | return nullptr; | 111 | 266 | } | 112 | 600 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 600 | { | 114 | 600 | return extn_as_T; | 115 | 600 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 10.8k | } | 121 | 10.8k | | 122 | 10.8k | return nullptr; | 123 | 10.8k | } |
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 | 104 | 12.1k | { | 105 | 12.1k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 1.11k | { | 107 | 1.11k | // Unknown_Extension oid_name is empty | 108 | 1.11k | if(extn->oid_name().empty()) | 109 | 460 | { | 110 | 460 | return nullptr; | 111 | 460 | } | 112 | 656 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 656 | { | 114 | 656 | return extn_as_T; | 115 | 656 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.0k | } | 121 | 11.0k | | 122 | 11.0k | return nullptr; | 123 | 11.0k | } |
Botan::Cert_Extension::Name_Constraints const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Name_Constraints>(Botan::OID const&) const Line | Count | Source | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 233 | { | 107 | 233 | // Unknown_Extension oid_name is empty | 108 | 233 | if(extn->oid_name().empty()) | 109 | 155 | { | 110 | 155 | return nullptr; | 111 | 155 | } | 112 | 78 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 78 | { | 114 | 78 | return extn_as_T; | 115 | 78 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.5k | } | 121 | 11.5k | | 122 | 11.5k | return nullptr; | 123 | 11.5k | } |
Botan::Cert_Extension::Basic_Constraints const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Basic_Constraints>(Botan::OID const&) const Line | Count | Source | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 438 | { | 107 | 438 | // Unknown_Extension oid_name is empty | 108 | 438 | if(extn->oid_name().empty()) | 109 | 162 | { | 110 | 162 | return nullptr; | 111 | 162 | } | 112 | 276 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 276 | { | 114 | 276 | return extn_as_T; | 115 | 276 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.3k | } | 121 | 11.3k | | 122 | 11.3k | return nullptr; | 123 | 11.3k | } |
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 | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 353 | { | 107 | 353 | // Unknown_Extension oid_name is empty | 108 | 353 | if(extn->oid_name().empty()) | 109 | 171 | { | 110 | 171 | return nullptr; | 111 | 171 | } | 112 | 182 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 182 | { | 114 | 182 | return extn_as_T; | 115 | 182 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.4k | } | 121 | 11.4k | | 122 | 11.4k | return nullptr; | 123 | 11.4k | } |
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 | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 503 | { | 107 | 503 | // Unknown_Extension oid_name is empty | 108 | 503 | if(extn->oid_name().empty()) | 109 | 202 | { | 110 | 202 | return nullptr; | 111 | 202 | } | 112 | 301 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 301 | { | 114 | 301 | return extn_as_T; | 115 | 301 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.2k | } | 121 | 11.2k | | 122 | 11.2k | return nullptr; | 123 | 11.2k | } |
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 | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 412 | { | 107 | 412 | // Unknown_Extension oid_name is empty | 108 | 412 | if(extn->oid_name().empty()) | 109 | 243 | { | 110 | 243 | return nullptr; | 111 | 243 | } | 112 | 169 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 169 | { | 114 | 169 | return extn_as_T; | 115 | 169 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.3k | } | 121 | 11.3k | | 122 | 11.3k | return nullptr; | 123 | 11.3k | } |
Botan::Cert_Extension::Certificate_Policies const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::Certificate_Policies>(Botan::OID const&) const Line | Count | Source | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 355 | { | 107 | 355 | // Unknown_Extension oid_name is empty | 108 | 355 | if(extn->oid_name().empty()) | 109 | 233 | { | 110 | 233 | return nullptr; | 111 | 233 | } | 112 | 122 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 122 | { | 114 | 122 | return extn_as_T; | 115 | 122 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.4k | } | 121 | 11.4k | | 122 | 11.4k | return nullptr; | 123 | 11.4k | } |
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 | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 187 | { | 107 | 187 | // Unknown_Extension oid_name is empty | 108 | 187 | if(extn->oid_name().empty()) | 109 | 122 | { | 110 | 122 | return nullptr; | 111 | 122 | } | 112 | 65 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 65 | { | 114 | 65 | return extn_as_T; | 115 | 65 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.5k | } | 121 | 11.5k | | 122 | 11.5k | return nullptr; | 123 | 11.5k | } |
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 | 104 | 11.7k | { | 105 | 11.7k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 236 | { | 107 | 236 | // Unknown_Extension oid_name is empty | 108 | 236 | if(extn->oid_name().empty()) | 109 | 162 | { | 110 | 162 | return nullptr; | 111 | 162 | } | 112 | 74 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 74 | { | 114 | 74 | return extn_as_T; | 115 | 74 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 11.5k | } | 121 | 11.5k | | 122 | 11.5k | return nullptr; | 123 | 11.5k | } |
Botan::Cert_Extension::CRL_Number const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_Number>(Botan::OID const&) const Line | Count | Source | 104 | 395 | { | 105 | 395 | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 7 | { | 107 | 7 | // Unknown_Extension oid_name is empty | 108 | 7 | if(extn->oid_name().empty()) | 109 | 6 | { | 110 | 6 | return nullptr; | 111 | 6 | } | 112 | 1 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 1 | { | 114 | 1 | return extn_as_T; | 115 | 1 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 388 | } | 121 | 388 | | 122 | 388 | return nullptr; | 123 | 388 | } |
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 | 104 | 395 | { | 105 | 395 | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 19 | { | 107 | 19 | // Unknown_Extension oid_name is empty | 108 | 19 | if(extn->oid_name().empty()) | 109 | 10 | { | 110 | 10 | return nullptr; | 111 | 10 | } | 112 | 9 | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 9 | { | 114 | 9 | return extn_as_T; | 115 | 9 | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 376 | } | 121 | 376 | | 122 | 376 | return nullptr; | 123 | 376 | } |
Botan::Cert_Extension::CRL_ReasonCode const* Botan::Extensions::get_extension_object_as<Botan::Cert_Extension::CRL_ReasonCode>(Botan::OID const&) const Line | Count | Source | 104 | 4.07k | { | 105 | 4.07k | if(const Certificate_Extension* extn = get_extension_object(oid)) | 106 | 1.89k | { | 107 | 1.89k | // Unknown_Extension oid_name is empty | 108 | 1.89k | if(extn->oid_name().empty()) | 109 | 693 | { | 110 | 693 | return nullptr; | 111 | 693 | } | 112 | 1.20k | else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) | 113 | 1.20k | { | 114 | 1.20k | return extn_as_T; | 115 | 1.20k | } | 116 | 0 | else | 117 | 0 | { | 118 | 0 | throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed"); | 119 | 0 | } | 120 | 2.17k | } | 121 | 2.17k | | 122 | 2.17k | return nullptr; | 123 | 2.17k | } |
|
124 | | |
125 | | /** |
126 | | * Return the set of extensions in the order they appeared in the certificate |
127 | | * (or as they were added, if constructed) |
128 | | */ |
129 | | const std::vector<OID>& get_extension_oids() const |
130 | 0 | { |
131 | 0 | return m_extension_oids; |
132 | 0 | } |
133 | | |
134 | | /** |
135 | | * Return true if an extension was set |
136 | | */ |
137 | | bool extension_set(const OID& oid) const; |
138 | | |
139 | | /** |
140 | | * Return true if an extesion was set and marked critical |
141 | | */ |
142 | | bool critical_extension_set(const OID& oid) const; |
143 | | |
144 | | /** |
145 | | * Return the raw bytes of the extension |
146 | | * Will throw if OID was not set as an extension. |
147 | | */ |
148 | | std::vector<uint8_t> get_extension_bits(const OID& oid) const; |
149 | | |
150 | | void encode_into(class DER_Encoder&) const override; |
151 | | void decode_from(class BER_Decoder&) override; |
152 | | void contents_to(Data_Store&, Data_Store&) const; |
153 | | |
154 | | /** |
155 | | * Adds a new extension to the list. |
156 | | * @param extn pointer to the certificate extension (Extensions takes ownership) |
157 | | * @param critical whether this extension should be marked as critical |
158 | | * @throw Invalid_Argument if the extension is already present in the list |
159 | | */ |
160 | | void add(Certificate_Extension* extn, bool critical = false); |
161 | | |
162 | | /** |
163 | | * Adds a new extension to the list unless it already exists. If the extension |
164 | | * already exists within the Extensions object, the extn pointer will be deleted. |
165 | | * |
166 | | * @param extn pointer to the certificate extension (Extensions takes ownership) |
167 | | * @param critical whether this extension should be marked as critical |
168 | | * @return true if the object was added false if the extension was already used |
169 | | */ |
170 | | bool add_new(Certificate_Extension* extn, bool critical = false); |
171 | | |
172 | | /** |
173 | | * Adds an extension to the list or replaces it. |
174 | | * @param extn the certificate extension |
175 | | * @param critical whether this extension should be marked as critical |
176 | | */ |
177 | | void replace(Certificate_Extension* extn, bool critical = false); |
178 | | |
179 | | /** |
180 | | * Remove an extension from the list. Returns true if the |
181 | | * extension had been set, false otherwise. |
182 | | */ |
183 | | bool remove(const OID& oid); |
184 | | |
185 | | /** |
186 | | * Searches for an extension by OID and returns the result. |
187 | | * Only the known extensions types declared in this header |
188 | | * are searched for by this function. |
189 | | * @return Copy of extension with oid, nullptr if not found. |
190 | | * Can avoid creating a copy by using get_extension_object function |
191 | | */ |
192 | | std::unique_ptr<Certificate_Extension> get(const OID& oid) const; |
193 | | |
194 | | /** |
195 | | * Searches for an extension by OID and returns the result decoding |
196 | | * it to some arbitrary extension type chosen by the application. |
197 | | * |
198 | | * Only the unknown extensions, that is, extensions types that |
199 | | * are not declared in this header, are searched for by this |
200 | | * function. |
201 | | * |
202 | | * @return Pointer to new extension with oid, nullptr if not found. |
203 | | */ |
204 | | template<typename T> |
205 | | std::unique_ptr<T> get_raw(const OID& oid) const |
206 | | { |
207 | | auto extn_info = m_extension_info.find(oid); |
208 | | |
209 | | if(extn_info != m_extension_info.end()) |
210 | | { |
211 | | // Unknown_Extension oid_name is empty |
212 | | if(extn_info->second.obj().oid_name() == "") |
213 | | { |
214 | | std::unique_ptr<T> ext(new T); |
215 | | ext->decode_inner(extn_info->second.bits()); |
216 | | return ext; |
217 | | } |
218 | | } |
219 | | return nullptr; |
220 | | } |
221 | | |
222 | | /** |
223 | | * Returns a copy of the list of extensions together with the corresponding |
224 | | * criticality flag. All extensions are encoded as some object, falling back |
225 | | * to Unknown_Extension class which simply allows reading the bytes as well |
226 | | * as the criticality flag. |
227 | | */ |
228 | | std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const; |
229 | | |
230 | | /** |
231 | | * Returns the list of extensions as raw, encoded bytes |
232 | | * together with the corresponding criticality flag. |
233 | | * Contains all extensions, including any extensions encoded as Unknown_Extension |
234 | | */ |
235 | | std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const; |
236 | | |
237 | 31.4k | Extensions() {} |
238 | | |
239 | 0 | Extensions(const Extensions&) = default; |
240 | 27 | Extensions& operator=(const Extensions&) = default; |
241 | | |
242 | | Extensions(Extensions&&) = default; |
243 | | Extensions& operator=(Extensions&&) = default; |
244 | | |
245 | | private: |
246 | | static std::unique_ptr<Certificate_Extension> |
247 | | create_extn_obj(const OID& oid, |
248 | | bool critical, |
249 | | const std::vector<uint8_t>& body); |
250 | | |
251 | | class Extensions_Info |
252 | | { |
253 | | public: |
254 | | Extensions_Info(bool critical, |
255 | | Certificate_Extension* ext) : |
256 | | m_obj(ext), |
257 | | m_bits(m_obj->encode_inner()), |
258 | | m_critical(critical) |
259 | 0 | { |
260 | 0 | } |
261 | | |
262 | | Extensions_Info(bool critical, |
263 | | const std::vector<uint8_t>& encoding, |
264 | | Certificate_Extension* ext) : |
265 | | m_obj(ext), |
266 | | m_bits(encoding), |
267 | | m_critical(critical) |
268 | 39.2k | { |
269 | 39.2k | } |
270 | | |
271 | 13.1k | bool is_critical() const { return m_critical; } |
272 | 0 | const std::vector<uint8_t>& bits() const { return m_bits; } |
273 | | const Certificate_Extension& obj() const |
274 | 33.1k | { |
275 | 33.1k | BOTAN_ASSERT_NONNULL(m_obj.get()); |
276 | 33.1k | return *m_obj.get(); |
277 | 33.1k | } |
278 | | |
279 | | private: |
280 | | std::shared_ptr<Certificate_Extension> m_obj; |
281 | | std::vector<uint8_t> m_bits; |
282 | | bool m_critical = false; |
283 | | }; |
284 | | |
285 | | std::vector<OID> m_extension_oids; |
286 | | std::map<OID, Extensions_Info> m_extension_info; |
287 | | }; |
288 | | |
289 | | namespace Cert_Extension { |
290 | | |
291 | | static const size_t NO_CERT_PATH_LIMIT = 0xFFFFFFF0; |
292 | | |
293 | | /** |
294 | | * Basic Constraints Extension |
295 | | */ |
296 | | class BOTAN_PUBLIC_API(2,0) Basic_Constraints final : public Certificate_Extension |
297 | | { |
298 | | public: |
299 | | Basic_Constraints* copy() const override |
300 | 0 | { return new Basic_Constraints(m_is_ca, m_path_limit); } |
301 | | |
302 | | Basic_Constraints(bool ca = false, size_t limit = 0) : |
303 | 1.67k | m_is_ca(ca), m_path_limit(limit) {} |
304 | | |
305 | 276 | bool get_is_ca() const { return m_is_ca; } |
306 | | size_t get_path_limit() const; |
307 | | |
308 | 44.1k | static OID static_oid() { return OID("2.5.29.19"); } |
309 | 0 | OID oid_of() const override { return static_oid(); } |
310 | | |
311 | | private: |
312 | | std::string oid_name() const override |
313 | 552 | { return "X509v3.BasicConstraints"; } |
314 | | |
315 | | std::vector<uint8_t> encode_inner() const override; |
316 | | void decode_inner(const std::vector<uint8_t>&) override; |
317 | | void contents_to(Data_Store&, Data_Store&) const override; |
318 | | |
319 | | bool m_is_ca; |
320 | | size_t m_path_limit; |
321 | | }; |
322 | | |
323 | | /** |
324 | | * Key Usage Constraints Extension |
325 | | */ |
326 | | class BOTAN_PUBLIC_API(2,0) Key_Usage final : public Certificate_Extension |
327 | | { |
328 | | public: |
329 | 0 | Key_Usage* copy() const override { return new Key_Usage(m_constraints); } |
330 | | |
331 | 1.39k | explicit Key_Usage(Key_Constraints c = NO_CONSTRAINTS) : m_constraints(c) {} |
332 | | |
333 | 122 | Key_Constraints get_constraints() const { return m_constraints; } |
334 | | |
335 | 49.2k | static OID static_oid() { return OID("2.5.29.15"); } |
336 | 0 | OID oid_of() const override { return static_oid(); } |
337 | | |
338 | | private: |
339 | 242 | std::string oid_name() const override { return "X509v3.KeyUsage"; } |
340 | | |
341 | | bool should_encode() const override |
342 | 0 | { return (m_constraints != NO_CONSTRAINTS); } |
343 | | std::vector<uint8_t> encode_inner() const override; |
344 | | void decode_inner(const std::vector<uint8_t>&) override; |
345 | | void contents_to(Data_Store&, Data_Store&) const override; |
346 | | |
347 | | Key_Constraints m_constraints; |
348 | | }; |
349 | | |
350 | | /** |
351 | | * Subject Key Identifier Extension |
352 | | */ |
353 | | class BOTAN_PUBLIC_API(2,0) Subject_Key_ID final : public Certificate_Extension |
354 | | { |
355 | | public: |
356 | 1.89k | Subject_Key_ID() = default; |
357 | | |
358 | 0 | explicit Subject_Key_ID(const std::vector<uint8_t>& k) : m_key_id(k) {} |
359 | | |
360 | | Subject_Key_ID(const std::vector<uint8_t>& public_key, |
361 | | const std::string& hash_fn); |
362 | | |
363 | | Subject_Key_ID* copy() const override |
364 | 0 | { return new Subject_Key_ID(m_key_id); } |
365 | | |
366 | 600 | const std::vector<uint8_t>& get_key_id() const { return m_key_id; } |
367 | | |
368 | 51.1k | static OID static_oid() { return OID("2.5.29.14"); } |
369 | 0 | OID oid_of() const override { return static_oid(); } |
370 | | |
371 | | private: |
372 | | |
373 | | std::string oid_name() const override |
374 | 1.20k | { return "X509v3.SubjectKeyIdentifier"; } |
375 | | |
376 | 0 | bool should_encode() const override { return (m_key_id.size() > 0); } |
377 | | std::vector<uint8_t> encode_inner() const override; |
378 | | void decode_inner(const std::vector<uint8_t>&) override; |
379 | | void contents_to(Data_Store&, Data_Store&) const override; |
380 | | |
381 | | std::vector<uint8_t> m_key_id; |
382 | | }; |
383 | | |
384 | | /** |
385 | | * Authority Key Identifier Extension |
386 | | */ |
387 | | class BOTAN_PUBLIC_API(2,0) Authority_Key_ID final : public Certificate_Extension |
388 | | { |
389 | | public: |
390 | | Authority_Key_ID* copy() const override |
391 | 0 | { return new Authority_Key_ID(m_key_id); } |
392 | | |
393 | 1.80k | Authority_Key_ID() = default; |
394 | 0 | explicit Authority_Key_ID(const std::vector<uint8_t>& k) : m_key_id(k) {} |
395 | | |
396 | 656 | const std::vector<uint8_t>& get_key_id() const { return m_key_id; } |
397 | | |
398 | 39.5k | static OID static_oid() { return OID("2.5.29.35"); } |
399 | 0 | OID oid_of() const override { return static_oid(); } |
400 | | |
401 | | private: |
402 | | std::string oid_name() const override |
403 | 1.30k | { return "X509v3.AuthorityKeyIdentifier"; } |
404 | | |
405 | 0 | bool should_encode() const override { return (m_key_id.size() > 0); } |
406 | | std::vector<uint8_t> encode_inner() const override; |
407 | | void decode_inner(const std::vector<uint8_t>&) override; |
408 | | void contents_to(Data_Store&, Data_Store&) const override; |
409 | | |
410 | | std::vector<uint8_t> m_key_id; |
411 | | }; |
412 | | |
413 | | /** |
414 | | * Subject Alternative Name Extension |
415 | | */ |
416 | | class BOTAN_PUBLIC_API(2,4) Subject_Alternative_Name final : public Certificate_Extension |
417 | | { |
418 | | public: |
419 | 601 | const AlternativeName& get_alt_name() const { return m_alt_name; } |
420 | | |
421 | 47.8k | static OID static_oid() { return OID("2.5.29.17"); } |
422 | 0 | OID oid_of() const override { return static_oid(); } |
423 | | |
424 | | Subject_Alternative_Name* copy() const override |
425 | 0 | { return new Subject_Alternative_Name(get_alt_name()); } |
426 | | |
427 | | explicit Subject_Alternative_Name(const AlternativeName& name = AlternativeName()) : |
428 | 2.28k | m_alt_name(name) {} |
429 | | |
430 | | private: |
431 | 601 | std::string oid_name() const override { return "X509v3.SubjectAlternativeName"; } |
432 | | |
433 | 0 | bool should_encode() const override { return m_alt_name.has_items(); } |
434 | | std::vector<uint8_t> encode_inner() const override; |
435 | | void decode_inner(const std::vector<uint8_t>&) override; |
436 | | void contents_to(Data_Store&, Data_Store&) const override; |
437 | | |
438 | | AlternativeName m_alt_name; |
439 | | }; |
440 | | |
441 | | /** |
442 | | * Issuer Alternative Name Extension |
443 | | */ |
444 | | class BOTAN_PUBLIC_API(2,0) Issuer_Alternative_Name final : public Certificate_Extension |
445 | | { |
446 | | public: |
447 | 363 | const AlternativeName& get_alt_name() const { return m_alt_name; } |
448 | | |
449 | 45.5k | static OID static_oid() { return OID("2.5.29.18"); } |
450 | 0 | OID oid_of() const override { return static_oid(); } |
451 | | |
452 | | Issuer_Alternative_Name* copy() const override |
453 | 0 | { return new Issuer_Alternative_Name(get_alt_name()); } |
454 | | |
455 | | explicit Issuer_Alternative_Name(const AlternativeName& name = AlternativeName()) : |
456 | 1.41k | m_alt_name(name) {} |
457 | | |
458 | | private: |
459 | 363 | std::string oid_name() const override { return "X509v3.IssuerAlternativeName"; } |
460 | | |
461 | 0 | bool should_encode() const override { return m_alt_name.has_items(); } |
462 | | std::vector<uint8_t> encode_inner() const override; |
463 | | void decode_inner(const std::vector<uint8_t>&) override; |
464 | | void contents_to(Data_Store&, Data_Store&) const override; |
465 | | |
466 | | AlternativeName m_alt_name; |
467 | | }; |
468 | | |
469 | | /** |
470 | | * Extended Key Usage Extension |
471 | | */ |
472 | | class BOTAN_PUBLIC_API(2,0) Extended_Key_Usage final : public Certificate_Extension |
473 | | { |
474 | | public: |
475 | | Extended_Key_Usage* copy() const override |
476 | 0 | { return new Extended_Key_Usage(m_oids); } |
477 | | |
478 | 1.17k | Extended_Key_Usage() = default; |
479 | 0 | explicit Extended_Key_Usage(const std::vector<OID>& o) : m_oids(o) {} |
480 | | |
481 | 169 | const std::vector<OID>& get_oids() const { return m_oids; } |
482 | | |
483 | 30.4k | static OID static_oid() { return OID("2.5.29.37"); } |
484 | 0 | OID oid_of() const override { return static_oid(); } |
485 | | |
486 | | private: |
487 | 338 | std::string oid_name() const override { return "X509v3.ExtendedKeyUsage"; } |
488 | | |
489 | 0 | bool should_encode() const override { return (m_oids.size() > 0); } |
490 | | std::vector<uint8_t> encode_inner() const override; |
491 | | void decode_inner(const std::vector<uint8_t>&) override; |
492 | | void contents_to(Data_Store&, Data_Store&) const override; |
493 | | |
494 | | std::vector<OID> m_oids; |
495 | | }; |
496 | | |
497 | | /** |
498 | | * Name Constraints |
499 | | */ |
500 | | class BOTAN_PUBLIC_API(2,0) Name_Constraints final : public Certificate_Extension |
501 | | { |
502 | | public: |
503 | | Name_Constraints* copy() const override |
504 | 0 | { return new Name_Constraints(m_name_constraints); } |
505 | | |
506 | 3.66k | Name_Constraints() = default; |
507 | 0 | Name_Constraints(const NameConstraints &nc) : m_name_constraints(nc) {} |
508 | | |
509 | | void validate(const X509_Certificate& subject, const X509_Certificate& issuer, |
510 | | const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, |
511 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
512 | | size_t pos) override; |
513 | | |
514 | 78 | const NameConstraints& get_name_constraints() const { return m_name_constraints; } |
515 | | |
516 | 37.3k | static OID static_oid() { return OID("2.5.29.30"); } |
517 | 0 | OID oid_of() const override { return static_oid(); } |
518 | | |
519 | | private: |
520 | | std::string oid_name() const override |
521 | 156 | { return "X509v3.NameConstraints"; } |
522 | | |
523 | 0 | bool should_encode() const override { return true; } |
524 | | std::vector<uint8_t> encode_inner() const override; |
525 | | void decode_inner(const std::vector<uint8_t>&) override; |
526 | | void contents_to(Data_Store&, Data_Store&) const override; |
527 | | |
528 | | NameConstraints m_name_constraints; |
529 | | }; |
530 | | |
531 | | /** |
532 | | * Certificate Policies Extension |
533 | | */ |
534 | | class BOTAN_PUBLIC_API(2,0) Certificate_Policies final : public Certificate_Extension |
535 | | { |
536 | | public: |
537 | | Certificate_Policies* copy() const override |
538 | 0 | { return new Certificate_Policies(m_oids); } |
539 | | |
540 | 1.09k | Certificate_Policies() = default; |
541 | 0 | explicit Certificate_Policies(const std::vector<OID>& o) : m_oids(o) {} |
542 | | |
543 | | BOTAN_DEPRECATED("Use get_policy_oids") |
544 | 0 | std::vector<OID> get_oids() const { return m_oids; } |
545 | | |
546 | 122 | const std::vector<OID>& get_policy_oids() const { return m_oids; } |
547 | | |
548 | 31.5k | static OID static_oid() { return OID("2.5.29.32"); } |
549 | 0 | OID oid_of() const override { return static_oid(); } |
550 | | |
551 | | void validate(const X509_Certificate& subject, const X509_Certificate& issuer, |
552 | | const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path, |
553 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
554 | | size_t pos) override; |
555 | | private: |
556 | | std::string oid_name() const override |
557 | 243 | { return "X509v3.CertificatePolicies"; } |
558 | | |
559 | 0 | bool should_encode() const override { return (m_oids.size() > 0); } |
560 | | std::vector<uint8_t> encode_inner() const override; |
561 | | void decode_inner(const std::vector<uint8_t>&) override; |
562 | | void contents_to(Data_Store&, Data_Store&) const override; |
563 | | |
564 | | std::vector<OID> m_oids; |
565 | | }; |
566 | | |
567 | | /** |
568 | | * Authority Information Access Extension |
569 | | */ |
570 | | class BOTAN_PUBLIC_API(2,0) Authority_Information_Access final : public Certificate_Extension |
571 | | { |
572 | | public: |
573 | | Authority_Information_Access* copy() const override |
574 | 0 | { return new Authority_Information_Access(m_ocsp_responder, m_ca_issuers); } |
575 | | |
576 | 675 | Authority_Information_Access() = default; |
577 | | |
578 | | explicit Authority_Information_Access(const std::string& ocsp, const std::vector<std::string>& ca_issuers = std::vector<std::string>()) : |
579 | 0 | m_ocsp_responder(ocsp), m_ca_issuers(ca_issuers) {} |
580 | | |
581 | 65 | std::string ocsp_responder() const { return m_ocsp_responder; } |
582 | | |
583 | 29.2k | static OID static_oid() { return OID("1.3.6.1.5.5.7.1.1"); } |
584 | 0 | OID oid_of() const override { return static_oid(); } |
585 | 65 | const std::vector<std::string> ca_issuers() const { return m_ca_issuers; } |
586 | | |
587 | | private: |
588 | | std::string oid_name() const override |
589 | 130 | { return "PKIX.AuthorityInformationAccess"; } |
590 | | |
591 | 0 | bool should_encode() const override { return (!m_ocsp_responder.empty()); } |
592 | | |
593 | | std::vector<uint8_t> encode_inner() const override; |
594 | | void decode_inner(const std::vector<uint8_t>&) override; |
595 | | |
596 | | void contents_to(Data_Store&, Data_Store&) const override; |
597 | | |
598 | | std::string m_ocsp_responder; |
599 | | std::vector<std::string> m_ca_issuers; |
600 | | }; |
601 | | |
602 | | /** |
603 | | * CRL Number Extension |
604 | | */ |
605 | | class BOTAN_PUBLIC_API(2,0) CRL_Number final : public Certificate_Extension |
606 | | { |
607 | | public: |
608 | | CRL_Number* copy() const override; |
609 | | |
610 | 652 | CRL_Number() : m_has_value(false), m_crl_number(0) {} |
611 | 0 | CRL_Number(size_t n) : m_has_value(true), m_crl_number(n) {} |
612 | | |
613 | | size_t get_crl_number() const; |
614 | | |
615 | 31.1k | static OID static_oid() { return OID("2.5.29.20"); } |
616 | 0 | OID oid_of() const override { return static_oid(); } |
617 | | |
618 | | private: |
619 | 21 | std::string oid_name() const override { return "X509v3.CRLNumber"; } |
620 | | |
621 | 0 | bool should_encode() const override { return m_has_value; } |
622 | | std::vector<uint8_t> encode_inner() const override; |
623 | | void decode_inner(const std::vector<uint8_t>&) override; |
624 | | void contents_to(Data_Store&, Data_Store&) const override; |
625 | | |
626 | | bool m_has_value; |
627 | | size_t m_crl_number; |
628 | | }; |
629 | | |
630 | | /** |
631 | | * CRL Entry Reason Code Extension |
632 | | */ |
633 | | class BOTAN_PUBLIC_API(2,0) CRL_ReasonCode final : public Certificate_Extension |
634 | | { |
635 | | public: |
636 | | CRL_ReasonCode* copy() const override |
637 | 0 | { return new CRL_ReasonCode(m_reason); } |
638 | | |
639 | 2.69k | explicit CRL_ReasonCode(CRL_Code r = UNSPECIFIED) : m_reason(r) {} |
640 | | |
641 | 1.20k | CRL_Code get_reason() const { return m_reason; } |
642 | | |
643 | 34.1k | static OID static_oid() { return OID("2.5.29.21"); } |
644 | 0 | OID oid_of() const override { return static_oid(); } |
645 | | |
646 | | private: |
647 | 1.22k | std::string oid_name() const override { return "X509v3.ReasonCode"; } |
648 | | |
649 | 0 | bool should_encode() const override { return (m_reason != UNSPECIFIED); } |
650 | | std::vector<uint8_t> encode_inner() const override; |
651 | | void decode_inner(const std::vector<uint8_t>&) override; |
652 | | void contents_to(Data_Store&, Data_Store&) const override; |
653 | | |
654 | | CRL_Code m_reason; |
655 | | }; |
656 | | |
657 | | /** |
658 | | * CRL Distribution Points Extension |
659 | | * todo enforce restrictions from RFC 5280 4.2.1.13 |
660 | | */ |
661 | | class BOTAN_PUBLIC_API(2,0) CRL_Distribution_Points final : public Certificate_Extension |
662 | | { |
663 | | public: |
664 | | class BOTAN_PUBLIC_API(2,0) Distribution_Point final : public ASN1_Object |
665 | | { |
666 | | public: |
667 | | void encode_into(class DER_Encoder&) const override; |
668 | | void decode_from(class BER_Decoder&) override; |
669 | | |
670 | 570 | const AlternativeName& point() const { return m_point; } |
671 | | private: |
672 | | AlternativeName m_point; |
673 | | }; |
674 | | |
675 | | CRL_Distribution_Points* copy() const override |
676 | 0 | { return new CRL_Distribution_Points(m_distribution_points); } |
677 | | |
678 | 1.65k | CRL_Distribution_Points() = default; |
679 | | |
680 | | explicit CRL_Distribution_Points(const std::vector<Distribution_Point>& points) : |
681 | 0 | m_distribution_points(points) {} |
682 | | |
683 | | const std::vector<Distribution_Point>& distribution_points() const |
684 | 0 | { return m_distribution_points; } |
685 | | |
686 | | const std::vector<std::string>& crl_distribution_urls() const |
687 | 74 | { return m_crl_distribution_urls; } |
688 | | |
689 | 33.6k | static OID static_oid() { return OID("2.5.29.31"); } |
690 | 0 | OID oid_of() const override { return static_oid(); } |
691 | | |
692 | | private: |
693 | | std::string oid_name() const override |
694 | 147 | { return "X509v3.CRLDistributionPoints"; } |
695 | | |
696 | | bool should_encode() const override |
697 | 0 | { return !m_distribution_points.empty(); } |
698 | | |
699 | | std::vector<uint8_t> encode_inner() const override; |
700 | | void decode_inner(const std::vector<uint8_t>&) override; |
701 | | void contents_to(Data_Store&, Data_Store&) const override; |
702 | | |
703 | | std::vector<Distribution_Point> m_distribution_points; |
704 | | std::vector<std::string> m_crl_distribution_urls; |
705 | | }; |
706 | | |
707 | | /** |
708 | | * CRL Issuing Distribution Point Extension |
709 | | * todo enforce restrictions from RFC 5280 5.2.5 |
710 | | */ |
711 | | class CRL_Issuing_Distribution_Point final : public Certificate_Extension |
712 | | { |
713 | | public: |
714 | 462 | CRL_Issuing_Distribution_Point() = default; |
715 | | |
716 | | explicit CRL_Issuing_Distribution_Point(const CRL_Distribution_Points::Distribution_Point& distribution_point) : |
717 | 0 | m_distribution_point(distribution_point) {} |
718 | | |
719 | | CRL_Issuing_Distribution_Point* copy() const override |
720 | 0 | { return new CRL_Issuing_Distribution_Point(m_distribution_point); } |
721 | | |
722 | | const AlternativeName& get_point() const |
723 | 9 | { return m_distribution_point.point(); } |
724 | | |
725 | 20.6k | static OID static_oid() { return OID("2.5.29.28"); } |
726 | 0 | OID oid_of() const override { return static_oid(); } |
727 | | |
728 | | private: |
729 | | std::string oid_name() const override |
730 | 25 | { return "X509v3.CRLIssuingDistributionPoint"; } |
731 | | |
732 | 0 | bool should_encode() const override { return true; } |
733 | | std::vector<uint8_t> encode_inner() const override; |
734 | | void decode_inner(const std::vector<uint8_t>&) override; |
735 | | void contents_to(Data_Store&, Data_Store&) const override; |
736 | | |
737 | | CRL_Distribution_Points::Distribution_Point m_distribution_point; |
738 | | }; |
739 | | |
740 | | /** |
741 | | * An unknown X.509 extension |
742 | | * Will add a failure to the path validation result, if critical |
743 | | */ |
744 | | class BOTAN_PUBLIC_API(2,4) Unknown_Extension final : public Certificate_Extension |
745 | | { |
746 | | public: |
747 | | Unknown_Extension(const OID& oid, bool critical) : |
748 | 31.1k | m_oid(oid), m_critical(critical) {} |
749 | | |
750 | | Unknown_Extension* copy() const override |
751 | 0 | { return new Unknown_Extension(m_oid, m_critical); } |
752 | | |
753 | | /** |
754 | | * Return the OID of this unknown extension |
755 | | */ |
756 | | OID oid_of() const override |
757 | 0 | { return m_oid; } |
758 | | |
759 | | //static_oid not defined for Unknown_Extension |
760 | | |
761 | | /** |
762 | | * Return the extension contents |
763 | | */ |
764 | 0 | const std::vector<uint8_t>& extension_contents() const { return m_bytes; } |
765 | | |
766 | | /** |
767 | | * Return if this extension was marked critical |
768 | | */ |
769 | 0 | bool is_critical_extension() const { return m_critical; } |
770 | | |
771 | | void validate(const X509_Certificate&, const X509_Certificate&, |
772 | | const std::vector<std::shared_ptr<const X509_Certificate>>&, |
773 | | std::vector<std::set<Certificate_Status_Code>>& cert_status, |
774 | | size_t pos) override |
775 | 0 | { |
776 | 0 | if(m_critical) |
777 | 0 | { |
778 | 0 | cert_status.at(pos).insert(Certificate_Status_Code::UNKNOWN_CRITICAL_EXTENSION); |
779 | 0 | } |
780 | 0 | } |
781 | | |
782 | | private: |
783 | 13.5k | std::string oid_name() const override { return ""; } |
784 | | |
785 | 0 | bool should_encode() const override { return true; } |
786 | | std::vector<uint8_t> encode_inner() const override; |
787 | | void decode_inner(const std::vector<uint8_t>&) override; |
788 | | void contents_to(Data_Store&, Data_Store&) const override; |
789 | | |
790 | | OID m_oid; |
791 | | bool m_critical; |
792 | | std::vector<uint8_t> m_bytes; |
793 | | }; |
794 | | |
795 | | } |
796 | | |
797 | | } |
798 | | |
799 | | #endif |