xref: /openbsd-src/lib/libcrypto/asn1/a_enum.c (revision 68dd5bb1859285b71cb62a10bf107b8ad54064d9)
1 /* $OpenBSD: a_enum.c,v 1.29 2023/07/05 21:23:36 beck 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 <string.h>
61 
62 #include <openssl/asn1.h>
63 #include <openssl/asn1t.h>
64 #include <openssl/bn.h>
65 #include <openssl/buffer.h>
66 #include <openssl/err.h>
67 
68 #include "asn1_local.h"
69 #include "bytestring.h"
70 
71 /*
72  * Code for ENUMERATED type: identical to INTEGER apart from a different tag.
73  * for comments on encoding see a_int.c
74  */
75 
76 const ASN1_ITEM ASN1_ENUMERATED_it = {
77 	.itype = ASN1_ITYPE_PRIMITIVE,
78 	.utype = V_ASN1_ENUMERATED,
79 	.sname = "ASN1_ENUMERATED",
80 };
81 
82 ASN1_ENUMERATED *
83 ASN1_ENUMERATED_new(void)
84 {
85 	return (ASN1_ENUMERATED *)ASN1_item_new(&ASN1_ENUMERATED_it);
86 }
87 LCRYPTO_ALIAS(ASN1_ENUMERATED_new);
88 
89 static void
90 asn1_aenum_clear(ASN1_ENUMERATED *aenum)
91 {
92 	freezero(aenum->data, aenum->length);
93 
94 	memset(aenum, 0, sizeof(*aenum));
95 
96 	aenum->type = V_ASN1_ENUMERATED;
97 }
98 
99 void
100 ASN1_ENUMERATED_free(ASN1_ENUMERATED *a)
101 {
102 	ASN1_item_free((ASN1_VALUE *)a, &ASN1_ENUMERATED_it);
103 }
104 LCRYPTO_ALIAS(ASN1_ENUMERATED_free);
105 
106 int
107 ASN1_ENUMERATED_get_int64(int64_t *out_val, const ASN1_ENUMERATED *aenum)
108 {
109 	CBS cbs;
110 
111 	*out_val = 0;
112 
113 	if (aenum == NULL || aenum->length < 0)
114 		return 0;
115 
116 	if (aenum->type != V_ASN1_ENUMERATED &&
117 	    aenum->type != V_ASN1_NEG_ENUMERATED) {
118 		ASN1error(ASN1_R_WRONG_INTEGER_TYPE);
119 		return 0;
120 	}
121 
122 	CBS_init(&cbs, aenum->data, aenum->length);
123 
124 	return asn1_aint_get_int64(&cbs, (aenum->type == V_ASN1_NEG_ENUMERATED),
125 	    out_val);
126 }
127 LCRYPTO_ALIAS(ASN1_ENUMERATED_get_int64);
128 
129 int
130 ASN1_ENUMERATED_set_int64(ASN1_ENUMERATED *aenum, int64_t val)
131 {
132 	uint64_t uval;
133 
134 	asn1_aenum_clear(aenum);
135 
136 	uval = (uint64_t)val;
137 
138 	if (val < 0) {
139 		aenum->type = V_ASN1_NEG_ENUMERATED;
140 		uval = -uval;
141 	}
142 
143 	return asn1_aint_set_uint64(uval, &aenum->data, &aenum->length);
144 }
145 LCRYPTO_ALIAS(ASN1_ENUMERATED_set_int64);
146 
147 long
148 ASN1_ENUMERATED_get(const ASN1_ENUMERATED *aenum)
149 {
150 	int64_t val;
151 
152 	if (aenum == NULL)
153 		return 0;
154 	if (!ASN1_ENUMERATED_get_int64(&val, aenum))
155 		return -1;
156 	if (val < LONG_MIN || val > LONG_MAX) {
157 		/* hmm... a bit ugly, return all ones */
158 		return -1;
159 	}
160 
161 	return (long)val;
162 }
163 LCRYPTO_ALIAS(ASN1_ENUMERATED_get);
164 
165 int
166 ASN1_ENUMERATED_set(ASN1_ENUMERATED *aenum, long val)
167 {
168 	return ASN1_ENUMERATED_set_int64(aenum, val);
169 }
170 LCRYPTO_ALIAS(ASN1_ENUMERATED_set);
171 
172 ASN1_ENUMERATED *
173 BN_to_ASN1_ENUMERATED(const BIGNUM *bn, ASN1_ENUMERATED *ai)
174 {
175 	ASN1_ENUMERATED *ret;
176 	int len, j;
177 
178 	if (ai == NULL)
179 		ret = ASN1_ENUMERATED_new();
180 	else
181 		ret = ai;
182 	if (ret == NULL) {
183 		ASN1error(ERR_R_NESTED_ASN1_ERROR);
184 		goto err;
185 	}
186 	if (BN_is_negative(bn))
187 		ret->type = V_ASN1_NEG_ENUMERATED;
188 	else
189 		ret->type = V_ASN1_ENUMERATED;
190 	j = BN_num_bits(bn);
191 	len = ((j == 0) ? 0 : ((j / 8) + 1));
192 	if (ret->length < len + 4) {
193 		unsigned char *new_data = realloc(ret->data, len + 4);
194 		if (!new_data) {
195 			ASN1error(ERR_R_MALLOC_FAILURE);
196 			goto err;
197 		}
198 		ret->data = new_data;
199 	}
200 	ret->length = BN_bn2bin(bn, ret->data);
201 
202 	/* Correct zero case */
203 	if (!ret->length) {
204 		ret->data[0] = 0;
205 		ret->length = 1;
206 	}
207 	return (ret);
208 
209  err:
210 	if (ret != ai)
211 		ASN1_ENUMERATED_free(ret);
212 	return (NULL);
213 }
214 LCRYPTO_ALIAS(BN_to_ASN1_ENUMERATED);
215 
216 BIGNUM *
217 ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai, BIGNUM *bn)
218 {
219 	BIGNUM *ret;
220 
221 	if ((ret = BN_bin2bn(ai->data, ai->length, bn)) == NULL)
222 		ASN1error(ASN1_R_BN_LIB);
223 	else if (ai->type == V_ASN1_NEG_ENUMERATED)
224 		BN_set_negative(ret, 1);
225 	return (ret);
226 }
227 LCRYPTO_ALIAS(ASN1_ENUMERATED_to_BN);
228 
229 /* Based on a_int.c: equivalent ENUMERATED functions */
230 
231 int
232 i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a)
233 {
234 	int i, n = 0;
235 	static const char h[] = "0123456789ABCDEF";
236 	char buf[2];
237 
238 	if (a == NULL)
239 		return (0);
240 
241 	if (a->length == 0) {
242 		if (BIO_write(bp, "00", 2) != 2)
243 			goto err;
244 		n = 2;
245 	} else {
246 		for (i = 0; i < a->length; i++) {
247 			if ((i != 0) && (i % 35 == 0)) {
248 				if (BIO_write(bp, "\\\n", 2) != 2)
249 					goto err;
250 				n += 2;
251 			}
252 			buf[0] = h[((unsigned char)a->data[i] >> 4) & 0x0f];
253 			buf[1] = h[((unsigned char)a->data[i]) & 0x0f];
254 			if (BIO_write(bp, buf, 2) != 2)
255 				goto err;
256 			n += 2;
257 		}
258 	}
259 	return (n);
260 
261  err:
262 	return (-1);
263 }
264 LCRYPTO_ALIAS(i2a_ASN1_ENUMERATED);
265 
266 int
267 a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size)
268 {
269 	int ret = 0;
270 	int i, j,k, m,n, again, bufsize;
271 	unsigned char *s = NULL, *sp;
272 	unsigned char *bufp;
273 	int first = 1;
274 	size_t num = 0, slen = 0;
275 
276 	bs->type = V_ASN1_ENUMERATED;
277 
278 	bufsize = BIO_gets(bp, buf, size);
279 	for (;;) {
280 		if (bufsize < 1)
281 			goto err_sl;
282 		i = bufsize;
283 		if (buf[i-1] == '\n')
284 			buf[--i] = '\0';
285 		if (i == 0)
286 			goto err_sl;
287 		if (buf[i-1] == '\r')
288 			buf[--i] = '\0';
289 		if (i == 0)
290 			goto err_sl;
291 		if (buf[i - 1] == '\\') {
292 			i--;
293 			again = 1;
294 		} else
295 			again = 0;
296 		buf[i] = '\0';
297 		if (i < 2)
298 			goto err_sl;
299 
300 		bufp = (unsigned char *)buf;
301 		if (first) {
302 			first = 0;
303 			if ((bufp[0] == '0') && (buf[1] == '0')) {
304 				bufp += 2;
305 				i -= 2;
306 			}
307 		}
308 		k = 0;
309 		if (i % 2 != 0) {
310 			ASN1error(ASN1_R_ODD_NUMBER_OF_CHARS);
311 			goto err;
312 		}
313 		i /= 2;
314 		if (num + i > slen) {
315 			sp = realloc(s, num + i);
316 			if (sp == NULL) {
317 				ASN1error(ERR_R_MALLOC_FAILURE);
318 				goto err;
319 			}
320 			s = sp;
321 			slen = num + i;
322 		}
323 		for (j = 0; j < i; j++, k += 2) {
324 			for (n = 0; n < 2; n++) {
325 				m = bufp[k + n];
326 				if ((m >= '0') && (m <= '9'))
327 					m -= '0';
328 				else if ((m >= 'a') && (m <= 'f'))
329 					m = m - 'a' + 10;
330 				else if ((m >= 'A') && (m <= 'F'))
331 					m = m - 'A' + 10;
332 				else {
333 					ASN1error(ASN1_R_NON_HEX_CHARACTERS);
334 					goto err;
335 				}
336 				s[num + j] <<= 4;
337 				s[num + j] |= m;
338 			}
339 		}
340 		num += i;
341 		if (again)
342 			bufsize = BIO_gets(bp, buf, size);
343 		else
344 			break;
345 	}
346 	bs->length = num;
347 	bs->data = s;
348 	return (1);
349 
350  err_sl:
351 	ASN1error(ASN1_R_SHORT_LINE);
352  err:
353 	free(s);
354 	return (ret);
355 }
356 LCRYPTO_ALIAS(a2i_ASN1_ENUMERATED);
357 
358 int
359 c2i_ASN1_ENUMERATED_cbs(ASN1_ENUMERATED **out_aenum, CBS *cbs)
360 {
361 	ASN1_ENUMERATED *aenum = NULL;
362 
363 	if (out_aenum == NULL)
364 		return 0;
365 
366 	if (*out_aenum != NULL) {
367 		ASN1_INTEGER_free(*out_aenum);
368 		*out_aenum = NULL;
369 	}
370 
371 	if (!c2i_ASN1_INTEGER_cbs((ASN1_INTEGER **)&aenum, cbs))
372 		return 0;
373 
374 	aenum->type = V_ASN1_ENUMERATED | (aenum->type & V_ASN1_NEG);
375 	*out_aenum = aenum;
376 
377 	return 1;
378 }
379 
380 int
381 i2d_ASN1_ENUMERATED(ASN1_ENUMERATED *a, unsigned char **out)
382 {
383 	return ASN1_item_i2d((ASN1_VALUE *)a, out, &ASN1_ENUMERATED_it);
384 }
385 LCRYPTO_ALIAS(i2d_ASN1_ENUMERATED);
386 
387 ASN1_ENUMERATED *
388 d2i_ASN1_ENUMERATED(ASN1_ENUMERATED **a, const unsigned char **in, long len)
389 {
390 	return (ASN1_ENUMERATED *)ASN1_item_d2i((ASN1_VALUE **)a, in, len,
391 	    &ASN1_ENUMERATED_it);
392 }
393 LCRYPTO_ALIAS(d2i_ASN1_ENUMERATED);
394