Commit b2ed778ac0e964ebe5a77945b9c076ee28a93695

Edward Thomson 2018-11-18T22:20:10

http transport: reset error message on cert failure Store the error message from the underlying TLS library before calling the certificate callback. If it refuses to act (demonstrated by returning GIT_PASSTHROUGH) then restore the error message. Otherwise, if the callback does not set an error message, set a sensible default that implicates the callback itself.

diff --git a/src/transports/http.c b/src/transports/http.c
index 82ae77d..65b5f5f 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -692,25 +692,25 @@ static int check_certificate(
 	void *cert_cb_payload)
 {
 	git_cert *cert;
+	git_error_state last_error = {0};
 	int error;
 
 	if ((error = git_stream_certificate(&cert, stream)) < 0)
 		return error;
 
-	giterr_clear();
-	error = cert_cb(cert, is_valid, url->host, cert_cb_payload);
+	giterr_state_capture(&last_error, GIT_ECERTIFICATE);
 
-	if (error == GIT_PASSTHROUGH)
-		error = is_valid ? 0 : GIT_ECERTIFICATE;
+	error = cert_cb(cert, is_valid, url->host, cert_cb_payload);
 
-	if (error) {
-		if (!giterr_last())
-			giterr_set(GITERR_NET, "user cancelled certificate check");
+	if (error == GIT_PASSTHROUGH && !is_valid)
+		return giterr_state_restore(&last_error);
+	else if (error == GIT_PASSTHROUGH)
+		error = 0;
+	else if (error && !giterr_last())
+		giterr_set(GITERR_NET, "user rejected certificate for %s", url->host);
 
-		return error;
-	}
-
-	return 0;
+	giterr_state_free(&last_error);
+	return error;
 }
 
 static int http_connect(http_subtransport *t)