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>
25 throw Encoding_Error(
"Could not convert unknown NameType to string");
44 const size_t index = m_name.index();
46 if(index == RFC822_IDX) {
47 return std::get<RFC822_IDX>(m_name);
48 }
else if(index == DNS_IDX) {
49 return std::get<DNS_IDX>(m_name);
50 }
else if(index == URI_IDX) {
51 return std::get<URI_IDX>(m_name);
52 }
else if(index == DN_IDX) {
53 return std::get<DN_IDX>(m_name).to_string();
54 }
else if(index == IPV4_IDX) {
55 auto [net, mask] = std::get<IPV4_IDX>(m_name);
87 m_name.emplace<DN_IDX>(dn);
94 m_name.emplace<IPV4_IDX>(std::make_pair(net, mask));
95 }
else if(obj.
length() == 32) {
108 const auto& constraint = std::get<DNS_IDX>(m_name);
116 auto [net, mask] = std::get<IPV4_IDX>(m_name);
117 return (ip & mask) == net;
124 const X509_DN& constraint = std::get<DN_IDX>(m_name);
131 class MatchScore final {
133 MatchScore() : m_any(
false), m_some(
false), m_all(
true) {}
165 const auto& constraint = std::get<DNS_IDX>(m_name);
167 const auto& alt_names = alt_name.
dns();
169 for(
const std::string& dns : alt_names) {
173 if(alt_name.
count() == 0) {
182 const X509_DN& constraint = std::get<DN_IDX>(m_name);
189 auto [net, mask] = std::get<IPV4_IDX>(m_name);
191 if(alt_name.
count() == 0) {
195 bool match = (ipv4.value() & mask) == net;
201 bool match = (ipv4 & mask) == net;
210 return score.result();
216 if(
name.size() == constraint.size()) {
217 return name == constraint;
218 }
else if(constraint.size() >
name.size()) {
224 if(constraint.empty()) {
228 std::string_view substr =
name.substr(
name.size() - constraint.size(), constraint.size());
230 if(constraint.front() ==
'.') {
231 return substr == constraint;
232 }
else if(substr[0] ==
'.') {
233 return substr.substr(1) == constraint;
235 return substr == constraint &&
name[
name.size() - constraint.size() - 1] ==
'.';
242 const auto attr =
name.get_attributes();
246 for(
const auto& c : constraint.dn_info()) {
247 auto i = attr.equal_range(c.first);
249 if(i.first != i.second) {
251 ret = ret && (i.first->second == c.second.value());
255 return tries > 0 && ret;
259 os << gn.
type() <<
":" << gn.
name();
288 std::vector<GeneralSubtree>&& excluded_subtrees) :
289 m_permitted_subtrees(std::move(permitted_subtrees)), m_excluded_subtrees(std::move(excluded_subtrees)) {
290 for(
const auto& c : m_permitted_subtrees) {
291 m_permitted_name_types.insert(c.base().type_code());
293 for(
const auto& c : m_excluded_subtrees) {
294 m_excluded_name_types.insert(c.base().type_code());
300bool exceeds_limit(
size_t dn_count,
size_t alt_count,
size_t constraint_count) {
305 constexpr size_t MAX_NC_CHECKS = (1 << 20);
307 if(
auto names =
checked_add(dn_count, alt_count)) {
308 if(
auto product =
checked_mul(*names, constraint_count)) {
309 if(*product < MAX_NC_CHECKS) {
342 auto is_permitted_dn = [&](
const X509_DN& dn) {
348 for(
const auto& c : m_permitted_subtrees) {
349 if(c.base().matches_dn(dn)) {
358 auto is_permitted_dns_name = [&](
const std::string& name) {
359 if(name.empty() || name.starts_with(
".")) {
368 for(
const auto& c : m_permitted_subtrees) {
369 if(c.base().matches_dns(name)) {
378 auto is_permitted_ipv4 = [&](uint32_t ipv4) {
384 for(
const auto& c : m_permitted_subtrees) {
385 if(c.base().matches_ipv4(ipv4)) {
398 for(
const auto& alt_dn : alt_name.directory_names()) {
399 if(!is_permitted_dn(alt_dn)) {
404 for(
const auto& alt_dns : alt_name.dns()) {
405 if(!is_permitted_dns_name(alt_dns)) {
410 for(
const auto& alt_ipv4 : alt_name.ipv4_address()) {
411 if(!is_permitted_ipv4(alt_ipv4)) {
416 if(alt_name.count() == 0) {
418 if(cn.find(
".") != std::string::npos) {
420 if(!is_permitted_ipv4(ipv4.value())) {
424 if(!is_permitted_dns_name(cn)) {
461 auto is_excluded_dn = [&](
const X509_DN& dn) {
467 for(
const auto& c : m_excluded_subtrees) {
468 if(c.base().matches_dn(dn)) {
477 auto is_excluded_dns_name = [&](
const std::string& name) {
478 if(name.empty() || name.starts_with(
".")) {
487 for(
const auto& c : m_excluded_subtrees) {
488 if(c.base().matches_dns(name)) {
497 auto is_excluded_ipv4 = [&](uint32_t ipv4) {
503 for(
const auto& c : m_excluded_subtrees) {
504 if(c.base().matches_ipv4(ipv4)) {
517 for(
const auto& alt_dn : alt_name.directory_names()) {
518 if(is_excluded_dn(alt_dn)) {
523 for(
const auto& alt_dns : alt_name.dns()) {
524 if(is_excluded_dns_name(alt_dns)) {
529 for(
const auto& alt_ipv4 : alt_name.ipv4_address()) {
530 if(is_excluded_ipv4(alt_ipv4)) {
535 if(alt_name.count() == 0) {
537 if(cn.find(
".") != std::string::npos) {
539 if(is_excluded_ipv4(ipv4.value())) {
543 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 decode_from(BER_Decoder &from) override
void encode_into(DER_Encoder &to) 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
A single Name Constraint.
void encode_into(DER_Encoder &to) const override
const GeneralName & base() const
void decode_from(BER_Decoder &from) override
NameConstraints()=default
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
std::vector< std::string > get_attribute(std::string_view attr) const
void decode_from(BER_Decoder &from) override
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)