Coverage Report

Created: 2026-02-14 06:34

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
static LHASH_OF(ASN1_STRING_TABLE) *string_tables = nullptr;
42
static CRYPTO_MUTEX string_tables_lock = CRYPTO_MUTEX_INIT;
43
44
0
void ASN1_STRING_set_default_mask(unsigned long mask) {}
45
46
0
unsigned long ASN1_STRING_get_default_mask() { return B_ASN1_UTF8STRING; }
47
48
0
int ASN1_STRING_set_default_mask_asc(const char *p) { return 1; }
49
50
static const ASN1_STRING_TABLE *asn1_string_table_get(int nid);
51
52
// The following function generates an ASN1_STRING based on limits in a
53
// table. Frequently the types and length of an ASN1_STRING are restricted by
54
// a corresponding OID. For example certificates and certificate requests.
55
56
ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in,
57
11.5k
                                    ossl_ssize_t len, int inform, int nid) {
58
11.5k
  ASN1_STRING *str = nullptr;
59
11.5k
  int ret;
60
11.5k
  if (!out) {
61
0
    out = &str;
62
0
  }
63
11.5k
  const ASN1_STRING_TABLE *tbl = asn1_string_table_get(nid);
64
11.5k
  if (tbl != nullptr) {
65
8.20k
    unsigned long mask = tbl->mask;
66
8.20k
    if (!(tbl->flags & STABLE_NO_MASK)) {
67
6.83k
      mask &= B_ASN1_UTF8STRING;
68
6.83k
    }
69
8.20k
    ret = ASN1_mbstring_ncopy(out, in, len, inform, mask, tbl->minsize,
70
8.20k
                              tbl->maxsize);
71
8.20k
  } else {
72
3.35k
    ret = ASN1_mbstring_copy(out, in, len, inform, B_ASN1_UTF8STRING);
73
3.35k
  }
74
11.5k
  if (ret <= 0) {
75
18
    return nullptr;
76
18
  }
77
11.5k
  return *out;
78
11.5k
}
79
80
// Now the tables and helper functions for the string table:
81
82
// See RFC 5280.
83
#define ub_name 32768
84
#define ub_common_name 64
85
#define ub_locality_name 128
86
#define ub_state_name 128
87
#define ub_organization_name 64
88
#define ub_organization_unit_name 64
89
#define ub_email_address 128
90
#define ub_serial_number 64
91
92
// This table must be kept in NID order
93
94
static const ASN1_STRING_TABLE tbl_standard[] = {
95
    {NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0},
96
    {NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
97
    {NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0},
98
    {NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0},
99
    {NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0},
100
    {NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE,
101
     0},
102
    {NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING,
103
     STABLE_NO_MASK},
104
    {NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0},
105
    {NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
106
    {NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0},
107
    {NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0},
108
    {NID_surname, 1, ub_name, DIRSTRING_TYPE, 0},
109
    {NID_initials, 1, ub_name, DIRSTRING_TYPE, 0},
110
    {NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING,
111
     STABLE_NO_MASK},
112
    {NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK},
113
    {NID_name, 1, ub_name, DIRSTRING_TYPE, 0},
114
    {NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK},
115
    {NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK},
116
    {NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}};
117
118
38.0k
static int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b) {
119
38.0k
  if (a->nid < b->nid) {
120
24.5k
    return -1;
121
24.5k
  }
122
13.4k
  if (a->nid > b->nid) {
123
5.27k
    return 1;
124
5.27k
  }
125
8.20k
  return 0;
126
13.4k
}
127
128
38.0k
static int table_cmp_void(const void *a, const void *b) {
129
38.0k
  return table_cmp(reinterpret_cast<const ASN1_STRING_TABLE *>(a),
130
38.0k
                   reinterpret_cast<const ASN1_STRING_TABLE *>(b));
131
38.0k
}
132
133
0
static uint32_t table_hash(const ASN1_STRING_TABLE *tbl) {
134
0
  return OPENSSL_hash32(&tbl->nid, sizeof(tbl->nid));
135
0
}
136
137
11.5k
static const ASN1_STRING_TABLE *asn1_string_table_get(int nid) {
138
11.5k
  ASN1_STRING_TABLE key;
139
11.5k
  key.nid = nid;
140
11.5k
  const ASN1_STRING_TABLE *tbl = reinterpret_cast<ASN1_STRING_TABLE *>(
141
11.5k
      bsearch(&key, tbl_standard, std::size(tbl_standard),
142
11.5k
              sizeof(ASN1_STRING_TABLE), table_cmp_void));
143
11.5k
  if (tbl != nullptr) {
144
8.20k
    return tbl;
145
8.20k
  }
146
147
3.35k
  CRYPTO_MUTEX_lock_read(&string_tables_lock);
148
3.35k
  if (string_tables != nullptr) {
149
0
    tbl = lh_ASN1_STRING_TABLE_retrieve(string_tables, &key);
150
0
  }
151
3.35k
  CRYPTO_MUTEX_unlock_read(&string_tables_lock);
152
  // Note returning |tbl| without the lock is only safe because
153
  // |ASN1_STRING_TABLE_add| cannot modify or delete existing entries. If we
154
  // wish to support that, this function must copy the result under a lock.
155
3.35k
  return tbl;
156
11.5k
}
157
158
int ASN1_STRING_TABLE_add(int nid, long minsize, long maxsize,
159
0
                          unsigned long mask, unsigned long flags) {
160
  // Existing entries cannot be overwritten.
161
0
  if (asn1_string_table_get(nid) != nullptr) {
162
0
    OPENSSL_PUT_ERROR(ASN1, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
163
0
    return 0;
164
0
  }
165
166
0
  int ret = 0;
167
0
  CRYPTO_MUTEX_lock_write(&string_tables_lock);
168
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
      goto err;
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
      goto err;
183
0
    }
184
0
  }
185
186
0
  tbl = New<ASN1_STRING_TABLE>();
187
0
  if (tbl == nullptr) {
188
0
    goto err;
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
    goto err;
199
0
  }
200
0
  assert(old_tbl == nullptr);
201
0
  ret = 1;
202
203
0
err:
204
0
  CRYPTO_MUTEX_unlock_write(&string_tables_lock);
205
0
  return ret;
206
0
}
207
208
0
void ASN1_STRING_TABLE_cleanup() {}
209
210
void bssl::asn1_get_string_table_for_testing(const ASN1_STRING_TABLE **out_ptr,
211
0
                                             size_t *out_len) {
212
0
  *out_ptr = tbl_standard;
213
0
  *out_len = std::size(tbl_standard);
214
0
}