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