Botan 3.12.0
Crypto and TLS for C&
asn1_alt_name.cpp
Go to the documentation of this file.
1/*
2* AlternativeName
3* (C) 1999-2007 Jack Lloyd
4* 2007 Yves Jerschow
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/pkix_types.h>
10
11#include <botan/internal/fmt.h>
12#include <botan/internal/parsing.h>
13#include <sstream>
14
15namespace Botan {
16
17/*
18* Create an AlternativeName
19*/
20AlternativeName::AlternativeName(std::string_view email_addr,
21 std::string_view uri,
22 std::string_view dns,
23 std::string_view ip) {
24 if(!email_addr.empty()) {
25 add_email(email_addr);
26 }
27 if(!dns.empty()) {
28 add_dns(dns);
29 }
30 if(!uri.empty()) {
31 add_uri(uri);
32 }
33 if(!ip.empty()) {
34 if(auto ipv4 = string_to_ipv4(ip)) {
35 add_ipv4_address(*ipv4);
36 } else {
37 throw Invalid_Argument(fmt("Invalid IPv4 address '{}'", ip));
38 }
39 }
40}
41
42/*
43* Add an attribute to an alternative name
44*/
45void AlternativeName::add_attribute(std::string_view type, std::string_view value) {
46 if(type.empty() || value.empty()) {
47 return;
48 }
49
50 if(type == "DNS") {
51 this->add_dns(value);
52 } else if(type == "RFC822") {
53 this->add_email(value);
54 } else if(type == "URI") {
55 this->add_uri(value);
56 } else if(type == "DN") {
57 X509_DN dn;
58 std::istringstream ss{std::string(value)};
59 ss >> dn;
60 this->add_dn(dn);
61 } else if(type == "IP") {
62 if(auto ipv4 = string_to_ipv4(value)) {
63 add_ipv4_address(*ipv4);
64 } else {
65 throw Invalid_Argument(fmt("Invalid IPv4 address '{}'", value));
66 }
67 } else {
68 throw Not_Implemented(fmt("Unknown AlternativeName name type {}", type));
69 }
70}
71
72/*
73* Add an OtherName field
74*/
75void AlternativeName::add_othername(const OID& oid, std::string_view value, ASN1_Type type) {
76 if(value.empty()) {
77 return;
78 }
79 this->add_other_name(oid, ASN1_String(value, type));
80}
81
82/*
83* Return all of the alternative names
84*/
85std::multimap<std::string, std::string> AlternativeName::contents() const {
86 std::multimap<std::string, std::string> names;
87
88 for(const auto& nm : this->dns()) {
89 names.emplace("DNS", nm);
90 }
91
92 for(const auto& nm : this->email()) {
93 names.emplace("RFC822", nm);
94 }
95
96 for(const auto& nm : this->uris()) {
97 names.emplace("URI", nm);
98 }
99
100 for(const uint32_t ipv4 : this->ipv4_address()) {
101 names.emplace("IP", ipv4_to_string(ipv4));
102 }
103
104 for(const auto& ipv6 : this->ipv6_address()) {
105 names.emplace("IPv6", ipv6.to_string());
106 }
107
108 for(const auto& nm : this->directory_names()) {
109 names.emplace("DN", nm.to_string());
110 }
111
112 for(const auto& othername : this->other_names()) {
113 names.emplace(othername.first.to_formatted_string(), othername.second.value());
114 }
115
116 return names;
117}
118
119std::multimap<std::string, std::string, std::less<>> AlternativeName::get_attributes() const {
120 std::multimap<std::string, std::string, std::less<>> r;
121
122 for(const auto& c : this->contents()) {
123 r.emplace(c.first, c.second);
124 }
125
126 return r;
127}
128
129bool AlternativeName::has_field(std::string_view attr) const {
130 return !this->get_attribute(attr).empty();
131}
132
133std::string AlternativeName::get_first_attribute(std::string_view type) const {
134 auto attr = this->get_attribute(type);
135
136 if(!attr.empty()) {
137 return attr[0];
138 }
139
140 return "";
141}
142
143std::vector<std::string> AlternativeName::get_attribute(std::string_view attr) const {
144 auto set_to_vector = [](const std::set<std::string>& s) -> std::vector<std::string> { return {s.begin(), s.end()}; };
145
146 if(attr == "DNS") {
147 return set_to_vector(this->dns());
148 } else if(attr == "RFC822") {
149 return set_to_vector(this->email());
150 } else if(attr == "URI") {
151 return set_to_vector(this->uris());
152 } else if(attr == "DN") {
153 std::vector<std::string> ret;
154
155 for(const auto& nm : this->directory_names()) {
156 ret.push_back(nm.to_string());
157 }
158
159 return ret;
160 } else if(attr == "IP") {
161 std::vector<std::string> ip_str;
162 for(const uint32_t ipv4 : this->ipv4_address()) {
163 ip_str.push_back(ipv4_to_string(ipv4));
164 }
165 return ip_str;
166 } else {
167 return {};
168 }
169}
170
172 // This logic really does not make any sense, but it is
173 // how this function was historically implemented.
174
175 X509_DN combined_dn;
176
177 for(const auto& dn : this->directory_names()) {
178 std::ostringstream oss;
179 oss << dn;
180
181 std::istringstream iss(oss.str());
182 iss >> combined_dn;
183 }
184
185 return combined_dn;
186}
187
188/*
189* Return if this object has anything useful
190*/
191} // namespace Botan
const std::set< X509_DN > & directory_names() const
Return the set of directory names included in this alternative name.
Definition pkix_types.h:198
std::string get_first_attribute(std::string_view attr) const
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
std::multimap< std::string, std::string > contents() const
std::vector< std::string > get_attribute(std::string_view attr) const
const std::set< uint32_t > & ipv4_address() const
Return the set of IPv4 addresses included in this alternative name.
Definition pkix_types.h:186
const std::set< std::pair< OID, ASN1_String > > & other_names() const
Return the set of "other names" included in this alternative name.
Definition pkix_types.h:193
const std::set< std::string > & uris() const
Return the set of URIs included in this alternative name.
Definition pkix_types.h:177
void add_uri(std::string_view uri)
Add a URI to this AlternativeName.
Definition alt_name.cpp:17
void add_attribute(std::string_view type, std::string_view value)
const std::set< std::string > & dns() const
Return the set of DNS names included in this alternative name.
Definition pkix_types.h:183
std::multimap< std::string, std::string, std::less<> > get_attributes() const
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)
const std::set< IPv6Address > & ipv6_address() const
Return the set of IPv6 addresses included in this alternative name.
Definition pkix_types.h:189
const std::set< std::string > & email() const
Return the set of email addresses included in this alternative name.
Definition pkix_types.h:180
void add_dn(const X509_DN &dn)
Add a directory name to this AlternativeName.
Definition alt_name.cpp:39
AlternativeName()=default
Create an empty name.
bool has_field(std::string_view attr) const
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
ASN1_Type
Definition asn1_obj.h:43
std::optional< uint32_t > string_to_ipv4(std::string_view str)
Definition parsing.cpp:155
std::string ipv4_to_string(uint32_t ip)
Definition parsing.cpp:361