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