Botan 3.4.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/ber_dec.h>
12#include <botan/der_enc.h>
13#include <botan/internal/loadstor.h>
14#include <botan/internal/parsing.h>
15#include <botan/internal/stl_util.h>
16
17#include <sstream>
18
19namespace Botan {
20
21/*
22* Create an AlternativeName
23*/
24AlternativeName::AlternativeName(std::string_view email_addr,
25 std::string_view uri,
26 std::string_view dns,
27 std::string_view ip) {
28 add_attribute("RFC822", email_addr);
29 add_attribute("DNS", dns);
30 add_attribute("URI", uri);
31 add_attribute("IP", ip);
32}
33
34/*
35* Add an attribute to an alternative name
36*/
37void AlternativeName::add_attribute(std::string_view type, std::string_view value) {
38 if(type.empty() || value.empty()) {
39 return;
40 }
41
42 auto range = m_alt_info.equal_range(type);
43 for(auto j = range.first; j != range.second; ++j) {
44 if(j->second == value) {
45 return;
46 }
47 }
48
49 m_alt_info.emplace(type, value);
50}
51
52/*
53* Add an OtherName field
54*/
55void AlternativeName::add_othername(const OID& oid, std::string_view value, ASN1_Type type) {
56 if(value.empty()) {
57 return;
58 }
59 multimap_insert(m_othernames, oid, ASN1_String(value, type));
60}
61
62/*
63* Return all of the alternative names
64*/
65std::multimap<std::string, std::string> AlternativeName::contents() const {
66 std::multimap<std::string, std::string> names;
67
68 for(const auto& name : m_alt_info) {
69 names.emplace(name.first, name.second);
70 }
71
72 for(const auto& othername : m_othernames) {
73 multimap_insert(names, othername.first.to_formatted_string(), othername.second.value());
74 }
75
76 return names;
77}
78
79bool AlternativeName::has_field(std::string_view attr) const {
80 auto range = m_alt_info.equal_range(attr);
81 return (range.first != range.second);
82}
83
84std::string AlternativeName::get_first_attribute(std::string_view attr) const {
85 auto i = m_alt_info.lower_bound(attr);
86 if(i != m_alt_info.end() && i->first == attr) {
87 return i->second;
88 }
89
90 return "";
91}
92
93std::vector<std::string> AlternativeName::get_attribute(std::string_view attr) const {
94 std::vector<std::string> results;
95 auto range = m_alt_info.equal_range(attr);
96 for(auto i = range.first; i != range.second; ++i) {
97 results.push_back(i->second);
98 }
99 return results;
100}
101
103 X509_DN dn;
104 auto range = m_alt_info.equal_range("DN");
105
106 for(auto i = range.first; i != range.second; ++i) {
107 std::istringstream strm(i->second);
108 strm >> dn;
109 }
110
111 return dn;
112}
113
114/*
115* Return if this object has anything useful
116*/
118 return (!m_alt_info.empty() || !m_othernames.empty());
119}
120
121namespace {
122
123/*
124* DER encode an AlternativeName entry
125*/
126void encode_entries(DER_Encoder& encoder,
127 const std::multimap<std::string, std::string, std::less<>>& attr,
128 std::string_view type,
129 ASN1_Type tagging) {
130 auto range = attr.equal_range(type);
131
132 for(auto i = range.first; i != range.second; ++i) {
133 if(type == "RFC822" || type == "DNS" || type == "URI") {
134 ASN1_String asn1_string(i->second, ASN1_Type::Ia5String);
135 encoder.add_object(tagging, ASN1_Class::ContextSpecific, asn1_string.value());
136 } else if(type == "IP") {
137 const uint32_t ip = string_to_ipv4(i->second);
138 uint8_t ip_buf[4] = {0};
139 store_be(ip, ip_buf);
140 encoder.add_object(tagging, ASN1_Class::ContextSpecific, ip_buf, 4);
141 } else if(type == "DN") {
142 std::stringstream ss(i->second);
143 X509_DN dn;
144 ss >> dn;
145 encoder.encode(dn);
146 }
147 }
148}
149
150} // namespace
151
152/*
153* DER encode an AlternativeName extension
154*/
156 der.start_sequence();
157
158 encode_entries(der, m_alt_info, "RFC822", ASN1_Type(1));
159 encode_entries(der, m_alt_info, "DNS", ASN1_Type(2));
160 encode_entries(der, m_alt_info, "DN", ASN1_Type(4));
161 encode_entries(der, m_alt_info, "URI", ASN1_Type(6));
162 encode_entries(der, m_alt_info, "IP", ASN1_Type(7));
163
164 for(const auto& othername : m_othernames) {
165 der.start_explicit(0)
166 .encode(othername.first)
168 .encode(othername.second)
169 .end_explicit()
170 .end_explicit();
171 }
172
173 der.end_cons();
174}
175
176/*
177* Decode a BER encoded AlternativeName
178*/
180 BER_Decoder names = source.start_sequence();
181
182 // FIXME this is largely a duplication of GeneralName::decode_from
183
184 while(names.more_items()) {
185 BER_Object obj = names.get_next_object();
186
188 BER_Decoder othername(obj);
189
190 OID oid;
191 othername.decode(oid);
192 if(othername.more_items()) {
193 BER_Object othername_value_outer = othername.get_next_object();
194 othername.verify_end();
195
196 if(othername_value_outer.is_a(0, ASN1_Class::ExplicitContextSpecific) == false) {
197 throw Decoding_Error("Invalid tags on otherName value");
198 }
199
200 BER_Decoder othername_value_inner(othername_value_outer);
201
202 BER_Object value = othername_value_inner.get_next_object();
203 othername_value_inner.verify_end();
204
206 add_othername(oid, ASN1::to_string(value), value.type());
207 }
208 }
209 }
211 add_attribute("RFC822", ASN1::to_string(obj));
212 } else if(obj.is_a(2, ASN1_Class::ContextSpecific)) {
213 add_attribute("DNS", ASN1::to_string(obj));
214 } else if(obj.is_a(6, ASN1_Class::ContextSpecific)) {
215 add_attribute("URI", ASN1::to_string(obj));
217 BER_Decoder dec(obj);
218 X509_DN dn;
219 std::stringstream ss;
220
221 dec.decode(dn);
222 ss << dn;
223
224 add_attribute("DN", ss.str());
225 } else if(obj.is_a(7, ASN1_Class::ContextSpecific)) {
226 if(obj.length() == 4) {
227 const uint32_t ip = load_be<uint32_t>(obj.bits(), 0);
228 add_attribute("IP", ipv4_to_string(ip));
229 }
230 }
231 }
232}
233
234} // namespace Botan
static bool is_string_type(ASN1_Type tag)
Definition asn1_str.cpp:60
std::string get_first_attribute(std::string_view attr) const
std::multimap< std::string, std::string > contents() const
std::vector< std::string > get_attribute(std::string_view attr) const
void add_attribute(std::string_view type, std::string_view value)
void encode_into(DER_Encoder &) const override
AlternativeName(std::string_view email_addr="", std::string_view uri="", std::string_view dns="", std::string_view ip_address="")
void add_othername(const OID &oid, std::string_view value, ASN1_Type type)
void decode_from(BER_Decoder &) override
bool has_field(std::string_view attr) const
BER_Object get_next_object()
Definition ber_dec.cpp:231
BER_Decoder & decode(bool &out)
Definition ber_dec.h:176
bool more_items() const
Definition ber_dec.cpp:195
BER_Decoder & verify_end()
Definition ber_dec.cpp:205
BER_Decoder start_sequence()
Definition ber_dec.h:113
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:61
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:222
DER_Encoder & end_explicit()
Definition der_enc.cpp:200
DER_Encoder & start_explicit(uint16_t type_tag)
Definition der_enc.cpp:186
DER_Encoder & start_sequence()
Definition der_enc.h:65
DER_Encoder & end_cons()
Definition der_enc.cpp:171
DER_Encoder & encode(bool b)
Definition der_enc.cpp:250
std::string name
std::string to_string(const BER_Object &obj)
Definition asn1_obj.cpp:185
uint32_t string_to_ipv4(std::string_view str)
Definition parsing.cpp:156
ASN1_Type
Definition asn1_obj.h:43
void multimap_insert(std::multimap< K, V > &multimap, const K &key, const V &value)
Definition stl_util.h:110
std::string ipv4_to_string(uint32_t ip)
Definition parsing.cpp:181
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:711