OLD | NEW |
| (Empty) |
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 int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, | |
84 int inform, unsigned long mask) | |
85 { | |
86 return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0); | |
87 } | |
88 | |
89 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 int outform, outlen = 0; | |
97 ASN1_STRING *dest; | |
98 unsigned char *p; | |
99 int nchar; | |
100 char strbuf[32]; | |
101 int (*cpyfunc)(unsigned long,void *) = NULL; | |
102 if(len == -1) len = strlen((const char *)in); | |
103 if(!mask) mask = DIRSTRING_TYPE; | |
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) { | |
110 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, | |
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) { | |
119 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, | |
120 ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); | |
121 return -1; | |
122 } | |
123 nchar = len >> 2; | |
124 break; | |
125 | |
126 case MBSTRING_UTF8: | |
127 nchar = 0; | |
128 /* This counts the characters and does utf8 syntax checking */ | |
129 ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); | |
130 if(ret < 0) { | |
131 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, | |
132 ASN1_R_INVALID_UTF8STRING); | |
133 return -1; | |
134 } | |
135 break; | |
136 | |
137 case MBSTRING_ASC: | |
138 nchar = len; | |
139 break; | |
140 | |
141 default: | |
142 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT); | |
143 return -1; | |
144 } | |
145 | |
146 if((minsize > 0) && (nchar < minsize)) { | |
147 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT); | |
148 BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize); | |
149 ERR_add_error_data(2, "minsize=", strbuf); | |
150 return -1; | |
151 } | |
152 | |
153 if((maxsize > 0) && (nchar > maxsize)) { | |
154 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG); | |
155 BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize); | |
156 ERR_add_error_data(2, "maxsize=", strbuf); | |
157 return -1; | |
158 } | |
159 | |
160 /* Now work out minimal type (if any) */ | |
161 if(traverse_string(in, len, inform, type_str, &mask) < 0) { | |
162 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS); | |
163 return -1; | |
164 } | |
165 | |
166 | |
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; | |
183 if(*out) { | |
184 free_out = 0; | |
185 dest = *out; | |
186 if(dest->data) { | |
187 dest->length = 0; | |
188 OPENSSL_free(dest->data); | |
189 dest->data = NULL; | |
190 } | |
191 dest->type = str_type; | |
192 } else { | |
193 free_out = 1; | |
194 dest = ASN1_STRING_type_new(str_type); | |
195 if(!dest) { | |
196 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, | |
197 ERR_R_MALLOC_FAILURE); | |
198 return -1; | |
199 } | |
200 *out = dest; | |
201 } | |
202 /* If both the same type just copy across */ | |
203 if(inform == outform) { | |
204 if(!ASN1_STRING_set(dest, in, len)) { | |
205 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,ERR_R_MALLOC_FAILURE)
; | |
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 } | |
234 if(!(p = OPENSSL_malloc(outlen + 1))) { | |
235 if(free_out) ASN1_STRING_free(dest); | |
236 ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,ERR_R_MALLOC_FAILURE); | |
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 | |
250 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 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) { | |
264 value = ((unsigned long)*p++) << 24; | |
265 value |= ((unsigned long)*p++) << 16; | |
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 { | |
299 int *outlen; | |
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 */ | |
388 #ifndef CHARSET_EBCDIC | |
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; | |
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])) r
eturn 1; | |
398 #endif /*CHARSET_EBCDIC*/ | |
399 return 0; | |
400 } | |
OLD | NEW |