1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: asn1_lib.c,v 1.54 2022/05/05 19:18:56 jsing Exp $ */
2*de0e0e4dSAntonio Huete Jimenez /*
3*de0e0e4dSAntonio Huete Jimenez  * Copyright (c) 2021 Joel Sing <jsing@openbsd.org>
4f5b1c8a1SJohn Marino  *
5*de0e0e4dSAntonio Huete Jimenez  * Permission to use, copy, modify, and distribute this software for any
6*de0e0e4dSAntonio Huete Jimenez  * purpose with or without fee is hereby granted, provided that the above
7*de0e0e4dSAntonio Huete Jimenez  * copyright notice and this permission notice appear in all copies.
8f5b1c8a1SJohn Marino  *
9*de0e0e4dSAntonio Huete Jimenez  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*de0e0e4dSAntonio Huete Jimenez  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*de0e0e4dSAntonio Huete Jimenez  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*de0e0e4dSAntonio Huete Jimenez  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*de0e0e4dSAntonio Huete Jimenez  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*de0e0e4dSAntonio Huete Jimenez  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*de0e0e4dSAntonio Huete Jimenez  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16f5b1c8a1SJohn Marino  */
17f5b1c8a1SJohn Marino 
18f5b1c8a1SJohn Marino #include <limits.h>
19*de0e0e4dSAntonio Huete Jimenez #include <stdlib.h>
20f5b1c8a1SJohn Marino 
21*de0e0e4dSAntonio Huete Jimenez #include "bytestring.h"
22f5b1c8a1SJohn Marino 
23f5b1c8a1SJohn Marino int
asn1_get_identifier_cbs(CBS * cbs,int der_mode,uint8_t * out_class,int * out_constructed,uint32_t * out_tag_number)24*de0e0e4dSAntonio Huete Jimenez asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class,
25*de0e0e4dSAntonio Huete Jimenez     int *out_constructed, uint32_t *out_tag_number)
26f5b1c8a1SJohn Marino {
27*de0e0e4dSAntonio Huete Jimenez 	uint8_t tag_class, tag_val;
28*de0e0e4dSAntonio Huete Jimenez 	int tag_constructed;
29*de0e0e4dSAntonio Huete Jimenez 	uint32_t tag_number;
30f5b1c8a1SJohn Marino 
31*de0e0e4dSAntonio Huete Jimenez 	/*
32*de0e0e4dSAntonio Huete Jimenez 	 * Decode ASN.1 identifier octets - see ITU-T X.690 section 8.1.2.
33*de0e0e4dSAntonio Huete Jimenez 	 */
34f5b1c8a1SJohn Marino 
35*de0e0e4dSAntonio Huete Jimenez 	*out_class = 0;
36*de0e0e4dSAntonio Huete Jimenez 	*out_constructed = 0;
37*de0e0e4dSAntonio Huete Jimenez 	*out_tag_number = 0;
38f5b1c8a1SJohn Marino 
39*de0e0e4dSAntonio Huete Jimenez 	if (!CBS_get_u8(cbs, &tag_val))
40f5b1c8a1SJohn Marino 		return 0;
41*de0e0e4dSAntonio Huete Jimenez 
42*de0e0e4dSAntonio Huete Jimenez 	/*
43*de0e0e4dSAntonio Huete Jimenez 	 * ASN.1 tag class, encoding (primitive or constructed) and tag number
44*de0e0e4dSAntonio Huete Jimenez 	 * are encoded in one or more identifier octets - the first octet
45*de0e0e4dSAntonio Huete Jimenez 	 * contains the 2 bit tag class, the 1 bit encoding type and 5 bits
46*de0e0e4dSAntonio Huete Jimenez 	 * of tag number.
47*de0e0e4dSAntonio Huete Jimenez 	 *
48*de0e0e4dSAntonio Huete Jimenez 	 * For tag numbers larger than 30 (0x1e) the 5 bit tag number in the
49*de0e0e4dSAntonio Huete Jimenez 	 * first octet is set to all ones (0x1f) - the tag number is then
50*de0e0e4dSAntonio Huete Jimenez 	 * encoded in subsequent octets - each of which have a one bit
51*de0e0e4dSAntonio Huete Jimenez 	 * continuation flag and 7 bits of tag number in big-endian form.
52*de0e0e4dSAntonio Huete Jimenez 	 * The encoding should not contain leading zeros but can for BER.
53*de0e0e4dSAntonio Huete Jimenez 	 */
54*de0e0e4dSAntonio Huete Jimenez 	tag_class = (tag_val >> 6) & 0x3;
55*de0e0e4dSAntonio Huete Jimenez 	tag_constructed = (tag_val >> 5) & 0x1;
56*de0e0e4dSAntonio Huete Jimenez 	tag_number = tag_val & 0x1f;
57*de0e0e4dSAntonio Huete Jimenez 
58*de0e0e4dSAntonio Huete Jimenez 	/* Long form. */
59*de0e0e4dSAntonio Huete Jimenez 	if (tag_number == 0x1f) {
60*de0e0e4dSAntonio Huete Jimenez 		tag_number = 0;
61*de0e0e4dSAntonio Huete Jimenez 		do {
62*de0e0e4dSAntonio Huete Jimenez 			if (!CBS_get_u8(cbs, &tag_val))
63f5b1c8a1SJohn Marino 				return 0;
64*de0e0e4dSAntonio Huete Jimenez 			if (der_mode && tag_number == 0 && tag_val == 0x80)
65f5b1c8a1SJohn Marino 				return 0;
66*de0e0e4dSAntonio Huete Jimenez 			if (tag_number > (UINT32_MAX >> 7))
67f5b1c8a1SJohn Marino 				return 0;
68*de0e0e4dSAntonio Huete Jimenez 			tag_number = tag_number << 7 | (tag_val & 0x7f);
69*de0e0e4dSAntonio Huete Jimenez 		} while ((tag_val & 0x80) != 0);
70*de0e0e4dSAntonio Huete Jimenez 	}
71*de0e0e4dSAntonio Huete Jimenez 
72*de0e0e4dSAntonio Huete Jimenez 	*out_class = tag_class;
73*de0e0e4dSAntonio Huete Jimenez 	*out_constructed = tag_constructed;
74*de0e0e4dSAntonio Huete Jimenez 	*out_tag_number = tag_number;
75*de0e0e4dSAntonio Huete Jimenez 
76f5b1c8a1SJohn Marino 	return 1;
77f5b1c8a1SJohn Marino }
78f5b1c8a1SJohn Marino 
79*de0e0e4dSAntonio Huete Jimenez int
asn1_get_length_cbs(CBS * cbs,int der_mode,int * out_indefinite,size_t * out_length)80*de0e0e4dSAntonio Huete Jimenez asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite,
81*de0e0e4dSAntonio Huete Jimenez     size_t *out_length)
82f5b1c8a1SJohn Marino {
83*de0e0e4dSAntonio Huete Jimenez 	uint8_t len_bytes;
84*de0e0e4dSAntonio Huete Jimenez 	size_t length;
85*de0e0e4dSAntonio Huete Jimenez 	uint8_t val;
86f5b1c8a1SJohn Marino 
87*de0e0e4dSAntonio Huete Jimenez 	/*
88*de0e0e4dSAntonio Huete Jimenez 	 * Decode ASN.1 length octets - see ITU-T X.690 section 8.1.3.
89*de0e0e4dSAntonio Huete Jimenez 	 */
90*de0e0e4dSAntonio Huete Jimenez 
91*de0e0e4dSAntonio Huete Jimenez 	*out_length = 0;
92*de0e0e4dSAntonio Huete Jimenez 	*out_indefinite = 0;
93*de0e0e4dSAntonio Huete Jimenez 
94*de0e0e4dSAntonio Huete Jimenez 	if (!CBS_get_u8(cbs, &val))
95*de0e0e4dSAntonio Huete Jimenez 		return 0;
96*de0e0e4dSAntonio Huete Jimenez 
97*de0e0e4dSAntonio Huete Jimenez 	/*
98*de0e0e4dSAntonio Huete Jimenez 	 * Short form - length is encoded in the lower 7 bits of a single byte.
99*de0e0e4dSAntonio Huete Jimenez 	 */
100*de0e0e4dSAntonio Huete Jimenez 	if (val < 0x80) {
101*de0e0e4dSAntonio Huete Jimenez 		*out_length = val;
102*de0e0e4dSAntonio Huete Jimenez 		return 1;
103f5b1c8a1SJohn Marino 	}
104*de0e0e4dSAntonio Huete Jimenez 
105*de0e0e4dSAntonio Huete Jimenez 	/*
106*de0e0e4dSAntonio Huete Jimenez 	 * Indefinite length - content continues until an End of Content (EOC)
107*de0e0e4dSAntonio Huete Jimenez 	 * marker is reached. Must be used with constructed encoding.
108*de0e0e4dSAntonio Huete Jimenez 	 */
109*de0e0e4dSAntonio Huete Jimenez 	if (val == 0x80) {
110*de0e0e4dSAntonio Huete Jimenez 		*out_indefinite = 1;
111*de0e0e4dSAntonio Huete Jimenez 		return 1;
112*de0e0e4dSAntonio Huete Jimenez 	}
113*de0e0e4dSAntonio Huete Jimenez 
114*de0e0e4dSAntonio Huete Jimenez 	/*
115*de0e0e4dSAntonio Huete Jimenez 	 * Long form - the lower 7 bits of the first byte specifies the number
116*de0e0e4dSAntonio Huete Jimenez 	 * of bytes used to encode the length, the following bytes specify the
117*de0e0e4dSAntonio Huete Jimenez 	 * length in big-endian form. The encoding should not contain leading
118*de0e0e4dSAntonio Huete Jimenez 	 * zeros but can for BER. A length value of 0x7f is invalid.
119*de0e0e4dSAntonio Huete Jimenez 	 */
120*de0e0e4dSAntonio Huete Jimenez 	if ((len_bytes = val & 0x7f) == 0x7f)
121*de0e0e4dSAntonio Huete Jimenez 		return 0;
122*de0e0e4dSAntonio Huete Jimenez 
123*de0e0e4dSAntonio Huete Jimenez 	length = 0;
124*de0e0e4dSAntonio Huete Jimenez 
125*de0e0e4dSAntonio Huete Jimenez 	while (len_bytes-- > 0) {
126*de0e0e4dSAntonio Huete Jimenez 		if (!CBS_get_u8(cbs, &val))
127*de0e0e4dSAntonio Huete Jimenez 			return 0;
128*de0e0e4dSAntonio Huete Jimenez 		if (der_mode && length == 0 && val == 0)
129*de0e0e4dSAntonio Huete Jimenez 			return 0;
130*de0e0e4dSAntonio Huete Jimenez 		if (length > (SIZE_MAX >> 8))
131*de0e0e4dSAntonio Huete Jimenez 			return 0;
132*de0e0e4dSAntonio Huete Jimenez 		length = (length << 8) | val;
133*de0e0e4dSAntonio Huete Jimenez 	}
134*de0e0e4dSAntonio Huete Jimenez 
135*de0e0e4dSAntonio Huete Jimenez 	*out_length = length;
136*de0e0e4dSAntonio Huete Jimenez 
137*de0e0e4dSAntonio Huete Jimenez 	return 1;
138f5b1c8a1SJohn Marino }
139f5b1c8a1SJohn Marino 
140f5b1c8a1SJohn Marino int
asn1_get_object_cbs(CBS * cbs,int der_mode,uint8_t * out_tag_class,int * out_constructed,uint32_t * out_tag_number,int * out_indefinite,size_t * out_length)141*de0e0e4dSAntonio Huete Jimenez asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_tag_class,
142*de0e0e4dSAntonio Huete Jimenez     int *out_constructed, uint32_t *out_tag_number, int *out_indefinite,
143*de0e0e4dSAntonio Huete Jimenez     size_t *out_length)
144f5b1c8a1SJohn Marino {
145*de0e0e4dSAntonio Huete Jimenez 	int constructed, indefinite;
146*de0e0e4dSAntonio Huete Jimenez 	uint32_t tag_number;
147*de0e0e4dSAntonio Huete Jimenez 	uint8_t tag_class;
148*de0e0e4dSAntonio Huete Jimenez 	size_t length;
149f5b1c8a1SJohn Marino 
150*de0e0e4dSAntonio Huete Jimenez 	*out_tag_class = 0;
151*de0e0e4dSAntonio Huete Jimenez 	*out_constructed = 0;
152*de0e0e4dSAntonio Huete Jimenez 	*out_tag_number = 0;
153*de0e0e4dSAntonio Huete Jimenez 	*out_indefinite = 0;
154*de0e0e4dSAntonio Huete Jimenez 	*out_length = 0;
155f5b1c8a1SJohn Marino 
156*de0e0e4dSAntonio Huete Jimenez 	if (!asn1_get_identifier_cbs(cbs, der_mode, &tag_class, &constructed,
157*de0e0e4dSAntonio Huete Jimenez 	    &tag_number))
158*de0e0e4dSAntonio Huete Jimenez 		return 0;
159*de0e0e4dSAntonio Huete Jimenez 	if (!asn1_get_length_cbs(cbs, der_mode, &indefinite, &length))
160*de0e0e4dSAntonio Huete Jimenez 		return 0;
161f5b1c8a1SJohn Marino 
162*de0e0e4dSAntonio Huete Jimenez 	/* Indefinite length can only be used with constructed encoding. */
163*de0e0e4dSAntonio Huete Jimenez 	if (indefinite && !constructed)
164*de0e0e4dSAntonio Huete Jimenez 		return 0;
165f5b1c8a1SJohn Marino 
166*de0e0e4dSAntonio Huete Jimenez 	*out_tag_class = tag_class;
167*de0e0e4dSAntonio Huete Jimenez 	*out_constructed = constructed;
168*de0e0e4dSAntonio Huete Jimenez 	*out_tag_number = tag_number;
169*de0e0e4dSAntonio Huete Jimenez 	*out_indefinite = indefinite;
170*de0e0e4dSAntonio Huete Jimenez 	*out_length = length;
171f5b1c8a1SJohn Marino 
172*de0e0e4dSAntonio Huete Jimenez 	return 1;
173f5b1c8a1SJohn Marino }
174f5b1c8a1SJohn Marino 
175f5b1c8a1SJohn Marino int
asn1_get_primitive(CBS * cbs,int der_mode,uint32_t * out_tag_number,CBS * out_content)176*de0e0e4dSAntonio Huete Jimenez asn1_get_primitive(CBS *cbs, int der_mode, uint32_t *out_tag_number,
177*de0e0e4dSAntonio Huete Jimenez     CBS *out_content)
178f5b1c8a1SJohn Marino {
179*de0e0e4dSAntonio Huete Jimenez 	int constructed, indefinite;
180*de0e0e4dSAntonio Huete Jimenez 	uint32_t tag_number;
181*de0e0e4dSAntonio Huete Jimenez 	uint8_t tag_class;
182*de0e0e4dSAntonio Huete Jimenez 	size_t length;
183f5b1c8a1SJohn Marino 
184*de0e0e4dSAntonio Huete Jimenez 	*out_tag_number = 0;
185f5b1c8a1SJohn Marino 
186*de0e0e4dSAntonio Huete Jimenez 	CBS_init(out_content, NULL, 0);
187f5b1c8a1SJohn Marino 
188*de0e0e4dSAntonio Huete Jimenez 	if (!asn1_get_identifier_cbs(cbs, der_mode, &tag_class, &constructed,
189*de0e0e4dSAntonio Huete Jimenez 	    &tag_number))
190*de0e0e4dSAntonio Huete Jimenez 		return 0;
191*de0e0e4dSAntonio Huete Jimenez 	if (!asn1_get_length_cbs(cbs, der_mode, &indefinite, &length))
192*de0e0e4dSAntonio Huete Jimenez 		return 0;
193f5b1c8a1SJohn Marino 
194*de0e0e4dSAntonio Huete Jimenez 	/* A primitive is not constructed and has a definite length. */
195*de0e0e4dSAntonio Huete Jimenez 	if (constructed || indefinite)
196*de0e0e4dSAntonio Huete Jimenez 		return 0;
197f5b1c8a1SJohn Marino 
198*de0e0e4dSAntonio Huete Jimenez 	if (!CBS_get_bytes(cbs, out_content, length))
199*de0e0e4dSAntonio Huete Jimenez 		return 0;
200f5b1c8a1SJohn Marino 
201*de0e0e4dSAntonio Huete Jimenez 	*out_tag_number = tag_number;
20272c33676SMaxim Ag 
203*de0e0e4dSAntonio Huete Jimenez 	return 1;
20472c33676SMaxim Ag }
205