1 /* 2 * ASN.1 DER parsing 3 * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 11 #include "common.h" 12 #include "asn1.h" 13 14 struct asn1_oid asn1_sha1_oid = { 15 .oid = { 1, 3, 14, 3, 2, 26 }, 16 .len = 6 17 }; 18 19 struct asn1_oid asn1_sha256_oid = { 20 .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }, 21 .len = 9 22 }; 23 24 25 static int asn1_valid_der_boolean(struct asn1_hdr *hdr) 26 { 27 /* Enforce DER requirements for a single way of encoding a BOOLEAN */ 28 if (hdr->length != 1) { 29 wpa_printf(MSG_DEBUG, "ASN.1: Unexpected BOOLEAN length (%u)", 30 hdr->length); 31 return 0; 32 } 33 34 if (hdr->payload[0] != 0 && hdr->payload[0] != 0xff) { 35 wpa_printf(MSG_DEBUG, 36 "ASN.1: Invalid BOOLEAN value 0x%x (DER requires 0 or 0xff)", 37 hdr->payload[0]); 38 return 0; 39 } 40 41 return 1; 42 } 43 44 45 static int asn1_valid_der(struct asn1_hdr *hdr) 46 { 47 if (hdr->class != ASN1_CLASS_UNIVERSAL) 48 return 1; 49 if (hdr->tag == ASN1_TAG_BOOLEAN && !asn1_valid_der_boolean(hdr)) 50 return 0; 51 return 1; 52 } 53 54 55 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) 56 { 57 const u8 *pos, *end; 58 u8 tmp; 59 60 os_memset(hdr, 0, sizeof(*hdr)); 61 pos = buf; 62 end = buf + len; 63 64 if (pos >= end) { 65 wpa_printf(MSG_DEBUG, "ASN.1: No room for Identifier"); 66 return -1; 67 } 68 hdr->identifier = *pos++; 69 hdr->class = hdr->identifier >> 6; 70 hdr->constructed = !!(hdr->identifier & (1 << 5)); 71 72 if ((hdr->identifier & 0x1f) == 0x1f) { 73 hdr->tag = 0; 74 do { 75 if (pos >= end) { 76 wpa_printf(MSG_DEBUG, "ASN.1: Identifier " 77 "underflow"); 78 return -1; 79 } 80 tmp = *pos++; 81 wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " 82 "0x%02x", tmp); 83 hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); 84 } while (tmp & 0x80); 85 } else 86 hdr->tag = hdr->identifier & 0x1f; 87 88 if (pos >= end) { 89 wpa_printf(MSG_DEBUG, "ASN.1: No room for Length"); 90 return -1; 91 } 92 tmp = *pos++; 93 if (tmp & 0x80) { 94 if (tmp == 0xff) { 95 wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " 96 "value 0xff used"); 97 return -1; 98 } 99 tmp &= 0x7f; /* number of subsequent octets */ 100 hdr->length = 0; 101 if (tmp > 4) { 102 wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); 103 return -1; 104 } 105 while (tmp--) { 106 if (pos >= end) { 107 wpa_printf(MSG_DEBUG, "ASN.1: Length " 108 "underflow"); 109 return -1; 110 } 111 hdr->length = (hdr->length << 8) | *pos++; 112 } 113 } else { 114 /* Short form - length 0..127 in one octet */ 115 hdr->length = tmp; 116 } 117 118 if (end < pos || hdr->length > (unsigned int) (end - pos)) { 119 wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); 120 return -1; 121 } 122 123 hdr->payload = pos; 124 125 return asn1_valid_der(hdr) ? 0 : -1; 126 } 127 128 129 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) 130 { 131 const u8 *pos, *end; 132 unsigned long val; 133 u8 tmp; 134 135 os_memset(oid, 0, sizeof(*oid)); 136 137 pos = buf; 138 end = buf + len; 139 140 while (pos < end) { 141 val = 0; 142 143 do { 144 if (pos >= end) 145 return -1; 146 tmp = *pos++; 147 val = (val << 7) | (tmp & 0x7f); 148 } while (tmp & 0x80); 149 150 if (oid->len >= ASN1_MAX_OID_LEN) { 151 wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); 152 return -1; 153 } 154 if (oid->len == 0) { 155 /* 156 * The first octet encodes the first two object 157 * identifier components in (X*40) + Y formula. 158 * X = 0..2. 159 */ 160 oid->oid[0] = val / 40; 161 if (oid->oid[0] > 2) 162 oid->oid[0] = 2; 163 oid->oid[1] = val - oid->oid[0] * 40; 164 oid->len = 2; 165 } else 166 oid->oid[oid->len++] = val; 167 } 168 169 return 0; 170 } 171 172 173 int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, 174 const u8 **next) 175 { 176 struct asn1_hdr hdr; 177 178 if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) 179 return -1; 180 181 if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { 182 wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " 183 "tag 0x%x", hdr.class, hdr.tag); 184 return -1; 185 } 186 187 *next = hdr.payload + hdr.length; 188 189 return asn1_parse_oid(hdr.payload, hdr.length, oid); 190 } 191 192 193 void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len) 194 { 195 char *pos = buf; 196 size_t i; 197 int ret; 198 199 if (len == 0) 200 return; 201 202 buf[0] = '\0'; 203 204 for (i = 0; i < oid->len; i++) { 205 ret = os_snprintf(pos, buf + len - pos, 206 "%s%lu", 207 i == 0 ? "" : ".", oid->oid[i]); 208 if (os_snprintf_error(buf + len - pos, ret)) 209 break; 210 pos += ret; 211 } 212 buf[len - 1] = '\0'; 213 } 214 215 216 static u8 rotate_bits(u8 octet) 217 { 218 int i; 219 u8 res; 220 221 res = 0; 222 for (i = 0; i < 8; i++) { 223 res <<= 1; 224 if (octet & 1) 225 res |= 1; 226 octet >>= 1; 227 } 228 229 return res; 230 } 231 232 233 unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) 234 { 235 unsigned long val = 0; 236 const u8 *pos = buf; 237 238 /* BER requires that unused bits are zero, so we can ignore the number 239 * of unused bits */ 240 pos++; 241 242 if (len >= 2) 243 val |= rotate_bits(*pos++); 244 if (len >= 3) 245 val |= ((unsigned long) rotate_bits(*pos++)) << 8; 246 if (len >= 4) 247 val |= ((unsigned long) rotate_bits(*pos++)) << 16; 248 if (len >= 5) 249 val |= ((unsigned long) rotate_bits(*pos++)) << 24; 250 if (len >= 6) 251 wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " 252 "(BIT STRING length %lu)", 253 __func__, (unsigned long) len); 254 255 return val; 256 } 257 258 259 int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b) 260 { 261 size_t i; 262 263 if (a->len != b->len) 264 return 0; 265 266 for (i = 0; i < a->len; i++) { 267 if (a->oid[i] != b->oid[i]) 268 return 0; 269 } 270 271 return 1; 272 } 273