/src/boringssl/pki/parse_name.cc
Line | Count | Source |
1 | | // Copyright 2016 The Chromium Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include "parse_name.h" |
16 | | |
17 | | #include <cassert> |
18 | | |
19 | | #include <openssl/bytestring.h> |
20 | | #include <openssl/mem.h> |
21 | | |
22 | | #include "parse_values.h" |
23 | | #include "string_util.h" |
24 | | |
25 | | BSSL_NAMESPACE_BEGIN |
26 | | |
27 | | namespace { |
28 | | |
29 | | // Returns a string containing the dotted numeric form of |oid|, or an empty |
30 | | // string on error. |
31 | 0 | std::string OidToString(der::Input oid) { |
32 | 0 | CBS cbs; |
33 | 0 | CBS_init(&cbs, oid.data(), oid.size()); |
34 | 0 | bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs)); |
35 | 0 | if (!text) { |
36 | 0 | return std::string(); |
37 | 0 | } |
38 | 0 | return text.get(); |
39 | 0 | } |
40 | | |
41 | | } // namespace |
42 | | |
43 | 0 | bool X509NameAttribute::ValueAsString(std::string *out) const { |
44 | 0 | switch (value_tag) { |
45 | 0 | case CBS_ASN1_T61STRING: |
46 | 0 | return der::ParseTeletexStringAsLatin1(value, out); |
47 | 0 | case CBS_ASN1_IA5STRING: |
48 | 0 | return der::ParseIA5String(value, out); |
49 | 0 | case CBS_ASN1_PRINTABLESTRING: |
50 | 0 | return der::ParsePrintableString(value, out); |
51 | 0 | case CBS_ASN1_UTF8STRING: |
52 | 0 | *out = BytesAsStringView(value); |
53 | 0 | return true; |
54 | 0 | case CBS_ASN1_UNIVERSALSTRING: |
55 | 0 | return der::ParseUniversalString(value, out); |
56 | 0 | case CBS_ASN1_BMPSTRING: |
57 | 0 | return der::ParseBmpString(value, out); |
58 | 0 | default: |
59 | 0 | return false; |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | bool X509NameAttribute::ValueAsStringWithUnsafeOptions( |
64 | 0 | PrintableStringHandling printable_string_handling, std::string *out) const { |
65 | 0 | if (printable_string_handling == PrintableStringHandling::kAsUTF8Hack && |
66 | 0 | value_tag == CBS_ASN1_PRINTABLESTRING) { |
67 | 0 | *out = BytesAsStringView(value); |
68 | 0 | return true; |
69 | 0 | } |
70 | 0 | return ValueAsString(out); |
71 | 0 | } |
72 | | |
73 | 404k | bool X509NameAttribute::ValueAsStringUnsafe(std::string *out) const { |
74 | 404k | switch (value_tag) { |
75 | 30.6k | case CBS_ASN1_IA5STRING: |
76 | 83.6k | case CBS_ASN1_PRINTABLESTRING: |
77 | 83.6k | case CBS_ASN1_T61STRING: |
78 | 249k | case CBS_ASN1_UTF8STRING: |
79 | 249k | *out = BytesAsStringView(value); |
80 | 249k | return true; |
81 | 7.58k | case CBS_ASN1_UNIVERSALSTRING: |
82 | 7.58k | return der::ParseUniversalString(value, out); |
83 | 147k | case CBS_ASN1_BMPSTRING: |
84 | 147k | return der::ParseBmpString(value, out); |
85 | 0 | default: |
86 | 0 | assert(0); // NOTREACHED |
87 | 0 | return false; |
88 | 404k | } |
89 | 404k | } |
90 | | |
91 | 0 | bool X509NameAttribute::AsRFC2253String(std::string *out) const { |
92 | 0 | std::string type_string; |
93 | 0 | std::string value_string; |
94 | | // TODO(mattm): Add streetAddress and domainComponent here? |
95 | 0 | if (type == der::Input(kTypeCommonNameOid)) { |
96 | 0 | type_string = "CN"; |
97 | 0 | } else if (type == der::Input(kTypeSurnameOid)) { |
98 | 0 | type_string = "SN"; |
99 | 0 | } else if (type == der::Input(kTypeCountryNameOid)) { |
100 | 0 | type_string = "C"; |
101 | 0 | } else if (type == der::Input(kTypeLocalityNameOid)) { |
102 | 0 | type_string = "L"; |
103 | 0 | } else if (type == der::Input(kTypeStateOrProvinceNameOid)) { |
104 | 0 | type_string = "ST"; |
105 | 0 | } else if (type == der::Input(kTypeOrganizationNameOid)) { |
106 | 0 | type_string = "O"; |
107 | 0 | } else if (type == der::Input(kTypeOrganizationUnitNameOid)) { |
108 | 0 | type_string = "OU"; |
109 | 0 | } else if (type == der::Input(kTypeGivenNameOid)) { |
110 | 0 | type_string = "givenName"; |
111 | 0 | } else if (type == der::Input(kTypeEmailAddressOid)) { |
112 | 0 | type_string = "emailAddress"; |
113 | 0 | } else { |
114 | 0 | type_string = OidToString(type); |
115 | 0 | if (type_string.empty()) { |
116 | 0 | return false; |
117 | 0 | } |
118 | 0 | value_string = "#" + bssl::string_util::HexEncode(value); |
119 | 0 | } |
120 | | |
121 | 0 | if (value_string.empty()) { |
122 | 0 | std::string unescaped; |
123 | 0 | if (!ValueAsStringUnsafe(&unescaped)) { |
124 | 0 | return false; |
125 | 0 | } |
126 | | |
127 | 0 | bool nonprintable = false; |
128 | 0 | for (unsigned int i = 0; i < unescaped.length(); ++i) { |
129 | 0 | uint8_t c = static_cast<uint8_t>(unescaped[i]); |
130 | 0 | if (i == 0 && c == '#') { |
131 | 0 | value_string += "\\#"; |
132 | 0 | } else if (i == 0 && c == ' ') { |
133 | 0 | value_string += "\\ "; |
134 | 0 | } else if (i == unescaped.length() - 1 && c == ' ') { |
135 | 0 | value_string += "\\ "; |
136 | 0 | } else if (c == ',' || c == '+' || c == '"' || c == '\\' || c == '<' || |
137 | 0 | c == '>' || c == ';') { |
138 | 0 | value_string += "\\"; |
139 | 0 | value_string += c; |
140 | 0 | } else if (c < 32 || c > 126) { |
141 | 0 | nonprintable = true; |
142 | 0 | value_string += "\\" + bssl::string_util::HexEncode(Span(&c, 1)); |
143 | 0 | } else { |
144 | 0 | value_string += c; |
145 | 0 | } |
146 | 0 | } |
147 | | |
148 | | // If we have non-printable characters in a TeletexString, we hex encode |
149 | | // since we don't handle Teletex control codes. |
150 | 0 | if (nonprintable && value_tag == CBS_ASN1_T61STRING) { |
151 | 0 | value_string = "#" + bssl::string_util::HexEncode(value); |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | 0 | *out = type_string + "=" + value_string; |
156 | 0 | return true; |
157 | 0 | } |
158 | | |
159 | 356k | bool ReadRdn(der::Parser *parser, RelativeDistinguishedName *out) { |
160 | 781k | while (parser->HasMore()) { |
161 | 424k | der::Parser attr_type_and_value; |
162 | 424k | if (!parser->ReadSequence(&attr_type_and_value)) { |
163 | 114 | return false; |
164 | 114 | } |
165 | | // Read the attribute type, which must be an OBJECT IDENTIFIER. |
166 | 424k | der::Input type; |
167 | 424k | if (!attr_type_and_value.ReadTag(CBS_ASN1_OBJECT, &type)) { |
168 | 43 | return false; |
169 | 43 | } |
170 | | |
171 | | // Read the attribute value. |
172 | 424k | CBS_ASN1_TAG tag; |
173 | 424k | der::Input value; |
174 | 424k | if (!attr_type_and_value.ReadTagAndValue(&tag, &value)) { |
175 | 44 | return false; |
176 | 44 | } |
177 | | |
178 | | // There should be no more elements in the sequence after reading the |
179 | | // attribute type and value. |
180 | 424k | if (attr_type_and_value.HasMore()) { |
181 | 22 | return false; |
182 | 22 | } |
183 | | |
184 | 424k | out->push_back(X509NameAttribute(type, tag, value)); |
185 | 424k | } |
186 | | |
187 | | // RFC 5280 section 4.1.2.4 |
188 | | // RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue |
189 | 356k | return out->size() != 0; |
190 | 356k | } |
191 | | |
192 | 0 | bool ParseName(der::Input name_tlv, RDNSequence *out) { |
193 | 0 | der::Parser name_parser(name_tlv); |
194 | 0 | der::Input name_value; |
195 | 0 | if (!name_parser.ReadTag(CBS_ASN1_SEQUENCE, &name_value)) { |
196 | 0 | return false; |
197 | 0 | } |
198 | 0 | return ParseNameValue(name_value, out); |
199 | 0 | } |
200 | | |
201 | 0 | bool ParseNameValue(der::Input name_value, RDNSequence *out) { |
202 | 0 | der::Parser rdn_sequence_parser(name_value); |
203 | 0 | while (rdn_sequence_parser.HasMore()) { |
204 | 0 | der::Parser rdn_parser; |
205 | 0 | if (!rdn_sequence_parser.ReadConstructed(CBS_ASN1_SET, &rdn_parser)) { |
206 | 0 | return false; |
207 | 0 | } |
208 | 0 | RelativeDistinguishedName type_and_values; |
209 | 0 | if (!ReadRdn(&rdn_parser, &type_and_values)) { |
210 | 0 | return false; |
211 | 0 | } |
212 | 0 | out->push_back(type_and_values); |
213 | 0 | } |
214 | | |
215 | 0 | return true; |
216 | 0 | } |
217 | | |
218 | 0 | bool ConvertToRFC2253(const RDNSequence &rdn_sequence, std::string *out) { |
219 | 0 | std::string rdns_string; |
220 | 0 | size_t size = rdn_sequence.size(); |
221 | 0 | for (size_t i = 0; i < size; ++i) { |
222 | 0 | RelativeDistinguishedName rdn = rdn_sequence[size - i - 1]; |
223 | 0 | std::string rdn_string; |
224 | 0 | for (const auto &atv : rdn) { |
225 | 0 | if (!rdn_string.empty()) { |
226 | 0 | rdn_string += "+"; |
227 | 0 | } |
228 | 0 | std::string atv_string; |
229 | 0 | if (!atv.AsRFC2253String(&atv_string)) { |
230 | 0 | return false; |
231 | 0 | } |
232 | 0 | rdn_string += atv_string; |
233 | 0 | } |
234 | 0 | if (!rdns_string.empty()) { |
235 | 0 | rdns_string += ","; |
236 | 0 | } |
237 | 0 | rdns_string += rdn_string; |
238 | 0 | } |
239 | | |
240 | 0 | *out = rdns_string; |
241 | 0 | return true; |
242 | 0 | } |
243 | | |
244 | | BSSL_NAMESPACE_END |