Coverage Report

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