1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: a_mbstr.c,v 1.24 2021/12/25 13:17:48 jsing Exp $ */
2f5b1c8a1SJohn Marino /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3f5b1c8a1SJohn Marino  * project 1999.
4f5b1c8a1SJohn Marino  */
5f5b1c8a1SJohn Marino /* ====================================================================
6f5b1c8a1SJohn Marino  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7f5b1c8a1SJohn Marino  *
8f5b1c8a1SJohn Marino  * Redistribution and use in source and binary forms, with or without
9f5b1c8a1SJohn Marino  * modification, are permitted provided that the following conditions
10f5b1c8a1SJohn Marino  * are met:
11f5b1c8a1SJohn Marino  *
12f5b1c8a1SJohn Marino  * 1. Redistributions of source code must retain the above copyright
13f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer.
14f5b1c8a1SJohn Marino  *
15f5b1c8a1SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
16f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer in
17f5b1c8a1SJohn Marino  *    the documentation and/or other materials provided with the
18f5b1c8a1SJohn Marino  *    distribution.
19f5b1c8a1SJohn Marino  *
20f5b1c8a1SJohn Marino  * 3. All advertising materials mentioning features or use of this
21f5b1c8a1SJohn Marino  *    software must display the following acknowledgment:
22f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
23f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24f5b1c8a1SJohn Marino  *
25f5b1c8a1SJohn Marino  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26f5b1c8a1SJohn Marino  *    endorse or promote products derived from this software without
27f5b1c8a1SJohn Marino  *    prior written permission. For written permission, please contact
28f5b1c8a1SJohn Marino  *    licensing@OpenSSL.org.
29f5b1c8a1SJohn Marino  *
30f5b1c8a1SJohn Marino  * 5. Products derived from this software may not be called "OpenSSL"
31f5b1c8a1SJohn Marino  *    nor may "OpenSSL" appear in their names without prior written
32f5b1c8a1SJohn Marino  *    permission of the OpenSSL Project.
33f5b1c8a1SJohn Marino  *
34f5b1c8a1SJohn Marino  * 6. Redistributions of any form whatsoever must retain the following
35f5b1c8a1SJohn Marino  *    acknowledgment:
36f5b1c8a1SJohn Marino  *    "This product includes software developed by the OpenSSL Project
37f5b1c8a1SJohn Marino  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38f5b1c8a1SJohn Marino  *
39f5b1c8a1SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40f5b1c8a1SJohn Marino  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41f5b1c8a1SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42f5b1c8a1SJohn Marino  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43f5b1c8a1SJohn Marino  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44f5b1c8a1SJohn Marino  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45f5b1c8a1SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46f5b1c8a1SJohn Marino  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47f5b1c8a1SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48f5b1c8a1SJohn Marino  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49f5b1c8a1SJohn Marino  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50f5b1c8a1SJohn Marino  * OF THE POSSIBILITY OF SUCH DAMAGE.
51f5b1c8a1SJohn Marino  * ====================================================================
52f5b1c8a1SJohn Marino  *
53f5b1c8a1SJohn Marino  * This product includes cryptographic software written by Eric Young
54f5b1c8a1SJohn Marino  * (eay@cryptsoft.com).  This product includes software written by Tim
55f5b1c8a1SJohn Marino  * Hudson (tjh@cryptsoft.com).
56f5b1c8a1SJohn Marino  *
57f5b1c8a1SJohn Marino  */
58f5b1c8a1SJohn Marino 
59f5b1c8a1SJohn Marino #include <ctype.h>
60f5b1c8a1SJohn Marino #include <stdio.h>
61f5b1c8a1SJohn Marino #include <string.h>
62f5b1c8a1SJohn Marino 
63f5b1c8a1SJohn Marino #include <openssl/asn1.h>
64f5b1c8a1SJohn Marino #include <openssl/err.h>
65f5b1c8a1SJohn Marino 
66f5b1c8a1SJohn Marino #include "asn1_locl.h"
67f5b1c8a1SJohn Marino 
68f5b1c8a1SJohn Marino static int traverse_string(const unsigned char *p, int len, int inform,
69f5b1c8a1SJohn Marino     int (*rfunc)(unsigned long value, void *in), void *arg);
70f5b1c8a1SJohn Marino static int in_utf8(unsigned long value, void *arg);
71f5b1c8a1SJohn Marino static int out_utf8(unsigned long value, void *arg);
72f5b1c8a1SJohn Marino static int type_str(unsigned long value, void *arg);
73f5b1c8a1SJohn Marino static int cpy_asc(unsigned long value, void *arg);
74f5b1c8a1SJohn Marino static int cpy_bmp(unsigned long value, void *arg);
75f5b1c8a1SJohn Marino static int cpy_univ(unsigned long value, void *arg);
76f5b1c8a1SJohn Marino static int cpy_utf8(unsigned long value, void *arg);
77f5b1c8a1SJohn Marino static int is_printable(unsigned long value);
78f5b1c8a1SJohn Marino 
79f5b1c8a1SJohn Marino /* These functions take a string in UTF8, ASCII or multibyte form and
80f5b1c8a1SJohn Marino  * a mask of permissible ASN1 string types. It then works out the minimal
81f5b1c8a1SJohn Marino  * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8)
82f5b1c8a1SJohn Marino  * and creates a string of the correct type with the supplied data.
83f5b1c8a1SJohn Marino  * Yes this is horrible: it has to be :-(
84f5b1c8a1SJohn Marino  * The 'ncopy' form checks minimum and maximum size limits too.
85f5b1c8a1SJohn Marino  */
86f5b1c8a1SJohn Marino 
87f5b1c8a1SJohn Marino int
ASN1_mbstring_copy(ASN1_STRING ** out,const unsigned char * in,int len,int inform,unsigned long mask)88f5b1c8a1SJohn Marino ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
89f5b1c8a1SJohn Marino     int inform, unsigned long mask)
90f5b1c8a1SJohn Marino {
91f5b1c8a1SJohn Marino 	return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
92f5b1c8a1SJohn Marino }
93f5b1c8a1SJohn Marino 
94f5b1c8a1SJohn Marino int
ASN1_mbstring_ncopy(ASN1_STRING ** out,const unsigned char * in,int len,int inform,unsigned long mask,long minsize,long maxsize)95f5b1c8a1SJohn Marino ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
96f5b1c8a1SJohn Marino     int inform, unsigned long mask, long minsize, long maxsize)
97f5b1c8a1SJohn Marino {
98f5b1c8a1SJohn Marino 	int str_type;
99f5b1c8a1SJohn Marino 	int ret;
100f5b1c8a1SJohn Marino 	char free_out;
101f5b1c8a1SJohn Marino 	int outform, outlen = 0;
102f5b1c8a1SJohn Marino 	ASN1_STRING *dest;
103f5b1c8a1SJohn Marino 	unsigned char *p;
104f5b1c8a1SJohn Marino 	int nchar;
105f5b1c8a1SJohn Marino 	int (*cpyfunc)(unsigned long, void *) = NULL;
106f5b1c8a1SJohn Marino 
107f5b1c8a1SJohn Marino 	if (len < 0)
108f5b1c8a1SJohn Marino 		len = strlen((const char *)in);
109f5b1c8a1SJohn Marino 	if (!mask)
110f5b1c8a1SJohn Marino 		mask = DIRSTRING_TYPE;
111f5b1c8a1SJohn Marino 
112f5b1c8a1SJohn Marino 	/* First do a string check and work out the number of characters */
113f5b1c8a1SJohn Marino 	switch (inform) {
114f5b1c8a1SJohn Marino 	case MBSTRING_BMP:
115f5b1c8a1SJohn Marino 		if (len & 1) {
11672c33676SMaxim Ag 			ASN1error(ASN1_R_INVALID_BMPSTRING_LENGTH);
117f5b1c8a1SJohn Marino 			return -1;
118f5b1c8a1SJohn Marino 		}
119f5b1c8a1SJohn Marino 		nchar = len >> 1;
120f5b1c8a1SJohn Marino 		break;
121f5b1c8a1SJohn Marino 
122f5b1c8a1SJohn Marino 	case MBSTRING_UNIV:
123f5b1c8a1SJohn Marino 		if (len & 3) {
12472c33676SMaxim Ag 			ASN1error(ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
125f5b1c8a1SJohn Marino 			return -1;
126f5b1c8a1SJohn Marino 		}
127f5b1c8a1SJohn Marino 		nchar = len >> 2;
128f5b1c8a1SJohn Marino 		break;
129f5b1c8a1SJohn Marino 
130f5b1c8a1SJohn Marino 	case MBSTRING_UTF8:
131f5b1c8a1SJohn Marino 		nchar = 0;
132f5b1c8a1SJohn Marino 		/* This counts the characters and does utf8 syntax checking */
133f5b1c8a1SJohn Marino 		ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
134f5b1c8a1SJohn Marino 		if (ret < 0) {
13572c33676SMaxim Ag 			ASN1error(ASN1_R_INVALID_UTF8STRING);
136f5b1c8a1SJohn Marino 			return -1;
137f5b1c8a1SJohn Marino 		}
138f5b1c8a1SJohn Marino 		break;
139f5b1c8a1SJohn Marino 
140f5b1c8a1SJohn Marino 	case MBSTRING_ASC:
141f5b1c8a1SJohn Marino 		nchar = len;
142f5b1c8a1SJohn Marino 		break;
143f5b1c8a1SJohn Marino 
144f5b1c8a1SJohn Marino 	default:
14572c33676SMaxim Ag 		ASN1error(ASN1_R_UNKNOWN_FORMAT);
146f5b1c8a1SJohn Marino 		return -1;
147f5b1c8a1SJohn Marino 	}
148f5b1c8a1SJohn Marino 
149f5b1c8a1SJohn Marino 	if ((minsize > 0) && (nchar < minsize)) {
15072c33676SMaxim Ag 		ASN1error(ASN1_R_STRING_TOO_SHORT);
151f5b1c8a1SJohn Marino 		ERR_asprintf_error_data("minsize=%ld", minsize);
152f5b1c8a1SJohn Marino 		return -1;
153f5b1c8a1SJohn Marino 	}
154f5b1c8a1SJohn Marino 
155f5b1c8a1SJohn Marino 	if ((maxsize > 0) && (nchar > maxsize)) {
15672c33676SMaxim Ag 		ASN1error(ASN1_R_STRING_TOO_LONG);
157f5b1c8a1SJohn Marino 		ERR_asprintf_error_data("maxsize=%ld", maxsize);
158f5b1c8a1SJohn Marino 		return -1;
159f5b1c8a1SJohn Marino 	}
160f5b1c8a1SJohn Marino 
161f5b1c8a1SJohn Marino 	/* Now work out minimal type (if any) */
162f5b1c8a1SJohn Marino 	if (traverse_string(in, len, inform, type_str, &mask) < 0) {
16372c33676SMaxim Ag 		ASN1error(ASN1_R_ILLEGAL_CHARACTERS);
164f5b1c8a1SJohn Marino 		return -1;
165f5b1c8a1SJohn Marino 	}
166f5b1c8a1SJohn Marino 
167f5b1c8a1SJohn Marino 
168f5b1c8a1SJohn Marino 	/* Now work out output format and string type */
169f5b1c8a1SJohn Marino 	outform = MBSTRING_ASC;
170f5b1c8a1SJohn Marino 	if (mask & B_ASN1_PRINTABLESTRING)
171f5b1c8a1SJohn Marino 		str_type = V_ASN1_PRINTABLESTRING;
172f5b1c8a1SJohn Marino 	else if (mask & B_ASN1_IA5STRING)
173f5b1c8a1SJohn Marino 		str_type = V_ASN1_IA5STRING;
174f5b1c8a1SJohn Marino 	else if (mask & B_ASN1_T61STRING)
175f5b1c8a1SJohn Marino 		str_type = V_ASN1_T61STRING;
176f5b1c8a1SJohn Marino 	else if (mask & B_ASN1_BMPSTRING) {
177f5b1c8a1SJohn Marino 		str_type = V_ASN1_BMPSTRING;
178f5b1c8a1SJohn Marino 		outform = MBSTRING_BMP;
179f5b1c8a1SJohn Marino 	} else if (mask & B_ASN1_UNIVERSALSTRING) {
180f5b1c8a1SJohn Marino 		str_type = V_ASN1_UNIVERSALSTRING;
181f5b1c8a1SJohn Marino 		outform = MBSTRING_UNIV;
182f5b1c8a1SJohn Marino 	} else {
183f5b1c8a1SJohn Marino 		str_type = V_ASN1_UTF8STRING;
184f5b1c8a1SJohn Marino 		outform = MBSTRING_UTF8;
185f5b1c8a1SJohn Marino 	}
186f5b1c8a1SJohn Marino 	if (!out)
187f5b1c8a1SJohn Marino 		return str_type;
188f5b1c8a1SJohn Marino 	if (*out) {
189f5b1c8a1SJohn Marino 		free_out = 0;
190f5b1c8a1SJohn Marino 		dest = *out;
191f5b1c8a1SJohn Marino 		if (dest->data) {
192f5b1c8a1SJohn Marino 			dest->length = 0;
193f5b1c8a1SJohn Marino 			free(dest->data);
194f5b1c8a1SJohn Marino 			dest->data = NULL;
195f5b1c8a1SJohn Marino 		}
196f5b1c8a1SJohn Marino 		dest->type = str_type;
197f5b1c8a1SJohn Marino 	} else {
198f5b1c8a1SJohn Marino 		free_out = 1;
199f5b1c8a1SJohn Marino 		dest = ASN1_STRING_type_new(str_type);
200f5b1c8a1SJohn Marino 		if (!dest) {
20172c33676SMaxim Ag 			ASN1error(ERR_R_MALLOC_FAILURE);
202f5b1c8a1SJohn Marino 			return -1;
203f5b1c8a1SJohn Marino 		}
204f5b1c8a1SJohn Marino 		*out = dest;
205f5b1c8a1SJohn Marino 	}
206f5b1c8a1SJohn Marino 	/* If both the same type just copy across */
207f5b1c8a1SJohn Marino 	if (inform == outform) {
208f5b1c8a1SJohn Marino 		if (!ASN1_STRING_set(dest, in, len)) {
20972c33676SMaxim Ag 			ASN1error(ERR_R_MALLOC_FAILURE);
210f5b1c8a1SJohn Marino 			goto err;
211f5b1c8a1SJohn Marino 		}
212f5b1c8a1SJohn Marino 		return str_type;
213f5b1c8a1SJohn Marino 	}
214f5b1c8a1SJohn Marino 
215f5b1c8a1SJohn Marino 	/* Work out how much space the destination will need */
216f5b1c8a1SJohn Marino 	switch (outform) {
217f5b1c8a1SJohn Marino 	case MBSTRING_ASC:
218f5b1c8a1SJohn Marino 		outlen = nchar;
219f5b1c8a1SJohn Marino 		cpyfunc = cpy_asc;
220f5b1c8a1SJohn Marino 		break;
221f5b1c8a1SJohn Marino 
222f5b1c8a1SJohn Marino 	case MBSTRING_BMP:
223f5b1c8a1SJohn Marino 		outlen = nchar << 1;
224f5b1c8a1SJohn Marino 		cpyfunc = cpy_bmp;
225f5b1c8a1SJohn Marino 		break;
226f5b1c8a1SJohn Marino 
227f5b1c8a1SJohn Marino 	case MBSTRING_UNIV:
228f5b1c8a1SJohn Marino 		outlen = nchar << 2;
229f5b1c8a1SJohn Marino 		cpyfunc = cpy_univ;
230f5b1c8a1SJohn Marino 		break;
231f5b1c8a1SJohn Marino 
232f5b1c8a1SJohn Marino 	case MBSTRING_UTF8:
233f5b1c8a1SJohn Marino 		outlen = 0;
234f5b1c8a1SJohn Marino 		if (traverse_string(in, len, inform, out_utf8, &outlen) < 0) {
23572c33676SMaxim Ag 			ASN1error(ASN1_R_ILLEGAL_CHARACTERS);
236f5b1c8a1SJohn Marino 			goto err;
237f5b1c8a1SJohn Marino 		}
238f5b1c8a1SJohn Marino 		cpyfunc = cpy_utf8;
239f5b1c8a1SJohn Marino 		break;
240f5b1c8a1SJohn Marino 	}
241f5b1c8a1SJohn Marino 	if (!(p = malloc(outlen + 1))) {
24272c33676SMaxim Ag 		ASN1error(ERR_R_MALLOC_FAILURE);
243f5b1c8a1SJohn Marino 		goto err;
244f5b1c8a1SJohn Marino 	}
245f5b1c8a1SJohn Marino 	dest->length = outlen;
246f5b1c8a1SJohn Marino 	dest->data = p;
247f5b1c8a1SJohn Marino 	p[outlen] = 0;
248f5b1c8a1SJohn Marino 	traverse_string(in, len, inform, cpyfunc, &p);
249f5b1c8a1SJohn Marino 	return str_type;
250f5b1c8a1SJohn Marino 
251f5b1c8a1SJohn Marino  err:
252f5b1c8a1SJohn Marino 	if (free_out) {
253f5b1c8a1SJohn Marino 		ASN1_STRING_free(dest);
254f5b1c8a1SJohn Marino 		*out = NULL;
255f5b1c8a1SJohn Marino 	}
256f5b1c8a1SJohn Marino 	return -1;
257f5b1c8a1SJohn Marino }
258f5b1c8a1SJohn Marino 
259f5b1c8a1SJohn Marino /* This function traverses a string and passes the value of each character
260f5b1c8a1SJohn Marino  * to an optional function along with a void * argument.
261f5b1c8a1SJohn Marino  */
262f5b1c8a1SJohn Marino 
263f5b1c8a1SJohn Marino static int
traverse_string(const unsigned char * p,int len,int inform,int (* rfunc)(unsigned long value,void * in),void * arg)264f5b1c8a1SJohn Marino traverse_string(const unsigned char *p, int len, int inform,
265f5b1c8a1SJohn Marino     int (*rfunc)(unsigned long value, void *in), void *arg)
266f5b1c8a1SJohn Marino {
267f5b1c8a1SJohn Marino 	unsigned long value;
268f5b1c8a1SJohn Marino 	int ret;
269f5b1c8a1SJohn Marino 
270f5b1c8a1SJohn Marino 	while (len) {
271f5b1c8a1SJohn Marino 		switch (inform) {
272f5b1c8a1SJohn Marino 		case MBSTRING_ASC:
273f5b1c8a1SJohn Marino 			value = *p++;
274f5b1c8a1SJohn Marino 			len--;
275f5b1c8a1SJohn Marino 			break;
276f5b1c8a1SJohn Marino 		case MBSTRING_BMP:
277f5b1c8a1SJohn Marino 			value = *p++ << 8;
278f5b1c8a1SJohn Marino 			value |= *p++;
279f5b1c8a1SJohn Marino 			/* BMP is explictly defined to not support surrogates */
280f5b1c8a1SJohn Marino 			if (UNICODE_IS_SURROGATE(value))
281f5b1c8a1SJohn Marino 				return -1;
282f5b1c8a1SJohn Marino 			len -= 2;
283f5b1c8a1SJohn Marino 			break;
284f5b1c8a1SJohn Marino 		case MBSTRING_UNIV:
285f5b1c8a1SJohn Marino 			value = (unsigned long)*p++ << 24;
286f5b1c8a1SJohn Marino 			value |= *p++ << 16;
287f5b1c8a1SJohn Marino 			value |= *p++ << 8;
288f5b1c8a1SJohn Marino 			value |= *p++;
289f5b1c8a1SJohn Marino 			if (value > UNICODE_MAX || UNICODE_IS_SURROGATE(value))
290f5b1c8a1SJohn Marino 				return -1;
291f5b1c8a1SJohn Marino 			len -= 4;
292f5b1c8a1SJohn Marino 			break;
293f5b1c8a1SJohn Marino 		default:
294f5b1c8a1SJohn Marino 			ret = UTF8_getc(p, len, &value);
295f5b1c8a1SJohn Marino 			if (ret < 0)
296f5b1c8a1SJohn Marino 				return -1;
297f5b1c8a1SJohn Marino 			len -= ret;
298f5b1c8a1SJohn Marino 			p += ret;
299f5b1c8a1SJohn Marino 			break;
300f5b1c8a1SJohn Marino 		}
301f5b1c8a1SJohn Marino 		if (rfunc) {
302f5b1c8a1SJohn Marino 			ret = rfunc(value, arg);
303f5b1c8a1SJohn Marino 			if (ret <= 0)
304f5b1c8a1SJohn Marino 				return ret;
305f5b1c8a1SJohn Marino 		}
306f5b1c8a1SJohn Marino 	}
307f5b1c8a1SJohn Marino 	return 1;
308f5b1c8a1SJohn Marino }
309f5b1c8a1SJohn Marino 
310f5b1c8a1SJohn Marino /* Various utility functions for traverse_string */
311f5b1c8a1SJohn Marino 
312f5b1c8a1SJohn Marino /* Just count number of characters */
313f5b1c8a1SJohn Marino 
314f5b1c8a1SJohn Marino static int
in_utf8(unsigned long value,void * arg)315f5b1c8a1SJohn Marino in_utf8(unsigned long value, void *arg)
316f5b1c8a1SJohn Marino {
317f5b1c8a1SJohn Marino 	int *nchar;
318f5b1c8a1SJohn Marino 
319f5b1c8a1SJohn Marino 	nchar = arg;
320f5b1c8a1SJohn Marino 	(*nchar)++;
321f5b1c8a1SJohn Marino 	return 1;
322f5b1c8a1SJohn Marino }
323f5b1c8a1SJohn Marino 
324f5b1c8a1SJohn Marino /* Determine size of output as a UTF8 String */
325f5b1c8a1SJohn Marino 
326f5b1c8a1SJohn Marino static int
out_utf8(unsigned long value,void * arg)327f5b1c8a1SJohn Marino out_utf8(unsigned long value, void *arg)
328f5b1c8a1SJohn Marino {
329f5b1c8a1SJohn Marino 	int *outlen;
330f5b1c8a1SJohn Marino 	int ret;
331f5b1c8a1SJohn Marino 
332f5b1c8a1SJohn Marino 	outlen = arg;
333f5b1c8a1SJohn Marino 	ret = UTF8_putc(NULL, -1, value);
334f5b1c8a1SJohn Marino 	if (ret < 0)
335f5b1c8a1SJohn Marino 		return ret;
336f5b1c8a1SJohn Marino 	*outlen += ret;
337f5b1c8a1SJohn Marino 	return 1;
338f5b1c8a1SJohn Marino }
339f5b1c8a1SJohn Marino 
340f5b1c8a1SJohn Marino /* Determine the "type" of a string: check each character against a
341f5b1c8a1SJohn Marino  * supplied "mask".
342f5b1c8a1SJohn Marino  */
343f5b1c8a1SJohn Marino 
344f5b1c8a1SJohn Marino static int
type_str(unsigned long value,void * arg)345f5b1c8a1SJohn Marino type_str(unsigned long value, void *arg)
346f5b1c8a1SJohn Marino {
347f5b1c8a1SJohn Marino 	unsigned long types;
348f5b1c8a1SJohn Marino 
349f5b1c8a1SJohn Marino 	types = *((unsigned long *)arg);
350f5b1c8a1SJohn Marino 	if ((types & B_ASN1_PRINTABLESTRING) && !is_printable(value))
351f5b1c8a1SJohn Marino 		types &= ~B_ASN1_PRINTABLESTRING;
352f5b1c8a1SJohn Marino 	if ((types & B_ASN1_IA5STRING) && (value > 127))
353f5b1c8a1SJohn Marino 		types &= ~B_ASN1_IA5STRING;
354f5b1c8a1SJohn Marino 	if ((types & B_ASN1_T61STRING) && (value > 0xff))
355f5b1c8a1SJohn Marino 		types &= ~B_ASN1_T61STRING;
356f5b1c8a1SJohn Marino 	if ((types & B_ASN1_BMPSTRING) && (value > 0xffff))
357f5b1c8a1SJohn Marino 		types &= ~B_ASN1_BMPSTRING;
358f5b1c8a1SJohn Marino 	if (!types)
359f5b1c8a1SJohn Marino 		return -1;
360f5b1c8a1SJohn Marino 	*((unsigned long *)arg) = types;
361f5b1c8a1SJohn Marino 	return 1;
362f5b1c8a1SJohn Marino }
363f5b1c8a1SJohn Marino 
364f5b1c8a1SJohn Marino /* Copy one byte per character ASCII like strings */
365f5b1c8a1SJohn Marino 
366f5b1c8a1SJohn Marino static int
cpy_asc(unsigned long value,void * arg)367f5b1c8a1SJohn Marino cpy_asc(unsigned long value, void *arg)
368f5b1c8a1SJohn Marino {
369f5b1c8a1SJohn Marino 	unsigned char **p, *q;
370f5b1c8a1SJohn Marino 
371f5b1c8a1SJohn Marino 	p = arg;
372f5b1c8a1SJohn Marino 	q = *p;
373f5b1c8a1SJohn Marino 	*q = value;
374f5b1c8a1SJohn Marino 	(*p)++;
375f5b1c8a1SJohn Marino 	return 1;
376f5b1c8a1SJohn Marino }
377f5b1c8a1SJohn Marino 
378f5b1c8a1SJohn Marino /* Copy two byte per character BMPStrings */
379f5b1c8a1SJohn Marino 
380f5b1c8a1SJohn Marino static int
cpy_bmp(unsigned long value,void * arg)381f5b1c8a1SJohn Marino cpy_bmp(unsigned long value, void *arg)
382f5b1c8a1SJohn Marino {
383f5b1c8a1SJohn Marino 	unsigned char **p, *q;
384f5b1c8a1SJohn Marino 
385f5b1c8a1SJohn Marino 	p = arg;
386f5b1c8a1SJohn Marino 	q = *p;
387f5b1c8a1SJohn Marino 	*q++ = (value >> 8) & 0xff;
388f5b1c8a1SJohn Marino 	*q = value & 0xff;
389f5b1c8a1SJohn Marino 	*p += 2;
390f5b1c8a1SJohn Marino 	return 1;
391f5b1c8a1SJohn Marino }
392f5b1c8a1SJohn Marino 
393f5b1c8a1SJohn Marino /* Copy four byte per character UniversalStrings */
394f5b1c8a1SJohn Marino 
395f5b1c8a1SJohn Marino static int
cpy_univ(unsigned long value,void * arg)396f5b1c8a1SJohn Marino cpy_univ(unsigned long value, void *arg)
397f5b1c8a1SJohn Marino {
398f5b1c8a1SJohn Marino 	unsigned char **p, *q;
399f5b1c8a1SJohn Marino 
400f5b1c8a1SJohn Marino 	p = arg;
401f5b1c8a1SJohn Marino 	q = *p;
402f5b1c8a1SJohn Marino 	*q++ = (value >> 24) & 0xff;
403f5b1c8a1SJohn Marino 	*q++ = (value >> 16) & 0xff;
404f5b1c8a1SJohn Marino 	*q++ = (value >> 8) & 0xff;
405f5b1c8a1SJohn Marino 	*q = value & 0xff;
406f5b1c8a1SJohn Marino 	*p += 4;
407f5b1c8a1SJohn Marino 	return 1;
408f5b1c8a1SJohn Marino }
409f5b1c8a1SJohn Marino 
410f5b1c8a1SJohn Marino /* Copy to a UTF8String */
411f5b1c8a1SJohn Marino 
412f5b1c8a1SJohn Marino static int
cpy_utf8(unsigned long value,void * arg)413f5b1c8a1SJohn Marino cpy_utf8(unsigned long value, void *arg)
414f5b1c8a1SJohn Marino {
415f5b1c8a1SJohn Marino 	unsigned char **p;
416f5b1c8a1SJohn Marino 
417f5b1c8a1SJohn Marino 	int ret;
418f5b1c8a1SJohn Marino 	p = arg;
419f5b1c8a1SJohn Marino 	/* We already know there is enough room so pass 0xff as the length */
420f5b1c8a1SJohn Marino 	ret = UTF8_putc(*p, 0xff, value);
421f5b1c8a1SJohn Marino 	*p += ret;
422f5b1c8a1SJohn Marino 	return 1;
423f5b1c8a1SJohn Marino }
424f5b1c8a1SJohn Marino 
425f5b1c8a1SJohn Marino /* Return 1 if the character is permitted in a PrintableString */
426f5b1c8a1SJohn Marino static int
is_printable(unsigned long value)427f5b1c8a1SJohn Marino is_printable(unsigned long value)
428f5b1c8a1SJohn Marino {
429f5b1c8a1SJohn Marino 	int ch;
430f5b1c8a1SJohn Marino 
431f5b1c8a1SJohn Marino 	if (value > 0x7f)
432f5b1c8a1SJohn Marino 		return 0;
433f5b1c8a1SJohn Marino 	ch = (int)value;
434f5b1c8a1SJohn Marino 
435f5b1c8a1SJohn Marino 	/* Note: we can't use 'isalnum' because certain accented
436f5b1c8a1SJohn Marino 	 * characters may count as alphanumeric in some environments.
437f5b1c8a1SJohn Marino 	 */
438f5b1c8a1SJohn Marino 	if ((ch >= 'a') && (ch <= 'z'))
439f5b1c8a1SJohn Marino 		return 1;
440f5b1c8a1SJohn Marino 	if ((ch >= 'A') && (ch <= 'Z'))
441f5b1c8a1SJohn Marino 		return 1;
442f5b1c8a1SJohn Marino 	if ((ch >= '0') && (ch <= '9'))
443f5b1c8a1SJohn Marino 		return 1;
444f5b1c8a1SJohn Marino 	if ((ch == ' ') || strchr("'()+,-./:=?", ch))
445f5b1c8a1SJohn Marino 		return 1;
446f5b1c8a1SJohn Marino 	return 0;
447f5b1c8a1SJohn Marino }
448