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