159191Skris/* a_mbstr.c */ 2280297Sjkim/* 3280297Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4280297Sjkim * 1999. 559191Skris */ 659191Skris/* ==================================================================== 759191Skris * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 859191Skris * 959191Skris * Redistribution and use in source and binary forms, with or without 1059191Skris * modification, are permitted provided that the following conditions 1159191Skris * are met: 1259191Skris * 1359191Skris * 1. Redistributions of source code must retain the above copyright 14280297Sjkim * notice, this list of conditions and the following disclaimer. 1559191Skris * 1659191Skris * 2. Redistributions in binary form must reproduce the above copyright 1759191Skris * notice, this list of conditions and the following disclaimer in 1859191Skris * the documentation and/or other materials provided with the 1959191Skris * distribution. 2059191Skris * 2159191Skris * 3. All advertising materials mentioning features or use of this 2259191Skris * software must display the following acknowledgment: 2359191Skris * "This product includes software developed by the OpenSSL Project 2459191Skris * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 2559191Skris * 2659191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2759191Skris * endorse or promote products derived from this software without 2859191Skris * prior written permission. For written permission, please contact 2959191Skris * licensing@OpenSSL.org. 3059191Skris * 3159191Skris * 5. Products derived from this software may not be called "OpenSSL" 3259191Skris * nor may "OpenSSL" appear in their names without prior written 3359191Skris * permission of the OpenSSL Project. 3459191Skris * 3559191Skris * 6. Redistributions of any form whatsoever must retain the following 3659191Skris * acknowledgment: 3759191Skris * "This product includes software developed by the OpenSSL Project 3859191Skris * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 3959191Skris * 4059191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 4159191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4259191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4359191Skris * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 4459191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4559191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4659191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4759191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4859191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4959191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5059191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 5159191Skris * OF THE POSSIBILITY OF SUCH DAMAGE. 5259191Skris * ==================================================================== 5359191Skris * 5459191Skris * This product includes cryptographic software written by Eric Young 5559191Skris * (eay@cryptsoft.com). This product includes software written by Tim 5659191Skris * Hudson (tjh@cryptsoft.com). 5759191Skris * 5859191Skris */ 5959191Skris 6059191Skris#include <stdio.h> 6159191Skris#include <ctype.h> 6259191Skris#include "cryptlib.h" 6359191Skris#include <openssl/asn1.h> 6459191Skris 6559191Skrisstatic int traverse_string(const unsigned char *p, int len, int inform, 66280297Sjkim int (*rfunc) (unsigned long value, void *in), 67280297Sjkim void *arg); 6859191Skrisstatic int in_utf8(unsigned long value, void *arg); 6959191Skrisstatic int out_utf8(unsigned long value, void *arg); 7059191Skrisstatic int type_str(unsigned long value, void *arg); 7159191Skrisstatic int cpy_asc(unsigned long value, void *arg); 7259191Skrisstatic int cpy_bmp(unsigned long value, void *arg); 7359191Skrisstatic int cpy_univ(unsigned long value, void *arg); 7459191Skrisstatic int cpy_utf8(unsigned long value, void *arg); 7559191Skrisstatic int is_printable(unsigned long value); 7659191Skris 77280297Sjkim/* 78280297Sjkim * These functions take a string in UTF8, ASCII or multibyte form and a mask 79280297Sjkim * of permissible ASN1 string types. It then works out the minimal type 80280297Sjkim * (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and 81280297Sjkim * creates a string of the correct type with the supplied data. Yes this is 82280297Sjkim * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum 83280297Sjkim * size limits too. 8459191Skris */ 8559191Skris 8659191Skrisint ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, 87280297Sjkim int inform, unsigned long mask) 8859191Skris{ 89280297Sjkim return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0); 9059191Skris} 9159191Skris 9259191Skrisint ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, 93280297Sjkim int inform, unsigned long mask, 94280297Sjkim long minsize, long maxsize) 9559191Skris{ 96280297Sjkim int str_type; 97280297Sjkim int ret; 98280297Sjkim char free_out; 99280297Sjkim int outform, outlen = 0; 100280297Sjkim ASN1_STRING *dest; 101280297Sjkim unsigned char *p; 102280297Sjkim int nchar; 103280297Sjkim char strbuf[32]; 104280297Sjkim int (*cpyfunc) (unsigned long, void *) = NULL; 105280297Sjkim if (len == -1) 106280297Sjkim len = strlen((const char *)in); 107280297Sjkim if (!mask) 108280297Sjkim mask = DIRSTRING_TYPE; 10959191Skris 110280297Sjkim /* First do a string check and work out the number of characters */ 111280297Sjkim switch (inform) { 11259191Skris 113280297Sjkim case MBSTRING_BMP: 114280297Sjkim if (len & 1) { 115280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 116280297Sjkim ASN1_R_INVALID_BMPSTRING_LENGTH); 117280297Sjkim return -1; 118280297Sjkim } 119280297Sjkim nchar = len >> 1; 120280297Sjkim break; 12159191Skris 122280297Sjkim case MBSTRING_UNIV: 123280297Sjkim if (len & 3) { 124280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 125280297Sjkim ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); 126280297Sjkim return -1; 127280297Sjkim } 128280297Sjkim nchar = len >> 2; 129280297Sjkim break; 13059191Skris 131280297Sjkim case MBSTRING_UTF8: 132280297Sjkim nchar = 0; 133280297Sjkim /* This counts the characters and does utf8 syntax checking */ 134280297Sjkim ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); 135280297Sjkim if (ret < 0) { 136280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_INVALID_UTF8STRING); 137280297Sjkim return -1; 138280297Sjkim } 139280297Sjkim break; 14059191Skris 141280297Sjkim case MBSTRING_ASC: 142280297Sjkim nchar = len; 143280297Sjkim break; 14459191Skris 145280297Sjkim default: 146280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT); 147280297Sjkim return -1; 148280297Sjkim } 14959191Skris 150280297Sjkim if ((minsize > 0) && (nchar < minsize)) { 151280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT); 152331638Sjkim BIO_snprintf(strbuf, sizeof(strbuf), "%ld", minsize); 153280297Sjkim ERR_add_error_data(2, "minsize=", strbuf); 154280297Sjkim return -1; 155280297Sjkim } 15659191Skris 157280297Sjkim if ((maxsize > 0) && (nchar > maxsize)) { 158280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG); 159331638Sjkim BIO_snprintf(strbuf, sizeof(strbuf), "%ld", maxsize); 160280297Sjkim ERR_add_error_data(2, "maxsize=", strbuf); 161280297Sjkim return -1; 162280297Sjkim } 16359191Skris 164280297Sjkim /* Now work out minimal type (if any) */ 165280297Sjkim if (traverse_string(in, len, inform, type_str, &mask) < 0) { 166280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS); 167280297Sjkim return -1; 168280297Sjkim } 16959191Skris 170280297Sjkim /* Now work out output format and string type */ 171280297Sjkim outform = MBSTRING_ASC; 172280297Sjkim if (mask & B_ASN1_PRINTABLESTRING) 173280297Sjkim str_type = V_ASN1_PRINTABLESTRING; 174280297Sjkim else if (mask & B_ASN1_IA5STRING) 175280297Sjkim str_type = V_ASN1_IA5STRING; 176280297Sjkim else if (mask & B_ASN1_T61STRING) 177280297Sjkim str_type = V_ASN1_T61STRING; 178280297Sjkim else if (mask & B_ASN1_BMPSTRING) { 179280297Sjkim str_type = V_ASN1_BMPSTRING; 180280297Sjkim outform = MBSTRING_BMP; 181280297Sjkim } else if (mask & B_ASN1_UNIVERSALSTRING) { 182280297Sjkim str_type = V_ASN1_UNIVERSALSTRING; 183280297Sjkim outform = MBSTRING_UNIV; 184280297Sjkim } else { 185280297Sjkim str_type = V_ASN1_UTF8STRING; 186280297Sjkim outform = MBSTRING_UTF8; 187280297Sjkim } 188280297Sjkim if (!out) 189280297Sjkim return str_type; 190280297Sjkim if (*out) { 191280297Sjkim free_out = 0; 192280297Sjkim dest = *out; 193280297Sjkim if (dest->data) { 194280297Sjkim dest->length = 0; 195280297Sjkim OPENSSL_free(dest->data); 196280297Sjkim dest->data = NULL; 197280297Sjkim } 198280297Sjkim dest->type = str_type; 199280297Sjkim } else { 200280297Sjkim free_out = 1; 201280297Sjkim dest = ASN1_STRING_type_new(str_type); 202280297Sjkim if (!dest) { 203280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 204280297Sjkim return -1; 205280297Sjkim } 206280297Sjkim *out = dest; 207280297Sjkim } 208280297Sjkim /* If both the same type just copy across */ 209280297Sjkim if (inform == outform) { 210280297Sjkim if (!ASN1_STRING_set(dest, in, len)) { 211280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 212280297Sjkim return -1; 213280297Sjkim } 214280297Sjkim return str_type; 215280297Sjkim } 21659191Skris 217280297Sjkim /* Work out how much space the destination will need */ 218280297Sjkim switch (outform) { 219280297Sjkim case MBSTRING_ASC: 220280297Sjkim outlen = nchar; 221280297Sjkim cpyfunc = cpy_asc; 222280297Sjkim break; 22359191Skris 224280297Sjkim case MBSTRING_BMP: 225280297Sjkim outlen = nchar << 1; 226280297Sjkim cpyfunc = cpy_bmp; 227280297Sjkim break; 22859191Skris 229280297Sjkim case MBSTRING_UNIV: 230280297Sjkim outlen = nchar << 2; 231280297Sjkim cpyfunc = cpy_univ; 232280297Sjkim break; 23359191Skris 234280297Sjkim case MBSTRING_UTF8: 235280297Sjkim outlen = 0; 236280297Sjkim traverse_string(in, len, inform, out_utf8, &outlen); 237280297Sjkim cpyfunc = cpy_utf8; 238280297Sjkim break; 239280297Sjkim } 240280297Sjkim if (!(p = OPENSSL_malloc(outlen + 1))) { 241280297Sjkim if (free_out) 242280297Sjkim ASN1_STRING_free(dest); 243280297Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 244280297Sjkim return -1; 245280297Sjkim } 246280297Sjkim dest->length = outlen; 247280297Sjkim dest->data = p; 248280297Sjkim p[outlen] = 0; 249280297Sjkim traverse_string(in, len, inform, cpyfunc, &p); 250280297Sjkim return str_type; 25159191Skris} 25259191Skris 253280297Sjkim/* 254280297Sjkim * This function traverses a string and passes the value of each character to 255280297Sjkim * an optional function along with a void * argument. 25659191Skris */ 25759191Skris 25859191Skrisstatic int traverse_string(const unsigned char *p, int len, int inform, 259280297Sjkim int (*rfunc) (unsigned long value, void *in), 260280297Sjkim void *arg) 26159191Skris{ 262280297Sjkim unsigned long value; 263280297Sjkim int ret; 264280297Sjkim while (len) { 265280297Sjkim if (inform == MBSTRING_ASC) { 266280297Sjkim value = *p++; 267280297Sjkim len--; 268280297Sjkim } else if (inform == MBSTRING_BMP) { 269280297Sjkim value = *p++ << 8; 270280297Sjkim value |= *p++; 271280297Sjkim len -= 2; 272280297Sjkim } else if (inform == MBSTRING_UNIV) { 273280297Sjkim value = ((unsigned long)*p++) << 24; 274280297Sjkim value |= ((unsigned long)*p++) << 16; 275280297Sjkim value |= *p++ << 8; 276280297Sjkim value |= *p++; 277280297Sjkim len -= 4; 278280297Sjkim } else { 279280297Sjkim ret = UTF8_getc(p, len, &value); 280280297Sjkim if (ret < 0) 281280297Sjkim return -1; 282280297Sjkim len -= ret; 283280297Sjkim p += ret; 284280297Sjkim } 285280297Sjkim if (rfunc) { 286280297Sjkim ret = rfunc(value, arg); 287280297Sjkim if (ret <= 0) 288280297Sjkim return ret; 289280297Sjkim } 290280297Sjkim } 291280297Sjkim return 1; 29259191Skris} 29359191Skris 29459191Skris/* Various utility functions for traverse_string */ 29559191Skris 29659191Skris/* Just count number of characters */ 29759191Skris 29859191Skrisstatic int in_utf8(unsigned long value, void *arg) 29959191Skris{ 300280297Sjkim int *nchar; 301280297Sjkim nchar = arg; 302280297Sjkim (*nchar)++; 303280297Sjkim return 1; 30459191Skris} 30559191Skris 30659191Skris/* Determine size of output as a UTF8 String */ 30759191Skris 30859191Skrisstatic int out_utf8(unsigned long value, void *arg) 30959191Skris{ 310280297Sjkim int *outlen; 311280297Sjkim outlen = arg; 312280297Sjkim *outlen += UTF8_putc(NULL, -1, value); 313280297Sjkim return 1; 31459191Skris} 31559191Skris 316280297Sjkim/* 317280297Sjkim * Determine the "type" of a string: check each character against a supplied 318280297Sjkim * "mask". 31959191Skris */ 32059191Skris 32159191Skrisstatic int type_str(unsigned long value, void *arg) 32259191Skris{ 323280297Sjkim unsigned long types; 324280297Sjkim types = *((unsigned long *)arg); 325280297Sjkim if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value)) 326280297Sjkim types &= ~B_ASN1_PRINTABLESTRING; 327280297Sjkim if ((types & B_ASN1_IA5STRING) && (value > 127)) 328280297Sjkim types &= ~B_ASN1_IA5STRING; 329280297Sjkim if ((types & B_ASN1_T61STRING) && (value > 0xff)) 330280297Sjkim types &= ~B_ASN1_T61STRING; 331280297Sjkim if ((types & B_ASN1_BMPSTRING) && (value > 0xffff)) 332280297Sjkim types &= ~B_ASN1_BMPSTRING; 333280297Sjkim if (!types) 334280297Sjkim return -1; 335280297Sjkim *((unsigned long *)arg) = types; 336280297Sjkim return 1; 33759191Skris} 33859191Skris 33959191Skris/* Copy one byte per character ASCII like strings */ 34059191Skris 34159191Skrisstatic int cpy_asc(unsigned long value, void *arg) 34259191Skris{ 343280297Sjkim unsigned char **p, *q; 344280297Sjkim p = arg; 345280297Sjkim q = *p; 346280297Sjkim *q = (unsigned char)value; 347280297Sjkim (*p)++; 348280297Sjkim return 1; 34959191Skris} 35059191Skris 35159191Skris/* Copy two byte per character BMPStrings */ 35259191Skris 35359191Skrisstatic int cpy_bmp(unsigned long value, void *arg) 35459191Skris{ 355280297Sjkim unsigned char **p, *q; 356280297Sjkim p = arg; 357280297Sjkim q = *p; 358280297Sjkim *q++ = (unsigned char)((value >> 8) & 0xff); 359280297Sjkim *q = (unsigned char)(value & 0xff); 360280297Sjkim *p += 2; 361280297Sjkim return 1; 36259191Skris} 36359191Skris 36459191Skris/* Copy four byte per character UniversalStrings */ 36559191Skris 36659191Skrisstatic int cpy_univ(unsigned long value, void *arg) 36759191Skris{ 368280297Sjkim unsigned char **p, *q; 369280297Sjkim p = arg; 370280297Sjkim q = *p; 371280297Sjkim *q++ = (unsigned char)((value >> 24) & 0xff); 372280297Sjkim *q++ = (unsigned char)((value >> 16) & 0xff); 373280297Sjkim *q++ = (unsigned char)((value >> 8) & 0xff); 374280297Sjkim *q = (unsigned char)(value & 0xff); 375280297Sjkim *p += 4; 376280297Sjkim return 1; 37759191Skris} 37859191Skris 37959191Skris/* Copy to a UTF8String */ 38059191Skris 38159191Skrisstatic int cpy_utf8(unsigned long value, void *arg) 38259191Skris{ 383280297Sjkim unsigned char **p; 384280297Sjkim int ret; 385280297Sjkim p = arg; 386280297Sjkim /* We already know there is enough room so pass 0xff as the length */ 387280297Sjkim ret = UTF8_putc(*p, 0xff, value); 388280297Sjkim *p += ret; 389280297Sjkim return 1; 39059191Skris} 39159191Skris 39259191Skris/* Return 1 if the character is permitted in a PrintableString */ 39359191Skrisstatic int is_printable(unsigned long value) 39459191Skris{ 395280297Sjkim int ch; 396280297Sjkim if (value > 0x7f) 397280297Sjkim return 0; 398280297Sjkim ch = (int)value; 399280297Sjkim /* 400280297Sjkim * Note: we can't use 'isalnum' because certain accented characters may 401280297Sjkim * count as alphanumeric in some environments. 402280297Sjkim */ 40368651Skris#ifndef CHARSET_EBCDIC 404280297Sjkim if ((ch >= 'a') && (ch <= 'z')) 405280297Sjkim return 1; 406280297Sjkim if ((ch >= 'A') && (ch <= 'Z')) 407280297Sjkim return 1; 408280297Sjkim if ((ch >= '0') && (ch <= '9')) 409280297Sjkim return 1; 410280297Sjkim if ((ch == ' ') || strchr("'()+,-./:=?", ch)) 411280297Sjkim return 1; 412280297Sjkim#else /* CHARSET_EBCDIC */ 413280297Sjkim if ((ch >= os_toascii['a']) && (ch <= os_toascii['z'])) 414280297Sjkim return 1; 415280297Sjkim if ((ch >= os_toascii['A']) && (ch <= os_toascii['Z'])) 416280297Sjkim return 1; 417280297Sjkim if ((ch >= os_toascii['0']) && (ch <= os_toascii['9'])) 418280297Sjkim return 1; 419280297Sjkim if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch])) 420280297Sjkim return 1; 421280297Sjkim#endif /* CHARSET_EBCDIC */ 422280297Sjkim return 0; 42359191Skris} 424