asn1_encoder.c 10 KB

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