18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ASN.1 DER parsing 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "asn1.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 tmp; 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(hdr, 0, sizeof(*hdr)); 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = buf + len; 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->identifier = *pos++; 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->class = hdr->identifier >> 6; 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->constructed = !!(hdr->identifier & (1 << 5)); 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((hdr->identifier & 0x1f) == 0x1f) { 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->tag = 0; 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt do { 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos >= end) { 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "ASN.1: Identifier " 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "underflow"); 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = *pos++; 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: " 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "0x%02x", tmp); 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->tag = (hdr->tag << 7) | (tmp & 0x7f); 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } while (tmp & 0x80); 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->tag = hdr->identifier & 0x1f; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = *pos++; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp & 0x80) { 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp == 0xff) { 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "ASN.1: Reserved length " 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "value 0xff used"); 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp &= 0x7f; /* number of subsequent octets */ 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->length = 0; 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (tmp > 4) { 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "ASN.1: Too long length field"); 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (tmp--) { 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos >= end) { 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "ASN.1: Length " 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "underflow"); 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->length = (hdr->length << 8) | *pos++; 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Short form - length 0..127 in one octet */ 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->length = tmp; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end < pos || hdr->length > (unsigned int) (end - pos)) { 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow"); 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr->payload = pos; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid) 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned long val; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 tmp; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(oid, 0, sizeof(*oid)); 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = buf + len; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val = 0; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt do { 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos >= end) 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt tmp = *pos++; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val = (val << 7) | (tmp & 0x7f); 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } while (tmp & 0x80); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oid->len >= ASN1_MAX_OID_LEN) { 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value"); 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oid->len == 0) { 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The first octet encodes the first two object 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * identifier components in (X*40) + Y formula. 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * X = 0..2. 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[0] = val / 40; 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oid->oid[0] > 2) 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[0] = 2; 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[1] = val - oid->oid[0] * 40; 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->len = 2; 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[oid->len++] = val; 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 **next) 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) { 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d " 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "tag 0x%x", hdr.class, hdr.tag); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *next = hdr.payload + hdr.length; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return asn1_parse_oid(hdr.payload, hdr.length, oid); 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *pos = buf; 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[0] = '\0'; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < oid->len; i++) { 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_snprintf(pos, buf + len - pos, 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%s%lu", 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt i == 0 ? "" : ".", oid->oid[i]); 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0 || ret >= buf + len - pos) 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += ret; 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[len - 1] = '\0'; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 rotate_bits(u8 octet) 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 res; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = 0; 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < 8; i++) { 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res <<= 1; 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (octet & 1) 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res |= 1; 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt octet >>= 1; 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned long val = 0; 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos = buf; 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* BER requires that unused bits are zero, so we can ignore the number 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of unused bits */ 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len >= 2) 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val |= rotate_bits(*pos++); 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len >= 3) 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val |= ((unsigned long) rotate_bits(*pos++)) << 8; 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len >= 4) 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val |= ((unsigned long) rotate_bits(*pos++)) << 16; 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len >= 5) 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val |= ((unsigned long) rotate_bits(*pos++)) << 24; 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len >= 6) 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored " 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(BIT STRING length %lu)", 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt __func__, (unsigned long) len); 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return val; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 207