xref: /openbsd/lib/libcrypto/asn1/a_string.c (revision 2e0be48d)
1 /* $OpenBSD: a_string.c,v 1.17 2023/08/15 18:05:15 tb Exp $ */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young (eay@cryptsoft.com).
7  * The implementation was written so as to conform with Netscapes SSL.
8  *
9  * This library is free for commercial and non-commercial use as long as
10  * the following conditions are aheared to.  The following conditions
11  * apply to all code found in this distribution, be it the RC4, RSA,
12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13  * included with this distribution is covered by the same copyright terms
14  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15  *
16  * Copyright remains Eric Young's, and as such any Copyright notices in
17  * the code are not to be removed.
18  * If this package is used in a product, Eric Young should be given attribution
19  * as the author of the parts of the library used.
20  * This can be in the form of a textual message at program startup or
21  * in documentation (online or textual) provided with the package.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. All advertising materials mentioning features or use of this software
32  *    must display the following acknowledgement:
33  *    "This product includes cryptographic software written by
34  *     Eric Young (eay@cryptsoft.com)"
35  *    The word 'cryptographic' can be left out if the rouines from the library
36  *    being used are not cryptographic related :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  * The licence and distribution terms for any publically available version or
54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55  * copied and put under another distribution licence
56  * [including the GNU Public Licence.]
57  */
58 
59 #include <limits.h>
60 #include <stdlib.h>
61 #include <string.h>
62 
63 #include <openssl/asn1.h>
64 #include <openssl/err.h>
65 
66 #include "asn1_local.h"
67 
68 ASN1_STRING *
ASN1_STRING_new(void)69 ASN1_STRING_new(void)
70 {
71 	return ASN1_STRING_type_new(V_ASN1_OCTET_STRING);
72 }
73 LCRYPTO_ALIAS(ASN1_STRING_new);
74 
75 ASN1_STRING *
ASN1_STRING_type_new(int type)76 ASN1_STRING_type_new(int type)
77 {
78 	ASN1_STRING *astr;
79 
80 	if ((astr = calloc(1, sizeof(ASN1_STRING))) == NULL) {
81 		ASN1error(ERR_R_MALLOC_FAILURE);
82 		return NULL;
83 	}
84 	astr->type = type;
85 
86 	return astr;
87 }
88 LCRYPTO_ALIAS(ASN1_STRING_type_new);
89 
90 static void
ASN1_STRING_clear(ASN1_STRING * astr)91 ASN1_STRING_clear(ASN1_STRING *astr)
92 {
93 	if (!(astr->flags & ASN1_STRING_FLAG_NDEF))
94 		freezero(astr->data, astr->length);
95 
96 	astr->flags &= ~ASN1_STRING_FLAG_NDEF;
97 	astr->data = NULL;
98 	astr->length = 0;
99 }
100 
101 void
ASN1_STRING_free(ASN1_STRING * astr)102 ASN1_STRING_free(ASN1_STRING *astr)
103 {
104 	if (astr == NULL)
105 		return;
106 
107 	ASN1_STRING_clear(astr);
108 
109 	free(astr);
110 }
111 LCRYPTO_ALIAS(ASN1_STRING_free);
112 
113 int
ASN1_STRING_cmp(const ASN1_STRING * a,const ASN1_STRING * b)114 ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
115 {
116 	int cmp;
117 
118 	if (a == NULL || b == NULL)
119 		return -1;
120 	if ((cmp = (a->length - b->length)) != 0)
121 		return cmp;
122 	if (a->length != 0) {
123 		if ((cmp = memcmp(a->data, b->data, a->length)) != 0)
124 			return cmp;
125 	}
126 
127 	return a->type - b->type;
128 }
129 LCRYPTO_ALIAS(ASN1_STRING_cmp);
130 
131 int
ASN1_STRING_copy(ASN1_STRING * dst,const ASN1_STRING * src)132 ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *src)
133 {
134 	if (src == NULL)
135 		return 0;
136 
137 	if (!ASN1_STRING_set(dst, src->data, src->length))
138 		return 0;
139 
140 	dst->type = src->type;
141 	dst->flags = src->flags & ~ASN1_STRING_FLAG_NDEF;
142 
143 	return 1;
144 }
145 LCRYPTO_ALIAS(ASN1_STRING_copy);
146 
147 ASN1_STRING *
ASN1_STRING_dup(const ASN1_STRING * src)148 ASN1_STRING_dup(const ASN1_STRING *src)
149 {
150 	ASN1_STRING *astr;
151 
152 	if (src == NULL)
153 		return NULL;
154 
155 	if ((astr = ASN1_STRING_new()) == NULL)
156 		return NULL;
157 	if (!ASN1_STRING_copy(astr, src)) {
158 		ASN1_STRING_free(astr);
159 		return NULL;
160 	}
161 	return astr;
162 }
163 LCRYPTO_ALIAS(ASN1_STRING_dup);
164 
165 int
ASN1_STRING_set(ASN1_STRING * astr,const void * _data,int len)166 ASN1_STRING_set(ASN1_STRING *astr, const void *_data, int len)
167 {
168 	const char *data = _data;
169 
170 	if (len == -1) {
171 		size_t slen;
172 
173 		if (data == NULL)
174 			return 0;
175 
176 		if ((slen = strlen(data)) > INT_MAX)
177 			return 0;
178 
179 		len = (int)slen;
180 	}
181 
182 	ASN1_STRING_clear(astr);
183 
184 	if (len < 0 || len >= INT_MAX)
185 		return 0;
186 
187 	if ((astr->data = calloc(1, len + 1)) == NULL) {
188 		ASN1error(ERR_R_MALLOC_FAILURE);
189 		return 0;
190 	}
191 	astr->length = len;
192 
193 	if (data != NULL) {
194 		memcpy(astr->data, data, len);
195 		astr->data[len] = '\0';
196 	}
197 
198 	return 1;
199 }
200 LCRYPTO_ALIAS(ASN1_STRING_set);
201 
202 void
ASN1_STRING_set0(ASN1_STRING * astr,void * data,int len)203 ASN1_STRING_set0(ASN1_STRING *astr, void *data, int len)
204 {
205 	ASN1_STRING_clear(astr);
206 
207 	astr->data = data;
208 	astr->length = len;
209 }
210 LCRYPTO_ALIAS(ASN1_STRING_set0);
211 
212 int
ASN1_STRING_length(const ASN1_STRING * astr)213 ASN1_STRING_length(const ASN1_STRING *astr)
214 {
215 	return astr->length;
216 }
217 LCRYPTO_ALIAS(ASN1_STRING_length);
218 
219 void
ASN1_STRING_length_set(ASN1_STRING * astr,int len)220 ASN1_STRING_length_set(ASN1_STRING *astr, int len)
221 {
222 	/* This is dangerous and unfixable. */
223 	astr->length = len;
224 }
225 LCRYPTO_ALIAS(ASN1_STRING_length_set);
226 
227 int
ASN1_STRING_type(const ASN1_STRING * astr)228 ASN1_STRING_type(const ASN1_STRING *astr)
229 {
230 	return astr->type;
231 }
232 LCRYPTO_ALIAS(ASN1_STRING_type);
233 
234 unsigned char *
ASN1_STRING_data(ASN1_STRING * astr)235 ASN1_STRING_data(ASN1_STRING *astr)
236 {
237 	return astr->data;
238 }
239 LCRYPTO_ALIAS(ASN1_STRING_data);
240 
241 const unsigned char *
ASN1_STRING_get0_data(const ASN1_STRING * astr)242 ASN1_STRING_get0_data(const ASN1_STRING *astr)
243 {
244 	return astr->data;
245 }
246 LCRYPTO_ALIAS(ASN1_STRING_get0_data);
247 
248 int
ASN1_STRING_print(BIO * bp,const ASN1_STRING * astr)249 ASN1_STRING_print(BIO *bp, const ASN1_STRING *astr)
250 {
251 	int i, n;
252 	char buf[80];
253 	const char *p;
254 
255 	if (astr == NULL)
256 		return 0;
257 
258 	n = 0;
259 	p = (const char *)astr->data;
260 	for (i = 0; i < astr->length; i++) {
261 		if ((p[i] > '~') || ((p[i] < ' ') &&
262 		    (p[i] != '\n') && (p[i] != '\r')))
263 			buf[n] = '.';
264 		else
265 			buf[n] = p[i];
266 		n++;
267 		if (n >= 80) {
268 			if (BIO_write(bp, buf, n) <= 0)
269 				return 0;
270 			n = 0;
271 		}
272 	}
273 	if (n > 0) {
274 		if (BIO_write(bp, buf, n) <= 0)
275 			return 0;
276 	}
277 
278 	return 1;
279 }
280 LCRYPTO_ALIAS(ASN1_STRING_print);
281 
282 /*
283  * Utility function: convert any string type to UTF8, returns number of bytes
284  * in output string or a negative error code
285  */
286 int
ASN1_STRING_to_UTF8(unsigned char ** out,const ASN1_STRING * in)287 ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in)
288 {
289 	ASN1_STRING *astr = NULL;
290 	int mbflag;
291 	int ret = -1;
292 
293 	/*
294 	 * XXX We can't fail on *out != NULL here since things like haproxy and
295 	 * grpc pass in a pointer to an uninitialized pointer on the stack.
296 	 */
297 	if (out == NULL)
298 		goto err;
299 
300 	if (in == NULL)
301 		goto err;
302 
303 	if ((mbflag = asn1_tag2charwidth(in->type)) == -1)
304 		goto err;
305 
306 	mbflag |= MBSTRING_FLAG;
307 
308 	if ((ret = ASN1_mbstring_copy(&astr, in->data, in->length, mbflag,
309 	    B_ASN1_UTF8STRING)) < 0)
310 		goto err;
311 
312 	*out = astr->data;
313 	ret = astr->length;
314 
315 	astr->data = NULL;
316 	astr->length = 0;
317 
318  err:
319 	ASN1_STRING_free(astr);
320 
321 	return ret;
322 }
323 LCRYPTO_ALIAS(ASN1_STRING_to_UTF8);
324 
325 int
i2a_ASN1_STRING(BIO * bp,const ASN1_STRING * astr,int type)326 i2a_ASN1_STRING(BIO *bp, const ASN1_STRING *astr, int type)
327 {
328 	int i, n = 0;
329 	static const char h[] = "0123456789ABCDEF";
330 	char buf[2];
331 
332 	if (astr == NULL)
333 		return 0;
334 
335 	if (astr->length == 0) {
336 		if (BIO_write(bp, "0", 1) != 1)
337 			goto err;
338 		n = 1;
339 	} else {
340 		for (i = 0; i < astr->length; i++) {
341 			if ((i != 0) && (i % 35 == 0)) {
342 				if (BIO_write(bp, "\\\n", 2) != 2)
343 					goto err;
344 				n += 2;
345 			}
346 			buf[0] = h[((unsigned char)astr->data[i] >> 4) & 0x0f];
347 			buf[1] = h[((unsigned char)astr->data[i]) & 0x0f];
348 			if (BIO_write(bp, buf, 2) != 2)
349 				goto err;
350 			n += 2;
351 		}
352 	}
353 	return n;
354 
355  err:
356 	return -1;
357 }
358 LCRYPTO_ALIAS(i2a_ASN1_STRING);
359 
360 int
a2i_ASN1_STRING(BIO * bp,ASN1_STRING * astr,char * buf,int size)361 a2i_ASN1_STRING(BIO *bp, ASN1_STRING *astr, char *buf, int size)
362 {
363 	int ret = 0;
364 	int i, j, k, m, n, again, bufsize;
365 	unsigned char *s = NULL, *sp;
366 	unsigned char *bufp;
367 	int first = 1;
368 	size_t num = 0, slen = 0;
369 
370 	bufsize = BIO_gets(bp, buf, size);
371 	for (;;) {
372 		if (bufsize < 1) {
373 			if (first)
374 				break;
375 			else
376 				goto err_sl;
377 		}
378 		first = 0;
379 
380 		i = bufsize;
381 		if (buf[i-1] == '\n')
382 			buf[--i] = '\0';
383 		if (i == 0)
384 			goto err_sl;
385 		if (buf[i-1] == '\r')
386 			buf[--i] = '\0';
387 		if (i == 0)
388 			goto err_sl;
389 		if (buf[i - 1] == '\\') {
390 			i--;
391 			again = 1;
392 		} else
393 			again = 0;
394 		buf[i] = '\0';
395 		if (i < 2)
396 			goto err_sl;
397 
398 		bufp = (unsigned char *)buf;
399 
400 		k = 0;
401 		if (i % 2 != 0) {
402 			ASN1error(ASN1_R_ODD_NUMBER_OF_CHARS);
403 			goto err;
404 		}
405 		i /= 2;
406 		if (num + i > slen) {
407 			sp = realloc(s, num + i);
408 			if (sp == NULL) {
409 				ASN1error(ERR_R_MALLOC_FAILURE);
410 				goto err;
411 			}
412 			s = sp;
413 			slen = num + i;
414 		}
415 		for (j = 0; j < i; j++, k += 2) {
416 			for (n = 0; n < 2; n++) {
417 				m = bufp[k + n];
418 				if ((m >= '0') && (m <= '9'))
419 					m -= '0';
420 				else if ((m >= 'a') && (m <= 'f'))
421 					m = m - 'a' + 10;
422 				else if ((m >= 'A') && (m <= 'F'))
423 					m = m - 'A' + 10;
424 				else {
425 					ASN1error(ASN1_R_NON_HEX_CHARACTERS);
426 					goto err;
427 				}
428 				s[num + j] <<= 4;
429 				s[num + j] |= m;
430 			}
431 		}
432 		num += i;
433 		if (again)
434 			bufsize = BIO_gets(bp, buf, size);
435 		else
436 			break;
437 	}
438 	astr->length = num;
439 	astr->data = s;
440 
441 	return 1;
442 
443  err_sl:
444 	ASN1error(ASN1_R_SHORT_LINE);
445  err:
446 	free(s);
447 
448 	return ret;
449 }
450 LCRYPTO_ALIAS(a2i_ASN1_STRING);
451