1526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/* 2526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * X.509v3 certificate parsing and processing (RFC 3280 profile) 3526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 4526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 5526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * This program is free software; you can redistribute it and/or modify 6526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * it under the terms of the GNU General Public License version 2 as 7526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * published by the Free Software Foundation. 8526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 9526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 10526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * license. 11526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 12526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * See README and COPYING for more details. 13526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 14526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 15526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "includes.h" 16526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 17526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "common.h" 18526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 19526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef CONFIG_INTERNAL_X509 20526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 21526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "asn1.h" 22526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "crypto.h" 23526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#include "x509v3.h" 24526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 25526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 26526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void x509_free_name(struct x509_name *name) 27526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 28526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(name->cn); 29526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(name->c); 30526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(name->l); 31526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(name->st); 32526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(name->o); 33526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(name->ou); 34526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(name->email); 35526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt name->cn = name->c = name->l = name->st = name->o = name->ou = NULL; 36526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt name->email = NULL; 37526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 38526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 39526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 40526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 41526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_free - Free an X.509 certificate 42526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @cert: Certificate to be freed 43526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 44526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid x509_certificate_free(struct x509_certificate *cert) 45526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 46526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert == NULL) 47526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 48526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->next) { 49526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p " 50526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "was still on a list (next=%p)\n", 51526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert, cert->next); 52526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 53526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_free_name(&cert->issuer); 54526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_free_name(&cert->subject); 55526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(cert->public_key); 56526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(cert->sign_value); 57526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(cert); 58526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 59526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 60526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 61526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 62526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_free - Free an X.509 certificate chain 63526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @cert: Pointer to the first certificate in the chain 64526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 65526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid x509_certificate_chain_free(struct x509_certificate *cert) 66526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 67526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *next; 68526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 69526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (cert) { 70526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt next = cert->next; 71526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->next = NULL; 72526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 73526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert = next; 74526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 75526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 76526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 77526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 78526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_whitespace(char c) 79526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 80526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return c == ' ' || c == '\t'; 81526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 82526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 83526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 84526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic void x509_str_strip_whitespace(char *a) 85526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 86526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *ipos, *opos; 87526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int remove_whitespace = 1; 88526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 89526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ipos = opos = a; 90526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 91526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (*ipos) { 92526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (remove_whitespace && x509_whitespace(*ipos)) 93526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ipos++; 94526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else { 95526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt remove_whitespace = x509_whitespace(*ipos); 96526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *opos++ = *ipos++; 97526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 98526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 99526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *opos-- = '\0'; 101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (opos > a && x509_whitespace(*opos)) 102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *opos = '\0'; 103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_str_compare(const char *a, const char *b) 107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *aa, *bb; 109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int ret; 110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!a && b) 112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (a && !b) 114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!a && !b) 116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt aa = os_strdup(a); 119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt bb = os_strdup(b); 120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (aa == NULL || bb == NULL) { 122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(aa); 123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(bb); 124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return os_strcasecmp(a, b); 125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_str_strip_whitespace(aa); 128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_str_strip_whitespace(bb); 129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_strcasecmp(aa, bb); 131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(aa); 133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(bb); 134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return ret; 136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_name_compare - Compare X.509 certificate names 141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @a: Certificate name 142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @b: Certificate name 143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: <0, 0, or >0 based on whether a is less than, equal to, or 144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * greater than b 145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint x509_name_compare(struct x509_name *a, struct x509_name *b) 147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int res; 149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!a && b) 151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (a && !b) 153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!a && !b) 155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_str_compare(a->cn, b->cn); 158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res) 159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_str_compare(a->c, b->c); 161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res) 162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_str_compare(a->l, b->l); 164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res) 165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_str_compare(a->st, b->st); 167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res) 168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_str_compare(a->o, b->o); 170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res) 171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_str_compare(a->ou, b->ou); 173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res) 174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_str_compare(a->email, b->email); 176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res) 177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_algorithm_identifier( 184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *buf, size_t len, 185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_algorithm_identifier *id, const u8 **next) 186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, *end; 189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * AlgorithmIdentifier ::= SEQUENCE { 192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * algorithm OBJECT IDENTIFIER, 193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * parameters ANY DEFINED BY algorithm OPTIONAL 194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(AlgorithmIdentifier) - found class %d tag 0x%x", 202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = pos + hdr.length; 207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (end > buf + len) 209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *next = end; 212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_oid(pos, end - pos, &id->oid, &pos)) 214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* TODO: optional parameters */ 217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_public_key(const u8 *buf, size_t len, 223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *cert, 224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 **next) 225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, *end; 228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * SubjectPublicKeyInfo ::= SEQUENCE { 231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * algorithm AlgorithmIdentifier, 232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * subjectPublicKey BIT STRING 233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = buf; 237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = buf + len; 238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(SubjectPublicKeyInfo) - found class %d tag 0x%x", 244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + hdr.length > end) 250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = pos + hdr.length; 252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *next = end; 253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_algorithm_identifier(pos, end - pos, 255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &cert->public_key_alg, &pos)) 256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_BITSTRING) { 261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " 262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(subjectPublicKey) - found class %d tag 0x%x", 263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.length < 1) 267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (*pos) { 270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", 271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos); 272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * TODO: should this be rejected? X.509 certificates are 274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * unlikely to use such a construction. Now we would end up 275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * including the extra bits in the buffer which may also be 276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * ok. 277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(cert->public_key); 280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->public_key = os_malloc(hdr.length - 1); 281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->public_key == NULL) { 282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " 283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "public key"); 284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cert->public_key, pos + 1, hdr.length - 1); 287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->public_key_len = hdr.length - 1; 288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey", 289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->public_key, cert->public_key_len); 290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, 296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 **next) 297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; 300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_oid oid; 301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char **fieldp; 302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Name ::= CHOICE { RDNSequence } 305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName 306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue 307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * AttributeTypeAndValue ::= SEQUENCE { 308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * type AttributeType, 309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * value AttributeValue 310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * AttributeType ::= OBJECT IDENTIFIER 312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * AttributeValue ::= ANY DEFINED BY AttributeType 313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(Name / RDNSequencer) - found class %d tag 0x%x", 320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + hdr.length > buf + len) 326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = *next = pos + hdr.length; 329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pos < end) { 331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SET) { 334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SET " 335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(RelativeDistinguishedName) - found class " 336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "%d tag 0x%x", hdr.class, hdr.tag); 337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_free_name(name); 338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt set_pos = hdr.payload; 342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = set_end = hdr.payload + hdr.length; 343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 || 345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(AttributeTypeAndValue) - found class %d " 349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "tag 0x%x", hdr.class, hdr.tag); 350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_free_name(name); 351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt seq_pos = hdr.payload; 355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt seq_end = hdr.payload + hdr.length; 356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) { 358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_free_name(name); 359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 || 363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL) { 364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse " 365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "AttributeValue"); 366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_free_name(name); 367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* RFC 3280: 371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * MUST: country, organization, organizational-unit, 372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * distinguished name qualifier, state or province name, 373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * common name, serial number. 374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * SHOULD: locality, title, surname, given name, initials, 375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pseudonym, generation qualifier. 376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * MUST: domainComponent (RFC 2247). 377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = NULL; 379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (oid.len == 4 && 380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) { 381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* id-at ::= 2.5.4 */ 382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (oid.oid[3]) { 383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 3: 384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* commonName */ 385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = &name->cn; 386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 6: 388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* countryName */ 389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = &name->c; 390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 7: 392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* localityName */ 393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = &name->l; 394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 8: 396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* stateOrProvinceName */ 397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = &name->st; 398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 10: 400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* organizationName */ 401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = &name->o; 402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 11: 404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* organizationalUnitName */ 405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = &name->ou; 406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else if (oid.len == 7 && 409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid.oid[0] == 1 && oid.oid[1] == 2 && 410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid.oid[2] == 840 && oid.oid[3] == 113549 && 411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid.oid[4] == 1 && oid.oid[5] == 9 && 412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid.oid[6] == 1) { 413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 1.2.840.113549.1.9.1 - e-mailAddress */ 414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt fieldp = &name->email; 415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (fieldp == NULL) { 418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID", 419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (u8 *) oid.oid, 420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid.len * sizeof(oid.oid[0])); 421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data", 422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.payload, hdr.length); 423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(*fieldp); 427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *fieldp = os_malloc(hdr.length + 1); 428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (*fieldp == NULL) { 429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_free_name(name); 430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(*fieldp, hdr.payload, hdr.length); 433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (*fieldp)[hdr.length] = '\0'; 434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_name_string - Convert an X.509 certificate name into a string 442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @name: Name to convert 443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @buf: Buffer for the string 444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Maximum buffer length 445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtvoid x509_name_string(struct x509_name *name, char *buf, size_t len) 447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char *pos, *end; 449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int ret; 450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len == 0) 452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return; 453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = buf; 455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = buf + len; 456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (name->c) { 458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, end - pos, "C=%s, ", name->c); 459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= end - pos) 460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto done; 461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (name->st) { 464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, end - pos, "ST=%s, ", name->st); 465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= end - pos) 466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto done; 467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (name->l) { 470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, end - pos, "L=%s, ", name->l); 471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= end - pos) 472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto done; 473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (name->o) { 476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, end - pos, "O=%s, ", name->o); 477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= end - pos) 478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto done; 479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (name->ou) { 482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, end - pos, "OU=%s, ", name->ou); 483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= end - pos) 484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto done; 485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (name->cn) { 488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, end - pos, "CN=%s, ", name->cn); 489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= end - pos) 490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto done; 491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') { 495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos-- = '\0'; 496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos-- = '\0'; 497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (name->email) { 500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt ret = os_snprintf(pos, end - pos, "/emailAddress=%s", 501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt name->email); 502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (ret < 0 || ret >= end - pos) 503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto done; 504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += ret; 505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtdone: 508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end[-1] = '\0'; 509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, 513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_time_t *val) 514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const char *pos; 516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int year, month, day, hour, min, sec; 517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Time ::= CHOICE { 520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * utcTime UTCTime, 521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * generalTime GeneralizedTime 522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * UTCTime: YYMMDDHHMMSSZ 525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * GeneralizedTime: YYYYMMDDHHMMSSZ 526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = (const char *) buf; 529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (asn1_tag) { 531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case ASN1_TAG_UTCTIME: 532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len != 13 || buf[12] != 'Z') { 533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " 534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "UTCTime format", buf, len); 535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sscanf(pos, "%02d", &year) != 1) { 538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " 539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "UTCTime year", buf, len); 540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (year < 50) 543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt year += 2000; 544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt else 545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt year += 1900; 546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case ASN1_TAG_GENERALIZEDTIME: 549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (len != 15 || buf[14] != 'Z') { 550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " 551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "GeneralizedTime format", buf, len); 552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sscanf(pos, "%04d", &year) != 1) { 555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " 556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "GeneralizedTime year", buf, len); 557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 4; 560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt default: 562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or " 563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "GeneralizedTime - found tag 0x%x", asn1_tag); 564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sscanf(pos, "%02d", &month) != 1) { 568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(month)", buf, len); 570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sscanf(pos, "%02d", &day) != 1) { 575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(day)", buf, len); 577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sscanf(pos, "%02d", &hour) != 1) { 582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(hour)", buf, len); 584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sscanf(pos, "%02d", &min) != 1) { 589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(min)", buf, len); 591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos += 2; 594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (sscanf(pos, "%02d", &sec) != 1) { 596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time " 597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(sec)", buf, len); 598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (os_mktime(year, month, day, hour, min, sec, val) < 0) { 602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time", 603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf, len); 604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (year < 1970) { 605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * At least some test certificates have been configured 607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * to use dates prior to 1970. Set the date to 608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * beginning of 1970 to handle these case. 609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Year=%d before epoch - " 611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "assume epoch as the time", year); 612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *val = 0; 613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_validity(const u8 *buf, size_t len, 623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *cert, const u8 **next) 624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos; 627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t plen; 628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Validity ::= SEQUENCE { 631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * notBefore Time, 632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * notAfter Time 633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * RFC 3280, 4.1.2.5: 636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * CAs conforming to this profile MUST always encode certificate 637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * validity dates through the year 2049 as UTCTime; certificate 638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * validity dates in 2050 or later MUST be encoded as GeneralizedTime. 639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(Validity) - found class %d tag 0x%x", 646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt plen = hdr.length; 651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + plen > buf + len) 653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *next = pos + plen; 656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, plen, &hdr) < 0 || 658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_parse_time(hdr.payload, hdr.length, hdr.tag, 660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &cert->not_before) < 0) { 661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore " 662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Time", hdr.payload, hdr.length); 663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload + hdr.length; 667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt plen = *next - pos; 668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, plen, &hdr) < 0 || 670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_parse_time(hdr.payload, hdr.length, hdr.tag, 672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &cert->not_after) < 0) { 673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter " 674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Time", hdr.payload, hdr.length); 675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu", 679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) cert->not_before, 680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) cert->not_after); 681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_id_ce_oid(struct asn1_oid *oid) 687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* id-ce arc from X.509 for standard X.509v3 extensions */ 689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return oid->len >= 4 && 690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[0] == 2 /* joint-iso-ccitt */ && 691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[1] == 5 /* ds */ && 692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[2] == 29 /* id-ce */; 693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_ext_key_usage(struct x509_certificate *cert, 697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, size_t len) 698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * KeyUsage ::= BIT STRING { 703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * digitalSignature (0), 704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * nonRepudiation (1), 705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * keyEncipherment (2), 706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * dataEncipherment (3), 707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * keyAgreement (4), 708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * keyCertSign (5), 709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * cRLSign (6), 710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * encipherOnly (7), 711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * decipherOnly (8) } 712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_BITSTRING || 717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.length < 1) { 718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in " 719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "KeyUsage; found %d tag 0x%x len %d", 720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag, hdr.length); 721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->extensions_present |= X509_EXT_KEY_USAGE; 725526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length); 726526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 727526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage); 728526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 729526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 730526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 731526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 732526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 733526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_ext_basic_constraints(struct x509_certificate *cert, 734526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, size_t len) 735526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 736526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 737526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned long value; 738526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t left; 739526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 740526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 741526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * BasicConstraints ::= SEQUENCE { 742526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * cA BOOLEAN DEFAULT FALSE, 743526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * pathLenConstraint INTEGER (0..MAX) OPTIONAL } 744526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 745526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 746526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 747526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 748526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 749526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in " 750526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "BasicConstraints; found %d tag 0x%x", 751526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 752526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 753526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 754526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 755526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS; 756526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 757526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.length == 0) 758526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 759526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 760526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 || 761526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL) { 762526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse " 763526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "BasicConstraints"); 764526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 765526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 766526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 767526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.tag == ASN1_TAG_BOOLEAN) { 768526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.length != 1) { 769526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected " 770526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Boolean length (%u) in BasicConstraints", 771526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.length); 772526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 773526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 774526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->ca = hdr.payload[0]; 775526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 776526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.payload + hdr.length == pos + len) { 777526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d", 778526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->ca); 779526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 780526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 781526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 782526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(hdr.payload + hdr.length, len - hdr.length, 783526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &hdr) < 0 || 784526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL) { 785526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse " 786526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "BasicConstraints"); 787526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 788526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 789526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 790526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 791526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.tag != ASN1_TAG_INTEGER) { 792526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in " 793526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "BasicConstraints; found class %d tag 0x%x", 794526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 795526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 796526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 797526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 798526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 799526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left = hdr.length; 800526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt value = 0; 801526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (left) { 802526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt value <<= 8; 803526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt value |= *pos++; 804526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left--; 805526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 806526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 807526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->path_len_constraint = value; 808526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT; 809526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 810526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d " 811526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "pathLenConstraint=%lu", 812526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->ca, cert->path_len_constraint); 813526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 814526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 815526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 816526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 817526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 818526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_extension_data(struct x509_certificate *cert, 819526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_oid *oid, 820526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, size_t len) 821526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 822526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!x509_id_ce_oid(oid)) 823526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 824526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 825526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* TODO: add other extensions required by RFC 3280, Ch 4.2: 826526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * certificate policies (section 4.2.1.5) 827526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * the subject alternative name (section 4.2.1.7) 828526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * name constraints (section 4.2.1.11) 829526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * policy constraints (section 4.2.1.12) 830526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * extended key usage (section 4.2.1.13) 831526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * inhibit any-policy (section 4.2.1.15) 832526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 833526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (oid->oid[3]) { 834526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 15: /* id-ce-keyUsage */ 835526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return x509_parse_ext_key_usage(cert, pos, len); 836526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 19: /* id-ce-basicConstraints */ 837526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return x509_parse_ext_basic_constraints(cert, pos, len); 838526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt default: 839526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 1; 840526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 841526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 842526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 843526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 844526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_extension(struct x509_certificate *cert, 845526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, size_t len, const u8 **next) 846526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 847526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *end; 848526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 849526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_oid oid; 850526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int critical_ext = 0, res; 851526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char buf[80]; 852526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 853526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 854526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Extension ::= SEQUENCE { 855526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * extnID OBJECT IDENTIFIER, 856526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * critical BOOLEAN DEFAULT FALSE, 857526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * extnValue OCTET STRING 858526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 859526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 860526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 861526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 862526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 863526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 864526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " 865526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Extensions: class %d tag 0x%x; expected SEQUENCE", 866526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 867526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 868526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 869526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 870526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *next = end = pos + hdr.length; 871526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 872526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) { 873526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for " 874526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Extension (expected OID)"); 875526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 876526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 877526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 878526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 879526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 880526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (hdr.tag != ASN1_TAG_BOOLEAN && 881526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_OCTETSTRING)) { 882526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in " 883526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Extensions: class %d tag 0x%x; expected BOOLEAN " 884526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "or OCTET STRING", hdr.class, hdr.tag); 885526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 886526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 887526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 888526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.tag == ASN1_TAG_BOOLEAN) { 889526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.length != 1) { 890526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected " 891526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Boolean length (%u)", hdr.length); 892526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 893526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 894526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt critical_ext = hdr.payload[0]; 895526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 896526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 897526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (hdr.class != ASN1_CLASS_UNIVERSAL && 898526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_PRIVATE) || 899526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_OCTETSTRING) { 900526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header " 901526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "in Extensions: class %d tag 0x%x; " 902526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "expected OCTET STRING", 903526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 904526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 905526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 906526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 907526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 908526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt asn1_oid_to_str(&oid, buf, sizeof(buf)); 909526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d", 910526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf, critical_ext); 911526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length); 912526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 913526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length); 914526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res < 0) 915526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return res; 916526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (res == 1 && critical_ext) { 917526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "X509: Unknown critical extension %s", 918526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf); 919526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 920526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 921526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 922526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 923526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 924526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 925526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 926526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_extensions(struct x509_certificate *cert, 927526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, size_t len) 928526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 929526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *end; 930526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 931526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 932526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */ 933526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 934526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 935526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 936526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 937526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data " 938526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "for Extensions: class %d tag 0x%x; " 939526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "expected SEQUENCE", hdr.class, hdr.tag); 940526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 941526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 942526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 943526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 944526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = pos + hdr.length; 945526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 946526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (pos < end) { 947526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_extension(cert, pos, end - pos, &pos) 948526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt < 0) 949526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 950526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 951526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 952526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 953526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 954526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 955526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 956526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_parse_tbs_certificate(const u8 *buf, size_t len, 957526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *cert, 958526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 **next) 959526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 960526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 961526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, *end; 962526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t left; 963526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char sbuf[128]; 964526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt unsigned long value; 965526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 966526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* tbsCertificate TBSCertificate ::= SEQUENCE */ 967526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(buf, len, &hdr) < 0 || 968526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 969526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 970526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start " 971526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "with a valid SEQUENCE - found class %d tag 0x%x", 972526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 973526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 974526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 975526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 976526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = *next = pos + hdr.length; 977526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 978526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 979526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * version [0] EXPLICIT Version DEFAULT v1 980526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Version ::= INTEGER { v1(0), v2(1), v3(2) } 981526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 982526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0) 983526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 984526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 985526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 986526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) { 987526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0) 988526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 989526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 990526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.class != ASN1_CLASS_UNIVERSAL || 991526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_INTEGER) { 992526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " 993526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "version field - found class %d tag 0x%x", 994526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 995526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 996526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 997526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.length != 1) { 998526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unexpected version field " 999526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "length %u (expected 1)", hdr.length); 1000526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1001526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1002526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 1003526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left = hdr.length; 1004526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt value = 0; 1005526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (left) { 1006526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt value <<= 8; 1007526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt value |= *pos++; 1008526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left--; 1009526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1010526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1011526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->version = value; 1012526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->version != X509_CERT_V1 && 1013526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->version != X509_CERT_V2 && 1014526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->version != X509_CERT_V3) { 1015526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unsupported version %d", 1016526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->version + 1); 1017526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1018526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1019526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1020526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0) 1021526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1022526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } else 1023526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->version = X509_CERT_V1; 1024526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1); 1025526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1026526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* serialNumber CertificateSerialNumber ::= INTEGER */ 1027526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.class != ASN1_CLASS_UNIVERSAL || 1028526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_INTEGER) { 1029526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for " 1030526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "serialNumber; class=%d tag=0x%x", 1031526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1032526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1033526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1034526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1035526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 1036526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left = hdr.length; 1037526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt while (left) { 1038526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->serial_number <<= 8; 1039526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->serial_number |= *pos++; 1040526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt left--; 1041526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1042526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number); 1043526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1044526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* signature AlgorithmIdentifier */ 1045526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature, 1046526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &pos)) 1047526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1048526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1049526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* issuer Name */ 1050526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_name(pos, end - pos, &cert->issuer, &pos)) 1051526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1052526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_name_string(&cert->issuer, sbuf, sizeof(sbuf)); 1053526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf); 1054526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1055526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* validity Validity */ 1056526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_validity(pos, end - pos, cert, &pos)) 1057526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1058526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1059526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* subject Name */ 1060526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_name(pos, end - pos, &cert->subject, &pos)) 1061526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1062526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_name_string(&cert->subject, sbuf, sizeof(sbuf)); 1063526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf); 1064526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1065526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* subjectPublicKeyInfo SubjectPublicKeyInfo */ 1066526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_public_key(pos, end - pos, cert, &pos)) 1067526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1068526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1069526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos == end) 1070526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1071526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1072526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->version == X509_CERT_V1) 1073526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1074526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1075526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1076526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { 1077526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" 1078526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt " tag to parse optional tbsCertificate " 1079526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "field(s); parsed class %d tag 0x%x", 1080526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1081526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1082526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1083526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1084526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.tag == 1) { 1085526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */ 1086526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: issuerUniqueID"); 1087526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* TODO: parse UniqueIdentifier ::= BIT STRING */ 1088526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1089526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.payload + hdr.length == end) 1090526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1091526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1092526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1093526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { 1094526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" 1095526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt " tag to parse optional tbsCertificate " 1096526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "field(s); parsed class %d tag 0x%x", 1097526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1098526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1099526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1100526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1101526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1102526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.tag == 2) { 1103526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */ 1104526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: subjectUniqueID"); 1105526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* TODO: parse UniqueIdentifier ::= BIT STRING */ 1106526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1107526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.payload + hdr.length == end) 1108526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1109526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1110526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1111526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) { 1112526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific" 1113526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt " tag to parse optional tbsCertificate " 1114526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "field(s); parsed class %d tag 0x%x", 1115526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1116526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1117526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1118526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1119526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1120526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.tag != 3) { 1121526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Ignored unexpected " 1122526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Context-Specific tag %d in optional " 1123526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "tbsCertificate fields", hdr.tag); 1124526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1125526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1126526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1127526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* extensions [3] EXPLICIT Extensions OPTIONAL */ 1128526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1129526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->version != X509_CERT_V3) { 1130526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and " 1131526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "Extensions data which are only allowed for " 1132526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "version 3", cert->version + 1); 1133526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1134526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1135526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1136526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0) 1137526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1138526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1139526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload + hdr.length; 1140526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos < end) { 1141526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_DEBUG, 1142526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "X509: Ignored extra tbsCertificate data", 1143526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos, end - pos); 1144526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1145526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1146526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1147526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1148526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1149526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1150526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_rsadsi_oid(struct asn1_oid *oid) 1151526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1152526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return oid->len >= 4 && 1153526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[0] == 1 /* iso */ && 1154526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[1] == 2 /* member-body */ && 1155526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[2] == 840 /* us */ && 1156526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[3] == 113549 /* rsadsi */; 1157526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1158526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1159526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1160526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_pkcs_oid(struct asn1_oid *oid) 1161526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1162526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return oid->len >= 5 && 1163526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_rsadsi_oid(oid) && 1164526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[4] == 1 /* pkcs */; 1165526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1166526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1167526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1168526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_digest_oid(struct asn1_oid *oid) 1169526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1170526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return oid->len >= 5 && 1171526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_rsadsi_oid(oid) && 1172526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[4] == 2 /* digestAlgorithm */; 1173526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1174526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1175526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1176526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_sha1_oid(struct asn1_oid *oid) 1177526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1178526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return oid->len == 6 && 1179526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[0] == 1 /* iso */ && 1180526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[1] == 3 /* identified-organization */ && 1181526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[2] == 14 /* oiw */ && 1182526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[3] == 3 /* secsig */ && 1183526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[4] == 2 /* algorithms */ && 1184526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[5] == 26 /* id-sha1 */; 1185526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1186526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1187526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1188526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_sha256_oid(struct asn1_oid *oid) 1189526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1190526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return oid->len == 9 && 1191526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[0] == 2 /* joint-iso-itu-t */ && 1192526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[1] == 16 /* country */ && 1193526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[2] == 840 /* us */ && 1194526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[3] == 1 /* organization */ && 1195526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[4] == 101 /* gov */ && 1196526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[5] == 3 /* csor */ && 1197526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[6] == 4 /* nistAlgorithm */ && 1198526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[7] == 2 /* hashAlgs */ && 1199526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt oid->oid[8] == 1 /* sha256 */; 1200526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1201526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1202526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1203526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1204526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_parse - Parse a X.509 certificate in DER format 1205526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @buf: Pointer to the X.509 certificate in DER format 1206526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @len: Buffer length 1207526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to the parsed certificate or %NULL on failure 1208526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 1209526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Caller is responsible for freeing the returned certificate by calling 1210526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_free(). 1211526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1212526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len) 1213526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1214526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 1215526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, *end, *hash_start; 1216526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *cert; 1217526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1218526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert = os_zalloc(sizeof(*cert) + len); 1219526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert == NULL) 1220526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1221526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cert + 1, buf, len); 1222526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->cert_start = (u8 *) (cert + 1); 1223526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->cert_len = len; 1224526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1225526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = buf; 1226526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = buf + len; 1227526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1228526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */ 1229526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1230526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Certificate ::= SEQUENCE */ 1231526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, len, &hdr) < 0 || 1232526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 1233526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 1234526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate did not start with " 1235526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "a valid SEQUENCE - found class %d tag 0x%x", 1236526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1237526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1238526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1239526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1240526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 1241526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1242526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + hdr.length > end) { 1243526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1244526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1245526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1246526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1247526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pos + hdr.length < end) { 1248526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER " 1249526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "encoded certificate", 1250526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos + hdr.length, end - pos + hdr.length); 1251526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = pos + hdr.length; 1252526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1253526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1254526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash_start = pos; 1255526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->tbs_cert_start = cert->cert_start + (hash_start - buf); 1256526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) { 1257526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1258526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1259526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1260526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->tbs_cert_len = pos - hash_start; 1261526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1262526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* signatureAlgorithm AlgorithmIdentifier */ 1263526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_parse_algorithm_identifier(pos, end - pos, 1264526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &cert->signature_alg, &pos)) { 1265526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1266526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1267526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1268526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1269526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* signatureValue BIT STRING */ 1270526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1271526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 1272526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_BITSTRING) { 1273526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " 1274526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(signatureValue) - found class %d tag 0x%x", 1275526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1276526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1277526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1278526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1279526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.length < 1) { 1280526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1281526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1282526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1283526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 1284526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (*pos) { 1285526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", 1286526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *pos); 1287526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* PKCS #1 v1.5 10.2.1: 1288526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * It is an error if the length in bits of the signature S is 1289526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * not a multiple of eight. 1290526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1291526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1292526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1293526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1294526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(cert->sign_value); 1295526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->sign_value = os_malloc(hdr.length - 1); 1296526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->sign_value == NULL) { 1297526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " 1298526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "signatureValue"); 1299526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_certificate_free(cert); 1300526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1301526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1302526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcpy(cert->sign_value, pos + 1, hdr.length - 1); 1303526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->sign_value_len = hdr.length - 1; 1304526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: signature", 1305526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->sign_value, cert->sign_value_len); 1306526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1307526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return cert; 1308526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1309526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1310526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1311526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1312526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_check_signature - Verify certificate signature 1313526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @issuer: Issuer certificate 1314526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @cert: Certificate to be verified 1315526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 if cert has a valid signature that was signed by the issuer, 1316526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * -1 if not 1317526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1318526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint x509_certificate_check_signature(struct x509_certificate *issuer, 1319526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *cert) 1320526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1321526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct crypto_public_key *pk; 1322526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 *data; 1323526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt const u8 *pos, *end, *next, *da_end; 1324526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t data_len; 1325526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_hdr hdr; 1326526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct asn1_oid oid; 1327526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt u8 hash[32]; 1328526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt size_t hash_len; 1329526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1330526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!x509_pkcs_oid(&cert->signature.oid) || 1331526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->signature.oid.len != 7 || 1332526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->signature.oid.oid[5] != 1 /* pkcs-1 */) { 1333526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unrecognized signature " 1334526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "algorithm"); 1335526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1336526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1337526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1338526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pk = crypto_public_key_import(issuer->public_key, 1339526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt issuer->public_key_len); 1340526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (pk == NULL) 1341526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1342526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1343526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data_len = cert->sign_value_len; 1344526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt data = os_malloc(data_len); 1345526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (data == NULL) { 1346526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt crypto_public_key_free(pk); 1347526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1348526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1349526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1350526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value, 1351526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->sign_value_len, data, 1352526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &data_len) < 0) { 1353526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature"); 1354526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt crypto_public_key_free(pk); 1355526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1356526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1357526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1358526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt crypto_public_key_free(pk); 1359526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1360526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len); 1361526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1362526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 1363526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * PKCS #1 v1.5, 10.1.2: 1364526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 1365526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * DigestInfo ::= SEQUENCE { 1366526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * digestAlgorithm DigestAlgorithmIdentifier, 1367526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * digest Digest 1368526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 1369526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 1370526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * DigestAlgorithmIdentifier ::= AlgorithmIdentifier 1371526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 1372526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Digest ::= OCTET STRING 1373526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * 1374526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1375526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(data, data_len, &hdr) < 0 || 1376526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 1377526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 1378526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 1379526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(DigestInfo) - found class %d tag 0x%x", 1380526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1381526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1382526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1383526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1384526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1385526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = hdr.payload; 1386526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = pos + hdr.length; 1387526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1388526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* 1389526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * X.509: 1390526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * AlgorithmIdentifier ::= SEQUENCE { 1391526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * algorithm OBJECT IDENTIFIER, 1392526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * parameters ANY DEFINED BY algorithm OPTIONAL 1393526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * } 1394526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1395526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1396526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1397526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 1398526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_SEQUENCE) { 1399526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " 1400526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(AlgorithmIdentifier) - found class %d tag 0x%x", 1401526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1402526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1403526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1404526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1405526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt da_end = hdr.payload + hdr.length; 1406526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1407526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { 1408526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm"); 1409526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1410526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1411526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1412526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1413526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_sha1_oid(&oid)) { 1414526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->signature.oid.oid[6] != 1415526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 5 /* sha-1WithRSAEncryption */) { 1416526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 " 1417526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "does not match with certificate " 1418526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "signatureAlgorithm (%lu)", 1419526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->signature.oid.oid[6]); 1420526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1421526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1422526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1423526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto skip_digest_oid; 1424526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1425526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1426526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_sha256_oid(&oid)) { 1427526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->signature.oid.oid[6] != 1428526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 11 /* sha2561WithRSAEncryption */) { 1429526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA256 " 1430526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "does not match with certificate " 1431526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "signatureAlgorithm (%lu)", 1432526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->signature.oid.oid[6]); 1433526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1434526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1435526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1436526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt goto skip_digest_oid; 1437526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1438526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1439526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!x509_digest_oid(&oid)) { 1440526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm"); 1441526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1442526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1443526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1444526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (oid.oid[5]) { 1445526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 5: /* md5 */ 1446526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */) 1447526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { 1448526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does " 1449526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "not match with certificate " 1450526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "signatureAlgorithm (%lu)", 1451526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->signature.oid.oid[6]); 1452526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1453526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1454526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1455526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1456526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 2: /* md2 */ 1457526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 4: /* md4 */ 1458526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt default: 1459526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm " 1460526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(%lu)", oid.oid[5]); 1461526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1462526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1463526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1464526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1465526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtskip_digest_oid: 1466526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt /* Digest ::= OCTET STRING */ 1467526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt pos = da_end; 1468526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt end = data + data_len; 1469526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1470526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1471526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class != ASN1_CLASS_UNIVERSAL || 1472526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.tag != ASN1_TAG_OCTETSTRING) { 1473526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING " 1474526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(Digest) - found class %d tag 0x%x", 1475526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.class, hdr.tag); 1476526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1477526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1478526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1479526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest", 1480526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hdr.payload, hdr.length); 1481526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1482526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt switch (cert->signature.oid.oid[6]) { 1483526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 4: /* md5WithRSAEncryption */ 1484526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, 1485526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash); 1486526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash_len = 16; 1487526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)", 1488526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash, hash_len); 1489526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1490526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 5: /* sha-1WithRSAEncryption */ 1491526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, 1492526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash); 1493526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash_len = 20; 1494526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)", 1495526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash, hash_len); 1496526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1497526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 11: /* sha256WithRSAEncryption */ 1498526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#ifdef NEED_SHA256 1499526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sha256_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len, 1500526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash); 1501526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash_len = 32; 1502526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA256)", 1503526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt hash, hash_len); 1504526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1505526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#else /* NEED_SHA256 */ 1506526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "X509: SHA256 support disabled"); 1507526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1508526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1509526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* NEED_SHA256 */ 1510526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 2: /* md2WithRSAEncryption */ 1511526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 12: /* sha384WithRSAEncryption */ 1512526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt case 13: /* sha512WithRSAEncryption */ 1513526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt default: 1514526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "X509: Unsupported certificate signature " 1515526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "algorithm (%lu)", cert->signature.oid.oid[6]); 1516526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1517526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1518526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1519526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1520526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (hdr.length != hash_len || 1521526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_memcmp(hdr.payload, hash, hdr.length) != 0) { 1522526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "X509: Certificate Digest does not match " 1523526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "with calculated tbsCertificate hash"); 1524526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1525526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1526526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1527526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1528526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_free(data); 1529526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1530526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with " 1531526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "calculated tbsCertificate hash"); 1532526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1533526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1534526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1535526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1536526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1537526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstatic int x509_valid_issuer(const struct x509_certificate *cert) 1538526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1539526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) && 1540526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt !cert->ca) { 1541526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an " 1542526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "issuer"); 1543526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1544526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1545526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1546526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->version == X509_CERT_V3 && 1547526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt !(cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS)) { 1548526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: v3 CA certificate did not " 1549526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "include BasicConstraints extension"); 1550526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1551526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1552526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1553526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((cert->extensions_present & X509_EXT_KEY_USAGE) && 1554526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) { 1555526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have " 1556526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "keyCertSign bit in Key Usage"); 1557526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1558526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1559526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1560526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1561526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1562526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1563526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1564526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1565526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_chain_validate - Validate X.509 certificate chain 1566526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @trusted: List of trusted certificates 1567526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @chain: Certificate chain to be validated (first chain must be issued by 1568526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * signed by the second certificate in the chain and so on) 1569526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @reason: Buffer for returning failure reason (X509_VALIDATE_*) 1570526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 0 if chain is valid, -1 if not 1571526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1572526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint x509_certificate_chain_validate(struct x509_certificate *trusted, 1573526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *chain, 1574526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int *reason) 1575526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1576526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt long unsigned idx; 1577526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt int chain_trusted = 0; 1578526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *cert, *trust; 1579526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt char buf[128]; 1580526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct os_time now; 1581526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1582526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_OK; 1583526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1584526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Validate certificate chain"); 1585526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt os_get_time(&now); 1586526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1587526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (cert = chain, idx = 0; cert; cert = cert->next, idx++) { 1588526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_name_string(&cert->subject, buf, sizeof(buf)); 1589526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf); 1590526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1591526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (chain_trusted) 1592526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt continue; 1593526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1594526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((unsigned long) now.sec < 1595526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) cert->not_before || 1596526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) now.sec > 1597526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt (unsigned long) cert->not_after) { 1598526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_INFO, "X509: Certificate not valid " 1599526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "(now=%lu not_before=%lu not_after=%lu)", 1600526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt now.sec, cert->not_before, cert->not_after); 1601526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_CERTIFICATE_EXPIRED; 1602526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1603526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1604526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1605526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (cert->next) { 1606526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_name_compare(&cert->issuer, 1607526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt &cert->next->subject) != 0) { 1608526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate " 1609526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "chain issuer name mismatch"); 1610526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_name_string(&cert->issuer, buf, 1611526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sizeof(buf)); 1612526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: cert issuer: %s", 1613526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt buf); 1614526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt x509_name_string(&cert->next->subject, buf, 1615526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt sizeof(buf)); 1616526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: next cert " 1617526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "subject: %s", buf); 1618526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN; 1619526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1620526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1621526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1622526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_valid_issuer(cert->next) < 0) { 1623526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 1624526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1625526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1626526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1627526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if ((cert->next->extensions_present & 1628526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt X509_EXT_PATH_LEN_CONSTRAINT) && 1629526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt idx > cert->next->path_len_constraint) { 1630526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: pathLenConstraint" 1631526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt " not met (idx=%lu issuer " 1632526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "pathLenConstraint=%lu)", idx, 1633526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt cert->next->path_len_constraint); 1634526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 1635526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1636526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1637526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1638526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_certificate_check_signature(cert->next, cert) 1639526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt < 0) { 1640526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Invalid " 1641526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "certificate signature within " 1642526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "chain"); 1643526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 1644526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1645526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1646526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1647526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1648526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (trust = trusted; trust; trust = trust->next) { 1649526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_name_compare(&cert->issuer, &trust->subject) 1650526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt == 0) 1651526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt break; 1652526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1653526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1654526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (trust) { 1655526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Found issuer from the " 1656526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "list of trusted certificates"); 1657526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_valid_issuer(trust) < 0) { 1658526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 1659526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1660526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1661526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1662526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_certificate_check_signature(trust, cert) < 0) 1663526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt { 1664526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Invalid " 1665526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "certificate signature"); 1666526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_BAD_CERTIFICATE; 1667526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1668526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1669526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1670526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Trusted certificate " 1671526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "found to complete the chain"); 1672526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt chain_trusted = 1; 1673526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1674526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1675526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1676526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (!chain_trusted) { 1677526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers " 1678526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "from the list of trusted certificates"); 1679526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (trusted) { 1680526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt *reason = X509_VALIDATE_UNKNOWN_CA; 1681526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return -1; 1682526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1683526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate chain validation " 1684526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt "disabled - ignore unknown CA issue"); 1685526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1686526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1687526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt wpa_printf(MSG_DEBUG, "X509: Certificate chain valid"); 1688526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1689526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return 0; 1690526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1691526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1692526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1693526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1694526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_get_subject - Get a certificate based on Subject name 1695526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @chain: Certificate chain to search through 1696526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @name: Subject name to search for 1697526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: Pointer to the certificate with the given Subject name or 1698526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * %NULL on failure 1699526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1700526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtstruct x509_certificate * 1701526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtx509_certificate_get_subject(struct x509_certificate *chain, 1702526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_name *name) 1703526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1704526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt struct x509_certificate *cert; 1705526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1706526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt for (cert = chain; cert; cert = cert->next) { 1707526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt if (x509_name_compare(&cert->subject, name) == 0) 1708526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return cert; 1709526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt } 1710526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return NULL; 1711526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1712526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1713526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1714526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt/** 1715526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * x509_certificate_self_signed - Is the certificate self-signed? 1716526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * @cert: Certificate 1717526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt * Returns: 1 if certificate is self-signed, 0 if not 1718526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt */ 1719526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidtint x509_certificate_self_signed(struct x509_certificate *cert) 1720526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt{ 1721526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt return x509_name_compare(&cert->issuer, &cert->subject) == 0; 1722526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt} 1723526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt 1724526fc2a7dc09b4450086cdec313a5c44d36b10fdDmitry Shmidt#endif /* CONFIG_INTERNAL_X509 */ 1725