• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "net/cert/pki/parse_name.h"
6 
7 #include "net/cert/pki/string_util.h"
8 #include "net/der/parse_values.h"
9 #include "third_party/boringssl/src/include/openssl/bytestring.h"
10 #include "third_party/boringssl/src/include/openssl/mem.h"
11 
12 namespace net {
13 
14 namespace {
15 
16 // Returns a string containing the dotted numeric form of |oid|, or an empty
17 // string on error.
OidToString(der::Input oid)18 std::string OidToString(der::Input oid) {
19   CBS cbs;
20   CBS_init(&cbs, oid.UnsafeData(), oid.Length());
21   bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs));
22   if (!text)
23     return std::string();
24   return text.get();
25 }
26 
27 }  // namespace
28 
ValueAsString(std::string * out) const29 bool X509NameAttribute::ValueAsString(std::string* out) const {
30   switch (value_tag) {
31     case der::kTeletexString:
32       return der::ParseTeletexStringAsLatin1(value, out);
33     case der::kIA5String:
34       return der::ParseIA5String(value, out);
35     case der::kPrintableString:
36       return der::ParsePrintableString(value, out);
37     case der::kUtf8String:
38       *out = value.AsString();
39       return true;
40     case der::kUniversalString:
41       return der::ParseUniversalString(value, out);
42     case der::kBmpString:
43       return der::ParseBmpString(value, out);
44     default:
45       return false;
46   }
47 }
48 
ValueAsStringWithUnsafeOptions(PrintableStringHandling printable_string_handling,std::string * out) const49 bool X509NameAttribute::ValueAsStringWithUnsafeOptions(
50     PrintableStringHandling printable_string_handling,
51     std::string* out) const {
52   if (printable_string_handling == PrintableStringHandling::kAsUTF8Hack &&
53       value_tag == der::kPrintableString) {
54     *out = value.AsString();
55     return true;
56   }
57   return ValueAsString(out);
58 }
59 
ValueAsStringUnsafe(std::string * out) const60 bool X509NameAttribute::ValueAsStringUnsafe(std::string* out) const {
61   switch (value_tag) {
62     case der::kIA5String:
63     case der::kPrintableString:
64     case der::kTeletexString:
65     case der::kUtf8String:
66       *out = value.AsString();
67       return true;
68     case der::kUniversalString:
69       return der::ParseUniversalString(value, out);
70     case der::kBmpString:
71       return der::ParseBmpString(value, out);
72     default:
73       assert(0);  // NOTREACHED
74       return false;
75   }
76 }
77 
AsRFC2253String(std::string * out) const78 bool X509NameAttribute::AsRFC2253String(std::string* out) const {
79   std::string type_string;
80   std::string value_string;
81   // TODO(mattm): Add streetAddress and domainComponent here?
82   if (type == der::Input(kTypeCommonNameOid)) {
83     type_string = "CN";
84   } else if (type == der::Input(kTypeSurnameOid)) {
85     type_string = "SN";
86   } else if (type == der::Input(kTypeCountryNameOid)) {
87     type_string = "C";
88   } else if (type == der::Input(kTypeLocalityNameOid)) {
89     type_string = "L";
90   } else if (type == der::Input(kTypeStateOrProvinceNameOid)) {
91     type_string = "ST";
92   } else if (type == der::Input(kTypeOrganizationNameOid)) {
93     type_string = "O";
94   } else if (type == der::Input(kTypeOrganizationUnitNameOid)) {
95     type_string = "OU";
96   } else if (type == der::Input(kTypeGivenNameOid)) {
97     type_string = "givenName";
98   } else if (type == der::Input(kTypeEmailAddressOid)) {
99     type_string = "emailAddress";
100   } else {
101     type_string = OidToString(type);
102     if (type_string.empty())
103       return false;
104     value_string =
105         "#" + net::string_util::HexEncode(value.UnsafeData(), value.Length());
106   }
107 
108   if (value_string.empty()) {
109     std::string unescaped;
110     if (!ValueAsStringUnsafe(&unescaped))
111       return false;
112 
113     bool nonprintable = false;
114     for (unsigned int i = 0; i < unescaped.length(); ++i) {
115       unsigned char c = static_cast<unsigned char>(unescaped[i]);
116       if (i == 0 && c == '#') {
117         value_string += "\\#";
118       } else if (i == 0 && c == ' ') {
119         value_string += "\\ ";
120       } else if (i == unescaped.length() - 1 && c == ' ') {
121         value_string += "\\ ";
122       } else if (c == ',' || c == '+' || c == '"' || c == '\\' || c == '<' ||
123                  c == '>' || c == ';') {
124         value_string += "\\";
125         value_string += c;
126       } else if (c < 32 || c > 126) {
127         nonprintable = true;
128         std::string h;
129         h += c;
130         value_string +=
131             "\\" + net::string_util::HexEncode(
132                        reinterpret_cast<const uint8_t*>(h.data()), h.length());
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 == der::kTeletexString)
141       value_string =
142           "#" + net::string_util::HexEncode(value.UnsafeData(), value.Length());
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     // Read the attribute type, which must be an OBJECT IDENTIFIER.
155     der::Input type;
156     if (!attr_type_and_value.ReadTag(der::kOid, &type))
157       return false;
158 
159     // Read the attribute value.
160     der::Tag tag;
161     der::Input value;
162     if (!attr_type_and_value.ReadTagAndValue(&tag, &value))
163       return false;
164 
165     // There should be no more elements in the sequence after reading the
166     // attribute type and value.
167     if (attr_type_and_value.HasMore())
168       return false;
169 
170     out->push_back(X509NameAttribute(type, tag, value));
171   }
172 
173   // RFC 5280 section 4.1.2.4
174   // RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
175   return out->size() != 0;
176 }
177 
ParseName(const der::Input & name_tlv,RDNSequence * out)178 bool ParseName(const der::Input& name_tlv, RDNSequence* out) {
179   der::Parser name_parser(name_tlv);
180   der::Input name_value;
181   if (!name_parser.ReadTag(der::kSequence, &name_value))
182     return false;
183   return ParseNameValue(name_value, out);
184 }
185 
ParseNameValue(const der::Input & name_value,RDNSequence * out)186 bool ParseNameValue(const der::Input& name_value, RDNSequence* out) {
187   der::Parser rdn_sequence_parser(name_value);
188   while (rdn_sequence_parser.HasMore()) {
189     der::Parser rdn_parser;
190     if (!rdn_sequence_parser.ReadConstructed(der::kSet, &rdn_parser))
191       return false;
192     RelativeDistinguishedName type_and_values;
193     if (!ReadRdn(&rdn_parser, &type_and_values))
194       return false;
195     out->push_back(type_and_values);
196   }
197 
198   return true;
199 }
200 
ConvertToRFC2253(const RDNSequence & rdn_sequence,std::string * out)201 bool ConvertToRFC2253(const RDNSequence& rdn_sequence, std::string* out) {
202   std::string rdns_string;
203   size_t size = rdn_sequence.size();
204   for (size_t i = 0; i < size; ++i) {
205     RelativeDistinguishedName rdn = rdn_sequence[size - i - 1];
206     std::string rdn_string;
207     for (const auto& atv : rdn) {
208       if (!rdn_string.empty())
209         rdn_string += "+";
210       std::string atv_string;
211       if (!atv.AsRFC2253String(&atv_string))
212         return false;
213       rdn_string += atv_string;
214     }
215     if (!rdns_string.empty())
216       rdns_string += ",";
217     rdns_string += rdn_string;
218   }
219 
220   *out = rdns_string;
221   return true;
222 }
223 
224 }  // namespace net
225