Continue standardising malloc style for libcrypto
[openssl.git] / crypto / asn1 / a_mbstr.c
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 "internal/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_numeric(unsigned long value);
76 static int is_printable(unsigned long value);
77
78 /*
79  * These functions take a string in UTF8, ASCII or multibyte form and a mask
80  * of permissible ASN1 string types. It then works out the minimal type
81  * (using the order Numeric < Printable < IA5 < T61 < BMP < Universal < UTF8)
82  * and creates a string of the correct type with the supplied data. Yes this is
83  * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
84  * size limits too.
85  */
86
87 int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
88                        int inform, unsigned long mask)
89 {
90     return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
91 }
92
93 int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
94                         int inform, unsigned long mask,
95                         long minsize, long maxsize)
96 {
97     int str_type;
98     int ret;
99     char free_out;
100     int outform, outlen = 0;
101     ASN1_STRING *dest;
102     unsigned char *p;
103     int nchar;
104     char strbuf[32];
105     int (*cpyfunc) (unsigned long, void *) = NULL;
106     if (len == -1)
107         len = strlen((const char *)in);
108     if (!mask)
109         mask = DIRSTRING_TYPE;
110
111     /* First do a string check and work out the number of characters */
112     switch (inform) {
113
114     case MBSTRING_BMP:
115         if (len & 1) {
116             ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
117                     ASN1_R_INVALID_BMPSTRING_LENGTH);
118             return -1;
119         }
120         nchar = len >> 1;
121         break;
122
123     case MBSTRING_UNIV:
124         if (len & 3) {
125             ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
126                     ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
127             return -1;
128         }
129         nchar = len >> 2;
130         break;
131
132     case MBSTRING_UTF8:
133         nchar = 0;
134         /* This counts the characters and does utf8 syntax checking */
135         ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
136         if (ret < 0) {
137             ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_INVALID_UTF8STRING);
138             return -1;
139         }
140         break;
141
142     case MBSTRING_ASC:
143         nchar = len;
144         break;
145
146     default:
147         ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT);
148         return -1;
149     }
150
151     if ((minsize > 0) && (nchar < minsize)) {
152         ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT);
153         BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
154         ERR_add_error_data(2, "minsize=", strbuf);
155         return -1;
156     }
157
158     if ((maxsize > 0) && (nchar > maxsize)) {
159         ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG);
160         BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
161         ERR_add_error_data(2, "maxsize=", strbuf);
162         return -1;
163     }
164
165     /* Now work out minimal type (if any) */
166     if (traverse_string(in, len, inform, type_str, &mask) < 0) {
167         ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS);
168         return -1;
169     }
170
171     /* Now work out output format and string type */
172     outform = MBSTRING_ASC;
173     if (mask & B_ASN1_NUMERICSTRING)
174         str_type = V_ASN1_NUMERICSTRING;
175     else if (mask & B_ASN1_PRINTABLESTRING)
176         str_type = V_ASN1_PRINTABLESTRING;
177     else if (mask & B_ASN1_IA5STRING)
178         str_type = V_ASN1_IA5STRING;
179     else if (mask & B_ASN1_T61STRING)
180         str_type = V_ASN1_T61STRING;
181     else if (mask & B_ASN1_BMPSTRING) {
182         str_type = V_ASN1_BMPSTRING;
183         outform = MBSTRING_BMP;
184     } else if (mask & B_ASN1_UNIVERSALSTRING) {
185         str_type = V_ASN1_UNIVERSALSTRING;
186         outform = MBSTRING_UNIV;
187     } else {
188         str_type = V_ASN1_UTF8STRING;
189         outform = MBSTRING_UTF8;
190     }
191     if (!out)
192         return str_type;
193     if (*out) {
194         free_out = 0;
195         dest = *out;
196         OPENSSL_free(dest->data);
197         dest->data = NULL;
198         dest->length = 0;
199         dest->type = str_type;
200     } else {
201         free_out = 1;
202         dest = ASN1_STRING_type_new(str_type);
203         if (dest == NULL) {
204             ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
205             return -1;
206         }
207         *out = dest;
208     }
209     /* If both the same type just copy across */
210     if (inform == outform) {
211         if (!ASN1_STRING_set(dest, in, len)) {
212             ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
213             return -1;
214         }
215         return str_type;
216     }
217
218     /* Work out how much space the destination will need */
219     switch (outform) {
220     case MBSTRING_ASC:
221         outlen = nchar;
222         cpyfunc = cpy_asc;
223         break;
224
225     case MBSTRING_BMP:
226         outlen = nchar << 1;
227         cpyfunc = cpy_bmp;
228         break;
229
230     case MBSTRING_UNIV:
231         outlen = nchar << 2;
232         cpyfunc = cpy_univ;
233         break;
234
235     case MBSTRING_UTF8:
236         outlen = 0;
237         traverse_string(in, len, inform, out_utf8, &outlen);
238         cpyfunc = cpy_utf8;
239         break;
240     }
241     if ((p = OPENSSL_malloc(outlen + 1)) == NULL) {
242         if (free_out)
243             ASN1_STRING_free(dest);
244         ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
245         return -1;
246     }
247     dest->length = outlen;
248     dest->data = p;
249     p[outlen] = 0;
250     traverse_string(in, len, inform, cpyfunc, &p);
251     return str_type;
252 }
253
254 /*
255  * This function traverses a string and passes the value of each character to
256  * an optional function along with a void * argument.
257  */
258
259 static int traverse_string(const unsigned char *p, int len, int inform,
260                            int (*rfunc) (unsigned long value, void *in),
261                            void *arg)
262 {
263     unsigned long value;
264     int ret;
265     while (len) {
266         if (inform == MBSTRING_ASC) {
267             value = *p++;
268             len--;
269         } else if (inform == MBSTRING_BMP) {
270             value = *p++ << 8;
271             value |= *p++;
272             len -= 2;
273         } else if (inform == MBSTRING_UNIV) {
274             value = ((unsigned long)*p++) << 24;
275             value |= ((unsigned long)*p++) << 16;
276             value |= *p++ << 8;
277             value |= *p++;
278             len -= 4;
279         } else {
280             ret = UTF8_getc(p, len, &value);
281             if (ret < 0)
282                 return -1;
283             len -= ret;
284             p += ret;
285         }
286         if (rfunc) {
287             ret = rfunc(value, arg);
288             if (ret <= 0)
289                 return ret;
290         }
291     }
292     return 1;
293 }
294
295 /* Various utility functions for traverse_string */
296
297 /* Just count number of characters */
298
299 static int in_utf8(unsigned long value, void *arg)
300 {
301     int *nchar;
302     nchar = arg;
303     (*nchar)++;
304     return 1;
305 }
306
307 /* Determine size of output as a UTF8 String */
308
309 static int out_utf8(unsigned long value, void *arg)
310 {
311     int *outlen;
312     outlen = arg;
313     *outlen += UTF8_putc(NULL, -1, value);
314     return 1;
315 }
316
317 /*
318  * Determine the "type" of a string: check each character against a supplied
319  * "mask".
320  */
321
322 static int type_str(unsigned long value, void *arg)
323 {
324     unsigned long types;
325     types = *((unsigned long *)arg);
326     if ((types & B_ASN1_NUMERICSTRING) && !is_numeric(value))
327         types &= ~B_ASN1_NUMERICSTRING;
328     if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
329         types &= ~B_ASN1_PRINTABLESTRING;
330     if ((types & B_ASN1_IA5STRING) && (value > 127))
331         types &= ~B_ASN1_IA5STRING;
332     if ((types & B_ASN1_T61STRING) && (value > 0xff))
333         types &= ~B_ASN1_T61STRING;
334     if ((types & B_ASN1_BMPSTRING) && (value > 0xffff))
335         types &= ~B_ASN1_BMPSTRING;
336     if (!types)
337         return -1;
338     *((unsigned long *)arg) = types;
339     return 1;
340 }
341
342 /* Copy one byte per character ASCII like strings */
343
344 static int cpy_asc(unsigned long value, void *arg)
345 {
346     unsigned char **p, *q;
347     p = arg;
348     q = *p;
349     *q = (unsigned char)value;
350     (*p)++;
351     return 1;
352 }
353
354 /* Copy two byte per character BMPStrings */
355
356 static int cpy_bmp(unsigned long value, void *arg)
357 {
358     unsigned char **p, *q;
359     p = arg;
360     q = *p;
361     *q++ = (unsigned char)((value >> 8) & 0xff);
362     *q = (unsigned char)(value & 0xff);
363     *p += 2;
364     return 1;
365 }
366
367 /* Copy four byte per character UniversalStrings */
368
369 static int cpy_univ(unsigned long value, void *arg)
370 {
371     unsigned char **p, *q;
372     p = arg;
373     q = *p;
374     *q++ = (unsigned char)((value >> 24) & 0xff);
375     *q++ = (unsigned char)((value >> 16) & 0xff);
376     *q++ = (unsigned char)((value >> 8) & 0xff);
377     *q = (unsigned char)(value & 0xff);
378     *p += 4;
379     return 1;
380 }
381
382 /* Copy to a UTF8String */
383
384 static int cpy_utf8(unsigned long value, void *arg)
385 {
386     unsigned char **p;
387     int ret;
388     p = arg;
389     /* We already know there is enough room so pass 0xff as the length */
390     ret = UTF8_putc(*p, 0xff, value);
391     *p += ret;
392     return 1;
393 }
394
395 /* Return 1 if the character is permitted in a PrintableString */
396 static int is_printable(unsigned long value)
397 {
398     int ch;
399     if (value > 0x7f)
400         return 0;
401     ch = (int)value;
402     /*
403      * Note: we can't use 'isalnum' because certain accented characters may
404      * count as alphanumeric in some environments.
405      */
406 #ifndef CHARSET_EBCDIC
407     if ((ch >= 'a') && (ch <= 'z'))
408         return 1;
409     if ((ch >= 'A') && (ch <= 'Z'))
410         return 1;
411     if ((ch >= '0') && (ch <= '9'))
412         return 1;
413     if ((ch == ' ') || strchr("'()+,-./:=?", ch))
414         return 1;
415 #else                           /* CHARSET_EBCDIC */
416     if ((ch >= os_toascii['a']) && (ch <= os_toascii['z']))
417         return 1;
418     if ((ch >= os_toascii['A']) && (ch <= os_toascii['Z']))
419         return 1;
420     if ((ch >= os_toascii['0']) && (ch <= os_toascii['9']))
421         return 1;
422     if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch]))
423         return 1;
424 #endif                          /* CHARSET_EBCDIC */
425     return 0;
426 }
427
428 /* Return 1 if the character is a digit or space */
429 static int is_numeric(unsigned long value)
430 {
431     int ch;
432     if (value > 0x7f)
433         return 0;
434     ch = (int)value;
435 #ifndef CHARSET_EBCDIC
436     if (!isdigit(ch) && ch != ' ')
437         return 0;
438 #else
439     if (ch > os_toascii['9'])
440         return 0;
441     if (ch < os_toascii['0'] && ch != os_toascii[' '])
442         return 0;
443 #endif
444     return 1;
445 }