Botan 2.17.3
Crypto and TLS for C&
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
15namespace Botan {
16
17class DER_Encoder;
18
19GeneralName::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
164bool GeneralName::matches_dns(const std::string& nam) const
165 {
166 if(nam.size() == name().size())
167 {
168 return nam == name();
169 }
170 else if(name().size() > nam.size())
171 {
172 return false;
173 }
174 else // name.size() < nam.size()
175 {
176 std::string constr = name().front() == '.' ? name() : "." + name();
177 // constr is suffix of nam
178 return constr == nam.substr(nam.size() - constr.size(), constr.size());
179 }
180 }
181
182bool GeneralName::matches_dn(const std::string& nam) const
183 {
184 std::stringstream ss(nam);
185 std::stringstream tt(name());
186 X509_DN nam_dn, my_dn;
187
188 ss >> nam_dn;
189 tt >> my_dn;
190
191 auto attr = nam_dn.get_attributes();
192 bool ret = true;
193 size_t trys = 0;
194
195 for(const auto& c: my_dn.dn_info())
196 {
197 auto i = attr.equal_range(c.first);
198
199 if(i.first != i.second)
200 {
201 trys += 1;
202 ret = ret && (i.first->second == c.second.value());
203 }
204 }
205
206 return trys > 0 && ret;
207 }
208
209bool GeneralName::matches_ip(const std::string& nam) const
210 {
211 uint32_t ip = string_to_ipv4(nam);
212 std::vector<std::string> p = split_on(name(), '/');
213
214 if(p.size() != 2)
215 throw Decoding_Error("failed to parse IPv4 address");
216
217 uint32_t net = string_to_ipv4(p.at(0));
218 uint32_t mask = string_to_ipv4(p.at(1));
219
220 return (ip & mask) == net;
221 }
222
223std::ostream& operator<<(std::ostream& os, const GeneralName& gn)
224 {
225 os << gn.type() << ":" << gn.name();
226 return os;
227 }
228
230 {
231 size_t p0, p1;
232 const auto min = std::stoull(str, &p0, 10);
233 const auto max = std::stoull(str.substr(p0 + 1), &p1, 10);
234 GeneralName gn(str.substr(p0 + p1 + 2));
235
236 if(p0 > 0 && p1 > 0)
237 {
238 m_minimum = static_cast<size_t>(min);
239 m_maximum = static_cast<size_t>(max);
240 m_base = gn;
241 }
242 else
243 {
244 throw Invalid_Argument("Failed to decode Name Constraint");
245 }
246 }
247
249 {
250 throw Not_Implemented("General Subtree encoding");
251 }
252
254 {
256 .decode(m_base)
257 .decode_optional(m_minimum,ASN1_Tag(0), CONTEXT_SPECIFIC,size_t(0))
258 .end_cons();
259
260 if(m_minimum != 0)
261 throw Decoding_Error("GeneralSubtree minimum must be 0");
262
263 m_maximum = std::numeric_limits<std::size_t>::max();
264 }
265
266std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs)
267 {
268 os << gs.minimum() << "," << gs.maximum() << "," << gs.base();
269 return os;
270 }
271}
std::vector< std::string > get_attribute(const std::string &attr) const
BER_Decoder start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: ber_dec.cpp:290
BER_Object get_next_object()
Definition: ber_dec.cpp:237
BER_Decoder & decode(bool &out)
Definition: ber_dec.h:170
BER_Decoder & decode_optional(T &out, ASN1_Tag type_tag, ASN1_Tag class_tag, const T &default_value=T())
Definition: ber_dec.h:337
BER_Decoder & end_cons()
Definition: ber_dec.cpp:300
size_t length() const
Definition: asn1_obj.h:121
const uint8_t * bits() const
Definition: asn1_obj.h:119
bool is_a(ASN1_Tag type_tag, ASN1_Tag class_tag) const
Definition: asn1_obj.cpp:71
X.509 GeneralName Type.
Definition: pkix_types.h:196
GeneralName()=default
const std::string & type() const
Definition: pkix_types.h:225
void encode_into(DER_Encoder &) const override
MatchResult matches(const X509_Certificate &cert) const
void decode_from(BER_Decoder &) override
const std::string & name() const
Definition: pkix_types.h:230
A single Name Constraint.
Definition: pkix_types.h:258
void decode_from(BER_Decoder &) override
size_t maximum() const
Definition: pkix_types.h:299
size_t minimum() const
Definition: pkix_types.h:294
const GeneralName & base() const
Definition: pkix_types.h:289
void encode_into(DER_Encoder &) const override
const X509_DN & subject_dn() const
Definition: x509cert.cpp:476
const AlternativeName & subject_alt_name() const
Definition: x509cert.cpp:631
void decode_from(BER_Decoder &) override
Definition: x509_dn.cpp:272
std::vector< std::string > get_attribute(const std::string &attr) const
Definition: x509_dn.cpp:109
std::string to_string() const
Definition: x509_dn.cpp:326
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Definition: alg_id.cpp:13
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:148
uint32_t string_to_ipv4(const std::string &str)
Definition: parsing.cpp:253
uint32_t load_be< uint32_t >(const uint8_t in[], size_t off)
Definition: loadstor.h:179
int operator<<(int fd, Pipe &pipe)
Definition: fd_unix.cpp:17
ASN1_Tag
Definition: asn1_obj.h:25
@ CONSTRUCTED
Definition: asn1_obj.h:30
@ SEQUENCE
Definition: asn1_obj.h:42
@ CONTEXT_SPECIFIC
Definition: asn1_obj.h:28
std::string ipv4_to_string(uint32_t ip)
Definition: parsing.cpp:278