xref: /aosp_15_r20/external/cronet/third_party/boringssl/src/crypto/asn1/a_mbstr.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 <limits.h>
60 #include <string.h>
61 
62 #include <openssl/bytestring.h>
63 #include <openssl/err.h>
64 #include <openssl/mem.h>
65 
66 #include "../bytestring/internal.h"
67 #include "internal.h"
68 
69 // These functions take a string in UTF8, ASCII or multibyte form and a mask
70 // of permissible ASN1 string types. It then works out the minimal type
71 // (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and
72 // creates a string of the correct type with the supplied data. Yes this is
73 // horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
74 // size limits too.
75 
ASN1_mbstring_copy(ASN1_STRING ** out,const unsigned char * in,ossl_ssize_t len,int inform,unsigned long mask)76 int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in,
77                        ossl_ssize_t len, int inform, unsigned long mask) {
78   return ASN1_mbstring_ncopy(out, in, len, inform, mask, /*minsize=*/0,
79                              /*maxsize=*/0);
80 }
81 
OPENSSL_DECLARE_ERROR_REASON(ASN1,INVALID_BMPSTRING)82 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_BMPSTRING)
83 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UNIVERSALSTRING)
84 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UTF8STRING)
85 
86 int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in,
87                         ossl_ssize_t len, int inform, unsigned long mask,
88                         ossl_ssize_t minsize, ossl_ssize_t maxsize) {
89   if (len == -1) {
90     len = strlen((const char *)in);
91   }
92   if (!mask) {
93     mask = DIRSTRING_TYPE;
94   }
95 
96   int (*decode_func)(CBS *, uint32_t *);
97   int error;
98   switch (inform) {
99     case MBSTRING_BMP:
100       decode_func = CBS_get_ucs2_be;
101       error = ASN1_R_INVALID_BMPSTRING;
102       break;
103 
104     case MBSTRING_UNIV:
105       decode_func = CBS_get_utf32_be;
106       error = ASN1_R_INVALID_UNIVERSALSTRING;
107       break;
108 
109     case MBSTRING_UTF8:
110       decode_func = CBS_get_utf8;
111       error = ASN1_R_INVALID_UTF8STRING;
112       break;
113 
114     case MBSTRING_ASC:
115       decode_func = CBS_get_latin1;
116       error = ERR_R_INTERNAL_ERROR;  // Latin-1 inputs are never invalid.
117       break;
118 
119     default:
120       OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT);
121       return -1;
122   }
123 
124   // Check |minsize| and |maxsize| and work out the minimal type, if any.
125   CBS cbs;
126   CBS_init(&cbs, in, len);
127   size_t utf8_len = 0, nchar = 0;
128   while (CBS_len(&cbs) != 0) {
129     uint32_t c;
130     if (!decode_func(&cbs, &c)) {
131       OPENSSL_PUT_ERROR(ASN1, error);
132       return -1;
133     }
134     if (nchar == 0 && (inform == MBSTRING_BMP || inform == MBSTRING_UNIV) &&
135         c == 0xfeff) {
136       // Reject byte-order mark. We could drop it but that would mean
137       // adding ambiguity around whether a BOM was included or not when
138       // matching strings.
139       //
140       // For a little-endian UCS-2 string, the BOM will appear as 0xfffe
141       // and will be rejected as noncharacter, below.
142       OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
143       return -1;
144     }
145 
146     // Update which output formats are still possible.
147     if ((mask & B_ASN1_PRINTABLESTRING) && !asn1_is_printable(c)) {
148       mask &= ~B_ASN1_PRINTABLESTRING;
149     }
150     if ((mask & B_ASN1_IA5STRING) && (c > 127)) {
151       mask &= ~B_ASN1_IA5STRING;
152     }
153     if ((mask & B_ASN1_T61STRING) && (c > 0xff)) {
154       mask &= ~B_ASN1_T61STRING;
155     }
156     if ((mask & B_ASN1_BMPSTRING) && (c > 0xffff)) {
157       mask &= ~B_ASN1_BMPSTRING;
158     }
159     if (!mask) {
160       OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
161       return -1;
162     }
163 
164     nchar++;
165     utf8_len += CBB_get_utf8_len(c);
166     if (maxsize > 0 && nchar > (size_t)maxsize) {
167       OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
168       ERR_add_error_dataf("maxsize=%zu", (size_t)maxsize);
169       return -1;
170     }
171   }
172 
173   if (minsize > 0 && nchar < (size_t)minsize) {
174     OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT);
175     ERR_add_error_dataf("minsize=%zu", (size_t)minsize);
176     return -1;
177   }
178 
179   // Now work out output format and string type
180   int str_type;
181   int (*encode_func)(CBB *, uint32_t) = CBB_add_latin1;
182   size_t size_estimate = nchar;
183   int outform = MBSTRING_ASC;
184   if (mask & B_ASN1_PRINTABLESTRING) {
185     str_type = V_ASN1_PRINTABLESTRING;
186   } else if (mask & B_ASN1_IA5STRING) {
187     str_type = V_ASN1_IA5STRING;
188   } else if (mask & B_ASN1_T61STRING) {
189     str_type = V_ASN1_T61STRING;
190   } else if (mask & B_ASN1_BMPSTRING) {
191     str_type = V_ASN1_BMPSTRING;
192     outform = MBSTRING_BMP;
193     encode_func = CBB_add_ucs2_be;
194     size_estimate = 2 * nchar;
195   } else if (mask & B_ASN1_UNIVERSALSTRING) {
196     str_type = V_ASN1_UNIVERSALSTRING;
197     encode_func = CBB_add_utf32_be;
198     size_estimate = 4 * nchar;
199     outform = MBSTRING_UNIV;
200   } else if (mask & B_ASN1_UTF8STRING) {
201     str_type = V_ASN1_UTF8STRING;
202     outform = MBSTRING_UTF8;
203     encode_func = CBB_add_utf8;
204     size_estimate = utf8_len;
205   } else {
206     OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
207     return -1;
208   }
209 
210   if (!out) {
211     return str_type;
212   }
213 
214   int free_dest = 0;
215   ASN1_STRING *dest;
216   if (*out) {
217     dest = *out;
218   } else {
219     free_dest = 1;
220     dest = ASN1_STRING_type_new(str_type);
221     if (!dest) {
222       return -1;
223     }
224   }
225 
226   CBB cbb;
227   CBB_zero(&cbb);
228   // If both the same type just copy across
229   if (inform == outform) {
230     if (!ASN1_STRING_set(dest, in, len)) {
231       goto err;
232     }
233     dest->type = str_type;
234     *out = dest;
235     return str_type;
236   }
237   if (!CBB_init(&cbb, size_estimate + 1)) {
238     goto err;
239   }
240   CBS_init(&cbs, in, len);
241   while (CBS_len(&cbs) != 0) {
242     uint32_t c;
243     if (!decode_func(&cbs, &c) || !encode_func(&cbb, c)) {
244       OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
245       goto err;
246     }
247   }
248   uint8_t *data = NULL;
249   size_t data_len;
250   if (// OpenSSL historically NUL-terminated this value with a single byte,
251       // even for |MBSTRING_BMP| and |MBSTRING_UNIV|.
252       !CBB_add_u8(&cbb, 0) || !CBB_finish(&cbb, &data, &data_len) ||
253       data_len < 1 || data_len > INT_MAX) {
254     OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
255     OPENSSL_free(data);
256     goto err;
257   }
258   dest->type = str_type;
259   ASN1_STRING_set0(dest, data, (int)data_len - 1);
260   *out = dest;
261   return str_type;
262 
263 err:
264   if (free_dest) {
265     ASN1_STRING_free(dest);
266   }
267   CBB_cleanup(&cbb);
268   return -1;
269 }
270 
asn1_is_printable(uint32_t value)271 int asn1_is_printable(uint32_t value) {
272   if (value > 0x7f) {
273     return 0;
274   }
275   return OPENSSL_isalnum(value) || //
276          value == ' ' || value == '\'' || value == '(' || value == ')' ||
277          value == '+' || value == ',' || value == '-' || value == '.' ||
278          value == '/' || value == ':' || value == '=' || value == '?';
279 }
280