Botan 3.3.0
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
10#include <botan/ber_dec.h>
11#include <botan/x509cert.h>
12#include <botan/internal/loadstor.h>
13#include <botan/internal/parsing.h>
14#include <functional>
15#include <sstream>
16
17namespace Botan {
18
19class DER_Encoder;
20
21GeneralName::GeneralName(const std::string& str) : GeneralName() {
22 size_t p = str.find(':');
23
24 if(p != std::string::npos) {
25 m_type = str.substr(0, p);
26 m_name = str.substr(p + 1, std::string::npos);
27 } else {
28 throw Invalid_Argument("Failed to decode Name Constraint");
29 }
30}
31
33 throw Not_Implemented("GeneralName encoding");
34}
35
37 BER_Object obj = ber.get_next_object();
38
40 m_type = "RFC822";
41 m_name = ASN1::to_string(obj);
42 } else if(obj.is_a(2, ASN1_Class::ContextSpecific)) {
43 m_type = "DNS";
44 m_name = ASN1::to_string(obj);
45 } else if(obj.is_a(6, ASN1_Class::ContextSpecific)) {
46 m_type = "URI";
47 m_name = ASN1::to_string(obj);
49 m_type = "DN";
50 X509_DN dn;
51 BER_Decoder dec(obj);
52 std::stringstream ss;
53
54 dn.decode_from(dec);
55 ss << dn;
56
57 m_name = ss.str();
58 } else if(obj.is_a(7, ASN1_Class::ContextSpecific)) {
59 if(obj.length() == 8) {
60 m_type = "IP";
61 m_name =
62 ipv4_to_string(load_be<uint32_t>(obj.bits(), 0)) + "/" + ipv4_to_string(load_be<uint32_t>(obj.bits(), 1));
63 } else if(obj.length() == 32) {
64 throw Decoding_Error("Unsupported IPv6 name constraint");
65 } else {
66 throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length()));
67 }
68 } else {
69 throw Decoding_Error("Found unknown GeneralName type");
70 }
71}
72
74 std::vector<std::string> nam;
75 std::function<bool(const GeneralName*, const std::string&)> match_fn;
76
77 const X509_DN& dn = cert.subject_dn();
78 const AlternativeName& alt_name = cert.subject_alt_name();
79
80 if(type() == "DNS") {
81 match_fn = std::mem_fn(&GeneralName::matches_dns);
82
83 nam = alt_name.get_attribute("DNS");
84
85 if(nam.empty()) {
86 nam = dn.get_attribute("CN");
87 }
88 } else if(type() == "DN") {
89 match_fn = std::mem_fn(&GeneralName::matches_dn);
90
91 nam.push_back(dn.to_string());
92
93 const auto alt_dn = alt_name.dn();
94 if(alt_dn.empty() == false) {
95 nam.push_back(alt_dn.to_string());
96 }
97 } else if(type() == "IP") {
98 match_fn = std::mem_fn(&GeneralName::matches_ip);
99 nam = alt_name.get_attribute("IP");
100 } else {
102 }
103
104 if(nam.empty()) {
106 }
107
108 bool some = false;
109 bool all = true;
110
111 for(const std::string& n : nam) {
112 bool m = match_fn(this, n);
113
114 some |= m;
115 all &= m;
116 }
117
118 if(all) {
119 return MatchResult::All;
120 } else if(some) {
121 return MatchResult::Some;
122 } else {
123 return MatchResult::None;
124 }
125}
126
127bool GeneralName::matches_dns(const std::string& nam) const {
128 if(nam.size() == name().size()) {
129 return tolower_string(nam) == tolower_string(name());
130 } else if(name().size() > nam.size()) {
131 // The constraint is longer than the issued name: not possibly a match
132 return false;
133 } else // name.size() < nam.size()
134 {
135 // constr is suffix of nam
136 const std::string constr = name().front() == '.' ? name() : "." + name();
137 const std::string substr = nam.substr(nam.size() - constr.size(), constr.size());
138 return tolower_string(constr) == tolower_string(substr);
139 }
140}
141
142bool GeneralName::matches_dn(const std::string& nam) const {
143 std::stringstream ss(nam);
144 std::stringstream tt(name());
145 X509_DN nam_dn, my_dn;
146
147 ss >> nam_dn;
148 tt >> my_dn;
149
150 auto attr = nam_dn.get_attributes();
151 bool ret = true;
152 size_t trys = 0;
153
154 for(const auto& c : my_dn.dn_info()) {
155 auto i = attr.equal_range(c.first);
156
157 if(i.first != i.second) {
158 trys += 1;
159 ret = ret && (i.first->second == c.second.value());
160 }
161 }
162
163 return trys > 0 && ret;
164}
165
166bool GeneralName::matches_ip(const std::string& nam) const {
167 uint32_t ip = string_to_ipv4(nam);
168 std::vector<std::string> p = split_on(name(), '/');
169
170 if(p.size() != 2) {
171 throw Decoding_Error("failed to parse IPv4 address");
172 }
173
174 uint32_t net = string_to_ipv4(p.at(0));
175 uint32_t mask = string_to_ipv4(p.at(1));
176
177 return (ip & mask) == net;
178}
179
180std::ostream& operator<<(std::ostream& os, const GeneralName& gn) {
181 os << gn.type() << ":" << gn.name();
182 return os;
183}
184
186 size_t p0, p1;
187 const auto min = std::stoull(str, &p0, 10);
188 const auto max = std::stoull(str.substr(p0 + 1), &p1, 10);
189 GeneralName gn(str.substr(p0 + p1 + 2));
190
191 if(p0 > 0 && p1 > 0) {
192 m_minimum = static_cast<size_t>(min);
193 m_maximum = static_cast<size_t>(max);
194 m_base = gn;
195 } else {
196 throw Invalid_Argument("Failed to decode Name Constraint");
197 }
198}
199
201 throw Not_Implemented("General Subtree encoding");
202}
203
205 ber.start_sequence()
206 .decode(m_base)
207 .decode_optional(m_minimum, ASN1_Type(0), ASN1_Class::ContextSpecific, size_t(0))
208 .end_cons();
209
210 if(m_minimum != 0) {
211 throw Decoding_Error("GeneralSubtree minimum must be 0");
212 }
213
214 m_maximum = std::numeric_limits<std::size_t>::max();
215}
216
217std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs) {
218 os << gs.minimum() << "," << gs.maximum() << "," << gs.base();
219 return os;
220}
221} // namespace Botan
std::vector< std::string > get_attribute(std::string_view attr) const
BER_Object get_next_object()
Definition ber_dec.cpp:231
BER_Decoder & decode(bool &out)
Definition ber_dec.h:176
BER_Decoder & end_cons()
Definition ber_dec.cpp:295
BER_Decoder start_sequence()
Definition ber_dec.h:113
BER_Decoder & decode_optional(T &out, ASN1_Type type_tag, ASN1_Class class_tag, const T &default_value=T())
Definition ber_dec.h:317
size_t length() const
Definition asn1_obj.h:152
const uint8_t * bits() const
Definition asn1_obj.h:150
bool is_a(ASN1_Type type_tag, ASN1_Class class_tag) const
Definition asn1_obj.cpp:61
X.509 GeneralName Type.
Definition pkix_types.h:181
GeneralName()=default
const std::string & type() const
Definition pkix_types.h:209
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:214
A single Name Constraint.
Definition pkix_types.h:241
void decode_from(BER_Decoder &) override
size_t maximum() const
Definition pkix_types.h:279
size_t minimum() const
Definition pkix_types.h:274
const GeneralName & base() const
Definition pkix_types.h:269
void encode_into(DER_Encoder &) const override
const X509_DN & subject_dn() const
Definition x509cert.cpp:362
const AlternativeName & subject_alt_name() const
Definition x509cert.cpp:501
void decode_from(BER_Decoder &) override
Definition x509_dn.cpp:347
std::vector< std::string > get_attribute(std::string_view attr) const
Definition x509_dn.cpp:172
std::string to_string() const
Definition x509_dn.cpp:402
std::string to_string(const BER_Object &obj)
Definition asn1_obj.cpp:185
uint32_t string_to_ipv4(std::string_view str)
Definition parsing.cpp:156
ASN1_Type
Definition asn1_obj.h:43
std::vector< std::string > split_on(std::string_view str, char delim)
Definition parsing.cpp:111
std::string tolower_string(std::string_view in)
Definition parsing.cpp:196
std::ostream & operator<<(std::ostream &out, const OID &oid)
Definition asn1_oid.cpp:140
std::string ipv4_to_string(uint32_t ip)
Definition parsing.cpp:181