GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/crypto/../../libssl/src/crypto/asn1/a_mbstr.c Lines: 81 195 41.5 %
Date: 2016-12-06 Branches: 35 100 35.0 %

Line Branch Exec Source
1
/* $OpenBSD: a_mbstr.c,v 1.22 2015/07/16 02:18:58 miod Exp $ */
2
/* Written by Dr Stephen N Henson (steve@openssl.org) 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 <ctype.h>
60
#include <stdio.h>
61
#include <string.h>
62
63
#include <openssl/asn1.h>
64
#include <openssl/err.h>
65
66
#include "asn1_locl.h"
67
68
static int traverse_string(const unsigned char *p, int len, int inform,
69
    int (*rfunc)(unsigned long value, void *in), void *arg);
70
static int in_utf8(unsigned long value, void *arg);
71
static int out_utf8(unsigned long value, void *arg);
72
static int type_str(unsigned long value, void *arg);
73
static int cpy_asc(unsigned long value, void *arg);
74
static int cpy_bmp(unsigned long value, void *arg);
75
static int cpy_univ(unsigned long value, void *arg);
76
static int cpy_utf8(unsigned long value, void *arg);
77
static int is_printable(unsigned long value);
78
79
/* These functions take a string in UTF8, ASCII or multibyte form and
80
 * a mask of permissible ASN1 string types. It then works out the minimal
81
 * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8)
82
 * and creates a string of the correct type with the supplied data.
83
 * Yes this is horrible: it has to be :-(
84
 * The 'ncopy' form checks minimum and maximum size limits too.
85
 */
86
87
int
88
ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
89
    int inform, unsigned long mask)
90
1352
{
91
1352
	return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
92
}
93
94
int
95
ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
96
    int inform, unsigned long mask, long minsize, long maxsize)
97
1352
{
98
	int str_type;
99
	int ret;
100
	char free_out;
101
1352
	int outform, outlen = 0;
102
	ASN1_STRING *dest;
103
	unsigned char *p;
104
	int nchar;
105
1352
	int (*cpyfunc)(unsigned long, void *) = NULL;
106
107
1352
	if (len < 0)
108
		len = strlen((const char *)in);
109
1352
	if (!mask)
110
		mask = DIRSTRING_TYPE;
111
112
	/* First do a string check and work out the number of characters */
113

1352
	switch (inform) {
114
	case MBSTRING_BMP:
115
		if (len & 1) {
116
			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
117
			    ASN1_R_INVALID_BMPSTRING_LENGTH);
118
			return -1;
119
		}
120
		nchar = len >> 1;
121
		break;
122
123
	case MBSTRING_UNIV:
124
		if (len & 3) {
125
			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
126
			    ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
127
			return -1;
128
		}
129
		nchar = len >> 2;
130
		break;
131
132
	case MBSTRING_UTF8:
133
134
		nchar = 0;
134
		/* This counts the characters and does utf8 syntax checking */
135
134
		ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
136
134
		if (ret < 0) {
137
			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
138
			    ASN1_R_INVALID_UTF8STRING);
139
			return -1;
140
		}
141
		break;
142
143
	case MBSTRING_ASC:
144
1218
		nchar = len;
145
1218
		break;
146
147
	default:
148
		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_UNKNOWN_FORMAT);
149
		return -1;
150
	}
151
152

1352
	if ((minsize > 0) && (nchar < minsize)) {
153
		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_SHORT);
154
		ERR_asprintf_error_data("minsize=%ld", minsize);
155
		return -1;
156
	}
157
158

1352
	if ((maxsize > 0) && (nchar > maxsize)) {
159
		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_STRING_TOO_LONG);
160
		ERR_asprintf_error_data("maxsize=%ld", maxsize);
161
		return -1;
162
	}
163
164
	/* Now work out minimal type (if any) */
165
1352
	if (traverse_string(in, len, inform, type_str, &mask) < 0) {
166
		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ASN1_R_ILLEGAL_CHARACTERS);
167
		return -1;
168
	}
169
170
171
	/* Now work out output format and string type */
172
1352
	outform = MBSTRING_ASC;
173
1352
	if (mask & B_ASN1_PRINTABLESTRING)
174
		str_type = V_ASN1_PRINTABLESTRING;
175
1352
	else if (mask & B_ASN1_IA5STRING)
176
		str_type = V_ASN1_IA5STRING;
177
1352
	else if (mask & B_ASN1_T61STRING)
178
		str_type = V_ASN1_T61STRING;
179
1352
	else if (mask & B_ASN1_BMPSTRING) {
180
		str_type = V_ASN1_BMPSTRING;
181
		outform = MBSTRING_BMP;
182
1352
	} else if (mask & B_ASN1_UNIVERSALSTRING) {
183
		str_type = V_ASN1_UNIVERSALSTRING;
184
		outform = MBSTRING_UNIV;
185
	} else {
186
1352
		str_type = V_ASN1_UTF8STRING;
187
1352
		outform = MBSTRING_UTF8;
188
	}
189
1352
	if (!out)
190
		return str_type;
191
1352
	if (*out) {
192
1352
		free_out = 0;
193
1352
		dest = *out;
194
1352
		if (dest->data) {
195
			dest->length = 0;
196
			free(dest->data);
197
			dest->data = NULL;
198
		}
199
1352
		dest->type = str_type;
200
	} else {
201
		free_out = 1;
202
		dest = ASN1_STRING_type_new(str_type);
203
		if (!dest) {
204
			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
205
			    ERR_R_MALLOC_FAILURE);
206
			return -1;
207
		}
208
		*out = dest;
209
	}
210
	/* If both the same type just copy across */
211
1352
	if (inform == outform) {
212
134
		if (!ASN1_STRING_set(dest, in, len)) {
213
			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
214
			    ERR_R_MALLOC_FAILURE);
215
			goto err;
216
		}
217
134
		return str_type;
218
	}
219
220
	/* Work out how much space the destination will need */
221

1218
	switch (outform) {
222
	case MBSTRING_ASC:
223
		outlen = nchar;
224
		cpyfunc = cpy_asc;
225
		break;
226
227
	case MBSTRING_BMP:
228
		outlen = nchar << 1;
229
		cpyfunc = cpy_bmp;
230
		break;
231
232
	case MBSTRING_UNIV:
233
		outlen = nchar << 2;
234
		cpyfunc = cpy_univ;
235
		break;
236
237
	case MBSTRING_UTF8:
238
1218
		outlen = 0;
239
1218
		if (traverse_string(in, len, inform, out_utf8, &outlen) < 0) {
240
			ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY,
241
			    ASN1_R_ILLEGAL_CHARACTERS);
242
			goto err;
243
		}
244
1218
		cpyfunc = cpy_utf8;
245
		break;
246
	}
247
1218
	if (!(p = malloc(outlen + 1))) {
248
		ASN1err(ASN1_F_ASN1_MBSTRING_NCOPY, ERR_R_MALLOC_FAILURE);
249
		goto err;
250
	}
251
1218
	dest->length = outlen;
252
1218
	dest->data = p;
253
1218
	p[outlen] = 0;
254
1218
	traverse_string(in, len, inform, cpyfunc, &p);
255
1218
	return str_type;
256
257
err:
258
	if (free_out) {
259
		ASN1_STRING_free(dest);
260
		*out = NULL;
261
	}
262
	return -1;
263
}
264
265
/* This function traverses a string and passes the value of each character
266
 * to an optional function along with a void * argument.
267
 */
268
269
static int
270
traverse_string(const unsigned char *p, int len, int inform,
271
    int (*rfunc)(unsigned long value, void *in), void *arg)
272
3922
{
273
	unsigned long value;
274
	int ret;
275
276
79574
	while (len) {
277

71730
		switch (inform) {
278
		case MBSTRING_ASC:
279
66084
			value = *p++;
280
66084
			len--;
281
66084
			break;
282
		case MBSTRING_BMP:
283
			value = *p++ << 8;
284
			value |= *p++;
285
			/* BMP is explictly defined to not support surrogates */
286
			if (UNICODE_IS_SURROGATE(value))
287
				return -1;
288
			len -= 2;
289
			break;
290
		case MBSTRING_UNIV:
291
			value = (unsigned long)*p++ << 24;
292
			value |= *p++ << 16;
293
			value |= *p++ << 8;
294
			value |= *p++;
295
			if (value > UNICODE_MAX || UNICODE_IS_SURROGATE(value))
296
				return -1;
297
			len -= 4;
298
			break;
299
		default:
300
5646
			ret = UTF8_getc(p, len, &value);
301
5646
			if (ret < 0)
302
				return -1;
303
5646
			len -= ret;
304
5646
			p += ret;
305
			break;
306
		}
307
71730
		if (rfunc) {
308
71730
			ret = rfunc(value, arg);
309
71730
			if (ret <= 0)
310
				return ret;
311
		}
312
	}
313
3922
	return 1;
314
}
315
316
/* Various utility functions for traverse_string */
317
318
/* Just count number of characters */
319
320
static int
321
in_utf8(unsigned long value, void *arg)
322
2823
{
323
	int *nchar;
324
325
2823
	nchar = arg;
326
2823
	(*nchar)++;
327
2823
	return 1;
328
}
329
330
/* Determine size of output as a UTF8 String */
331
332
static int
333
out_utf8(unsigned long value, void *arg)
334
22028
{
335
	int *outlen;
336
	int ret;
337
338
22028
	outlen = arg;
339
22028
	ret = UTF8_putc(NULL, -1, value);
340
22028
	if (ret < 0)
341
		return ret;
342
22028
	*outlen += ret;
343
22028
	return 1;
344
}
345
346
/* Determine the "type" of a string: check each character against a
347
 * supplied "mask".
348
 */
349
350
static int
351
type_str(unsigned long value, void *arg)
352
24851
{
353
	unsigned long types;
354
355
24851
	types = *((unsigned long *)arg);
356

24851
	if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
357
		types &= ~B_ASN1_PRINTABLESTRING;
358
24851
	if ((types & B_ASN1_IA5STRING) && (value > 127))
359
		types &= ~B_ASN1_IA5STRING;
360
24851
	if ((types & B_ASN1_T61STRING) && (value > 0xff))
361
		types &= ~B_ASN1_T61STRING;
362
24851
	if ((types & B_ASN1_BMPSTRING) && (value > 0xffff))
363
		types &= ~B_ASN1_BMPSTRING;
364
24851
	if (!types)
365
		return -1;
366
24851
	*((unsigned long *)arg) = types;
367
24851
	return 1;
368
}
369
370
/* Copy one byte per character ASCII like strings */
371
372
static int
373
cpy_asc(unsigned long value, void *arg)
374
{
375
	unsigned char **p, *q;
376
377
	p = arg;
378
	q = *p;
379
	*q = value;
380
	(*p)++;
381
	return 1;
382
}
383
384
/* Copy two byte per character BMPStrings */
385
386
static int
387
cpy_bmp(unsigned long value, void *arg)
388
{
389
	unsigned char **p, *q;
390
391
	p = arg;
392
	q = *p;
393
	*q++ = (value >> 8) & 0xff;
394
	*q = value & 0xff;
395
	*p += 2;
396
	return 1;
397
}
398
399
/* Copy four byte per character UniversalStrings */
400
401
static int
402
cpy_univ(unsigned long value, void *arg)
403
{
404
	unsigned char **p, *q;
405
406
	p = arg;
407
	q = *p;
408
	*q++ = (value >> 24) & 0xff;
409
	*q++ = (value >> 16) & 0xff;
410
	*q++ = (value >> 8) & 0xff;
411
	*q = value & 0xff;
412
	*p += 4;
413
	return 1;
414
}
415
416
/* Copy to a UTF8String */
417
418
static int
419
cpy_utf8(unsigned long value, void *arg)
420
22028
{
421
	unsigned char **p;
422
423
	int ret;
424
22028
	p = arg;
425
	/* We already know there is enough room so pass 0xff as the length */
426
22028
	ret = UTF8_putc(*p, 0xff, value);
427
22028
	*p += ret;
428
22028
	return 1;
429
}
430
431
/* Return 1 if the character is permitted in a PrintableString */
432
static int
433
is_printable(unsigned long value)
434
{
435
	int ch;
436
437
	if (value > 0x7f)
438
		return 0;
439
	ch = (int)value;
440
441
	/* Note: we can't use 'isalnum' because certain accented
442
	 * characters may count as alphanumeric in some environments.
443
	 */
444
	if ((ch >= 'a') && (ch <= 'z'))
445
		return 1;
446
	if ((ch >= 'A') && (ch <= 'Z'))
447
		return 1;
448
	if ((ch >= '0') && (ch <= '9'))
449
		return 1;
450
	if ((ch == ' ') || strchr("'()+,-./:=?", ch))
451
		return 1;
452
	return 0;
453
}