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