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.
OidToString(der::Input oid)31 std::string OidToString(der::Input oid) {
32 CBS cbs;
33 CBS_init(&cbs, oid.data(), oid.size());
34 bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs));
35 if (!text) {
36 return std::string();
37 }
38 return text.get();
39 }
40
41 } // namespace
42
ValueAsString(std::string * out) const43 bool X509NameAttribute::ValueAsString(std::string *out) const {
44 switch (value_tag) {
45 case CBS_ASN1_T61STRING:
46 return der::ParseTeletexStringAsLatin1(value, out);
47 case CBS_ASN1_IA5STRING:
48 return der::ParseIA5String(value, out);
49 case CBS_ASN1_PRINTABLESTRING:
50 return der::ParsePrintableString(value, out);
51 case CBS_ASN1_UTF8STRING:
52 *out = BytesAsStringView(value);
53 return true;
54 case CBS_ASN1_UNIVERSALSTRING:
55 return der::ParseUniversalString(value, out);
56 case CBS_ASN1_BMPSTRING:
57 return der::ParseBmpString(value, out);
58 default:
59 return false;
60 }
61 }
62
ValueAsStringWithUnsafeOptions(PrintableStringHandling printable_string_handling,std::string * out) const63 bool X509NameAttribute::ValueAsStringWithUnsafeOptions(
64 PrintableStringHandling printable_string_handling, std::string *out) const {
65 if (printable_string_handling == PrintableStringHandling::kAsUTF8Hack &&
66 value_tag == CBS_ASN1_PRINTABLESTRING) {
67 *out = BytesAsStringView(value);
68 return true;
69 }
70 return ValueAsString(out);
71 }
72
ValueAsStringUnsafe(std::string * out) const73 bool X509NameAttribute::ValueAsStringUnsafe(std::string *out) const {
74 switch (value_tag) {
75 case CBS_ASN1_IA5STRING:
76 case CBS_ASN1_PRINTABLESTRING:
77 case CBS_ASN1_T61STRING:
78 case CBS_ASN1_UTF8STRING:
79 *out = BytesAsStringView(value);
80 return true;
81 case CBS_ASN1_UNIVERSALSTRING:
82 return der::ParseUniversalString(value, out);
83 case CBS_ASN1_BMPSTRING:
84 return der::ParseBmpString(value, out);
85 default:
86 assert(0); // NOTREACHED
87 return false;
88 }
89 }
90
AsRFC2253String(std::string * out) const91 bool X509NameAttribute::AsRFC2253String(std::string *out) const {
92 std::string type_string;
93 std::string value_string;
94 // TODO(mattm): Add streetAddress and domainComponent here?
95 if (type == der::Input(kTypeCommonNameOid)) {
96 type_string = "CN";
97 } else if (type == der::Input(kTypeSurnameOid)) {
98 type_string = "SN";
99 } else if (type == der::Input(kTypeCountryNameOid)) {
100 type_string = "C";
101 } else if (type == der::Input(kTypeLocalityNameOid)) {
102 type_string = "L";
103 } else if (type == der::Input(kTypeStateOrProvinceNameOid)) {
104 type_string = "ST";
105 } else if (type == der::Input(kTypeOrganizationNameOid)) {
106 type_string = "O";
107 } else if (type == der::Input(kTypeOrganizationUnitNameOid)) {
108 type_string = "OU";
109 } else if (type == der::Input(kTypeGivenNameOid)) {
110 type_string = "givenName";
111 } else if (type == der::Input(kTypeEmailAddressOid)) {
112 type_string = "emailAddress";
113 } else {
114 type_string = OidToString(type);
115 if (type_string.empty()) {
116 return false;
117 }
118 value_string = "#" + bssl::string_util::HexEncode(value);
119 }
120
121 if (value_string.empty()) {
122 std::string unescaped;
123 if (!ValueAsStringUnsafe(&unescaped)) {
124 return false;
125 }
126
127 bool nonprintable = false;
128 for (unsigned int i = 0; i < unescaped.length(); ++i) {
129 uint8_t c = static_cast<uint8_t>(unescaped[i]);
130 if (i == 0 && c == '#') {
131 value_string += "\\#";
132 } else if (i == 0 && c == ' ') {
133 value_string += "\\ ";
134 } else if (i == unescaped.length() - 1 && c == ' ') {
135 value_string += "\\ ";
136 } else if (c == ',' || c == '+' || c == '"' || c == '\\' || c == '<' ||
137 c == '>' || c == ';') {
138 value_string += "\\";
139 value_string += c;
140 } else if (c < 32 || c > 126) {
141 nonprintable = true;
142 value_string += "\\" + bssl::string_util::HexEncode(Span(&c, 1));
143 } else {
144 value_string += c;
145 }
146 }
147
148 // If we have non-printable characters in a TeletexString, we hex encode
149 // since we don't handle Teletex control codes.
150 if (nonprintable && value_tag == CBS_ASN1_T61STRING) {
151 value_string = "#" + bssl::string_util::HexEncode(value);
152 }
153 }
154
155 *out = type_string + "=" + value_string;
156 return true;
157 }
158
ReadRdn(der::Parser * parser,RelativeDistinguishedName * out)159 bool ReadRdn(der::Parser *parser, RelativeDistinguishedName *out) {
160 while (parser->HasMore()) {
161 der::Parser attr_type_and_value;
162 if (!parser->ReadSequence(&attr_type_and_value)) {
163 return false;
164 }
165 // Read the attribute type, which must be an OBJECT IDENTIFIER.
166 der::Input type;
167 if (!attr_type_and_value.ReadTag(CBS_ASN1_OBJECT, &type)) {
168 return false;
169 }
170
171 // Read the attribute value.
172 CBS_ASN1_TAG tag;
173 der::Input value;
174 if (!attr_type_and_value.ReadTagAndValue(&tag, &value)) {
175 return false;
176 }
177
178 // There should be no more elements in the sequence after reading the
179 // attribute type and value.
180 if (attr_type_and_value.HasMore()) {
181 return false;
182 }
183
184 out->push_back(X509NameAttribute(type, tag, value));
185 }
186
187 // RFC 5280 section 4.1.2.4
188 // RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
189 return out->size() != 0;
190 }
191
ParseName(der::Input name_tlv,RDNSequence * out)192 bool ParseName(der::Input name_tlv, RDNSequence *out) {
193 der::Parser name_parser(name_tlv);
194 der::Input name_value;
195 if (!name_parser.ReadTag(CBS_ASN1_SEQUENCE, &name_value)) {
196 return false;
197 }
198 return ParseNameValue(name_value, out);
199 }
200
ParseNameValue(der::Input name_value,RDNSequence * out)201 bool ParseNameValue(der::Input name_value, RDNSequence *out) {
202 der::Parser rdn_sequence_parser(name_value);
203 while (rdn_sequence_parser.HasMore()) {
204 der::Parser rdn_parser;
205 if (!rdn_sequence_parser.ReadConstructed(CBS_ASN1_SET, &rdn_parser)) {
206 return false;
207 }
208 RelativeDistinguishedName type_and_values;
209 if (!ReadRdn(&rdn_parser, &type_and_values)) {
210 return false;
211 }
212 out->push_back(type_and_values);
213 }
214
215 return true;
216 }
217
ConvertToRFC2253(const RDNSequence & rdn_sequence,std::string * out)218 bool ConvertToRFC2253(const RDNSequence &rdn_sequence, std::string *out) {
219 std::string rdns_string;
220 size_t size = rdn_sequence.size();
221 for (size_t i = 0; i < size; ++i) {
222 RelativeDistinguishedName rdn = rdn_sequence[size - i - 1];
223 std::string rdn_string;
224 for (const auto &atv : rdn) {
225 if (!rdn_string.empty()) {
226 rdn_string += "+";
227 }
228 std::string atv_string;
229 if (!atv.AsRFC2253String(&atv_string)) {
230 return false;
231 }
232 rdn_string += atv_string;
233 }
234 if (!rdns_string.empty()) {
235 rdns_string += ",";
236 }
237 rdns_string += rdn_string;
238 }
239
240 *out = rdns_string;
241 return true;
242 }
243
244 BSSL_NAMESPACE_END
245