Skip to content

Commit 6e4bbf2

Browse files
committed
net: move rfc2818 hostname / wildcard matching to util
1 parent dbe343b commit 6e4bbf2

File tree

7 files changed

+80
-78
lines changed

7 files changed

+80
-78
lines changed

src/libgit2/netops.c

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -83,42 +83,3 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons)
8383
memset(buf->data + cons, 0x0, buf->len - buf->offset);
8484
buf->offset -= cons;
8585
}
86-
87-
/* Match host names according to RFC 2818 rules */
88-
int gitno__match_host(const char *pattern, const char *host)
89-
{
90-
for (;;) {
91-
char c = git__tolower(*pattern++);
92-
93-
if (c == '\0')
94-
return *host ? -1 : 0;
95-
96-
if (c == '*') {
97-
c = *pattern;
98-
/* '*' at the end matches everything left */
99-
if (c == '\0')
100-
return 0;
101-
102-
/*
103-
* We've found a pattern, so move towards the next matching
104-
* char. The '.' is handled specially because wildcards aren't
105-
* allowed to cross subdomains.
106-
*/
107-
108-
while(*host) {
109-
char h = git__tolower(*host);
110-
if (c == h)
111-
return gitno__match_host(pattern, host++);
112-
if (h == '.')
113-
return gitno__match_host(pattern, host);
114-
host++;
115-
}
116-
return -1;
117-
}
118-
119-
if (c != git__tolower(*host++))
120-
return -1;
121-
}
122-
123-
return -1;
124-
}

src/libgit2/netops.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,6 @@ enum {
4545
GITNO_CONNECT_SSL = 1
4646
};
4747

48-
/**
49-
* Check if the name in a cert matches the wanted hostname
50-
*
51-
* Check if a pattern from a certificate matches the hostname we
52-
* wanted to connect to according to RFC2818 rules (which specifies
53-
* HTTP over TLS). Mainly, an asterisk matches anything, but is
54-
* limited to a single url component.
55-
*
56-
* Note that this does not set an error message. It expects the user
57-
* to provide the message for the user.
58-
*/
59-
int gitno__match_host(const char *pattern, const char *host);
60-
6148
void gitno_buffer_setup_fromstream(git_stream *st, gitno_buffer *buf, char *data, size_t len);
6249
void gitno_buffer_setup_callback(gitno_buffer *buf, char *data, size_t len, int (*recv)(gitno_buffer *buf), void *cb_data);
6350
int gitno_recv(gitno_buffer *buf);

src/libgit2/streams/openssl.c

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "settings.h"
1919
#include "posix.h"
2020
#include "stream.h"
21+
#include "net.h"
2122
#include "streams/socket.h"
2223
#include "netops.h"
2324
#include "git2/transport.h"
@@ -357,15 +358,10 @@ static int ssl_teardown(SSL *ssl)
357358
return ret;
358359
}
359360

360-
static int check_host_name(const char *name, const char *host)
361+
static bool check_host_name(const char *host, const char *name)
361362
{
362-
if (!strcasecmp(name, host))
363-
return 0;
364-
365-
if (gitno__match_host(name, host) < 0)
366-
return -1;
367-
368-
return 0;
363+
return !strcasecmp(host, name) ||
364+
git_net_hostname_matches_cert(host, name);
369365
}
370366

371367
static int verify_server_cert(SSL *ssl, const char *host)
@@ -425,10 +421,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
425421
if (memchr(name, '\0', namelen))
426422
continue;
427423

428-
if (check_host_name(name, host) < 0)
429-
matched = 0;
430-
else
431-
matched = 1;
424+
matched = !!check_host_name(host, name);
432425
} else if (type == GEN_IPADD) {
433426
/* Here name isn't so much a name but a binary representation of the IP */
434427
matched = addr && !!memcmp(name, addr, namelen);
@@ -481,7 +474,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
481474
goto cert_fail_name;
482475
}
483476

484-
if (check_host_name((char *)peer_cn, host) < 0)
477+
if (!check_host_name(host, (char *)peer_cn))
485478
goto cert_fail_name;
486479

487480
goto cleanup;

src/util/net.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,50 @@
1919
#define DEFAULT_PORT_GIT "9418"
2020
#define DEFAULT_PORT_SSH "22"
2121

22+
bool git_net_hostname_matches_cert(
23+
const char *hostname,
24+
const char *pattern)
25+
{
26+
for (;;) {
27+
char c = git__tolower(*pattern++);
28+
29+
if (c == '\0')
30+
return *hostname ? false : true;
31+
32+
if (c == '*') {
33+
c = *pattern;
34+
35+
/* '*' at the end matches everything left */
36+
if (c == '\0')
37+
return true;
38+
39+
/*
40+
* We've found a pattern, so move towards the
41+
* next matching char. The '.' is handled
42+
* specially because wildcards aren't allowed
43+
* to cross subdomains.
44+
*/
45+
while(*hostname) {
46+
char h = git__tolower(*hostname);
47+
48+
if (h == c)
49+
return git_net_hostname_matches_cert(hostname++, pattern);
50+
else if (h == '.')
51+
return git_net_hostname_matches_cert(hostname, pattern);
52+
53+
hostname++;
54+
}
55+
56+
return false;
57+
}
58+
59+
if (c != git__tolower(*hostname++))
60+
return false;
61+
}
62+
63+
return false;
64+
}
65+
2266
bool git_net_str_is_url(const char *str)
2367
{
2468
const char *c;

src/util/net.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,23 @@
99

1010
#include "git2_util.h"
1111

12+
/*
13+
* Hostname handling
14+
*/
15+
16+
/*
17+
* See if a given hostname matches a certificate name pattern, according
18+
* to RFC2818 rules (which specifies HTTP over TLS). Mainly, an asterisk
19+
* matches anything, but is limited to a single url component.
20+
*/
21+
extern bool git_net_hostname_matches_cert(
22+
const char *hostname,
23+
const char *pattern);
24+
25+
/*
26+
* URL handling
27+
*/
28+
1229
typedef struct git_net_url {
1330
char *scheme;
1431
char *host;

tests/libgit2/network/matchhost.c

Lines changed: 0 additions & 13 deletions
This file was deleted.

tests/util/hostname.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "clar_libgit2.h"
2+
#include "net.h"
3+
4+
void test_hostname__matches_cert(void)
5+
{
6+
cl_assert_equal_b(true, git_net_hostname_matches_cert("www.example.org", "*.example.org"));
7+
cl_assert_equal_b(true, git_net_hostname_matches_cert("www.foo.example.org", "*.foo.example.org"));
8+
cl_assert_equal_b(false, git_net_hostname_matches_cert("foo.example.org", "*.foo.example.org"));
9+
cl_assert_equal_b(false, git_net_hostname_matches_cert("www.example.org", "*.foo.example.org"));
10+
cl_assert_equal_b(false, git_net_hostname_matches_cert("example.org", "*.example.org"));
11+
cl_assert_equal_b(false, git_net_hostname_matches_cert("www.foo.example.org", "*.example.org"));
12+
cl_assert_equal_b(false, git_net_hostname_matches_cert("blah.www.www.example.org", "*.example.org"));
13+
}

0 commit comments

Comments
 (0)