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 | |
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 | |
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 */ |
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 | |