1/* 2 * ASN.1 DER parsing 3 * Copyright (c) 2006, 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 14int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) 15{ 16 const u8 *pos, *end; 17 u8 tmp; 18 19 os_memset(hdr, 0, sizeof(*hdr)); 20 pos = buf; 21 end = buf + len; 22 23 hdr->identifier = *pos++; 24 hdr->class = hdr->identifier >> 6; 25 hdr->constructed = !!(hdr->identifier & (1 << 5)); 26 27 if ((hdr->identifier & 0x1f) == 0x1f) { 28 hdr->tag = 0; 29 do { 30 if (pos >= end) { 31 wpa_printf(MSG_DEBUG, "ASN.1: Identifier " 32 "underflow"); 33 return -1; 34 } 35 tmp = *pos++; 36 wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " 37 "0x%02x", tmp); 38 hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); 39 } while (tmp & 0x80); 40 } else 41 hdr->tag = hdr->identifier & 0x1f; 42 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 69 if (end < pos || hdr->length > (unsigned int) (end - pos)) { 70 wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); 71 return -1; 72 } 73 74 hdr->payload = pos; 75 return 0; 76} 77 78 79int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) 80{ 81 const u8 *pos, *end; 82 unsigned long val; 83 u8 tmp; 84 85 os_memset(oid, 0, sizeof(*oid)); 86 87 pos = buf; 88 end = buf + len; 89 90 while (pos < end) { 91 val = 0; 92 93 do { 94 if (pos >= end) 95 return -1; 96 tmp = *pos++; 97 val = (val << 7) | (tmp & 0x7f); 98 } while (tmp & 0x80); 99 100 if (oid->len >= ASN1_MAX_OID_LEN) { 101 wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); 102 return -1; 103 } 104 if (oid->len == 0) { 105 /* 106 * The first octet encodes the first two object 107 * identifier components in (X*40) + Y formula. 108 * X = 0..2. 109 */ 110 oid->oid[0] = val / 40; 111 if (oid->oid[0] > 2) 112 oid->oid[0] = 2; 113 oid->oid[1] = val - oid->oid[0] * 40; 114 oid->len = 2; 115 } else 116 oid->oid[oid->len++] = val; 117 } 118 119 return 0; 120} 121 122 123int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, 124 const u8 **next) 125{ 126 struct asn1_hdr hdr; 127 128 if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) 129 return -1; 130 131 if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { 132 wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " 133 "tag 0x%x", hdr.class, hdr.tag); 134 return -1; 135 } 136 137 *next = hdr.payload + hdr.length; 138 139 return asn1_parse_oid(hdr.payload, hdr.length, oid); 140} 141 142 143void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) 144{ 145 char *pos = buf; 146 size_t i; 147 int ret; 148 149 if (len == 0) 150 return; 151 152 buf[0] = '\0'; 153 154 for (i = 0; i < oid->len; i++) { 155 ret = os_snprintf(pos, buf + len - pos, 156 "%s%lu", 157 i == 0 ? "" : ".", oid->oid[i]); 158 if (ret < 0 || ret >= buf + len - pos) 159 break; 160 pos += ret; 161 } 162 buf[len - 1] = '\0'; 163} 164 165 166static u8 rotate_bits(u8 octet) 167{ 168 int i; 169 u8 res; 170 171 res = 0; 172 for (i = 0; i < 8; i++) { 173 res <<= 1; 174 if (octet & 1) 175 res |= 1; 176 octet >>= 1; 177 } 178 179 return res; 180} 181 182 183unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) 184{ 185 unsigned long val = 0; 186 const u8 *pos = buf; 187 188 /* BER requires that unused bits are zero, so we can ignore the number 189 * of unused bits */ 190 pos++; 191 192 if (len >= 2) 193 val |= rotate_bits(*pos++); 194 if (len >= 3) 195 val |= ((unsigned long) rotate_bits(*pos++)) << 8; 196 if (len >= 4) 197 val |= ((unsigned long) rotate_bits(*pos++)) << 16; 198 if (len >= 5) 199 val |= ((unsigned long) rotate_bits(*pos++)) << 24; 200 if (len >= 6) 201 wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " 202 "(BIT STRING length %lu)", 203 __func__, (unsigned long) len); 204 205 return val; 206} 207