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