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