Coverage Report

Created: 2026-10-27 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/x509/x_name.cc
Line
Count
Source
1
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
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 <ctype.h>
16
#include <limits.h>
17
#include <string.h>
18
19
#include <utility>
20
21
#include <openssl/asn1.h>
22
#include <openssl/asn1t.h>
23
#include <openssl/bytestring.h>
24
#include <openssl/buf.h>
25
#include <openssl/err.h>
26
#include <openssl/mem.h>
27
#include <openssl/obj.h>
28
#include <openssl/stack.h>
29
#include <openssl/x509.h>
30
31
#include "../asn1/internal.h"
32
#include "../bytestring/internal.h"
33
#include "../internal.h"
34
#include "../mem_internal.h"
35
#include "internal.h"
36
37
38
using namespace bssl;
39
40
// X509_NAME_MAX is the length of the maximum encoded `X509_NAME` we accept.
41
374k
#define X509_NAME_MAX (1024 * 1024)
42
43
namespace {
44
45
932k
int asn1_marshal_string_canon(CBB *cbb, const ASN1_STRING *in) {
46
932k
  int (*decode_func)(CBS *, uint32_t *);
47
932k
  int error;
48
932k
  switch (in->type) {
49
281k
    case V_ASN1_UTF8STRING:
50
281k
      decode_func = CBS_get_utf8;
51
281k
      error = ASN1_R_INVALID_UTF8STRING;
52
281k
      break;
53
5.69k
    case V_ASN1_BMPSTRING:
54
5.69k
      decode_func = CBS_get_ucs2_be;
55
5.69k
      error = ASN1_R_INVALID_BMPSTRING;
56
5.69k
      break;
57
5.52k
    case V_ASN1_UNIVERSALSTRING:
58
5.52k
      decode_func = CBS_get_utf32_be;
59
5.52k
      error = ASN1_R_INVALID_UNIVERSALSTRING;
60
5.52k
      break;
61
325k
    case V_ASN1_PRINTABLESTRING:
62
346k
    case V_ASN1_T61STRING:
63
375k
    case V_ASN1_IA5STRING:
64
378k
    case V_ASN1_VISIBLESTRING:
65
378k
      decode_func = CBS_get_latin1;
66
378k
      error = ERR_R_INTERNAL_ERROR;  // Latin-1 inputs are never invalid.
67
378k
      break;
68
261k
    default:
69
      // Other string types are not canonicalized.
70
261k
      return asn1_marshal_any_string(cbb, in);
71
932k
  }
72
73
671k
  CBB child;
74
671k
  if (!CBB_add_asn1(cbb, &child, CBS_ASN1_UTF8STRING)) {
75
0
    return 0;
76
0
  }
77
78
671k
  bool empty = true;
79
671k
  bool in_whitespace = false;
80
671k
  CBS cbs;
81
671k
  CBS_init(&cbs, in->data, in->length);
82
26.6M
  while (CBS_len(&cbs) != 0) {
83
25.9M
    uint32_t c;
84
25.9M
    if (!decode_func(&cbs, &c)) {
85
0
      OPENSSL_PUT_ERROR(ASN1, error);
86
0
      return 0;
87
0
    }
88
25.9M
    if (OPENSSL_isspace(c)) {
89
739k
      if (empty) {
90
15.3k
        continue;  // Trim leading whitespace.
91
15.3k
      }
92
723k
      in_whitespace = true;
93
25.2M
    } else {
94
25.2M
      if (in_whitespace) {
95
        // Collapse the previous run of whitespace into one space.
96
548k
        if (!CBB_add_u8(&child, ' ')) {
97
0
          return 0;
98
0
        }
99
548k
      }
100
25.2M
      in_whitespace = false;
101
      // Lowecase ASCII codepoints.
102
25.2M
      if (c <= 0x7f) {
103
6.95M
        c = OPENSSL_tolower(c);
104
6.95M
      }
105
25.2M
      if (!CBB_add_utf8(&child, c)) {
106
0
        return 0;
107
0
      }
108
25.2M
      empty = false;
109
25.2M
    }
110
25.9M
  }
111
112
671k
  return CBB_flush(cbb);
113
671k
}
114
115
949k
int x509_parse_name_entry(CBS *cbs, X509_NAME_ENTRY *out) {
116
949k
  auto *out_impl = FromOpaque(out);
117
949k
  CBS seq;
118
949k
  if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE)) {
119
211
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
120
211
    return 0;
121
211
  }
122
949k
  out_impl->object.reset(asn1_parse_object(&seq, /*tag=*/0));
123
949k
  if (out_impl->object == nullptr ||                        //
124
949k
      !asn1_parse_any_as_string(&seq, out_impl->value.get()) ||  //
125
948k
      CBS_len(&seq) != 0) {
126
1.08k
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
127
1.08k
    return 0;
128
1.08k
  }
129
948k
  return 1;
130
949k
}
131
132
int x509_marshal_name_entry(CBB *cbb, const X509_NAME_ENTRY *entry,
133
1.88M
                            int canonicalize) {
134
1.88M
  auto *entry_impl = FromOpaque(entry);
135
1.88M
  CBB seq;
136
1.88M
  if (!CBB_add_asn1(cbb, &seq, CBS_ASN1_SEQUENCE) ||
137
1.88M
      !asn1_marshal_object(&seq, entry_impl->object.get(), /*tag=*/0)) {
138
3
    return 0;
139
3
  }
140
1.88M
  int ok = canonicalize
141
1.88M
               ? asn1_marshal_string_canon(&seq, entry_impl->value.get())
142
1.88M
               : asn1_marshal_any_string(&seq, entry_impl->value.get());
143
1.88M
  if (!ok) {
144
0
    return 0;
145
0
  }
146
1.88M
  return CBB_flush(cbb);
147
1.88M
}
148
149
8.59k
int x509_marshal_name_entry_no_canon(CBB *cbb, const X509_NAME_ENTRY *entry) {
150
8.59k
  return x509_marshal_name_entry(cbb, entry, /*canonicalize=*/0);
151
8.59k
}
152
153
int x509_marshal_name_entries(CBB *out, const X509_NAME *name,
154
752k
                              int canonicalize) {
155
752k
  auto *impl = FromOpaque(name);
156
752k
  if (sk_X509_NAME_ENTRY_num(impl->entries.get()) == 0) {
157
12.4k
    return 1;
158
12.4k
  }
159
160
  // Bootstrap the first RDN.
161
739k
  int set = FromOpaque(sk_X509_NAME_ENTRY_value(impl->entries.get(), 0))->set;
162
739k
  CBB rdn;
163
739k
  if (!CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) {
164
0
    return 0;
165
0
  }
166
167
1.86M
  for (const X509_NAME_ENTRY *entry : impl->entries.get()) {
168
1.86M
    if (FromOpaque(entry)->set != set) {
169
      // Flush the previous RDN and start a new one.
170
749k
      if (!CBB_flush_asn1_set_of(&rdn) ||
171
749k
          !CBB_add_asn1(out, &rdn, CBS_ASN1_SET)) {
172
0
        return 0;
173
0
      }
174
749k
      set = FromOpaque(entry)->set;
175
749k
    }
176
1.86M
    if (!x509_marshal_name_entry(&rdn, entry, canonicalize)) {
177
0
      return 0;
178
0
    }
179
1.86M
  }
180
181
739k
  return CBB_flush_asn1_set_of(&rdn) && CBB_flush(out);
182
739k
}
183
184
}  // namespace
185
186
965k
bssl::X509NameEntry::X509NameEntry() {
187
965k
  object.reset(const_cast<ASN1_OBJECT *>(OBJ_get_undef()));
188
965k
}
189
190
31.4k
X509_NAME_ENTRY *X509_NAME_ENTRY_new() { return New<X509NameEntry>(); }
191
192
964k
void X509_NAME_ENTRY_free(X509_NAME_ENTRY *entry) { Delete(FromOpaque(entry)); }
193
194
BSSL_NAMESPACE_BEGIN
195
196
IMPLEMENT_EXTERN_ASN1_PARSE_INTO(X509_NAME_ENTRY, X509_NAME_ENTRY_new,
197
                                 X509_NAME_ENTRY_free, CBS_ASN1_SEQUENCE,
198
                                 x509_parse_name_entry,
199
                                 x509_marshal_name_entry_no_canon)
200
201
BSSL_NAMESPACE_END
202
203
15.6k
X509_NAME_ENTRY *X509_NAME_ENTRY_dup(const X509_NAME_ENTRY *entry) {
204
15.6k
  ScopedCBB cbb;
205
15.6k
  if (!CBB_init(cbb.get(), 16) ||
206
15.6k
      !x509_marshal_name_entry(cbb.get(), entry, /*canonicalize=*/0)) {
207
3
    return nullptr;
208
3
  }
209
15.6k
  CBS cbs;
210
15.6k
  CBS_init(&cbs, CBB_data(cbb.get()), CBB_len(cbb.get()));
211
15.6k
  UniquePtr<X509_NAME_ENTRY> copy(X509_NAME_ENTRY_new());
212
15.6k
  if (copy == nullptr || !x509_parse_name_entry(&cbs, copy.get())) {
213
0
    return nullptr;
214
0
  }
215
15.6k
  return copy.release();
216
15.6k
}
217
218
452k
bssl::X509Name::~X509Name() { Delete(cache.exchange(nullptr)); }
219
220
12.7k
X509_NAME *X509_NAME_new() { return New<X509Name>(); }
221
222
16.1k
void X509_NAME_free(X509_NAME *name) { Delete(FromOpaque(name)); }
223
224
374k
int bssl::x509_parse_name(CBS *cbs, X509_NAME *out) {
225
374k
  auto *impl = FromOpaque(out);
226
374k
  impl->entries = nullptr;
227
374k
  x509_name_invalidate_cache(impl);
228
229
374k
  impl->entries.reset(sk_X509_NAME_ENTRY_new_null());
230
374k
  if (impl->entries == nullptr) {
231
0
    return 0;
232
0
  }
233
374k
  CBS seq, rdn;
234
374k
  if (!CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE) ||
235
      // Bound the size of an X509_NAME we are willing to parse.
236
374k
      CBS_len(&seq) > X509_NAME_MAX) {
237
192
    OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
238
192
    return 0;
239
192
  }
240
374k
  static_assert(X509_NAME_MAX <= INT_MAX, "set may overflow");
241
1.11M
  for (int set = 0; CBS_len(&seq) > 0; set++) {
242
744k
    if (!CBS_get_asn1(&seq, &rdn, CBS_ASN1_SET) ||  //
243
744k
        CBS_len(&rdn) == 0) {
244
281
      OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR);
245
281
      return 0;
246
281
    }
247
1.67M
    while (CBS_len(&rdn) != 0) {
248
934k
      auto entry = MakeUnique<X509NameEntry>();
249
934k
      if (entry == nullptr || !x509_parse_name_entry(&rdn, entry.get())) {
250
1.25k
        return 0;
251
1.25k
      }
252
932k
      entry->set = set;
253
932k
      if (!PushToStack(impl->entries.get(), std::move(entry))) {
254
0
        return 0;
255
0
      }
256
932k
    }
257
744k
  }
258
259
  // While we are single-threaded, also fill in the cached state.
260
373k
  return x509_name_get_cache(impl) != nullptr;
261
374k
}
262
263
391k
const X509NameCache *bssl::x509_name_get_cache(const X509_NAME *name) {
264
391k
  auto *impl = FromOpaque(name);
265
391k
  const X509NameCache *cache = impl->cache.load();
266
391k
  if (cache != nullptr) {
267
14.8k
    return cache;
268
14.8k
  }
269
270
376k
  UniquePtr<X509NameCache> new_cache = MakeUnique<X509NameCache>();
271
  // Cache the DER encoding, including the outer TLV.
272
376k
  ScopedCBB cbb;
273
376k
  CBB seq;
274
376k
  if (!CBB_init(cbb.get(), 16) ||
275
376k
      !CBB_add_asn1(cbb.get(), &seq, CBS_ASN1_SEQUENCE) ||
276
376k
      !x509_marshal_name_entries(&seq, impl, /*canonicalize=*/0) ||
277
376k
      !CBBFinishArray(cbb.get(), &new_cache->der)) {
278
0
    return nullptr;
279
0
  }
280
  // Cache the canonicalized form, without the outer TLV.
281
376k
  if (!CBB_init(cbb.get(), 16) ||
282
376k
      !x509_marshal_name_entries(cbb.get(), impl, /*canonicalize=*/1) ||
283
376k
      !CBBFinishArray(cbb.get(), &new_cache->canon)) {
284
0
    return nullptr;
285
0
  }
286
287
376k
  X509NameCache *expected = nullptr;
288
376k
  if (impl->cache.compare_exchange_strong(expected, new_cache.get())) {
289
    // We won the race. `impl` now owns `new_cache`.
290
376k
    return new_cache.release();
291
376k
  }
292
293
  // Some other thread installed a (presumably identical) cache. Release the one
294
  // we made and return the winning one.
295
376k
  assert(expected != nullptr);
296
0
  return expected;
297
0
}
298
299
390k
void bssl::x509_name_invalidate_cache(X509_NAME *name) {
300
390k
  auto *impl = FromOpaque(name);
301
390k
  Delete(impl->cache.exchange(nullptr));
302
390k
}
303
304
9.17k
int bssl::x509_marshal_name(CBB *out, const X509_NAME *in) {
305
9.17k
  const X509NameCache *cache = x509_name_get_cache(in);
306
9.17k
  if (cache == nullptr) {
307
0
    return 0;
308
0
  }
309
9.17k
  return CBB_add_bytes(out, cache->der.data(), cache->der.size());
310
9.17k
}
311
312
60
int bssl::x509_name_copy(X509_NAME *dst, const X509_NAME *src) {
313
60
  const X509NameCache *cache = x509_name_get_cache(src);
314
60
  if (cache == nullptr) {
315
0
    return 0;
316
0
  }
317
  // Callers sometimes try to set a name back to itself. We check this after
318
  // `x509_name_get_cache` because, if `src` was so broken that it could not be
319
  // serialized, we used to return an error. (It's not clear if this codepath is
320
  // even possible.)
321
60
  if (dst == src) {
322
0
    return 1;
323
0
  }
324
60
  CBS cbs(cache->der);
325
60
  if (!x509_parse_name(&cbs, dst)) {
326
0
    return 0;
327
0
  }
328
60
  assert(CBS_len(&cbs) == 0);
329
60
  return 1;
330
60
}
331
332
60
X509_NAME *X509_NAME_dup(const X509_NAME *name) {
333
60
  UniquePtr<X509_NAME> copy(X509_NAME_new());
334
60
  if (copy == nullptr || !x509_name_copy(copy.get(), name)) {
335
0
    return nullptr;
336
0
  }
337
60
  return copy.release();
338
60
}
339
340
1.18k
X509_NAME *d2i_X509_NAME(X509_NAME **out, const uint8_t **inp, long len) {
341
1.18k
  return D2IFromCBS(out, inp, len, [](CBS *cbs) -> UniquePtr<X509_NAME> {
342
1.18k
    UniquePtr<X509_NAME> name(X509_NAME_new());
343
1.18k
    if (name == nullptr || !x509_parse_name(cbs, name.get())) {
344
349
      return nullptr;
345
349
    }
346
836
    return name;
347
1.18k
  });
348
1.18k
}
349
350
3.27k
int i2d_X509_NAME(const X509_NAME *in, uint8_t **outp) {
351
3.27k
  if (in == nullptr) {
352
0
    OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER);
353
0
    return -1;
354
0
  }
355
3.27k
  const X509NameCache *cache = x509_name_get_cache(in);
356
3.27k
  if (cache == nullptr) {
357
0
    return -1;
358
0
  }
359
3.27k
  if (cache->der.size() > INT_MAX) {
360
0
    OPENSSL_PUT_ERROR(X509, ERR_R_OVERFLOW);
361
0
    return -1;
362
0
  }
363
3.27k
  int len = static_cast<int>(cache->der.size());
364
3.27k
  if (outp == nullptr) {
365
0
    return len;
366
0
  }
367
3.27k
  if (*outp == nullptr) {
368
3.27k
    *outp = static_cast<uint8_t *>(
369
3.27k
        OPENSSL_memdup(cache->der.data(), cache->der.size()));
370
3.27k
    return *outp != nullptr ? len : -1;
371
3.27k
  }
372
0
  OPENSSL_memcpy(*outp, cache->der.data(), cache->der.size());
373
0
  *outp += cache->der.size();
374
0
  return len;
375
3.27k
}
376
377
IMPLEMENT_EXTERN_ASN1_PARSE_INTO(X509_NAME, X509_NAME_new, X509_NAME_free,
378
                                 CBS_ASN1_SEQUENCE, x509_parse_name,
379
                                 x509_marshal_name)
380
381
0
int X509_NAME_set(X509_NAME **xn, const X509_NAME *name) {
382
0
  UniquePtr<X509_NAME> copy(X509_NAME_dup(name));
383
0
  if (copy == nullptr) {
384
0
    return 0;
385
0
  }
386
0
  X509_NAME_free(*xn);
387
0
  *xn = copy.release();
388
0
  return 1;
389
0
}
390
391
2.83k
int X509_NAME_ENTRY_set(const X509_NAME_ENTRY *ne) {
392
2.83k
  return FromOpaque(ne)->set;
393
2.83k
}
394
395
int X509_NAME_get0_der(const X509_NAME *nm, const unsigned char **out_der,
396
0
                       size_t *out_der_len) {
397
0
  const X509NameCache *cache = x509_name_get_cache(nm);
398
0
  if (cache == nullptr) {
399
0
    return 0;
400
0
  }
401
0
  if (out_der != nullptr) {
402
0
    *out_der = cache->der.data();
403
0
  }
404
0
  if (out_der_len != nullptr) {
405
0
    *out_der_len = cache->der.size();
406
0
  }
407
0
  return 1;
408
0
}