mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-08 19:51:31 +00:00
ssl: look up the last CN the alternative names don't match
This commit is contained in:
parent
3f9eb1e502
commit
441df990b4
65
src/netops.c
65
src/netops.c
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user