summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2014-06-30 22:31:14 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2014-06-30 22:37:19 +0200
commit168082ce13b3d9ec1f13bb8e46d12a796223684d (patch)
tree2e69d0f58327bccad6f5d5344e58cd7e5d7c53e8
parent5164790207758160da4ab97c9f8fcc44e41d46fa (diff)
downloadgnutls-168082ce13b3d9ec1f13bb8e46d12a796223684d.tar.gz
gnutls_x509_crt_check_hostname() checks text ip addresses as well.
That aligns the documentation with the implementation.
-rw-r--r--configure.ac2
-rw-r--r--lib/x509/rfc2818_hostname.c69
2 files changed, 70 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index e7c4d8b767..23a72f87f5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -151,7 +151,7 @@ AC_C_BIGENDIAN
dnl No fork on MinGW, disable some self-tests until we fix them.
dnl Check clock_gettime and pthread_mutex_lock in libc (avoid linking to other libs)
-AC_CHECK_FUNCS([fork inet_ntop getrusage getpwuid_r nanosleep daemon getpid clock_gettime iconv localtime vasprintf],,)
+AC_CHECK_FUNCS([fork inet_ntop inet_pton getrusage getpwuid_r nanosleep daemon getpid clock_gettime iconv localtime vasprintf],,)
AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork" != "no")
AC_LIB_HAVE_LINKFLAGS(rt,, [#include <time.h>
diff --git a/lib/x509/rfc2818_hostname.c b/lib/x509/rfc2818_hostname.c
index da2f2c1478..5a4caaa92c 100644
--- a/lib/x509/rfc2818_hostname.c
+++ b/lib/x509/rfc2818_hostname.c
@@ -24,6 +24,43 @@
#include <x509_int.h>
#include <common.h>
#include <gnutls_errors.h>
+#include <arpa/inet.h>
+
+static int
+check_ip(gnutls_x509_crt_t cert, const void *ip, unsigned ip_size)
+{
+ char temp[16];
+ size_t temp_size;
+ unsigned i;
+ int ret;
+
+ /* try matching against:
+ * 1) a IPaddress alternative name (subjectAltName) extension
+ * in the certificate
+ */
+
+ /* Check through all included subjectAltName extensions, comparing
+ * against all those of type IPAddress.
+ */
+ for (i = 0; !(ret < 0); i++) {
+ temp_size = sizeof(temp);
+ ret = gnutls_x509_crt_get_subject_alt_name(cert, i,
+ temp,
+ &temp_size,
+ NULL);
+
+ if (ret == GNUTLS_SAN_IPADDRESS) {
+ if (temp_size == ip_size && memcmp(temp, ip, ip_size) == 0)
+ return 1;
+ } else if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ ret = 0;
+ }
+ }
+
+ /* not found a matching IP
+ */
+ return 0;
+}
/**
* gnutls_x509_crt_check_hostname:
@@ -50,6 +87,38 @@ gnutls_x509_crt_check_hostname(gnutls_x509_crt_t cert,
int found_dnsname = 0;
int ret = 0;
int i = 0;
+ struct in_addr ipv4;
+ char *p = NULL;
+
+ /* check whether @hostname is an ip address */
+ if ((p=strchr(hostname, ':')) != NULL || inet_aton(hostname, &ipv4) != 0) {
+
+ if (p != NULL) {
+#ifdef HAVE_INET_PTON
+ struct in6_addr ipv6;
+
+ ret = inet_pton(AF_INET6, hostname, &ipv6);
+ if (ret == 0) {
+ gnutls_assert();
+ goto hostname_fallback;
+ }
+ ret = check_ip(cert, &ipv6, 16);
+#else
+ ret = 0;
+#endif
+ } else {
+ ret = check_ip(cert, &ipv4, 4);
+ }
+
+ if (ret != 0)
+ return ret;
+
+ /* There are several misconfigured servers, that place their IP
+ * in the DNS field of subjectAlternativeName. Don't break these
+ * configurations and verify the IP as it would have been a DNS name. */
+ }
+
+ hostname_fallback:
/* try matching against:
* 1) a DNS name as an alternative name (subjectAltName) extension