📄 x509v3.c
字号:
/* * X.509v3 certificate parsing and processing (RFC 3280 profile) * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#ifdef CONFIG_INTERNAL_X509#include "asn1.h"#include "crypto.h"#include "x509v3.h"static void x509_free_name(struct x509_name *name){ os_free(name->cn); os_free(name->c); os_free(name->l); os_free(name->st); os_free(name->o); os_free(name->ou); os_free(name->email); name->cn = name->c = name->l = name->st = name->o = name->ou = NULL; name->email = NULL;}/** * x509_certificate_free - Free an X.509 certificate * @cert: Certificate to be freed */void x509_certificate_free(struct x509_certificate *cert){ if (cert == NULL) return; if (cert->next) { wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p " "was still on a list (next=%p)\n", cert, cert->next); } x509_free_name(&cert->issuer); x509_free_name(&cert->subject); os_free(cert->public_key); os_free(cert->sign_value); os_free(cert);}/** * x509_certificate_free - Free an X.509 certificate chain * @cert: Pointer to the first certificate in the chain */void x509_certificate_chain_free(struct x509_certificate *cert){ struct x509_certificate *next; while (cert) { next = cert->next; cert->next = NULL; x509_certificate_free(cert); cert = next; }}static int x509_whitespace(char c){ return c == ' ' || c == '\t';}static void x509_str_strip_whitespace(char *a){ char *ipos, *opos; int remove_whitespace = 1; ipos = opos = a; while (*ipos) { if (remove_whitespace && x509_whitespace(*ipos)) ipos++; else { remove_whitespace = x509_whitespace(*ipos); *opos++ = *ipos++; } } *opos-- = '\0'; if (opos > a && x509_whitespace(*opos)) *opos = '\0';}static int x509_str_compare(const char *a, const char *b){ char *aa, *bb; int ret; if (!a && b) return -1; if (a && !b) return 1; if (!a && !b) return 0; aa = os_strdup(a); bb = os_strdup(b); if (aa == NULL || bb == NULL) { os_free(aa); os_free(bb); return os_strcasecmp(a, b); } x509_str_strip_whitespace(aa); x509_str_strip_whitespace(bb); ret = os_strcasecmp(aa, bb); os_free(aa); os_free(bb); return ret;}/** * x509_name_compare - Compare X.509 certificate names * @a: Certificate name * @b: Certificate name * Returns: <0, 0, or >0 based on whether a is less than, equal to, or * greater than b */int x509_name_compare(struct x509_name *a, struct x509_name *b){ int res; if (!a && b) return -1; if (a && !b) return 1; if (!a && !b) return 0; res = x509_str_compare(a->cn, b->cn); if (res) return res; res = x509_str_compare(a->c, b->c); if (res) return res; res = x509_str_compare(a->l, b->l); if (res) return res; res = x509_str_compare(a->st, b->st); if (res) return res; res = x509_str_compare(a->o, b->o); if (res) return res; res = x509_str_compare(a->ou, b->ou); if (res) return res; res = x509_str_compare(a->email, b->email); if (res) return res; return 0;}static int x509_parse_algorithm_identifier( const u8 *buf, size_t len, struct x509_algorithm_identifier *id, const u8 **next){ struct asn1_hdr hdr; const u8 *pos, *end; /* * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(AlgorithmIdentifier) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; end = pos + hdr.length; if (end > buf + len) return -1; *next = end; if (asn1_get_oid(pos, end - pos, &id->oid, &pos)) return -1; /* TODO: optional parameters */ return 0;}static int x509_parse_public_key(const u8 *buf, size_t len, struct x509_certificate *cert, const u8 **next){ struct asn1_hdr hdr; const u8 *pos, *end; /* * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING * } */ pos = buf; end = buf + len; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(SubjectPublicKeyInfo) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; if (pos + hdr.length > end) return -1; end = pos + hdr.length; *next = end; if (x509_parse_algorithm_identifier(pos, end - pos, &cert->public_key_alg, &pos)) return -1; if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_BITSTRING) { wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING " "(subjectPublicKey) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } if (hdr.length < 1) return -1; pos = hdr.payload; if (*pos) { wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits", *pos); /* * TODO: should this be rejected? X.509 certificates are * unlikely to use such a construction. Now we would end up * including the extra bits in the buffer which may also be * ok. */ } os_free(cert->public_key); cert->public_key = os_malloc(hdr.length - 1); if (cert->public_key == NULL) { wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for " "public key"); return -1; } os_memcpy(cert->public_key, pos + 1, hdr.length - 1); cert->public_key_len = hdr.length - 1; wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey", cert->public_key, cert->public_key_len); return 0;}static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, const u8 **next){ struct asn1_hdr hdr; const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end; struct asn1_oid oid; char **fieldp; /* * Name ::= CHOICE { RDNSequence } * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue * AttributeTypeAndValue ::= SEQUENCE { * type AttributeType, * value AttributeValue * } * AttributeType ::= OBJECT IDENTIFIER * AttributeValue ::= ANY DEFINED BY AttributeType */ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(Name / RDNSequencer) - found class %d tag 0x%x", hdr.class, hdr.tag); return -1; } pos = hdr.payload; if (pos + hdr.length > buf + len) return -1; end = *next = pos + hdr.length; while (pos < end) { if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) { wpa_printf(MSG_DEBUG, "X509: Expected SET " "(RelativeDistinguishedName) - found class " "%d tag 0x%x", hdr.class, hdr.tag); x509_free_name(name); return -1; } set_pos = hdr.payload; pos = set_end = hdr.payload + hdr.length; if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE) { wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE " "(AttributeTypeAndValue) - found class %d " "tag 0x%x", hdr.class, hdr.tag); x509_free_name(name); return -1; } seq_pos = hdr.payload; seq_end = hdr.payload + hdr.length; if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) { x509_free_name(name); return -1; } if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 || hdr.class != ASN1_CLASS_UNIVERSAL) { wpa_printf(MSG_DEBUG, "X509: Failed to parse " "AttributeValue"); x509_free_name(name); return -1; } /* RFC 3280: * MUST: country, organization, organizational-unit, * distinguished name qualifier, state or province name, * common name, serial number. * SHOULD: locality, title, surname, given name, initials, * pseudonym, generation qualifier. * MUST: domainComponent (RFC 2247). */ fieldp = NULL; if (oid.len == 4 && oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) { /* id-at ::= 2.5.4 */ switch (oid.oid[3]) { case 3: /* commonName */ fieldp = &name->cn; break; case 6: /* countryName */ fieldp = &name->c; break; case 7: /* localityName */ fieldp = &name->l; break; case 8: /* stateOrProvinceName */ fieldp = &name->st; break; case 10: /* organizationName */ fieldp = &name->o; break; case 11: /* organizationalUnitName */ fieldp = &name->ou; break; } } else if (oid.len == 7 && oid.oid[0] == 1 && oid.oid[1] == 2 && oid.oid[2] == 840 && oid.oid[3] == 113549 && oid.oid[4] == 1 && oid.oid[5] == 9 && oid.oid[6] == 1) { /* 1.2.840.113549.1.9.1 - e-mailAddress */ fieldp = &name->email; } if (fieldp == NULL) { wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID", (u8 *) oid.oid, oid.len * sizeof(oid.oid[0])); wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data", hdr.payload, hdr.length); continue; } os_free(*fieldp); *fieldp = os_malloc(hdr.length + 1); if (*fieldp == NULL) { x509_free_name(name); return -1; } os_memcpy(*fieldp, hdr.payload, hdr.length); (*fieldp)[hdr.length] = '\0'; } return 0;}/** * x509_name_string - Convert an X.509 certificate name into a string * @name: Name to convert * @buf: Buffer for the string * @len: Maximum buffer length */void x509_name_string(struct x509_name *name, char *buf, size_t len){ char *pos, *end; int ret; if (len == 0) return; pos = buf; end = buf + len; if (name->c) { ret = os_snprintf(pos, end - pos, "C=%s, ", name->c); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (name->st) { ret = os_snprintf(pos, end - pos, "ST=%s, ", name->st); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (name->l) { ret = os_snprintf(pos, end - pos, "L=%s, ", name->l); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (name->o) { ret = os_snprintf(pos, end - pos, "O=%s, ", name->o); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (name->ou) { ret = os_snprintf(pos, end - pos, "OU=%s, ", name->ou); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (name->cn) { ret = os_snprintf(pos, end - pos, "CN=%s, ", name->cn); if (ret < 0 || ret >= end - pos) goto done; pos += ret; } if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') { *pos-- = '\0'; *pos-- = '\0'; } if (name->email) { ret = os_snprintf(pos, end - pos, "/emailAddress=%s", name->email); if (ret < 0 || ret >= end - pos) goto done; pos += ret; }done: end[-1] = '\0';}static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag, os_time_t *val){ const char *pos; int year, month, day, hour, min, sec; /* * Time ::= CHOICE { * utcTime UTCTime, * generalTime GeneralizedTime * } * * UTCTime: YYMMDDHHMMSSZ * GeneralizedTime: YYYYMMDDHHMMSSZ */ pos = (const char *) buf; switch (asn1_tag) { case ASN1_TAG_UTCTIME: if (len != 13 || buf[12] != 'Z') { wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " "UTCTime format", buf, len); return -1; } if (sscanf(pos, "%02d", &year) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " "UTCTime year", buf, len); return -1; } if (year < 50) year += 2000; else year += 1900; pos += 2; break; case ASN1_TAG_GENERALIZEDTIME: if (len != 15 || buf[14] != 'Z') { wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized " "GeneralizedTime format", buf, len); return -1; } if (sscanf(pos, "%04d", &year) != 1) { wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse " "GeneralizedTime year", buf, len); return -1; } pos += 4;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -