Coverage Report

Created: 2025-11-03 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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