$search
00001 /* 00002 * ASN.1 DER parsing 00003 * Copyright (c) 2006, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "asn1.h" 00019 00020 int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) 00021 { 00022 const u8 *pos, *end; 00023 u8 tmp; 00024 00025 os_memset(hdr, 0, sizeof(*hdr)); 00026 pos = buf; 00027 end = buf + len; 00028 00029 hdr->identifier = *pos++; 00030 hdr->class = hdr->identifier >> 6; 00031 hdr->constructed = !!(hdr->identifier & (1 << 5)); 00032 00033 if ((hdr->identifier & 0x1f) == 0x1f) { 00034 hdr->tag = 0; 00035 do { 00036 if (pos >= end) { 00037 wpa_printf(MSG_DEBUG, "ASN.1: Identifier " 00038 "underflow"); 00039 return -1; 00040 } 00041 tmp = *pos++; 00042 wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " 00043 "0x%02x", tmp); 00044 hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); 00045 } while (tmp & 0x80); 00046 } else 00047 hdr->tag = hdr->identifier & 0x1f; 00048 00049 tmp = *pos++; 00050 if (tmp & 0x80) { 00051 if (tmp == 0xff) { 00052 wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " 00053 "value 0xff used"); 00054 return -1; 00055 } 00056 tmp &= 0x7f; /* number of subsequent octets */ 00057 hdr->length = 0; 00058 if (tmp > 4) { 00059 wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); 00060 return -1; 00061 } 00062 while (tmp--) { 00063 if (pos >= end) { 00064 wpa_printf(MSG_DEBUG, "ASN.1: Length " 00065 "underflow"); 00066 return -1; 00067 } 00068 hdr->length = (hdr->length << 8) | *pos++; 00069 } 00070 } else { 00071 /* Short form - length 0..127 in one octet */ 00072 hdr->length = tmp; 00073 } 00074 00075 if (end < pos || hdr->length > (unsigned int) (end - pos)) { 00076 wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); 00077 return -1; 00078 } 00079 00080 hdr->payload = pos; 00081 return 0; 00082 } 00083 00084 00085 int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) 00086 { 00087 const u8 *pos, *end; 00088 unsigned long val; 00089 u8 tmp; 00090 00091 os_memset(oid, 0, sizeof(*oid)); 00092 00093 pos = buf; 00094 end = buf + len; 00095 00096 while (pos < end) { 00097 val = 0; 00098 00099 do { 00100 if (pos >= end) 00101 return -1; 00102 tmp = *pos++; 00103 val = (val << 7) | (tmp & 0x7f); 00104 } while (tmp & 0x80); 00105 00106 if (oid->len >= ASN1_MAX_OID_LEN) { 00107 wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); 00108 return -1; 00109 } 00110 if (oid->len == 0) { 00111 /* 00112 * The first octet encodes the first two object 00113 * identifier components in (X*40) + Y formula. 00114 * X = 0..2. 00115 */ 00116 oid->oid[0] = val / 40; 00117 if (oid->oid[0] > 2) 00118 oid->oid[0] = 2; 00119 oid->oid[1] = val - oid->oid[0] * 40; 00120 oid->len = 2; 00121 } else 00122 oid->oid[oid->len++] = val; 00123 } 00124 00125 return 0; 00126 } 00127 00128 00129 int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, 00130 const u8 **next) 00131 { 00132 struct asn1_hdr hdr; 00133 00134 if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) 00135 return -1; 00136 00137 if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { 00138 wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " 00139 "tag 0x%x", hdr.class, hdr.tag); 00140 return -1; 00141 } 00142 00143 *next = hdr.payload + hdr.length; 00144 00145 return asn1_parse_oid(hdr.payload, hdr.length, oid); 00146 } 00147 00148 00149 void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) 00150 { 00151 char *pos = buf; 00152 size_t i; 00153 int ret; 00154 00155 if (len == 0) 00156 return; 00157 00158 buf[0] = '\0'; 00159 00160 for (i = 0; i < oid->len; i++) { 00161 ret = os_snprintf(pos, buf + len - pos, 00162 "%s%lu", 00163 i == 0 ? "" : ".", oid->oid[i]); 00164 if (ret < 0 || ret >= buf + len - pos) 00165 break; 00166 pos += ret; 00167 } 00168 buf[len - 1] = '\0'; 00169 } 00170 00171 00172 static u8 rotate_bits(u8 octet) 00173 { 00174 int i; 00175 u8 res; 00176 00177 res = 0; 00178 for (i = 0; i < 8; i++) { 00179 res <<= 1; 00180 if (octet & 1) 00181 res |= 1; 00182 octet >>= 1; 00183 } 00184 00185 return res; 00186 } 00187 00188 00189 unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) 00190 { 00191 unsigned long val = 0; 00192 const u8 *pos = buf; 00193 00194 /* BER requires that unused bits are zero, so we can ignore the number 00195 * of unused bits */ 00196 pos++; 00197 00198 if (len >= 2) 00199 val |= rotate_bits(*pos++); 00200 if (len >= 3) 00201 val |= ((unsigned long) rotate_bits(*pos++)) << 8; 00202 if (len >= 4) 00203 val |= ((unsigned long) rotate_bits(*pos++)) << 16; 00204 if (len >= 5) 00205 val |= ((unsigned long) rotate_bits(*pos++)) << 24; 00206 if (len >= 6) 00207 wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " 00208 "(BIT STRING length %lu)", 00209 __func__, (unsigned long) len); 00210 00211 return val; 00212 }