xref: /freebsd/lib/libsecureboot/openpgp/decode.c (revision 2f513db7)
1 /*-
2  * Copyright (c) 2018, Juniper Networks, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include <libsecureboot.h>
30 
31 #include "decode.h"
32 
33 char *
34 octets2hex(unsigned char *ptr, size_t n)
35 {
36 	char *hex;
37 	char *cp;
38 	size_t i;
39 
40 	hex = malloc(2 * n + 1);
41 	if (hex != NULL) {
42 		for (i = 0, cp = hex; i < n; i++) {
43 			snprintf(&cp[i*2], 3, "%02X", ptr[i]);
44 		}
45 	}
46 	return (hex);
47 }
48 
49 unsigned char *
50 i2octets(int n, size_t i)
51 {
52 	static unsigned char o[16];
53 	int x, j;
54 
55 	if (n > 15)
56 		return (NULL);
57 	for (j = 0, x = n - 1; x >= 0; x--, j++) {
58 		o[j] = (unsigned char)((i & (0xff << x * 8)) >> x * 8);
59 	}
60 	return (o);
61 }
62 
63 int
64 octets2i(unsigned char *ptr, size_t n)
65 {
66 	size_t i;
67 	int val;
68 
69 	for (val = i = 0; i < n; i++) {
70 		val |= (*ptr++ << ((n - i - 1) * 8));
71 	}
72 	return (val);
73 }
74 
75 /**
76  * @brief decode packet tag
77  *
78  * Also indicate if new/old and in the later case
79  * the length type
80  *
81  * @sa rfc4880:4.2
82  */
83 int
84 decode_tag(unsigned char *ptr, int *isnew, int *ltype)
85 {
86 	int tag;
87 
88 	if (!ptr || !isnew || !ltype)
89 		return (-1);
90 	tag = *ptr;
91 
92 	if (!(tag & OPENPGP_TAG_ISTAG))
93 		return (-1);		/* we are lost! */
94 	*isnew = tag & OPENPGP_TAG_ISNEW;
95 	if (*isnew) {
96 		*ltype = -1;		/* irrelevant */
97 		tag &= OPENPGP_TAG_NEW_MASK;
98 	} else {
99 		*ltype = tag & OPENPGP_TAG_OLD_TYPE;
100 		tag = (tag & OPENPGP_TAG_OLD_MASK) >> 2;
101 	}
102 	return (tag);
103 }
104 
105 /**
106  * @brief return packet length
107  *
108  * @sa rfc4880:4.2.2
109  */
110 static int
111 decode_new_len(unsigned char **pptr)
112 {
113 	unsigned char *ptr;
114 	int len = -1;
115 
116 	if (pptr == NULL)
117 		return (-1);
118 	ptr = *pptr;
119 
120 	if (!(*ptr < 224 || *ptr == 255))
121 		return (-1);		/* not supported */
122 
123 	if (*ptr < 192)
124 		len = *ptr++;
125 	else if (*ptr < 224) {
126 		len = ((*ptr - 192) << 8) + *(ptr+1) + 192;
127 		ptr++;
128 	} else if (*ptr == 255) {
129 		len = (*ptr++ << 24);
130 		len |= (*ptr++ << 16);
131 		len |= (*ptr++ < 8);
132 		len |= *ptr++;
133 	}
134 
135 	*pptr = ptr;
136 	return (len);
137 }
138 
139 /**
140  * @brief return packet length
141  *
142  * @sa rfc4880:4.2.1
143  */
144 static int
145 decode_len(unsigned char **pptr, int ltype)
146 {
147 	unsigned char *ptr;
148 	int len;
149 
150 	if (ltype < 0)
151 		return (decode_new_len(pptr));
152 
153 	if (pptr == NULL)
154 		return (-1);
155 
156 	ptr = *pptr;
157 
158 	switch (ltype) {
159 	case 0:
160 		len = *ptr++;
161 		break;
162 	case 1:
163 		len = (*ptr++ << 8);
164 		len |= *ptr++;
165 		break;
166 	case 2:
167 		len =  *ptr++ << 24;
168 		len |= *ptr++ << 16;
169 		len |= *ptr++ << 8;
170 		len |= *ptr++;
171 		break;
172 	case 3:
173 	default:
174 		/* Not supported */
175 		len = -1;
176 	}
177 
178 	*pptr = ptr;
179 	return (len);
180 }
181 
182 /**
183  * @brief return pointer and length of an mpi
184  *
185  * @sa rfc4880:3.2
186  */
187 unsigned char *
188 decode_mpi(unsigned char **pptr, size_t *sz)
189 {
190 	unsigned char *data;
191 	unsigned char *ptr;
192 	size_t mlen;
193 
194 	if (pptr == NULL || sz == NULL)
195 		return (NULL);
196 
197 	ptr = *pptr;
198 
199 	mlen = (size_t)(*ptr++ << 8);
200 	mlen |= (size_t)*ptr++;		/* number of bits */
201 	mlen = (mlen + 7) / 8;		/* number of bytes */
202 	*sz = mlen;
203 	data = ptr;
204 	ptr += mlen;
205 	*pptr = ptr;
206 	return (data);
207 }
208 
209 /**
210  * @brief return an OpenSSL BIGNUM from mpi
211  *
212  * @sa rfc4880:3.2
213  */
214 #ifdef USE_BEARSSL
215 unsigned char *
216 mpi2bn(unsigned char **pptr, size_t *sz)
217 {
218 	return (decode_mpi(pptr, sz));
219 }
220 #else
221 BIGNUM *
222 mpi2bn(unsigned char **pptr)
223 {
224 	BIGNUM *bn = NULL;
225 	unsigned char *ptr;
226 	int mlen;
227 
228 	if (pptr == NULL)
229 		return (NULL);
230 
231 	ptr = *pptr;
232 
233 	mlen = (*ptr++ << 8);
234 	mlen |= *ptr++;			/* number of bits */
235 	mlen = (mlen + 7) / 8;		/* number of bytes */
236 	bn = BN_bin2bn(ptr, mlen, NULL);
237 	ptr += mlen;
238 	*pptr = ptr;
239 
240 	return (bn);
241 }
242 #endif
243 
244 /**
245  * @brief decode a packet
246  *
247  * If want is set, check that the packet tag matches
248  * if all good, call the provided decoder with its arg
249  *
250  * @return count of unconsumed data
251  *
252  * @sa rfc4880:4.2
253  */
254 int
255 decode_packet(int want, unsigned char **pptr, size_t nbytes,
256     decoder_t decoder, void *decoder_arg)
257 {
258 	int tag;
259 	unsigned char *ptr;
260 	unsigned char *nptr;
261 	int isnew, ltype;
262 	int len;
263 	int hlen;
264 	int rc = 0;
265 
266 	nptr = ptr = *pptr;
267 
268 	tag = decode_tag(ptr, &isnew, &ltype);
269 
270 	if (want > 0 && tag != want)
271 		return (-1);
272 	ptr++;
273 
274 	len = rc = decode_len(&ptr, ltype);
275 	hlen = (int)(ptr - nptr);
276 	nptr = ptr + len;		/* consume it */
277 
278 	if (decoder)
279 		rc = decoder(tag, &ptr, len, decoder_arg);
280 	*pptr = nptr;
281 	nbytes -= (size_t)(hlen + len);
282 	if (rc < 0)
283 		return (rc);		/* error */
284 	return ((int)nbytes);		/* unconsumed data */
285 }
286 
287 /**
288  * @brief decode a sub packet
289  *
290  * @sa rfc4880:5.2.3.1
291  */
292 unsigned char *
293 decode_subpacket(unsigned char **pptr, int *stag, int *sz)
294 {
295 	unsigned char *ptr;
296 	int len;
297 
298 	ptr = *pptr;
299 	len = decode_len(&ptr, -1);
300 	*sz = (int)(len + ptr - *pptr);
301 	*pptr = ptr + len;
302 	*stag = *ptr++;
303 	return (ptr);
304 }
305