Commit 08545d36 by Carlos Martín Nieto

winhttp: credential check on successful connect

On successful connection, still ask the user whether they accept the server's certificate, indicating that WinHTTP would let it though.
parent 23ca0ad5
......@@ -16,6 +16,8 @@
#include "remote.h"
#include "repository.h"
#include <wincrypt.h>
#pragma comment(lib, "crypt32")
#include <winhttp.h>
#pragma comment(lib, "winhttp")
......@@ -203,6 +205,31 @@ static int fallback_cred_acquire_cb(
return error;
}
static int certificate_check(winhttp_stream *s, int valid)
{
int error;
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
PCERT_CONTEXT cert_ctx;
DWORD cert_ctx_size = sizeof(cert_ctx);
if (t->owner->certificate_check_cb == NULL)
return 0;
if (!WinHttpQueryOption(s->request, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert_ctx, &cert_ctx_size)) {
giterr_set(GITERR_OS, "failed to get server certificate");
return -1;
}
giterr_clear();
error = t->owner->certificate_check_cb(GIT_CERT_X509, cert_ctx->pbCertEncoded, cert_ctx->cbCertEncoded, valid, t->owner->cred_acquire_payload);
CertFreeCertificateContext(cert_ctx);
if (error < 0 && !giterr_last())
giterr_set(GITERR_NET, "user cancelled certificate check");
return error;
}
static int winhttp_stream_connect(winhttp_stream *s)
{
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
......@@ -384,6 +411,8 @@ static int winhttp_stream_connect(winhttp_stream *s)
goto on_error;
}
/* set up the certificate failure callback */
/* We've done everything up to calling WinHttpSendRequest. */
error = 0;
......@@ -537,6 +566,7 @@ static int winhttp_stream_read(
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
DWORD dw_bytes_read;
char replay_count = 0;
int error;
replay:
/* Enforce a reasonable cap on the number of replays */
......@@ -566,6 +596,9 @@ replay:
s->sent_request = 1;
}
if ((error = certificate_check(s, 1)) < 0)
return error;
if (s->chunked) {
assert(s->verb == post_verb);
......@@ -815,6 +848,7 @@ static int winhttp_stream_write_single(
winhttp_stream *s = (winhttp_stream *)stream;
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
DWORD bytes_written;
int error;
if (!s->request && winhttp_stream_connect(s) < 0)
return -1;
......@@ -835,6 +869,9 @@ static int winhttp_stream_write_single(
s->sent_request = 1;
if ((error = certificate_check(s, 1)) < 0)
return error;
if (!WinHttpWriteData(s->request,
(LPCVOID)buffer,
(DWORD)len,
......@@ -954,6 +991,7 @@ static int winhttp_stream_write_chunked(
{
winhttp_stream *s = (winhttp_stream *)stream;
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
int error;
if (!s->request && winhttp_stream_connect(s) < 0)
return -1;
......@@ -978,6 +1016,9 @@ static int winhttp_stream_write_chunked(
s->sent_request = 1;
}
if ((error = certificate_check(s, 1)) < 0)
return error;
if (len > CACHED_POST_BODY_BUF_SIZE) {
/* Flush, if necessary */
if (s->chunk_buffer_len > 0) {
......
......@@ -485,11 +485,13 @@ void test_online_clone__certificate_invalid(void)
{
g_options.remote_callbacks.certificate_check = fail_certificate_check;
cl_git_fail_with(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options),
cl_git_fail_with(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options),
GIT_ECERTIFICATE);
#ifdef GIT_SSH
cl_git_fail_with(git_clone(&g_repo, "ssh://github.com/libgit2/TestGitRepository", "./foo", &g_options),
GIT_ECERTIFICATE);
#endif
}
static int succeed_certificate_check(git_cert_t type, void *data, size_t len, int valid, void *payload)
......@@ -507,5 +509,5 @@ void test_online_clone__certificate_valid(void)
{
g_options.remote_callbacks.certificate_check = succeed_certificate_check;
cl_git_pass(git_clone(&g_repo, "http://github.com/libgit2/TestGitRepository", "./foo", &g_options));
cl_git_pass(git_clone(&g_repo, "https://github.com/libgit2/TestGitRepository", "./foo", &g_options));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment