Coverage Report

Created: 2026-10-27 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/asn1/a_strnid.cc
Line
Count
Source
1
// Copyright 1999-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 <openssl/asn1.h>
16
17
#include <assert.h>
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include <iterator>
22
23
#include <openssl/err.h>
24
#include <openssl/mem.h>
25
#include <openssl/obj.h>
26
27
#include "../internal.h"
28
#include "../lhash/internal.h"
29
#include "../mem_internal.h"
30
#include "internal.h"
31
32
33
using namespace bssl;
34
35
BSSL_NAMESPACE_BEGIN
36
37
DEFINE_LHASH_OF(ASN1_STRING_TABLE)
38
39
BSSL_NAMESPACE_END
40
41
0
void ASN1_STRING_set_default_mask(unsigned long mask) {}
42
43
0
unsigned long ASN1_STRING_get_default_mask() { return B_ASN1_UTF8STRING; }
44
45
0
int ASN1_STRING_set_default_mask_asc(const char *p) { return 1; }
46
47
// Now the tables and helper functions for the string table:
48
49
// See RFC 5280.
50
#define ub_name 32768
51
#define ub_common_name 64
52
#define ub_locality_name 128
53
#define ub_state_name 128
54
#define ub_organization_name 64
55
#define ub_organization_unit_name 64
56
#define ub_email_address 128
57
#define ub_serial_number 64
58
59
namespace {
60
61
LHASH_OF(ASN1_STRING_TABLE) *string_tables = nullptr;
62
StaticMutex string_tables_lock;
63
64
// This table must be kept in NID order
65
66
const ASN1_STRING_TABLE tbl_standard[] = {
67
    {NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
68
    {NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
69
    {NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
70
    {NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
71
    {NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
72
    {NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE,
73
     0},
74
    {NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING,
75
     STABLE_NO_MASK},
76
    {NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0},
77
    {NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
78
    {NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
79
    {NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
80
    {NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
81
    {NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
82
    {NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING,
83
     STABLE_NO_MASK},
84
    {NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
85
    {NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
86
    {NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
87
    {NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
88
    {NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}};
89
90
54.2k
int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b) {
91
54.2k
  if (a->nid < b->nid) {
92
36.2k
    return -1;
93
36.2k
  }
94
18.0k
  if (a->nid > b->nid) {
95
8.53k
    return 1;
96
8.53k
  }
97
9.50k
  return 0;
98
18.0k
}
99
100
54.2k
int table_cmp_void(const void *a, const void *b) {
101
54.2k
  return table_cmp(reinterpret_cast<const ASN1_STRING_TABLE *>(a),
102
54.2k
                   reinterpret_cast<const ASN1_STRING_TABLE *>(b));
103
54.2k
}
104
105
0
uint32_t table_hash(const ASN1_STRING_TABLE *tbl) {
106
0
  return OPENSSL_hash32(&tbl->nid, sizeof(tbl->nid));
107
0
}
108
109
15.6k
const ASN1_STRING_TABLE *asn1_string_table_get(int nid) {
110
15.6k
  ASN1_STRING_TABLE key;
111
15.6k
  key.nid = nid;
112
15.6k
  const ASN1_STRING_TABLE *tbl = reinterpret_cast<ASN1_STRING_TABLE *>(
113
15.6k
      bsearch(&key, tbl_standard, std::size(tbl_standard),
114
15.6k
              sizeof(ASN1_STRING_TABLE), table_cmp_void));
115
15.6k
  if (tbl != nullptr) {
116
9.50k
    return tbl;
117
9.50k
  }
118
119
6.09k
  string_tables_lock.LockRead();
120
6.09k
  if (string_tables != nullptr) {
121
0
    tbl = lh_ASN1_STRING_TABLE_retrieve(string_tables, &key);
122
0
  }
123
6.09k
  string_tables_lock.UnlockRead();
124
  // Note returning `tbl` without the lock is only safe because
125
  // `ASN1_STRING_TABLE_add` cannot modify or delete existing entries. If we
126
  // wish to support that, this function must copy the result under a lock.
127
6.09k
  return tbl;
128
15.6k
}
129
130
}  // namespace
131
132
// The following function generates an ASN1_STRING based on limits in a
133
// table. Frequently the types and length of an ASN1_STRING are restricted by
134
// a corresponding OID. For example certificates and certificate requests.
135
136
ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in,
137
15.6k
                                    ossl_ssize_t len, int inform, int nid) {
138
15.6k
  ASN1_STRING *str = nullptr;
139
15.6k
  int ret;
140
15.6k
  if (!out) {
141
0
    out = &str;
142
0
  }
143
15.6k
  const ASN1_STRING_TABLE *tbl = asn1_string_table_get(nid);
144
15.6k
  if (tbl != nullptr) {
145
9.50k
    unsigned long mask = tbl->mask;
146
9.50k
    if (!(tbl->flags & STABLE_NO_MASK)) {
147
8.11k
      mask &= B_ASN1_UTF8STRING;
148
8.11k
    }
149
9.50k
    ret = ASN1_mbstring_ncopy(out, in, len, inform, mask, tbl->minsize,
150
9.50k
                              tbl->maxsize);
151
9.50k
  } else {
152
6.09k
    ret = ASN1_mbstring_copy(out, in, len, inform, B_ASN1_UTF8STRING);
153
6.09k
  }
154
15.6k
  if (ret <= 0) {
155
14
    return nullptr;
156
14
  }
157
15.5k
  return *out;
158
15.6k
}
159
160
int ASN1_STRING_TABLE_add(int nid, long minsize, long maxsize,
161
0
                          unsigned long mask, unsigned long flags) {
162
  // Existing entries cannot be overwritten.
163
0
  if (asn1_string_table_get(nid) != nullptr) {
164
0
    OPENSSL_PUT_ERROR(ASN1, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
165
0
    return 0;
166
0
  }
167
168
0
  MutexWriteLock lock(&string_tables_lock);
169
0
  ASN1_STRING_TABLE *tbl = nullptr;
170
0
  if (string_tables == nullptr) {
171
0
    string_tables = lh_ASN1_STRING_TABLE_new(table_hash, table_cmp);
172
0
    if (string_tables == nullptr) {
173
0
      return 0;
174
0
    }
175
0
  } else {
176
    // Check again for an existing entry. One may have been added while
177
    // unlocked.
178
0
    ASN1_STRING_TABLE key;
179
0
    key.nid = nid;
180
0
    if (lh_ASN1_STRING_TABLE_retrieve(string_tables, &key) != nullptr) {
181
0
      OPENSSL_PUT_ERROR(ASN1, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
182
0
      return 0;
183
0
    }
184
0
  }
185
186
0
  tbl = New<ASN1_STRING_TABLE>();
187
0
  if (tbl == nullptr) {
188
0
    return 0;
189
0
  }
190
0
  tbl->nid = nid;
191
0
  tbl->flags = flags;
192
0
  tbl->minsize = minsize;
193
0
  tbl->maxsize = maxsize;
194
0
  tbl->mask = mask;
195
0
  ASN1_STRING_TABLE *old_tbl;
196
0
  if (!lh_ASN1_STRING_TABLE_insert(string_tables, &old_tbl, tbl)) {
197
0
    Delete(tbl);
198
0
    return 0;
199
0
  }
200
0
  assert(old_tbl == nullptr);
201
0
  return 1;
202
0
}
203
204
0
void ASN1_STRING_TABLE_cleanup() {}
205
206
void bssl::asn1_get_string_table_for_testing(const ASN1_STRING_TABLE **out_ptr,
207
0
                                             size_t *out_len) {
208
0
  *out_ptr = tbl_standard;
209
0
  *out_len = std::size(tbl_standard);
210
0
}