9#include <botan/pkix_types.h>
11#include <botan/ber_dec.h>
12#include <botan/x509cert.h>
13#include <botan/internal/fmt.h>
14#include <botan/internal/int_utils.h>
15#include <botan/internal/loadstor.h>
16#include <botan/internal/parsing.h>
27 throw Encoding_Error(
"Could not convert unknown NameType to string");
46 const size_t index = m_name.index();
48 if(index == RFC822_IDX) {
49 return std::get<RFC822_IDX>(m_name);
50 }
else if(index == DNS_IDX) {
51 return std::get<DNS_IDX>(m_name);
52 }
else if(index == URI_IDX) {
53 return std::get<URI_IDX>(m_name);
54 }
else if(index == DN_IDX) {
55 return std::get<DN_IDX>(m_name).to_string();
56 }
else if(index == IPV4_IDX) {
57 auto [net, mask] = std::get<IPV4_IDX>(m_name);
89 m_name.emplace<DN_IDX>(dn);
96 m_name.emplace<IPV4_IDX>(std::make_pair(net, mask));
97 }
else if(obj.
length() == 32) {
110 const auto& constraint = std::get<DNS_IDX>(m_name);
118 auto [net, mask] = std::get<IPV4_IDX>(m_name);
119 return (ip & mask) == net;
126 const X509_DN& constraint = std::get<DN_IDX>(m_name);
133 class MatchScore
final {
135 MatchScore() : m_any(
false), m_some(
false), m_all(
true) {}
145 return MatchResult::NotFound;
147 return MatchResult::All;
149 return MatchResult::Some;
151 return MatchResult::None;
167 const auto& constraint = std::get<DNS_IDX>(m_name);
169 const auto& alt_names = alt_name.
dns();
171 for(
const std::string& dns : alt_names) {
175 if(alt_name.
count() == 0) {
184 const X509_DN& constraint = std::get<DN_IDX>(m_name);
191 auto [net, mask] = std::get<IPV4_IDX>(m_name);
193 if(alt_name.
count() == 0) {
197 bool match = (ipv4.value() & mask) == net;
203 bool match = (ipv4 & mask) == net;
212 return score.result();
218 if(
name.size() == constraint.size()) {
219 return name == constraint;
220 }
else if(constraint.size() >
name.size()) {
226 if(constraint.empty()) {
230 std::string_view substr =
name.substr(
name.size() - constraint.size(), constraint.size());
232 if(constraint.front() ==
'.') {
233 return substr == constraint;
234 }
else if(substr[0] ==
'.') {
235 return substr.substr(1) == constraint;
237 return substr == constraint &&
name[
name.size() - constraint.size() - 1] ==
'.';
244 const auto attr =
name.get_attributes();
248 for(
const auto& c : constraint.dn_info()) {
249 auto i = attr.equal_range(c.first);
251 if(i.first != i.second) {
253 ret = ret && (i.first->second == c.second.value());
257 return trys > 0 && ret;
261 os << gn.
type() <<
":" << gn.
name();
290 std::vector<GeneralSubtree>&& excluded_subtrees) :
291 m_permitted_subtrees(std::move(permitted_subtrees)), m_excluded_subtrees(std::move(excluded_subtrees)) {
292 for(
const auto& c : m_permitted_subtrees) {
293 m_permitted_name_types.insert(c.base().type_code());
295 for(
const auto& c : m_excluded_subtrees) {
296 m_excluded_name_types.insert(c.base().type_code());
302bool exceeds_limit(
size_t dn_count,
size_t alt_count,
size_t constraint_count) {
307 constexpr size_t MAX_NC_CHECKS = (1 << 20);
309 if(
auto names =
checked_add(dn_count, alt_count)) {
310 if(
auto product =
checked_mul(*names, constraint_count)) {
311 if(*product < MAX_NC_CHECKS) {
344 auto is_permitted_dn = [&](
const X509_DN& dn) {
350 for(
const auto& c : m_permitted_subtrees) {
351 if(c.base().matches_dn(dn)) {
360 auto is_permitted_dns_name = [&](
const std::string&
name) {
361 if(
name.empty() ||
name.starts_with(
".")) {
370 for(
const auto& c : m_permitted_subtrees) {
371 if(c.base().matches_dns(
name)) {
380 auto is_permitted_ipv4 = [&](uint32_t ipv4) {
386 for(
const auto& c : m_permitted_subtrees) {
387 if(c.base().matches_ipv4(ipv4)) {
400 for(
const auto& alt_dn : alt_name.directory_names()) {
401 if(!is_permitted_dn(alt_dn)) {
406 for(
const auto& alt_dns : alt_name.dns()) {
407 if(!is_permitted_dns_name(alt_dns)) {
412 for(
const auto& alt_ipv4 : alt_name.ipv4_address()) {
413 if(!is_permitted_ipv4(alt_ipv4)) {
418 if(alt_name.count() == 0) {
420 if(cn.find(
".") != std::string::npos) {
422 if(!is_permitted_ipv4(ipv4.value())) {
426 if(!is_permitted_dns_name(cn)) {
463 auto is_excluded_dn = [&](
const X509_DN& dn) {
469 for(
const auto& c : m_excluded_subtrees) {
470 if(c.base().matches_dn(dn)) {
479 auto is_excluded_dns_name = [&](
const std::string&
name) {
480 if(
name.empty() ||
name.starts_with(
".")) {
489 for(
const auto& c : m_excluded_subtrees) {
490 if(c.base().matches_dns(
name)) {
499 auto is_excluded_ipv4 = [&](uint32_t ipv4) {
505 for(
const auto& c : m_excluded_subtrees) {
506 if(c.base().matches_ipv4(ipv4)) {
519 for(
const auto& alt_dn : alt_name.directory_names()) {
520 if(is_excluded_dn(alt_dn)) {
525 for(
const auto& alt_dns : alt_name.dns()) {
526 if(is_excluded_dns_name(alt_dns)) {
531 for(
const auto& alt_ipv4 : alt_name.ipv4_address()) {
532 if(is_excluded_ipv4(alt_ipv4)) {
537 if(alt_name.count() == 0) {
539 if(cn.find(
".") != std::string::npos) {
541 if(is_excluded_ipv4(ipv4.value())) {
545 if(is_excluded_dns_name(cn)) {
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ASSERT_UNREACHABLE()
const std::set< X509_DN > & directory_names() const
Return the set of directory names included in this alternative name.
const std::set< uint32_t > & ipv4_address() const
Return the set of IPv4 addresses included in this alternative name.
const std::set< std::string > & dns() const
Return the set of DNS names included in this alternative name.
BER_Object get_next_object()
BER_Decoder & decode(bool &out)
BER_Decoder start_sequence()
BER_Decoder & decode_optional(T &out, ASN1_Type type_tag, ASN1_Class class_tag, const T &default_value=T())
const uint8_t * bits() const
bool is_a(ASN1_Type type_tag, ASN1_Class class_tag) const
void encode_into(DER_Encoder &) const override
MatchResult matches(const X509_Certificate &cert) const
bool matches_dn(const X509_DN &dn) const
bool matches_dns(const std::string &dns_name) const
bool matches_ipv4(uint32_t ip) const
void decode_from(BER_Decoder &) override
A single Name Constraint.
void decode_from(BER_Decoder &) override
const GeneralName & base() const
void encode_into(DER_Encoder &) const override
bool is_permitted(const X509_Certificate &cert, bool reject_unknown) const
bool is_excluded(const X509_Certificate &cert, bool reject_unknown) const
const std::vector< GeneralSubtree > & permitted() const
const std::vector< GeneralSubtree > & excluded() const
const X509_DN & subject_dn() const
std::vector< std::string > subject_info(std::string_view name) const
const AlternativeName & subject_alt_name() const
void decode_from(BER_Decoder &) override
std::vector< std::string > get_attribute(std::string_view attr) const
int(* final)(unsigned char *, CTX *)
std::string to_string(const BER_Object &obj)
constexpr std::optional< T > checked_add(T a, T b)
@ ExplicitContextSpecific
std::string fmt(std::string_view format, const T &... args)
std::string tolower_string(std::string_view in)
std::ostream & operator<<(std::ostream &out, const OID &oid)
constexpr std::optional< T > checked_mul(T a, T b)
std::optional< uint32_t > string_to_ipv4(std::string_view str)
std::string ipv4_to_string(uint32_t ip)
constexpr auto load_be(ParamTs &&... params)