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