Botan  2.4.0
Crypto and TLS for C++11
name_constraint.cpp
Go to the documentation of this file.
1 /*
2 * X.509 Name Constraint
3 * (C) 2015 Kai Michaelis
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/name_constraint.h>
9 #include <botan/asn1_alt_name.h>
10 #include <botan/ber_dec.h>
11 #include <botan/loadstor.h>
12 #include <botan/x509_dn.h>
13 #include <botan/x509cert.h>
14 #include <botan/parsing.h>
15 #include <sstream>
16 
17 namespace Botan {
18 
19 class DER_Encoder;
20 
21 GeneralName::GeneralName(const std::string& str) : GeneralName()
22  {
23  size_t p = str.find(':');
24 
25  if(p != std::string::npos)
26  {
27  m_type = str.substr(0, p);
28  m_name = str.substr(p + 1, std::string::npos);
29  }
30  else
31  {
32  throw Invalid_Argument("Failed to decode Name Constraint");
33  }
34  }
35 
37  {
38  throw Not_Implemented("GeneralName encoding");
39  }
40 
42  {
43  BER_Object obj = ber.get_next_object();
44  if((obj.class_tag != CONTEXT_SPECIFIC) &&
46  throw Decoding_Error("Invalid class tag while decoding GeneralName");
47 
48  const ASN1_Tag tag = obj.type_tag;
49 
50  if(tag == 1 || tag == 2 || tag == 6)
51  {
52  m_name = ASN1::to_string(obj);
53 
54  if(tag == 1)
55  {
56  m_type = "RFC822";
57  }
58  else if(tag == 2)
59  {
60  m_type = "DNS";
61  }
62  else if(tag == 6)
63  {
64  m_type = "URI";
65  }
66  }
67  else if(tag == 4)
68  {
69  X509_DN dn;
70  BER_Decoder dec(obj.value);
71  std::stringstream ss;
72 
73  dn.decode_from(dec);
74  ss << dn;
75 
76  m_name = ss.str();
77  m_type = "DN";
78  }
79  else if(tag == 7)
80  {
81  if(obj.value.size() == 8)
82  {
83  const std::vector<uint8_t> ip(obj.value.begin(), obj.value.begin() + 4);
84  const std::vector<uint8_t> net(obj.value.begin() + 4, obj.value.end());
85  m_type = "IP";
86  m_name = ipv4_to_string(load_be<uint32_t>(ip.data(), 0)) + "/" + ipv4_to_string(load_be<uint32_t>(net.data(), 0));
87  }
88  else if(obj.value.size() == 32)
89  {
90  throw Decoding_Error("Unsupported IPv6 name constraint");
91  }
92  else
93  {
94  throw Decoding_Error("Invalid IP name constraint size " +
95  std::to_string(obj.value.size()));
96  }
97  }
98  else
99  {
100  throw Decoding_Error("Found unknown GeneralName type");
101  }
102  }
103 
105  {
106  std::vector<std::string> nam;
107  std::function<bool(const GeneralName*, const std::string&)> match_fn;
108 
109  const X509_DN& dn = cert.subject_dn();
110  const AlternativeName& alt_name = cert.subject_alt_name();
111 
112  if(type() == "DNS")
113  {
114  match_fn = std::mem_fn(&GeneralName::matches_dns);
115 
116  nam = alt_name.get_attribute("DNS");
117 
118  if(nam.empty())
119  {
120  nam = dn.get_attribute("CN");
121  }
122  }
123  else if(type() == "DN")
124  {
125  match_fn = std::mem_fn(&GeneralName::matches_dn);
126 
127  std::stringstream ss;
128  ss << dn;
129  nam.push_back(ss.str());
130  }
131  else if(type() == "IP")
132  {
133  match_fn = std::mem_fn(&GeneralName::matches_ip);
134  nam = alt_name.get_attribute("IP");
135  }
136  else
137  {
138  return MatchResult::UnknownType;
139  }
140 
141  if(nam.empty())
142  {
143  return MatchResult::NotFound;
144  }
145 
146  bool some = false;
147  bool all = true;
148 
149  for(const std::string& n: nam)
150  {
151  bool m = match_fn(this, n);
152 
153  some |= m;
154  all &= m;
155  }
156 
157  if(all)
158  {
159  return MatchResult::All;
160  }
161  else if(some)
162  {
163  return MatchResult::Some;
164  }
165  else
166  {
167  return MatchResult::None;
168  }
169  }
170 
171 bool GeneralName::matches_dns(const std::string& nam) const
172  {
173  if(nam.size() == name().size())
174  {
175  return nam == name();
176  }
177  else if(name().size() > nam.size())
178  {
179  return false;
180  }
181  else // name.size() < nam.size()
182  {
183  std::string constr = name().front() == '.' ? name() : "." + name();
184  // constr is suffix of nam
185  return constr == nam.substr(nam.size() - constr.size(), constr.size());
186  }
187  }
188 
189 bool GeneralName::matches_dn(const std::string& nam) const
190  {
191  std::stringstream ss(nam);
192  std::stringstream tt(name());
193  X509_DN nam_dn, my_dn;
194 
195  ss >> nam_dn;
196  tt >> my_dn;
197 
198  auto attr = nam_dn.get_attributes();
199  bool ret = true;
200  size_t trys = 0;
201 
202  for(const std::pair<OID,std::string>& c: my_dn.get_attributes())
203  {
204  auto i = attr.equal_range(c.first);
205 
206  if(i.first != i.second)
207  {
208  trys += 1;
209  ret = ret && (i.first->second == c.second);
210  }
211  }
212 
213  return trys > 0 && ret;
214  }
215 
216 bool GeneralName::matches_ip(const std::string& nam) const
217  {
218  uint32_t ip = string_to_ipv4(nam);
219  std::vector<std::string> p = split_on(name(), '/');
220 
221  if(p.size() != 2)
222  throw Decoding_Error("failed to parse IPv4 address");
223 
224  uint32_t net = string_to_ipv4(p.at(0));
225  uint32_t mask = string_to_ipv4(p.at(1));
226 
227  return (ip & mask) == net;
228  }
229 
230 std::ostream& operator<<(std::ostream& os, const GeneralName& gn)
231  {
232  os << gn.type() << ":" << gn.name();
233  return os;
234  }
235 
237  {
238  size_t p0, p1;
239  size_t min = std::stoull(str, &p0, 10);
240  size_t max = std::stoull(str.substr(p0 + 1), &p1, 10);
241  GeneralName gn(str.substr(p0 + p1 + 2));
242 
243  if(p0 > 0 && p1 > 0)
244  {
245  m_minimum = min;
246  m_maximum = max;
247  m_base = gn;
248  }
249  else
250  {
251  throw Invalid_Argument("Failed to decode Name Constraint");
252  }
253  }
254 
256  {
257  throw Not_Implemented("General Subtree encoding");
258  }
259 
261  {
262  ber.start_cons(SEQUENCE)
263  .decode(m_base)
264  .decode_optional(m_minimum,ASN1_Tag(0), CONTEXT_SPECIFIC,size_t(0))
265  .end_cons();
266 
267  if(m_minimum != 0)
268  throw Decoding_Error("GeneralSubtree minimum must be 0");
269 
270  m_maximum = std::numeric_limits<std::size_t>::max();
271  }
272 
273 std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs)
274  {
275  os << gs.minimum() << "," << gs.maximum() << "," << gs.base();
276  return os;
277  }
278 }
size_t maximum() const
void decode_from(BER_Decoder &) override
int operator<<(int fd, Pipe &pipe)
Definition: fd_unix.cpp:17
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:142
uint32_t load_be< uint32_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:177
const std::string & type() const
BER_Decoder & decode(bool &v)
Definition: ber_dec.cpp:355
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:108
ASN1_Tag
Definition: asn1_obj.h:22
GeneralName base() const
void decode_from(class BER_Decoder &) override
Definition: x509_dn.cpp:264
MatchResult matches(const X509_Certificate &cert) const
BER_Decoder & decode_optional(T &out, ASN1_Tag type_tag, ASN1_Tag class_tag, const T &default_value=T())
Definition: ber_dec.h:230
void encode_into(DER_Encoder &) const override
std::vector< std::string > get_attribute(const std::string &attr) const
Definition: x509_dn.cpp:113
const X509_DN & subject_dn() const
Definition: x509cert.cpp:415
secure_vector< uint8_t > value
Definition: asn1_obj.h:97
BER_Decoder & end_cons()
Definition: ber_dec.cpp:265
std::string ipv4_to_string(uint32_t ip)
Definition: parsing.cpp:292
std::vector< std::string > get_attribute(const std::string &attr) const
void encode_into(DER_Encoder &) const override
const std::string & name() const
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:251
Definition: alg_id.cpp:13
X.509 GeneralName Type.
uint32_t string_to_ipv4(const std::string &str)
Definition: parsing.cpp:267
A single Name Constraint.
void decode_from(BER_Decoder &) override
BER_Object get_next_object()
Definition: ber_dec.cpp:197
GeneralName()=default
ASN1_Tag class_tag
Definition: asn1_obj.h:94
size_t minimum() const
ASN1_Tag type_tag
Definition: asn1_obj.h:94
std::multimap< OID, std::string > get_attributes() const
Definition: x509_dn.cpp:67
const AlternativeName & subject_alt_name() const
Definition: x509cert.cpp:561