X.509: Add parsing of alternative name to internal TLS implementation
The alternative name extensions are now parsed, but the actual values are not yet used for alt. subject name matching.
This commit is contained in:
parent
4625a47f4b
commit
efe22727da
4 changed files with 254 additions and 16 deletions
|
@ -85,28 +85,16 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
|
|||
}
|
||||
|
||||
|
||||
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
|
||||
const u8 **next)
|
||||
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *pos, *end;
|
||||
unsigned long val;
|
||||
u8 tmp;
|
||||
|
||||
os_memset(oid, 0, sizeof(*oid));
|
||||
|
||||
if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
|
||||
return -1;
|
||||
|
||||
if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
|
||||
"tag 0x%x", hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = hdr.payload;
|
||||
end = hdr.payload + hdr.length;
|
||||
*next = end;
|
||||
pos = buf;
|
||||
end = buf + len;
|
||||
|
||||
while (pos < end) {
|
||||
val = 0;
|
||||
|
@ -141,6 +129,26 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
|
|||
}
|
||||
|
||||
|
||||
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
|
||||
const u8 **next)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
|
||||
if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
|
||||
return -1;
|
||||
|
||||
if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
|
||||
"tag 0x%x", hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*next = hdr.payload + hdr.length;
|
||||
|
||||
return asn1_parse_oid(hdr.payload, hdr.length, oid);
|
||||
}
|
||||
|
||||
|
||||
void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
|
||||
{
|
||||
char *pos = buf;
|
||||
|
|
|
@ -63,6 +63,7 @@ struct asn1_oid {
|
|||
|
||||
|
||||
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
|
||||
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid);
|
||||
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
|
||||
const u8 **next);
|
||||
void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
|
||||
|
|
221
src/tls/x509v3.c
221
src/tls/x509v3.c
|
@ -34,6 +34,15 @@ static void x509_free_name(struct x509_name *name)
|
|||
os_free(name->email);
|
||||
name->cn = name->c = name->l = name->st = name->o = name->ou = NULL;
|
||||
name->email = NULL;
|
||||
|
||||
os_free(name->alt_email);
|
||||
os_free(name->dns);
|
||||
os_free(name->uri);
|
||||
os_free(name->ip);
|
||||
name->alt_email = name->dns = name->uri = NULL;
|
||||
name->ip = NULL;
|
||||
name->ip_len = 0;
|
||||
os_memset(&name->rid, 0, sizeof(name->rid));
|
||||
}
|
||||
|
||||
|
||||
|
@ -815,6 +824,213 @@ static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
|
|||
}
|
||||
|
||||
|
||||
static int x509_parse_alt_name_rfc8222(struct x509_name *name,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
/* rfc822Name IA5String */
|
||||
wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - rfc822Name", pos, len);
|
||||
os_free(name->alt_email);
|
||||
name->alt_email = os_zalloc(len + 1);
|
||||
if (name->alt_email == NULL)
|
||||
return -1;
|
||||
os_memcpy(name->alt_email, pos, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_alt_name_dns(struct x509_name *name,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
/* dNSName IA5String */
|
||||
wpa_hexdump_ascii(MSG_MSGDUMP, "X509: altName - dNSName", pos, len);
|
||||
os_free(name->dns);
|
||||
name->dns = os_zalloc(len + 1);
|
||||
if (name->dns == NULL)
|
||||
return -1;
|
||||
os_memcpy(name->dns, pos, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_alt_name_uri(struct x509_name *name,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
/* uniformResourceIdentifier IA5String */
|
||||
wpa_hexdump_ascii(MSG_MSGDUMP,
|
||||
"X509: altName - uniformResourceIdentifier",
|
||||
pos, len);
|
||||
os_free(name->uri);
|
||||
name->uri = os_zalloc(len + 1);
|
||||
if (name->uri == NULL)
|
||||
return -1;
|
||||
os_memcpy(name->uri, pos, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_alt_name_ip(struct x509_name *name,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
/* iPAddress OCTET STRING */
|
||||
wpa_hexdump(MSG_MSGDUMP, "X509: altName - iPAddress", pos, len);
|
||||
os_free(name->ip);
|
||||
name->ip = os_malloc(len);
|
||||
if (name->ip == NULL)
|
||||
return -1;
|
||||
os_memcpy(name->ip, pos, len);
|
||||
name->ip_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_alt_name_rid(struct x509_name *name,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
/* registeredID OBJECT IDENTIFIER */
|
||||
if (asn1_parse_oid(pos, len, &name->rid) < 0)
|
||||
return -1;
|
||||
|
||||
asn1_oid_to_str(&name->rid, buf, sizeof(buf));
|
||||
wpa_printf(MSG_MSGDUMP, "X509: altName - registeredID: %s", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_ext_alt_name(struct x509_name *name,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *p, *end;
|
||||
|
||||
/*
|
||||
* GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
|
||||
*
|
||||
* GeneralName ::= CHOICE {
|
||||
* otherName [0] OtherName,
|
||||
* rfc822Name [1] IA5String,
|
||||
* dNSName [2] IA5String,
|
||||
* x400Address [3] ORAddress,
|
||||
* directoryName [4] Name,
|
||||
* ediPartyName [5] EDIPartyName,
|
||||
* uniformResourceIdentifier [6] IA5String,
|
||||
* iPAddress [7] OCTET STRING,
|
||||
* registeredID [8] OBJECT IDENTIFIER }
|
||||
*
|
||||
* OtherName ::= SEQUENCE {
|
||||
* type-id OBJECT IDENTIFIER,
|
||||
* value [0] EXPLICIT ANY DEFINED BY type-id }
|
||||
*
|
||||
* EDIPartyName ::= SEQUENCE {
|
||||
* nameAssigner [0] DirectoryString OPTIONAL,
|
||||
* partyName [1] DirectoryString }
|
||||
*/
|
||||
|
||||
for (p = pos, end = pos + len; p < end; p = hdr.payload + hdr.length) {
|
||||
int res;
|
||||
|
||||
if (asn1_get_next(p, end - p, &hdr) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "X509: Failed to parse "
|
||||
"SubjectAltName item");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC)
|
||||
continue;
|
||||
|
||||
switch (hdr.tag) {
|
||||
case 1:
|
||||
res = x509_parse_alt_name_rfc8222(name, hdr.payload,
|
||||
hdr.length);
|
||||
break;
|
||||
case 2:
|
||||
res = x509_parse_alt_name_dns(name, hdr.payload,
|
||||
hdr.length);
|
||||
break;
|
||||
case 6:
|
||||
res = x509_parse_alt_name_uri(name, hdr.payload,
|
||||
hdr.length);
|
||||
break;
|
||||
case 7:
|
||||
res = x509_parse_alt_name_ip(name, hdr.payload,
|
||||
hdr.length);
|
||||
break;
|
||||
case 8:
|
||||
res = x509_parse_alt_name_rid(name, hdr.payload,
|
||||
hdr.length);
|
||||
break;
|
||||
case 0: /* TODO: otherName */
|
||||
case 3: /* TODO: x500Address */
|
||||
case 4: /* TODO: directoryName */
|
||||
case 5: /* TODO: ediPartyName */
|
||||
default:
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_ext_subject_alt_name(struct x509_certificate *cert,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
|
||||
/* SubjectAltName ::= GeneralNames */
|
||||
|
||||
if (asn1_get_next(pos, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
|
||||
"SubjectAltName; found %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "X509: SubjectAltName");
|
||||
cert->extensions_present |= X509_EXT_SUBJECT_ALT_NAME;
|
||||
|
||||
if (hdr.length == 0)
|
||||
return 0;
|
||||
|
||||
return x509_parse_ext_alt_name(&cert->subject, hdr.payload,
|
||||
hdr.length);
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
|
||||
const u8 *pos, size_t len)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
|
||||
/* IssuerAltName ::= GeneralNames */
|
||||
|
||||
if (asn1_get_next(pos, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
|
||||
"IssuerAltName; found %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "X509: IssuerAltName");
|
||||
cert->extensions_present |= X509_EXT_ISSUER_ALT_NAME;
|
||||
|
||||
if (hdr.length == 0)
|
||||
return 0;
|
||||
|
||||
return x509_parse_ext_alt_name(&cert->issuer, hdr.payload,
|
||||
hdr.length);
|
||||
}
|
||||
|
||||
|
||||
static int x509_parse_extension_data(struct x509_certificate *cert,
|
||||
struct asn1_oid *oid,
|
||||
const u8 *pos, size_t len)
|
||||
|
@ -824,7 +1040,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
|
|||
|
||||
/* TODO: add other extensions required by RFC 3280, Ch 4.2:
|
||||
* certificate policies (section 4.2.1.5)
|
||||
* the subject alternative name (section 4.2.1.7)
|
||||
* name constraints (section 4.2.1.11)
|
||||
* policy constraints (section 4.2.1.12)
|
||||
* extended key usage (section 4.2.1.13)
|
||||
|
@ -833,6 +1048,10 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
|
|||
switch (oid->oid[3]) {
|
||||
case 15: /* id-ce-keyUsage */
|
||||
return x509_parse_ext_key_usage(cert, pos, len);
|
||||
case 17: /* id-ce-subjectAltName */
|
||||
return x509_parse_ext_subject_alt_name(cert, pos, len);
|
||||
case 18: /* id-ce-issuerAltName */
|
||||
return x509_parse_ext_issuer_alt_name(cert, pos, len);
|
||||
case 19: /* id-ce-basicConstraints */
|
||||
return x509_parse_ext_basic_constraints(cert, pos, len);
|
||||
default:
|
||||
|
|
|
@ -29,6 +29,14 @@ struct x509_name {
|
|||
char *o; /* organizationName */
|
||||
char *ou; /* organizationalUnitName */
|
||||
char *email; /* emailAddress */
|
||||
|
||||
/* from alternative name extension */
|
||||
char *alt_email; /* rfc822Name */
|
||||
char *dns; /* dNSName */
|
||||
char *uri; /* uniformResourceIdentifier */
|
||||
u8 *ip; /* iPAddress */
|
||||
size_t ip_len; /* IPv4: 4, IPv6: 16 */
|
||||
struct asn1_oid rid; /* registeredID */
|
||||
};
|
||||
|
||||
struct x509_certificate {
|
||||
|
@ -52,6 +60,8 @@ struct x509_certificate {
|
|||
#define X509_EXT_BASIC_CONSTRAINTS (1 << 0)
|
||||
#define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1)
|
||||
#define X509_EXT_KEY_USAGE (1 << 2)
|
||||
#define X509_EXT_SUBJECT_ALT_NAME (1 << 3)
|
||||
#define X509_EXT_ISSUER_ALT_NAME (1 << 4)
|
||||
|
||||
/* BasicConstraints */
|
||||
int ca; /* cA */
|
||||
|
|
Loading…
Reference in a new issue