ssl/libcrypto/src/crypto/asn1/a_mbstr.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* a_mbstr.c */
       
     2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) 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 
       
    64 static int traverse_string(const unsigned char *p, int len, int inform,
       
    65 		 int (*rfunc)(unsigned long value, void *in), void *arg);
       
    66 static int in_utf8(unsigned long value, void *arg);
       
    67 static int out_utf8(unsigned long value, void *arg);
       
    68 static int type_str(unsigned long value, void *arg);
       
    69 static int cpy_asc(unsigned long value, void *arg);
       
    70 static int cpy_bmp(unsigned long value, void *arg);
       
    71 static int cpy_univ(unsigned long value, void *arg);
       
    72 static int cpy_utf8(unsigned long value, void *arg);
       
    73 static int is_printable(unsigned long value);
       
    74 
       
    75 /* These functions take a string in UTF8, ASCII or multibyte form and
       
    76  * a mask of permissible ASN1 string types. It then works out the minimal
       
    77  * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8)
       
    78  * and creates a string of the correct type with the supplied data.
       
    79  * Yes this is horrible: it has to be :-(
       
    80  * The 'ncopy' form checks minimum and maximum size limits too.
       
    81  */
       
    82 
       
    83 EXPORT_C int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
       
    84 					int inform, unsigned long mask)
       
    85 {
       
    86 	return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
       
    87 }
       
    88 
       
    89 EXPORT_C int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
       
    90 					int inform, unsigned long mask, 
       
    91 					long minsize, long maxsize)
       
    92 {
       
    93 	int str_type;
       
    94 	int ret;
       
    95 	char free_out;
       
    96 	int outform, outlen;
       
    97 	ASN1_STRING *dest;
       
    98 	unsigned char *p;
       
    99 	int nchar;
       
   100 	char strbuf[32];
       
   101 	int (*cpyfunc)(unsigned long,void *) = NULL;
       
   102 	if(len == -1) len = strlen((const char *)in);
       
   103 	if(!mask) mask = DIRSTRING_TYPE;
       
   104 
       
   105 	/* First do a string check and work out the number of characters */
       
   106 	switch(inform) {
       
   107 
       
   108 		case MBSTRING_BMP:
       
   109 		if(len & 1) {
       
   110 			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
       
   111 					 ASN1_R_INVALID_BMPSTRING_LENGTH);
       
   112 			return -1;
       
   113 		}
       
   114 		nchar = len >> 1;
       
   115 		break;
       
   116 
       
   117 		case MBSTRING_UNIV:
       
   118 		if(len & 3) {
       
   119 			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
       
   120 					 ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
       
   121 			return -1;
       
   122 		}
       
   123 		nchar = len >> 2;
       
   124 		break;
       
   125 
       
   126 		case MBSTRING_UTF8:
       
   127 		nchar = 0;
       
   128 		/* This counts the characters and does utf8 syntax checking */
       
   129 		ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
       
   130 		if(ret < 0) {
       
   131 			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
       
   132 						 ASN1_R_INVALID_UTF8STRING);
       
   133 			return -1;
       
   134 		}
       
   135 		break;
       
   136 
       
   137 		case MBSTRING_ASC:
       
   138 		nchar = len;
       
   139 		break;
       
   140 
       
   141 		default:
       
   142 		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT);
       
   143 		return -1;
       
   144 	}
       
   145 
       
   146 	if((minsize > 0) && (nchar < minsize)) {
       
   147 		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT);
       
   148 		BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize);
       
   149 		ERR_add_error_data(2, "minsize=", strbuf);
       
   150 		return -1;
       
   151 	}
       
   152 
       
   153 	if((maxsize > 0) && (nchar > maxsize)) {
       
   154 		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG);
       
   155 		BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize);
       
   156 		ERR_add_error_data(2, "maxsize=", strbuf);
       
   157 		return -1;
       
   158 	}
       
   159 
       
   160 	/* Now work out minimal type (if any) */
       
   161 	if(traverse_string(in, len, inform, type_str, &mask) < 0) {
       
   162 		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS);
       
   163 		return -1;
       
   164 	}
       
   165 
       
   166 
       
   167 	/* Now work out output format and string type */
       
   168 	outform = MBSTRING_ASC;
       
   169 	if(mask & B_ASN1_PRINTABLESTRING) str_type = V_ASN1_PRINTABLESTRING;
       
   170 	else if(mask & B_ASN1_IA5STRING) str_type = V_ASN1_IA5STRING;
       
   171 	else if(mask & B_ASN1_T61STRING) str_type = V_ASN1_T61STRING;
       
   172 	else if(mask & B_ASN1_BMPSTRING) {
       
   173 		str_type = V_ASN1_BMPSTRING;
       
   174 		outform = MBSTRING_BMP;
       
   175 	} else if(mask & B_ASN1_UNIVERSALSTRING) {
       
   176 		str_type = V_ASN1_UNIVERSALSTRING;
       
   177 		outform = MBSTRING_UNIV;
       
   178 	} else {
       
   179 		str_type = V_ASN1_UTF8STRING;
       
   180 		outform = MBSTRING_UTF8;
       
   181 	}
       
   182 	if(!out) return str_type;
       
   183 	if(*out) {
       
   184 		free_out = 0;
       
   185 		dest = *out;
       
   186 		if(dest->data) {
       
   187 			dest->length = 0;
       
   188 			OPENSSL_free(dest->data);
       
   189 			dest->data = NULL;
       
   190 		}
       
   191 		dest->type = str_type;
       
   192 	} else {
       
   193 		free_out = 1;
       
   194 		dest = ASN1_STRING_type_new(str_type);
       
   195 		if(!dest) {
       
   196 			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
       
   197 							ERR_R_MALLOC_FAILURE);
       
   198 			return -1;
       
   199 		}
       
   200 		*out = dest;
       
   201 	}
       
   202 	/* If both the same type just copy across */
       
   203 	if(inform == outform) {
       
   204 		if(!ASN1_STRING_set(dest, in, len)) {
       
   205 			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,ERR_R_MALLOC_FAILURE);
       
   206 			return -1;
       
   207 		}
       
   208 		return str_type;
       
   209 	} 
       
   210 
       
   211 	/* Work out how much space the destination will need */
       
   212 	switch(outform) {
       
   213 		case MBSTRING_ASC:
       
   214 		outlen = nchar;
       
   215 		cpyfunc = cpy_asc;
       
   216 		break;
       
   217 
       
   218 		case MBSTRING_BMP:
       
   219 		outlen = nchar << 1;
       
   220 		cpyfunc = cpy_bmp;
       
   221 		break;
       
   222 
       
   223 		case MBSTRING_UNIV:
       
   224 		outlen = nchar << 2;
       
   225 		cpyfunc = cpy_univ;
       
   226 		break;
       
   227 
       
   228 		case MBSTRING_UTF8:
       
   229 		outlen = 0;
       
   230 		traverse_string(in, len, inform, out_utf8, &outlen);
       
   231 		cpyfunc = cpy_utf8;
       
   232 		break;
       
   233 	}
       
   234 	if(!(p = OPENSSL_malloc(outlen + 1))) {
       
   235 		if(free_out) ASN1_STRING_free(dest);
       
   236 		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,ERR_R_MALLOC_FAILURE);
       
   237 		return -1;
       
   238 	}
       
   239 	dest->length = outlen;
       
   240 	dest->data = p;
       
   241 	p[outlen] = 0;
       
   242 	traverse_string(in, len, inform, cpyfunc, &p);
       
   243 	return str_type;	
       
   244 }
       
   245 
       
   246 /* This function traverses a string and passes the value of each character
       
   247  * to an optional function along with a void * argument.
       
   248  */
       
   249 
       
   250 static int traverse_string(const unsigned char *p, int len, int inform,
       
   251 		 int (*rfunc)(unsigned long value, void *in), void *arg)
       
   252 {
       
   253 	unsigned long value;
       
   254 	int ret;
       
   255 	while(len) {
       
   256 		if(inform == MBSTRING_ASC) {
       
   257 			value = *p++;
       
   258 			len--;
       
   259 		} else if(inform == MBSTRING_BMP) {
       
   260 			value = *p++ << 8;
       
   261 			value |= *p++;
       
   262 			len -= 2;
       
   263 		} else if(inform == MBSTRING_UNIV) {
       
   264 			value = ((unsigned long)*p++) << 24;
       
   265 			value |= ((unsigned long)*p++) << 16;
       
   266 			value |= *p++ << 8;
       
   267 			value |= *p++;
       
   268 			len -= 4;
       
   269 		} else {
       
   270 			ret = UTF8_getc(p, len, &value);
       
   271 			if(ret < 0) return -1;
       
   272 			len -= ret;
       
   273 			p += ret;
       
   274 		}
       
   275 		if(rfunc) {
       
   276 			ret = rfunc(value, arg);
       
   277 			if(ret <= 0) return ret;
       
   278 		}
       
   279 	}
       
   280 	return 1;
       
   281 }
       
   282 
       
   283 /* Various utility functions for traverse_string */
       
   284 
       
   285 /* Just count number of characters */
       
   286 
       
   287 static int in_utf8(unsigned long value, void *arg)
       
   288 {
       
   289 	int *nchar;
       
   290 	nchar = arg;
       
   291 	(*nchar)++;
       
   292 	return 1;
       
   293 }
       
   294 
       
   295 /* Determine size of output as a UTF8 String */
       
   296 
       
   297 static int out_utf8(unsigned long value, void *arg)
       
   298 {
       
   299 	int *outlen;
       
   300 	outlen = arg;
       
   301 	*outlen += UTF8_putc(NULL, -1, value);
       
   302 	return 1;
       
   303 }
       
   304 
       
   305 /* Determine the "type" of a string: check each character against a
       
   306  * supplied "mask".
       
   307  */
       
   308 
       
   309 static int type_str(unsigned long value, void *arg)
       
   310 {
       
   311 	unsigned long types;
       
   312 	types = *((unsigned long *)arg);
       
   313 	if((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
       
   314 					types &= ~B_ASN1_PRINTABLESTRING;
       
   315 	if((types & B_ASN1_IA5STRING) && (value > 127))
       
   316 					types &= ~B_ASN1_IA5STRING;
       
   317 	if((types & B_ASN1_T61STRING) && (value > 0xff))
       
   318 					types &= ~B_ASN1_T61STRING;
       
   319 	if((types & B_ASN1_BMPSTRING) && (value > 0xffff))
       
   320 					types &= ~B_ASN1_BMPSTRING;
       
   321 	if(!types) return -1;
       
   322 	*((unsigned long *)arg) = types;
       
   323 	return 1;
       
   324 }
       
   325 
       
   326 /* Copy one byte per character ASCII like strings */
       
   327 
       
   328 static int cpy_asc(unsigned long value, void *arg)
       
   329 {
       
   330 	unsigned char **p, *q;
       
   331 	p = arg;
       
   332 	q = *p;
       
   333 	*q = (unsigned char) value;
       
   334 	(*p)++;
       
   335 	return 1;
       
   336 }
       
   337 
       
   338 /* Copy two byte per character BMPStrings */
       
   339 
       
   340 static int cpy_bmp(unsigned long value, void *arg)
       
   341 {
       
   342 	unsigned char **p, *q;
       
   343 	p = arg;
       
   344 	q = *p;
       
   345 	*q++ = (unsigned char) ((value >> 8) & 0xff);
       
   346 	*q = (unsigned char) (value & 0xff);
       
   347 	*p += 2;
       
   348 	return 1;
       
   349 }
       
   350 
       
   351 /* Copy four byte per character UniversalStrings */
       
   352 
       
   353 static int cpy_univ(unsigned long value, void *arg)
       
   354 {
       
   355 	unsigned char **p, *q;
       
   356 	p = arg;
       
   357 	q = *p;
       
   358 	*q++ = (unsigned char) ((value >> 24) & 0xff);
       
   359 	*q++ = (unsigned char) ((value >> 16) & 0xff);
       
   360 	*q++ = (unsigned char) ((value >> 8) & 0xff);
       
   361 	*q = (unsigned char) (value & 0xff);
       
   362 	*p += 4;
       
   363 	return 1;
       
   364 }
       
   365 
       
   366 /* Copy to a UTF8String */
       
   367 
       
   368 static int cpy_utf8(unsigned long value, void *arg)
       
   369 {
       
   370 	unsigned char **p;
       
   371 	int ret;
       
   372 	p = arg;
       
   373 	/* We already know there is enough room so pass 0xff as the length */
       
   374 	ret = UTF8_putc(*p, 0xff, value);
       
   375 	*p += ret;
       
   376 	return 1;
       
   377 }
       
   378 
       
   379 /* Return 1 if the character is permitted in a PrintableString */
       
   380 static int is_printable(unsigned long value)
       
   381 {
       
   382 	int ch;
       
   383 	if(value > 0x7f) return 0;
       
   384 	ch = (int) value;
       
   385 	/* Note: we can't use 'isalnum' because certain accented 
       
   386 	 * characters may count as alphanumeric in some environments.
       
   387 	 */
       
   388 #ifndef CHARSET_EBCDIC
       
   389 	if((ch >= 'a') && (ch <= 'z')) return 1;
       
   390 	if((ch >= 'A') && (ch <= 'Z')) return 1;
       
   391 	if((ch >= '0') && (ch <= '9')) return 1;
       
   392 	if ((ch == ' ') || strchr("'()+,-./:=?", ch)) return 1;
       
   393 #else /*CHARSET_EBCDIC*/
       
   394 	if((ch >= os_toascii['a']) && (ch <= os_toascii['z'])) return 1;
       
   395 	if((ch >= os_toascii['A']) && (ch <= os_toascii['Z'])) return 1;
       
   396 	if((ch >= os_toascii['0']) && (ch <= os_toascii['9'])) return 1;
       
   397 	if ((ch == os_toascii[' ']) || strchr("'()+,-./:=?", os_toebcdic[ch])) return 1;
       
   398 #endif /*CHARSET_EBCDIC*/
       
   399 	return 0;
       
   400 }