summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-12-30 12:42:42 -0500
committerEdward Thomson <ethomson@github.com>2017-01-21 23:15:54 +0000
commit1910a04adbdd58e5517b38488433f655066c3586 (patch)
tree07ab0dde387a45cc65cee42ad92c3aabd5d44654
parent0418d3b7a8469464b9d22d1646034fcca4bda346 (diff)
downloadlibgit2-1910a04adbdd58e5517b38488433f655066c3586.tar.gz
winhttp: set proper cert failure error messages
Set up a WinHTTP status callback; inspect the WinHTTP status for WINHTTP_CALLBACK_STATUS_SECURE_FAILURE, and convert the status code to a useful message for callers.
-rw-r--r--src/transports/winhttp.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index 79b3ac6b4..0d304d6b3 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -242,8 +242,12 @@ static int certificate_check(winhttp_stream *s, int valid)
git_cert_x509 cert;
/* If there is no override, we should fail if WinHTTP doesn't think it's fine */
- if (t->owner->certificate_check_cb == NULL && !valid)
+ if (t->owner->certificate_check_cb == NULL && !valid) {
+ if (!giterr_last())
+ giterr_set(GITERR_NET, "unknown certificate check failure");
+
return GIT_ECERTIFICATE;
+ }
if (t->owner->certificate_check_cb == NULL || !t->connection_data.use_ssl)
return 0;
@@ -691,6 +695,38 @@ static int user_agent(git_buf *ua)
return git_buf_putc(ua, ')');
}
+static void CALLBACK winhttp_status(
+ HINTERNET connection,
+ DWORD_PTR ctx,
+ DWORD code,
+ LPVOID info,
+ DWORD info_len)
+{
+ DWORD status;
+
+ if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
+ return;
+
+ status = *((DWORD *)info);
+
+ if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
+ giterr_set(GITERR_NET, "SSL certificate issued for different common name");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
+ giterr_set(GITERR_NET, "SSL certificate has expired");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
+ giterr_set(GITERR_NET, "SSL certificate signed by unknown CA");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
+ giterr_set(GITERR_NET, "SSL certificate is invalid");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
+ giterr_set(GITERR_NET, "certificate revocation check failed");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
+ giterr_set(GITERR_NET, "SSL certificate was revoked");
+ else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
+ giterr_set(GITERR_NET, "security libraries could not be loaded");
+ else
+ giterr_set(GITERR_NET, "unknown security error %d", status);
+}
+
static int winhttp_connect(
winhttp_subtransport *t)
{
@@ -760,6 +796,11 @@ static int winhttp_connect(
goto on_error;
}
+ if (WinHttpSetStatusCallback(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
+ giterr_set(GITERR_OS, "failed to set status callback");
+ goto on_error;
+ }
+
error = 0;
on_error:
@@ -798,16 +839,15 @@ static int send_request(winhttp_stream *s, size_t len, int ignore_length)
int request_failed = 0, cert_valid = 1, error = 0;
DWORD ignore_flags;
- if ((error = do_send_request(s, len, ignore_length)) < 0)
- request_failed = 1;
-
- if (request_failed) {
+ giterr_clear();
+ if ((error = do_send_request(s, len, ignore_length)) < 0) {
if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
giterr_set(GITERR_OS, "failed to send request");
return -1;
- } else {
- cert_valid = 0;
}
+
+ request_failed = 1;
+ cert_valid = 0;
}
giterr_clear();