From c763e0be7221cc055d61eec9d30c1ff8a4a0fc32 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 7 Jun 2021 20:48:09 +0300 Subject: fixes #2912 (Drop WinCrypto API support) --- src/mir_app/mir_app.vcxproj | 3 +- src/mir_app/mir_app.vcxproj.filters | 3 + src/mir_app/src/mir_app.def | 6 + src/mir_app/src/mir_app64.def | 6 + src/mir_app/src/miranda.h | 2 +- src/mir_app/src/modules.cpp | 2 - src/mir_app/src/netlib.cpp | 8 +- src/mir_app/src/netlib.h | 2 - src/mir_app/src/netlib_http.cpp | 2 +- src/mir_app/src/netlib_log.cpp | 2 +- src/mir_app/src/netlib_openconn.cpp | 22 -- src/mir_app/src/netlib_pktrecver.cpp | 2 +- src/mir_app/src/netlib_sock.cpp | 22 +- src/mir_app/src/netlib_ssl.cpp | 434 +++++++++++++++++++++++++++++++++++ src/mir_app/src/newplugins.cpp | 37 +-- src/mir_app/src/pluginopts.cpp | 2 +- src/mir_app/src/stdafx.h | 4 +- 17 files changed, 472 insertions(+), 87 deletions(-) create mode 100644 src/mir_app/src/netlib_ssl.cpp (limited to 'src/mir_app') diff --git a/src/mir_app/mir_app.vcxproj b/src/mir_app/mir_app.vcxproj index 4af6e20925..3991cc00a4 100644 --- a/src/mir_app/mir_app.vcxproj +++ b/src/mir_app/mir_app.vcxproj @@ -124,6 +124,7 @@ + @@ -191,7 +192,7 @@ src/mir_app64.def /ignore:4197 %(AdditionalOptions) type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27amd64%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies) - libcrypto.lib;%(AdditionalDependencies) + libcrypto.lib;libssl.lib;crypt32.lib;%(AdditionalDependencies) res/miranda32.exe.manifest diff --git a/src/mir_app/mir_app.vcxproj.filters b/src/mir_app/mir_app.vcxproj.filters index 8c239e56a1..aebb101b75 100644 --- a/src/mir_app/mir_app.vcxproj.filters +++ b/src/mir_app/mir_app.vcxproj.filters @@ -395,6 +395,9 @@ Source Files + + Source Files + diff --git a/src/mir_app/src/mir_app.def b/src/mir_app/src/mir_app.def index 5b47571ebc..541ff70dad 100644 --- a/src/mir_app/src/mir_app.def +++ b/src/mir_app/src/mir_app.def @@ -781,3 +781,9 @@ Chat_Mute @868 _WebSocket_SendBinary@12 @869 NONAME _WebSocket_SendText@8 @870 NONAME ?OnContactAdded@PROTO_INTERFACE@@UAEXI@Z @871 NONAME +_Netlib_SslConnect@12 @872 NONAME +_Netlib_SslFree@4 @873 NONAME +_Netlib_SslPending@4 @874 NONAME +_Netlib_SslRead@16 @875 NONAME +_Netlib_SslShutdown@4 @876 NONAME +_Netlib_SslWrite@12 @877 NONAME diff --git a/src/mir_app/src/mir_app64.def b/src/mir_app/src/mir_app64.def index 3c61daf61d..04a989d599 100644 --- a/src/mir_app/src/mir_app64.def +++ b/src/mir_app/src/mir_app64.def @@ -781,3 +781,9 @@ Chat_Mute @868 WebSocket_SendBinary @869 NONAME WebSocket_SendText @870 NONAME ?OnContactAdded@PROTO_INTERFACE@@UEAAXI@Z @871 NONAME +Netlib_SslConnect @872 NONAME +Netlib_SslFree @873 NONAME +Netlib_SslPending @874 NONAME +Netlib_SslRead @875 NONAME +Netlib_SslShutdown @876 NONAME +Netlib_SslWrite @877 NONAME diff --git a/src/mir_app/src/miranda.h b/src/mir_app/src/miranda.h index ec43c2c428..dc1d7594b4 100644 --- a/src/mir_app/src/miranda.h +++ b/src/mir_app/src/miranda.h @@ -69,7 +69,7 @@ extern DWORD hMainThreadId; extern HANDLE hOkToExitEvent, hModulesLoadedEvent; extern HANDLE hAccListChanged; extern wchar_t mirandabootini[MAX_PATH]; -extern struct pluginEntry *plugin_checker, *plugin_crshdmp, *plugin_service, *plugin_ssl, *plugin_clist; +extern struct pluginEntry *plugin_checker, *plugin_crshdmp, *plugin_service, *plugin_clist; extern bool g_bModulesLoadedFired, g_bMirandaTerminated; /**** newplugins.cpp *******************************************************************/ diff --git a/src/mir_app/src/modules.cpp b/src/mir_app/src/modules.cpp index c3cdaeb716..7f6aa752b4 100644 --- a/src/mir_app/src/modules.cpp +++ b/src/mir_app/src/modules.cpp @@ -34,7 +34,6 @@ int LoadNewPluginsModuleInfos(void); // core: preloading plugins int LoadSendRecvAuthModule(void); // core: auth dialogs int LoadNewPluginsModule(void); // core: N.O. plugins int LoadNetlibModule(void); // core: network -int LoadSslModule(void); int LoadProtocolsModule(void); // core: protocol manager int LoadAccountsModule(void); // core: account manager int LoadIgnoreModule(void); // protocol filter: ignore @@ -101,7 +100,6 @@ int LoadDefaultModules(void) // the database will select which db plugin to use, or fail if no profile is selected if (LoadDatabaseModule()) return 1; if (LoadNetlibModule()) return 1; - if (LoadSslModule()) return 1; // database is available here InitIni(); diff --git a/src/mir_app/src/netlib.cpp b/src/mir_app/src/netlib.cpp index 624d02860b..5dd7bf4f97 100644 --- a/src/mir_app/src/netlib.cpp +++ b/src/mir_app/src/netlib.cpp @@ -43,8 +43,6 @@ static int CompareNetlibUser(const NetlibUser* p1, const NetlibUser* p2) LIST netlibUser(5, CompareNetlibUser); mir_cs csNetlibUser; -SSL_API sslApi; - void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings) { mir_free(settings->szIncomingPorts); @@ -253,8 +251,8 @@ void NetlibDoCloseSocket(NetlibConnection *nlc, bool noShutdown) Netlib_Logf(nlc->nlu, "(%p:%u) Connection closed internal", nlc, nlc->s); if (nlc->hSsl) { if (!noShutdown) - sslApi.shutdown(nlc->hSsl); - sslApi.sfree(nlc->hSsl); + Netlib_SslShutdown(nlc->hSsl); + Netlib_SslFree(nlc->hSsl); nlc->hSsl = nullptr; } @@ -405,7 +403,7 @@ MIR_APP_DLL(void) Netlib_Shutdown(HNETLIBCONN h) { NetlibConnection *nlc = h; if (!nlc->termRequested) { - if (nlc->hSsl) sslApi.shutdown(nlc->hSsl); + if (nlc->hSsl) Netlib_SslShutdown(nlc->hSsl); if (nlc->s != INVALID_SOCKET) shutdown(nlc->s, SD_BOTH); if (nlc->s2 != INVALID_SOCKET) shutdown(nlc->s2, SD_BOTH); nlc->termRequested = true; diff --git a/src/mir_app/src/netlib.h b/src/mir_app/src/netlib.h index b75eb0f8ad..aeae2a7bd0 100644 --- a/src/mir_app/src/netlib.h +++ b/src/mir_app/src/netlib.h @@ -33,8 +33,6 @@ int GetNetlibHandleType(void*); #define NLHRF_SMARTREMOVEHOST 0x00000004 // for internal purposes only -extern struct SSL_API sslApi; - struct NetlibUser { int handleType; diff --git a/src/mir_app/src/netlib_http.cpp b/src/mir_app/src/netlib_http.cpp index c0c689e236..9db81ae182 100644 --- a/src/mir_app/src/netlib_http.cpp +++ b/src/mir_app/src/netlib_http.cpp @@ -83,7 +83,7 @@ static int RecvWithTimeoutTime(NetlibConnection *nlc, unsigned dwTimeoutTime, ch { DWORD dwTimeNow; - if (nlc->foreBuf.isEmpty() && !sslApi.pending(nlc->hSsl)) { + if (nlc->foreBuf.isEmpty() && !Netlib_SslPending(nlc->hSsl)) { while ((dwTimeNow = GetTickCount()) < dwTimeoutTime) { unsigned dwDeltaTime = min(dwTimeoutTime - dwTimeNow, 1000); int res = WaitUntilReadable(nlc->s, dwDeltaTime); diff --git a/src/mir_app/src/netlib_log.cpp b/src/mir_app/src/netlib_log.cpp index 0514b1d890..9a3955eeae 100644 --- a/src/mir_app/src/netlib_log.cpp +++ b/src/mir_app/src/netlib_log.cpp @@ -493,7 +493,7 @@ MIR_APP_DLL(void) Netlib_Dump(HNETLIBCONN nlc, const void *pBuf, size_t len, boo isText = false; else if (!(flags & MSG_DUMPASTEXT)) { if (logOptions.autoDetectText) { - for (int i = 0; i < len; i++) { + for (size_t i = 0; i < len; i++) { if ((buf[i] < ' ' && buf[i] != '\t' && buf[i] != '\r' && buf[i] != '\n') || buf[i] >= 0x80) { isText = false; break; diff --git a/src/mir_app/src/netlib_openconn.cpp b/src/mir_app/src/netlib_openconn.cpp index 6c352ea09e..7fd4badd57 100644 --- a/src/mir_app/src/netlib_openconn.cpp +++ b/src/mir_app/src/netlib_openconn.cpp @@ -837,28 +837,6 @@ MIR_APP_DLL(HNETLIBCONN) Netlib_OpenConnection(NetlibUser *nlu, const NETLIBOPEN return nlc; } -MIR_APP_DLL(int) Netlib_StartSsl(HNETLIBCONN hConnection, const char *szHost) -{ - NetlibConnection *nlc = (NetlibConnection*)hConnection; - if (nlc == nullptr) - return 0; - - NetlibUser *nlu = nlc->nlu; - if (szHost == nullptr) - szHost = nlc->nloc.szHost; - szHost = NEWSTR_ALLOCA(szHost); - - Netlib_Logf(nlu, "(%d %s) Starting SSL negotiation", int(nlc->s), szHost); - - nlc->hSsl = sslApi.connect(nlc->s, szHost, nlu->settings.validateSSL); - if (nlc->hSsl == nullptr) - Netlib_Logf(nlu, "(%d %s) Failure to negotiate SSL connection", int(nlc->s), szHost); - else - Netlib_Logf(nlu, "(%d %s) SSL negotiation successful", int(nlc->s), szHost); - - return nlc->hSsl != nullptr; -} - NetlibConnection::NetlibConnection() { handleType = NLH_CONNECTION; diff --git a/src/mir_app/src/netlib_pktrecver.cpp b/src/mir_app/src/netlib_pktrecver.cpp index 44a48b7450..1ef5fbd5cc 100644 --- a/src/mir_app/src/netlib_pktrecver.cpp +++ b/src/mir_app/src/netlib_pktrecver.cpp @@ -66,7 +66,7 @@ MIR_APP_DLL(int) Netlib_GetMorePackets(HANDLE hReceiver, NETLIBPACKETRECVER *nlp } if (nlprParam->dwTimeout != INFINITE) { - if (!sslApi.pending(nlpr->nlc->hSsl) && WaitUntilReadable(nlpr->nlc->s, nlprParam->dwTimeout) <= 0) { + if (!Netlib_SslPending(nlpr->nlc->hSsl) && WaitUntilReadable(nlpr->nlc->s, nlprParam->dwTimeout) <= 0) { *nlprParam = nlpr->packetRecver; return SOCKET_ERROR; } diff --git a/src/mir_app/src/netlib_sock.cpp b/src/mir_app/src/netlib_sock.cpp index d829541e2f..4cfe8ee4ff 100644 --- a/src/mir_app/src/netlib_sock.cpp +++ b/src/mir_app/src/netlib_sock.cpp @@ -37,7 +37,7 @@ MIR_APP_DLL(int) Netlib_Send(HNETLIBCONN nlc, const char *buf, int len, int flag int result; Netlib_Dump(nlc, (PBYTE)buf, len, true, flags); if (nlc->hSsl) - result = sslApi.write(nlc->hSsl, buf, len); + result = Netlib_SslWrite(nlc->hSsl, buf, len); else result = send(nlc->s, buf, len, flags & 0xFFFF); @@ -63,7 +63,7 @@ MIR_APP_DLL(int) Netlib_Recv(HNETLIBCONN nlc, char *buf, int len, int flags) nlc->foreBuf.remove(recvResult); } else if (nlc->hSsl) - recvResult = sslApi.read(nlc->hSsl, buf, len, (flags & MSG_PEEK) != 0); + recvResult = Netlib_SslRead(nlc->hSsl, buf, len, (flags & MSG_PEEK) != 0); else recvResult = recv(nlc->s, buf, len, flags & 0xFFFF); @@ -92,7 +92,7 @@ static int ConnectionListToSocketList(const HNETLIBCONN *hConns, fd_set *fd, int return 0; } FD_SET(nlcCheck->s, fd); - if (!nlcCheck->foreBuf.isEmpty() || sslApi.pending(nlcCheck->hSsl)) + if (!nlcCheck->foreBuf.isEmpty() || Netlib_SslPending(nlcCheck->hSsl)) pending++; } return 1; @@ -160,7 +160,7 @@ MIR_APP_DLL(int) Netlib_SelectEx(NETLIBSELECTEX *nls) conn = (NetlibConnection*)nls->hReadConns[j]; if (conn == nullptr || conn == INVALID_HANDLE_VALUE) break; - if (sslApi.pending(conn->hSsl)) + if (Netlib_SslPending(conn->hSsl)) nls->hReadStatus[j] = TRUE; nls->hReadStatus[j] = FD_ISSET(conn->s, &readfd); } @@ -227,20 +227,6 @@ MIR_APP_DLL(int) Netlib_GetConnectionInfo(HNETLIBCONN nlc, NETLIBCONNINFO *connI ///////////////////////////////////////////////////////////////////////////////////////// -MIR_APP_DLL(void*) Netlib_GetTlsUnique(HNETLIBCONN nlc, int &cbLen) -{ - if (nlc == nullptr || nlc->hSsl == nullptr || sslApi.unique == nullptr) - return nullptr; - - void *pBuf = sslApi.unique(nlc->hSsl, &cbLen); - if (pBuf == nullptr || !cbLen) - return nullptr; - - return pBuf; -} - -///////////////////////////////////////////////////////////////////////////////////////// - inline bool IsAddrGlobal(const IN6_ADDR *a) { unsigned char High = a->s6_bytes[0] & 0xf0; diff --git a/src/mir_app/src/netlib_ssl.cpp b/src/mir_app/src/netlib_ssl.cpp new file mode 100644 index 0000000000..abb87557d4 --- /dev/null +++ b/src/mir_app/src/netlib_ssl.cpp @@ -0,0 +1,434 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" +#include "netlib.h" + +#include +#include + +static bool bSslInitDone; + +enum SocketState +{ + sockOpen, + sockClosed, + sockError +}; + +struct SslHandle : public MZeroedObject +{ + ~SslHandle() + { + if (session) + SSL_free(session); + if (ctx) + SSL_CTX_free(ctx); + } + + SOCKET s; + SSL_CTX *ctx; + SSL *session; + SocketState state; +}; + +static void SSL_library_unload(void) +{ + /* Load Library Pointers */ + if (!bSslInitDone) + return; + + bSslInitDone = false; +} + +static bool SSL_library_load(void) +{ + /* Load Library Pointers */ + if (bSslInitDone) + return true; + + if (!bSslInitDone) { // init OpenSSL + SSL_library_init(); + SSL_load_error_strings(); + // FIXME check errors + + bSslInitDone = true; + } + + return bSslInitDone; +} + +const char* SSL_GetCipherName(SslHandle *ssl) +{ + if (!ssl || !ssl->session) + return nullptr; + + return SSL_CIPHER_get_name(SSL_get_current_cipher(ssl->session)); +} + +static void ReportSslError(SECURITY_STATUS scRet, int line, bool = false) +{ + CMStringW tszMsg(FORMAT, L"SSL connection failure(%x %u) :", scRet, line); + + switch (scRet) { + case 0: + case ERROR_NOT_READY: + return; + + case SEC_E_INVALID_TOKEN: + tszMsg += TranslateW_LP(L"Client cannot decode host message. Possible causes: host does not support SSL or requires not existing security package"); + break; + + case CERT_E_CN_NO_MATCH: + case SEC_E_WRONG_PRINCIPAL: + tszMsg += TranslateW_LP(L"Host we are connecting to is not the one certificate was issued for"); + break; + + default: + wchar_t szMsgBuf[256]; + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, scRet, LANG_USER_DEFAULT, szMsgBuf, _countof(szMsgBuf), nullptr); + tszMsg += szMsgBuf; + } + + Netlib_LogfW(nullptr, tszMsg); + + SetLastError(scRet); + PUShowMessageW(tszMsg.GetBuffer(), SM_WARNING); +} + +static bool ClientConnect(SslHandle *ssl, const char*) +{ + SSL_METHOD *meth = (SSL_METHOD*)SSLv23_client_method(); + + // contrary to what it's named, SSLv23 announces all supported ciphers/versions, + // generally TLS1.2 in a TLS1.0 Client Hello + if (!meth) { + Netlib_Logf(nullptr, "SSL setup failure: client method"); + return false; + } + ssl->ctx = SSL_CTX_new(meth); + if (!ssl->ctx) { + Netlib_Logf(nullptr, "SSL setup failure: context"); + return false; + } + + // SSL_read/write should transparently handle renegotiations + SSL_CTX_ctrl(ssl->ctx, SSL_CTRL_MODE, SSL_MODE_AUTO_RETRY, nullptr); + + RAND_screen(); + ssl->session = SSL_new(ssl->ctx); + if (!ssl->session) { + Netlib_Logf(nullptr, "SSL setup failure: session"); + return false; + } + SSL_set_fd(ssl->session, ssl->s); + + int err = SSL_connect(ssl->session); + + if (err != 1) { + err = SSL_get_error(ssl->session, err); + Netlib_Logf(nullptr, "SSL negotiation failure (%d)", err); + return false; + } + + const char *suite = SSL_GetCipherName(ssl); + if (suite != nullptr) + Netlib_Logf(nullptr, "SSL established with %s", suite); + return true; +} + +static PCCERT_CONTEXT SSL_X509ToCryptCert(X509 * x509) +{ + unsigned char *buf = nullptr; + PCCERT_CONTEXT pCertContext = nullptr; + + int len = i2d_X509(x509, &buf); + if ((len >= 0) && buf) { + pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, buf, len); + + CRYPTO_free(buf, __FILE__, __LINE__); + } + return pCertContext; +} + +static PCCERT_CONTEXT SSL_CertChainToCryptAnchor(SSL* session) +{ + /* convert the active certificate chain provided in the handshake of 'session' into + the format used by CryptAPI. + */ + PCCERT_CONTEXT anchor = nullptr; + // create cert store + HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, nullptr); + + if (store) { + X509 *server_cert = SSL_get_peer_certificate(session); + if (server_cert) { + // add the server's cert first, to make sure CryptAPI builds the correct chain + PCCERT_CONTEXT primary_cert; + BOOL ok = CertAddCertificateContextToStore(store, SSL_X509ToCryptCert(server_cert), CERT_STORE_ADD_ALWAYS, &primary_cert); + if (ok && primary_cert) { + // add all remaining certs to store (note: stack needs not be freed, it is not a copy) + STACK_OF(X509) *server_chain = SSL_get_peer_cert_chain(session); + if (server_chain) { + for (int i = 0; i < OPENSSL_sk_num((OPENSSL_STACK *)server_chain); i++) { + X509 *next_cert = (X509 *)OPENSSL_sk_value((OPENSSL_STACK *)server_chain, i); + CertAddCertificateContextToStore(store, SSL_X509ToCryptCert(next_cert), CERT_STORE_ADD_USE_EXISTING, nullptr); + } + } + + // return primary cert; MUST be freed by caller which will free the associated store + anchor = primary_cert; + } + else { + if (primary_cert) + CertFreeCertificateContext(primary_cert); + } + + X509_free(server_cert); + } + + CertCloseStore(store, 0); + } + + return anchor; +} + +static LPSTR rgszUsages[] = +{ + szOID_PKIX_KP_SERVER_AUTH, + szOID_SERVER_GATED_CRYPTO, + szOID_SGC_NETSCAPE +}; + +static bool VerifyCertificate(SslHandle *ssl, PCSTR pszServerName, DWORD dwCertFlags) +{ + DWORD scRet; + + ptrW pwszServerName(mir_a2u(pszServerName)); + + HTTPSPolicyCallbackData polHttps = {}; + CERT_CHAIN_POLICY_PARA PolicyPara = {}; + CERT_CHAIN_POLICY_STATUS PolicyStatus = {}; + CERT_CHAIN_PARA ChainPara = {}; + + PCCERT_CHAIN_CONTEXT pChainContext = nullptr; + PCCERT_CONTEXT pServerCert = SSL_CertChainToCryptAnchor(ssl->session); + if (pServerCert == nullptr) { + scRet = SEC_E_WRONG_PRINCIPAL; + goto cleanup; + } + + ChainPara.cbSize = sizeof(ChainPara); + ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR; + ChainPara.RequestedUsage.Usage.cUsageIdentifier = _countof(rgszUsages); + ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages; + + if (!CertGetCertificateChain(nullptr, pServerCert, nullptr, pServerCert->hCertStore, &ChainPara, 0, nullptr, &pChainContext)) { + scRet = GetLastError(); + goto cleanup; + } + + polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData); + polHttps.dwAuthType = AUTHTYPE_SERVER; + polHttps.fdwChecks = dwCertFlags; + polHttps.pwszServerName = pwszServerName; + + PolicyPara.cbSize = sizeof(PolicyPara); + PolicyPara.pvExtraPolicyPara = &polHttps; + + PolicyStatus.cbSize = sizeof(PolicyStatus); + + if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext, &PolicyPara, &PolicyStatus)) { + scRet = GetLastError(); + goto cleanup; + } + + if (PolicyStatus.dwError) { + scRet = PolicyStatus.dwError; + goto cleanup; + } + + scRet = SEC_E_OK; + +cleanup: + if (pChainContext) + CertFreeCertificateChain(pChainContext); + if (pServerCert) + CertFreeCertificateContext(pServerCert); + + ReportSslError(scRet, __LINE__, true); + return scRet == SEC_E_OK; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// negotiate SSL session, verify cert, return NULL if failed + +MIR_APP_DLL(HSSL) Netlib_SslConnect(SOCKET s, const char* host, int verify) +{ + SslHandle *ssl = new SslHandle(); + ssl->s = s; + bool res = ClientConnect(ssl, host); + + if (res && verify) { + DWORD dwFlags = 0; + if (!host || inet_addr(host) != INADDR_NONE) + dwFlags |= 0x00001000; + res = VerifyCertificate(ssl, host, dwFlags); + } + + if (res) + return ssl; + + delete ssl; + return nullptr; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// return true if there is either unsend or buffered received data (ie. after peek) + +MIR_APP_DLL(BOOL) Netlib_SslPending(HSSL ssl) +{ + return ssl && ssl->session && (SSL_pending(ssl->session) > 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// reads number of bytes, keeps in buffer if peek != 0 + +MIR_APP_DLL(int) Netlib_SslRead(HSSL ssl, char *buf, int num, int peek) +{ + if (!ssl || !ssl->session) return SOCKET_ERROR; + if (num <= 0) return 0; + + int err = 0; + if (peek) + err = SSL_peek(ssl->session, buf, num); + else + err = SSL_read(ssl->session, buf, num); + + if (err <= 0) { + int err2 = SSL_get_error(ssl->session, err); + if (err2 == SSL_ERROR_ZERO_RETURN) { + Netlib_Logf(nullptr, "SSL connection gracefully closed"); + ssl->state = sockClosed; + return 0; + } + + Netlib_Logf(nullptr, "SSL failure recieving data (%d, %d, %d)", err, err2, WSAGetLastError()); + ssl->state = sockError; + return SOCKET_ERROR; + } + + return err; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// writes data to the SSL socket + +MIR_APP_DLL(int) Netlib_SslWrite(HSSL ssl, const char *buf, int num) +{ + if (!ssl || !ssl->session) + return SOCKET_ERROR; + if (num <= 0) + return 0; + + int err = SSL_write(ssl->session, buf, num); + if (err > 0) + return err; + + int err2 = SSL_get_error(ssl->session, err); + switch (err2) { + case SSL_ERROR_ZERO_RETURN: + Netlib_Logf(nullptr, "SSL connection gracefully closed"); + ssl->state = sockClosed; + break; + + default: + Netlib_Logf(nullptr, "SSL failure sending data (%d, %d, %d)", err, err2, WSAGetLastError()); + ssl->state = sockError; + return SOCKET_ERROR; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// closes SSL session, but keeps socket open + +MIR_APP_DLL(void) Netlib_SslShutdown(HSSL ssl) +{ + if (ssl && ssl->session) + SSL_shutdown(ssl->session); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// frees all data associated with the SSL socket + +MIR_APP_DLL(void) Netlib_SslFree(HSSL ssl) +{ + delete ssl; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// makes connection SSL +// returns 0 on failure / 1 on success + +MIR_APP_DLL(int) Netlib_StartSsl(HNETLIBCONN hConnection, const char *szHost) +{ + NetlibConnection *nlc = (NetlibConnection*)hConnection; + if (nlc == nullptr) + return 0; + + NetlibUser *nlu = nlc->nlu; + if (szHost == nullptr) + szHost = nlc->nloc.szHost; + szHost = NEWSTR_ALLOCA(szHost); + + Netlib_Logf(nlu, "(%d %s) Starting SSL negotiation", int(nlc->s), szHost); + + nlc->hSsl = Netlib_SslConnect(nlc->s, szHost, nlu->settings.validateSSL); + if (nlc->hSsl == nullptr) + Netlib_Logf(nlu, "(%d %s) Failure to negotiate SSL connection", int(nlc->s), szHost); + else + Netlib_Logf(nlu, "(%d %s) SSL negotiation successful", int(nlc->s), szHost); + + return nlc->hSsl != nullptr; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// gets TLS channel binging data for a socket + +MIR_APP_DLL(void*) Netlib_GetTlsUnique(HNETLIBCONN nlc, int &cbLen) +{ + if (nlc == nullptr || nlc->hSsl == nullptr) + return nullptr; + + char buf[1000]; + size_t len = SSL_get_finished(nlc->hSsl->session, buf, sizeof(buf)); + if (len == 0) + return nullptr; + + cbLen = (int)len; + void *pBuf = mir_alloc(len); + memcpy(pBuf, buf, len); + return pBuf; +} diff --git a/src/mir_app/src/newplugins.cpp b/src/mir_app/src/newplugins.cpp index 9f91136a80..210d129118 100644 --- a/src/mir_app/src/newplugins.cpp +++ b/src/mir_app/src/newplugins.cpp @@ -59,7 +59,7 @@ HANDLE hevLoadModule, hevUnloadModule; wchar_t mirandabootini[MAX_PATH]; static int askAboutIgnoredPlugins; -pluginEntry *plugin_checker, *plugin_crshdmp, *plugin_service, *plugin_ssl, *plugin_clist; +pluginEntry *plugin_checker, *plugin_crshdmp, *plugin_service, *plugin_clist; ///////////////////////////////////////////////////////////////////////////////////////// @@ -111,19 +111,21 @@ static const MUUID pluginBannedList[] = { 0xf0fdf73a, 0x753d, 0x499d, { 0x8d, 0xba, 0x33, 0x6d, 0xb7, 0x9c, 0xdd, 0x41 } }, // advancedautoaway { 0xa5bb1b7a, 0xb7cd, 0x4cbb, { 0xa7, 0xdb, 0xce, 0xb4, 0xeb, 0x71, 0xda, 0x49 } }, // keepstatus { 0x4b733944, 0x5a70, 0x4b52, { 0xab, 0x2d, 0x68, 0xb1, 0xef, 0x38, 0xff, 0xe8 } }, // startupstatus + { 0x8d0a046d, 0x8ea9, 0x4c55, { 0xb5, 0x68, 0x38, 0xda, 0x52, 0x05, 0x64, 0xfd } }, // stdauth { 0x9d6c3213, 0x02b4, 0x4fe1, { 0x92, 0xe6, 0x52, 0x6d, 0xe1, 0x4f, 0x8d, 0x65 } }, // stdchat + { 0x1e64fd80, 0x299e, 0x48a0, { 0x94, 0x41, 0xde, 0x28, 0x68, 0x56, 0x3b, 0x6f } }, // stdhelp + { 0x53ac190b, 0xe223, 0x4341, { 0x82, 0x5f, 0x70, 0x9d, 0x85, 0x20, 0x21, 0x5b } }, // stdidle + { 0x312C4F84, 0x75BE, 0x4404, { 0xBC, 0xB1, 0xC1, 0x03, 0xDB, 0xE5, 0xA3, 0xB8 } }, // stdssl { 0x621f886b, 0xa7f6, 0x457f, { 0x9d, 0x62, 0x8e, 0xe8, 0x4c, 0x27, 0x59, 0x93 } }, // modernopt { 0x08B86253, 0xEC6E, 0x4d09, { 0xB7, 0xA9, 0x64, 0xAC, 0xDF, 0x06, 0x27, 0xB8 } }, // gtalkext { 0x4f1ff7fa, 0x4d75, 0x44b9, { 0x93, 0xb0, 0x2c, 0xed, 0x2e, 0x4f, 0x9e, 0x3e } }, // whatsapp { 0xb908773a, 0x86f7, 0x4a91, { 0x86, 0x74, 0x6a, 0x20, 0xba, 0x0e, 0x67, 0xd1 } }, // dropbox { 0x748f8934, 0x781a, 0x528d, { 0x52, 0x08, 0x00, 0x12, 0x65, 0x40, 0x4a, 0xb3 } }, // tlen - { 0x8d0a046d, 0x8ea9, 0x4c55, { 0xb5, 0x68, 0x38, 0xda, 0x52, 0x05, 0x64, 0xfd } }, // stdauth - { 0x1e64fd80, 0x299e, 0x48a0, { 0x94, 0x41, 0xde, 0x28, 0x68, 0x56, 0x3b, 0x6f } }, // stdhelp { 0x3750a5a3, 0xbf0d, 0x490e, { 0xb6, 0x5d, 0x41, 0xac, 0x4d, 0x29, 0xae, 0xb3 } }, // aim { 0x7c070f7c, 0x459e, 0x46b7, { 0x8e, 0x6d, 0xbc, 0x6e, 0xfa, 0xa2, 0x2f, 0x78 } }, // advaimg - { 0x53ac190b, 0xe223, 0x4341, { 0x82, 0x5f, 0x70, 0x9d, 0x85, 0x20, 0x21, 0x5b } }, // stdidle { 0x6f376b33, 0xd3f4, 0x4c4f, { 0xa9, 0x6b, 0x77, 0xda, 0x08, 0x04, 0x3b, 0x06 } }, // importtxt { 0xe7c48bab, 0x8ace, 0x4cb3, { 0x84, 0x46, 0xd4, 0xb7, 0x34, 0x81, 0xf4, 0x97 } }, // mra + { 0xb649702c, 0x13de, 0x408a, { 0xb6, 0xc2, 0xfb, 0x8f, 0xed, 0x2a, 0x2c, 0x90 } }, // openssl { 0x73a9615c, 0x7d4e, 0x4555, { 0xba, 0xdb, 0xee, 0x05, 0xdc, 0x92, 0x8e, 0xff } }, // icqoscar8 { 0xcf97fd5d, 0xb911, 0x47a8, { 0xaf, 0x03, 0xd2, 0x19, 0x68, 0xb5, 0xb8, 0x94 } }, // sms { 0x26a9125d, 0x7863, 0x4e01, { 0xaf, 0x0e, 0xd1, 0x4e, 0xf9, 0x5c, 0x50, 0x54 } }, // old Popup.dll @@ -388,11 +390,6 @@ pluginEntry* OpenPlugin(wchar_t *tszFileName, wchar_t *dir, wchar_t *path) clistPlugins.insert(p); p->bIsClist = true; } - // plugin declared that it's a ssl provider. mark it for the future load - else if (hasMuuid(pIds, MIID_SSL)) { - plugin_ssl = p; - p->bIsLast = true; - } // plugin declared that it's a service mode plugin. // load it for a profile manager's window else if (hasMuuid(pIds, MIID_SERVICEMODE)) { @@ -656,28 +653,6 @@ MIR_APP_DLL(int) SetServiceModePlugin(const char *szPluginName, WPARAM wParam, L return 1; } -///////////////////////////////////////////////////////////////////////////////////////// - -int LoadSslModule(void) -{ - bool bExtSSLLoaded = false; - - if (plugin_ssl != nullptr) { - if (!TryLoadPlugin(plugin_ssl, false)) { - Plugin_Uninit(plugin_ssl); - } - else - bExtSSLLoaded = true; - } - if (!bExtSSLLoaded) { - MuuidReplacement stdSsl = { MIID_SSL, L"stdssl", nullptr }; - if (!LoadCorePlugin(stdSsl)) - return 1; - } - mir_getSI(&sslApi); - return 0; -} - ///////////////////////////////////////////////////////////////////////////////////////// // Event hook to unload all non-core plugins // hooked very late, after all the internal plugins, blah diff --git a/src/mir_app/src/pluginopts.cpp b/src/mir_app/src/pluginopts.cpp index 90b489b082..2e5b87960f 100644 --- a/src/mir_app/src/pluginopts.cpp +++ b/src/mir_app/src/pluginopts.cpp @@ -135,7 +135,7 @@ static BOOL dialogListPlugins(WIN32_FIND_DATA *fd, wchar_t *path, WPARAM, LPARAM CCtrlListView *pCtrl = (CCtrlListView*)lParam; bool bNoCheckbox = (dat->flags & STATIC_PLUGIN) != 0; - if (bNoCheckbox || hasMuuid(pIds, MIID_CLIST) || hasMuuid(pIds, MIID_SSL)) + if (bNoCheckbox || hasMuuid(pIds, MIID_CLIST)) dat->bRequiresRestart = true; LVITEM it = { 0 }; diff --git a/src/mir_app/src/stdafx.h b/src/mir_app/src/stdafx.h index bbcc675087..890c13c082 100644 --- a/src/mir_app/src/stdafx.h +++ b/src/mir_app/src/stdafx.h @@ -29,6 +29,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define INCL_WINSOCK_API_TYPEDEFS 1 +#define HSSL_DEFINED 1 +typedef struct SslHandle *HSSL; + #include #include #include @@ -92,7 +95,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include -#include #include #include #include -- cgit v1.2.3