GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libcrypto/asn1/a_mbstr.c Lines: 96 184 52.2 %
Date: 2017-11-07 Branches: 51 102 50.0 %

Line Branch Exec Source
1
/* $OpenBSD: a_mbstr.c,v 1.23 2017/01/29 17:49:22 beck 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
{
91
244440
	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
{
98
	int str_type;
99
	int ret;
100
	char free_out;
101
122474
	int outform, outlen = 0;
102
	ASN1_STRING *dest;
103
122474
	unsigned char *p;
104
122474
	int nchar;
105
	int (*cpyfunc)(unsigned long, void *) = NULL;
106
107
122474
	if (len < 0)
108
248
		len = strlen((const char *)in);
109
122474
	if (!mask)
110
		mask = DIRSTRING_TYPE;
111
112
	/* First do a string check and work out the number of characters */
113

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

122726
	if ((minsize > 0) && (nchar < minsize)) {
150
		ASN1error(ASN1_R_STRING_TOO_SHORT);
151
		ERR_asprintf_error_data("minsize=%ld", minsize);
152
		return -1;
153
	}
154
155

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

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

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

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