Botan 3.13.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
16#include <botan/dns_name.h>
17#include <botan/email.h>
18#include <botan/ipv4_address.h>
19#include <botan/ipv6_address.h>
20#include <botan/pkix_enums.h>
21#include <botan/uri.h>
22#include <compare>
23#include <initializer_list>
24#include <iosfwd>
25#include <map>
26#include <memory>
27#include <optional>
28#include <set>
29#include <string>
30#include <string_view>
31#include <variant>
32#include <vector>
33
34namespace Botan {
35
37class Public_Key;
38class BigInt;
40
41BOTAN_DEPRECATED("Use Key_Constraints::to_string")
42
44 return c.to_string();
45}
46
47/**
48* X.509 certificate serial number (RFC 5280 CertificateSerialNumber)
49*
50* Stores the value as the contents octets of the DER INTEGER encoding
51* (two's complement, minimal length), so the sign is preserved and
52* equality on the stored bytes is value equality.
53*
54* RFC 5280 4.1.2.2:
55* The serial number MUST be a positive integer assigned by the CA to
56* each certificate.
57* and
58* Note: Non-conforming CAs may issue certificates with serial numbers
59* that are negative or zero. Certificate users SHOULD be prepared to
60* gracefully handle such certificates.
61*
62* so non-conforming values are representable, and can be detected with
63* is_negative, is_zero and octet_length.
64*/
65class BOTAN_PUBLIC_API(3, 13) X509_Serial_Number final : public ASN1_Object {
66 public:
67 /**
68 * Serial number zero
69 */
70 X509_Serial_Number() : m_contents{0x00} {}
71
72 /**
73 * Create from an integer value
74 */
75 explicit X509_Serial_Number(const BigInt& value);
76
77 /**
78 * Create from an unsigned big-endian encoded integer
79 */
80 static X509_Serial_Number from_bytes(std::span<const uint8_t> bytes);
81
82 /**
83 * Create from the contents octets of a BER INTEGER (big-endian two's
84 * complement). Redundant leading octets are normalized away; an empty
85 * input is rejected.
86 */
87 static X509_Serial_Number from_der_contents(std::span<const uint8_t> contents);
88
89 /**
90 * Generate a serial number suitable for issuing a certificate.
91 *
92 * The result is positive, never zero, and contains 126 bits of output
93 * from the RNG. The topmost bit is cleared, and the 127th bit is set.
94 */
95 static X509_Serial_Number random(RandomNumberGenerator& rng);
96
97 /**
98 * Return true if the serial number is negative
99 *
100 * TODO(Botan4) remove this once negative serial numbers are prohibited
101 */
102 bool is_negative() const;
103
104 /**
105 * Return true if the serial number is the integer zero
106 */
107 bool is_zero() const;
108
109 /**
110 * Number of contents octets in the DER encoding of this value
111 */
112 size_t octet_length() const { return m_contents.size(); }
113
114 /**
115 * True if this serial number satisfies the RFC 5280 4.1.2.2 rules for
116 * conforming CAs: a positive integer of at most 20 octets
117 */
118 bool conforms_to_rfc5280() const { return !is_negative() && !is_zero() && octet_length() <= 20; }
119
120 /**
121 * The contents octets of the DER INTEGER encoding (big-endian two's
122 * complement, minimal length)
123 */
124 std::span<const uint8_t> der_contents() const { return m_contents; }
125
126 /**
127 * The absolute value as unsigned big-endian bytes without leading
128 * zeros. Note this loses the sign, and is empty for a zero serial;
129 * it matches X509_Certificate::serial_number.
130 */
131 std::vector<uint8_t> magnitude() const;
132
133 BigInt to_bigint() const;
134
135 /**
136 * The value in hex, prefixed with '-' if negative
137 */
138 std::string to_string() const;
139
140 void encode_into(DER_Encoder& to) const override;
141 void decode_from(BER_Decoder& from) override;
142
143 bool operator==(const X509_Serial_Number& other) const { return m_contents == other.m_contents; }
144
145 /**
146 * Numeric ordering
147 */
148 std::strong_ordering operator<=>(const X509_Serial_Number& other) const;
149
150 private:
151 std::vector<uint8_t> m_contents;
152};
153
154/**
155* Distinguished Name
156*/
157class BOTAN_PUBLIC_API(2, 0) X509_DN final : public ASN1_Object {
158 public:
159 X509_DN() = default;
160
161 X509_DN(std::initializer_list<std::pair<std::string_view, std::string_view>> args) {
162 for(const auto& i : args) {
163 add_attribute(i.first, i.second);
164 }
165 }
166
167 /**
168 * Since DN matching for Name Constraints requires preserving order and
169 * multimaps have sorted keys, this constructor is deprecated.
170 */
171 BOTAN_DEPRECATED("Deprecated use initializer list constructor")
172 explicit X509_DN(const std::multimap<OID, std::string>& args) {
173 for(const auto& i : args) {
174 add_attribute(i.first, i.second);
175 }
176 }
177
178 /**
179 * Since DN matching for Name Constraints requires preserving order and
180 * multimaps have sorted keys, this constructor is deprecated.
181 */
182 BOTAN_DEPRECATED("Deprecated use initializer list constructor")
183 explicit X509_DN(const std::multimap<std::string, std::string>& args) {
184 for(const auto& i : args) {
185 add_attribute(i.first, i.second);
186 }
187 }
188
189 void encode_into(DER_Encoder& to) const override;
190 void decode_from(BER_Decoder& from) override;
191
192 bool has_field(const OID& oid) const;
193 ASN1_String get_first_attribute(const OID& oid) const;
194
195 /*
196 * Return the BER encoded data, if any
197 */
198 const std::vector<uint8_t>& get_bits() const { return m_dn_bits; }
199
200 std::vector<uint8_t> DER_encode() const;
201
202 bool empty() const { return m_rdn.empty(); }
203
204 /**
205 * Number of relative distinguished names (RDNs) in the DN. Note: prior
206 * to multi-AVA RDN support this returned the total number of AVAs; the
207 * two differ only when the DN contains a multi-valued RDN.
208 */
209 size_t count() const { return m_rdn.size(); }
210
211 std::string to_string() const;
212
213 /**
214 * Parse the string representation of a distinguished name.
215 *
216 * The grammar accepted is a subset of RFC 4514 Section 3, but also accepts
217 * quoted-value forms ala RFC 2253. The entire input must be consumed.
218 *
219 * @param str the string to parse
220 * @return the parsed DN, or nullopt if @p str is not a well-formed DN
221 */
222 static std::optional<X509_DN> parse(std::string_view str);
223
224 /**
225 * Return the DN as a sequence of RDNs. Each RDN is an X.501
226 * SET OF AttributeTypeAndValue; the inner vector preserves the
227 * decoded order but RDN equality is set-based per RFC 5280 7.1.
228 */
229 const std::vector<std::vector<std::pair<OID, ASN1_String>>>& rdns() const { return m_rdn; }
230
231 /**
232 * Return the DN attributes as a flat sequence of AVAs in decoded order.
233 * RDN structure is not preserved in this view; prefer rdns() to retain it.
234 */
235 BOTAN_DEPRECATED("Use rdns() which preserves RDN structure")
236 std::vector<std::pair<OID, ASN1_String>> dn_info() const;
237
238 std::multimap<OID, std::string> get_attributes() const;
239 std::multimap<std::string, std::string> contents() const;
240
241 bool has_field(std::string_view attr) const;
242 std::vector<std::string> get_attribute(std::string_view attr) const;
243 std::string get_first_attribute(std::string_view attr) const;
244
245 void add_attribute(std::string_view key, std::string_view val);
246
247 void add_attribute(const OID& oid, std::string_view val) { add_attribute(oid, ASN1_String(val)); }
248
249 void add_attribute(const OID& oid, const ASN1_String& val);
250
251 /**
252 * Append a complete RDN. The provided AVAs become one
253 * RelativeDistinguishedName (X.501 SET OF AttributeTypeAndValue).
254 * An empty input is ignored.
255 */
256 void add_rdn(std::vector<std::pair<OID, ASN1_String>> rdn);
257
258 static std::string deref_info_field(std::string_view key);
259
260 /**
261 * Lookup upper bounds in characters for the length of distinguished name fields
262 * as given in RFC 5280, Appendix A.
263 *
264 * @param oid the oid of the DN to lookup
265 * @return the upper bound, or zero if no ub is known to Botan
266 */
267 static size_t lookup_ub(const OID& oid);
268
269 /**
270 * Return a canonical byte encoding
271 *
272 * Internal interface, not covered by SemVer
273 */
274 const std::vector<uint8_t>& _canonical_bytes() const { return m_canonical_dn_bits; }
275
276 private:
277 void update_canonical_bits();
278
279 // Outer vector: sequence of RDNs. Inner vector: AVAs within
280 // one RDN (X.501 SET OF AttributeTypeAndValue).
281 std::vector<std::vector<std::pair<OID, ASN1_String>>> m_rdn;
282 std::vector<uint8_t> m_dn_bits;
283 std::vector<uint8_t> m_canonical_dn_bits;
284};
285
286BOTAN_PUBLIC_API(2, 0) bool operator==(const X509_DN& dn1, const X509_DN& dn2);
287BOTAN_PUBLIC_API(2, 0) bool operator!=(const X509_DN& dn1, const X509_DN& dn2);
288
289/*
290The ordering here is arbitrary and may change from release to release.
291It is intended for allowing DNs as keys in std::map and similar containers
292*/
293BOTAN_PUBLIC_API(2, 0) bool operator<(const X509_DN& dn1, const X509_DN& dn2);
294
295BOTAN_PUBLIC_API(2, 0) std::ostream& operator<<(std::ostream& out, const X509_DN& dn);
296
297/**
298* Parse the input stream as a DN
299* Prefer X509_DN::parse
300*/
301BOTAN_DEPRECATED_API("Use X509_DN::parse") std::istream& operator>>(std::istream& in, X509_DN& dn);
302
303/**
304* Alternative Name
305*/
306class BOTAN_PUBLIC_API(2, 0) AlternativeName final : public ASN1_Object {
307 public:
308 /// An "OtherName" GeneralName entry: type-id OID and the inner ANY value as raw BER
309 class OtherNameValue final {
310 public:
311 const OID& oid() const { return m_oid; }
312
313 std::span<const uint8_t> value() const { return m_value; }
314
315 bool operator<(const OtherNameValue& other) const {
316 if(oid() != other.oid()) {
317 return oid() < other.oid();
318 }
319 return m_value < other.m_value;
320 }
321
322 private:
323 friend class AlternativeName;
324
325 OtherNameValue(const OID& oid, std::vector<uint8_t> value) : m_oid(oid), m_value(std::move(value)) {}
326
327 OtherNameValue(const OID& oid, std::span<const uint8_t> value) :
328 m_oid(oid), m_value(value.begin(), value.end()) {}
329
330 OID m_oid;
331 std::vector<uint8_t> m_value;
332 };
333
334 void encode_into(DER_Encoder& to) const override;
335 void decode_from(BER_Decoder& from) override;
336
337 /// Create an empty name
338 AlternativeName() = default;
339
340 /// Add a URI to this AlternativeName, parsing and validating the input
341 void add_uri(std::string_view uri);
342
343 /// Add a previously parsed URI to this AlternativeName
344 void add_uri(URI uri);
345
346 /// Add an email address to this AlternativeName, parsing and validating the input
347 void add_email(std::string_view addr);
348
349 /// Add a previously parsed email address to this AlternativeName
350 void add_email(EmailAddress addr);
351
352 /// Add a DNS name to this AlternativeName, parsing and validating the input
353 void add_dns(std::string_view dns);
354
355 /// Add a previously parsed DNS name to this AlternativeName
356 void add_dns(DNSName dns);
357
358 /// Add an "OtherName" identified by object identifier to this AlternativeName
359 void add_other_name(const OID& oid, const ASN1_String& value);
360
361 /// Add an "OtherName" with arbitrary inner value, given as raw BER bytes
362 ///
363 /// `value` must be a complete BER-encoded object (tag + length + content)
364 /// representing the inner ANY value of the OtherName.
365 void add_other_name_value(const OID& oid, std::span<const uint8_t> value);
366
367 /// Add a registeredID (RFC 5280 [8])
368 void add_registered_id(const OID& oid);
369
370 /// Add a directory name to this AlternativeName
371 void add_dn(const X509_DN& dn);
372
373 /// Add an IP address to this alternative name
374 BOTAN_DEPRECATED("Use variant taking IPv4Address") void add_ipv4_address(uint32_t ipv4) {
375 this->add_ipv4_address(IPv4Address(ipv4));
376 }
377
378 /// Add an IP address to this alternative name
379 void add_ipv4_address(const IPv4Address& ipv4);
380
381 /// Add an IPv6 address to this alternative name
382 void add_ipv6_address(const IPv6Address& ipv6);
383
384 /// Return the set of URIs included in this alternative name
385 ///
386 /// Deprecated: use uri_names() instead, which exposes the parsed
387 /// URI values. This accessor constructs a copy.
388 BOTAN_DEPRECATED("Use AlternativeName::uri_names") std::set<std::string> uris() const;
389
390 /// Return the set of URIs included in this alternative name
391 const std::set<URI>& uri_names() const { return m_uri; }
392
393 /// Return the set of email addresses included in this alternative name
394 ///
395 /// Deprecated: use email_addresses() instead, which exposes the
396 /// parsed EmailAddress values. This accessor constructs a copy.
397 BOTAN_DEPRECATED("Use AlternativeName::email_addresses") std::set<std::string> email() const;
398
399 /// Return the set of email addresses included in this alternative name
400 const std::set<EmailAddress>& email_addresses() const { return m_email; }
401
402 /// Return the set of DNS names included in this alternative name
403 ///
404 /// Deprecated: use dns_names() instead, which exposes the parsed
405 /// DNSName values. This accessor constructs a copy.
406 BOTAN_DEPRECATED("Use AlternativeName::dns_names") std::set<std::string> dns() const;
407
408 /// Return the set of DNS names included in this alternative name
409 const std::set<DNSName>& dns_names() const { return m_dns; }
410
411 /// Return the set of IPv4 addresses included in this alternative name
412 BOTAN_DEPRECATED("Use ipv4_addresses") std::set<uint32_t> ipv4_address() const;
413
414 /// Return the set of IPv6 addresses included in this alternative name
415 BOTAN_DEPRECATED("Use ipv6_addresses") const std::set<IPv6Address>& ipv6_address() const {
416 return ipv6_addresses();
417 }
418
419 /// Return the set of IPv4 addresses included in this alternative name
420 const std::set<IPv4Address>& ipv4_addresses() const { return m_ipv4_addrs; }
421
422 /// Return the set of IPv6 addresses included in this alternative name
423 const std::set<IPv6Address>& ipv6_addresses() const { return m_ipv6_addrs; }
424
425 /// Return the set of "other names" whose value was a recognized ASN1_String type
426 BOTAN_DEPRECATED("Use AlternativeName::other_name_values")
427 const std::set<std::pair<OID, ASN1_String>>& other_names() const {
428 return m_othernames;
429 }
430
431 /// Return all "OtherName" entries with their inner ANY value as raw BER
432 const std::set<OtherNameValue>& other_name_values() const { return m_other_name_values; }
433
434 /// Return the set of `SmtpUTF8Mailbox` SAN entries (RFC 9598).
435 ///
436 /// Any such values are also included with their raw encoding in other_name_values
437 const std::set<SmtpUtf8Mailbox>& smtp_utf8_mailboxes() const { return m_smtp_utf8_mailboxes; }
438
439 /// Return the set of registeredID OIDs
440 const std::set<OID>& registered_ids() const { return m_registered_ids; }
441
442 /// Return the set of directory names included in this alternative name
443 const std::set<X509_DN>& directory_names() const { return m_dn_names; }
444
445 /// Return the total number of names in this AlternativeName
446 ///
447 /// This only counts names which were parsed, ignoring names which
448 /// were of some unknown type
449 size_t count() const;
450
451 /// Return true if this has any names set
452 bool has_items() const;
453
454 /// Return true if this alternative name is empty (zero names)
455 bool is_empty() const;
456
457 // Old, now deprecated interface follows:
458 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
459 std::multimap<std::string, std::string> contents() const;
460
461 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}.empty()")
462 bool has_field(std::string_view attr) const;
463
464 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
465 std::vector<std::string> get_attribute(std::string_view attr) const;
466
467 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
468 std::multimap<std::string, std::string, std::less<>> get_attributes() const;
469
470 BOTAN_DEPRECATED("Use AlternativeName::{uris, email, dns, othernames, directory_names}")
471 std::string get_first_attribute(std::string_view attr) const;
472
473 BOTAN_DEPRECATED("Use AlternativeName::add_{uri, dns, email, ...}")
474 void add_attribute(std::string_view type, std::string_view value);
475
476 BOTAN_DEPRECATED("Use AlternativeName::add_other_name")
477 void add_othername(const OID& oid, std::string_view value, ASN1_Type type);
478
479 BOTAN_DEPRECATED("Use AlternativeName::othernames") std::multimap<OID, ASN1_String> get_othernames() const;
480
481 /**
482 * This returns all of the alternative name DNs combined into a single DN
483 *
484 * This result is not a valid DN. The logic is retained for compatibility,
485 * but this function should not be used. It will be removed in Botan4.
486 */
487 BOTAN_DEPRECATED("Use AlternativeName::directory_names") X509_DN dn() const;
488
489 BOTAN_DEPRECATED("Use plain constructor plus add_{uri,dns,email,ipv4_address}")
490 BOTAN_FUTURE_EXPLICIT AlternativeName(std::string_view email_addr,
491 std::string_view uri = "",
492 std::string_view dns = "",
493 std::string_view ip_address = "");
494
495 private:
496 std::set<DNSName> m_dns;
497 std::set<URI> m_uri;
498 std::set<EmailAddress> m_email;
499 std::set<IPv4Address> m_ipv4_addrs;
500 std::set<IPv6Address> m_ipv6_addrs;
501 std::set<X509_DN> m_dn_names;
502 std::set<std::pair<OID, ASN1_String>> m_othernames; // TODO(Botan4) remove this
503 std::set<OtherNameValue> m_other_name_values;
504 std::set<SmtpUtf8Mailbox> m_smtp_utf8_mailboxes;
505 std::set<OID> m_registered_ids;
506};
507
508/**
509* Attribute
510*/
511class BOTAN_PUBLIC_API(2, 0) Attribute final : public ASN1_Object {
512 public:
513 void encode_into(DER_Encoder& to) const override;
514 void decode_from(BER_Decoder& from) override;
515
516 Attribute() = default;
517 Attribute(const OID& oid, const std::vector<uint8_t>& params);
518 Attribute(std::string_view oid_str, const std::vector<uint8_t>& params);
519
520 const OID& oid() const { return m_oid; }
521
522 const std::vector<uint8_t>& parameters() const { return m_parameters; }
523
524 const OID& object_identifier() const { return m_oid; }
525
526 const std::vector<uint8_t>& get_parameters() const { return m_parameters; }
527
528 private:
529 OID m_oid;
530 std::vector<uint8_t> m_parameters;
531};
532
533/**
534* @brief X.509 GeneralName Type
535*
536* Handles parsing GeneralName types in their BER and canonical string
537* encoding. Allows matching GeneralNames against each other using
538* the rules laid out in the RFC 5280, sec. 4.2.1.10 (Name Constraints).
539*
540* This entire class is deprecated and will be removed in a future
541* major release
542*/
543class BOTAN_PUBLIC_API(2, 0) GeneralName final : public ASN1_Object {
544 public:
545 enum MatchResult : uint8_t /* NOLINT(*-use-enum-class) */ {
551 };
552
553 enum class NameType : uint8_t {
555 RFC822 = 1,
556 DNS = 2,
557 URI = 3,
558 DN = 4,
559 IPv4 = 5,
560 IPv6 = 6,
561 Other = 7,
562 };
563
564 BOTAN_DEPRECATED("Deprecated use NameConstraints") GeneralName() = default;
565
566 static GeneralName email(std::string_view email);
567 static GeneralName dns(std::string_view dns);
568 static GeneralName uri(std::string_view uri);
570 static GeneralName ipv4_address(uint32_t ipv4);
571 static GeneralName ipv4_address(uint32_t ipv4, uint32_t mask);
573 static GeneralName ipv4_address(const IPv4Subnet& subnet);
574 static GeneralName ipv6_address(const IPv6Address& ipv6);
575 static GeneralName ipv6_address(const IPv6Subnet& subnet);
576
577 /**
578 * Wrap a URI SAN in a GeneralName, this is used for ffi
579 * @warning internal function that may be removed at any time
580 */
581 static GeneralName _uri_san_value(std::string_view full_uri);
582
583 /**
584 * Wrap a DNS SAN in a GeneralName, this is used for ffi
585 * @warning internal function that may be removed at any time
586 */
587 static GeneralName _dns_san_value(std::string_view dns);
588
589 void encode_into(DER_Encoder& to) const override;
590
591 void decode_from(BER_Decoder& from) override;
592
593 /**
594 * @return Type of the name expressed in this restriction
595 */
596 NameType type_code() const { return m_type; }
597
598 /**
599 * @return Type of the name. Can be DN, DNS, IP, RFC822 or URI.
600 */
601 BOTAN_DEPRECATED("Deprecated use type_code") std::string type() const;
602
603 /**
604 * @return The name as string. Format depends on type.
605 */
606 BOTAN_DEPRECATED("Deprecated no replacement") std::string name() const;
607
608 /**
609 * @return The name as binary string. Format depends on type.
610 */
611 BOTAN_DEPRECATED("Deprecated no replacement") std::vector<uint8_t> binary_name() const;
612
613 /**
614 * Checks whether a given certificate (partially) matches this name.
615 * @param cert certificate to be matched
616 * @return the match result
617 */
618 BOTAN_DEPRECATED("Deprecated use NameConstraints type") MatchResult matches(const X509_Certificate& cert) const;
619
620 bool matches_dns(const std::string& dns_name) const;
621 bool matches_dns(const DNSName& dns_name) const;
622
623 bool matches_ipv4(uint32_t ip) const;
624
625 bool matches_ipv4(const IPv4Address& ip) const { return matches_ipv4(ip.address()); }
626
627 bool matches_ipv6(const IPv6Address& ip) const;
628 bool matches_dn(const X509_DN& dn) const;
629 bool matches_uri(const URI& uri) const;
630 bool matches_email(const EmailAddress& addr) const;
631 bool matches_email(const SmtpUtf8Mailbox& mailbox) const;
632
633 private:
634 friend class NameConstraints;
635
636 class EmailConstraint final {
637 public:
638 EmailConstraint() = default;
639
640 static std::optional<EmailConstraint> from_string(std::string_view input);
641
642 const std::string& value() const { return m_value; }
643
644 auto operator<=>(const EmailConstraint&) const = default;
645
646 private:
647 explicit EmailConstraint(std::string value) : m_value(std::move(value)) {}
648
649 std::string m_value;
650 };
651
652 class DNSConstraint final {
653 public:
654 DNSConstraint() = default;
655
656 static std::optional<DNSConstraint> from_string(std::string_view input);
657
658 static std::optional<DNSConstraint> from_san_value(std::string_view input);
659
660 const std::string& value() const { return m_value; }
661
662 auto operator<=>(const DNSConstraint&) const = default;
663
664 private:
665 explicit DNSConstraint(std::string value) : m_value(std::move(value)) {}
666
667 std::string m_value;
668 };
669
670 class URIConstraint final {
671 public:
672 URIConstraint() = default;
673
674 static std::optional<URIConstraint> from_string(std::string_view input);
675
676 static std::optional<URIConstraint> from_san_value(std::string_view full_uri);
677
678 const std::string& value() const { return m_value; }
679
680 auto operator<=>(const URIConstraint&) const = default;
681
682 private:
683 explicit URIConstraint(std::string value) : m_value(std::move(value)) {}
684
685 std::string m_value;
686 };
687
688 /*
689 TODO: consider adding OtherConstraint and UnknownConstraint types here and eliminating m_type,
690 using m_name variant choice as the single source of the constraint type
691 */
692 using NameVariant = std::variant<EmailConstraint, DNSConstraint, URIConstraint, X509_DN, IPv4Subnet, IPv6Subnet>;
693
694 GeneralName(NameType type, NameVariant name) : m_type(type), m_name(std::move(name)) {}
695
696 NameType m_type = NameType::Unknown;
697 NameVariant m_name;
698
699 /**
700 * Partial DN matching according to RFC 5280, Section 7.1, i.e.,
701 * whether the constraint is a prefix of the name.
702 */
703 static bool matches_dn(const X509_DN& name, const X509_DN& constraint);
704};
705
706BOTAN_DEPRECATED("Deprecated no replacement") std::ostream& operator<<(std::ostream& os, const GeneralName& gn);
707
708/**
709* @brief A single Name Constraint
710*
711* The Name Constraint extension adds a minimum and maximum path
712* length to a GeneralName to form a constraint. The length limits
713* are not used in PKIX.
714*
715* This entire class is deprecated and will be removed in a future
716* major release
717*/
718class BOTAN_PUBLIC_API(2, 0) GeneralSubtree final : public ASN1_Object {
719 public:
720 /**
721 * Creates an empty name constraint.
722 */
723 BOTAN_DEPRECATED("Deprecated use NameConstraints") GeneralSubtree();
724
725 /**
726 * Creates a name constraint over the given base name.
727 */
728 explicit GeneralSubtree(GeneralName base) : m_base(std::move(base)) {}
729
730 void encode_into(DER_Encoder& to) const override;
731
732 void decode_from(BER_Decoder& from) override;
733
734 /**
735 * @return name
736 */
737 const GeneralName& base() const { return m_base; }
738
739 private:
740 GeneralName m_base;
741};
742
743BOTAN_DEPRECATED("Deprecated no replacement") std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs);
744
745/**
746* @brief Name Constraints
747*
748* Wraps the Name Constraints associated with a certificate.
749*/
751 public:
752 /**
753 * Creates an empty name NameConstraints.
754 */
755 NameConstraints() = default;
756
757 /**
758 * Creates NameConstraints from a list of permitted and excluded subtrees.
759 * @param permitted_subtrees names for which the certificate is permitted
760 * @param excluded_subtrees names for which the certificate is not permitted
761 */
762 NameConstraints(std::vector<GeneralSubtree>&& permitted_subtrees,
763 std::vector<GeneralSubtree>&& excluded_subtrees);
764
765 /**
766 * @return permitted names
767 */
768 BOTAN_DEPRECATED("Deprecated no replacement") const std::vector<GeneralSubtree>& permitted() const {
769 return m_permitted_subtrees;
770 }
771
772 /**
773 * @return excluded names
774 */
775 BOTAN_DEPRECATED("Deprecated no replacement") const std::vector<GeneralSubtree>& excluded() const {
776 return m_excluded_subtrees;
777 }
778
779 /**
780 * Return true if all of the names in the certificate are permitted
781 */
782 bool is_permitted(const X509_Certificate& cert, bool reject_unknown) const;
783
784 /**
785 * Return true if any of the names in the certificate are excluded
786 */
787 bool is_excluded(const X509_Certificate& cert, bool reject_unknown) const;
788
789 private:
790 std::vector<GeneralSubtree> m_permitted_subtrees;
791 std::vector<GeneralSubtree> m_excluded_subtrees;
792
793 std::set<GeneralName::NameType> m_permitted_name_types;
794 std::set<GeneralName::NameType> m_excluded_name_types;
795};
796
798
799/**
800* X.509 Certificate Extension
801*/
802class BOTAN_PUBLIC_API(2, 0) Certificate_Extension /* NOLINT(*-special-member-functions) */ {
803 public:
804 /**
805 * Return object identifier for this extension
806 *
807 * @return OID representing this extension
808 */
809 virtual OID oid_of() const = 0;
810
811 /**
812 * Return string identifier for this extension
813 *
814 * If possible the OID table should match oid_name, ie
815 * `OID::from_string(ext->oid_name()) == ext->oid_of()`
816 *
817 * @return specific OID name, or empty if unknown
818 */
819 virtual std::string oid_name() const = 0;
820
821 /**
822 * Make a copy of this extension
823 * @return copy of this
824 */
825 virtual std::unique_ptr<Certificate_Extension> copy() const = 0;
826
827 /**
828 * Query if @param context is an appropriate context for this extension to exist
829 *
830 * Many extensions are used across different types of X509 objects but some
831 * are specific, this allows decoding to reject extensions in an
832 * inappropriate context.
833 */
834 virtual bool is_appropriate_context(Extension_Context context) const = 0;
835
836 /**
837 * Callback visited during path validation.
838 *
839 * An extension can implement this callback to inspect
840 * the path during path validation.
841 *
842 * If an error occurs during validation of this extension,
843 * an appropriate status code shall be added to cert_status.
844 *
845 * @param subject Subject certificate that contains this extension
846 * @param issuer Issuer certificate. nullopt for certificates with no
847 * available issuer (e.g. non self-signed trust anchors).
848 * @param cert_path Certificate path which is currently validated
849 * @param cert_status Certificate validation status codes for subject certificate
850 * @param pos Position of subject certificate in cert_path
851 */
852 virtual void validate(const X509_Certificate& subject,
853 const std::optional<X509_Certificate>& issuer,
854 const std::vector<X509_Certificate>& cert_path,
855 std::vector<std::set<Certificate_Status_Code>>& cert_status,
856 size_t pos) const;
857
858 virtual ~Certificate_Extension() = default;
859
860 protected:
861 friend class Extensions;
862
863 virtual bool should_encode() const { return true; }
864
865 virtual std::vector<uint8_t> encode_inner() const = 0;
866 virtual void decode_inner(const std::vector<uint8_t>&) = 0;
867};
868
869/**
870* X.509 Certificate Extension List
871*/
872class BOTAN_PUBLIC_API(2, 0) Extensions final : public ASN1_Object {
873 public:
874 /**
875 * Look up an object in the extensions, based on OID Returns
876 * nullptr if not set, if the extension was either absent or not
877 * handled. The pointer returned is owned by the Extensions
878 * object.
879 * This would be better with an optional<T> return value
880 */
881 const Certificate_Extension* get_extension_object(const OID& oid) const;
882
883 template <typename T>
884 const T* get_extension_object_as(const OID& oid = T::static_oid()) const {
885 if(const Certificate_Extension* extn = get_extension_object(oid)) {
886 // Unknown_Extension oid_name is empty
887 if(extn->oid_name().empty()) {
888 return nullptr;
889 } else if(const T* extn_as_T = dynamic_cast<const T*>(extn)) {
890 return extn_as_T;
891 } else {
892 throw Decoding_Error("Exception::get_extension_object_as dynamic_cast failed");
893 }
894 }
895
896 return nullptr;
897 }
898
899 /**
900 * Return the set of extensions in the order they appeared in the certificate
901 * (or as they were added, if constructed)
902 */
903 const std::vector<OID>& get_extension_oids() const { return m_extension_oids; }
904
905 /**
906 * Return the set of critical extensions in the order they appeared in the extension list
907 * (This may be an empty vector)
908 */
909 std::vector<OID> critical_extensions() const;
910
911 /**
912 * Return true if an extension was set
913 */
914 bool extension_set(const OID& oid) const;
915
916 /**
917 * Return true if an extension was set and marked critical
918 */
919 bool critical_extension_set(const OID& oid) const;
920
921 /**
922 * Return the raw bytes of the extension
923 * Will throw if OID was not set as an extension.
924 */
925 std::vector<uint8_t> get_extension_bits(const OID& oid) const;
926
927 void encode_into(DER_Encoder& to) const override;
928 void decode_from(BER_Decoder& from) override;
929 void decode_from(BER_Decoder& from, std::optional<Extension_Context> context);
930
931 /**
932 * Return true if an unrecognized critical extension was encountered
933 * during the most recent decode_from. Resets on each call to decode_from
934 * and is not affected by subsequent calls to add/replace/remove.
935 */
936 bool has_unknown_critical_extension() const { return m_has_unknown_critical_extension; }
937
938 /**
939 * Adds a new extension to the list.
940 * @param extn pointer to the certificate extension (Extensions takes ownership)
941 * @param critical whether this extension should be marked as critical
942 * @throw Invalid_Argument if the extension is already present in the list
943 */
944 void add(std::unique_ptr<Certificate_Extension> extn, bool critical = false);
945
946 /**
947 * Adds a new extension to the list unless it already exists. If the extension
948 * already exists within the Extensions object, the extn pointer will be deleted.
949 *
950 * @param extn pointer to the certificate extension (Extensions takes ownership)
951 * @param critical whether this extension should be marked as critical
952 * @return true if the object was added false if the extension was already used
953 */
954 bool add_new(std::unique_ptr<Certificate_Extension> extn, bool critical = false);
955
956 /**
957 * Adds an extension to the list or replaces it.
958 * @param extn the certificate extension
959 * @param critical whether this extension should be marked as critical
960 */
961 void replace(std::unique_ptr<Certificate_Extension> extn, bool critical = false);
962
963 /**
964 * Remove an extension from the list. Returns true if the
965 * extension had been set, false otherwise.
966 */
967 bool remove(const OID& oid);
968
969 /**
970 * Searches for an extension by OID and returns the result.
971 * Only the known extensions types declared in this header
972 * are searched for by this function.
973 * @return Copy of extension with oid, nullptr if not found.
974 * Can avoid creating a copy by using get_extension_object function
975 */
976 std::unique_ptr<Certificate_Extension> get(const OID& oid) const;
977
978 /**
979 * Searches for an extension by OID and returns the result decoding
980 * it to some arbitrary extension type chosen by the application.
981 *
982 * Only the unknown extensions, that is, extensions types that
983 * are not declared in this header, are searched for by this
984 * function.
985 *
986 * @return Pointer to new extension with oid, nullptr if not found.
987 */
988 template <typename T>
989 std::unique_ptr<T> get_raw(const OID& oid) const {
990 auto extn_info = m_extension_info.find(oid);
991
992 if(extn_info != m_extension_info.end()) {
993 // Unknown_Extension oid_name is empty
994 if(extn_info->second.obj().oid_name().empty()) {
995 auto ext = std::make_unique<T>();
996 ext->decode_inner(extn_info->second.bits());
997 return ext;
998 }
999 }
1000 return nullptr;
1001 }
1002
1003 /**
1004 * Returns a copy of the list of extensions together with the corresponding
1005 * criticality flag. All extensions are encoded as some object, falling back
1006 * to Unknown_Extension class which simply allows reading the bytes as well
1007 * as the criticality flag.
1008 */
1009 std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const;
1010
1011 /**
1012 * Invoke the validation callback for each extension.
1013 */
1014 void validate(const X509_Certificate& subject,
1015 const std::optional<X509_Certificate>& issuer,
1016 const std::vector<X509_Certificate>& cert_path,
1017 std::vector<std::set<Certificate_Status_Code>>& cert_status,
1018 size_t pos) const;
1019
1020 /**
1021 * Returns the list of extensions as raw, encoded bytes
1022 * together with the corresponding criticality flag.
1023 * Contains all extensions, including any extensions encoded as Unknown_Extension
1024 */
1025 std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const;
1026
1027 size_t count() const { return m_extension_oids.size(); }
1028
1029 Extensions() = default;
1030
1031 Extensions(const Extensions&) = default;
1032 Extensions& operator=(const Extensions&) = default;
1033
1036
1037 ~Extensions() override = default;
1038
1039 private:
1040 static std::unique_ptr<Certificate_Extension> create_extn_obj(const OID& oid,
1041 bool critical,
1042 const std::vector<uint8_t>& body,
1043 std::optional<Extension_Context> context);
1044
1045 class BOTAN_UNSTABLE_API Extensions_Info final {
1046 public:
1047 Extensions_Info(bool critical, std::unique_ptr<Certificate_Extension> ext) :
1048 m_obj(std::move(ext)), m_bits(m_obj->encode_inner()), m_critical(critical) {}
1049
1050 Extensions_Info(bool critical,
1051 const std::vector<uint8_t>& encoding,
1052 std::unique_ptr<Certificate_Extension> ext) :
1053 m_obj(std::move(ext)), m_bits(encoding), m_critical(critical) {}
1054
1055 bool is_critical() const { return m_critical; }
1056
1057 const std::vector<uint8_t>& bits() const { return m_bits; }
1058
1059 const Certificate_Extension& obj() const;
1060
1061 private:
1062 std::shared_ptr<Certificate_Extension> m_obj;
1063 std::vector<uint8_t> m_bits;
1064 bool m_critical = false;
1065 };
1066
1067 std::vector<OID> m_extension_oids;
1068 std::map<OID, Extensions_Info> m_extension_info;
1069 bool m_has_unknown_critical_extension = false;
1070};
1071
1072} // namespace Botan
1073
1074#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:21
#define BOTAN_UNSTABLE_API
Definition api.h:34
#define BOTAN_DEPRECATED(msg)
Definition api.h:73
#define BOTAN_FUTURE_EXPLICIT
Definition api.h:52
#define BOTAN_DEPRECATED_API(msg)
Definition api.h:27
ASN1_Object()=default
An "OtherName" GeneralName entry: type-id OID and the inner ANY value as raw BER.
Definition pkix_types.h:309
bool operator<(const OtherNameValue &other) const
Definition pkix_types.h:315
std::span< const uint8_t > value() const
Definition pkix_types.h:313
const std::set< IPv6Address > & ipv6_addresses() const
Return the set of IPv6 addresses included in this alternative name.
Definition pkix_types.h:423
const std::set< DNSName > & dns_names() const
Return the set of DNS names included in this alternative name.
Definition pkix_types.h:409
const std::set< X509_DN > & directory_names() const
Return the set of directory names included in this alternative name.
Definition pkix_types.h:443
void add_dns(std::string_view dns)
Add a DNS name to this AlternativeName, parsing and validating the input.
Definition alt_name.cpp:63
std::set< std::string > dns() const
Definition alt_name.cpp:78
void add_ipv4_address(uint32_t ipv4)
Add an IP address to this alternative name.
Definition pkix_types.h:374
void add_email(std::string_view addr)
Add an email address to this AlternativeName, parsing and validating the input.
Definition alt_name.cpp:40
const std::set< EmailAddress > & email_addresses() const
Return the set of email addresses included in this alternative name.
Definition pkix_types.h:400
const std::set< std::pair< OID, ASN1_String > > & other_names() const
Return the set of "other names" whose value was a recognized ASN1_String type.
Definition pkix_types.h:427
const std::set< SmtpUtf8Mailbox > & smtp_utf8_mailboxes() const
Definition pkix_types.h:437
void add_uri(std::string_view uri)
Add a URI to this AlternativeName, parsing and validating the input.
Definition alt_name.cpp:17
void add_registered_id(const OID &oid)
Add a registeredID (RFC 5280 [8]).
Definition alt_name.cpp:97
const std::set< OtherNameValue > & other_name_values() const
Return all "OtherName" entries with their inner ANY value as raw BER.
Definition pkix_types.h:432
void add_other_name_value(const OID &oid, std::span< const uint8_t > value)
Definition alt_name.cpp:93
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:86
const std::set< IPv6Address > & ipv6_address() const
Return the set of IPv6 addresses included in this alternative name.
Definition pkix_types.h:415
const std::set< IPv4Address > & ipv4_addresses() const
Return the set of IPv4 addresses included in this alternative name.
Definition pkix_types.h:420
void add_dn(const X509_DN &dn)
Add a directory name to this AlternativeName.
Definition alt_name.cpp:101
const std::set< URI > & uri_names() const
Return the set of URIs included in this alternative name.
Definition pkix_types.h:391
AlternativeName()=default
Create an empty name.
std::multimap< OID, ASN1_String > get_othernames() const
const std::set< OID > & registered_ids() const
Return the set of registeredID OIDs.
Definition pkix_types.h:440
const std::vector< uint8_t > & parameters() const
Definition pkix_types.h:522
void decode_from(BER_Decoder &from) override
const OID & object_identifier() const
Definition pkix_types.h:524
const OID & oid() const
Definition pkix_types.h:520
void encode_into(DER_Encoder &to) const override
Attribute()=default
const std::vector< uint8_t > & get_parameters() const
Definition pkix_types.h:526
Definition x509_crl.h:32
virtual bool should_encode() const
Definition pkix_types.h:863
virtual void validate(const X509_Certificate &subject, const std::optional< X509_Certificate > &issuer, const std::vector< X509_Certificate > &cert_path, std::vector< std::set< Certificate_Status_Code > > &cert_status, size_t pos) const
Definition x509_ext.cpp:181
virtual std::string oid_name() const =0
virtual OID oid_of() const =0
virtual std::unique_ptr< Certificate_Extension > copy() const =0
virtual bool is_appropriate_context(Extension_Context context) const =0
virtual std::vector< uint8_t > encode_inner() const =0
virtual ~Certificate_Extension()=default
virtual void decode_inner(const std::vector< uint8_t > &)=0
const Certificate_Extension * get_extension_object(const OID &oid) const
Definition x509_ext.cpp:256
std::unique_ptr< T > get_raw(const OID &oid) const
Definition pkix_types.h:989
Extensions & operator=(const Extensions &)=default
bool has_unknown_critical_extension() const
Definition pkix_types.h:936
Extensions(const Extensions &)=default
~Extensions() override=default
size_t count() const
Extensions(Extensions &&)=default
const std::vector< OID > & get_extension_oids() const
Definition pkix_types.h:903
const T * get_extension_object_as(const OID &oid=T::static_oid()) const
Definition pkix_types.h:884
Extensions()=default
Extensions & operator=(Extensions &&)=default
X.509 GeneralName Type.
Definition pkix_types.h:543
static GeneralName email(std::string_view email)
void decode_from(BER_Decoder &from) override
GeneralName()=default
static GeneralName ipv4_address(uint32_t ipv4)
void encode_into(DER_Encoder &to) const override
static GeneralName uri(std::string_view uri)
static GeneralName _dns_san_value(std::string_view dns)
static GeneralName ipv6_address(const IPv6Address &ipv6)
friend class NameConstraints
Definition pkix_types.h:634
NameType type_code() const
Definition pkix_types.h:596
bool matches_ipv4(const IPv4Address &ip) const
Definition pkix_types.h:625
bool matches_ipv4(uint32_t ip) const
static GeneralName dns(std::string_view dns)
static GeneralName _uri_san_value(std::string_view full_uri)
static GeneralName directory_name(Botan::X509_DN dn)
A single Name Constraint.
Definition pkix_types.h:718
const GeneralName & base() const
Definition pkix_types.h:737
const std::vector< GeneralSubtree > & permitted() const
Definition pkix_types.h:768
const std::vector< GeneralSubtree > & excluded() const
Definition pkix_types.h:775
const std::vector< std::vector< std::pair< OID, ASN1_String > > > & rdns() const
Definition pkix_types.h:229
void add_attribute(const OID &oid, std::string_view val)
Definition pkix_types.h:247
void add_attribute(std::string_view key, std::string_view val)
Definition x509_dn.cpp:137
X509_DN()=default
const std::vector< uint8_t > & _canonical_bytes() const
Definition pkix_types.h:274
X509_DN(std::initializer_list< std::pair< std::string_view, std::string_view > > args)
Definition pkix_types.h:161
bool empty() const
Definition pkix_types.h:202
const std::vector< uint8_t > & get_bits() const
Definition pkix_types.h:198
size_t count() const
Definition pkix_types.h:209
size_t octet_length() const
Definition pkix_types.h:112
bool conforms_to_rfc5280() const
Definition pkix_types.h:118
std::span< const uint8_t > der_contents() const
Definition pkix_types.h:124
bool operator==(const X509_Serial_Number &other) const
Definition pkix_types.h:143
ASN1_Type
Definition asn1_obj.h:47
auto operator<=>(const Strong< T, Tags... > &lhs, const Strong< T, Tags... > &rhs)
Extension_Context
Definition pkix_types.h:797
std::string to_string(ErrorType type)
Convert an ErrorType to string.
Definition exceptn.cpp:13
std::string key_constraints_to_string(Key_Constraints c)
Definition pkix_types.h:43