mirror of
https://github.com/libgit2/libgit2.git
synced 2026-06-22 06:26:26 +00:00
net: move rfc2818 hostname / wildcard matching to util
This commit is contained in:
@@ -83,42 +83,3 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons)
|
||||
memset(buf->data + cons, 0x0, buf->len - buf->offset);
|
||||
buf->offset -= cons;
|
||||
}
|
||||
|
||||
/* Match host names according to RFC 2818 rules */
|
||||
int gitno__match_host(const char *pattern, const char *host)
|
||||
{
|
||||
for (;;) {
|
||||
char c = git__tolower(*pattern++);
|
||||
|
||||
if (c == '\0')
|
||||
return *host ? -1 : 0;
|
||||
|
||||
if (c == '*') {
|
||||
c = *pattern;
|
||||
/* '*' at the end matches everything left */
|
||||
if (c == '\0')
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We've found a pattern, so move towards the next matching
|
||||
* char. The '.' is handled specially because wildcards aren't
|
||||
* allowed to cross subdomains.
|
||||
*/
|
||||
|
||||
while(*host) {
|
||||
char h = git__tolower(*host);
|
||||
if (c == h)
|
||||
return gitno__match_host(pattern, host++);
|
||||
if (h == '.')
|
||||
return gitno__match_host(pattern, host);
|
||||
host++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (c != git__tolower(*host++))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -45,19 +45,6 @@ enum {
|
||||
GITNO_CONNECT_SSL = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the name in a cert matches the wanted hostname
|
||||
*
|
||||
* Check if a pattern from a certificate matches the hostname we
|
||||
* wanted to connect to according to RFC2818 rules (which specifies
|
||||
* HTTP over TLS). Mainly, an asterisk matches anything, but is
|
||||
* limited to a single url component.
|
||||
*
|
||||
* Note that this does not set an error message. It expects the user
|
||||
* to provide the message for the user.
|
||||
*/
|
||||
int gitno__match_host(const char *pattern, const char *host);
|
||||
|
||||
void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len);
|
||||
void gitno_buffer_setup_callback(gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data);
|
||||
int gitno_recv(gitno_buffer *buf);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "settings.h"
|
||||
#include "posix.h"
|
||||
#include "stream.h"
|
||||
#include "net.h"
|
||||
#include "streams/socket.h"
|
||||
#include "netops.h"
|
||||
#include "git2/transport.h"
|
||||
@@ -357,15 +358,10 @@ static int ssl_teardown(SSL *ssl)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_host_name(const char *name, const char *host)
|
||||
static bool check_host_name(const char *host, const char *name)
|
||||
{
|
||||
if (!strcasecmp(name, host))
|
||||
return 0;
|
||||
|
||||
if (gitno__match_host(name, host) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return !strcasecmp(host, name) ||
|
||||
git_net_hostname_matches_cert(host, name);
|
||||
}
|
||||
|
||||
static int verify_server_cert(SSL *ssl, const char *host)
|
||||
@@ -425,10 +421,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
|
||||
if (memchr(name, '\0', namelen))
|
||||
continue;
|
||||
|
||||
if (check_host_name(name, host) < 0)
|
||||
matched = 0;
|
||||
else
|
||||
matched = 1;
|
||||
matched = !!check_host_name(host, name);
|
||||
} else if (type == GEN_IPADD) {
|
||||
/* Here name isn't so much a name but a binary representation of the IP */
|
||||
matched = addr && !!memcmp(name, addr, namelen);
|
||||
@@ -481,7 +474,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
|
||||
goto cert_fail_name;
|
||||
}
|
||||
|
||||
if (check_host_name((char *)peer_cn, host) < 0)
|
||||
if (!check_host_name(host, (char *)peer_cn))
|
||||
goto cert_fail_name;
|
||||
|
||||
goto cleanup;
|
||||
|
||||
@@ -19,6 +19,50 @@
|
||||
#define DEFAULT_PORT_GIT "9418"
|
||||
#define DEFAULT_PORT_SSH "22"
|
||||
|
||||
bool git_net_hostname_matches_cert(
|
||||
const char *hostname,
|
||||
const char *pattern)
|
||||
{
|
||||
for (;;) {
|
||||
char c = git__tolower(*pattern++);
|
||||
|
||||
if (c == '\0')
|
||||
return *hostname ? false : true;
|
||||
|
||||
if (c == '*') {
|
||||
c = *pattern;
|
||||
|
||||
/* '*' at the end matches everything left */
|
||||
if (c == '\0')
|
||||
return true;
|
||||
|
||||
/*
|
||||
* We've found a pattern, so move towards the
|
||||
* next matching char. The '.' is handled
|
||||
* specially because wildcards aren't allowed
|
||||
* to cross subdomains.
|
||||
*/
|
||||
while(*hostname) {
|
||||
char h = git__tolower(*hostname);
|
||||
|
||||
if (h == c)
|
||||
return git_net_hostname_matches_cert(hostname++, pattern);
|
||||
else if (h == '.')
|
||||
return git_net_hostname_matches_cert(hostname, pattern);
|
||||
|
||||
hostname++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c != git__tolower(*hostname++))
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool git_net_str_is_url(const char *str)
|
||||
{
|
||||
const char *c;
|
||||
|
||||
@@ -9,6 +9,23 @@
|
||||
|
||||
#include "git2_util.h"
|
||||
|
||||
/*
|
||||
* Hostname handling
|
||||
*/
|
||||
|
||||
/*
|
||||
* See if a given hostname matches a certificate name pattern, according
|
||||
* to RFC2818 rules (which specifies HTTP over TLS). Mainly, an asterisk
|
||||
* matches anything, but is limited to a single url component.
|
||||
*/
|
||||
extern bool git_net_hostname_matches_cert(
|
||||
const char *hostname,
|
||||
const char *pattern);
|
||||
|
||||
/*
|
||||
* URL handling
|
||||
*/
|
||||
|
||||
typedef struct git_net_url {
|
||||
char *scheme;
|
||||
char *host;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "netops.h"
|
||||
|
||||
void test_network_matchhost__match(void)
|
||||
{
|
||||
cl_git_pass(gitno__match_host("*.example.org", "www.example.org"));
|
||||
cl_git_pass(gitno__match_host("*.foo.example.org", "www.foo.example.org"));
|
||||
cl_git_fail(gitno__match_host("*.foo.example.org", "foo.example.org"));
|
||||
cl_git_fail(gitno__match_host("*.foo.example.org", "www.example.org"));
|
||||
cl_git_fail(gitno__match_host("*.example.org", "example.org"));
|
||||
cl_git_fail(gitno__match_host("*.example.org", "www.foo.example.org"));
|
||||
cl_git_fail(gitno__match_host("*.example.org", "blah.www.www.example.org"));
|
||||
}
|
||||
13
tests/util/hostname.c
Normal file
13
tests/util/hostname.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "net.h"
|
||||
|
||||
void test_hostname__matches_cert(void)
|
||||
{
|
||||
cl_assert_equal_b(true, git_net_hostname_matches_cert("www.example.org", "*.example.org"));
|
||||
cl_assert_equal_b(true, git_net_hostname_matches_cert("www.foo.example.org", "*.foo.example.org"));
|
||||
cl_assert_equal_b(false, git_net_hostname_matches_cert("foo.example.org", "*.foo.example.org"));
|
||||
cl_assert_equal_b(false, git_net_hostname_matches_cert("www.example.org", "*.foo.example.org"));
|
||||
cl_assert_equal_b(false, git_net_hostname_matches_cert("example.org", "*.example.org"));
|
||||
cl_assert_equal_b(false, git_net_hostname_matches_cert("www.foo.example.org", "*.example.org"));
|
||||
cl_assert_equal_b(false, git_net_hostname_matches_cert("blah.www.www.example.org", "*.example.org"));
|
||||
}
|
||||
Reference in New Issue
Block a user