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