Botan  2.1.0
Crypto and TLS for C++11
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/asn1_alt_name.h>
10 #include <botan/der_enc.h>
11 #include <botan/ber_dec.h>
12 #include <botan/oids.h>
13 #include <botan/internal/stl_util.h>
14 #include <botan/charset.h>
15 #include <botan/parsing.h>
16 #include <botan/loadstor.h>
17 
18 namespace Botan {
19 
20 namespace {
21 
22 /*
23 * Check if type is a known ASN.1 string type
24 */
25 bool is_string_type(ASN1_Tag tag)
26  {
27  return (tag == NUMERIC_STRING ||
28  tag == PRINTABLE_STRING ||
29  tag == VISIBLE_STRING ||
30  tag == T61_STRING ||
31  tag == IA5_STRING ||
32  tag == UTF8_STRING ||
33  tag == BMP_STRING);
34  }
35 
36 }
37 
38 /*
39 * Create an AlternativeName
40 */
41 AlternativeName::AlternativeName(const std::string& email_addr,
42  const std::string& uri,
43  const std::string& dns,
44  const std::string& ip)
45  {
46  add_attribute("RFC822", email_addr);
47  add_attribute("DNS", dns);
48  add_attribute("URI", uri);
49  add_attribute("IP", ip);
50  }
51 
52 /*
53 * Add an attribute to an alternative name
54 */
55 void AlternativeName::add_attribute(const std::string& type,
56  const std::string& str)
57  {
58  if(type.empty() || str.empty())
59  return;
60 
61  auto range = m_alt_info.equal_range(type);
62  for(auto j = range.first; j != range.second; ++j)
63  if(j->second == str)
64  return;
65 
66  multimap_insert(m_alt_info, type, str);
67  }
68 
69 /*
70 * Add an OtherName field
71 */
72 void AlternativeName::add_othername(const OID& oid, const std::string& value,
73  ASN1_Tag type)
74  {
75  if(value.empty())
76  return;
77  multimap_insert(m_othernames, oid, ASN1_String(value, type));
78  }
79 
80 /*
81 * Get the attributes of this alternative name
82 */
83 std::multimap<std::string, std::string> AlternativeName::get_attributes() const
84  {
85  return m_alt_info;
86  }
87 
88 /*
89 * Get the otherNames
90 */
91 std::multimap<OID, ASN1_String> AlternativeName::get_othernames() const
92  {
93  return m_othernames;
94  }
95 
96 /*
97 * Return all of the alternative names
98 */
99 std::multimap<std::string, std::string> AlternativeName::contents() const
100  {
101  std::multimap<std::string, std::string> names;
102 
103  for(auto i = m_alt_info.begin(); i != m_alt_info.end(); ++i)
104  multimap_insert(names, i->first, i->second);
105 
106  for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i)
107  multimap_insert(names, OIDS::lookup(i->first), i->second.value());
108 
109  return names;
110  }
111 
112 /*
113 * Return if this object has anything useful
114 */
116  {
117  return (m_alt_info.size() > 0 || m_othernames.size() > 0);
118  }
119 
120 namespace {
121 
122 /*
123 * DER encode an AlternativeName entry
124 */
125 void encode_entries(DER_Encoder& encoder,
126  const std::multimap<std::string, std::string>& attr,
127  const std::string& type, ASN1_Tag tagging)
128  {
129  auto range = attr.equal_range(type);
130 
131  for(auto i = range.first; i != range.second; ++i)
132  {
133  if(type == "RFC822" || type == "DNS" || type == "URI")
134  {
135  ASN1_String asn1_string(i->second, IA5_STRING);
136  encoder.add_object(tagging, CONTEXT_SPECIFIC, asn1_string.iso_8859());
137  }
138  else if(type == "IP")
139  {
140  const uint32_t ip = string_to_ipv4(i->second);
141  uint8_t ip_buf[4] = { 0 };
142  store_be(ip, ip_buf);
143  encoder.add_object(tagging, CONTEXT_SPECIFIC, ip_buf, 4);
144  }
145  }
146  }
147 
148 }
149 
150 /*
151 * DER encode an AlternativeName extension
152 */
154  {
155  der.start_cons(SEQUENCE);
156 
157  encode_entries(der, m_alt_info, "RFC822", ASN1_Tag(1));
158  encode_entries(der, m_alt_info, "DNS", ASN1_Tag(2));
159  encode_entries(der, m_alt_info, "URI", ASN1_Tag(6));
160  encode_entries(der, m_alt_info, "IP", ASN1_Tag(7));
161 
162  for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i)
163  {
164  der.start_explicit(0)
165  .encode(i->first)
166  .start_explicit(0)
167  .encode(i->second)
168  .end_explicit()
169  .end_explicit();
170  }
171 
172  der.end_cons();
173  }
174 
175 /*
176 * Decode a BER encoded AlternativeName
177 */
179  {
180  BER_Decoder names = source.start_cons(SEQUENCE);
181 
182  while(names.more_items())
183  {
184  BER_Object obj = names.get_next_object();
185  if((obj.class_tag != CONTEXT_SPECIFIC) &&
187  continue;
188 
189  const ASN1_Tag tag = obj.type_tag;
190 
191  if(tag == 0)
192  {
193  BER_Decoder othername(obj.value);
194 
195  OID oid;
196  othername.decode(oid);
197  if(othername.more_items())
198  {
199  BER_Object othername_value_outer = othername.get_next_object();
200  othername.verify_end();
201 
202  if(othername_value_outer.type_tag != ASN1_Tag(0) ||
203  othername_value_outer.class_tag !=
205  )
206  throw Decoding_Error("Invalid tags on otherName value");
207 
208  BER_Decoder othername_value_inner(othername_value_outer.value);
209 
210  BER_Object value = othername_value_inner.get_next_object();
211  othername_value_inner.verify_end();
212 
213  const ASN1_Tag value_type = value.type_tag;
214 
215  if(is_string_type(value_type) && value.class_tag == UNIVERSAL)
216  add_othername(oid, ASN1::to_string(value), value_type);
217  }
218  }
219  else if(tag == 1 || tag == 2 || tag == 6)
220  {
221  const std::string value = Charset::transcode(ASN1::to_string(obj),
223  LOCAL_CHARSET);
224 
225  if(tag == 1) add_attribute("RFC822", value);
226  if(tag == 2) add_attribute("DNS", value);
227  if(tag == 6) add_attribute("URI", value);
228  }
229  else if(tag == 7)
230  {
231  if(obj.value.size() == 4)
232  {
233  const uint32_t ip = load_be<uint32_t>(&obj.value[0], 0);
234  add_attribute("IP", ipv4_to_string(ip));
235  }
236  }
237 
238  }
239  }
240 
241 }
void encode_into(class DER_Encoder &) const override
DER_Encoder & add_object(ASN1_Tag type_tag, ASN1_Tag class_tag, const uint8_t rep[], size_t length)
Definition: der_enc.cpp:381
void add_attribute(const std::string &, const std::string &)
void store_be(uint16_t in, uint8_t out[2])
Definition: loadstor.h:441
uint32_t load_be< uint32_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:185
BER_Decoder & decode(bool &v)
Definition: ber_dec.cpp:376
DER_Encoder & end_explicit()
Definition: der_enc.cpp:174
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:47
MechanismType type
std::multimap< std::string, std::string > contents() const
std::string ipv4_to_string(uint32_t ip)
Definition: parsing.cpp:288
DER_Encoder & end_cons()
Definition: der_enc.cpp:147
std::multimap< OID, ASN1_String > get_othernames() const
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:216
secure_vector< uint8_t > value
Definition: asn1_obj.h:94
bool more_items() const
Definition: ber_dec.cpp:158
std::string transcode(const std::string &str, Character_Set to, Character_Set from)
Definition: charset.cpp:103
std::string lookup(const OID &oid)
Definition: oids.cpp:18
ASN1_Tag
Definition: asn1_obj.h:22
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:258
std::multimap< std::string, std::string > get_attributes() const
Definition: alg_id.cpp:13
void add_othername(const OID &, const std::string &, ASN1_Tag)
BER_Object get_next_object()
Definition: ber_dec.cpp:210
AlternativeName(const std::string &="", const std::string &="", const std::string &="", const std::string &="")
ASN1_Tag class_tag
Definition: asn1_obj.h:91
ASN1_Tag type_tag
Definition: asn1_obj.h:91
BER_Decoder & verify_end()
Definition: ber_dec.cpp:168
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:137
void multimap_insert(std::multimap< K, V > &multimap, const K &key, const V &value)
Definition: stl_util.h:76
uint32_t string_to_ipv4(const std::string &str)
Definition: parsing.cpp:263
void decode_from(class BER_Decoder &) override
DER_Encoder & start_explicit(uint16_t type_tag)
Definition: der_enc.cpp:161