xref: /linux/lib/asn1_encoder.c (revision b1e78ef3)
1b0706762SJames Bottomley // SPDX-License-Identifier: GPL-2.0-only
2b0706762SJames Bottomley /*
3b0706762SJames Bottomley  * Simple encoder primitives for ASN.1 BER/DER/CER
4b0706762SJames Bottomley  *
5b0706762SJames Bottomley  * Copyright (C) 2019 James.Bottomley@HansenPartnership.com
6b0706762SJames Bottomley  */
7b0706762SJames Bottomley 
8b0706762SJames Bottomley #include <linux/asn1_encoder.h>
9b0706762SJames Bottomley #include <linux/bug.h>
10b0706762SJames Bottomley #include <linux/string.h>
11b0706762SJames Bottomley #include <linux/module.h>
12b0706762SJames Bottomley 
13b0706762SJames Bottomley /**
14b0706762SJames Bottomley  * asn1_encode_integer() - encode positive integer to ASN.1
15b0706762SJames Bottomley  * @data:	pointer to the pointer to the data
16b0706762SJames Bottomley  * @end_data:	end of data pointer, points one beyond last usable byte in @data
17b0706762SJames Bottomley  * @integer:	integer to be encoded
18b0706762SJames Bottomley  *
19b0706762SJames Bottomley  * This is a simplified encoder: it only currently does
20b0706762SJames Bottomley  * positive integers, but it should be simple enough to add the
21b0706762SJames Bottomley  * negative case if a use comes along.
22b0706762SJames Bottomley  */
23b0706762SJames Bottomley unsigned char *
asn1_encode_integer(unsigned char * data,const unsigned char * end_data,s64 integer)24b0706762SJames Bottomley asn1_encode_integer(unsigned char *data, const unsigned char *end_data,
25b0706762SJames Bottomley 		    s64 integer)
26b0706762SJames Bottomley {
27b0706762SJames Bottomley 	int data_len = end_data - data;
28b0706762SJames Bottomley 	unsigned char *d = &data[2];
29b0706762SJames Bottomley 	bool found = false;
30b0706762SJames Bottomley 	int i;
31b0706762SJames Bottomley 
32b0706762SJames Bottomley 	if (WARN(integer < 0,
33b0706762SJames Bottomley 		 "BUG: integer encode only supports positive integers"))
34b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
35b0706762SJames Bottomley 
36b0706762SJames Bottomley 	if (IS_ERR(data))
37b0706762SJames Bottomley 		return data;
38b0706762SJames Bottomley 
39b0706762SJames Bottomley 	/* need at least 3 bytes for tag, length and integer encoding */
40b0706762SJames Bottomley 	if (data_len < 3)
41b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
42b0706762SJames Bottomley 
43b0706762SJames Bottomley 	/* remaining length where at d (the start of the integer encoding) */
44b0706762SJames Bottomley 	data_len -= 2;
45b0706762SJames Bottomley 
46b0706762SJames Bottomley 	data[0] = _tag(UNIV, PRIM, INT);
47b0706762SJames Bottomley 	if (integer == 0) {
48b0706762SJames Bottomley 		*d++ = 0;
49b0706762SJames Bottomley 		goto out;
50b0706762SJames Bottomley 	}
51b0706762SJames Bottomley 
52b0706762SJames Bottomley 	for (i = sizeof(integer); i > 0 ; i--) {
53b0706762SJames Bottomley 		int byte = integer >> (8 * (i - 1));
54b0706762SJames Bottomley 
55b0706762SJames Bottomley 		if (!found && byte == 0)
56b0706762SJames Bottomley 			continue;
57b0706762SJames Bottomley 
58b0706762SJames Bottomley 		/*
59b0706762SJames Bottomley 		 * for a positive number the first byte must have bit
60b0706762SJames Bottomley 		 * 7 clear in two's complement (otherwise it's a
61b0706762SJames Bottomley 		 * negative number) so prepend a leading zero if
62b0706762SJames Bottomley 		 * that's not the case
63b0706762SJames Bottomley 		 */
64b0706762SJames Bottomley 		if (!found && (byte & 0x80)) {
65b0706762SJames Bottomley 			/*
66b0706762SJames Bottomley 			 * no check needed here, we already know we
67b0706762SJames Bottomley 			 * have len >= 1
68b0706762SJames Bottomley 			 */
69b0706762SJames Bottomley 			*d++ = 0;
70b0706762SJames Bottomley 			data_len--;
71b0706762SJames Bottomley 		}
72b0706762SJames Bottomley 
73b0706762SJames Bottomley 		found = true;
74b0706762SJames Bottomley 		if (data_len == 0)
75b0706762SJames Bottomley 			return ERR_PTR(-EINVAL);
76b0706762SJames Bottomley 
77b0706762SJames Bottomley 		*d++ = byte;
78b0706762SJames Bottomley 		data_len--;
79b0706762SJames Bottomley 	}
80b0706762SJames Bottomley 
81b0706762SJames Bottomley  out:
82b0706762SJames Bottomley 	data[1] = d - data - 2;
83b0706762SJames Bottomley 
84b0706762SJames Bottomley 	return d;
85b0706762SJames Bottomley }
86b0706762SJames Bottomley EXPORT_SYMBOL_GPL(asn1_encode_integer);
87b0706762SJames Bottomley 
88b0706762SJames Bottomley /* calculate the base 128 digit values setting the top bit of the first octet */
asn1_encode_oid_digit(unsigned char ** _data,int * data_len,u32 oid)89b0706762SJames Bottomley static int asn1_encode_oid_digit(unsigned char **_data, int *data_len, u32 oid)
90b0706762SJames Bottomley {
91b0706762SJames Bottomley 	unsigned char *data = *_data;
92b0706762SJames Bottomley 	int start = 7 + 7 + 7 + 7;
93b0706762SJames Bottomley 	int ret = 0;
94b0706762SJames Bottomley 
95b0706762SJames Bottomley 	if (*data_len < 1)
96b0706762SJames Bottomley 		return -EINVAL;
97b0706762SJames Bottomley 
98b0706762SJames Bottomley 	/* quick case */
99b0706762SJames Bottomley 	if (oid == 0) {
100b0706762SJames Bottomley 		*data++ = 0x80;
101b0706762SJames Bottomley 		(*data_len)--;
102b0706762SJames Bottomley 		goto out;
103b0706762SJames Bottomley 	}
104b0706762SJames Bottomley 
105b0706762SJames Bottomley 	while (oid >> start == 0)
106b0706762SJames Bottomley 		start -= 7;
107b0706762SJames Bottomley 
108b0706762SJames Bottomley 	while (start > 0 && *data_len > 0) {
109b0706762SJames Bottomley 		u8 byte;
110b0706762SJames Bottomley 
111b0706762SJames Bottomley 		byte = oid >> start;
112b0706762SJames Bottomley 		oid = oid - (byte << start);
113b0706762SJames Bottomley 		start -= 7;
114b0706762SJames Bottomley 		byte |= 0x80;
115b0706762SJames Bottomley 		*data++ = byte;
116b0706762SJames Bottomley 		(*data_len)--;
117b0706762SJames Bottomley 	}
118b0706762SJames Bottomley 
119b0706762SJames Bottomley 	if (*data_len > 0) {
120b0706762SJames Bottomley 		*data++ = oid;
121b0706762SJames Bottomley 		(*data_len)--;
122b0706762SJames Bottomley 	} else {
123b0706762SJames Bottomley 		ret = -EINVAL;
124b0706762SJames Bottomley 	}
125b0706762SJames Bottomley 
126b0706762SJames Bottomley  out:
127b0706762SJames Bottomley 	*_data = data;
128b0706762SJames Bottomley 	return ret;
129b0706762SJames Bottomley }
130b0706762SJames Bottomley 
131b0706762SJames Bottomley /**
132b0706762SJames Bottomley  * asn1_encode_oid() - encode an oid to ASN.1
133b0706762SJames Bottomley  * @data:	position to begin encoding at
134b0706762SJames Bottomley  * @end_data:	end of data pointer, points one beyond last usable byte in @data
135b0706762SJames Bottomley  * @oid:	array of oids
136b0706762SJames Bottomley  * @oid_len:	length of oid array
137b0706762SJames Bottomley  *
138b0706762SJames Bottomley  * this encodes an OID up to ASN.1 when presented as an array of OID values
139b0706762SJames Bottomley  */
140b0706762SJames Bottomley unsigned char *
asn1_encode_oid(unsigned char * data,const unsigned char * end_data,u32 oid[],int oid_len)141b0706762SJames Bottomley asn1_encode_oid(unsigned char *data, const unsigned char *end_data,
142b0706762SJames Bottomley 		u32 oid[], int oid_len)
143b0706762SJames Bottomley {
144b0706762SJames Bottomley 	int data_len = end_data - data;
145b0706762SJames Bottomley 	unsigned char *d = data + 2;
146b0706762SJames Bottomley 	int i, ret;
147b0706762SJames Bottomley 
148b0706762SJames Bottomley 	if (WARN(oid_len < 2, "OID must have at least two elements"))
149b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
150b0706762SJames Bottomley 
151b0706762SJames Bottomley 	if (WARN(oid_len > 32, "OID is too large"))
152b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
153b0706762SJames Bottomley 
154b0706762SJames Bottomley 	if (IS_ERR(data))
155b0706762SJames Bottomley 		return data;
156b0706762SJames Bottomley 
157b0706762SJames Bottomley 
158b0706762SJames Bottomley 	/* need at least 3 bytes for tag, length and OID encoding */
159b0706762SJames Bottomley 	if (data_len < 3)
160b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
161b0706762SJames Bottomley 
162b0706762SJames Bottomley 	data[0] = _tag(UNIV, PRIM, OID);
163b0706762SJames Bottomley 	*d++ = oid[0] * 40 + oid[1];
164b0706762SJames Bottomley 
165b0706762SJames Bottomley 	data_len -= 3;
166b0706762SJames Bottomley 
167b0706762SJames Bottomley 	for (i = 2; i < oid_len; i++) {
168b0706762SJames Bottomley 		ret = asn1_encode_oid_digit(&d, &data_len, oid[i]);
169b0706762SJames Bottomley 		if (ret < 0)
170b0706762SJames Bottomley 			return ERR_PTR(ret);
171b0706762SJames Bottomley 	}
172b0706762SJames Bottomley 
173b0706762SJames Bottomley 	data[1] = d - data - 2;
174b0706762SJames Bottomley 
175b0706762SJames Bottomley 	return d;
176b0706762SJames Bottomley }
177b0706762SJames Bottomley EXPORT_SYMBOL_GPL(asn1_encode_oid);
178b0706762SJames Bottomley 
179b0706762SJames Bottomley /**
180b0706762SJames Bottomley  * asn1_encode_length() - encode a length to follow an ASN.1 tag
181b0706762SJames Bottomley  * @data: pointer to encode at
182*9dbbc3b9SZhen Lei  * @data_len: pointer to remaining length (adjusted by routine)
183b0706762SJames Bottomley  * @len: length to encode
184b0706762SJames Bottomley  *
185b0706762SJames Bottomley  * This routine can encode lengths up to 65535 using the ASN.1 rules.
186b0706762SJames Bottomley  * It will accept a negative length and place a zero length tag
187b0706762SJames Bottomley  * instead (to keep the ASN.1 valid).  This convention allows other
188b0706762SJames Bottomley  * encoder primitives to accept negative lengths as singalling the
189b0706762SJames Bottomley  * sequence will be re-encoded when the length is known.
190b0706762SJames Bottomley  */
asn1_encode_length(unsigned char ** data,int * data_len,int len)191b0706762SJames Bottomley static int asn1_encode_length(unsigned char **data, int *data_len, int len)
192b0706762SJames Bottomley {
193b0706762SJames Bottomley 	if (*data_len < 1)
194b0706762SJames Bottomley 		return -EINVAL;
195b0706762SJames Bottomley 
196b0706762SJames Bottomley 	if (len < 0) {
197b0706762SJames Bottomley 		*((*data)++) = 0;
198b0706762SJames Bottomley 		(*data_len)--;
199b0706762SJames Bottomley 		return 0;
200b0706762SJames Bottomley 	}
201b0706762SJames Bottomley 
202b0706762SJames Bottomley 	if (len <= 0x7f) {
203b0706762SJames Bottomley 		*((*data)++) = len;
204b0706762SJames Bottomley 		(*data_len)--;
205b0706762SJames Bottomley 		return 0;
206b0706762SJames Bottomley 	}
207b0706762SJames Bottomley 
208b0706762SJames Bottomley 	if (*data_len < 2)
209b0706762SJames Bottomley 		return -EINVAL;
210b0706762SJames Bottomley 
211b0706762SJames Bottomley 	if (len <= 0xff) {
212b0706762SJames Bottomley 		*((*data)++) = 0x81;
213b0706762SJames Bottomley 		*((*data)++) = len & 0xff;
214b0706762SJames Bottomley 		*data_len -= 2;
215b0706762SJames Bottomley 		return 0;
216b0706762SJames Bottomley 	}
217b0706762SJames Bottomley 
218b0706762SJames Bottomley 	if (*data_len < 3)
219b0706762SJames Bottomley 		return -EINVAL;
220b0706762SJames Bottomley 
221b0706762SJames Bottomley 	if (len <= 0xffff) {
222b0706762SJames Bottomley 		*((*data)++) = 0x82;
223b0706762SJames Bottomley 		*((*data)++) = (len >> 8) & 0xff;
224b0706762SJames Bottomley 		*((*data)++) = len & 0xff;
225b0706762SJames Bottomley 		*data_len -= 3;
226b0706762SJames Bottomley 		return 0;
227b0706762SJames Bottomley 	}
228b0706762SJames Bottomley 
229b0706762SJames Bottomley 	if (WARN(len > 0xffffff, "ASN.1 length can't be > 0xffffff"))
230b0706762SJames Bottomley 		return -EINVAL;
231b0706762SJames Bottomley 
232b0706762SJames Bottomley 	if (*data_len < 4)
233b0706762SJames Bottomley 		return -EINVAL;
234b0706762SJames Bottomley 	*((*data)++) = 0x83;
235b0706762SJames Bottomley 	*((*data)++) = (len >> 16) & 0xff;
236b0706762SJames Bottomley 	*((*data)++) = (len >> 8) & 0xff;
237b0706762SJames Bottomley 	*((*data)++) = len & 0xff;
238b0706762SJames Bottomley 	*data_len -= 4;
239b0706762SJames Bottomley 
240b0706762SJames Bottomley 	return 0;
241b0706762SJames Bottomley }
242b0706762SJames Bottomley 
243b0706762SJames Bottomley /**
244b0706762SJames Bottomley  * asn1_encode_tag() - add a tag for optional or explicit value
245b0706762SJames Bottomley  * @data:	pointer to place tag at
246b0706762SJames Bottomley  * @end_data:	end of data pointer, points one beyond last usable byte in @data
247b0706762SJames Bottomley  * @tag:	tag to be placed
248b0706762SJames Bottomley  * @string:	the data to be tagged
249b0706762SJames Bottomley  * @len:	the length of the data to be tagged
250b0706762SJames Bottomley  *
251b0706762SJames Bottomley  * Note this currently only handles short form tags < 31.
252b0706762SJames Bottomley  *
253b0706762SJames Bottomley  * Standard usage is to pass in a @tag, @string and @length and the
254b0706762SJames Bottomley  * @string will be ASN.1 encoded with @tag and placed into @data.  If
255b0706762SJames Bottomley  * the encoding would put data past @end_data then an error is
256b0706762SJames Bottomley  * returned, otherwise a pointer to a position one beyond the encoding
257b0706762SJames Bottomley  * is returned.
258b0706762SJames Bottomley  *
259b0706762SJames Bottomley  * To encode in place pass a NULL @string and -1 for @len and the
260b0706762SJames Bottomley  * maximum allowable beginning and end of the data; all this will do
261b0706762SJames Bottomley  * is add the current maximum length and update the data pointer to
262b0706762SJames Bottomley  * the place where the tag contents should be placed is returned.  The
263b0706762SJames Bottomley  * data should be copied in by the calling routine which should then
264b0706762SJames Bottomley  * repeat the prior statement but now with the known length.  In order
265b0706762SJames Bottomley  * to avoid having to keep both before and after pointers, the repeat
266b0706762SJames Bottomley  * expects to be called with @data pointing to where the first encode
267b0706762SJames Bottomley  * returned it and still NULL for @string but the real length in @len.
268b0706762SJames Bottomley  */
269b0706762SJames Bottomley unsigned char *
asn1_encode_tag(unsigned char * data,const unsigned char * end_data,u32 tag,const unsigned char * string,int len)270b0706762SJames Bottomley asn1_encode_tag(unsigned char *data, const unsigned char *end_data,
271b0706762SJames Bottomley 		u32 tag, const unsigned char *string, int len)
272b0706762SJames Bottomley {
273b0706762SJames Bottomley 	int data_len = end_data - data;
274b0706762SJames Bottomley 	int ret;
275b0706762SJames Bottomley 
276b0706762SJames Bottomley 	if (WARN(tag > 30, "ASN.1 tag can't be > 30"))
277b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
278b0706762SJames Bottomley 
279b0706762SJames Bottomley 	if (!string && WARN(len > 127,
280b0706762SJames Bottomley 			    "BUG: recode tag is too big (>127)"))
281b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
282b0706762SJames Bottomley 
283b0706762SJames Bottomley 	if (IS_ERR(data))
284b0706762SJames Bottomley 		return data;
285b0706762SJames Bottomley 
286b0706762SJames Bottomley 	if (!string && len > 0) {
287b0706762SJames Bottomley 		/*
288b0706762SJames Bottomley 		 * we're recoding, so move back to the start of the
289b0706762SJames Bottomley 		 * tag and install a dummy length because the real
290b0706762SJames Bottomley 		 * data_len should be NULL
291b0706762SJames Bottomley 		 */
292b0706762SJames Bottomley 		data -= 2;
293b0706762SJames Bottomley 		data_len = 2;
294b0706762SJames Bottomley 	}
295b0706762SJames Bottomley 
296b0706762SJames Bottomley 	if (data_len < 2)
297b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
298b0706762SJames Bottomley 
299b0706762SJames Bottomley 	*(data++) = _tagn(CONT, CONS, tag);
300b0706762SJames Bottomley 	data_len--;
301b0706762SJames Bottomley 	ret = asn1_encode_length(&data, &data_len, len);
302b0706762SJames Bottomley 	if (ret < 0)
303b0706762SJames Bottomley 		return ERR_PTR(ret);
304b0706762SJames Bottomley 
305b0706762SJames Bottomley 	if (!string)
306b0706762SJames Bottomley 		return data;
307b0706762SJames Bottomley 
308b0706762SJames Bottomley 	if (data_len < len)
309b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
310b0706762SJames Bottomley 
311b0706762SJames Bottomley 	memcpy(data, string, len);
312b0706762SJames Bottomley 	data += len;
313b0706762SJames Bottomley 
314b0706762SJames Bottomley 	return data;
315b0706762SJames Bottomley }
316b0706762SJames Bottomley EXPORT_SYMBOL_GPL(asn1_encode_tag);
317b0706762SJames Bottomley 
318b0706762SJames Bottomley /**
319b0706762SJames Bottomley  * asn1_encode_octet_string() - encode an ASN.1 OCTET STRING
320b0706762SJames Bottomley  * @data:	pointer to encode at
321b0706762SJames Bottomley  * @end_data:	end of data pointer, points one beyond last usable byte in @data
322b0706762SJames Bottomley  * @string:	string to be encoded
323b0706762SJames Bottomley  * @len:	length of string
324b0706762SJames Bottomley  *
325b0706762SJames Bottomley  * Note ASN.1 octet strings may contain zeros, so the length is obligatory.
326b0706762SJames Bottomley  */
327b0706762SJames Bottomley unsigned char *
asn1_encode_octet_string(unsigned char * data,const unsigned char * end_data,const unsigned char * string,u32 len)328b0706762SJames Bottomley asn1_encode_octet_string(unsigned char *data,
329b0706762SJames Bottomley 			 const unsigned char *end_data,
330b0706762SJames Bottomley 			 const unsigned char *string, u32 len)
331b0706762SJames Bottomley {
332b0706762SJames Bottomley 	int data_len = end_data - data;
333b0706762SJames Bottomley 	int ret;
334b0706762SJames Bottomley 
335b0706762SJames Bottomley 	if (IS_ERR(data))
336b0706762SJames Bottomley 		return data;
337b0706762SJames Bottomley 
338b0706762SJames Bottomley 	/* need minimum of 2 bytes for tag and length of zero length string */
339b0706762SJames Bottomley 	if (data_len < 2)
340b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
341b0706762SJames Bottomley 
342b0706762SJames Bottomley 	*(data++) = _tag(UNIV, PRIM, OTS);
343b0706762SJames Bottomley 	data_len--;
344b0706762SJames Bottomley 
345b0706762SJames Bottomley 	ret = asn1_encode_length(&data, &data_len, len);
346b0706762SJames Bottomley 	if (ret)
347b0706762SJames Bottomley 		return ERR_PTR(ret);
348b0706762SJames Bottomley 
349b0706762SJames Bottomley 	if (data_len < len)
350b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
351b0706762SJames Bottomley 
352b0706762SJames Bottomley 	memcpy(data, string, len);
353b0706762SJames Bottomley 	data += len;
354b0706762SJames Bottomley 
355b0706762SJames Bottomley 	return data;
356b0706762SJames Bottomley }
357b0706762SJames Bottomley EXPORT_SYMBOL_GPL(asn1_encode_octet_string);
358b0706762SJames Bottomley 
359b0706762SJames Bottomley /**
360b0706762SJames Bottomley  * asn1_encode_sequence() - wrap a byte stream in an ASN.1 SEQUENCE
361b0706762SJames Bottomley  * @data:	pointer to encode at
362b0706762SJames Bottomley  * @end_data:	end of data pointer, points one beyond last usable byte in @data
363b0706762SJames Bottomley  * @seq:	data to be encoded as a sequence
364b0706762SJames Bottomley  * @len:	length of the data to be encoded as a sequence
365b0706762SJames Bottomley  *
366b0706762SJames Bottomley  * Fill in a sequence.  To encode in place, pass NULL for @seq and -1
367b0706762SJames Bottomley  * for @len; then call again once the length is known (still with NULL
368b0706762SJames Bottomley  * for @seq). In order to avoid having to keep both before and after
369b0706762SJames Bottomley  * pointers, the repeat expects to be called with @data pointing to
370b0706762SJames Bottomley  * where the first encode placed it.
371b0706762SJames Bottomley  */
372b0706762SJames Bottomley unsigned char *
asn1_encode_sequence(unsigned char * data,const unsigned char * end_data,const unsigned char * seq,int len)373b0706762SJames Bottomley asn1_encode_sequence(unsigned char *data, const unsigned char *end_data,
374b0706762SJames Bottomley 		     const unsigned char *seq, int len)
375b0706762SJames Bottomley {
376b0706762SJames Bottomley 	int data_len = end_data - data;
377b0706762SJames Bottomley 	int ret;
378b0706762SJames Bottomley 
379b0706762SJames Bottomley 	if (!seq && WARN(len > 127,
380b0706762SJames Bottomley 			 "BUG: recode sequence is too big (>127)"))
381b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
382b0706762SJames Bottomley 
383b0706762SJames Bottomley 	if (IS_ERR(data))
384b0706762SJames Bottomley 		return data;
385b0706762SJames Bottomley 
386b0706762SJames Bottomley 	if (!seq && len >= 0) {
387b0706762SJames Bottomley 		/*
388b0706762SJames Bottomley 		 * we're recoding, so move back to the start of the
389b0706762SJames Bottomley 		 * sequence and install a dummy length because the
390b0706762SJames Bottomley 		 * real length should be NULL
391b0706762SJames Bottomley 		 */
392b0706762SJames Bottomley 		data -= 2;
393b0706762SJames Bottomley 		data_len = 2;
394b0706762SJames Bottomley 	}
395b0706762SJames Bottomley 
396b0706762SJames Bottomley 	if (data_len < 2)
397b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
398b0706762SJames Bottomley 
399b0706762SJames Bottomley 	*(data++) = _tag(UNIV, CONS, SEQ);
400b0706762SJames Bottomley 	data_len--;
401b0706762SJames Bottomley 
402b0706762SJames Bottomley 	ret = asn1_encode_length(&data, &data_len, len);
403b0706762SJames Bottomley 	if (ret)
404b0706762SJames Bottomley 		return ERR_PTR(ret);
405b0706762SJames Bottomley 
406b0706762SJames Bottomley 	if (!seq)
407b0706762SJames Bottomley 		return data;
408b0706762SJames Bottomley 
409b0706762SJames Bottomley 	if (data_len < len)
410b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
411b0706762SJames Bottomley 
412b0706762SJames Bottomley 	memcpy(data, seq, len);
413b0706762SJames Bottomley 	data += len;
414b0706762SJames Bottomley 
415b0706762SJames Bottomley 	return data;
416b0706762SJames Bottomley }
417b0706762SJames Bottomley EXPORT_SYMBOL_GPL(asn1_encode_sequence);
418b0706762SJames Bottomley 
419b0706762SJames Bottomley /**
420b0706762SJames Bottomley  * asn1_encode_boolean() - encode a boolean value to ASN.1
421b0706762SJames Bottomley  * @data:	pointer to encode at
422b0706762SJames Bottomley  * @end_data:	end of data pointer, points one beyond last usable byte in @data
423b0706762SJames Bottomley  * @val:	the boolean true/false value
424b0706762SJames Bottomley  */
425b0706762SJames Bottomley unsigned char *
asn1_encode_boolean(unsigned char * data,const unsigned char * end_data,bool val)426b0706762SJames Bottomley asn1_encode_boolean(unsigned char *data, const unsigned char *end_data,
427b0706762SJames Bottomley 		    bool val)
428b0706762SJames Bottomley {
429b0706762SJames Bottomley 	int data_len = end_data - data;
430b0706762SJames Bottomley 
431b0706762SJames Bottomley 	if (IS_ERR(data))
432b0706762SJames Bottomley 		return data;
433b0706762SJames Bottomley 
434b0706762SJames Bottomley 	/* booleans are 3 bytes: tag, length == 1 and value == 0 or 1 */
435b0706762SJames Bottomley 	if (data_len < 3)
436b0706762SJames Bottomley 		return ERR_PTR(-EINVAL);
437b0706762SJames Bottomley 
438b0706762SJames Bottomley 	*(data++) = _tag(UNIV, PRIM, BOOL);
439b0706762SJames Bottomley 	data_len--;
440b0706762SJames Bottomley 
441b0706762SJames Bottomley 	asn1_encode_length(&data, &data_len, 1);
442b0706762SJames Bottomley 
443b0706762SJames Bottomley 	if (val)
444b0706762SJames Bottomley 		*(data++) = 1;
445b0706762SJames Bottomley 	else
446b0706762SJames Bottomley 		*(data++) = 0;
447b0706762SJames Bottomley 
448b0706762SJames Bottomley 	return data;
449b0706762SJames Bottomley }
450b0706762SJames Bottomley EXPORT_SYMBOL_GPL(asn1_encode_boolean);
451b0706762SJames Bottomley 
452b0706762SJames Bottomley MODULE_LICENSE("GPL");
453