ber.c
Go to the documentation of this file.
1 /* Copyright (c) 2014, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <openssl/bytestring.h>
16 
17 #include <assert.h>
18 #include <string.h>
19 
20 #include "internal.h"
21 #include "../internal.h"
22 
23 
24 // kMaxDepth is a just a sanity limit. The code should be such that the length
25 // of the input being processes always decreases. None the less, a very large
26 // input could otherwise cause the stack to overflow.
27 static const unsigned kMaxDepth = 2048;
28 
29 // is_string_type returns one if |tag| is a string type and zero otherwise. It
30 // ignores the constructed bit.
31 static int is_string_type(unsigned tag) {
32  // While BER supports constructed BIT STRINGS, OpenSSL misparses them. To
33  // avoid acting on an ambiguous input, we do not support constructed BIT
34  // STRINGS. See https://github.com/openssl/openssl/issues/12810.
35  switch (tag & ~CBS_ASN1_CONSTRUCTED) {
40  case CBS_ASN1_T61STRING:
42  case CBS_ASN1_IA5STRING:
47  case CBS_ASN1_BMPSTRING:
48  return 1;
49  default:
50  return 0;
51  }
52 }
53 
54 // cbs_find_ber walks an ASN.1 structure in |orig_in| and sets |*ber_found|
55 // depending on whether an indefinite length element or constructed string was
56 // found. The value of |orig_in| is not changed. It returns one on success (i.e.
57 // |*ber_found| was set) and zero on error.
58 static int cbs_find_ber(const CBS *orig_in, int *ber_found, unsigned depth) {
59  CBS in;
60 
61  if (depth > kMaxDepth) {
62  return 0;
63  }
64 
65  CBS_init(&in, CBS_data(orig_in), CBS_len(orig_in));
66  *ber_found = 0;
67 
68  while (CBS_len(&in) > 0) {
69  CBS contents;
70  unsigned tag;
71  size_t header_len;
72 
73  if (!CBS_get_any_ber_asn1_element(&in, &contents, &tag, &header_len,
74  ber_found)) {
75  return 0;
76  }
77  if (*ber_found) {
78  return 1;
79  }
80  if (tag & CBS_ASN1_CONSTRUCTED) {
81  if (is_string_type(tag)) {
82  // Constructed strings are only legal in BER and require conversion.
83  *ber_found = 1;
84  return 1;
85  }
86  if (!CBS_skip(&contents, header_len) ||
87  !cbs_find_ber(&contents, ber_found, depth + 1)) {
88  return 0;
89  }
90  }
91  }
92 
93  return 1;
94 }
95 
96 // is_eoc returns true if |header_len| and |contents|, as returned by
97 // |CBS_get_any_ber_asn1_element|, indicate an "end of contents" (EOC) value.
98 static char is_eoc(size_t header_len, CBS *contents) {
99  return header_len == 2 && CBS_len(contents) == 2 &&
100  OPENSSL_memcmp(CBS_data(contents), "\x00\x00", 2) == 0;
101 }
102 
103 // cbs_convert_ber reads BER data from |in| and writes DER data to |out|. If
104 // |string_tag| is non-zero, then all elements must match |string_tag| up to the
105 // constructed bit and primitive element bodies are written to |out| without
106 // element headers. This is used when concatenating the fragments of a
107 // constructed string. If |looking_for_eoc| is set then any EOC elements found
108 // will cause the function to return after consuming it. It returns one on
109 // success and zero on error.
110 static int cbs_convert_ber(CBS *in, CBB *out, unsigned string_tag,
111  char looking_for_eoc, unsigned depth) {
112  assert(!(string_tag & CBS_ASN1_CONSTRUCTED));
113 
114  if (depth > kMaxDepth) {
115  return 0;
116  }
117 
118  while (CBS_len(in) > 0) {
119  CBS contents;
120  unsigned tag, child_string_tag = string_tag;
121  size_t header_len;
122  int ber_found;
123  CBB *out_contents, out_contents_storage;
124 
125  if (!CBS_get_any_ber_asn1_element(in, &contents, &tag, &header_len,
126  &ber_found)) {
127  return 0;
128  }
129 
130  if (is_eoc(header_len, &contents)) {
131  return looking_for_eoc;
132  }
133 
134  if (string_tag != 0) {
135  // This is part of a constructed string. All elements must match
136  // |string_tag| up to the constructed bit and get appended to |out|
137  // without a child element.
138  if ((tag & ~CBS_ASN1_CONSTRUCTED) != string_tag) {
139  return 0;
140  }
141  out_contents = out;
142  } else {
143  unsigned out_tag = tag;
145  // If a constructed string, clear the constructed bit and inform
146  // children to concatenate bodies.
147  out_tag &= ~CBS_ASN1_CONSTRUCTED;
148  child_string_tag = out_tag;
149  }
150  if (!CBB_add_asn1(out, &out_contents_storage, out_tag)) {
151  return 0;
152  }
153  out_contents = &out_contents_storage;
154  }
155 
156  if (CBS_len(&contents) == header_len && header_len > 0 &&
157  CBS_data(&contents)[header_len - 1] == 0x80) {
158  // This is an indefinite length element.
159  if (!cbs_convert_ber(in, out_contents, child_string_tag,
160  1 /* looking for eoc */, depth + 1) ||
161  !CBB_flush(out)) {
162  return 0;
163  }
164  continue;
165  }
166 
167  if (!CBS_skip(&contents, header_len)) {
168  return 0;
169  }
170 
171  if (tag & CBS_ASN1_CONSTRUCTED) {
172  // Recurse into children.
173  if (!cbs_convert_ber(&contents, out_contents, child_string_tag,
174  0 /* not looking for eoc */, depth + 1)) {
175  return 0;
176  }
177  } else {
178  // Copy primitive contents as-is.
179  if (!CBB_add_bytes(out_contents, CBS_data(&contents),
180  CBS_len(&contents))) {
181  return 0;
182  }
183  }
184 
185  if (!CBB_flush(out)) {
186  return 0;
187  }
188  }
189 
190  return looking_for_eoc == 0;
191 }
192 
193 int CBS_asn1_ber_to_der(CBS *in, CBS *out, uint8_t **out_storage) {
194  CBB cbb;
195 
196  // First, do a quick walk to find any indefinite-length elements. Most of the
197  // time we hope that there aren't any and thus we can quickly return.
198  int conversion_needed;
199  if (!cbs_find_ber(in, &conversion_needed, 0)) {
200  return 0;
201  }
202 
203  if (!conversion_needed) {
204  if (!CBS_get_any_asn1_element(in, out, NULL, NULL)) {
205  return 0;
206  }
207  *out_storage = NULL;
208  return 1;
209  }
210 
211  size_t len;
212  if (!CBB_init(&cbb, CBS_len(in)) ||
213  !cbs_convert_ber(in, &cbb, 0, 0, 0) ||
214  !CBB_finish(&cbb, out_storage, &len)) {
215  CBB_cleanup(&cbb);
216  return 0;
217  }
218 
219  CBS_init(out, *out_storage, len);
220  return 1;
221 }
222 
224  unsigned outer_tag, unsigned inner_tag) {
225  assert(!(outer_tag & CBS_ASN1_CONSTRUCTED));
226  assert(!(inner_tag & CBS_ASN1_CONSTRUCTED));
227  assert(is_string_type(inner_tag));
228 
229  if (CBS_peek_asn1_tag(in, outer_tag)) {
230  // Normal implicitly-tagged string.
231  *out_storage = NULL;
232  return CBS_get_asn1(in, out, outer_tag);
233  }
234 
235  // Otherwise, try to parse an implicitly-tagged constructed string.
236  // |CBS_asn1_ber_to_der| is assumed to have run, so only allow one level deep
237  // of nesting.
238  CBB result;
239  CBS child;
240  if (!CBB_init(&result, CBS_len(in)) ||
241  !CBS_get_asn1(in, &child, outer_tag | CBS_ASN1_CONSTRUCTED)) {
242  goto err;
243  }
244 
245  while (CBS_len(&child) > 0) {
246  CBS chunk;
247  if (!CBS_get_asn1(&child, &chunk, inner_tag) ||
248  !CBB_add_bytes(&result, CBS_data(&chunk), CBS_len(&chunk))) {
249  goto err;
250  }
251  }
252 
253  uint8_t *data;
254  size_t len;
255  if (!CBB_finish(&result, &data, &len)) {
256  goto err;
257  }
258 
259  CBS_init(out, data, len);
260  *out_storage = data;
261  return 1;
262 
263 err:
265  return 0;
266 }
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
CBB_flush
#define CBB_flush
Definition: boringssl_prefix_symbols.h:1045
CBB_init
#define CBB_init
Definition: boringssl_prefix_symbols.h:1047
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
cbs_st
Definition: bytestring.h:39
OPENSSL_memcmp
static int OPENSSL_memcmp(const void *s1, const void *s2, size_t n)
Definition: third_party/boringssl-with-bazel/src/crypto/internal.h:811
CBB_cleanup
#define CBB_cleanup
Definition: boringssl_prefix_symbols.h:1039
CBS_skip
#define CBS_skip
Definition: boringssl_prefix_symbols.h:1092
CBS_data
#define CBS_data
Definition: boringssl_prefix_symbols.h:1057
string.h
CBS_ASN1_OCTETSTRING
#define CBS_ASN1_OCTETSTRING
Definition: bytestring.h:209
error_ref_leak.err
err
Definition: error_ref_leak.py:35
CBS_len
#define CBS_len
Definition: boringssl_prefix_symbols.h:1089
CBS_ASN1_IA5STRING
#define CBS_ASN1_IA5STRING
Definition: bytestring.h:220
CBS_get_asn1
#define CBS_get_asn1
Definition: boringssl_prefix_symbols.h:1061
CBS_ASN1_T61STRING
#define CBS_ASN1_T61STRING
Definition: bytestring.h:218
CBS_init
#define CBS_init
Definition: boringssl_prefix_symbols.h:1085
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
is_string_type
static int is_string_type(unsigned tag)
Definition: ber.c:31
CBS_ASN1_VIDEOTEXSTRING
#define CBS_ASN1_VIDEOTEXSTRING
Definition: bytestring.h:219
bytestring.h
CBS_get_asn1_implicit_string
int CBS_get_asn1_implicit_string(CBS *in, CBS *out, uint8_t **out_storage, unsigned outer_tag, unsigned inner_tag)
Definition: ber.c:223
CBS_peek_asn1_tag
#define CBS_peek_asn1_tag
Definition: boringssl_prefix_symbols.h:1091
internal.h
in
const char * in
Definition: third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc:391
CBS_get_any_asn1_element
#define CBS_get_any_asn1_element
Definition: boringssl_prefix_symbols.h:1059
tag
static void * tag(intptr_t t)
Definition: bad_client.cc:318
CBS_ASN1_BMPSTRING
#define CBS_ASN1_BMPSTRING
Definition: bytestring.h:227
CBB_finish
#define CBB_finish
Definition: boringssl_prefix_symbols.h:1043
CBS_asn1_ber_to_der
int CBS_asn1_ber_to_der(CBS *in, CBS *out, uint8_t **out_storage)
Definition: ber.c:193
CBB_add_asn1
#define CBB_add_asn1
Definition: boringssl_prefix_symbols.h:1019
CBS_get_any_ber_asn1_element
#define CBS_get_any_ber_asn1_element
Definition: boringssl_prefix_symbols.h:1060
googletest-filter-unittest.child
child
Definition: bloaty/third_party/googletest/googletest/test/googletest-filter-unittest.py:62
is_eoc
static char is_eoc(size_t header_len, CBS *contents)
Definition: ber.c:98
kMaxDepth
static const unsigned kMaxDepth
Definition: ber.c:27
CBS_ASN1_UTF8STRING
#define CBS_ASN1_UTF8STRING
Definition: bytestring.h:213
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
CBS_ASN1_NUMERICSTRING
#define CBS_ASN1_NUMERICSTRING
Definition: bytestring.h:216
CBS_ASN1_CONSTRUCTED
#define CBS_ASN1_CONSTRUCTED
Definition: bytestring.h:188
cbs_convert_ber
static int cbs_convert_ber(CBS *in, CBB *out, unsigned string_tag, char looking_for_eoc, unsigned depth)
Definition: ber.c:110
CBB_add_bytes
#define CBB_add_bytes
Definition: boringssl_prefix_symbols.h:1025
contents
string_view contents
Definition: elf.cc:597
cbs_find_ber
static int cbs_find_ber(const CBS *orig_in, int *ber_found, unsigned depth)
Definition: ber.c:58
CBS_ASN1_GRAPHICSTRING
#define CBS_ASN1_GRAPHICSTRING
Definition: bytestring.h:223
CBS_ASN1_VISIBLESTRING
#define CBS_ASN1_VISIBLESTRING
Definition: bytestring.h:224
CBS_ASN1_PRINTABLESTRING
#define CBS_ASN1_PRINTABLESTRING
Definition: bytestring.h:217
CBS_ASN1_UNIVERSALSTRING
#define CBS_ASN1_UNIVERSALSTRING
Definition: bytestring.h:226
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
mkowners.depth
depth
Definition: mkowners.py:114
CBS_ASN1_GENERALSTRING
#define CBS_ASN1_GENERALSTRING
Definition: bytestring.h:225
cbb_st
Definition: bytestring.h:375


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:46