Botan  2.6.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 
45  if(obj.is_a(1, CONTEXT_SPECIFIC))
46  {
47  m_type = "RFC822";
48  m_name = ASN1::to_string(obj);
49  }
50  else if(obj.is_a(2, CONTEXT_SPECIFIC))
51  {
52  m_type = "DNS";
53  m_name = ASN1::to_string(obj);
54  }
55  else if(obj.is_a(6, CONTEXT_SPECIFIC))
56  {
57  m_type = "URI";
58  m_name = ASN1::to_string(obj);
59  }
60  else if(obj.is_a(4, ASN1_Tag(CONTEXT_SPECIFIC | CONSTRUCTED)))
61  {
62  m_type = "DN";
63  X509_DN dn;
64  BER_Decoder dec(obj);
65  std::stringstream ss;
66 
67  dn.decode_from(dec);
68  ss << dn;
69 
70  m_name = ss.str();
71  }
72  else if(obj.is_a(7, CONTEXT_SPECIFIC))
73  {
74  if(obj.length() == 8)
75  {
76  m_type = "IP";
77  m_name = ipv4_to_string(load_be<uint32_t>(obj.bits(), 0)) + "/" +
79  }
80  else if(obj.length() == 32)
81  {
82  throw Decoding_Error("Unsupported IPv6 name constraint");
83  }
84  else
85  {
86  throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length()));
87  }
88  }
89  else
90  {
91  throw Decoding_Error("Found unknown GeneralName type");
92  }
93  }
94 
96  {
97  std::vector<std::string> nam;
98  std::function<bool(const GeneralName*, const std::string&)> match_fn;
99 
100  const X509_DN& dn = cert.subject_dn();
101  const AlternativeName& alt_name = cert.subject_alt_name();
102 
103  if(type() == "DNS")
104  {
105  match_fn = std::mem_fn(&GeneralName::matches_dns);
106 
107  nam = alt_name.get_attribute("DNS");
108 
109  if(nam.empty())
110  {
111  nam = dn.get_attribute("CN");
112  }
113  }
114  else if(type() == "DN")
115  {
116  match_fn = std::mem_fn(&GeneralName::matches_dn);
117 
118  std::stringstream ss;
119  ss << dn;
120  nam.push_back(ss.str());
121  }
122  else if(type() == "IP")
123  {
124  match_fn = std::mem_fn(&GeneralName::matches_ip);
125  nam = alt_name.get_attribute("IP");
126  }
127  else
128  {
129  return MatchResult::UnknownType;
130  }
131 
132  if(nam.empty())
133  {
134  return MatchResult::NotFound;
135  }
136 
137  bool some = false;
138  bool all = true;
139 
140  for(const std::string& n: nam)
141  {
142  bool m = match_fn(this, n);
143 
144  some |= m;
145  all &= m;
146  }
147 
148  if(all)
149  {
150  return MatchResult::All;
151  }
152  else if(some)
153  {
154  return MatchResult::Some;
155  }
156  else
157  {
158  return MatchResult::None;
159  }
160  }
161 
162 bool GeneralName::matches_dns(const std::string& nam) const
163  {
164  if(nam.size() == name().size())
165  {
166  return nam == name();
167  }
168  else if(name().size() > nam.size())
169  {
170  return false;
171  }
172  else // name.size() < nam.size()
173  {
174  std::string constr = name().front() == '.' ? name() : "." + name();
175  // constr is suffix of nam
176  return constr == nam.substr(nam.size() - constr.size(), constr.size());
177  }
178  }
179 
180 bool GeneralName::matches_dn(const std::string& nam) const
181  {
182  std::stringstream ss(nam);
183  std::stringstream tt(name());
184  X509_DN nam_dn, my_dn;
185 
186  ss >> nam_dn;
187  tt >> my_dn;
188 
189  auto attr = nam_dn.get_attributes();
190  bool ret = true;
191  size_t trys = 0;
192 
193  for(const auto& c: my_dn.dn_info())
194  {
195  auto i = attr.equal_range(c.first);
196 
197  if(i.first != i.second)
198  {
199  trys += 1;
200  ret = ret && (i.first->second == c.second.value());
201  }
202  }
203 
204  return trys > 0 && ret;
205  }
206 
207 bool GeneralName::matches_ip(const std::string& nam) const
208  {
209  uint32_t ip = string_to_ipv4(nam);
210  std::vector<std::string> p = split_on(name(), '/');
211 
212  if(p.size() != 2)
213  throw Decoding_Error("failed to parse IPv4 address");
214 
215  uint32_t net = string_to_ipv4(p.at(0));
216  uint32_t mask = string_to_ipv4(p.at(1));
217 
218  return (ip & mask) == net;
219  }
220 
221 std::ostream& operator<<(std::ostream& os, const GeneralName& gn)
222  {
223  os << gn.type() << ":" << gn.name();
224  return os;
225  }
226 
228  {
229  size_t p0, p1;
230  size_t min = std::stoull(str, &p0, 10);
231  size_t max = std::stoull(str.substr(p0 + 1), &p1, 10);
232  GeneralName gn(str.substr(p0 + p1 + 2));
233 
234  if(p0 > 0 && p1 > 0)
235  {
236  m_minimum = min;
237  m_maximum = max;
238  m_base = gn;
239  }
240  else
241  {
242  throw Invalid_Argument("Failed to decode Name Constraint");
243  }
244  }
245 
247  {
248  throw Not_Implemented("General Subtree encoding");
249  }
250 
252  {
253  ber.start_cons(SEQUENCE)
254  .decode(m_base)
255  .decode_optional(m_minimum,ASN1_Tag(0), CONTEXT_SPECIFIC,size_t(0))
256  .end_cons();
257 
258  if(m_minimum != 0)
259  throw Decoding_Error("GeneralSubtree minimum must be 0");
260 
261  m_maximum = std::numeric_limits<std::size_t>::max();
262  }
263 
264 std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs)
265  {
266  os << gs.minimum() << "," << gs.maximum() << "," << gs.base();
267  return os;
268  }
269 }
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:144
bool is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const
Definition: asn1_obj.cpp:31
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:338
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:145
ASN1_Tag
Definition: asn1_obj.h:22
GeneralName base() const
void decode_from(class BER_Decoder &) override
Definition: x509_dn.cpp:233
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:232
void encode_into(DER_Encoder &) const override
std::vector< std::string > get_attribute(const std::string &attr) const
Definition: x509_dn.cpp:108
const X509_DN & subject_dn() const
Definition: x509cert.cpp:429
BER_Decoder & end_cons()
Definition: ber_dec.cpp:253
std::string ipv4_to_string(uint32_t ip)
Definition: parsing.cpp:294
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:239
size_t length() const
Definition: asn1_obj.h:102
Definition: alg_id.cpp:13
X.509 GeneralName Type.
uint32_t string_to_ipv4(const std::string &str)
Definition: parsing.cpp:269
A single Name Constraint.
void decode_from(BER_Decoder &) override
BER_Object get_next_object()
Definition: ber_dec.cpp:184
const uint8_t * bits() const
Definition: asn1_obj.h:100
GeneralName()=default
size_t minimum() const
const AlternativeName & subject_alt_name() const
Definition: x509cert.cpp:575