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