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