• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.8
/src/lib/x509/name_constraint.cpp
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

17
namespace Botan {
18

19
class DER_Encoder;
20

21
GeneralName::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

32
void GeneralName::encode_into(DER_Encoder& /*to*/) const { throw Not_Implemented("GeneralName encoding"); }
×
33

34
void GeneralName::decode_from(BER_Decoder& ber) {
1,269✔
35
   BER_Object obj = ber.get_next_object();
1,269✔
36

37
   if(obj.is_a(1, ASN1_Class::ContextSpecific)) {
1,269✔
38
      m_type = "RFC822";
305✔
39
      m_name = ASN1::to_string(obj);
305✔
40
   } else if(obj.is_a(2, ASN1_Class::ContextSpecific)) {
964✔
41
      m_type = "DNS";
392✔
42
      m_name = ASN1::to_string(obj);
392✔
43
   } else if(obj.is_a(6, ASN1_Class::ContextSpecific)) {
572✔
44
      m_type = "URI";
44✔
45
      m_name = ASN1::to_string(obj);
44✔
46
   } else if(obj.is_a(4, ASN1_Class::ContextSpecific | ASN1_Class::Constructed)) {
528✔
47
      m_type = "DN";
333✔
48
      X509_DN dn;
333✔
49
      BER_Decoder dec(obj);
333✔
50
      std::stringstream ss;
333✔
51

52
      dn.decode_from(dec);
333✔
53
      ss << dn;
332✔
54

55
      m_name = ss.str();
332✔
56
   } else if(obj.is_a(7, ASN1_Class::ContextSpecific)) {
530✔
57
      if(obj.length() == 8) {
20✔
58
         m_type = "IP";
19✔
59
         m_name =
19✔
60
            ipv4_to_string(load_be<uint32_t>(obj.bits(), 0)) + "/" + ipv4_to_string(load_be<uint32_t>(obj.bits(), 1));
196✔
61
      } else if(obj.length() == 32) {
1✔
62
         throw Decoding_Error("Unsupported IPv6 name constraint");
×
63
      } else {
64
         throw Decoding_Error("Invalid IP name constraint size " + std::to_string(obj.length()));
2✔
65
      }
66
   } else {
67
      throw Decoding_Error("Found unknown GeneralName type");
175✔
68
   }
69
}
1,092✔
70

71
GeneralName::MatchResult GeneralName::matches(const X509_Certificate& cert) const {
133✔
72
   std::vector<std::string> nam;
133✔
73
   std::function<bool(const GeneralName*, const std::string&)> match_fn;
133✔
74

75
   const X509_DN& dn = cert.subject_dn();
133✔
76
   const AlternativeName& alt_name = cert.subject_alt_name();
133✔
77

78
   if(type() == "DNS") {
133✔
79
      match_fn = std::mem_fn(&GeneralName::matches_dns);
63✔
80

81
      nam = alt_name.get_attribute("DNS");
63✔
82

83
      if(nam.empty()) {
63✔
84
         nam = dn.get_attribute("CN");
×
85
      }
86
   } else if(type() == "DN") {
70✔
87
      match_fn = std::mem_fn(&GeneralName::matches_dn);
31✔
88

89
      nam.push_back(dn.to_string());
62✔
90

91
      const auto alt_dn = alt_name.dn();
31✔
92
      if(alt_dn.empty() == false) {
31✔
93
         nam.push_back(alt_dn.to_string());
2✔
94
      }
95
   } else if(type() == "IP") {
70✔
96
      match_fn = std::mem_fn(&GeneralName::matches_ip);
4✔
97
      nam = alt_name.get_attribute("IP");
4✔
98
   } else {
99
      return MatchResult::UnknownType;
100
   }
101

102
   if(nam.empty()) {
98✔
103
      return MatchResult::NotFound;
104
   }
105

106
   bool some = false;
107
   bool all = true;
108

109
   for(const std::string& n : nam) {
281✔
110
      bool m = match_fn(this, n);
183✔
111

112
      some |= m;
183✔
113
      all &= m;
183✔
114
   }
115

116
   if(all) {
98✔
117
      return MatchResult::All;
118
   } else if(some) {
78✔
119
      return MatchResult::Some;
120
   } else {
121
      return MatchResult::None;
77✔
122
   }
123
}
133✔
124

125
bool GeneralName::matches_dns(const std::string& nam) const {
147✔
126
   if(nam.size() == name().size()) {
147✔
127
      return tolower_string(nam) == tolower_string(name());
16✔
128
   } else if(name().size() > nam.size()) {
131✔
129
      // The constraint is longer than the issued name: not possibly a match
130
      return false;
131
   } else  // name.size() < nam.size()
132
   {
133
      // constr is suffix of nam
134
      const std::string constr = name().front() == '.' ? name() : "." + name();
121✔
135
      const std::string substr = nam.substr(nam.size() - constr.size(), constr.size());
121✔
136
      return tolower_string(constr) == tolower_string(substr);
171✔
137
   }
146✔
138
}
139

140
bool GeneralName::matches_dn(const std::string& nam) const {
32✔
141
   std::stringstream ss(nam);
32✔
142
   std::stringstream tt(name());
32✔
143
   X509_DN nam_dn, my_dn;
32✔
144

145
   ss >> nam_dn;
32✔
146
   tt >> my_dn;
32✔
147

148
   auto attr = nam_dn.get_attributes();
32✔
149
   bool ret = true;
32✔
150
   size_t trys = 0;
32✔
151

152
   for(const auto& c : my_dn.dn_info()) {
142✔
153
      auto i = attr.equal_range(c.first);
110✔
154

155
      if(i.first != i.second) {
110✔
156
         trys += 1;
110✔
157
         ret = ret && (i.first->second == c.second.value());
110✔
158
      }
159
   }
160

161
   return trys > 0 && ret;
64✔
162
}
32✔
163

164
bool GeneralName::matches_ip(const std::string& nam) const {
4✔
165
   uint32_t ip = string_to_ipv4(nam);
4✔
166
   std::vector<std::string> p = split_on(name(), '/');
4✔
167

168
   if(p.size() != 2)
4✔
169
      throw Decoding_Error("failed to parse IPv4 address");
×
170

171
   uint32_t net = string_to_ipv4(p.at(0));
4✔
172
   uint32_t mask = string_to_ipv4(p.at(1));
4✔
173

174
   return (ip & mask) == net;
4✔
175
}
4✔
176

177
std::ostream& operator<<(std::ostream& os, const GeneralName& gn) {
×
178
   os << gn.type() << ":" << gn.name();
×
179
   return os;
×
180
}
181

182
GeneralSubtree::GeneralSubtree(const std::string& str) : GeneralSubtree() {
×
183
   size_t p0, p1;
×
184
   const auto min = std::stoull(str, &p0, 10);
×
185
   const auto max = std::stoull(str.substr(p0 + 1), &p1, 10);
×
186
   GeneralName gn(str.substr(p0 + p1 + 2));
×
187

188
   if(p0 > 0 && p1 > 0) {
×
189
      m_minimum = static_cast<size_t>(min);
×
190
      m_maximum = static_cast<size_t>(max);
×
191
      m_base = gn;
×
192
   } else {
193
      throw Invalid_Argument("Failed to decode Name Constraint");
×
194
   }
195
}
×
196

197
void GeneralSubtree::encode_into(DER_Encoder& /*to*/) const { throw Not_Implemented("General Subtree encoding"); }
×
198

199
void GeneralSubtree::decode_from(BER_Decoder& ber) {
1,274✔
200
   ber.start_sequence()
1,274✔
201
      .decode(m_base)
1,269✔
202
      .decode_optional(m_minimum, ASN1_Type(0), ASN1_Class::ContextSpecific, size_t(0))
2,354✔
203
      .end_cons();
1,085✔
204

205
   if(m_minimum != 0)
1,074✔
206
      throw Decoding_Error("GeneralSubtree minimum must be 0");
1✔
207

208
   m_maximum = std::numeric_limits<std::size_t>::max();
1,073✔
209
}
1,073✔
210

211
std::ostream& operator<<(std::ostream& os, const GeneralSubtree& gs) {
×
212
   os << gs.minimum() << "," << gs.maximum() << "," << gs.base();
×
213
   return os;
×
214
}
215
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc