1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
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 (tjh@cryptsoft.com).
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 (eay@cryptsoft.com)"
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 (tjh@cryptsoft.com)"
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 "asn1_locl.h"
67 #include "../bytestring/internal.h"
68
69 static int is_printable(uint32_t value);
70
71 /*
72 * These functions take a string in UTF8, ASCII or multibyte form and a mask
73 * of permissible ASN1 string types. It then works out the minimal type
74 * (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and
75 * creates a string of the correct type with the supplied data. Yes this is
76 * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
77 * size limits too.
78 */
79
ASN1_mbstring_copy(ASN1_STRING ** out,const unsigned char * in,int len,int inform,unsigned long mask)80 int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
81 int inform, unsigned long mask)
82 {
83 return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
84 }
85
OPENSSL_DECLARE_ERROR_REASON(ASN1,INVALID_BMPSTRING)86 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_BMPSTRING)
87 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UNIVERSALSTRING)
88 OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_UTF8STRING)
89
90 int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
91 int inform, unsigned long mask,
92 long minsize, long maxsize)
93 {
94 int str_type;
95 char free_out;
96 ASN1_STRING *dest;
97 size_t nchar = 0;
98 char strbuf[32];
99 if (len == -1)
100 len = strlen((const char *)in);
101 if (!mask)
102 mask = DIRSTRING_TYPE;
103
104 int (*decode_func)(CBS *, uint32_t*);
105 int error;
106 switch (inform) {
107 case MBSTRING_BMP:
108 decode_func = cbs_get_ucs2_be;
109 error = ASN1_R_INVALID_BMPSTRING;
110 break;
111
112 case MBSTRING_UNIV:
113 decode_func = cbs_get_utf32_be;
114 error = ASN1_R_INVALID_UNIVERSALSTRING;
115 break;
116
117 case MBSTRING_UTF8:
118 decode_func = cbs_get_utf8;
119 error = ASN1_R_INVALID_UTF8STRING;
120 break;
121
122 case MBSTRING_ASC:
123 decode_func = cbs_get_latin1;
124 error = ERR_R_INTERNAL_ERROR; // Latin-1 inputs are never invalid.
125 break;
126
127 default:
128 OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT);
129 return -1;
130 }
131
132 /* Check |minsize| and |maxsize| and work out the minimal type, if any. */
133 CBS cbs;
134 CBS_init(&cbs, in, len);
135 size_t utf8_len = 0;
136 while (CBS_len(&cbs) != 0) {
137 uint32_t c;
138 if (!decode_func(&cbs, &c)) {
139 OPENSSL_PUT_ERROR(ASN1, error);
140 return -1;
141 }
142 if (nchar == 0 &&
143 (inform == MBSTRING_BMP || inform == MBSTRING_UNIV) &&
144 c == 0xfeff) {
145 /* Reject byte-order mark. We could drop it but that would mean
146 * adding ambiguity around whether a BOM was included or not when
147 * matching strings.
148 *
149 * For a little-endian UCS-2 string, the BOM will appear as 0xfffe
150 * and will be rejected as noncharacter, below. */
151 OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
152 return -1;
153 }
154
155 /* Update which output formats are still possible. */
156 if ((mask & B_ASN1_PRINTABLESTRING) && !is_printable(c)) {
157 mask &= ~B_ASN1_PRINTABLESTRING;
158 }
159 if ((mask & B_ASN1_IA5STRING) && (c > 127)) {
160 mask &= ~B_ASN1_IA5STRING;
161 }
162 if ((mask & B_ASN1_T61STRING) && (c > 0xff)) {
163 mask &= ~B_ASN1_T61STRING;
164 }
165 if ((mask & B_ASN1_BMPSTRING) && (c > 0xffff)) {
166 mask &= ~B_ASN1_BMPSTRING;
167 }
168 if (!mask) {
169 OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
170 return -1;
171 }
172
173 nchar++;
174 utf8_len += cbb_get_utf8_len(c);
175 }
176
177 if (minsize > 0 && nchar < (size_t)minsize) {
178 OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT);
179 BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
180 ERR_add_error_data(2, "minsize=", strbuf);
181 return -1;
182 }
183
184 if (maxsize > 0 && nchar > (size_t)maxsize) {
185 OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
186 BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
187 ERR_add_error_data(2, "maxsize=", strbuf);
188 return -1;
189 }
190
191 /* Now work out output format and string type */
192 int (*encode_func)(CBB *, uint32_t) = cbb_add_latin1;
193 size_t size_estimate = nchar;
194 int outform = MBSTRING_ASC;
195 if (mask & B_ASN1_PRINTABLESTRING) {
196 str_type = V_ASN1_PRINTABLESTRING;
197 } else if (mask & B_ASN1_IA5STRING) {
198 str_type = V_ASN1_IA5STRING;
199 } else if (mask & B_ASN1_T61STRING) {
200 str_type = V_ASN1_T61STRING;
201 } else if (mask & B_ASN1_BMPSTRING) {
202 str_type = V_ASN1_BMPSTRING;
203 outform = MBSTRING_BMP;
204 encode_func = cbb_add_ucs2_be;
205 size_estimate = 2 * nchar;
206 } else if (mask & B_ASN1_UNIVERSALSTRING) {
207 str_type = V_ASN1_UNIVERSALSTRING;
208 encode_func = cbb_add_utf32_be;
209 size_estimate = 4 * nchar;
210 outform = MBSTRING_UNIV;
211 } else {
212 str_type = V_ASN1_UTF8STRING;
213 outform = MBSTRING_UTF8;
214 encode_func = cbb_add_utf8;
215 size_estimate = utf8_len;
216 }
217
218 if (!out)
219 return str_type;
220 if (*out) {
221 free_out = 0;
222 dest = *out;
223 if (dest->data) {
224 dest->length = 0;
225 OPENSSL_free(dest->data);
226 dest->data = NULL;
227 }
228 dest->type = str_type;
229 } else {
230 free_out = 1;
231 dest = ASN1_STRING_type_new(str_type);
232 if (!dest) {
233 OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
234 return -1;
235 }
236 *out = dest;
237 }
238
239 /* If both the same type just copy across */
240 if (inform == outform) {
241 if (!ASN1_STRING_set(dest, in, len)) {
242 OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
243 return -1;
244 }
245 return str_type;
246 }
247
248 CBB cbb;
249 if (!CBB_init(&cbb, size_estimate + 1)) {
250 OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
251 goto err;
252 }
253 CBS_init(&cbs, in, len);
254 while (CBS_len(&cbs) != 0) {
255 uint32_t c;
256 if (!decode_func(&cbs, &c) ||
257 !encode_func(&cbb, c)) {
258 OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
259 goto err;
260 }
261 }
262 uint8_t *data = NULL;
263 size_t data_len;
264 if (/* OpenSSL historically NUL-terminated this value with a single byte,
265 * even for |MBSTRING_BMP| and |MBSTRING_UNIV|. */
266 !CBB_add_u8(&cbb, 0) ||
267 !CBB_finish(&cbb, &data, &data_len) ||
268 data_len < 1 ||
269 data_len > INT_MAX) {
270 OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
271 OPENSSL_free(data);
272 goto err;
273 }
274 dest->length = (int)(data_len - 1);
275 dest->data = data;
276 return str_type;
277
278 err:
279 if (free_out)
280 ASN1_STRING_free(dest);
281 CBB_cleanup(&cbb);
282 return -1;
283 }
284
285 /* Return 1 if the character is permitted in a PrintableString */
is_printable(uint32_t value)286 static int is_printable(uint32_t value)
287 {
288 int ch;
289 if (value > 0x7f)
290 return 0;
291 ch = (int)value;
292 /*
293 * Note: we can't use 'isalnum' because certain accented characters may
294 * count as alphanumeric in some environments.
295 */
296 if ((ch >= 'a') && (ch <= 'z'))
297 return 1;
298 if ((ch >= 'A') && (ch <= 'Z'))
299 return 1;
300 if ((ch >= '0') && (ch <= '9'))
301 return 1;
302 if ((ch == ' ') || strchr("'()+,-./:=?", ch))
303 return 1;
304 return 0;
305 }
306