Commit 9f7ad3c5d34d35a5ec2f34fa9cd8c92eff439329

Edward Thomson 2017-12-23T10:55:13

Merge pull request #4430 from tiennou/fix/openssl-x509-leak Free OpenSSL peer certificate

diff --git a/src/streams/openssl.c b/src/streams/openssl.c
index 2b24600..9d56607 100644
--- a/src/streams/openssl.c
+++ b/src/streams/openssl.c
@@ -332,7 +332,7 @@ static int check_host_name(const char *name, const char *host)
 
 static int verify_server_cert(SSL *ssl, const char *host)
 {
-	X509 *cert;
+	X509 *cert = NULL;
 	X509_NAME *peer_name;
 	ASN1_STRING *str;
 	unsigned char *peer_cn = NULL;
@@ -341,7 +341,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
 	struct in6_addr addr6;
 	struct in_addr addr4;
 	void *addr;
-	int i = -1,j;
+	int i = -1, j, error = 0;
 
 	if (SSL_get_verify_result(ssl) != X509_V_OK) {
 		giterr_set(GITERR_SSL, "the SSL certificate is invalid");
@@ -362,8 +362,9 @@ static int verify_server_cert(SSL *ssl, const char *host)
 
 	cert = SSL_get_peer_certificate(ssl);
 	if (!cert) {
+		error = -1;
 		giterr_set(GITERR_SSL, "the server did not provide a certificate");
-		return -1;
+		goto cleanup;
 	}
 
 	/* Check the alternative names */
@@ -401,8 +402,9 @@ static int verify_server_cert(SSL *ssl, const char *host)
 	if (matched == 0)
 		goto cert_fail_name;
 
-	if (matched == 1)
-		return 0;
+	if (matched == 1) {
+		goto cleanup;
+	}
 
 	/* If no alternative names are available, check the common name */
 	peer_name = X509_get_subject_name(cert);
@@ -444,18 +446,21 @@ static int verify_server_cert(SSL *ssl, const char *host)
 	if (check_host_name((char *)peer_cn, host) < 0)
 		goto cert_fail_name;
 
-	OPENSSL_free(peer_cn);
+	goto cleanup;
 
-	return 0;
+cert_fail_name:
+	error = GIT_ECERTIFICATE;
+	giterr_set(GITERR_SSL, "hostname does not match certificate");
+	goto cleanup;
 
 on_error:
-	OPENSSL_free(peer_cn);
-	return ssl_set_error(ssl, 0);
+	error = ssl_set_error(ssl, 0);
+	goto cleanup;
 
-cert_fail_name:
+cleanup:
+	X509_free(cert);
 	OPENSSL_free(peer_cn);
-	giterr_set(GITERR_SSL, "hostname does not match certificate");
-	return GIT_ECERTIFICATE;
+	return error;
 }
 
 typedef struct {