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