159191Skris/* a_mbstr.c */ 2194206Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 359191Skris * project 1999. 459191Skris */ 559191Skris/* ==================================================================== 659191Skris * Copyright (c) 1999 The OpenSSL Project. All rights reserved. 759191Skris * 859191Skris * Redistribution and use in source and binary forms, with or without 959191Skris * modification, are permitted provided that the following conditions 1059191Skris * are met: 1159191Skris * 1259191Skris * 1. Redistributions of source code must retain the above copyright 1359191Skris * notice, this list of conditions and the following disclaimer. 1459191Skris * 1559191Skris * 2. Redistributions in binary form must reproduce the above copyright 1659191Skris * notice, this list of conditions and the following disclaimer in 1759191Skris * the documentation and/or other materials provided with the 1859191Skris * distribution. 1959191Skris * 2059191Skris * 3. All advertising materials mentioning features or use of this 2159191Skris * software must display the following acknowledgment: 2259191Skris * "This product includes software developed by the OpenSSL Project 2359191Skris * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 2459191Skris * 2559191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 2659191Skris * endorse or promote products derived from this software without 2759191Skris * prior written permission. For written permission, please contact 2859191Skris * licensing@OpenSSL.org. 2959191Skris * 3059191Skris * 5. Products derived from this software may not be called "OpenSSL" 3159191Skris * nor may "OpenSSL" appear in their names without prior written 3259191Skris * permission of the OpenSSL Project. 3359191Skris * 3459191Skris * 6. Redistributions of any form whatsoever must retain the following 3559191Skris * acknowledgment: 3659191Skris * "This product includes software developed by the OpenSSL Project 3759191Skris * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 3859191Skris * 3959191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 4059191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4159191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4259191Skris * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 4359191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 4459191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 4559191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4659191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4759191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4859191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4959191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 5059191Skris * OF THE POSSIBILITY OF SUCH DAMAGE. 5159191Skris * ==================================================================== 5259191Skris * 5359191Skris * This product includes cryptographic software written by Eric Young 5459191Skris * (eay@cryptsoft.com). This product includes software written by Tim 5559191Skris * Hudson (tjh@cryptsoft.com). 5659191Skris * 5759191Skris */ 5859191Skris 5959191Skris#include <stdio.h> 6059191Skris#include <ctype.h> 6159191Skris#include "cryptlib.h" 6259191Skris#include <openssl/asn1.h> 6359191Skris 6459191Skrisstatic int traverse_string(const unsigned char *p, int len, int inform, 6559191Skris int (*rfunc)(unsigned long value, void *in), void *arg); 6659191Skrisstatic int in_utf8(unsigned long value, void *arg); 6759191Skrisstatic int out_utf8(unsigned long value, void *arg); 6859191Skrisstatic int type_str(unsigned long value, void *arg); 6959191Skrisstatic int cpy_asc(unsigned long value, void *arg); 7059191Skrisstatic int cpy_bmp(unsigned long value, void *arg); 7159191Skrisstatic int cpy_univ(unsigned long value, void *arg); 7259191Skrisstatic int cpy_utf8(unsigned long value, void *arg); 7359191Skrisstatic int is_printable(unsigned long value); 7459191Skris 7559191Skris/* These functions take a string in UTF8, ASCII or multibyte form and 7659191Skris * a mask of permissible ASN1 string types. It then works out the minimal 7759191Skris * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) 7859191Skris * and creates a string of the correct type with the supplied data. 7959191Skris * Yes this is horrible: it has to be :-( 8059191Skris * The 'ncopy' form checks minimum and maximum size limits too. 8159191Skris */ 8259191Skris 8359191Skrisint ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, 8459191Skris int inform, unsigned long mask) 8559191Skris{ 8659191Skris return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0); 8759191Skris} 8859191Skris 8959191Skrisint ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, 9059191Skris int inform, unsigned long mask, 9159191Skris long minsize, long maxsize) 9259191Skris{ 9359191Skris int str_type; 9459191Skris int ret; 9568651Skris char free_out; 96205128Ssimon int outform, outlen = 0; 9759191Skris ASN1_STRING *dest; 9859191Skris unsigned char *p; 9959191Skris int nchar; 10059191Skris char strbuf[32]; 10159191Skris int (*cpyfunc)(unsigned long,void *) = NULL; 10259191Skris if(len == -1) len = strlen((const char *)in); 10359191Skris if(!mask) mask = DIRSTRING_TYPE; 10459191Skris 10559191Skris /* First do a string check and work out the number of characters */ 10659191Skris switch(inform) { 10759191Skris 10859191Skris case MBSTRING_BMP: 10959191Skris if(len & 1) { 110160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 11159191Skris ASN1_R_INVALID_BMPSTRING_LENGTH); 11259191Skris return -1; 11359191Skris } 11459191Skris nchar = len >> 1; 11559191Skris break; 11659191Skris 11759191Skris case MBSTRING_UNIV: 11859191Skris if(len & 3) { 119160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 12059191Skris ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); 12159191Skris return -1; 12259191Skris } 12359191Skris nchar = len >> 2; 12459191Skris break; 12559191Skris 12659191Skris case MBSTRING_UTF8: 12759191Skris nchar = 0; 12859191Skris /* This counts the characters and does utf8 syntax checking */ 12959191Skris ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); 13059191Skris if(ret < 0) { 131160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 13259191Skris ASN1_R_INVALID_UTF8STRING); 13359191Skris return -1; 13459191Skris } 13559191Skris break; 13659191Skris 13759191Skris case MBSTRING_ASC: 13859191Skris nchar = len; 13959191Skris break; 14059191Skris 14159191Skris default: 142160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT); 14359191Skris return -1; 14459191Skris } 14559191Skris 14659191Skris if((minsize > 0) && (nchar < minsize)) { 147160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT); 148127128Snectar BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize); 14959191Skris ERR_add_error_data(2, "minsize=", strbuf); 15059191Skris return -1; 15159191Skris } 15259191Skris 15359191Skris if((maxsize > 0) && (nchar > maxsize)) { 154160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG); 155127128Snectar BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize); 15659191Skris ERR_add_error_data(2, "maxsize=", strbuf); 15759191Skris return -1; 15859191Skris } 15959191Skris 16059191Skris /* Now work out minimal type (if any) */ 16159191Skris if(traverse_string(in, len, inform, type_str, &mask) < 0) { 162160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS); 16359191Skris return -1; 16459191Skris } 16559191Skris 16659191Skris 16759191Skris /* Now work out output format and string type */ 16859191Skris outform = MBSTRING_ASC; 16959191Skris if(mask & B_ASN1_PRINTABLESTRING) str_type = V_ASN1_PRINTABLESTRING; 17059191Skris else if(mask & B_ASN1_IA5STRING) str_type = V_ASN1_IA5STRING; 17159191Skris else if(mask & B_ASN1_T61STRING) str_type = V_ASN1_T61STRING; 17259191Skris else if(mask & B_ASN1_BMPSTRING) { 17359191Skris str_type = V_ASN1_BMPSTRING; 17459191Skris outform = MBSTRING_BMP; 17559191Skris } else if(mask & B_ASN1_UNIVERSALSTRING) { 17659191Skris str_type = V_ASN1_UNIVERSALSTRING; 17759191Skris outform = MBSTRING_UNIV; 17859191Skris } else { 17959191Skris str_type = V_ASN1_UTF8STRING; 18059191Skris outform = MBSTRING_UTF8; 18159191Skris } 18259191Skris if(!out) return str_type; 18359191Skris if(*out) { 18468651Skris free_out = 0; 18559191Skris dest = *out; 18659191Skris if(dest->data) { 18759191Skris dest->length = 0; 18868651Skris OPENSSL_free(dest->data); 18959191Skris dest->data = NULL; 19059191Skris } 19159191Skris dest->type = str_type; 19259191Skris } else { 19368651Skris free_out = 1; 19459191Skris dest = ASN1_STRING_type_new(str_type); 19559191Skris if(!dest) { 196160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, 19759191Skris ERR_R_MALLOC_FAILURE); 19859191Skris return -1; 19959191Skris } 20059191Skris *out = dest; 20159191Skris } 20259191Skris /* If both the same type just copy across */ 20359191Skris if(inform == outform) { 20459191Skris if(!ASN1_STRING_set(dest, in, len)) { 205160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,ERR_R_MALLOC_FAILURE); 20659191Skris return -1; 20759191Skris } 20859191Skris return str_type; 20959191Skris } 21059191Skris 21159191Skris /* Work out how much space the destination will need */ 21259191Skris switch(outform) { 21359191Skris case MBSTRING_ASC: 21459191Skris outlen = nchar; 21559191Skris cpyfunc = cpy_asc; 21659191Skris break; 21759191Skris 21859191Skris case MBSTRING_BMP: 21959191Skris outlen = nchar << 1; 22059191Skris cpyfunc = cpy_bmp; 22159191Skris break; 22259191Skris 22359191Skris case MBSTRING_UNIV: 22459191Skris outlen = nchar << 2; 22559191Skris cpyfunc = cpy_univ; 22659191Skris break; 22759191Skris 22859191Skris case MBSTRING_UTF8: 22959191Skris outlen = 0; 23059191Skris traverse_string(in, len, inform, out_utf8, &outlen); 23159191Skris cpyfunc = cpy_utf8; 23259191Skris break; 23359191Skris } 23468651Skris if(!(p = OPENSSL_malloc(outlen + 1))) { 23568651Skris if(free_out) ASN1_STRING_free(dest); 236160814Ssimon ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,ERR_R_MALLOC_FAILURE); 23759191Skris return -1; 23859191Skris } 23959191Skris dest->length = outlen; 24059191Skris dest->data = p; 24159191Skris p[outlen] = 0; 24259191Skris traverse_string(in, len, inform, cpyfunc, &p); 24359191Skris return str_type; 24459191Skris} 24559191Skris 24659191Skris/* This function traverses a string and passes the value of each character 24759191Skris * to an optional function along with a void * argument. 24859191Skris */ 24959191Skris 25059191Skrisstatic int traverse_string(const unsigned char *p, int len, int inform, 25159191Skris int (*rfunc)(unsigned long value, void *in), void *arg) 25259191Skris{ 25359191Skris unsigned long value; 25459191Skris int ret; 25559191Skris while(len) { 25659191Skris if(inform == MBSTRING_ASC) { 25759191Skris value = *p++; 25859191Skris len--; 25959191Skris } else if(inform == MBSTRING_BMP) { 26059191Skris value = *p++ << 8; 26159191Skris value |= *p++; 26259191Skris len -= 2; 26359191Skris } else if(inform == MBSTRING_UNIV) { 26468651Skris value = ((unsigned long)*p++) << 24; 26568651Skris value |= ((unsigned long)*p++) << 16; 26659191Skris value |= *p++ << 8; 26759191Skris value |= *p++; 26859191Skris len -= 4; 26959191Skris } else { 27059191Skris ret = UTF8_getc(p, len, &value); 27159191Skris if(ret < 0) return -1; 27259191Skris len -= ret; 27359191Skris p += ret; 27459191Skris } 27559191Skris if(rfunc) { 27659191Skris ret = rfunc(value, arg); 27759191Skris if(ret <= 0) return ret; 27859191Skris } 27959191Skris } 28059191Skris return 1; 28159191Skris} 28259191Skris 28359191Skris/* Various utility functions for traverse_string */ 28459191Skris 28559191Skris/* Just count number of characters */ 28659191Skris 28759191Skrisstatic int in_utf8(unsigned long value, void *arg) 28859191Skris{ 28959191Skris int *nchar; 29059191Skris nchar = arg; 29159191Skris (*nchar)++; 29259191Skris return 1; 29359191Skris} 29459191Skris 29559191Skris/* Determine size of output as a UTF8 String */ 29659191Skris 29759191Skrisstatic int out_utf8(unsigned long value, void *arg) 29859191Skris{ 299120631Snectar int *outlen; 30059191Skris outlen = arg; 30159191Skris *outlen += UTF8_putc(NULL, -1, value); 30259191Skris return 1; 30359191Skris} 30459191Skris 30559191Skris/* Determine the "type" of a string: check each character against a 30659191Skris * supplied "mask". 30759191Skris */ 30859191Skris 30959191Skrisstatic int type_str(unsigned long value, void *arg) 31059191Skris{ 31159191Skris unsigned long types; 31259191Skris types = *((unsigned long *)arg); 31359191Skris if((types & B_ASN1_PRINTABLESTRING) && !is_printable(value)) 31459191Skris types &= ~B_ASN1_PRINTABLESTRING; 31559191Skris if((types & B_ASN1_IA5STRING) && (value > 127)) 31659191Skris types &= ~B_ASN1_IA5STRING; 31759191Skris if((types & B_ASN1_T61STRING) && (value > 0xff)) 31859191Skris types &= ~B_ASN1_T61STRING; 31959191Skris if((types & B_ASN1_BMPSTRING) && (value > 0xffff)) 32059191Skris types &= ~B_ASN1_BMPSTRING; 32159191Skris if(!types) return -1; 32259191Skris *((unsigned long *)arg) = types; 32359191Skris return 1; 32459191Skris} 32559191Skris 32659191Skris/* Copy one byte per character ASCII like strings */ 32759191Skris 32859191Skrisstatic int cpy_asc(unsigned long value, void *arg) 32959191Skris{ 33059191Skris unsigned char **p, *q; 33159191Skris p = arg; 33259191Skris q = *p; 33359191Skris *q = (unsigned char) value; 33459191Skris (*p)++; 33559191Skris return 1; 33659191Skris} 33759191Skris 33859191Skris/* Copy two byte per character BMPStrings */ 33959191Skris 34059191Skrisstatic int cpy_bmp(unsigned long value, void *arg) 34159191Skris{ 34259191Skris unsigned char **p, *q; 34359191Skris p = arg; 34459191Skris q = *p; 34559191Skris *q++ = (unsigned char) ((value >> 8) & 0xff); 34659191Skris *q = (unsigned char) (value & 0xff); 34759191Skris *p += 2; 34859191Skris return 1; 34959191Skris} 35059191Skris 35159191Skris/* Copy four byte per character UniversalStrings */ 35259191Skris 35359191Skrisstatic int cpy_univ(unsigned long value, void *arg) 35459191Skris{ 35559191Skris unsigned char **p, *q; 35659191Skris p = arg; 35759191Skris q = *p; 35859191Skris *q++ = (unsigned char) ((value >> 24) & 0xff); 35959191Skris *q++ = (unsigned char) ((value >> 16) & 0xff); 36059191Skris *q++ = (unsigned char) ((value >> 8) & 0xff); 36159191Skris *q = (unsigned char) (value & 0xff); 36259191Skris *p += 4; 36359191Skris return 1; 36459191Skris} 36559191Skris 36659191Skris/* Copy to a UTF8String */ 36759191Skris 36859191Skrisstatic int cpy_utf8(unsigned long value, void *arg) 36959191Skris{ 37059191Skris unsigned char **p; 37159191Skris int ret; 37259191Skris p = arg; 37359191Skris /* We already know there is enough room so pass 0xff as the length */ 37459191Skris ret = UTF8_putc(*p, 0xff, value); 37559191Skris *p += ret; 37659191Skris return 1; 37759191Skris} 37859191Skris 37959191Skris/* Return 1 if the character is permitted in a PrintableString */ 38059191Skrisstatic int is_printable(unsigned long value) 38159191Skris{ 38259191Skris int ch; 38359191Skris if(value > 0x7f) return 0; 38459191Skris ch = (int) value; 38559191Skris /* Note: we can't use 'isalnum' because certain accented 38659191Skris * characters may count as alphanumeric in some environments. 38759191Skris */ 38868651Skris#ifndef CHARSET_EBCDIC 38959191Skris if((ch >= 'a') && (ch <= 'z')) return 1; 39059191Skris if((ch >= 'A') && (ch <= 'Z')) return 1; 39159191Skris if((ch >= '0') && (ch <= '9')) return 1; 39259191Skris if ((ch == ' ') || strchr("'()+,-./:=?", ch)) return 1; 39368651Skris#else /*CHARSET_EBCDIC*/ 39468651Skris if((ch >= os_toascii['a']) && (ch <= os_toascii['z'])) return 1; 39568651Skris if((ch >= os_toascii['A']) && (ch <= os_toascii['Z'])) return 1; 39668651Skris if((ch >= os_toascii['0']) && (ch <= os_toascii['9'])) return 1; 39768651Skris if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch])) return 1; 39868651Skris#endif /*CHARSET_EBCDIC*/ 39959191Skris return 0; 40059191Skris} 401