Coverage Report

Created: 2021-02-21 07:20

/src/botan/src/lib/x509/asn1_alt_name.cpp
Line
Count
Source (jump to first uncovered line)
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
#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/internal/parsing.h>
15
#include <botan/internal/loadstor.h>
16
17
#include <sstream>
18
19
namespace Botan {
20
21
/*
22
* Create an AlternativeName
23
*/
24
AlternativeName::AlternativeName(const std::string& email_addr,
25
                                 const std::string& uri,
26
                                 const std::string& dns,
27
                                 const std::string& ip)
28
39.3k
   {
29
39.3k
   add_attribute("RFC822", email_addr);
30
39.3k
   add_attribute("DNS", dns);
31
39.3k
   add_attribute("URI", uri);
32
39.3k
   add_attribute("IP", ip);
33
39.3k
   }
34
35
/*
36
* Add an attribute to an alternative name
37
*/
38
void AlternativeName::add_attribute(const std::string& type,
39
                                    const std::string& value)
40
180k
   {
41
180k
   if(type.empty() || value.empty())
42
159k
      return;
43
44
20.8k
   auto range = m_alt_info.equal_range(type);
45
204k
   for(auto j = range.first; j != range.second; ++j)
46
190k
      if(j->second == value)
47
6.79k
         return;
48
49
14.0k
   multimap_insert(m_alt_info, type, value);
50
14.0k
   }
51
52
/*
53
* Add an OtherName field
54
*/
55
void AlternativeName::add_othername(const OID& oid, const std::string& value,
56
                                    ASN1_Type type)
57
3.11k
   {
58
3.11k
   if(value.empty())
59
101
      return;
60
3.01k
   multimap_insert(m_othernames, oid, ASN1_String(value, type));
61
3.01k
   }
62
63
/*
64
* Return all of the alternative names
65
*/
66
std::multimap<std::string, std::string> AlternativeName::contents() const
67
589
   {
68
589
   std::multimap<std::string, std::string> names;
69
70
2.74k
   for(auto i = m_alt_info.begin(); i != m_alt_info.end(); ++i)
71
2.15k
      {
72
2.15k
      multimap_insert(names, i->first, i->second);
73
2.15k
      }
74
75
1.39k
   for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i)
76
801
      {
77
801
      multimap_insert(names, i->first.to_formatted_string(), i->second.value());
78
801
      }
79
80
589
   return names;
81
589
   }
82
83
bool AlternativeName::has_field(const std::string& attr) const
84
0
   {
85
0
   auto range = m_alt_info.equal_range(attr);
86
0
   return (range.first != range.second);
87
0
   }
88
89
std::string AlternativeName::get_first_attribute(const std::string& attr) const
90
0
   {
91
0
   auto i = m_alt_info.lower_bound(attr);
92
0
   if(i != m_alt_info.end() && i->first == attr)
93
0
      return i->second;
94
95
0
   return "";
96
0
   }
97
98
std::vector<std::string> AlternativeName::get_attribute(const std::string& attr) const
99
0
   {
100
0
   std::vector<std::string> results;
101
0
   auto range = m_alt_info.equal_range(attr);
102
0
   for(auto i = range.first; i != range.second; ++i)
103
0
      results.push_back(i->second);
104
0
   return results;
105
0
   }
106
107
X509_DN AlternativeName::dn() const
108
0
   {
109
0
   X509_DN dn;
110
0
   auto range = m_alt_info.equal_range("DN");
111
112
0
   for(auto i = range.first; i != range.second; ++i)
113
0
      {
114
0
      std::istringstream strm(i->second);
115
0
      strm >> dn;
116
0
      }
117
118
0
   return dn;
119
0
   }
120
121
/*
122
* Return if this object has anything useful
123
*/
124
bool AlternativeName::has_items() const
125
0
   {
126
0
   return (m_alt_info.size() > 0 || m_othernames.size() > 0);
127
0
   }
128
129
namespace {
130
131
/*
132
* DER encode an AlternativeName entry
133
*/
134
void encode_entries(DER_Encoder& encoder,
135
                    const std::multimap<std::string, std::string>& attr,
136
                    const std::string& type, ASN1_Type tagging)
137
0
   {
138
0
   auto range = attr.equal_range(type);
139
140
0
   for(auto i = range.first; i != range.second; ++i)
141
0
      {
142
0
      if(type == "RFC822" || type == "DNS" || type == "URI")
143
0
         {
144
0
         ASN1_String asn1_string(i->second, ASN1_Type::Ia5String);
145
0
         encoder.add_object(tagging, ASN1_Class::ContextSpecific, asn1_string.value());
146
0
         }
147
0
      else if(type == "IP")
148
0
         {
149
0
         const uint32_t ip = string_to_ipv4(i->second);
150
0
         uint8_t ip_buf[4] = { 0 };
151
0
         store_be(ip, ip_buf);
152
0
         encoder.add_object(tagging, ASN1_Class::ContextSpecific, ip_buf, 4);
153
0
         }
154
0
      else if (type == "DN")
155
0
         {
156
0
         std::stringstream ss(i->second);
157
0
         X509_DN dn;
158
0
         ss >> dn;
159
0
         encoder.encode(dn);
160
0
         }
161
0
      }
162
0
   }
163
164
}
165
166
/*
167
* DER encode an AlternativeName extension
168
*/
169
void AlternativeName::encode_into(DER_Encoder& der) const
170
0
   {
171
0
   der.start_sequence();
172
173
0
   encode_entries(der, m_alt_info, "RFC822", ASN1_Type(1));
174
0
   encode_entries(der, m_alt_info, "DNS", ASN1_Type(2));
175
0
   encode_entries(der, m_alt_info, "DN", ASN1_Type(4));
176
0
   encode_entries(der, m_alt_info, "URI", ASN1_Type(6));
177
0
   encode_entries(der, m_alt_info, "IP", ASN1_Type(7));
178
179
0
   for(auto i = m_othernames.begin(); i != m_othernames.end(); ++i)
180
0
      {
181
0
      der.start_explicit(0)
182
0
         .encode(i->first)
183
0
         .start_explicit(0)
184
0
            .encode(i->second)
185
0
         .end_explicit()
186
0
      .end_explicit();
187
0
      }
188
189
0
   der.end_cons();
190
0
   }
191
192
/*
193
* Decode a BER encoded AlternativeName
194
*/
195
void AlternativeName::decode_from(BER_Decoder& source)
196
4.51k
   {
197
4.51k
   BER_Decoder names = source.start_sequence();
198
199
   // FIXME this is largely a duplication of GeneralName::decode_from
200
201
56.3k
   while(names.more_items())
202
51.8k
      {
203
51.8k
      BER_Object obj = names.get_next_object();
204
205
51.8k
      if(obj.is_a(0, ASN1_Class::ContextSpecific))
206
4.29k
         {
207
4.29k
         BER_Decoder othername(obj);
208
209
4.29k
         OID oid;
210
4.29k
         othername.decode(oid);
211
4.29k
         if(othername.more_items())
212
3.93k
            {
213
3.93k
            BER_Object othername_value_outer = othername.get_next_object();
214
3.93k
            othername.verify_end();
215
216
3.93k
            if(othername_value_outer.is_a(0, ASN1_Class::ExplicitContextSpecific) == false)
217
44
               throw Decoding_Error("Invalid tags on otherName value");
218
219
3.89k
            BER_Decoder othername_value_inner(othername_value_outer);
220
221
3.89k
            BER_Object value = othername_value_inner.get_next_object();
222
3.89k
            othername_value_inner.verify_end();
223
224
3.89k
            if(ASN1_String::is_string_type(value.type()) && value.get_class() == ASN1_Class::Universal)
225
3.11k
               {
226
3.11k
               add_othername(oid, ASN1::to_string(value), value.type());
227
3.11k
               }
228
3.89k
            }
229
4.29k
         }
230
51.8k
      if(obj.is_a(1, ASN1_Class::ContextSpecific))
231
8.16k
         {
232
8.16k
         add_attribute("RFC822", ASN1::to_string(obj));
233
8.16k
         }
234
43.6k
      else if(obj.is_a(2, ASN1_Class::ContextSpecific))
235
2.58k
         {
236
2.58k
         add_attribute("DNS", ASN1::to_string(obj));
237
2.58k
         }
238
41.0k
      else if(obj.is_a(6, ASN1_Class::ContextSpecific))
239
3.41k
         {
240
3.41k
         add_attribute("URI", ASN1::to_string(obj));
241
3.41k
         }
242
37.6k
      else if(obj.is_a(4, ASN1_Class::ContextSpecific | ASN1_Class::Constructed))
243
4.12k
         {
244
4.12k
         BER_Decoder dec(obj);
245
4.12k
         X509_DN dn;
246
4.12k
         std::stringstream ss;
247
248
4.12k
         dec.decode(dn);
249
4.12k
         ss << dn;
250
251
4.12k
         add_attribute("DN", ss.str());
252
4.12k
         }
253
33.5k
      else if(obj.is_a(7, ASN1_Class::ContextSpecific))
254
5.45k
         {
255
5.45k
         if(obj.length() == 4)
256
5.07k
            {
257
5.07k
            const uint32_t ip = load_be<uint32_t>(obj.bits(), 0);
258
5.07k
            add_attribute("IP", ipv4_to_string(ip));
259
5.07k
            }
260
5.45k
         }
261
262
51.8k
      }
263
4.51k
   }
264
265
}