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