Also return success in the domain_mask check if any of the DNSNames in the peer certificate's subjectAltName extension matches any of the mask strings supplied. --- ell/tls.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/ell/tls.c b/ell/tls.c index 3fe2ff5..f1d73bd 100644 --- a/ell/tls.c +++ b/ell/tls.c @@ -675,6 +675,10 @@ ok_next: static const struct asn1_oid dn_common_name_oid = { 3, { 0x55, 0x04, 0x03 } }; +static const struct asn1_oid subject_alt_name_oid = + { 3, { 0x55, 0x1d, 0x11 } }; + +#define SAN_DNS_NAME_ID ASN1_CONTEXT_IMPLICIT(2) static bool tls_cert_domains_match_mask(struct l_cert *cert, char **mask) { @@ -682,10 +686,14 @@ static bool tls_cert_domains_match_mask(struct l_cert *cert, char **mask) size_t dn_size; const char *cn = NULL; size_t cn_len; + const uint8_t *san; + size_t san_len; + uint8_t san_tag; + char **i; /* * Retrieve the Common Name from the Subject DN and check if it - * matches. TODO: possibly also look at SubjectAltName. + * matches. */ dn = l_cert_get_dn(cert, &dn_size); @@ -725,12 +733,43 @@ static bool tls_cert_domains_match_mask(struct l_cert *cert, char **mask) } } - if (!cn) + if (cn) + for (i = mask; *i; i++) + if (tls_domain_match_mask(cn, cn_len, *i, strlen(*i))) + return true; + + /* + * Locate SubjectAltName (RFC5280 Section 4.2.1.6) and descend into + * the sole SEQUENCE element, check if any DNSName matches. + */ + san = cert_get_extension(cert, &subject_alt_name_oid, NULL, &san_len); + if (!san) return false; - for (; *mask; mask++) - if (tls_domain_match_mask(cn, cn_len, *mask, strlen(*mask))) - return true; + san = asn1_der_find_elem(san, san_len, 0, &san_tag, &san_len); + if (unlikely(!san || san_tag != ASN1_ID_SEQUENCE)) + return NULL; + + end = san + san_len; + while (san < end) { + const uint8_t *value; + uint8_t tag; + size_t len; + + value = asn1_der_find_elem(san, end - san, SAN_DNS_NAME_ID, + &tag, &len); + if (!value) + return false; + + /* Type is implicitly IA5STRING */ + + for (i = mask; *i; i++) + if (tls_domain_match_mask((const char *) value, len, + *i, strlen(*i))) + return true; + + san = value + len; + } return false; } -- 2.20.1