Botan 3.7.1
Crypto and TLS for C&
pkix_types.h
Go to the documentation of this file.
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
16#include <botan/assert.h>
17#include <botan/pkix_enums.h>
18#include <iosfwd>
19#include <map>
20#include <set>
21#include <string>
22#include <string_view>
23#include <variant>
24#include <vector>
25
26namespace Botan {
27
28class X509_Certificate;
29class Public_Key;
30
31BOTAN_DEPRECATED("Use Key_Constraints::to_string")
32
34 return c.to_string();
35}
36
37/**
38* Distinguished Name
39*/
41 public:
42 X509_DN() = default;
43
44 explicit X509_DN(const std::multimap<OID, std::string>& args) {
45 for(const auto& i : args) {
46 add_attribute(i.first, i.second);
47 }
48 }
49
50 explicit X509_DN(const std::multimap<std::string, std::string>& args) {
51 for(const auto& i : args) {
52 add_attribute(i.first, i.second);
53 }
54 }
55
56 void encode_into(DER_Encoder&) const override;
57 void decode_from(BER_Decoder&) override;
58
59 bool has_field(const OID& oid) const;
60 ASN1_String get_first_attribute(const OID& oid) const;
61
62 /*
63 * Return the BER encoded data, if any
64 */
65 const std::vector<uint8_t>& get_bits() const { return m_dn_bits; }
66
67 std::vector<uint8_t> DER_encode() const;
68
69 bool empty() const { return m_rdn.empty(); }
70
71 size_t count() const { return m_rdn.size(); }
72
73 std::string to_string() const;
74
75 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(std::string_view attr) const;
81 std::vector<std::string> get_attribute(std::string_view attr) const;
82 std::string get_first_attribute(std::string_view attr) const;
83
84 void add_attribute(std::string_view key, std::string_view val);
85
86 void add_attribute(const OID& oid, std::string_view val) { add_attribute(oid, ASN1_String(val)); }
87
88 void add_attribute(const OID& oid, const ASN1_String& val);
89
90 static std::string deref_info_field(std::string_view key);
91
92 /**
93 * Lookup upper bounds in characters for the length of distinguished name fields
94 * as given in RFC 5280, Appendix A.
95 *
96 * @param oid the oid of the DN to lookup
97 * @return the upper bound, or zero if no ub is known to Botan
98 */
99 static size_t lookup_ub(const OID& oid);
100
101 private:
102 std::vector<std::pair<OID, ASN1_String>> m_rdn;
103 std::vector<uint8_t> m_dn_bits;
104};
105
106BOTAN_PUBLIC_API(2, 0) bool operator==(const X509_DN& dn1, const X509_DN& dn2);
107BOTAN_PUBLIC_API(2, 0) bool operator!=(const X509_DN& dn1, const X509_DN& dn2);
108
109/*
110The ordering here is arbitrary and may change from release to release.
111It is intended for allowing DNs as keys in std::map and similiar containers
112*/
113BOTAN_PUBLIC_API(2, 0) bool operator<(const X509_DN& dn1, const X509_DN& dn2);
114
115BOTAN_PUBLIC_API(2, 0) std::ostream& operator<<(std::ostream& out, const X509_DN& dn);
116BOTAN_PUBLIC_API(2, 0) std::istream& operator>>(std::istream& in, X509_DN& dn);
117
118/**
119* Alternative Name
120*/
122 public:
123 void encode_into(DER_Encoder&) const override;
124 void decode_from(BER_Decoder&) override;
125
126 /// Create an empty name
128
129 /// Add a URI to this AlternativeName
130 void add_uri(std::string_view uri);
131
132 /// Add a URI to this AlternativeName
133 void add_email(std::string_view addr);
134
135 /// Add a DNS name to this AlternativeName
136 void add_dns(std::string_view dns);
137
138 /// Add an "OtherName" identified by object identifier to this AlternativeName
139 void add_other_name(const OID& oid, const ASN1_String& value);
140
141 /// Add a directory name to this AlternativeName
142 void add_dn(const X509_DN& dn);
143
144 /// Add an IP address to this alternative name
145 void add_ipv4_address(uint32_t ipv4);
146
147 /// Return the set of URIs included in this alternative name
148 const std::set<std::string>& uris() const { return m_uri; }
149
150 /// Return the set of email addresses included in this alternative name
151 const std::set<std::string>& email() const { return m_email; }
152
153 /// Return the set of DNS names included in this alternative name
154 const std::set<std::string>& dns() const { return m_dns; }
155
156 /// Return the set of IPv4 addresses included in this alternative name
157 const std::set<uint32_t>& ipv4_address() const { return m_ipv4_addr; }
158
159 /// Return the set of "other names" included in this alternative name
160 BOTAN_DEPRECATED("Support for other names is deprecated")
161 const std::set<std::pair<OID, ASN1_String>>& other_names() const {
162 return m_othernames;
163 }
164
165 /// Return the set of directory names included in this alternative name
166 const std::set<X509_DN>& directory_names() const { return m_dn_names; }
167
168 /// Return the total number of names in this AlternativeName
169 ///
170 /// This only counts names which were parsed, ignoring names which
171 /// were of some unknown type
172 size_t count() const;
173
174 /// Return true if this has any names set
175 bool has_items() const;
176
177 // Old, now deprecated interface follows:
178 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
179 std::multimap<std::string, std::string> contents() const;
180
181 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}.empty()")
182 bool has_field(std::string_view attr) const;
183
184 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
185 std::vector<std::string> get_attribute(std::string_view attr) const;
186
187 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
188 std::multimap<std::string, std::string, std::less<>> get_attributes() const;
189
190 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
191 std::string get_first_attribute(std::string_view attr) const;
192
193 BOTAN_DEPRECATED("Use AlternativeName::add_{uri, dns, email, ...}")
194 void add_attribute(std::string_view type, std::string_view value);
195
196 BOTAN_DEPRECATED("Use AlternativeName::add_other_name")
197 void add_othername(const OID& oid, std::string_view value, ASN1_Type type);
198
199 BOTAN_DEPRECATED("Use AlternativeName::othernames") std::multimap<OID, ASN1_String> get_othernames() const;
200
201 BOTAN_DEPRECATED("Use AlternativeName::directory_names") X509_DN dn() const;
202
203 BOTAN_DEPRECATED("Use plain constructor plus add_{uri,dns,email,ipv4_address}")
204 AlternativeName(std::string_view email_addr,
205 std::string_view uri = "",
206 std::string_view dns = "",
207 std::string_view ip_address = "");
208
209 private:
210 std::set<std::string> m_dns;
211 std::set<std::string> m_uri;
212 std::set<std::string> m_email;
213 std::set<uint32_t> m_ipv4_addr;
214 std::set<X509_DN> m_dn_names;
215 std::set<std::pair<OID, ASN1_String>> m_othernames;
216};
217
218/**
219* Attribute
220*/
221class BOTAN_PUBLIC_API(2, 0) Attribute final : public ASN1_Object {
222 public:
223 void encode_into(DER_Encoder& to) const override;
224 void decode_from(BER_Decoder& from) override;
225
226 Attribute() = default;
227 Attribute(const OID& oid, const std::vector<uint8_t>& params);
228 Attribute(std::string_view oid_str, const std::vector<uint8_t>& params);
229
230 const OID& oid() const { return m_oid; }
231
232 const std::vector<uint8_t>& parameters() const { return m_parameters; }
233
234 const OID& object_identifier() const { return m_oid; }
235
236 const std::vector<uint8_t>& get_parameters() const { return m_parameters; }
237
238 private:
239 OID m_oid;
240 std::vector<uint8_t> m_parameters;
241};
242
243/**
244* @brief X.509 GeneralName Type
245*
246* Handles parsing GeneralName types in their BER and canonical string
247* encoding. Allows matching GeneralNames against each other using
248* the rules laid out in the RFC 5280, sec. 4.2.1.10 (Name Contraints).
249*
250* This entire class is deprecated and will be removed in a future
251* major release
252*/
253class BOTAN_PUBLIC_API(2, 0) GeneralName final : public ASN1_Object {
254 public:
255 enum MatchResult : int {
256 All,
257 Some,
258 None,
259 NotFound,
260 UnknownType,
261 };
262
263 enum class NameType : uint8_t {
264 Unknown = 0,
265 RFC822 = 1,
266 DNS = 2,
267 URI = 3,
268 DN = 4,
269 IPv4 = 5,
270 Other = 6,
271 };
272
273 BOTAN_DEPRECATED("Deprecated use NameConstraints") GeneralName() = default;
274
275 // Encoding is not implemented
276 void encode_into(DER_Encoder&) const override;
277
278 void decode_from(BER_Decoder&) override;
279
280 /**
281 * @return Type of the name expressed in this restriction
282 */
283 NameType type_code() const { return m_type; }
284
285 /**
286 * @return Type of the name. Can be DN, DNS, IP, RFC822 or URI.
287 */
288 BOTAN_DEPRECATED("Deprecated use type_code") std::string type() const;
289
290 /**
291 * @return The name as string. Format depends on type.
292 */
293 BOTAN_DEPRECATED("Deprecated no replacement") std::string name() const;
294
295 /**
296 * Checks whether a given certificate (partially) matches this name.
297 * @param cert certificate to be matched
298 * @return the match result
299 */
300 BOTAN_DEPRECATED("Deprecated use NameConstraints type") MatchResult matches(const X509_Certificate& cert) const;
301
302 bool matches_dns(const std::string& dns_name) const;
303 bool matches_ipv4(uint32_t ip) const;
304 bool matches_dn(const X509_DN& dn) const;
305
306 private:
307 static constexpr size_t RFC822_IDX = 0;
308 static constexpr size_t DNS_IDX = 1;
309 static constexpr size_t URI_IDX = 2;
310 static constexpr size_t DN_IDX = 3;
311 static constexpr size_t IPV4_IDX = 4;
312
313 NameType m_type;
314 std::variant<std::string, std::string, std::string, X509_DN, std::pair<uint32_t, uint32_t>> m_name;
315
316 static bool matches_dns(std::string_view name, std::string_view constraint);
317
318 static bool matches_dn(const X509_DN& name, const X509_DN& constraint);
319};
320
321BOTAN_DEPRECATED("Deprecated no replacement") std::ostream& operator<<(std::ostream& os, const GeneralName& gn);
322
323/**
324* @brief A single Name Constraint
325*
326* The Name Constraint extension adds a minimum and maximum path
327* length to a GeneralName to form a constraint. The length limits
328* are not used in PKIX.
329*
330* This entire class is deprecated and will be removed in a future
331* major release
332*/
333class BOTAN_PUBLIC_API(2, 0) GeneralSubtree final : public ASN1_Object {
334 public:
335 /**
336 * Creates an empty name constraint.
337 */
338 BOTAN_DEPRECATED("Deprecated use NameConstraints") GeneralSubtree();
339
340 void encode_into(DER_Encoder&) const override;
341
342 void decode_from(BER_Decoder&) override;
343
344 /**
345 * @return name
346 */
347 const GeneralName& base() const { return m_base; }
348
349 private:
350 GeneralName m_base;
351};
352
353BOTAN_DEPRECATED("Deprecated no replacement") std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs);
354
355/**
356* @brief Name Constraints
357*
358* Wraps the Name Constraints associated with a certificate.
359*/
360class BOTAN_PUBLIC_API(2, 0) NameConstraints final {
361 public:
362 /**
363 * Creates an empty name NameConstraints.
364 */
365 NameConstraints() : m_permitted_subtrees(), m_excluded_subtrees() {}
366
367 /**
368 * Creates NameConstraints from a list of permitted and excluded subtrees.
369 * @param permitted_subtrees names for which the certificate is permitted
370 * @param excluded_subtrees names for which the certificate is not permitted
371 */
372 NameConstraints(std::vector<GeneralSubtree>&& permitted_subtrees,
373 std::vector<GeneralSubtree>&& excluded_subtrees);
374
375 /**
376 * @return permitted names
377 */
378 BOTAN_DEPRECATED("Deprecated no replacement") const std::vector<GeneralSubtree>& permitted() const {
379 return m_permitted_subtrees;
380 }
381
382 /**
383 * @return excluded names
384 */
385 BOTAN_DEPRECATED("Deprecated no replacement") const std::vector<GeneralSubtree>& excluded() const {
386 return m_excluded_subtrees;
387 }
388
389 /**
390 * Return true if all of the names in the certificate are permitted
391 */
392 bool is_permitted(const X509_Certificate& cert, bool reject_unknown) const;
393
394 /**
395 * Return true if any of the names in the certificate are excluded
396 */
397 bool is_excluded(const X509_Certificate& cert, bool reject_unknown) const;
398
399 private:
400 std::vector<GeneralSubtree> m_permitted_subtrees;
401 std::vector<GeneralSubtree> m_excluded_subtrees;
402
403 std::set<GeneralName::NameType> m_permitted_name_types;
404 std::set<GeneralName::NameType> m_excluded_name_types;
405};
406
407/**
408* X.509 Certificate Extension
409*/
410class BOTAN_PUBLIC_API(2, 0) Certificate_Extension {
411 public:
412 /**
413 * @return OID representing this extension
414 */
415 virtual OID oid_of() const = 0;
416
417 /*
418 * @return specific OID name
419 * If possible OIDS table should match oid_name to OIDS, ie
420 * OID::from_string(ext->oid_name()) == ext->oid_of()
421 * Should return empty string if OID is not known
422 */
423 virtual std::string oid_name() const = 0;
424
425 /**
426 * Make a copy of this extension
427 * @return copy of this
428 */
429
430 virtual std::unique_ptr<Certificate_Extension> copy() const = 0;
431
432 /*
433 * Callback visited during path validation.
434 *
435 * An extension can implement this callback to inspect
436 * the path during path validation.
437 *
438 * If an error occurs during validation of this extension,
439 * an appropriate status code shall be added to cert_status.
440 *
441 * @param subject Subject certificate that contains this extension
442 * @param issuer Issuer certificate
443 * @param status Certificate validation status codes for subject certificate
444 * @param cert_path Certificate path which is currently validated
445 * @param pos Position of subject certificate in cert_path
446 */
447 virtual void validate(const X509_Certificate& subject,
448 const X509_Certificate& issuer,
449 const std::vector<X509_Certificate>& cert_path,
450 std::vector<std::set<Certificate_Status_Code>>& cert_status,
451 size_t pos);
452
453 virtual ~Certificate_Extension() = default;
454
455 protected:
456 friend class Extensions;
457
458 virtual bool should_encode() const { return true; }
459
460 virtual std::vector<uint8_t> encode_inner() const = 0;
461 virtual void decode_inner(const std::vector<uint8_t>&) = 0;
462};
463
464/**
465* X.509 Certificate Extension List
466*/
467class BOTAN_PUBLIC_API(2, 0) Extensions final : public ASN1_Object {
468 public:
469 /**
470 * Look up an object in the extensions, based on OID Returns
471 * nullptr if not set, if the extension was either absent or not
472 * handled. The pointer returned is owned by the Extensions
473 * object.
474 * This would be better with an optional<T> return value
475 */
476 const Certificate_Extension* get_extension_object(const OID& oid) const;
477
478 template <typename T>
479 const T* get_extension_object_as(const OID& oid = T::static_oid()) const {
480 if(const Certificate_Extension* extn = get_extension_object(oid)) {
481 // Unknown_Extension oid_name is empty
482 if(extn->oid_name().empty()) {
483 return nullptr;
484 } else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) {
485 return extn_as_T;
486 } else {
487 throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed");
488 }
489 }
490
491 return nullptr;
492 }
493
494 /**
495 * Return the set of extensions in the order they appeared in the certificate
496 * (or as they were added, if constructed)
497 */
498 const std::vector<OID>& get_extension_oids() const { return m_extension_oids; }
499
500 /**
501 * Return true if an extension was set
502 */
503 bool extension_set(const OID& oid) const;
504
505 /**
506 * Return true if an extesion was set and marked critical
507 */
508 bool critical_extension_set(const OID& oid) const;
509
510 /**
511 * Return the raw bytes of the extension
512 * Will throw if OID was not set as an extension.
513 */
514 std::vector<uint8_t> get_extension_bits(const OID& oid) const;
515
516 void encode_into(DER_Encoder&) const override;
517 void decode_from(BER_Decoder&) override;
518
519 /**
520 * Adds a new extension to the list.
521 * @param extn pointer to the certificate extension (Extensions takes ownership)
522 * @param critical whether this extension should be marked as critical
523 * @throw Invalid_Argument if the extension is already present in the list
524 */
525 void add(std::unique_ptr<Certificate_Extension> extn, bool critical = false);
526
527 /**
528 * Adds a new extension to the list unless it already exists. If the extension
529 * already exists within the Extensions object, the extn pointer will be deleted.
530 *
531 * @param extn pointer to the certificate extension (Extensions takes ownership)
532 * @param critical whether this extension should be marked as critical
533 * @return true if the object was added false if the extension was already used
534 */
535 bool add_new(std::unique_ptr<Certificate_Extension> extn, bool critical = false);
536
537 /**
538 * Adds an extension to the list or replaces it.
539 * @param extn the certificate extension
540 * @param critical whether this extension should be marked as critical
541 */
542 void replace(std::unique_ptr<Certificate_Extension> extn, bool critical = false);
543
544 /**
545 * Remove an extension from the list. Returns true if the
546 * extension had been set, false otherwise.
547 */
548 bool remove(const OID& oid);
549
550 /**
551 * Searches for an extension by OID and returns the result.
552 * Only the known extensions types declared in this header
553 * are searched for by this function.
554 * @return Copy of extension with oid, nullptr if not found.
555 * Can avoid creating a copy by using get_extension_object function
556 */
557 std::unique_ptr<Certificate_Extension> get(const OID& oid) const;
558
559 /**
560 * Searches for an extension by OID and returns the result decoding
561 * it to some arbitrary extension type chosen by the application.
562 *
563 * Only the unknown extensions, that is, extensions types that
564 * are not declared in this header, are searched for by this
565 * function.
566 *
567 * @return Pointer to new extension with oid, nullptr if not found.
568 */
569 template <typename T>
570 std::unique_ptr<T> get_raw(const OID& oid) const {
571 auto extn_info = m_extension_info.find(oid);
572
573 if(extn_info != m_extension_info.end()) {
574 // Unknown_Extension oid_name is empty
575 if(extn_info->second.obj().oid_name().empty()) {
576 auto ext = std::make_unique<T>();
577 ext->decode_inner(extn_info->second.bits());
578 return ext;
579 }
580 }
581 return nullptr;
582 }
583
584 /**
585 * Returns a copy of the list of extensions together with the corresponding
586 * criticality flag. All extensions are encoded as some object, falling back
587 * to Unknown_Extension class which simply allows reading the bytes as well
588 * as the criticality flag.
589 */
590 std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const;
591
592 /**
593 * Returns the list of extensions as raw, encoded bytes
594 * together with the corresponding criticality flag.
595 * Contains all extensions, including any extensions encoded as Unknown_Extension
596 */
597 std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const;
598
599 Extensions() = default;
600
601 Extensions(const Extensions&) = default;
602 Extensions& operator=(const Extensions&) = default;
603
604 Extensions(Extensions&&) = default;
605 Extensions& operator=(Extensions&&) = default;
606
607 private:
608 static std::unique_ptr<Certificate_Extension> create_extn_obj(const OID& oid,
609 bool critical,
610 const std::vector<uint8_t>& body);
611
612 class Extensions_Info {
613 public:
614 Extensions_Info(bool critical, std::unique_ptr<Certificate_Extension> ext) :
615 m_obj(std::move(ext)), m_bits(m_obj->encode_inner()), m_critical(critical) {}
616
617 Extensions_Info(bool critical,
618 const std::vector<uint8_t>& encoding,
619 std::unique_ptr<Certificate_Extension> ext) :
620 m_obj(std::move(ext)), m_bits(encoding), m_critical(critical) {}
621
622 bool is_critical() const { return m_critical; }
623
624 const std::vector<uint8_t>& bits() const { return m_bits; }
625
626 const Certificate_Extension& obj() const {
627 BOTAN_ASSERT_NONNULL(m_obj.get());
628 return *m_obj;
629 }
630
631 private:
632 std::shared_ptr<Certificate_Extension> m_obj;
633 std::vector<uint8_t> m_bits;
634 bool m_critical = false;
635 };
636
637 std::vector<OID> m_extension_oids;
638 std::map<OID, Extensions_Info> m_extension_info;
639};
640
641} // namespace Botan
642
643#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:19
#define BOTAN_DEPRECATED(msg)
Definition api.h:59
const std::set< X509_DN > & directory_names() const
Return the set of directory names included in this alternative name.
Definition pkix_types.h:166
const std::set< uint32_t > & ipv4_address() const
Return the set of IPv4 addresses included in this alternative name.
Definition pkix_types.h:157
const std::set< std::string > & uris() const
Return the set of URIs included in this alternative name.
Definition pkix_types.h:148
const std::set< std::string > & dns() const
Return the set of DNS names included in this alternative name.
Definition pkix_types.h:154
void add_other_name(const OID &oid, const ASN1_String &value)
Add an "OtherName" identified by object identifier to this AlternativeName.
Definition alt_name.cpp:36
AlternativeName()
Create an empty name.
Definition pkix_types.h:127
const std::set< std::string > & email() const
Return the set of email addresses included in this alternative name.
Definition pkix_types.h:151
Name Constraints.
Definition pkix_types.h:360
void add_attribute(const OID &oid, std::string_view val)
Definition pkix_types.h:86
X509_DN()=default
X509_DN(const std::multimap< OID, std::string > &args)
Definition pkix_types.h:44
const std::vector< std::pair< OID, ASN1_String > > & dn_info() const
Definition pkix_types.h:75
X509_DN(const std::multimap< std::string, std::string > &args)
Definition pkix_types.h:50
bool empty() const
Definition pkix_types.h:69
const std::vector< uint8_t > & get_bits() const
Definition pkix_types.h:65
size_t count() const
Definition pkix_types.h:71
int(* final)(unsigned char *, CTX *)
std::string key_constraints_to_string(Key_Constraints c)
Definition pkix_types.h:33