Commit 441df990 by Carlos Martín Nieto

ssl: look up the last CN the alternative names don't match

parent 3f9eb1e5
......@@ -219,12 +219,15 @@ static int verify_server_cert(git_transport *t, const char *host)
{
X509 *cert;
X509_NAME *peer_name;
char buf[1024];
ASN1_STRING *str;
unsigned char *peer_cn = NULL;
int matched = -1, type = GEN_DNS;
GENERAL_NAMES *alts;
struct in6_addr addr6;
struct in_addr addr4;
void *addr;
int i = -1,j;
/* Try to parse the host as an IP address to see if it is */
if (inet_pton(AF_INET, host, &addr4)) {
......@@ -243,7 +246,7 @@ static int verify_server_cert(git_transport *t, const char *host)
/* Check the alternative names */
alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (alts) {
int num, i;
int num;
num = sk_GENERAL_NAME_num(alts);
for (i = 0; i < num && matched != 1; i++) {
......@@ -257,7 +260,7 @@ static int verify_server_cert(git_transport *t, const char *host)
if (type == GEN_DNS) {
/* If it contains embedded NULs, don't even try */
if (namelen != strnlen(name, namelen))
if (memchr(name, '\0', namelen))
continue;
if (check_host_name(name, host) < 0)
......@@ -272,22 +275,62 @@ static int verify_server_cert(git_transport *t, const char *host)
}
GENERAL_NAMES_free(alts);
if (matched == 0) {
giterr_set(GITERR_SSL, "Certificate host name check failed");
return -1;
}
if (matched == 0)
goto on_error;
if (matched == 1)
return 0;
/* If no alternative names are available, check the common name */
peer_name = X509_get_subject_name(cert);
X509_NAME_get_text_by_NID(peer_name, NID_commonName, buf, sizeof(buf));
if (strcasecmp(host, buf)) {
giterr_set(GITERR_NET, "CN %s doesn't match host %s\n", buf, host);
return -1;
if (peer_name == NULL)
goto on_error;
if (peer_name) {
/* Get the index of the last CN entry */
while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0)
i = j;
}
if (i < 0)
goto on_error;
str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i));
if (str == NULL)
goto on_error;
/* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) {
int size = ASN1_STRING_length(str);
if (size > 0) {
peer_cn = OPENSSL_malloc(size + 1);
GITERR_CHECK_ALLOC(peer_cn);
memcpy(peer_cn, ASN1_STRING_data(str), size);
peer_cn[size] = '\0';
}
} else {
int size = ASN1_STRING_to_UTF8(&peer_cn, str);
GITERR_CHECK_ALLOC(peer_cn);
if (memchr(peer_cn, '\0', size))
goto cert_fail;
}
if (check_host_name((char *)peer_cn, host) < 0)
goto cert_fail;
OPENSSL_free(peer_cn);
return 0;
on_error:
OPENSSL_free(peer_cn);
return ssl_set_error(&t->ssl, 0);
cert_fail:
OPENSSL_free(peer_cn);
giterr_set(GITERR_SSL, "Certificate host name check failed");
return -1;
}
static int ssl_setup(git_transport *t, const char *host)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment