From cb0f0dd06dba84617585fe18e01bcdaffedce4f5 Mon Sep 17 00:00:00 2001 From: XinyuHou Date: Thu, 2 Apr 2015 11:56:51 +0100 Subject: [PATCH] Improved fingerprint verification #4522 Conflicts: src/lib/plugin/ns/SecureSocket.cpp src/lib/plugin/ns/SecureSocket.h src/lib/synergy/ClientApp.cpp --- src/lib/plugin/ns/SecureSocket.cpp | 150 ++++++++++++++--------------- src/lib/plugin/ns/SecureSocket.h | 7 +- 2 files changed, 78 insertions(+), 79 deletions(-) diff --git a/src/lib/plugin/ns/SecureSocket.cpp b/src/lib/plugin/ns/SecureSocket.cpp index ecda101d..56900461 100644 --- a/src/lib/plugin/ns/SecureSocket.cpp +++ b/src/lib/plugin/ns/SecureSocket.cpp @@ -44,10 +44,6 @@ struct Ssl { SSL* m_ssl; }; -int verifyCertFingerprint(X509_STORE_CTX* ctx, void* arg); - -bool CSecureSocket::s_verifyFingerprintFailed = false; - CSecureSocket::CSecureSocket( IEventQueue* events, CSocketMultiplexer* socketMultiplexer) : @@ -206,14 +202,6 @@ SecureSocket::initContext(bool server) if (m_ssl->m_context == NULL) { showError(); } - - if (!server) { - void* p = reinterpret_cast(const_cast(m_certFingerprint.c_str())); - SSL_CTX_set_cert_verify_callback( - m_ssl->m_context, - verifyCertFingerprint, - p); - } } void @@ -278,13 +266,15 @@ SecureSocket::secureConnect(int socket) m_secureReady = !retry; - if (s_verifyFingerprintFailed) { - throwError("failed to verify server certificate fingerprint"); - } - if (m_secureReady) { - LOG((CLOG_INFO "connected to secure socket")); - showCertificate(); + if (verifyCertFingerprint()) { + LOG((CLOG_INFO "connected to secure socket")); + showCertificate(); + } + else { + LOG((CLOG_ERR "failed to verity server certificate fingerprint")); + disconnect(); + } } return retry; @@ -367,8 +357,7 @@ SecureSocket::checkResult(int n, bool& fatal, bool& retry) if (fatal) { showError(); - sendEvent(getEvents()->forISocket().disconnected()); - sendEvent(getEvents()->forIStream().inputShutdown()); + disconnect(); } } @@ -409,11 +398,73 @@ SecureSocket::getError() } } +void +CSecureSocket::disconnect() +{ + sendEvent(getEvents()->forISocket().disconnected()); + sendEvent(getEvents()->forIStream().inputShutdown()); +} + +bool +CSecureSocket::verifyCertFingerprint() +{ + // calculate received certificate fingerprint + X509 *cert = cert = SSL_get_peer_certificate(m_ssl->m_ssl); + EVP_MD* tempDigest; + unsigned char tempFingerprint[EVP_MAX_MD_SIZE]; + unsigned int tempFingerprintLen; + tempDigest = (EVP_MD*)EVP_sha1(); + if (X509_digest(cert, tempDigest, tempFingerprint, &tempFingerprintLen) <= 0) { + return false; + } + + // convert fingerprint into hexdecimal format + std::stringstream ss; + ss << std::hex; + for (unsigned int i = 0; i < tempFingerprintLen; i++) { + ss << std::setw(2) << std::setfill('0') << (int)tempFingerprint[i]; + } + + // all uppercase + CString fingerprint = ss.str(); + std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(), ::toupper); + + // check if this fingerprint exist + CString fileLine; + CString certificateFingerprint; + std::ifstream file; + file.open(m_certFingerprint.c_str()); + + while (!file.eof()) { + getline(file,fileLine); + // example of a fingerprint: + // SHA1 Fingerprint=6E:41:1A:21:53:2E:A3:EF:4D:A6:F2:A6:BA:0E:27:09:8A:F3:A1:10 + size_t found = fileLine.find('='); + if (found != CString::npos) { + certificateFingerprint = fileLine.substr(found + 1); + + if (!certificateFingerprint.empty()) { + // remove colons + certificateFingerprint.erase(std::remove(certificateFingerprint.begin(), certificateFingerprint.end(), ':'), certificateFingerprint.end()); + + if(certificateFingerprint.compare(fingerprint) == 0) { + file.close(); + return true; + } + } + } + } + + file.close(); + + return false; +} + ISocketMultiplexerJob* -SecureSocket::serviceConnect(ISocketMultiplexerJob* job, +CSecureSocket::serviceConnect(ISocketMultiplexerJob* job, bool, bool write, bool error) { - Lock lock(&getMutex()); + CLock lock(&getMutex()); bool retry = true; #ifdef SYSAPI_WIN32 @@ -426,10 +477,10 @@ SecureSocket::serviceConnect(ISocketMultiplexerJob* job, } ISocketMultiplexerJob* -SecureSocket::serviceAccept(ISocketMultiplexerJob* job, +CSecureSocket::serviceAccept(ISocketMultiplexerJob* job, bool, bool write, bool error) { - Lock lock(&getMutex()); + CLock lock(&getMutex()); bool retry = true; #ifdef SYSAPI_WIN32 @@ -440,54 +491,3 @@ SecureSocket::serviceAccept(ISocketMultiplexerJob* job, return retry ? job : newJob(); } - -int -verifyCertFingerprint(X509_STORE_CTX* ctx, void* arg) -{ - X509 *cert = ctx->cert; - - EVP_MD* tempDigest; - unsigned char tempFingerprint[EVP_MAX_MD_SIZE]; - unsigned int tempFingerprintLen; - tempDigest = (EVP_MD*)EVP_sha1(); - if (X509_digest(cert, tempDigest, tempFingerprint, &tempFingerprintLen) <= 0) { - CSecureSocket::s_verifyFingerprintFailed = true; - return 0; - } - - std::stringstream ss; - ss << std::hex; - for (unsigned int i = 0; i < tempFingerprintLen; i++) { - ss << std::setw(2) << std::setfill('0') << (int)tempFingerprint[i]; - } - CString fingerprint = ss.str(); - std::transform(fingerprint.begin(), fingerprint.end(), fingerprint.begin(), ::toupper); - - CString fileLine; - CString certificateFingerprint; - char* certFingerprintFilename = reinterpret_cast(arg); - std::ifstream file; - file.open(certFingerprintFilename); - - while (!file.eof()) { - getline(file,fileLine); - size_t found = fileLine.find('='); - if (found != CString::npos) { - certificateFingerprint = fileLine.substr(found + 1); - - if (!certificateFingerprint.empty()) { - certificateFingerprint.erase(std::remove(certificateFingerprint.begin(), certificateFingerprint.end(), ':'), certificateFingerprint.end()); - - if(certificateFingerprint.compare(fingerprint) == 0) { - file.close(); - return 1; - } - } - } - } - - file.close(); - - CSecureSocket::s_verifyFingerprintFailed = true; - return 0; -} diff --git a/src/lib/plugin/ns/SecureSocket.h b/src/lib/plugin/ns/SecureSocket.h index 507566e8..725d5da9 100644 --- a/src/lib/plugin/ns/SecureSocket.h +++ b/src/lib/plugin/ns/SecureSocket.h @@ -61,7 +61,9 @@ private: void checkResult(int n, bool& fatal, bool& retry); void showError(); void throwError(const char* reason); - String getError(); + CString getError(); + void disconnect(); + bool verifyCertFingerprint(); ISocketMultiplexerJob* serviceConnect(ISocketMultiplexerJob*, @@ -75,7 +77,4 @@ private: Ssl* m_ssl; bool m_secureReady; CString m_certFingerprint; - -public: - static bool s_verifyFingerprintFailed; };