Line data Source code
1 : /* a_mbstr.c */
2 : /*
3 : * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
4 : * 1999.
5 : */
6 : /* ====================================================================
7 : * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions
11 : * are met:
12 : *
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer.
15 : *
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in
18 : * the documentation and/or other materials provided with the
19 : * distribution.
20 : *
21 : * 3. All advertising materials mentioning features or use of this
22 : * software must display the following acknowledgment:
23 : * "This product includes software developed by the OpenSSL Project
24 : * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 : *
26 : * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 : * endorse or promote products derived from this software without
28 : * prior written permission. For written permission, please contact
29 : * licensing@OpenSSL.org.
30 : *
31 : * 5. Products derived from this software may not be called "OpenSSL"
32 : * nor may "OpenSSL" appear in their names without prior written
33 : * permission of the OpenSSL Project.
34 : *
35 : * 6. Redistributions of any form whatsoever must retain the following
36 : * acknowledgment:
37 : * "This product includes software developed by the OpenSSL Project
38 : * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 : *
40 : * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 : * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 : * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 : * OF THE POSSIBILITY OF SUCH DAMAGE.
52 : * ====================================================================
53 : *
54 : * This product includes cryptographic software written by Eric Young
55 : * (eay@cryptsoft.com). This product includes software written by Tim
56 : * Hudson (tjh@cryptsoft.com).
57 : *
58 : */
59 :
60 : #include <stdio.h>
61 : #include <ctype.h>
62 : #include "cryptlib.h"
63 : #include <openssl/asn1.h>
64 :
65 : static int traverse_string(const unsigned char *p, int len, int inform,
66 : int (*rfunc) (unsigned long value, void *in),
67 : void *arg);
68 : static int in_utf8(unsigned long value, void *arg);
69 : static int out_utf8(unsigned long value, void *arg);
70 : static int type_str(unsigned long value, void *arg);
71 : static int cpy_asc(unsigned long value, void *arg);
72 : static int cpy_bmp(unsigned long value, void *arg);
73 : static int cpy_univ(unsigned long value, void *arg);
74 : static int cpy_utf8(unsigned long value, void *arg);
75 : static int is_printable(unsigned long value);
76 :
77 : /*
78 : * These functions take a string in UTF8, ASCII or multibyte form and a mask
79 : * of permissible ASN1 string types. It then works out the minimal type
80 : * (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and
81 : * creates a string of the correct type with the supplied data. Yes this is
82 : * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
83 : * size limits too.
84 : */
85 :
86 17904 : int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
87 : int inform, unsigned long mask)
88 : {
89 17904 : return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
90 : }
91 :
92 17904 : int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
93 : int inform, unsigned long mask,
94 : long minsize, long maxsize)
95 : {
96 : int str_type;
97 : int ret;
98 : char free_out;
99 17904 : int outform, outlen = 0;
100 : ASN1_STRING *dest;
101 : unsigned char *p;
102 : int nchar;
103 : char strbuf[32];
104 : int (*cpyfunc) (unsigned long, void *) = NULL;
105 17904 : if (len == -1)
106 0 : len = strlen((const char *)in);
107 17904 : if (!mask)
108 0 : mask = DIRSTRING_TYPE;
109 :
110 : /* First do a string check and work out the number of characters */
111 17904 : switch (inform) {
112 :
113 : case MBSTRING_BMP:
114 0 : if (len & 1) {
115 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
116 : ASN1_R_INVALID_BMPSTRING_LENGTH);
117 0 : return -1;
118 : }
119 0 : nchar = len >> 1;
120 0 : break;
121 :
122 : case MBSTRING_UNIV:
123 0 : if (len & 3) {
124 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
125 : ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
126 0 : return -1;
127 : }
128 0 : nchar = len >> 2;
129 0 : break;
130 :
131 : case MBSTRING_UTF8:
132 6346 : nchar = 0;
133 : /* This counts the characters and does utf8 syntax checking */
134 6346 : ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
135 6346 : if (ret < 0) {
136 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_INVALID_UTF8STRING);
137 0 : return -1;
138 : }
139 : break;
140 :
141 : case MBSTRING_ASC:
142 11558 : nchar = len;
143 11558 : break;
144 :
145 : default:
146 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT);
147 0 : return -1;
148 : }
149 :
150 17904 : if ((minsize > 0) && (nchar < minsize)) {
151 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT);
152 0 : BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
153 0 : ERR_add_error_data(2, "minsize=", strbuf);
154 0 : return -1;
155 : }
156 :
157 17904 : if ((maxsize > 0) && (nchar > maxsize)) {
158 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG);
159 0 : BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
160 0 : ERR_add_error_data(2, "maxsize=", strbuf);
161 0 : return -1;
162 : }
163 :
164 : /* Now work out minimal type (if any) */
165 17904 : if (traverse_string(in, len, inform, type_str, &mask) < 0) {
166 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS);
167 0 : return -1;
168 : }
169 :
170 : /* Now work out output format and string type */
171 : outform = MBSTRING_ASC;
172 17904 : if (mask & B_ASN1_PRINTABLESTRING)
173 : str_type = V_ASN1_PRINTABLESTRING;
174 17904 : else if (mask & B_ASN1_IA5STRING)
175 : str_type = V_ASN1_IA5STRING;
176 17904 : else if (mask & B_ASN1_T61STRING)
177 : str_type = V_ASN1_T61STRING;
178 17904 : else if (mask & B_ASN1_BMPSTRING) {
179 : str_type = V_ASN1_BMPSTRING;
180 : outform = MBSTRING_BMP;
181 17904 : } else if (mask & B_ASN1_UNIVERSALSTRING) {
182 : str_type = V_ASN1_UNIVERSALSTRING;
183 : outform = MBSTRING_UNIV;
184 : } else {
185 : str_type = V_ASN1_UTF8STRING;
186 : outform = MBSTRING_UTF8;
187 : }
188 17904 : if (!out)
189 : return str_type;
190 17904 : if (*out) {
191 : free_out = 0;
192 : dest = *out;
193 17904 : if (dest->data) {
194 0 : dest->length = 0;
195 0 : OPENSSL_free(dest->data);
196 0 : dest->data = NULL;
197 : }
198 17904 : dest->type = str_type;
199 : } else {
200 : free_out = 1;
201 0 : dest = ASN1_STRING_type_new(str_type);
202 0 : if (!dest) {
203 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
204 0 : return -1;
205 : }
206 0 : *out = dest;
207 : }
208 : /* If both the same type just copy across */
209 17904 : if (inform == outform) {
210 6346 : if (!ASN1_STRING_set(dest, in, len)) {
211 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
212 0 : return -1;
213 : }
214 : return str_type;
215 : }
216 :
217 : /* Work out how much space the destination will need */
218 11558 : switch (outform) {
219 : case MBSTRING_ASC:
220 0 : outlen = nchar;
221 : cpyfunc = cpy_asc;
222 0 : break;
223 :
224 : case MBSTRING_BMP:
225 0 : outlen = nchar << 1;
226 : cpyfunc = cpy_bmp;
227 0 : break;
228 :
229 : case MBSTRING_UNIV:
230 0 : outlen = nchar << 2;
231 : cpyfunc = cpy_univ;
232 0 : break;
233 :
234 : case MBSTRING_UTF8:
235 11558 : outlen = 0;
236 11558 : traverse_string(in, len, inform, out_utf8, &outlen);
237 : cpyfunc = cpy_utf8;
238 11558 : break;
239 : }
240 11558 : if (!(p = OPENSSL_malloc(outlen + 1))) {
241 0 : if (free_out)
242 0 : ASN1_STRING_free(dest);
243 0 : ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
244 0 : return -1;
245 : }
246 11558 : dest->length = outlen;
247 11558 : dest->data = p;
248 11558 : p[outlen] = 0;
249 11558 : traverse_string(in, len, inform, cpyfunc, &p);
250 11558 : return str_type;
251 : }
252 :
253 : /*
254 : * This function traverses a string and passes the value of each character to
255 : * an optional function along with a void * argument.
256 : */
257 :
258 47366 : static int traverse_string(const unsigned char *p, int len, int inform,
259 : int (*rfunc) (unsigned long value, void *in),
260 : void *arg)
261 : {
262 : unsigned long value;
263 : int ret;
264 625569 : while (len) {
265 530837 : if (inform == MBSTRING_ASC) {
266 361581 : value = *p++;
267 361581 : len--;
268 169256 : } else if (inform == MBSTRING_BMP) {
269 0 : value = *p++ << 8;
270 0 : value |= *p++;
271 0 : len -= 2;
272 169256 : } else if (inform == MBSTRING_UNIV) {
273 0 : value = ((unsigned long)*p++) << 24;
274 0 : value |= ((unsigned long)*p++) << 16;
275 0 : value |= *p++ << 8;
276 0 : value |= *p++;
277 0 : len -= 4;
278 : } else {
279 169256 : ret = UTF8_getc(p, len, &value);
280 169256 : if (ret < 0)
281 : return -1;
282 169256 : len -= ret;
283 169256 : p += ret;
284 : }
285 530837 : if (rfunc) {
286 530837 : ret = rfunc(value, arg);
287 530837 : if (ret <= 0)
288 : return ret;
289 : }
290 : }
291 : return 1;
292 : }
293 :
294 : /* Various utility functions for traverse_string */
295 :
296 : /* Just count number of characters */
297 :
298 84628 : static int in_utf8(unsigned long value, void *arg)
299 : {
300 : int *nchar;
301 : nchar = arg;
302 84628 : (*nchar)++;
303 84628 : return 1;
304 : }
305 :
306 : /* Determine size of output as a UTF8 String */
307 :
308 120527 : static int out_utf8(unsigned long value, void *arg)
309 : {
310 : int *outlen;
311 : outlen = arg;
312 120527 : *outlen += UTF8_putc(NULL, -1, value);
313 120527 : return 1;
314 : }
315 :
316 : /*
317 : * Determine the "type" of a string: check each character against a supplied
318 : * "mask".
319 : */
320 :
321 205155 : static int type_str(unsigned long value, void *arg)
322 : {
323 : unsigned long types;
324 205155 : types = *((unsigned long *)arg);
325 205155 : if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
326 0 : types &= ~B_ASN1_PRINTABLESTRING;
327 205155 : if ((types & B_ASN1_IA5STRING) && (value > 127))
328 0 : types &= ~B_ASN1_IA5STRING;
329 205155 : if ((types & B_ASN1_T61STRING) && (value > 0xff))
330 0 : types &= ~B_ASN1_T61STRING;
331 205155 : if ((types & B_ASN1_BMPSTRING) && (value > 0xffff))
332 0 : types &= ~B_ASN1_BMPSTRING;
333 205155 : if (!types)
334 : return -1;
335 205155 : *((unsigned long *)arg) = types;
336 205155 : return 1;
337 : }
338 :
339 : /* Copy one byte per character ASCII like strings */
340 :
341 0 : static int cpy_asc(unsigned long value, void *arg)
342 : {
343 : unsigned char **p, *q;
344 : p = arg;
345 0 : q = *p;
346 0 : *q = (unsigned char)value;
347 0 : (*p)++;
348 0 : return 1;
349 : }
350 :
351 : /* Copy two byte per character BMPStrings */
352 :
353 0 : static int cpy_bmp(unsigned long value, void *arg)
354 : {
355 : unsigned char **p, *q;
356 : p = arg;
357 0 : q = *p;
358 0 : *q++ = (unsigned char)((value >> 8) & 0xff);
359 0 : *q = (unsigned char)(value & 0xff);
360 0 : *p += 2;
361 0 : return 1;
362 : }
363 :
364 : /* Copy four byte per character UniversalStrings */
365 :
366 0 : static int cpy_univ(unsigned long value, void *arg)
367 : {
368 : unsigned char **p, *q;
369 : p = arg;
370 0 : q = *p;
371 0 : *q++ = (unsigned char)((value >> 24) & 0xff);
372 0 : *q++ = (unsigned char)((value >> 16) & 0xff);
373 0 : *q++ = (unsigned char)((value >> 8) & 0xff);
374 0 : *q = (unsigned char)(value & 0xff);
375 0 : *p += 4;
376 0 : return 1;
377 : }
378 :
379 : /* Copy to a UTF8String */
380 :
381 120527 : static int cpy_utf8(unsigned long value, void *arg)
382 : {
383 : unsigned char **p;
384 : int ret;
385 : p = arg;
386 : /* We already know there is enough room so pass 0xff as the length */
387 120527 : ret = UTF8_putc(*p, 0xff, value);
388 120527 : *p += ret;
389 120527 : return 1;
390 : }
391 :
392 : /* Return 1 if the character is permitted in a PrintableString */
393 0 : static int is_printable(unsigned long value)
394 : {
395 : int ch;
396 0 : if (value > 0x7f)
397 : return 0;
398 0 : ch = (int)value;
399 : /*
400 : * Note: we can't use 'isalnum' because certain accented characters may
401 : * count as alphanumeric in some environments.
402 : */
403 : #ifndef CHARSET_EBCDIC
404 0 : if ((ch >= 'a') && (ch <= 'z'))
405 : return 1;
406 0 : if ((ch >= 'A') && (ch <= 'Z'))
407 : return 1;
408 0 : if ((ch >= '0') && (ch <= '9'))
409 : return 1;
410 0 : if ((ch == ' ') || strchr("'()+,-./:=?", ch))
411 : return 1;
412 : #else /* CHARSET_EBCDIC */
413 : if ((ch >= os_toascii['a']) && (ch <= os_toascii['z']))
414 : return 1;
415 : if ((ch >= os_toascii['A']) && (ch <= os_toascii['Z']))
416 : return 1;
417 : if ((ch >= os_toascii['0']) && (ch <= os_toascii['9']))
418 : return 1;
419 : if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch]))
420 : return 1;
421 : #endif /* CHARSET_EBCDIC */
422 0 : return 0;
423 : }
|