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