/src/boringssl/crypto/asn1/a_strex.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2000-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 <ctype.h> |
19 | | #include <inttypes.h> |
20 | | #include <limits.h> |
21 | | #include <string.h> |
22 | | #include <time.h> |
23 | | |
24 | | #include <openssl/bio.h> |
25 | | #include <openssl/bytestring.h> |
26 | | #include <openssl/mem.h> |
27 | | |
28 | | #include "../bytestring/internal.h" |
29 | | #include "../internal.h" |
30 | | #include "internal.h" |
31 | | |
32 | | |
33 | | #define ESC_FLAGS \ |
34 | 0 | (ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_QUOTE | ASN1_STRFLGS_ESC_CTRL | \ |
35 | 0 | ASN1_STRFLGS_ESC_MSB) |
36 | | |
37 | 15.2k | static int maybe_write(BIO *out, const void *buf, int len) { |
38 | | // If |out| is NULL, ignore the output but report the length. |
39 | 15.2k | return out == NULL || BIO_write(out, buf, len) == len; |
40 | 15.2k | } |
41 | | |
42 | 6.09k | static int is_control_character(unsigned char c) { return c < 32 || c == 127; } |
43 | | |
44 | | static int do_esc_char(uint32_t c, unsigned long flags, char *do_quotes, |
45 | 11.3k | BIO *out, int is_first, int is_last) { |
46 | | // |c| is a |uint32_t| because, depending on |ASN1_STRFLGS_UTF8_CONVERT|, |
47 | | // we may be escaping bytes or Unicode codepoints. |
48 | 11.3k | char buf[16]; // Large enough for "\\W01234567". |
49 | 11.3k | unsigned char u8 = (unsigned char)c; |
50 | 11.3k | if (c > 0xffff) { |
51 | 0 | snprintf(buf, sizeof(buf), "\\W%08" PRIX32, c); |
52 | 11.3k | } else if (c > 0xff) { |
53 | 0 | snprintf(buf, sizeof(buf), "\\U%04" PRIX32, c); |
54 | 11.3k | } else if ((flags & ASN1_STRFLGS_ESC_MSB) && c > 0x7f) { |
55 | 5.27k | snprintf(buf, sizeof(buf), "\\%02X", c); |
56 | 6.09k | } else if ((flags & ASN1_STRFLGS_ESC_CTRL) && is_control_character(c)) { |
57 | 2.48k | snprintf(buf, sizeof(buf), "\\%02X", c); |
58 | 3.60k | } else if (flags & ASN1_STRFLGS_ESC_2253) { |
59 | | // See RFC 2253, sections 2.4 and 4. |
60 | 3.60k | if (c == '\\' || c == '"') { |
61 | | // Quotes and backslashes are always escaped, quoted or not. |
62 | 294 | snprintf(buf, sizeof(buf), "\\%c", (int)c); |
63 | 3.31k | } else if (c == ',' || c == '+' || c == '<' || c == '>' || c == ';' || |
64 | 3.31k | (is_first && (c == ' ' || c == '#')) || |
65 | 3.31k | (is_last && (c == ' '))) { |
66 | 956 | if (flags & ASN1_STRFLGS_ESC_QUOTE) { |
67 | | // No need to escape, just tell the caller to quote. |
68 | 956 | if (do_quotes != NULL) { |
69 | 478 | *do_quotes = 1; |
70 | 478 | } |
71 | 956 | return maybe_write(out, &u8, 1) ? 1 : -1; |
72 | 956 | } |
73 | 0 | snprintf(buf, sizeof(buf), "\\%c", (int)c); |
74 | 2.35k | } else { |
75 | 2.35k | return maybe_write(out, &u8, 1) ? 1 : -1; |
76 | 2.35k | } |
77 | 3.60k | } else if ((flags & ESC_FLAGS) && c == '\\') { |
78 | | // If any escape flags are set, also escape backslashes. |
79 | 0 | snprintf(buf, sizeof(buf), "\\%c", (int)c); |
80 | 0 | } else { |
81 | 0 | return maybe_write(out, &u8, 1) ? 1 : -1; |
82 | 0 | } |
83 | | |
84 | 8.06k | static_assert(sizeof(buf) < INT_MAX, "len may not fit in int"); |
85 | 8.06k | int len = (int)strlen(buf); |
86 | 8.06k | return maybe_write(out, buf, len) ? len : -1; |
87 | 11.3k | } |
88 | | |
89 | | // This function sends each character in a buffer to do_esc_char(). It |
90 | | // interprets the content formats and converts to or from UTF8 as |
91 | | // appropriate. |
92 | | |
93 | | static int do_buf(const unsigned char *buf, int buflen, int encoding, |
94 | 1.33k | unsigned long flags, char *quotes, BIO *out) { |
95 | 1.33k | int (*get_char)(CBS *cbs, uint32_t *out); |
96 | 1.33k | int get_char_error; |
97 | 1.33k | switch (encoding) { |
98 | 56 | case MBSTRING_UNIV: |
99 | 56 | get_char = CBS_get_utf32_be; |
100 | 56 | get_char_error = ASN1_R_INVALID_UNIVERSALSTRING; |
101 | 56 | break; |
102 | 74 | case MBSTRING_BMP: |
103 | 74 | get_char = CBS_get_ucs2_be; |
104 | 74 | get_char_error = ASN1_R_INVALID_BMPSTRING; |
105 | 74 | break; |
106 | 972 | case MBSTRING_ASC: |
107 | 972 | get_char = CBS_get_latin1; |
108 | 972 | get_char_error = ERR_R_INTERNAL_ERROR; // Should not be possible. |
109 | 972 | break; |
110 | 232 | case MBSTRING_UTF8: |
111 | 232 | get_char = CBS_get_utf8; |
112 | 232 | get_char_error = ASN1_R_INVALID_UTF8STRING; |
113 | 232 | break; |
114 | 0 | default: |
115 | 0 | assert(0); |
116 | 0 | return -1; |
117 | 1.33k | } |
118 | | |
119 | 1.33k | CBS cbs; |
120 | 1.33k | CBS_init(&cbs, buf, buflen); |
121 | 1.33k | int outlen = 0; |
122 | 9.84k | while (CBS_len(&cbs) != 0) { |
123 | 8.50k | const int is_first = CBS_data(&cbs) == buf; |
124 | 8.50k | uint32_t c; |
125 | 8.50k | if (!get_char(&cbs, &c)) { |
126 | 0 | OPENSSL_PUT_ERROR(ASN1, get_char_error); |
127 | 0 | return -1; |
128 | 0 | } |
129 | 8.50k | const int is_last = CBS_len(&cbs) == 0; |
130 | 8.50k | if (flags & ASN1_STRFLGS_UTF8_CONVERT) { |
131 | 8.50k | uint8_t utf8_buf[6]; |
132 | 8.50k | CBB utf8_cbb; |
133 | 8.50k | CBB_init_fixed(&utf8_cbb, utf8_buf, sizeof(utf8_buf)); |
134 | 8.50k | if (!CBB_add_utf8(&utf8_cbb, c)) { |
135 | 0 | OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR); |
136 | 0 | return 1; |
137 | 0 | } |
138 | 8.50k | size_t utf8_len = CBB_len(&utf8_cbb); |
139 | 19.8k | for (size_t i = 0; i < utf8_len; i++) { |
140 | 11.3k | int len = do_esc_char(utf8_buf[i], flags, quotes, out, |
141 | 11.3k | is_first && i == 0, is_last && i == utf8_len - 1); |
142 | 11.3k | if (len < 0) { |
143 | 0 | return -1; |
144 | 0 | } |
145 | 11.3k | outlen += len; |
146 | 11.3k | } |
147 | 8.50k | } else { |
148 | 0 | int len = do_esc_char(c, flags, quotes, out, is_first, is_last); |
149 | 0 | if (len < 0) { |
150 | 0 | return -1; |
151 | 0 | } |
152 | 0 | outlen += len; |
153 | 0 | } |
154 | 8.50k | } |
155 | 1.33k | return outlen; |
156 | 1.33k | } |
157 | | |
158 | | // This function hex dumps a buffer of characters |
159 | | |
160 | 549 | static int do_hex_dump(BIO *out, unsigned char *buf, int buflen) { |
161 | 549 | static const char hexdig[] = "0123456789ABCDEF"; |
162 | 549 | unsigned char *p, *q; |
163 | 549 | char hextmp[2]; |
164 | 549 | if (out) { |
165 | 549 | p = buf; |
166 | 549 | q = buf + buflen; |
167 | 3.44k | while (p != q) { |
168 | 2.89k | hextmp[0] = hexdig[*p >> 4]; |
169 | 2.89k | hextmp[1] = hexdig[*p & 0xf]; |
170 | 2.89k | if (!maybe_write(out, hextmp, 2)) { |
171 | 0 | return -1; |
172 | 0 | } |
173 | 2.89k | p++; |
174 | 2.89k | } |
175 | 549 | } |
176 | 549 | return buflen << 1; |
177 | 549 | } |
178 | | |
179 | | // "dump" a string. This is done when the type is unknown, or the flags |
180 | | // request it. We can either dump the content octets or the entire DER |
181 | | // encoding. This uses the RFC 2253 #01234 format. |
182 | | |
183 | 549 | static int do_dump(unsigned long flags, BIO *out, const ASN1_STRING *str) { |
184 | 549 | if (!maybe_write(out, "#", 1)) { |
185 | 0 | return -1; |
186 | 0 | } |
187 | | |
188 | | // If we don't dump DER encoding just dump content octets |
189 | 549 | if (!(flags & ASN1_STRFLGS_DUMP_DER)) { |
190 | 0 | int outlen = do_hex_dump(out, str->data, str->length); |
191 | 0 | if (outlen < 0) { |
192 | 0 | return -1; |
193 | 0 | } |
194 | 0 | return outlen + 1; |
195 | 0 | } |
196 | | |
197 | | // Placing the ASN1_STRING in a temporary ASN1_TYPE allows the DER encoding |
198 | | // to readily obtained. |
199 | 549 | ASN1_TYPE t; |
200 | 549 | OPENSSL_memset(&t, 0, sizeof(ASN1_TYPE)); |
201 | 549 | asn1_type_set0_string(&t, (ASN1_STRING *)str); |
202 | 549 | unsigned char *der_buf = NULL; |
203 | 549 | int der_len = i2d_ASN1_TYPE(&t, &der_buf); |
204 | 549 | if (der_len < 0) { |
205 | 0 | return -1; |
206 | 0 | } |
207 | 549 | int outlen = do_hex_dump(out, der_buf, der_len); |
208 | 549 | OPENSSL_free(der_buf); |
209 | 549 | if (outlen < 0) { |
210 | 0 | return -1; |
211 | 0 | } |
212 | 549 | return outlen + 1; |
213 | 549 | } |
214 | | |
215 | | // string_type_to_encoding returns the |MBSTRING_*| constant for the encoding |
216 | | // used by the |ASN1_STRING| type |type|, or -1 if |tag| is not a string |
217 | | // type. |
218 | 806k | static int string_type_to_encoding(int type) { |
219 | | // This function is sometimes passed ASN.1 universal types and sometimes |
220 | | // passed |ASN1_STRING| type values |
221 | 806k | switch (type) { |
222 | 360k | case V_ASN1_UTF8STRING: |
223 | 360k | return MBSTRING_UTF8; |
224 | 117 | case V_ASN1_NUMERICSTRING: |
225 | 382k | case V_ASN1_PRINTABLESTRING: |
226 | 392k | case V_ASN1_T61STRING: |
227 | 420k | case V_ASN1_IA5STRING: |
228 | 420k | case V_ASN1_UTCTIME: |
229 | 420k | case V_ASN1_GENERALIZEDTIME: |
230 | 421k | case V_ASN1_ISO64STRING: |
231 | | // |MBSTRING_ASC| refers to Latin-1, not ASCII. |
232 | 421k | return MBSTRING_ASC; |
233 | 4.43k | case V_ASN1_UNIVERSALSTRING: |
234 | 4.43k | return MBSTRING_UNIV; |
235 | 19.6k | case V_ASN1_BMPSTRING: |
236 | 19.6k | return MBSTRING_BMP; |
237 | 806k | } |
238 | 549 | return -1; |
239 | 806k | } |
240 | | |
241 | | // This is the main function, print out an ASN1_STRING taking note of various |
242 | | // escape and display options. Returns number of characters written or -1 if |
243 | | // an error occurred. |
244 | | |
245 | | int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, |
246 | 1.21k | unsigned long flags) { |
247 | 1.21k | int type = str->type; |
248 | 1.21k | int outlen = 0; |
249 | 1.21k | if (flags & ASN1_STRFLGS_SHOW_TYPE) { |
250 | 0 | const char *tagname = ASN1_tag2str(type); |
251 | 0 | outlen += strlen(tagname); |
252 | 0 | if (!maybe_write(out, tagname, outlen) || !maybe_write(out, ":", 1)) { |
253 | 0 | return -1; |
254 | 0 | } |
255 | 0 | outlen++; |
256 | 0 | } |
257 | | |
258 | | // Decide what to do with |str|, either dump the contents or display it. |
259 | 1.21k | int encoding; |
260 | 1.21k | if (flags & ASN1_STRFLGS_DUMP_ALL) { |
261 | | // Dump everything. |
262 | 0 | encoding = -1; |
263 | 1.21k | } else if (flags & ASN1_STRFLGS_IGNORE_TYPE) { |
264 | | // Ignore the string type and interpret the contents as Latin-1. |
265 | 0 | encoding = MBSTRING_ASC; |
266 | 1.21k | } else { |
267 | 1.21k | encoding = string_type_to_encoding(type); |
268 | 1.21k | if (encoding == -1 && (flags & ASN1_STRFLGS_DUMP_UNKNOWN) == 0) { |
269 | 0 | encoding = MBSTRING_ASC; |
270 | 0 | } |
271 | 1.21k | } |
272 | | |
273 | 1.21k | if (encoding == -1) { |
274 | 549 | int len = do_dump(flags, out, str); |
275 | 549 | if (len < 0) { |
276 | 0 | return -1; |
277 | 0 | } |
278 | 549 | outlen += len; |
279 | 549 | return outlen; |
280 | 549 | } |
281 | | |
282 | | // Measure the length. |
283 | 667 | char quotes = 0; |
284 | 667 | int len = do_buf(str->data, str->length, encoding, flags, "es, NULL); |
285 | 667 | if (len < 0) { |
286 | 0 | return -1; |
287 | 0 | } |
288 | 667 | outlen += len; |
289 | 667 | if (quotes) { |
290 | 201 | outlen += 2; |
291 | 201 | } |
292 | 667 | if (!out) { |
293 | 0 | return outlen; |
294 | 0 | } |
295 | | |
296 | | // Encode the value. |
297 | 667 | if ((quotes && !maybe_write(out, "\"", 1)) || |
298 | 667 | do_buf(str->data, str->length, encoding, flags, NULL, out) < 0 || |
299 | 667 | (quotes && !maybe_write(out, "\"", 1))) { |
300 | 0 | return -1; |
301 | 0 | } |
302 | 667 | return outlen; |
303 | 667 | } |
304 | | |
305 | | int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str, |
306 | 0 | unsigned long flags) { |
307 | 0 | BIO *bio = NULL; |
308 | 0 | if (fp != NULL) { |
309 | | // If |fp| is NULL, this function returns the number of bytes without |
310 | | // writing. |
311 | 0 | bio = BIO_new_fp(fp, BIO_NOCLOSE); |
312 | 0 | if (bio == NULL) { |
313 | 0 | return -1; |
314 | 0 | } |
315 | 0 | } |
316 | 0 | int ret = ASN1_STRING_print_ex(bio, str, flags); |
317 | 0 | BIO_free(bio); |
318 | 0 | return ret; |
319 | 0 | } |
320 | | |
321 | 805k | int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in) { |
322 | 805k | if (!in) { |
323 | 0 | return -1; |
324 | 0 | } |
325 | 805k | int mbflag = string_type_to_encoding(in->type); |
326 | 805k | if (mbflag == -1) { |
327 | 0 | OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_TAG); |
328 | 0 | return -1; |
329 | 0 | } |
330 | 805k | ASN1_STRING stmp, *str = &stmp; |
331 | 805k | stmp.data = NULL; |
332 | 805k | stmp.length = 0; |
333 | 805k | stmp.flags = 0; |
334 | 805k | int ret = |
335 | 805k | ASN1_mbstring_copy(&str, in->data, in->length, mbflag, B_ASN1_UTF8STRING); |
336 | 805k | if (ret < 0) { |
337 | 119 | return ret; |
338 | 119 | } |
339 | 805k | *out = stmp.data; |
340 | 805k | return stmp.length; |
341 | 805k | } |
342 | | |
343 | 22.8k | int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v) { |
344 | 22.8k | int i, n; |
345 | 22.8k | char buf[80]; |
346 | 22.8k | const char *p; |
347 | | |
348 | 22.8k | if (v == NULL) { |
349 | 0 | return 0; |
350 | 0 | } |
351 | 22.8k | n = 0; |
352 | 22.8k | p = (const char *)v->data; |
353 | 538k | for (i = 0; i < v->length; i++) { |
354 | 515k | if ((p[i] > '~') || ((p[i] < ' ') && (p[i] != '\n') && (p[i] != '\r'))) { |
355 | 335k | buf[n] = '.'; |
356 | 335k | } else { |
357 | 180k | buf[n] = p[i]; |
358 | 180k | } |
359 | 515k | n++; |
360 | 515k | if (n >= 80) { |
361 | 3.62k | if (BIO_write(bp, buf, n) <= 0) { |
362 | 0 | return 0; |
363 | 0 | } |
364 | 3.62k | n = 0; |
365 | 3.62k | } |
366 | 515k | } |
367 | 22.8k | if (n > 0) { |
368 | 20.3k | if (BIO_write(bp, buf, n) <= 0) { |
369 | 0 | return 0; |
370 | 0 | } |
371 | 20.3k | } |
372 | 22.8k | return 1; |
373 | 22.8k | } |
374 | | |
375 | 5.62k | int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) { |
376 | 5.62k | if (tm->type == V_ASN1_UTCTIME) { |
377 | 5.62k | return ASN1_UTCTIME_print(bp, tm); |
378 | 5.62k | } |
379 | 0 | if (tm->type == V_ASN1_GENERALIZEDTIME) { |
380 | 0 | return ASN1_GENERALIZEDTIME_print(bp, tm); |
381 | 0 | } |
382 | 0 | BIO_puts(bp, "Bad time value"); |
383 | 0 | return 0; |
384 | 0 | } |
385 | | |
386 | | static const char *const mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", |
387 | | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; |
388 | | |
389 | 1 | int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm) { |
390 | 1 | CBS cbs; |
391 | 1 | CBS_init(&cbs, tm->data, tm->length); |
392 | 1 | struct tm utc; |
393 | 1 | if (!CBS_parse_generalized_time(&cbs, &utc, /*allow_timezone_offset=*/0)) { |
394 | 0 | BIO_puts(bp, "Bad time value"); |
395 | 0 | return 0; |
396 | 0 | } |
397 | | |
398 | 1 | return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d GMT", mon[utc.tm_mon], |
399 | 1 | utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, |
400 | 1 | utc.tm_year + 1900) > 0; |
401 | 1 | } |
402 | | |
403 | 5.62k | int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) { |
404 | 5.62k | CBS cbs; |
405 | 5.62k | CBS_init(&cbs, tm->data, tm->length); |
406 | 5.62k | struct tm utc; |
407 | 5.62k | if (!CBS_parse_utc_time(&cbs, &utc, /*allow_timezone_offset=*/0)) { |
408 | 0 | BIO_puts(bp, "Bad time value"); |
409 | 0 | return 0; |
410 | 0 | } |
411 | | |
412 | 5.62k | return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d GMT", mon[utc.tm_mon], |
413 | 5.62k | utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec, |
414 | 5.62k | utc.tm_year + 1900) > 0; |
415 | 5.62k | } |