159191Skris/* a_mbstr.c */ 2280304Sjkim/* 3280304Sjkim * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 4280304Sjkim * 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 14280304Sjkim * 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, 66280304Sjkim int (*rfunc) (unsigned long value, void *in), 67280304Sjkim 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 77280304Sjkim/* 78280304Sjkim * These functions take a string in UTF8, ASCII or multibyte form and a mask 79280304Sjkim * of permissible ASN1 string types. It then works out the minimal type 80280304Sjkim * (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) and 81280304Sjkim * creates a string of the correct type with the supplied data. Yes this is 82280304Sjkim * horrible: it has to be :-( The 'ncopy' form checks minimum and maximum 83280304Sjkim * size limits too. 8459191Skris */ 8559191Skris 8659191Skrisint ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, 87280304Sjkim int inform, unsigned long mask) 8859191Skris{ 89280304Sjkim 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, 93280304Sjkim int inform, unsigned long mask, 94280304Sjkim long minsize, long maxsize) 9559191Skris{ 96280304Sjkim int str_type; 97280304Sjkim int ret; 98280304Sjkim char free_out; 99280304Sjkim int outform, outlen = 0; 100280304Sjkim ASN1_STRING *dest; 101280304Sjkim unsigned char *p; 102280304Sjkim int nchar; 103280304Sjkim char strbuf[32]; 104280304Sjkim int (*cpyfunc) (unsigned long, void *) = NULL; 105280304Sjkim if (len == -1) 106280304Sjkim len = strlen((const char *)in); 107280304Sjkim if (!mask) 108280304Sjkim mask = DIRSTRING_TYPE; 10959191Skris 110280304Sjkim /* First do a string check and work out the number of characters */ 111280304Sjkim switch (inform) { 11259191Skris 113280304Sjkim case MBSTRING_BMP: 114280304Sjkim if (len & 1) { 115280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 116280304Sjkim ASN1_R_INVALID_BMPSTRING_LENGTH); 117280304Sjkim return -1; 118280304Sjkim } 119280304Sjkim nchar = len >> 1; 120280304Sjkim break; 12159191Skris 122280304Sjkim case MBSTRING_UNIV: 123280304Sjkim if (len & 3) { 124280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 125280304Sjkim ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); 126280304Sjkim return -1; 127280304Sjkim } 128280304Sjkim nchar = len >> 2; 129280304Sjkim break; 13059191Skris 131280304Sjkim case MBSTRING_UTF8: 132280304Sjkim nchar = 0; 133280304Sjkim /* This counts the characters and does utf8 syntax checking */ 134280304Sjkim ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); 135280304Sjkim if (ret < 0) { 136280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_INVALID_UTF8STRING); 137280304Sjkim return -1; 138280304Sjkim } 139280304Sjkim break; 14059191Skris 141280304Sjkim case MBSTRING_ASC: 142280304Sjkim nchar = len; 143280304Sjkim break; 14459191Skris 145280304Sjkim default: 146280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT); 147280304Sjkim return -1; 148280304Sjkim } 14959191Skris 150280304Sjkim if ((minsize > 0) && (nchar < minsize)) { 151280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT); 152280304Sjkim BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize); 153280304Sjkim ERR_add_error_data(2, "minsize=", strbuf); 154280304Sjkim return -1; 155280304Sjkim } 15659191Skris 157280304Sjkim if ((maxsize > 0) && (nchar > maxsize)) { 158280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG); 159280304Sjkim BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize); 160280304Sjkim ERR_add_error_data(2, "maxsize=", strbuf); 161280304Sjkim return -1; 162280304Sjkim } 16359191Skris 164280304Sjkim /* Now work out minimal type (if any) */ 165280304Sjkim if (traverse_string(in, len, inform, type_str, &mask) < 0) { 166280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS); 167280304Sjkim return -1; 168280304Sjkim } 16959191Skris 170280304Sjkim /* Now work out output format and string type */ 171280304Sjkim outform = MBSTRING_ASC; 172280304Sjkim if (mask & B_ASN1_PRINTABLESTRING) 173280304Sjkim str_type = V_ASN1_PRINTABLESTRING; 174280304Sjkim else if (mask & B_ASN1_IA5STRING) 175280304Sjkim str_type = V_ASN1_IA5STRING; 176280304Sjkim else if (mask & B_ASN1_T61STRING) 177280304Sjkim str_type = V_ASN1_T61STRING; 178280304Sjkim else if (mask & B_ASN1_BMPSTRING) { 179280304Sjkim str_type = V_ASN1_BMPSTRING; 180280304Sjkim outform = MBSTRING_BMP; 181280304Sjkim } else if (mask & B_ASN1_UNIVERSALSTRING) { 182280304Sjkim str_type = V_ASN1_UNIVERSALSTRING; 183280304Sjkim outform = MBSTRING_UNIV; 184280304Sjkim } else { 185280304Sjkim str_type = V_ASN1_UTF8STRING; 186280304Sjkim outform = MBSTRING_UTF8; 187280304Sjkim } 188280304Sjkim if (!out) 189280304Sjkim return str_type; 190280304Sjkim if (*out) { 191280304Sjkim free_out = 0; 192280304Sjkim dest = *out; 193280304Sjkim if (dest->data) { 194280304Sjkim dest->length = 0; 195280304Sjkim OPENSSL_free(dest->data); 196280304Sjkim dest->data = NULL; 197280304Sjkim } 198280304Sjkim dest->type = str_type; 199280304Sjkim } else { 200280304Sjkim free_out = 1; 201280304Sjkim dest = ASN1_STRING_type_new(str_type); 202280304Sjkim if (!dest) { 203280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 204280304Sjkim return -1; 205280304Sjkim } 206280304Sjkim *out = dest; 207280304Sjkim } 208280304Sjkim /* If both the same type just copy across */ 209280304Sjkim if (inform == outform) { 210280304Sjkim if (!ASN1_STRING_set(dest, in, len)) { 211280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 212280304Sjkim return -1; 213280304Sjkim } 214280304Sjkim return str_type; 215280304Sjkim } 21659191Skris 217280304Sjkim /* Work out how much space the destination will need */ 218280304Sjkim switch (outform) { 219280304Sjkim case MBSTRING_ASC: 220280304Sjkim outlen = nchar; 221280304Sjkim cpyfunc = cpy_asc; 222280304Sjkim break; 22359191Skris 224280304Sjkim case MBSTRING_BMP: 225280304Sjkim outlen = nchar << 1; 226280304Sjkim cpyfunc = cpy_bmp; 227280304Sjkim break; 22859191Skris 229280304Sjkim case MBSTRING_UNIV: 230280304Sjkim outlen = nchar << 2; 231280304Sjkim cpyfunc = cpy_univ; 232280304Sjkim break; 23359191Skris 234280304Sjkim case MBSTRING_UTF8: 235280304Sjkim outlen = 0; 236280304Sjkim traverse_string(in, len, inform, out_utf8, &outlen); 237280304Sjkim cpyfunc = cpy_utf8; 238280304Sjkim break; 239280304Sjkim } 240280304Sjkim if (!(p = OPENSSL_malloc(outlen + 1))) { 241280304Sjkim if (free_out) 242280304Sjkim ASN1_STRING_free(dest); 243280304Sjkim ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE); 244280304Sjkim return -1; 245280304Sjkim } 246280304Sjkim dest->length = outlen; 247280304Sjkim dest->data = p; 248280304Sjkim p[outlen] = 0; 249280304Sjkim traverse_string(in, len, inform, cpyfunc, &p); 250280304Sjkim return str_type; 25159191Skris} 25259191Skris 253280304Sjkim/* 254280304Sjkim * This function traverses a string and passes the value of each character to 255280304Sjkim * an optional function along with a void * argument. 25659191Skris */ 25759191Skris 25859191Skrisstatic int traverse_string(const unsigned char *p, int len, int inform, 259280304Sjkim int (*rfunc) (unsigned long value, void *in), 260280304Sjkim void *arg) 26159191Skris{ 262280304Sjkim unsigned long value; 263280304Sjkim int ret; 264280304Sjkim while (len) { 265280304Sjkim if (inform == MBSTRING_ASC) { 266280304Sjkim value = *p++; 267280304Sjkim len--; 268280304Sjkim } else if (inform == MBSTRING_BMP) { 269280304Sjkim value = *p++ << 8; 270280304Sjkim value |= *p++; 271280304Sjkim len -= 2; 272280304Sjkim } else if (inform == MBSTRING_UNIV) { 273280304Sjkim value = ((unsigned long)*p++) << 24; 274280304Sjkim value |= ((unsigned long)*p++) << 16; 275280304Sjkim value |= *p++ << 8; 276280304Sjkim value |= *p++; 277280304Sjkim len -= 4; 278280304Sjkim } else { 279280304Sjkim ret = UTF8_getc(p, len, &value); 280280304Sjkim if (ret < 0) 281280304Sjkim return -1; 282280304Sjkim len -= ret; 283280304Sjkim p += ret; 284280304Sjkim } 285280304Sjkim if (rfunc) { 286280304Sjkim ret = rfunc(value, arg); 287280304Sjkim if (ret <= 0) 288280304Sjkim return ret; 289280304Sjkim } 290280304Sjkim } 291280304Sjkim 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{ 300280304Sjkim int *nchar; 301280304Sjkim nchar = arg; 302280304Sjkim (*nchar)++; 303280304Sjkim return 1; 30459191Skris} 30559191Skris 30659191Skris/* Determine size of output as a UTF8 String */ 30759191Skris 30859191Skrisstatic int out_utf8(unsigned long value, void *arg) 30959191Skris{ 310280304Sjkim int *outlen; 311280304Sjkim outlen = arg; 312280304Sjkim *outlen += UTF8_putc(NULL, -1, value); 313280304Sjkim return 1; 31459191Skris} 31559191Skris 316280304Sjkim/* 317280304Sjkim * Determine the "type" of a string: check each character against a supplied 318280304Sjkim * "mask". 31959191Skris */ 32059191Skris 32159191Skrisstatic int type_str(unsigned long value, void *arg) 32259191Skris{ 323280304Sjkim unsigned long types; 324280304Sjkim types = *((unsigned long *)arg); 325280304Sjkim if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value)) 326280304Sjkim types &= ~B_ASN1_PRINTABLESTRING; 327280304Sjkim if ((types & B_ASN1_IA5STRING) && (value > 127)) 328280304Sjkim types &= ~B_ASN1_IA5STRING; 329280304Sjkim if ((types & B_ASN1_T61STRING) && (value > 0xff)) 330280304Sjkim types &= ~B_ASN1_T61STRING; 331280304Sjkim if ((types & B_ASN1_BMPSTRING) && (value > 0xffff)) 332280304Sjkim types &= ~B_ASN1_BMPSTRING; 333280304Sjkim if (!types) 334280304Sjkim return -1; 335280304Sjkim *((unsigned long *)arg) = types; 336280304Sjkim return 1; 33759191Skris} 33859191Skris 33959191Skris/* Copy one byte per character ASCII like strings */ 34059191Skris 34159191Skrisstatic int cpy_asc(unsigned long value, void *arg) 34259191Skris{ 343280304Sjkim unsigned char **p, *q; 344280304Sjkim p = arg; 345280304Sjkim q = *p; 346280304Sjkim *q = (unsigned char)value; 347280304Sjkim (*p)++; 348280304Sjkim return 1; 34959191Skris} 35059191Skris 35159191Skris/* Copy two byte per character BMPStrings */ 35259191Skris 35359191Skrisstatic int cpy_bmp(unsigned long value, void *arg) 35459191Skris{ 355280304Sjkim unsigned char **p, *q; 356280304Sjkim p = arg; 357280304Sjkim q = *p; 358280304Sjkim *q++ = (unsigned char)((value >> 8) & 0xff); 359280304Sjkim *q = (unsigned char)(value & 0xff); 360280304Sjkim *p += 2; 361280304Sjkim return 1; 36259191Skris} 36359191Skris 36459191Skris/* Copy four byte per character UniversalStrings */ 36559191Skris 36659191Skrisstatic int cpy_univ(unsigned long value, void *arg) 36759191Skris{ 368280304Sjkim unsigned char **p, *q; 369280304Sjkim p = arg; 370280304Sjkim q = *p; 371280304Sjkim *q++ = (unsigned char)((value >> 24) & 0xff); 372280304Sjkim *q++ = (unsigned char)((value >> 16) & 0xff); 373280304Sjkim *q++ = (unsigned char)((value >> 8) & 0xff); 374280304Sjkim *q = (unsigned char)(value & 0xff); 375280304Sjkim *p += 4; 376280304Sjkim return 1; 37759191Skris} 37859191Skris 37959191Skris/* Copy to a UTF8String */ 38059191Skris 38159191Skrisstatic int cpy_utf8(unsigned long value, void *arg) 38259191Skris{ 383280304Sjkim unsigned char **p; 384280304Sjkim int ret; 385280304Sjkim p = arg; 386280304Sjkim /* We already know there is enough room so pass 0xff as the length */ 387280304Sjkim ret = UTF8_putc(*p, 0xff, value); 388280304Sjkim *p += ret; 389280304Sjkim return 1; 39059191Skris} 39159191Skris 39259191Skris/* Return 1 if the character is permitted in a PrintableString */ 39359191Skrisstatic int is_printable(unsigned long value) 39459191Skris{ 395280304Sjkim int ch; 396280304Sjkim if (value > 0x7f) 397280304Sjkim return 0; 398280304Sjkim ch = (int)value; 399280304Sjkim /* 400280304Sjkim * Note: we can't use 'isalnum' because certain accented characters may 401280304Sjkim * count as alphanumeric in some environments. 402280304Sjkim */ 40368651Skris#ifndef CHARSET_EBCDIC 404280304Sjkim if ((ch >= 'a') && (ch <= 'z')) 405280304Sjkim return 1; 406280304Sjkim if ((ch >= 'A') && (ch <= 'Z')) 407280304Sjkim return 1; 408280304Sjkim if ((ch >= '0') && (ch <= '9')) 409280304Sjkim return 1; 410280304Sjkim if ((ch == ' ') || strchr("'()+,-./:=?", ch)) 411280304Sjkim return 1; 412280304Sjkim#else /* CHARSET_EBCDIC */ 413280304Sjkim if ((ch >= os_toascii['a']) && (ch <= os_toascii['z'])) 414280304Sjkim return 1; 415280304Sjkim if ((ch >= os_toascii['A']) && (ch <= os_toascii['Z'])) 416280304Sjkim return 1; 417280304Sjkim if ((ch >= os_toascii['0']) && (ch <= os_toascii['9'])) 418280304Sjkim return 1; 419280304Sjkim if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch])) 420280304Sjkim return 1; 421280304Sjkim#endif /* CHARSET_EBCDIC */ 422280304Sjkim return 0; 42359191Skris} 424