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