Botan 3.12.0
Crypto and TLS for C&
alt_name.cpp
Go to the documentation of this file.
1/*
2* (C) 2024 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/pkix_types.h>
8
9#include <botan/ber_dec.h>
10#include <botan/der_enc.h>
11#include <botan/internal/int_utils.h>
12#include <botan/internal/loadstor.h>
13#include <botan/internal/parsing.h>
14
15namespace Botan {
16
17void AlternativeName::add_uri(std::string_view uri) {
18 if(!uri.empty()) {
19 m_uri.insert(std::string(uri));
20 }
21}
22
23void AlternativeName::add_email(std::string_view addr) {
24 if(!addr.empty()) {
25 m_email.insert(std::string(addr));
26 }
27}
28
29void AlternativeName::add_dns(std::string_view dns) {
30 if(!dns.empty()) {
31 m_dns.insert(tolower_string(dns));
32 }
33}
34
35void AlternativeName::add_other_name(const OID& oid, const ASN1_String& value) {
36 m_othernames.insert(std::make_pair(oid, value));
37}
38
40 m_dn_names.insert(dn);
41}
42
44 m_ipv4_addr.insert(ip);
45}
46
48 m_ipv6_addr.insert(ip);
49}
50
51size_t AlternativeName::count() const {
52 const auto sum = checked_add(m_dns.size(),
53 m_uri.size(),
54 m_email.size(),
55 m_ipv4_addr.size(),
56 m_ipv6_addr.size(),
57 m_dn_names.size(),
58 m_othernames.size());
59
60 BOTAN_ASSERT_NOMSG(sum.has_value());
61 return sum.value();
62}
63
65 return this->count() > 0;
66}
67
69 der.start_sequence();
70
71 /*
72 GeneralName ::= CHOICE {
73 otherName [0] OtherName,
74 rfc822Name [1] IA5String,
75 dNSName [2] IA5String,
76 x400Address [3] ORAddress,
77 directoryName [4] Name,
78 ediPartyName [5] EDIPartyName,
79 uniformResourceIdentifier [6] IA5String,
80 iPAddress [7] OCTET STRING,
81 registeredID [8] OBJECT IDENTIFIER }
82 */
83
84 for(const auto& othername : m_othernames) {
85 der.start_explicit(0)
86 .encode(othername.first)
88 .encode(othername.second)
90 .end_explicit();
91 }
92
93 for(const auto& name : m_email) {
94 const ASN1_String str(name, ASN1_Type::Ia5String);
96 }
97
98 for(const auto& name : m_dns) {
99 const ASN1_String str(name, ASN1_Type::Ia5String);
101 }
102
103 for(const auto& name : m_dn_names) {
104 der.add_object(ASN1_Type(4), ASN1_Class::ExplicitContextSpecific, name.DER_encode());
105 }
106
107 for(const auto& name : m_uri) {
108 const ASN1_String str(name, ASN1_Type::Ia5String);
110 }
111
112 for(const uint32_t ip : m_ipv4_addr) {
113 auto ip_buf = store_be(ip);
114 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
115 der.add_object(ASN1_Type(7), ASN1_Class::ContextSpecific, ip_buf.data(), 4);
116 }
117
118 for(const auto& ip : m_ipv6_addr) {
119 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
120 der.add_object(ASN1_Type(7), ASN1_Class::ContextSpecific, ip.address().data(), ip.address().size());
121 }
122
123 der.end_cons();
124}
125
127 BER_Decoder names = source.start_sequence();
128
129 while(names.more_items()) {
130 const BER_Object obj = names.get_next_object();
131
133 BER_Decoder othername(obj, names.limits());
134
135 OID oid;
136 othername.decode(oid);
137 if(othername.more_items()) {
138 const BER_Object othername_value_outer = othername.get_next_object();
139 othername.verify_end();
140
141 if(!othername_value_outer.is_a(0, ASN1_Class::ExplicitContextSpecific)) {
142 throw Decoding_Error("Invalid tags on otherName value");
143 }
144
145 BER_Decoder othername_value_inner(othername_value_outer, names.limits());
146
147 const BER_Object value = othername_value_inner.get_next_object();
148 othername_value_inner.verify_end();
149
151 add_othername(oid, ASN1::to_string(value), value.type());
152 }
153 }
154 } else if(obj.is_a(1, ASN1_Class::ContextSpecific)) {
156 } else if(obj.is_a(2, ASN1_Class::ContextSpecific)) {
159 BER_Decoder dec(obj, names.limits());
160 X509_DN dn;
161 dec.decode(dn);
162 this->add_dn(dn);
163 } else if(obj.is_a(6, ASN1_Class::ContextSpecific)) {
164 this->add_uri(ASN1::to_string(obj));
165 } else if(obj.is_a(7, ASN1_Class::ContextSpecific)) {
166 if(obj.length() == 4) {
167 const uint32_t ip = load_be<uint32_t>(obj.bits(), 0);
168 this->add_ipv4_address(ip);
169 } else if(obj.length() == 16) {
170 const IPv6Address ip(std::span<const uint8_t, 16>{obj.bits(), 16});
171 this->add_ipv6_address(ip);
172 } else {
173 throw Decoding_Error("Invalid IP constraint neither IPv4 or IPv6");
174 }
175 }
176 }
177}
178
179} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
const std::string & value() const
Definition asn1_obj.h:365
static bool is_string_type(ASN1_Type tag)
Definition asn1_str.cpp:131
void add_dns(std::string_view dns)
Add a DNS name to this AlternativeName.
Definition alt_name.cpp:29
void add_ipv4_address(uint32_t ipv4)
Add an IP address to this alternative name.
Definition alt_name.cpp:43
void add_email(std::string_view addr)
Add a URI to this AlternativeName.
Definition alt_name.cpp:23
size_t count() const
Definition alt_name.cpp:51
void encode_into(DER_Encoder &to) const override
Definition alt_name.cpp:68
void add_uri(std::string_view uri)
Add a URI to this AlternativeName.
Definition alt_name.cpp:17
void add_ipv6_address(const IPv6Address &ipv6)
Add an IPv6 address to this alternative name.
Definition alt_name.cpp:47
bool has_items() const
Return true if this has any names set.
Definition alt_name.cpp:64
const std::set< std::string > & dns() const
Return the set of DNS names included in this alternative name.
Definition pkix_types.h:183
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:35
void add_othername(const OID &oid, std::string_view value, ASN1_Type type)
void add_dn(const X509_DN &dn)
Add a directory name to this AlternativeName.
Definition alt_name.cpp:39
void decode_from(BER_Decoder &from) override
Definition alt_name.cpp:126
BER_Object get_next_object()
Definition ber_dec.cpp:426
BER_Decoder & decode(bool &out)
Definition ber_dec.h:220
bool more_items() const
Definition ber_dec.cpp:371
Limits limits() const
Definition ber_dec.h:98
BER_Decoder & verify_end()
Definition ber_dec.cpp:381
BER_Decoder start_sequence()
Definition ber_dec.h:160
size_t length() const
Definition asn1_obj.h:152
const uint8_t * bits() const
Definition asn1_obj.h:150
bool is_a(ASN1_Type type_tag, ASN1_Class class_tag) const
Definition asn1_obj.cpp:66
ASN1_Type type() const
Definition asn1_obj.h:146
ASN1_Class get_class() const
Definition asn1_obj.h:148
DER_Encoder & add_object(ASN1_Type type_tag, ASN1_Class class_tag, const uint8_t rep[], size_t length)
Definition der_enc.cpp:217
DER_Encoder & end_explicit()
Definition der_enc.cpp:195
DER_Encoder & start_explicit(uint16_t type_tag)
Definition der_enc.cpp:188
DER_Encoder & start_sequence()
Definition der_enc.h:67
DER_Encoder & end_cons()
Definition der_enc.cpp:173
DER_Encoder & encode(bool b)
Definition der_enc.cpp:245
std::string to_string(const BER_Object &obj)
Definition asn1_obj.cpp:190
constexpr std::optional< T > checked_add(T a, T b)
Definition int_utils.h:19
std::string tolower_string(std::string_view str)
Definition parsing.cpp:377
ASN1_Type
Definition asn1_obj.h:43
std::string check_and_canonicalize_dns_name(std::string_view name)
Definition parsing.cpp:531
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:504