components/git/patches/imap-send.patch
author Craig Mohrman <craig.mohrman@oracle.com>
Fri, 03 Apr 2015 10:20:02 -0700
changeset 4050 253de46fd78c
permissions -rw-r--r--
20761309 problem in UTILITY/GIT 20460364 GIT should have some master test results to compare against
This patch fixes CVE-2013-0308.
It was created from a diff between the version 1.8.1.4 of this file
from the community and the current one.  The only changes to this file
are for addressing this CVE.
Here is the community diff:
https://github.com/gitster/git/commit/0ee7198f457c8ea031b09b528cfd88f0f0e630d8

--- git-1.7.9.2/imap-send.c_orig	2012-02-22 18:04:18.000000000 -0800
+++ git-1.7.9.2/imap-send.c	2015-03-25 12:23:29.465800340 -0700
@@ -31,6 +31,7 @@
 #else
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
+#include <openssl/x509v3.h>
 #endif
 
 struct store_conf {
@@ -266,12 +267,64 @@
 	}
 }
 
+#ifdef NO_OPENSSL
 static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
 {
-#ifdef NO_OPENSSL
 	fprintf(stderr, "SSL requested but SSL support not compiled in\n");
 	return -1;
+}
+
 #else
+
+static int host_matches(const char *host, const char *pattern)
+{
+	if (pattern[0] == '*' && pattern[1] == '.') {
+		pattern += 2;
+		if (!(host = strchr(host, '.')))
+			return 0;
+		host++;
+	}
+
+	return *host && *pattern && !strcasecmp(host, pattern);
+}
+
+static int verify_hostname(X509 *cert, const char *hostname)
+{
+	int len;
+	X509_NAME *subj;
+	char cname[1000];
+	int i, found;
+	STACK_OF(GENERAL_NAME) *subj_alt_names;
+
+	/* try the DNS subjectAltNames */
+	found = 0;
+	if ((subj_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL))) {
+		int num_subj_alt_names = sk_GENERAL_NAME_num(subj_alt_names);
+		for (i = 0; !found && i < num_subj_alt_names; i++) {
+			GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value(subj_alt_names, i);
+			if (subj_alt_name->type == GEN_DNS &&
+			    strlen((const char *)subj_alt_name->d.ia5->data) == (size_t)subj_alt_name->d.ia5->length &&
+			    host_matches(hostname, (const char *)(subj_alt_name->d.ia5->data)))
+				found = 1;
+		}
+		sk_GENERAL_NAME_pop_free(subj_alt_names, GENERAL_NAME_free);
+	}
+	if (found)
+		return 0;
+
+	/* try the common name */
+	if (!(subj = X509_get_subject_name(cert)))
+		return error("cannot get certificate subject");
+	if ((len = X509_NAME_get_text_by_NID(subj, NID_commonName, cname, sizeof(cname))) < 0)
+		return error("cannot get certificate common name");
+	if (strlen(cname) == (size_t)len && host_matches(hostname, cname))
+		return 0;
+	return error("certificate owner '%s' does not match hostname '%s'",
+		     cname, hostname);
+}
+
+static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify)
+{
 #if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
 	const SSL_METHOD *meth;
 #else
@@ -279,6 +332,7 @@
 #endif
 	SSL_CTX *ctx;
 	int ret;
+	X509 *cert;
 
 	SSL_library_init();
 	SSL_load_error_strings();
@@ -322,9 +376,18 @@
 		return -1;
 	}
 
+	if (verify) {
+		/* make sure the hostname matches that of the certificate */
+		cert = SSL_get_peer_certificate(sock->ssl);
+		if (!cert)
+			return error("unable to get peer certificate.");
+		if (verify_hostname(cert, server.host) < 0)
+			return -1;
+	}
+
 	return 0;
-#endif
 }
+#endif
 
 static int socket_read(struct imap_socket *sock, char *buf, int len)
 {
@@ -1022,7 +1085,7 @@
 
 	ret = socket_write(&ctx->imap->buf.sock, response, strlen(response));
 	if (ret != strlen(response))
-		return error("IMAP error: sending response failed\n");
+		return error("IMAP error: sending response failed");
 
 	free(response);