From 431c110056f0090e9ddc6e1f5f2dc23ad8911779 Mon Sep 17 00:00:00 2001
From: Stephan Tesch <stephan@tesch.cx>
Date: Thu, 21 Jul 2016 20:00:32 +0000
Subject: [PATCH] Improve error reporting for the client certificate check

Until now, client certificates that have failed verification were reported as not being signed by the CA. That is not true for all cases. This patch adds an explanation in the debug log why verification failed.

fixes #12201
---
 lib/base/tlsstream.cpp     | 15 ++++++++++++++-
 lib/base/tlsstream.hpp     |  2 ++
 lib/remote/apilistener.cpp |  2 +-
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/lib/base/tlsstream.cpp b/lib/base/tlsstream.cpp
index e1470bb96..d0a1e442a 100644
--- a/lib/base/tlsstream.cpp
+++ b/lib/base/tlsstream.cpp
@@ -92,8 +92,16 @@ int TlsStream::ValidateCertificate(int preverify_ok, X509_STORE_CTX *ctx)
 {
 	SSL *ssl = static_cast<SSL *>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
 	TlsStream *stream = static_cast<TlsStream *>(SSL_get_ex_data(ssl, m_SSLIndex));
-	if (!preverify_ok)
+
+	if (!preverify_ok) {
 		stream->m_VerifyOK = false;
+
+		std::ostringstream msgbuf;
+		int err = X509_STORE_CTX_get_error(ctx);
+		msgbuf << "code " << err << ": " << X509_verify_cert_error_string(err);
+		stream->m_VerifyError = msgbuf.str();
+	}
+
 	return 1;
 }
 
@@ -102,6 +110,11 @@ bool TlsStream::IsVerifyOK(void) const
 	return m_VerifyOK;
 }
 
+String TlsStream::GetVerifyError(void) const
+{
+	return m_VerifyError;
+}
+
 /**
  * Retrieves the X509 certficate for this client.
  *
diff --git a/lib/base/tlsstream.hpp b/lib/base/tlsstream.hpp
index 132f66784..bfd4d2a23 100644
--- a/lib/base/tlsstream.hpp
+++ b/lib/base/tlsstream.hpp
@@ -69,6 +69,7 @@ public:
 	virtual bool IsDataAvailable(void) const override;
 
 	bool IsVerifyOK(void) const;
+	String GetVerifyError(void) const;
 
 private:
 	boost::shared_ptr<SSL> m_SSL;
@@ -77,6 +78,7 @@ private:
 	mutable boost::condition_variable m_CV;
 	bool m_HandshakeOK;
 	bool m_VerifyOK;
+	String m_VerifyError;
 	int m_ErrorCode;
 	bool m_ErrorOccurred;
 
diff --git a/lib/remote/apilistener.cpp b/lib/remote/apilistener.cpp
index 843294d8e..de2a4f7a9 100644
--- a/lib/remote/apilistener.cpp
+++ b/lib/remote/apilistener.cpp
@@ -363,7 +363,7 @@ void ApiListener::NewClientHandlerInternal(const Socket::Ptr& client, const Stri
 			log << "New client connection for identity '" << identity << "'";
 
 			if (!verify_ok)
-				log << " (client certificate not signed by CA)";
+				log << " (certificate validation failed: " << tlsStream->GetVerifyError() << ")";
 			else if (!endpoint)
 				log << " (no Endpoint object found for identity)";
 		}