xref: /aosp_15_r20/external/cronet/third_party/boringssl/src/crypto/asn1/a_strex.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* Copyright (C) 1995-1998 Eric Young ([email protected])
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young ([email protected]).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson ([email protected]).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young ([email protected])"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson ([email protected])"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.] */
56 
57 #include <openssl/asn1.h>
58 
59 #include <assert.h>
60 #include <ctype.h>
61 #include <inttypes.h>
62 #include <limits.h>
63 #include <string.h>
64 #include <time.h>
65 
66 #include <openssl/bio.h>
67 #include <openssl/bytestring.h>
68 #include <openssl/mem.h>
69 
70 #include "../bytestring/internal.h"
71 #include "../internal.h"
72 #include "internal.h"
73 
74 
75 #define ESC_FLAGS                                                           \
76   (ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_QUOTE | ASN1_STRFLGS_ESC_CTRL | \
77    ASN1_STRFLGS_ESC_MSB)
78 
maybe_write(BIO * out,const void * buf,int len)79 static int maybe_write(BIO *out, const void *buf, int len) {
80   // If |out| is NULL, ignore the output but report the length.
81   return out == NULL || BIO_write(out, buf, len) == len;
82 }
83 
is_control_character(unsigned char c)84 static int is_control_character(unsigned char c) { return c < 32 || c == 127; }
85 
do_esc_char(uint32_t c,unsigned long flags,char * do_quotes,BIO * out,int is_first,int is_last)86 static int do_esc_char(uint32_t c, unsigned long flags, char *do_quotes,
87                        BIO *out, int is_first, int is_last) {
88   // |c| is a |uint32_t| because, depending on |ASN1_STRFLGS_UTF8_CONVERT|,
89   // we may be escaping bytes or Unicode codepoints.
90   char buf[16];  // Large enough for "\\W01234567".
91   unsigned char u8 = (unsigned char)c;
92   if (c > 0xffff) {
93     snprintf(buf, sizeof(buf), "\\W%08" PRIX32, c);
94   } else if (c > 0xff) {
95     snprintf(buf, sizeof(buf), "\\U%04" PRIX32, c);
96   } else if ((flags & ASN1_STRFLGS_ESC_MSB) && c > 0x7f) {
97     snprintf(buf, sizeof(buf), "\\%02X", c);
98   } else if ((flags & ASN1_STRFLGS_ESC_CTRL) && is_control_character(c)) {
99     snprintf(buf, sizeof(buf), "\\%02X", c);
100   } else if (flags & ASN1_STRFLGS_ESC_2253) {
101     // See RFC 2253, sections 2.4 and 4.
102     if (c == '\\' || c == '"') {
103       // Quotes and backslashes are always escaped, quoted or not.
104       snprintf(buf, sizeof(buf), "\\%c", (int)c);
105     } else if (c == ',' || c == '+' || c == '<' || c == '>' || c == ';' ||
106                (is_first && (c == ' ' || c == '#')) ||
107                (is_last && (c == ' '))) {
108       if (flags & ASN1_STRFLGS_ESC_QUOTE) {
109         // No need to escape, just tell the caller to quote.
110         if (do_quotes != NULL) {
111           *do_quotes = 1;
112         }
113         return maybe_write(out, &u8, 1) ? 1 : -1;
114       }
115       snprintf(buf, sizeof(buf), "\\%c", (int)c);
116     } else {
117       return maybe_write(out, &u8, 1) ? 1 : -1;
118     }
119   } else if ((flags & ESC_FLAGS) && c == '\\') {
120     // If any escape flags are set, also escape backslashes.
121     snprintf(buf, sizeof(buf), "\\%c", (int)c);
122   } else {
123     return maybe_write(out, &u8, 1) ? 1 : -1;
124   }
125 
126   static_assert(sizeof(buf) < INT_MAX, "len may not fit in int");
127   int len = (int)strlen(buf);
128   return maybe_write(out, buf, len) ? len : -1;
129 }
130 
131 // This function sends each character in a buffer to do_esc_char(). It
132 // interprets the content formats and converts to or from UTF8 as
133 // appropriate.
134 
do_buf(const unsigned char * buf,int buflen,int encoding,unsigned long flags,char * quotes,BIO * out)135 static int do_buf(const unsigned char *buf, int buflen, int encoding,
136                   unsigned long flags, char *quotes, BIO *out) {
137   int (*get_char)(CBS *cbs, uint32_t *out);
138   int get_char_error;
139   switch (encoding) {
140     case MBSTRING_UNIV:
141       get_char = CBS_get_utf32_be;
142       get_char_error = ASN1_R_INVALID_UNIVERSALSTRING;
143       break;
144     case MBSTRING_BMP:
145       get_char = CBS_get_ucs2_be;
146       get_char_error = ASN1_R_INVALID_BMPSTRING;
147       break;
148     case MBSTRING_ASC:
149       get_char = CBS_get_latin1;
150       get_char_error = ERR_R_INTERNAL_ERROR;  // Should not be possible.
151       break;
152     case MBSTRING_UTF8:
153       get_char = CBS_get_utf8;
154       get_char_error = ASN1_R_INVALID_UTF8STRING;
155       break;
156     default:
157       assert(0);
158       return -1;
159   }
160 
161   CBS cbs;
162   CBS_init(&cbs, buf, buflen);
163   int outlen = 0;
164   while (CBS_len(&cbs) != 0) {
165     const int is_first = CBS_data(&cbs) == buf;
166     uint32_t c;
167     if (!get_char(&cbs, &c)) {
168       OPENSSL_PUT_ERROR(ASN1, get_char_error);
169       return -1;
170     }
171     const int is_last = CBS_len(&cbs) == 0;
172     if (flags & ASN1_STRFLGS_UTF8_CONVERT) {
173       uint8_t utf8_buf[6];
174       CBB utf8_cbb;
175       CBB_init_fixed(&utf8_cbb, utf8_buf, sizeof(utf8_buf));
176       if (!CBB_add_utf8(&utf8_cbb, c)) {
177         OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
178         return 1;
179       }
180       size_t utf8_len = CBB_len(&utf8_cbb);
181       for (size_t i = 0; i < utf8_len; i++) {
182         int len = do_esc_char(utf8_buf[i], flags, quotes, out,
183                               is_first && i == 0, is_last && i == utf8_len - 1);
184         if (len < 0) {
185           return -1;
186         }
187         outlen += len;
188       }
189     } else {
190       int len = do_esc_char(c, flags, quotes, out, is_first, is_last);
191       if (len < 0) {
192         return -1;
193       }
194       outlen += len;
195     }
196   }
197   return outlen;
198 }
199 
200 // This function hex dumps a buffer of characters
201 
do_hex_dump(BIO * out,unsigned char * buf,int buflen)202 static int do_hex_dump(BIO *out, unsigned char *buf, int buflen) {
203   static const char hexdig[] = "0123456789ABCDEF";
204   unsigned char *p, *q;
205   char hextmp[2];
206   if (out) {
207     p = buf;
208     q = buf + buflen;
209     while (p != q) {
210       hextmp[0] = hexdig[*p >> 4];
211       hextmp[1] = hexdig[*p & 0xf];
212       if (!maybe_write(out, hextmp, 2)) {
213         return -1;
214       }
215       p++;
216     }
217   }
218   return buflen << 1;
219 }
220 
221 // "dump" a string. This is done when the type is unknown, or the flags
222 // request it. We can either dump the content octets or the entire DER
223 // encoding. This uses the RFC 2253 #01234 format.
224 
do_dump(unsigned long flags,BIO * out,const ASN1_STRING * str)225 static int do_dump(unsigned long flags, BIO *out, const ASN1_STRING *str) {
226   if (!maybe_write(out, "#", 1)) {
227     return -1;
228   }
229 
230   // If we don't dump DER encoding just dump content octets
231   if (!(flags & ASN1_STRFLGS_DUMP_DER)) {
232     int outlen = do_hex_dump(out, str->data, str->length);
233     if (outlen < 0) {
234       return -1;
235     }
236     return outlen + 1;
237   }
238 
239   // Placing the ASN1_STRING in a temporary ASN1_TYPE allows the DER encoding
240   // to readily obtained.
241   ASN1_TYPE t;
242   OPENSSL_memset(&t, 0, sizeof(ASN1_TYPE));
243   asn1_type_set0_string(&t, (ASN1_STRING *)str);
244   unsigned char *der_buf = NULL;
245   int der_len = i2d_ASN1_TYPE(&t, &der_buf);
246   if (der_len < 0) {
247     return -1;
248   }
249   int outlen = do_hex_dump(out, der_buf, der_len);
250   OPENSSL_free(der_buf);
251   if (outlen < 0) {
252     return -1;
253   }
254   return outlen + 1;
255 }
256 
257 // string_type_to_encoding returns the |MBSTRING_*| constant for the encoding
258 // used by the |ASN1_STRING| type |type|, or -1 if |tag| is not a string
259 // type.
string_type_to_encoding(int type)260 static int string_type_to_encoding(int type) {
261   // This function is sometimes passed ASN.1 universal types and sometimes
262   // passed |ASN1_STRING| type values
263   switch (type) {
264     case V_ASN1_UTF8STRING:
265       return MBSTRING_UTF8;
266     case V_ASN1_NUMERICSTRING:
267     case V_ASN1_PRINTABLESTRING:
268     case V_ASN1_T61STRING:
269     case V_ASN1_IA5STRING:
270     case V_ASN1_UTCTIME:
271     case V_ASN1_GENERALIZEDTIME:
272     case V_ASN1_ISO64STRING:
273       // |MBSTRING_ASC| refers to Latin-1, not ASCII.
274       return MBSTRING_ASC;
275     case V_ASN1_UNIVERSALSTRING:
276       return MBSTRING_UNIV;
277     case V_ASN1_BMPSTRING:
278       return MBSTRING_BMP;
279   }
280   return -1;
281 }
282 
283 // This is the main function, print out an ASN1_STRING taking note of various
284 // escape and display options. Returns number of characters written or -1 if
285 // an error occurred.
286 
ASN1_STRING_print_ex(BIO * out,const ASN1_STRING * str,unsigned long flags)287 int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str,
288                          unsigned long flags) {
289   int type = str->type;
290   int outlen = 0;
291   if (flags & ASN1_STRFLGS_SHOW_TYPE) {
292     const char *tagname = ASN1_tag2str(type);
293     outlen += strlen(tagname);
294     if (!maybe_write(out, tagname, outlen) || !maybe_write(out, ":", 1)) {
295       return -1;
296     }
297     outlen++;
298   }
299 
300   // Decide what to do with |str|, either dump the contents or display it.
301   int encoding;
302   if (flags & ASN1_STRFLGS_DUMP_ALL) {
303     // Dump everything.
304     encoding = -1;
305   } else if (flags & ASN1_STRFLGS_IGNORE_TYPE) {
306     // Ignore the string type and interpret the contents as Latin-1.
307     encoding = MBSTRING_ASC;
308   } else {
309     encoding = string_type_to_encoding(type);
310     if (encoding == -1 && (flags & ASN1_STRFLGS_DUMP_UNKNOWN) == 0) {
311       encoding = MBSTRING_ASC;
312     }
313   }
314 
315   if (encoding == -1) {
316     int len = do_dump(flags, out, str);
317     if (len < 0) {
318       return -1;
319     }
320     outlen += len;
321     return outlen;
322   }
323 
324   // Measure the length.
325   char quotes = 0;
326   int len = do_buf(str->data, str->length, encoding, flags, &quotes, NULL);
327   if (len < 0) {
328     return -1;
329   }
330   outlen += len;
331   if (quotes) {
332     outlen += 2;
333   }
334   if (!out) {
335     return outlen;
336   }
337 
338   // Encode the value.
339   if ((quotes && !maybe_write(out, "\"", 1)) ||
340       do_buf(str->data, str->length, encoding, flags, NULL, out) < 0 ||
341       (quotes && !maybe_write(out, "\"", 1))) {
342     return -1;
343   }
344   return outlen;
345 }
346 
ASN1_STRING_print_ex_fp(FILE * fp,const ASN1_STRING * str,unsigned long flags)347 int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str,
348                             unsigned long flags) {
349   BIO *bio = NULL;
350   if (fp != NULL) {
351     // If |fp| is NULL, this function returns the number of bytes without
352     // writing.
353     bio = BIO_new_fp(fp, BIO_NOCLOSE);
354     if (bio == NULL) {
355       return -1;
356     }
357   }
358   int ret = ASN1_STRING_print_ex(bio, str, flags);
359   BIO_free(bio);
360   return ret;
361 }
362 
ASN1_STRING_to_UTF8(unsigned char ** out,const ASN1_STRING * in)363 int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in) {
364   if (!in) {
365     return -1;
366   }
367   int mbflag = string_type_to_encoding(in->type);
368   if (mbflag == -1) {
369     OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_TAG);
370     return -1;
371   }
372   ASN1_STRING stmp, *str = &stmp;
373   stmp.data = NULL;
374   stmp.length = 0;
375   stmp.flags = 0;
376   int ret =
377       ASN1_mbstring_copy(&str, in->data, in->length, mbflag, B_ASN1_UTF8STRING);
378   if (ret < 0) {
379     return ret;
380   }
381   *out = stmp.data;
382   return stmp.length;
383 }
384 
ASN1_STRING_print(BIO * bp,const ASN1_STRING * v)385 int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v) {
386   int i, n;
387   char buf[80];
388   const char *p;
389 
390   if (v == NULL) {
391     return 0;
392   }
393   n = 0;
394   p = (const char *)v->data;
395   for (i = 0; i < v->length; i++) {
396     if ((p[i] > '~') || ((p[i] < ' ') && (p[i] != '\n') && (p[i] != '\r'))) {
397       buf[n] = '.';
398     } else {
399       buf[n] = p[i];
400     }
401     n++;
402     if (n >= 80) {
403       if (BIO_write(bp, buf, n) <= 0) {
404         return 0;
405       }
406       n = 0;
407     }
408   }
409   if (n > 0) {
410     if (BIO_write(bp, buf, n) <= 0) {
411       return 0;
412     }
413   }
414   return 1;
415 }
416 
ASN1_TIME_print(BIO * bp,const ASN1_TIME * tm)417 int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) {
418   if (tm->type == V_ASN1_UTCTIME) {
419     return ASN1_UTCTIME_print(bp, tm);
420   }
421   if (tm->type == V_ASN1_GENERALIZEDTIME) {
422     return ASN1_GENERALIZEDTIME_print(bp, tm);
423   }
424   BIO_puts(bp, "Bad time value");
425   return 0;
426 }
427 
428 static const char *const mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
429                                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
430 
ASN1_GENERALIZEDTIME_print(BIO * bp,const ASN1_GENERALIZEDTIME * tm)431 int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm) {
432   CBS cbs;
433   CBS_init(&cbs, tm->data, tm->length);
434   struct tm utc;
435   if (!CBS_parse_generalized_time(&cbs, &utc, /*allow_timezone_offset=*/0)) {
436     BIO_puts(bp, "Bad time value");
437     return 0;
438   }
439 
440   return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d GMT", mon[utc.tm_mon],
441                     utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec,
442                     utc.tm_year + 1900) > 0;
443 }
444 
ASN1_UTCTIME_print(BIO * bp,const ASN1_UTCTIME * tm)445 int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) {
446   CBS cbs;
447   CBS_init(&cbs, tm->data, tm->length);
448   struct tm utc;
449   if (!CBS_parse_utc_time(&cbs, &utc, /*allow_timezone_offset=*/0)) {
450     BIO_puts(bp, "Bad time value");
451     return 0;
452   }
453 
454   return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d GMT", mon[utc.tm_mon],
455                     utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec,
456                     utc.tm_year + 1900) > 0;
457 }
458