Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/x509/asn1_alt_name.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* AlternativeName
3
* (C) 1999-2007 Jack Lloyd
4
*     2007 Yves Jerschow
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/pkix_types.h>
10
11
#include <botan/internal/fmt.h>
12
#include <botan/internal/parsing.h>
13
#include <sstream>
14
15
namespace Botan {
16
17
/*
18
* Create an AlternativeName
19
*/
20
AlternativeName::AlternativeName(std::string_view email_addr,
21
                                 std::string_view uri,
22
                                 std::string_view dns,
23
0
                                 std::string_view ip) {
24
0
   if(!email_addr.empty()) {
25
0
      add_email(email_addr);
26
0
   }
27
0
   if(!dns.empty()) {
28
0
      add_dns(dns);
29
0
   }
30
0
   if(!uri.empty()) {
31
0
      add_uri(uri);
32
0
   }
33
0
   if(!ip.empty()) {
34
0
      if(auto ipv4 = string_to_ipv4(ip)) {
35
0
         add_ipv4_address(*ipv4);
36
0
      } else {
37
0
         throw Invalid_Argument(fmt("Invalid IPv4 address '{}'", ip));
38
0
      }
39
0
   }
40
0
}
41
42
/*
43
* Add an attribute to an alternative name
44
*/
45
0
void AlternativeName::add_attribute(std::string_view type, std::string_view value) {
46
0
   if(type.empty() || value.empty()) {
47
0
      return;
48
0
   }
49
50
0
   if(type == "DNS") {
51
0
      this->add_dns(value);
52
0
   } else if(type == "RFC822") {
53
0
      this->add_email(value);
54
0
   } else if(type == "URI") {
55
0
      this->add_uri(value);
56
0
   } else if(type == "DN") {
57
0
      X509_DN dn;
58
0
      std::istringstream ss{std::string(value)};
59
0
      ss >> dn;
60
0
      this->add_dn(dn);
61
0
   } else if(type == "IP") {
62
0
      if(auto ipv4 = string_to_ipv4(value)) {
63
0
         add_ipv4_address(*ipv4);
64
0
      } else {
65
0
         throw Invalid_Argument(fmt("Invalid IPv4 address '{}'", value));
66
0
      }
67
0
   } else {
68
0
      throw Not_Implemented(fmt("Unknown AlternativeName name type {}", type));
69
0
   }
70
0
}
71
72
/*
73
* Add an OtherName field
74
*/
75
6.50k
void AlternativeName::add_othername(const OID& oid, std::string_view value, ASN1_Type type) {
76
6.50k
   if(value.empty()) {
77
152
      return;
78
152
   }
79
6.35k
   this->add_other_name(oid, ASN1_String(value, type));
80
6.35k
}
81
82
/*
83
* Return all of the alternative names
84
*/
85
3.75k
std::multimap<std::string, std::string> AlternativeName::contents() const {
86
3.75k
   std::multimap<std::string, std::string> names;
87
88
3.75k
   for(const auto& nm : this->dns()) {
89
970
      names.emplace("DNS", nm);
90
970
   }
91
92
4.89k
   for(const auto& nm : this->email()) {
93
4.89k
      names.emplace("RFC822", nm);
94
4.89k
   }
95
96
3.75k
   for(const auto& nm : this->uris()) {
97
3.08k
      names.emplace("URI", nm);
98
3.08k
   }
99
100
3.75k
   for(uint32_t ipv4 : this->ipv4_address()) {
101
2.30k
      names.emplace("IP", ipv4_to_string(ipv4));
102
2.30k
   }
103
104
3.75k
   for(const auto& nm : this->directory_names()) {
105
2.02k
      names.emplace("DN", nm.to_string());
106
2.02k
   }
107
108
3.75k
   for(const auto& othername : this->other_names()) {
109
2.53k
      names.emplace(othername.first.to_formatted_string(), othername.second.value());
110
2.53k
   }
111
112
3.75k
   return names;
113
3.75k
}
114
115
0
std::multimap<std::string, std::string, std::less<>> AlternativeName::get_attributes() const {
116
0
   std::multimap<std::string, std::string, std::less<>> r;
117
118
0
   for(const auto& c : this->contents()) {
119
0
      r.emplace(c.first, c.second);
120
0
   }
121
122
0
   return r;
123
0
}
124
125
0
bool AlternativeName::has_field(std::string_view attr) const {
126
0
   return !this->get_attribute(attr).empty();
127
0
}
128
129
0
std::string AlternativeName::get_first_attribute(std::string_view type) const {
130
0
   auto attr = this->get_attribute(type);
131
132
0
   if(!attr.empty()) {
133
0
      return attr[0];
134
0
   }
135
136
0
   return "";
137
0
}
138
139
3
std::vector<std::string> AlternativeName::get_attribute(std::string_view attr) const {
140
3
   auto set_to_vector = [](const std::set<std::string>& s) -> std::vector<std::string> { return {s.begin(), s.end()}; };
141
142
3
   if(attr == "DNS") {
143
0
      return set_to_vector(this->dns());
144
3
   } else if(attr == "RFC822") {
145
0
      return set_to_vector(this->email());
146
3
   } else if(attr == "URI") {
147
0
      return set_to_vector(this->uris());
148
3
   } else if(attr == "DN") {
149
0
      std::vector<std::string> ret;
150
151
0
      for(const auto& nm : this->directory_names()) {
152
0
         ret.push_back(nm.to_string());
153
0
      }
154
155
0
      return ret;
156
3
   } else if(attr == "IP") {
157
0
      std::vector<std::string> ip_str;
158
0
      for(uint32_t ipv4 : this->ipv4_address()) {
159
0
         ip_str.push_back(ipv4_to_string(ipv4));
160
0
      }
161
0
      return ip_str;
162
3
   } else {
163
3
      return {};
164
3
   }
165
3
}
166
167
0
X509_DN AlternativeName::dn() const {
168
   // This logic really does not make any sense, but it is
169
   // how this function was historically implemented.
170
171
0
   X509_DN combined_dn;
172
173
0
   for(const auto& dn : this->directory_names()) {
174
0
      std::ostringstream oss;
175
0
      oss << dn;
176
177
0
      std::istringstream iss(oss.str());
178
0
      iss >> combined_dn;
179
0
   }
180
181
0
   return combined_dn;
182
0
}
183
184
/*
185
* Return if this object has anything useful
186
*/
187
}  // namespace Botan