asn1.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * ASN.1 DER parsing
  3. * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #ifdef CONFIG_INTERNAL_X509
  17. #include "asn1.h"
  18. int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
  19. {
  20. const u8 *pos, *end;
  21. u8 tmp;
  22. os_memset(hdr, 0, sizeof(*hdr));
  23. pos = buf;
  24. end = buf + len;
  25. hdr->identifier = *pos++;
  26. hdr->class = hdr->identifier >> 6;
  27. hdr->constructed = !!(hdr->identifier & (1 << 5));
  28. if ((hdr->identifier & 0x1f) == 0x1f) {
  29. hdr->tag = 0;
  30. do {
  31. if (pos >= end) {
  32. wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
  33. "underflow");
  34. return -1;
  35. }
  36. tmp = *pos++;
  37. wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
  38. "0x%02x", tmp);
  39. hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
  40. } while (tmp & 0x80);
  41. } else
  42. hdr->tag = hdr->identifier & 0x1f;
  43. tmp = *pos++;
  44. if (tmp & 0x80) {
  45. if (tmp == 0xff) {
  46. wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
  47. "value 0xff used");
  48. return -1;
  49. }
  50. tmp &= 0x7f; /* number of subsequent octets */
  51. hdr->length = 0;
  52. if (tmp > 4) {
  53. wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
  54. return -1;
  55. }
  56. while (tmp--) {
  57. if (pos >= end) {
  58. wpa_printf(MSG_DEBUG, "ASN.1: Length "
  59. "underflow");
  60. return -1;
  61. }
  62. hdr->length = (hdr->length << 8) | *pos++;
  63. }
  64. } else {
  65. /* Short form - length 0..127 in one octet */
  66. hdr->length = tmp;
  67. }
  68. if (end < pos || hdr->length > (unsigned int) (end - pos)) {
  69. wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
  70. return -1;
  71. }
  72. hdr->payload = pos;
  73. return 0;
  74. }
  75. int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
  76. const u8 **next)
  77. {
  78. struct asn1_hdr hdr;
  79. const u8 *pos, *end;
  80. unsigned long val;
  81. u8 tmp;
  82. os_memset(oid, 0, sizeof(*oid));
  83. if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
  84. return -1;
  85. if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
  86. wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
  87. "tag 0x%x", hdr.class, hdr.tag);
  88. return -1;
  89. }
  90. pos = hdr.payload;
  91. end = hdr.payload + hdr.length;
  92. *next = end;
  93. while (pos < end) {
  94. val = 0;
  95. do {
  96. if (pos >= end)
  97. return -1;
  98. tmp = *pos++;
  99. val = (val << 7) | (tmp & 0x7f);
  100. } while (tmp & 0x80);
  101. if (oid->len >= ASN1_MAX_OID_LEN) {
  102. wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
  103. return -1;
  104. }
  105. if (oid->len == 0) {
  106. /*
  107. * The first octet encodes the first two object
  108. * identifier components in (X*40) + Y formula.
  109. * X = 0..2.
  110. */
  111. oid->oid[0] = val / 40;
  112. if (oid->oid[0] > 2)
  113. oid->oid[0] = 2;
  114. oid->oid[1] = val - oid->oid[0] * 40;
  115. oid->len = 2;
  116. } else
  117. oid->oid[oid->len++] = val;
  118. }
  119. return 0;
  120. }
  121. void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
  122. {
  123. char *pos = buf;
  124. size_t i;
  125. int ret;
  126. if (len == 0)
  127. return;
  128. buf[0] = '\0';
  129. for (i = 0; i < oid->len; i++) {
  130. ret = os_snprintf(pos, buf + len - pos,
  131. "%s%lu",
  132. i == 0 ? "" : ".", oid->oid[i]);
  133. if (ret < 0 || ret >= buf + len - pos)
  134. break;
  135. pos += ret;
  136. }
  137. buf[len - 1] = '\0';
  138. }
  139. static u8 rotate_bits(u8 octet)
  140. {
  141. int i;
  142. u8 res;
  143. res = 0;
  144. for (i = 0; i < 8; i++) {
  145. res <<= 1;
  146. if (octet & 1)
  147. res |= 1;
  148. octet >>= 1;
  149. }
  150. return res;
  151. }
  152. unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
  153. {
  154. unsigned long val = 0;
  155. const u8 *pos = buf;
  156. /* BER requires that unused bits are zero, so we can ignore the number
  157. * of unused bits */
  158. pos++;
  159. if (len >= 2)
  160. val |= rotate_bits(*pos++);
  161. if (len >= 3)
  162. val |= ((unsigned long) rotate_bits(*pos++)) << 8;
  163. if (len >= 4)
  164. val |= ((unsigned long) rotate_bits(*pos++)) << 16;
  165. if (len >= 5)
  166. val |= ((unsigned long) rotate_bits(*pos++)) << 24;
  167. if (len >= 6)
  168. wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
  169. "(BIT STRING length %lu)",
  170. __func__, (unsigned long) len);
  171. return val;
  172. }
  173. #endif /* CONFIG_INTERNAL_X509 */