Mercurial > dovecot > core-2.2
changeset 22017:62660946454b
lib-ssl-iostream: Support IP address SANs
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Mon, 08 May 2017 13:35:35 +0300 |
parents | 6389f6b095af |
children | c635141adb77 |
files | src/lib-ssl-iostream/iostream-openssl-common.c |
diffstat | 1 files changed, 38 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-ssl-iostream/iostream-openssl-common.c Fri May 05 12:35:23 2017 +0300 +++ b/src/lib-ssl-iostream/iostream-openssl-common.c Mon May 08 13:35:35 2017 +0300 @@ -1,11 +1,13 @@ /* Copyright (c) 2009-2017 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "net.h" #include "str.h" #include "iostream-openssl.h" #include <openssl/x509v3.h> #include <openssl/err.h> +#include <arpa/inet.h> enum { DOVECOT_SSL_PROTO_SSLv2 = 0x01, @@ -101,6 +103,23 @@ return asn1_string_to_c(name->d.ia5); } +static int get_general_ip_addr(const GENERAL_NAME *name, struct ip_addr *ip_r) +{ + if (ASN1_STRING_type(name->d.ip) != V_ASN1_OCTET_STRING) + return 0; + const unsigned char *data = ASN1_STRING_get0_data(name->d.ip); + + if (name->d.ip->length == sizeof(ip_r->u.ip4.s_addr)) { + ip_r->family = AF_INET; + memcpy(&ip_r->u.ip4.s_addr, data, sizeof(ip_r->u.ip4.s_addr)); + } else if (name->d.ip->length == sizeof(ip_r->u.ip6.s6_addr)) { + ip_r->family = AF_INET6; + memcpy(ip_r->u.ip6.s6_addr, data, sizeof(ip_r->u.ip6.s6_addr)); + } else + return -1; + return 0; +} + static const char *get_cname(X509 *cert) { X509_NAME *name; @@ -140,6 +159,7 @@ X509 *cert; STACK_OF(GENERAL_NAME) *gnames; const GENERAL_NAME *gn; + struct ip_addr ip; const char *dnsname; bool dns_names = FALSE; unsigned int i, count; @@ -151,13 +171,31 @@ /* verify against SubjectAltNames */ gnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); count = gnames == NULL ? 0 : sk_GENERAL_NAME_num(gnames); + + i_zero(&ip); + /* try to convert verify_name to IP */ + if (inet_pton(AF_INET6, verify_name, &ip.u.ip6) == 1) + ip.family = AF_INET6; + else if (inet_pton(AF_INET, verify_name, &ip.u.ip4) == 1) + ip.family = AF_INET; + else + i_zero(&ip); + for (i = 0; i < count; i++) { gn = sk_GENERAL_NAME_value(gnames, i); + if (gn->type == GEN_DNS) { dns_names = TRUE; dnsname = get_general_dns_name(gn); if (openssl_hostname_equals(dnsname, verify_name)) break; + } else if (gn->type == GEN_IPADD) { + struct ip_addr ip_2; + i_zero(&ip_2); + dns_names = TRUE; + if (get_general_ip_addr(gn, &ip_2) == 0 && + net_ip_compare(&ip, &ip_2)) + break; } } sk_GENERAL_NAME_pop_free(gnames, GENERAL_NAME_free);