x509v3.c revision c55524ad84d13014e8019491c2b17e5dcf13545a
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * X.509v3 certificate parsing and processing (RFC 3280 profile) 3c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify 68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation. 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license. 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details. 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "asn1.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "x509v3.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void x509_free_name(struct x509_name *name) 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < name->num_attr; i++) { 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->attr[i].value); 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->attr[i].value = NULL; 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->attr[i].type = X509_NAME_ATTR_NOT_USED; 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->num_attr = 0; 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->email); 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->email = NULL; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->alt_email); 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->dns); 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->uri); 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->ip); 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->alt_email = name->dns = name->uri = NULL; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->ip = NULL; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->ip_len = 0; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&name->rid, 0, sizeof(name->rid)); 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_free - Free an X.509 certificate 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert: Certificate to be freed 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid x509_certificate_free(struct x509_certificate *cert) 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert == NULL) 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->next) { 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p " 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "was still on a list (next=%p)\n", 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert, cert->next); 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(&cert->issuer); 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(&cert->subject); 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(cert->public_key); 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(cert->sign_value); 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(cert); 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_free - Free an X.509 certificate chain 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert: Pointer to the first certificate in the chain 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid x509_certificate_chain_free(struct x509_certificate *cert) 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *next; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (cert) { 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next = cert->next; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->next = NULL; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert = next; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_whitespace(char c) 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return c == ' ' || c == '\t'; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void x509_str_strip_whitespace(char *a) 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *ipos, *opos; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int remove_whitespace = 1; 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipos = opos = a; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*ipos) { 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (remove_whitespace && x509_whitespace(*ipos)) 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ipos++; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else { 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt remove_whitespace = x509_whitespace(*ipos); 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *opos++ = *ipos++; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *opos-- = '\0'; 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (opos > a && x509_whitespace(*opos)) 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *opos = '\0'; 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_str_compare(const char *a, const char *b) 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *aa, *bb; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!a && b) 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a && !b) 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!a && !b) 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt aa = os_strdup(a); 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt bb = os_strdup(b); 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (aa == NULL || bb == NULL) { 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(aa); 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(bb); 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return os_strcasecmp(a, b); 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_str_strip_whitespace(aa); 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_str_strip_whitespace(bb); 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_strcasecmp(aa, bb); 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(aa); 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(bb); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_name_compare - Compare X.509 certificate names 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @a: Certificate name 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @b: Certificate name 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: <0, 0, or >0 based on whether a is less than, equal to, or 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * greater than b 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint x509_name_compare(struct x509_name *a, struct x509_name *b) 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!a && b) 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a && !b) 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!a && !b) 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a->num_attr < b->num_attr) 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a->num_attr > b->num_attr) 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < a->num_attr; i++) { 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a->attr[i].type < b->attr[i].type) 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a->attr[i].type > b->attr[i].type) 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_str_compare(a->attr[i].value, b->attr[i].value); 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res) 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_str_compare(a->email, b->email); 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res) 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_algorithm_identifier( 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *buf, size_t len, 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_algorithm_identifier *id, const u8 **next) 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AlgorithmIdentifier ::= SEQUENCE { 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * algorithm OBJECT IDENTIFIER, 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * parameters ANY DEFINED BY algorithm OPTIONAL 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(AlgorithmIdentifier) - found class %d tag 0x%x", 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + hdr.length; 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end > buf + len) 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *next = end; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_oid(pos, end - pos, &id->oid, &pos)) 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: optional parameters */ 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_public_key(const u8 *buf, size_t len, 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *cert, 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 **next) 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * SubjectPublicKeyInfo ::= SEQUENCE { 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * algorithm AlgorithmIdentifier, 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * subjectPublicKey BIT STRING 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = buf + len; 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(SubjectPublicKeyInfo) - found class %d tag 0x%x", 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + hdr.length > end) 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + hdr.length; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *next = end; 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_algorithm_identifier(pos, end - pos, 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &cert->public_key_alg, &pos)) 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_BITSTRING) { 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(subjectPublicKey) - found class %d tag 0x%x", 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length < 1) 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*pos) { 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos); 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * TODO: should this be rejected? X.509 certificates are 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * unlikely to use such a construction. Now we would end up 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * including the extra bits in the buffer which may also be 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ok. 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(cert->public_key); 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->public_key = os_malloc(hdr.length - 1); 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->public_key == NULL) { 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "public key"); 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(cert->public_key, pos + 1, hdr.length - 1); 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->public_key_len = hdr.length - 1; 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey", 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->public_key, cert->public_key_len); 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 **next) 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_oid oid; 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *val; 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Name ::= CHOICE { RDNSequence } 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AttributeTypeAndValue ::= SEQUENCE { 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * type AttributeType, 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * value AttributeValue 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AttributeType ::= OBJECT IDENTIFIER 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AttributeValue ::= ANY DEFINED BY AttributeType 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(Name / RDNSequencer) - found class %d tag 0x%x", 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + hdr.length > buf + len) 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = *next = pos + hdr.length; 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum x509_name_attr_type type; 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SET) { 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SET " 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(RelativeDistinguishedName) - found class " 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d tag 0x%x", hdr.class, hdr.tag); 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt set_pos = hdr.payload; 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = set_end = hdr.payload + hdr.length; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 || 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(AttributeTypeAndValue) - found class %d " 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "tag 0x%x", hdr.class, hdr.tag); 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt seq_pos = hdr.payload; 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt seq_end = hdr.payload + hdr.length; 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) { 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 || 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL) { 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse " 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "AttributeValue"); 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* RFC 3280: 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MUST: country, organization, organizational-unit, 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * distinguished name qualifier, state or province name, 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * common name, serial number. 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * SHOULD: locality, title, surname, given name, initials, 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pseudonym, generation qualifier. 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MUST: domainComponent (RFC 2247). 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_NOT_USED; 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (oid.len == 4 && 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) { 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* id-at ::= 2.5.4 */ 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (oid.oid[3]) { 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 3: 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* commonName */ 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_CN; 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 6: 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* countryName */ 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_C; 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 7: 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* localityName */ 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_L; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 8: 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* stateOrProvinceName */ 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_ST; 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 10: 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* organizationName */ 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_O; 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 11: 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* organizationalUnitName */ 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_OU; 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (oid.len == 7 && 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[0] == 1 && oid.oid[1] == 2 && 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[2] == 840 && oid.oid[3] == 113549 && 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[4] == 1 && oid.oid[5] == 9 && 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[6] == 1) { 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1.2.840.113549.1.9.1 - e-mailAddress */ 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->email); 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->email = os_malloc(hdr.length + 1); 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (name->email == NULL) { 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(name->email, hdr.payload, hdr.length); 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->email[hdr.length] = '\0'; 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (oid.len == 7 && 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[0] == 0 && oid.oid[1] == 9 && 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[2] == 2342 && oid.oid[3] == 19200300 && 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[4] == 100 && oid.oid[5] == 1 && 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.oid[6] == 25) { 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 0.9.2342.19200300.100.1.25 - domainComponent */ 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt type = X509_NAME_ATTR_DC; 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (type == X509_NAME_ATTR_NOT_USED) { 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID", 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (u8 *) oid.oid, 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid.len * sizeof(oid.oid[0])); 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data", 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.payload, hdr.length); 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (name->num_attr == X509_MAX_NAME_ATTRIBUTES) { 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Too many Name attributes"); 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val = os_malloc(hdr.length + 1); 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (val == NULL) { 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(val, hdr.payload, hdr.length); 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val[hdr.length] = '\0'; 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strlen(val) != hdr.length) { 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Reject certificate with " 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "embedded NUL byte in a string (%s[NUL])", 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt val); 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_free_name(name); 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->attr[name->num_attr].type = type; 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->attr[name->num_attr].value = val; 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->num_attr++; 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic char * x509_name_attr_str(enum x509_name_attr_type type) 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (type) { 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_NOT_USED: 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "[N/A]"; 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_DC: 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "DC"; 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_CN: 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "CN"; 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_C: 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "C"; 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_L: 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "L"; 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_ST: 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "ST"; 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_O: 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "O"; 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case X509_NAME_ATTR_OU: 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "OU"; 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return "?"; 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_name_string - Convert an X.509 certificate name into a string 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @name: Name to convert 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Buffer for the string 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Maximum buffer length 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid x509_name_string(struct x509_name *name, char *buf, size_t len) 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *pos, *end; 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len == 0) 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = buf + len; 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < name->num_attr; i++) { 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_snprintf(pos, end - pos, "%s=%s, ", 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_name_attr_str(name->attr[i].type), 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->attr[i].value); 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0 || ret >= end - pos) 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto done; 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += ret; 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') { 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos--; 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos = '\0'; 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos--; 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos = '\0'; 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (name->email) { 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = os_snprintf(pos, end - pos, "/emailAddress=%s", 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->email); 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret < 0 || ret >= end - pos) 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto done; 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += ret; 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtdone: 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end[-1] = '\0'; 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_time_t *val) 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *pos; 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int year, month, day, hour, min, sec; 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Time ::= CHOICE { 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * utcTime UTCTime, 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * generalTime GeneralizedTime 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * UTCTime: YYMMDDHHMMSSZ 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * GeneralizedTime: YYYYMMDDHHMMSSZ 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = (const char *) buf; 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (asn1_tag) { 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ASN1_TAG_UTCTIME: 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len != 13 || buf[12] != 'Z') { 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "UTCTime format", buf, len); 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sscanf(pos, "%02d", &year) != 1) { 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "UTCTime year", buf, len); 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (year < 50) 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt year += 2000; 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt year += 1900; 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ASN1_TAG_GENERALIZEDTIME: 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len != 15 || buf[14] != 'Z') { 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "GeneralizedTime format", buf, len); 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sscanf(pos, "%04d", &year) != 1) { 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "GeneralizedTime year", buf, len); 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 4; 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or " 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "GeneralizedTime - found tag 0x%x", asn1_tag); 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sscanf(pos, "%02d", &month) != 1) { 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(month)", buf, len); 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sscanf(pos, "%02d", &day) != 1) { 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(day)", buf, len); 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sscanf(pos, "%02d", &hour) != 1) { 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(hour)", buf, len); 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sscanf(pos, "%02d", &min) != 1) { 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(min)", buf, len); 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos += 2; 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sscanf(pos, "%02d", &sec) != 1) { 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(sec)", buf, len); 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_mktime(year, month, day, hour, min, sec, val) < 0) { 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time", 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, len); 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (year < 1970) { 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * At least some test certificates have been configured 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to use dates prior to 1970. Set the date to 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * beginning of 1970 to handle these case. 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - " 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "assume epoch as the time", year); 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *val = 0; 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_validity(const u8 *buf, size_t len, 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *cert, const u8 **next) 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos; 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t plen; 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Validity ::= SEQUENCE { 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * notBefore Time, 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * notAfter Time 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * RFC 3280, 4.1.2.5: 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * CAs conforming to this profile MUST always encode certificate 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * validity dates through the year 2049 as UTCTime; certificate 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * validity dates in 2050 or later MUST be encoded as GeneralizedTime. 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(Validity) - found class %d tag 0x%x", 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = hdr.length; 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + plen > buf + len) 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *next = pos + plen; 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, plen, &hdr) < 0 || 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_parse_time(hdr.payload, hdr.length, hdr.tag, 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &cert->not_before) < 0) { 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore " 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Time", hdr.payload, hdr.length); 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload + hdr.length; 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt plen = *next - pos; 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, plen, &hdr) < 0 || 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_parse_time(hdr.payload, hdr.length, hdr.tag, 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &cert->not_after) < 0) { 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter " 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Time", hdr.payload, hdr.length); 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu", 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) cert->not_before, 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (unsigned long) cert->not_after); 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_id_ce_oid(struct asn1_oid *oid) 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* id-ce arc from X.509 for standard X.509v3 extensions */ 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return oid->len >= 4 && 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[0] == 2 /* joint-iso-ccitt */ && 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[1] == 5 /* ds */ && 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[2] == 29 /* id-ce */; 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_ext_key_usage(struct x509_certificate *cert, 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * KeyUsage ::= BIT STRING { 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * digitalSignature (0), 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * nonRepudiation (1), 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * keyEncipherment (2), 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * dataEncipherment (3), 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * keyAgreement (4), 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * keyCertSign (5), 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * cRLSign (6), 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * encipherOnly (7), 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * decipherOnly (8) } 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_BITSTRING || 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length < 1) { 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in " 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "KeyUsage; found %d tag 0x%x len %d", 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag, hdr.length); 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->extensions_present |= X509_EXT_KEY_USAGE; 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length); 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage); 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_ext_basic_constraints(struct x509_certificate *cert, 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned long value; 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left; 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * BasicConstraints ::= SEQUENCE { 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * cA BOOLEAN DEFAULT FALSE, 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * pathLenConstraint INTEGER (0..MAX) OPTIONAL } 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "BasicConstraints; found %d tag 0x%x", 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS; 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length == 0) 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 || 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL) { 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse " 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "BasicConstraints"); 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.tag == ASN1_TAG_BOOLEAN) { 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length != 1) { 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected " 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Boolean length (%u) in BasicConstraints", 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->ca = hdr.payload[0]; 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.payload + hdr.length == pos + len) { 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d", 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->ca); 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length, 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &hdr) < 0 || 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL) { 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse " 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "BasicConstraints"); 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.tag != ASN1_TAG_INTEGER) { 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in " 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "BasicConstraints; found class %d tag 0x%x", 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = hdr.length; 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt value = 0; 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left) { 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt value <<= 8; 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt value |= *pos++; 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left--; 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->path_len_constraint = value; 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT; 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d " 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "pathLenConstraint=%lu", 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->ca, cert->path_len_constraint); 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_alt_name_rfc8222(struct x509_name *name, 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* rfc822Name IA5String */ 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len); 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->alt_email); 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->alt_email = os_zalloc(len + 1); 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (name->alt_email == NULL) 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(name->alt_email, pos, len); 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strlen(name->alt_email) != len) { 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Reject certificate with " 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "embedded NUL byte in rfc822Name (%s[NUL])", 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->alt_email); 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->alt_email); 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->alt_email = NULL; 8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_alt_name_dns(struct x509_name *name, 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* dNSName IA5String */ 8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len); 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->dns); 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->dns = os_zalloc(len + 1); 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (name->dns == NULL) 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(name->dns, pos, len); 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strlen(name->dns) != len) { 8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Reject certificate with " 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "embedded NUL byte in dNSName (%s[NUL])", 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->dns); 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->dns); 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->dns = NULL; 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_alt_name_uri(struct x509_name *name, 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* uniformResourceIdentifier IA5String */ 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "X509: altName - uniformResourceIdentifier", 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, len); 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->uri); 9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->uri = os_zalloc(len + 1); 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (name->uri == NULL) 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(name->uri, pos, len); 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strlen(name->uri) != len) { 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Reject certificate with " 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "embedded NUL byte in uniformResourceIdentifier " 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(%s[NUL])", name->uri); 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->uri); 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->uri = NULL; 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_alt_name_ip(struct x509_name *name, 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* iPAddress OCTET STRING */ 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len); 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(name->ip); 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->ip = os_malloc(len); 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (name->ip == NULL) 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(name->ip, pos, len); 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt name->ip_len = len; 9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_alt_name_rid(struct x509_name *name, 9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[80]; 9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* registeredID OBJECT IDENTIFIER */ 9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_parse_oid(pos, len, &name->rid) < 0) 9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt asn1_oid_to_str(&name->rid, buf, sizeof(buf)); 9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf); 9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_ext_alt_name(struct x509_name *name, 9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *p, *end; 9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * GeneralName ::= CHOICE { 9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * otherName [0] OtherName, 9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * rfc822Name [1] IA5String, 9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * dNSName [2] IA5String, 9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x400Address [3] ORAddress, 9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * directoryName [4] Name, 9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ediPartyName [5] EDIPartyName, 9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * uniformResourceIdentifier [6] IA5String, 9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * iPAddress [7] OCTET STRING, 9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * registeredID [8] OBJECT IDENTIFIER } 9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * OtherName ::= SEQUENCE { 9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * type-id OBJECT IDENTIFIER, 9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * value [0] EXPLICIT ANY DEFINED BY type-id } 9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EDIPartyName ::= SEQUENCE { 9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * nameAssigner [0] DirectoryString OPTIONAL, 9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * partyName [1] DirectoryString } 9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) { 9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int res; 9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(p, end - p, &hdr) < 0) { 9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse " 9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "SubjectAltName item"); 9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) 9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (hdr.tag) { 9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 1: 9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_parse_alt_name_rfc8222(name, hdr.payload, 9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 2: 9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_parse_alt_name_dns(name, hdr.payload, 10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 6: 10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_parse_alt_name_uri(name, hdr.payload, 10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 7: 10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_parse_alt_name_ip(name, hdr.payload, 10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 8: 10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_parse_alt_name_rid(name, hdr.payload, 10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 0: /* TODO: otherName */ 10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 3: /* TODO: x500Address */ 10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 4: /* TODO: directoryName */ 10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 5: /* TODO: ediPartyName */ 10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = 0; 10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res < 0) 10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_ext_subject_alt_name(struct x509_certificate *cert, 10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* SubjectAltName ::= GeneralNames */ 10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " 10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "SubjectAltName; found %d tag 0x%x", 10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: SubjectAltName"); 10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME; 10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length == 0) 10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return x509_parse_ext_alt_name(&cert->subject, hdr.payload, 10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert, 10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* IssuerAltName ::= GeneralNames */ 10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " 10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "IssuerAltName; found %d tag 0x%x", 10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: IssuerAltName"); 10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME; 10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length == 0) 10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return x509_parse_ext_alt_name(&cert->issuer, hdr.payload, 10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.length); 10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_extension_data(struct x509_certificate *cert, 10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_oid *oid, 10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!x509_id_ce_oid(oid)) 10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: add other extensions required by RFC 3280, Ch 4.2: 10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * certificate policies (section 4.2.1.5) 10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * name constraints (section 4.2.1.11) 10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * policy constraints (section 4.2.1.12) 10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * extended key usage (section 4.2.1.13) 10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * inhibit any-policy (section 4.2.1.15) 10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (oid->oid[3]) { 10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 15: /* id-ce-keyUsage */ 11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return x509_parse_ext_key_usage(cert, pos, len); 11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 17: /* id-ce-subjectAltName */ 11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return x509_parse_ext_subject_alt_name(cert, pos, len); 11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 18: /* id-ce-issuerAltName */ 11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return x509_parse_ext_issuer_alt_name(cert, pos, len); 11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 19: /* id-ce-basicConstraints */ 11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return x509_parse_ext_basic_constraints(cert, pos, len); 11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_extension(struct x509_certificate *cert, 11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len, const u8 **next) 11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *end; 11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_oid oid; 11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int critical_ext = 0, res; 11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[80]; 11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Extension ::= SEQUENCE { 11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * extnID OBJECT IDENTIFIER, 11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * critical BOOLEAN DEFAULT FALSE, 11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * extnValue OCTET STRING 11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " 11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Extensions: class %d tag 0x%x; expected SEQUENCE", 11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *next = end = pos + hdr.length; 11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) { 11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for " 11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Extension (expected OID)"); 11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hdr.tag != ASN1_TAG_BOOLEAN && 11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_OCTETSTRING)) { 11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " 11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Extensions: class %d tag 0x%x; expected BOOLEAN " 11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "or OCTET STRING", hdr.class, hdr.tag); 11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.tag == ASN1_TAG_BOOLEAN) { 11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length != 1) { 11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected " 11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Boolean length (%u)", hdr.length); 11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt critical_ext = hdr.payload[0]; 11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (hdr.class != ASN1_CLASS_UNIVERSAL && 11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_PRIVATE) || 11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_OCTETSTRING) { 11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header " 11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "in Extensions: class %d tag 0x%x; " 11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "expected OCTET STRING", 11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt asn1_oid_to_str(&oid, buf, sizeof(buf)); 11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d", 11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf, critical_ext); 11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length); 11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length); 11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res < 0) 11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return res; 11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (res == 1 && critical_ext) { 11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Unknown critical extension %s", 11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf); 11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_extensions(struct x509_certificate *cert, 11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, size_t len) 11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *end; 11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */ 12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data " 12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for Extensions: class %d tag 0x%x; " 12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "expected SEQUENCE", hdr.class, hdr.tag); 12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + hdr.length; 12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (pos < end) { 12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_extension(cert, pos, end - pos, &pos) 12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt < 0) 12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_parse_tbs_certificate(const u8 *buf, size_t len, 12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *cert, 12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 **next) 12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end; 12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t left; 12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char sbuf[128]; 12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned long value; 12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* tbsCertificate TBSCertificate ::= SEQUENCE */ 12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start " 12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "with a valid SEQUENCE - found class %d tag 0x%x", 12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = *next = pos + hdr.length; 12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * version [0] EXPLICIT Version DEFAULT v1 12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Version ::= INTEGER { v1(0), v2(1), v3(2) } 12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0) 12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) { 12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0) 12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.class != ASN1_CLASS_UNIVERSAL || 12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_INTEGER) { 12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " 12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "version field - found class %d tag 0x%x", 12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length != 1) { 12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected version field " 12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "length %u (expected 1)", hdr.length); 12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = hdr.length; 12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt value = 0; 12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left) { 12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt value <<= 8; 12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt value |= *pos++; 12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left--; 12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->version = value; 12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->version != X509_CERT_V1 && 12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->version != X509_CERT_V2 && 12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->version != X509_CERT_V3) { 12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unsupported version %d", 12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->version + 1); 12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0) 12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->version = X509_CERT_V1; 12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1); 12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* serialNumber CertificateSerialNumber ::= INTEGER */ 12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.class != ASN1_CLASS_UNIVERSAL || 12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_INTEGER) { 12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " 12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "serialNumber; class=%d tag=0x%x", 13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left = hdr.length; 13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (left) { 13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->serial_number <<= 8; 13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->serial_number |= *pos++; 13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt left--; 13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number); 13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* signature AlgorithmIdentifier */ 13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature, 13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &pos)) 13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* issuer Name */ 13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_name(pos, end - pos, &cert->issuer, &pos)) 13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_name_string(&cert->issuer, sbuf, sizeof(sbuf)); 13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf); 13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* validity Validity */ 13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_validity(pos, end - pos, cert, &pos)) 13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* subject Name */ 13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_name(pos, end - pos, &cert->subject, &pos)) 13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_name_string(&cert->subject, sbuf, sizeof(sbuf)); 13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf); 13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* subjectPublicKeyInfo SubjectPublicKeyInfo */ 13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_public_key(pos, end - pos, cert, &pos)) 13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == end) 13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->version == X509_CERT_V1) 13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { 13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" 13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " tag to parse optional tbsCertificate " 13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "field(s); parsed class %d tag 0x%x", 13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.tag == 1) { 13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */ 13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: issuerUniqueID"); 13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: parse UniqueIdentifier ::= BIT STRING */ 13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.payload + hdr.length == end) 13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { 13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" 13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " tag to parse optional tbsCertificate " 13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "field(s); parsed class %d tag 0x%x", 13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.tag == 2) { 13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */ 13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: subjectUniqueID"); 13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: parse UniqueIdentifier ::= BIT STRING */ 13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.payload + hdr.length == end) 13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { 13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" 13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " tag to parse optional tbsCertificate " 13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "field(s); parsed class %d tag 0x%x", 13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.tag != 3) { 13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Ignored unexpected " 13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Context-Specific tag %d in optional " 13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "tbsCertificate fields", hdr.tag); 13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* extensions [3] EXPLICIT Extensions OPTIONAL */ 13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->version != X509_CERT_V3) { 13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and " 14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "Extensions data which are only allowed for " 14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "version 3", cert->version + 1); 14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0) 14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload + hdr.length; 14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos < end) { 14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, 14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "X509: Ignored extra tbsCertificate data", 14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, end - pos); 14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_rsadsi_oid(struct asn1_oid *oid) 14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return oid->len >= 4 && 14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[0] == 1 /* iso */ && 14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[1] == 2 /* member-body */ && 14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[2] == 840 /* us */ && 14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[3] == 113549 /* rsadsi */; 14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_pkcs_oid(struct asn1_oid *oid) 14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return oid->len >= 5 && 14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_rsadsi_oid(oid) && 14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[4] == 1 /* pkcs */; 14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_digest_oid(struct asn1_oid *oid) 14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return oid->len >= 5 && 14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_rsadsi_oid(oid) && 14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[4] == 2 /* digestAlgorithm */; 14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_sha1_oid(struct asn1_oid *oid) 14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return oid->len == 6 && 14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[0] == 1 /* iso */ && 14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[1] == 3 /* identified-organization */ && 14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[2] == 14 /* oiw */ && 14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[3] == 3 /* secsig */ && 14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[4] == 2 /* algorithms */ && 14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[5] == 26 /* id-sha1 */; 14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_sha256_oid(struct asn1_oid *oid) 14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return oid->len == 9 && 14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[0] == 2 /* joint-iso-itu-t */ && 14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[1] == 16 /* country */ && 14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[2] == 840 /* us */ && 14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[3] == 1 /* organization */ && 14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[4] == 101 /* gov */ && 14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[5] == 3 /* csor */ && 14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[6] == 4 /* nistAlgorithm */ && 14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[7] == 2 /* hashAlgs */ && 14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt oid->oid[8] == 1 /* sha256 */; 14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_parse - Parse a X.509 certificate in DER format 14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Pointer to the X.509 certificate in DER format 14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Buffer length 14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to the parsed certificate or %NULL on failure 14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Caller is responsible for freeing the returned certificate by calling 14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_free(). 14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len) 14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end, *hash_start; 14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *cert; 14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert = os_zalloc(sizeof(*cert) + len); 14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert == NULL) 14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(cert + 1, buf, len); 14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->cert_start = (u8 *) (cert + 1); 14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->cert_len = len; 14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = buf; 14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = buf + len; 14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */ 14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Certificate ::= SEQUENCE */ 15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 15018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 15028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 15038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate did not start with " 15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "a valid SEQUENCE - found class %d tag 0x%x", 15058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 15068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + hdr.length > end) { 15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos + hdr.length < end) { 15178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER " 15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "encoded certificate", 15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos + hdr.length, end - pos + hdr.length); 15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + hdr.length; 15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash_start = pos; 15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->tbs_cert_start = cert->cert_start + (hash_start - buf); 15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) { 15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->tbs_cert_len = pos - hash_start; 15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* signatureAlgorithm AlgorithmIdentifier */ 15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_parse_algorithm_identifier(pos, end - pos, 15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &cert->signature_alg, &pos)) { 15348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* signatureValue BIT STRING */ 15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_BITSTRING) { 15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " 15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(signatureValue) - found class %d tag 0x%x", 15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length < 1) { 15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*pos) { 15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", 15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos); 15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* PKCS #1 v1.5 10.2.1: 15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * It is an error if the length in bits of the signature S is 15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * not a multiple of eight. 15598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 15608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(cert->sign_value); 15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->sign_value = os_malloc(hdr.length - 1); 15658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->sign_value == NULL) { 15668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " 15678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "signatureValue"); 15688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_certificate_free(cert); 15698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 15708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 15718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(cert->sign_value, pos + 1, hdr.length - 1); 15728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->sign_value_len = hdr.length - 1; 15738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: signature", 15748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->sign_value, cert->sign_value_len); 15758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return cert; 15778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 15788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 15818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_check_signature - Verify certificate signature 15828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @issuer: Issuer certificate 15838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert: Certificate to be verified 15848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 if cert has a valid signature that was signed by the issuer, 15858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -1 if not 15868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 15878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint x509_certificate_check_signature(struct x509_certificate *issuer, 15888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *cert) 15898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 15908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct crypto_public_key *pk; 15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *data; 15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *end, *next, *da_end; 15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t data_len; 15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_hdr hdr; 15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct asn1_oid oid; 15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 hash[32]; 15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t hash_len; 15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!x509_pkcs_oid(&cert->signature.oid) || 16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->signature.oid.len != 7 || 16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->signature.oid.oid[5] != 1 /* pkcs-1 */) { 16028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unrecognized signature " 16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "algorithm"); 16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pk = crypto_public_key_import(issuer->public_key, 16088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt issuer->public_key_len); 16098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pk == NULL) 16108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data_len = cert->sign_value_len; 16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_malloc(data_len); 16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) { 16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt crypto_public_key_free(pk); 16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value, 16208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->sign_value_len, data, 16218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &data_len) < 0) { 16228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature"); 16238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt crypto_public_key_free(pk); 16248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 16258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt crypto_public_key_free(pk); 16288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len); 16308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 16328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * PKCS #1 v1.5, 10.1.2: 16338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 16348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * DigestInfo ::= SEQUENCE { 16358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * digestAlgorithm DigestAlgorithmIdentifier, 16368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * digest Digest 16378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 16388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 16398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * DigestAlgorithmIdentifier ::= AlgorithmIdentifier 16408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 16418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Digest ::= OCTET STRING 16428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 16438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 16448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(data, data_len, &hdr) < 0 || 16458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 16468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 16478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 16488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(DigestInfo) - found class %d tag 0x%x", 16498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 16508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 16518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = hdr.payload; 16558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = pos + hdr.length; 16568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 16588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * X.509: 16598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AlgorithmIdentifier ::= SEQUENCE { 16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * algorithm OBJECT IDENTIFIER, 16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * parameters ANY DEFINED BY algorithm OPTIONAL 16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * } 16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 16668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(AlgorithmIdentifier) - found class %d tag 0x%x", 16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt da_end = hdr.payload + hdr.length; 16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { 16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm"); 16788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_sha1_oid(&oid)) { 16838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->signature.oid.oid[6] != 16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5 /* sha-1WithRSAEncryption */) { 16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 " 16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "does not match with certificate " 16878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "signatureAlgorithm (%lu)", 16888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->signature.oid.oid[6]); 16898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 16908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 16918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto skip_digest_oid; 16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_sha256_oid(&oid)) { 16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->signature.oid.oid[6] != 16978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 11 /* sha2561WithRSAEncryption */) { 16988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 " 16998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "does not match with certificate " 17008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "signatureAlgorithm (%lu)", 17018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->signature.oid.oid[6]); 17028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 17048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto skip_digest_oid; 17068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!x509_digest_oid(&oid)) { 17098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm"); 17108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 17128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (oid.oid[5]) { 17148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 5: /* md5 */ 17158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */) 17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 17178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does " 17188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "not match with certificate " 17198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "signatureAlgorithm (%lu)", 17208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->signature.oid.oid[6]); 17218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 17238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 17258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 2: /* md2 */ 17268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 4: /* md4 */ 17278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 17288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm " 17298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(%lu)", oid.oid[5]); 17308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 17328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtskip_digest_oid: 17358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Digest ::= OCTET STRING */ 17368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = da_end; 17378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end = data + data_len; 17388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 17408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 17418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.tag != ASN1_TAG_OCTETSTRING) { 17428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING " 17438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(Digest) - found class %d tag 0x%x", 17448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.class, hdr.tag); 17458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 17478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest", 17498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hdr.payload, hdr.length); 17508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (cert->signature.oid.oid[6]) { 17528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 4: /* md5WithRSAEncryption */ 17538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, 17548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash); 17558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash_len = 16; 17568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)", 17578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash, hash_len); 17588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 17598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 5: /* sha-1WithRSAEncryption */ 17608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, 17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash); 17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash_len = 20; 17638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)", 17648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash, hash_len); 17658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 17668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 11: /* sha256WithRSAEncryption */ 17678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, 17688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash); 17698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash_len = 32; 17708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", 17718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash, hash_len); 17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 2: /* md2WithRSAEncryption */ 17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 12: /* sha384WithRSAEncryption */ 17758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 13: /* sha512WithRSAEncryption */ 17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 17778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Unsupported certificate signature " 17788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "algorithm (%lu)", cert->signature.oid.oid[6]); 17798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 17818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hdr.length != hash_len || 17848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(hdr.payload, hash, hdr.length) != 0) { 17858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Certificate Digest does not match " 17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "with calculated tbsCertificate hash"); 17878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(data); 17928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with " 17948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "calculated tbsCertificate hash"); 17958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 17978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 17998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int x509_valid_issuer(const struct x509_certificate *cert) 18018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 18028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) && 18038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !cert->ca) { 18048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an " 18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "issuer"); 18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 18088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->version == X509_CERT_V3 && 18108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) { 18118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not " 18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "include BasicConstraints extension"); 18138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 18148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 18158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((cert->extensions_present & X509_EXT_KEY_USAGE) && 18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) { 18188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have " 18198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "keyCertSign bit in Key Usage"); 18208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 18218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 18228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 18258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 18288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_chain_validate - Validate X.509 certificate chain 18298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @trusted: List of trusted certificates 18308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @chain: Certificate chain to be validated (first chain must be issued by 18318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * signed by the second certificate in the chain and so on) 18328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @reason: Buffer for returning failure reason (X509_VALIDATE_*) 18338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 if chain is valid, -1 if not 18348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 18358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint x509_certificate_chain_validate(struct x509_certificate *trusted, 18368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *chain, 1837c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt int *reason, int disable_time_checks) 18388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 18398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt long unsigned idx; 18408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int chain_trusted = 0; 18418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *cert, *trust; 18428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[128]; 18438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time now; 18448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_OK; 18468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Validate certificate chain"); 18488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&now); 18498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (cert = chain, idx = 0; cert; cert = cert->next, idx++) { 18518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_name_string(&cert->subject, buf, sizeof(buf)); 18528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf); 18538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (chain_trusted) 18558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 18568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1857c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt if (!disable_time_checks && 1858c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt ((unsigned long) now.sec < 1859c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt (unsigned long) cert->not_before || 1860c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt (unsigned long) now.sec > 1861c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt (unsigned long) cert->not_after)) { 18628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "X509: Certificate not valid " 18638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(now=%lu not_before=%lu not_after=%lu)", 18648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt now.sec, cert->not_before, cert->not_after); 18658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_CERTIFICATE_EXPIRED; 18668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 18678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 18688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (cert->next) { 18708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_name_compare(&cert->issuer, 18718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &cert->next->subject) != 0) { 18728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate " 18738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "chain issuer name mismatch"); 18748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_name_string(&cert->issuer, buf, 18758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(buf)); 18768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: cert issuer: %s", 18778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf); 18788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt x509_name_string(&cert->next->subject, buf, 18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(buf)); 18808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: next cert " 18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "subject: %s", buf); 18828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN; 18838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 18848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 18858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_valid_issuer(cert->next) < 0) { 18878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 18898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 18908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 18918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((cert->next->extensions_present & 18928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt X509_EXT_PATH_LEN_CONSTRAINT) && 18938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt idx > cert->next->path_len_constraint) { 18948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: pathLenConstraint" 18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " not met (idx=%lu issuer " 18968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "pathLenConstraint=%lu)", idx, 18978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt cert->next->path_len_constraint); 18988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 18998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 19008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_certificate_check_signature(cert->next, cert) 19038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt < 0) { 19048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Invalid " 19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "certificate signature within " 19068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "chain"); 19078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 19088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 19098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (trust = trusted; trust; trust = trust->next) { 19138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_name_compare(&cert->issuer, &trust->subject) 19148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt == 0) 19158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 19168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (trust) { 19198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Found issuer from the " 19208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "list of trusted certificates"); 19218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_valid_issuer(trust) < 0) { 19228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 19238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 19248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_certificate_check_signature(trust, cert) < 0) 19278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 19288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Invalid " 19298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "certificate signature"); 19308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 19318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 19328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Trusted certificate " 19358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "found to complete the chain"); 19368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt chain_trusted = 1; 19378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!chain_trusted) { 19418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers " 19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "from the list of trusted certificates"); 19438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (trusted) { 19448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *reason = X509_VALIDATE_UNKNOWN_CA; 19458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 19468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate chain validation " 19488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "disabled - ignore unknown CA issue"); 19498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate chain valid"); 19528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 19548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 19558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 19588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_get_subject - Get a certificate based on Subject name 19598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @chain: Certificate chain to search through 19608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @name: Subject name to search for 19618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to the certificate with the given Subject name or 19628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * %NULL on failure 19638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 19648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct x509_certificate * 19658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtx509_certificate_get_subject(struct x509_certificate *chain, 19668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_name *name) 19678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 19688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct x509_certificate *cert; 19698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (cert = chain; cert; cert = cert->next) { 19718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (x509_name_compare(&cert->subject, name) == 0) 19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return cert; 19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 19758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 19788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 19798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * x509_certificate_self_signed - Is the certificate self-signed? 19808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @cert: Certificate 19818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 if certificate is self-signed, 0 if not 19828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 19838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint x509_certificate_self_signed(struct x509_certificate *cert) 19848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 19858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return x509_name_compare(&cert->issuer, &cert->subject) == 0; 19868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1987