159191Skris/* a_mbstr.c */ 2296341Sdelphij/* 3296341Sdelphij * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4296341Sdelphij * 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 14296341Sdelphij * 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, 66296341Sdelphij int (*rfunc) (unsigned long value, void *in), 67296341Sdelphij 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 77296341Sdelphij/* 78296341Sdelphij * These functions take a string in UTF8, ASCII or multibyte form and a mask 79296341Sdelphij * of permissible ASN1 string types. It then works out the minimal type 80296341Sdelphij * (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and 81296341Sdelphij * creates a string of the correct type with the supplied data. Yes this is 82296341Sdelphij * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum 83296341Sdelphij * size limits too. 8459191Skris */ 8559191Skris 8659191Skrisint ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, 87296341Sdelphij int inform, unsigned long mask) 8859191Skris{ 89296341Sdelphij 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, 93296341Sdelphij int inform, unsigned long mask, 94296341Sdelphij long minsize, long maxsize) 9559191Skris{ 96296341Sdelphij int str_type; 97296341Sdelphij int ret; 98296341Sdelphij char free_out; 99296341Sdelphij int outform, outlen = 0; 100296341Sdelphij ASN1_STRING *dest; 101296341Sdelphij unsigned char *p; 102296341Sdelphij int nchar; 103296341Sdelphij char strbuf[32]; 104296341Sdelphij int (*cpyfunc) (unsigned long, void *) = NULL; 105296341Sdelphij if (len == -1) 106296341Sdelphij len = strlen((const char *)in); 107296341Sdelphij if (!mask) 108296341Sdelphij mask = DIRSTRING_TYPE; 10959191Skris 110296341Sdelphij /* First do a string check and work out the number of characters */ 111296341Sdelphij switch (inform) { 11259191Skris 113296341Sdelphij case MBSTRING_BMP: 114296341Sdelphij if (len & 1) { 115296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 116296341Sdelphij ASN1_R_INVALID_BMPSTRING_LENGTH); 117296341Sdelphij return -1; 118296341Sdelphij } 119296341Sdelphij nchar = len >> 1; 120296341Sdelphij break; 12159191Skris 122296341Sdelphij case MBSTRING_UNIV: 123296341Sdelphij if (len & 3) { 124296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 125296341Sdelphij ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); 126296341Sdelphij return -1; 127296341Sdelphij } 128296341Sdelphij nchar = len >> 2; 129296341Sdelphij break; 13059191Skris 131296341Sdelphij case MBSTRING_UTF8: 132296341Sdelphij nchar = 0; 133296341Sdelphij /* This counts the characters and does utf8 syntax checking */ 134296341Sdelphij ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); 135296341Sdelphij if (ret < 0) { 136296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_INVALID_UTF8STRING); 137296341Sdelphij return -1; 138296341Sdelphij } 139296341Sdelphij break; 14059191Skris 141296341Sdelphij case MBSTRING_ASC: 142296341Sdelphij nchar = len; 143296341Sdelphij break; 14459191Skris 145296341Sdelphij default: 146296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT); 147296341Sdelphij return -1; 148296341Sdelphij } 14959191Skris 150296341Sdelphij if ((minsize > 0) && (nchar < minsize)) { 151296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT); 152296341Sdelphij BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize); 153296341Sdelphij ERR_add_error_data(2, "minsize=", strbuf); 154296341Sdelphij return -1; 155296341Sdelphij } 15659191Skris 157296341Sdelphij if ((maxsize > 0) && (nchar > maxsize)) { 158296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG); 159296341Sdelphij BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize); 160296341Sdelphij ERR_add_error_data(2, "maxsize=", strbuf); 161296341Sdelphij return -1; 162296341Sdelphij } 16359191Skris 164296341Sdelphij /* Now work out minimal type (if any) */ 165296341Sdelphij if (traverse_string(in, len, inform, type_str, &mask) < 0) { 166296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS); 167296341Sdelphij return -1; 168296341Sdelphij } 16959191Skris 170296341Sdelphij /* Now work out output format and string type */ 171296341Sdelphij outform = MBSTRING_ASC; 172296341Sdelphij if (mask & B_ASN1_PRINTABLESTRING) 173296341Sdelphij str_type = V_ASN1_PRINTABLESTRING; 174296341Sdelphij else if (mask & B_ASN1_IA5STRING) 175296341Sdelphij str_type = V_ASN1_IA5STRING; 176296341Sdelphij else if (mask & B_ASN1_T61STRING) 177296341Sdelphij str_type = V_ASN1_T61STRING; 178296341Sdelphij else if (mask & B_ASN1_BMPSTRING) { 179296341Sdelphij str_type = V_ASN1_BMPSTRING; 180296341Sdelphij outform = MBSTRING_BMP; 181296341Sdelphij } else if (mask & B_ASN1_UNIVERSALSTRING) { 182296341Sdelphij str_type = V_ASN1_UNIVERSALSTRING; 183296341Sdelphij outform = MBSTRING_UNIV; 184296341Sdelphij } else { 185296341Sdelphij str_type = V_ASN1_UTF8STRING; 186296341Sdelphij outform = MBSTRING_UTF8; 187296341Sdelphij } 188296341Sdelphij if (!out) 189296341Sdelphij return str_type; 190296341Sdelphij if (*out) { 191296341Sdelphij free_out = 0; 192296341Sdelphij dest = *out; 193296341Sdelphij if (dest->data) { 194296341Sdelphij dest->length = 0; 195296341Sdelphij OPENSSL_free(dest->data); 196296341Sdelphij dest->data = NULL; 197296341Sdelphij } 198296341Sdelphij dest->type = str_type; 199296341Sdelphij } else { 200296341Sdelphij free_out = 1; 201296341Sdelphij dest = ASN1_STRING_type_new(str_type); 202296341Sdelphij if (!dest) { 203296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 204296341Sdelphij return -1; 205296341Sdelphij } 206296341Sdelphij *out = dest; 207296341Sdelphij } 208296341Sdelphij /* If both the same type just copy across */ 209296341Sdelphij if (inform == outform) { 210296341Sdelphij if (!ASN1_STRING_set(dest, in, len)) { 211296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 212296341Sdelphij return -1; 213296341Sdelphij } 214296341Sdelphij return str_type; 215296341Sdelphij } 21659191Skris 217296341Sdelphij /* Work out how much space the destination will need */ 218296341Sdelphij switch (outform) { 219296341Sdelphij case MBSTRING_ASC: 220296341Sdelphij outlen = nchar; 221296341Sdelphij cpyfunc = cpy_asc; 222296341Sdelphij break; 22359191Skris 224296341Sdelphij case MBSTRING_BMP: 225296341Sdelphij outlen = nchar << 1; 226296341Sdelphij cpyfunc = cpy_bmp; 227296341Sdelphij break; 22859191Skris 229296341Sdelphij case MBSTRING_UNIV: 230296341Sdelphij outlen = nchar << 2; 231296341Sdelphij cpyfunc = cpy_univ; 232296341Sdelphij break; 23359191Skris 234296341Sdelphij case MBSTRING_UTF8: 235296341Sdelphij outlen = 0; 236296341Sdelphij traverse_string(in, len, inform, out_utf8, &outlen); 237296341Sdelphij cpyfunc = cpy_utf8; 238296341Sdelphij break; 239296341Sdelphij } 240296341Sdelphij if (!(p = OPENSSL_malloc(outlen + 1))) { 241296341Sdelphij if (free_out) 242296341Sdelphij ASN1_STRING_free(dest); 243296341Sdelphij ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 244296341Sdelphij return -1; 245296341Sdelphij } 246296341Sdelphij dest->length = outlen; 247296341Sdelphij dest->data = p; 248296341Sdelphij p[outlen] = 0; 249296341Sdelphij traverse_string(in, len, inform, cpyfunc, &p); 250296341Sdelphij return str_type; 25159191Skris} 25259191Skris 253296341Sdelphij/* 254296341Sdelphij * This function traverses a string and passes the value of each character to 255296341Sdelphij * an optional function along with a void * argument. 25659191Skris */ 25759191Skris 25859191Skrisstatic int traverse_string(const unsigned char *p, int len, int inform, 259296341Sdelphij int (*rfunc) (unsigned long value, void *in), 260296341Sdelphij void *arg) 26159191Skris{ 262296341Sdelphij unsigned long value; 263296341Sdelphij int ret; 264296341Sdelphij while (len) { 265296341Sdelphij if (inform == MBSTRING_ASC) { 266296341Sdelphij value = *p++; 267296341Sdelphij len--; 268296341Sdelphij } else if (inform == MBSTRING_BMP) { 269296341Sdelphij value = *p++ << 8; 270296341Sdelphij value |= *p++; 271296341Sdelphij len -= 2; 272296341Sdelphij } else if (inform == MBSTRING_UNIV) { 273296341Sdelphij value = ((unsigned long)*p++) << 24; 274296341Sdelphij value |= ((unsigned long)*p++) << 16; 275296341Sdelphij value |= *p++ << 8; 276296341Sdelphij value |= *p++; 277296341Sdelphij len -= 4; 278296341Sdelphij } else { 279296341Sdelphij ret = UTF8_getc(p, len, &value); 280296341Sdelphij if (ret < 0) 281296341Sdelphij return -1; 282296341Sdelphij len -= ret; 283296341Sdelphij p += ret; 284296341Sdelphij } 285296341Sdelphij if (rfunc) { 286296341Sdelphij ret = rfunc(value, arg); 287296341Sdelphij if (ret <= 0) 288296341Sdelphij return ret; 289296341Sdelphij } 290296341Sdelphij } 291296341Sdelphij 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{ 300296341Sdelphij int *nchar; 301296341Sdelphij nchar = arg; 302296341Sdelphij (*nchar)++; 303296341Sdelphij return 1; 30459191Skris} 30559191Skris 30659191Skris/* Determine size of output as a UTF8 String */ 30759191Skris 30859191Skrisstatic int out_utf8(unsigned long value, void *arg) 30959191Skris{ 310296341Sdelphij int *outlen; 311296341Sdelphij outlen = arg; 312296341Sdelphij *outlen += UTF8_putc(NULL, -1, value); 313296341Sdelphij return 1; 31459191Skris} 31559191Skris 316296341Sdelphij/* 317296341Sdelphij * Determine the "type" of a string: check each character against a supplied 318296341Sdelphij * "mask". 31959191Skris */ 32059191Skris 32159191Skrisstatic int type_str(unsigned long value, void *arg) 32259191Skris{ 323296341Sdelphij unsigned long types; 324296341Sdelphij types = *((unsigned long *)arg); 325296341Sdelphij if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value)) 326296341Sdelphij types &= ~B_ASN1_PRINTABLESTRING; 327296341Sdelphij if ((types & B_ASN1_IA5STRING) && (value > 127)) 328296341Sdelphij types &= ~B_ASN1_IA5STRING; 329296341Sdelphij if ((types & B_ASN1_T61STRING) && (value > 0xff)) 330296341Sdelphij types &= ~B_ASN1_T61STRING; 331296341Sdelphij if ((types & B_ASN1_BMPSTRING) && (value > 0xffff)) 332296341Sdelphij types &= ~B_ASN1_BMPSTRING; 333296341Sdelphij if (!types) 334296341Sdelphij return -1; 335296341Sdelphij *((unsigned long *)arg) = types; 336296341Sdelphij return 1; 33759191Skris} 33859191Skris 33959191Skris/* Copy one byte per character ASCII like strings */ 34059191Skris 34159191Skrisstatic int cpy_asc(unsigned long value, void *arg) 34259191Skris{ 343296341Sdelphij unsigned char **p, *q; 344296341Sdelphij p = arg; 345296341Sdelphij q = *p; 346296341Sdelphij *q = (unsigned char)value; 347296341Sdelphij (*p)++; 348296341Sdelphij return 1; 34959191Skris} 35059191Skris 35159191Skris/* Copy two byte per character BMPStrings */ 35259191Skris 35359191Skrisstatic int cpy_bmp(unsigned long value, void *arg) 35459191Skris{ 355296341Sdelphij unsigned char **p, *q; 356296341Sdelphij p = arg; 357296341Sdelphij q = *p; 358296341Sdelphij *q++ = (unsigned char)((value >> 8) & 0xff); 359296341Sdelphij *q = (unsigned char)(value & 0xff); 360296341Sdelphij *p += 2; 361296341Sdelphij return 1; 36259191Skris} 36359191Skris 36459191Skris/* Copy four byte per character UniversalStrings */ 36559191Skris 36659191Skrisstatic int cpy_univ(unsigned long value, void *arg) 36759191Skris{ 368296341Sdelphij unsigned char **p, *q; 369296341Sdelphij p = arg; 370296341Sdelphij q = *p; 371296341Sdelphij *q++ = (unsigned char)((value >> 24) & 0xff); 372296341Sdelphij *q++ = (unsigned char)((value >> 16) & 0xff); 373296341Sdelphij *q++ = (unsigned char)((value >> 8) & 0xff); 374296341Sdelphij *q = (unsigned char)(value & 0xff); 375296341Sdelphij *p += 4; 376296341Sdelphij return 1; 37759191Skris} 37859191Skris 37959191Skris/* Copy to a UTF8String */ 38059191Skris 38159191Skrisstatic int cpy_utf8(unsigned long value, void *arg) 38259191Skris{ 383296341Sdelphij unsigned char **p; 384296341Sdelphij int ret; 385296341Sdelphij p = arg; 386296341Sdelphij /* We already know there is enough room so pass 0xff as the length */ 387296341Sdelphij ret = UTF8_putc(*p, 0xff, value); 388296341Sdelphij *p += ret; 389296341Sdelphij return 1; 39059191Skris} 39159191Skris 39259191Skris/* Return 1 if the character is permitted in a PrintableString */ 39359191Skrisstatic int is_printable(unsigned long value) 39459191Skris{ 395296341Sdelphij int ch; 396296341Sdelphij if (value > 0x7f) 397296341Sdelphij return 0; 398296341Sdelphij ch = (int)value; 399296341Sdelphij /* 400296341Sdelphij * Note: we can't use 'isalnum' because certain accented characters may 401296341Sdelphij * count as alphanumeric in some environments. 402296341Sdelphij */ 40368651Skris#ifndef CHARSET_EBCDIC 404296341Sdelphij if ((ch >= 'a') && (ch <= 'z')) 405296341Sdelphij return 1; 406296341Sdelphij if ((ch >= 'A') && (ch <= 'Z')) 407296341Sdelphij return 1; 408296341Sdelphij if ((ch >= '0') && (ch <= '9')) 409296341Sdelphij return 1; 410296341Sdelphij if ((ch == ' ') || strchr("'()+,-./:=?", ch)) 411296341Sdelphij return 1; 412296341Sdelphij#else /* CHARSET_EBCDIC */ 413296341Sdelphij if ((ch >= os_toascii['a']) && (ch <= os_toascii['z'])) 414296341Sdelphij return 1; 415296341Sdelphij if ((ch >= os_toascii['A']) && (ch <= os_toascii['Z'])) 416296341Sdelphij return 1; 417296341Sdelphij if ((ch >= os_toascii['0']) && (ch <= os_toascii['9'])) 418296341Sdelphij return 1; 419296341Sdelphij if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch])) 420296341Sdelphij return 1; 421296341Sdelphij#endif /* CHARSET_EBCDIC */ 422296341Sdelphij return 0; 42359191Skris} 424