Files
smartservice_native/hdssd/huslib/MultiplexSslSocket.cpp
T
2026-05-20 03:08:08 +09:00

628 lines
15 KiB
C++

#include "stringex.h"
#include "Defines.h"
#include "Common.h"
#include "Object.h"
#include "String.h"
#include "Logger.h"
#include "Socket.h"
#ifndef SINGLE_THREADED_MODEL
#include "Thread.h"
#endif
#include "Timer.h"
#include "NetUtil.h"
#include "Global.h"
#include "StreamBuffer.h"
#include "MultiplexSocket.h"
#include "MultiplexSslSocket.h"
//#include <limits.h>
/* common define */
typedef int bool_t;
//#define errlog printf
#if defined(_WIN32) /* Windows specific #includes and #defines */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400 /* To make it link in VS2005 */
#endif
//#include <windows.h>
#define SSL_LIB "ssleay32.dll"
#define CRYPTO_LIB "libeay32.dll"
static HANDLE dlopen(const char *dll_name, int flags)
{
return (LoadLibraryA(dll_name));
}
#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
#define RTLD_LAZY 0
#if _MSC_VER <= 1200
#define __func__ ""
#else
#define __func__ __FUNCTION__
#endif
#else
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/mman.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <pwd.h>
#include <unistd.h>
#include <dirent.h>
#include <dlfcn.h>
#define SSL_LIB "libssl.so"
#define CRYPTO_LIB "libcrypto.so"
typedef int SOCKET;
//#define false 0
//#define true 1
#define closesocket close
#endif
#include "openssl/ssl.h"
#include "openssl/tls1.h"
#include "openssl/err.h"
#ifdef _WIN32
#pragma comment(lib, "libeay32.lib")
#pragma comment(lib, "ssleay32.lib")
#endif
HSyncObject * g_arrSyncObject;
void ssl_locking_callback(int mode, int n, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
g_arrSyncObject[n].Lock();
else
g_arrSyncObject[n].Unlock();
}
/* This is a context that we pass to callbacks */
typedef struct tlsextctx_st {
BIO *biodebug;
int ack;
} tlsextctx;
static int ssl_servername_cb(SSL *s, int *ad, void *arg)
{
tlsextctx *p = (tlsextctx *) arg;
const char *hn = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
if (SSL_get_servername_type(s) != -1)
p->ack = !SSL_session_reused(s) && hn != NULL;
//else
// BIO_printf(bio_err, "Can't use SSL_get_servername\n");
return SSL_TLSEXT_ERR_OK;
}
void ssl_init()
{
int nLockCount = CRYPTO_num_locks();
g_arrSyncObject = new HSyncObject[nLockCount];
CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))ssl_locking_callback);
/* Initialize SSL crap */
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
}
SSL_CTX * ssl_client_init(const char * pszHostName) //...
{
if (pszHostName[0])
{
//if (strcmp(GetDomainNamePtr(pszHostName), "igi-global.com") == 0) // www.igi-global.com
// return SSL_CTX_new(TLSv1_1_client_method());
if (strcmp(GetDomainNamePtr(pszHostName), "wipson.com") == 0 || // www.wipson.com
strcmp(GetDomainNamePtr(pszHostName), "ibfd.org") == 0 || // www.ibfd.org
strcmp(GetDomainNamePtr(pszHostName), "igi-global.com") == 0 || // www.igi-global.com
strcmp(GetDomainNamePtr(pszHostName), "wisdomain.com") == 0 || // www.igi-global.com
strcmp(GetDomainNamePtr(pszHostName), "tobaccojournal.com") == 0 || // www.tobaccojournal.com
strcmp(GetDomainNamePtr(pszHostName), "cabdirect.org") == 0 || // www.tobaccojournal.com
strcmp(GetDomainNamePtr(pszHostName), "ebsco.com") == 0)// || // atoz.ebsco.com
//strcmp(GetDomainNamePtr(pszHostName), "refworks.com") == 0) // www.refworks.com
return SSL_CTX_new(TLSv1_client_method());
else if (strcmp(GetDomainNamePtr(pszHostName), "dbpia.co.kr") == 0)
return SSL_CTX_new(SSLv23_client_method());
//else if (strcmp(pszHostName, "saemobilus.sae.org") == 0 ||
// strcmp(pszHostName, "www.samsungdesign.net") == 0)
// return SSL_CTX_new(TLSv1_2_client_method());
//return SSL_CTX_new(SSLv23_client_method()); // www.samsungdesign.net, hb8xw4yu6z.search.serialssolutions.com fail
//return SSL_CTX_new(TLSv1_client_method()); // saemobilus.sae.org fail
}
return SSL_CTX_new(TLSv1_2_client_method());
}
int verify_callback(int ok, X509_STORE_CTX *store)
{
char data[256];
/* if (ok) to debug */
if (!ok)
{
X509 *cert = X509_STORE_CTX_get_current_cert(store);
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
fprintf(stderr, " issuer = %s\n", data);
X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
fprintf(stderr, " subject = %s\n", data);
fprintf(stderr, " err %i:%s\n", err, X509_verify_cert_error_string(err) );
}
return ok;
}
SSL_CTX * ssl_server_init(const char * pszCertPath, const char * pszKeyPath, const char * pszCaPath)
{
SSL_CTX * ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (ssl_ctx == NULL)
{
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_new in ssl_server_init\n");
return NULL;
}
//if (ctx->ssl_password_callback != NULL)
// SSL_CTX_set_default_passwd_cb(CTX, ctx->ssl_password_callback);
if (SSL_CTX_use_certificate_file(ssl_ctx, pszCertPath, SSL_FILETYPE_PEM) == 0)
{
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_use_certificate_file, %s\n", pszCertPath);
return NULL;
}
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, pszKeyPath, SSL_FILETYPE_PEM) == 0)
{
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_use_certificate_file, %s\n", pszKeyPath);
return NULL;
}
#if 0
sprintf(szPemFile, "%slibproxy_chain.pem", pszAppDir);
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, szPemFile) == 0)
{
HLOGF(2, "openssl\t[ERROR] Failed to SSL_CTX_use_certificate_chain_file, %s\n", szPemFile);
return NULL;
}
#endif
/* Load the CAs we trust*/
if (SSL_CTX_load_verify_locations(ssl_ctx, pszCaPath, 0) == 0)
{
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Failed to SSL_CTX_load_verify_locations, %s\n", pszCaPath);
return NULL;
}
//SSL_CTX_set_verify_depth(ssl_ctx, 1);
//SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback);
return ssl_ctx;
}
void ssl_ctx_destroy(SSL_CTX * ssl_ctx)
{
if (!ssl_ctx)
return;
SSL_CTX_free(ssl_ctx);
}
int ssl_send(SSL * ssl, char * buf, int len, int flags)
{
if (!ssl)
return -1;
return SSL_write(ssl, buf, len);
}
int ssl_recv(SSL * ssl, char * buf, int len, int flags)
{
if (!ssl)
return -1;
return SSL_read(ssl, buf, len);
}
//////////////////////////////////////////////////////////////////////////////
SSL_CTX * HMultiplexSslSocket::m_sslCtxServer = NULL;
void HMultiplexSslSocket::SslInit(const char * pszCertPath, const char * pszKeyPath, const char * pszCaPath)
{
static bool bIsSslInit = false;
if (bIsSslInit == false)
{
bIsSslInit = true;
ssl_init();
HMultiplexSslSocket::m_sslCtxServer = ssl_server_init(pszCertPath, pszKeyPath, pszCaPath);
}
}
void HMultiplexSslSocket::SslDestroy()
{
ssl_ctx_destroy(m_sslCtxServer);
m_sslCtxServer = NULL;
ERR_remove_state(0);
//ENGINE_cleanup();
//CONF_modules_unload(1);
ERR_free_strings();
EVP_cleanup();
sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
CRYPTO_cleanup_all_ex_data();
delete [] g_arrSyncObject;
}
///////////////////////////////////////
HMultiplexSslSocket::HMultiplexSslSocket()
{
m_ssl_ctx = NULL;
m_ssl = NULL;
m_rbio = NULL;
m_pStreamBufferForDecrypt = new HStreamBuffer(65536);
m_wbio = NULL;
m_pStreamBufferForSend = new HStreamBuffer(SSL3_RT_MAX_PACKET_SIZE);
m_pBufferForRecv = (char *)malloc(g_nSocketReceiveBlockSize);
m_szDstServerName[0] = '\0';
m_bIsSslConnecting = false;
m_bEncryptRetry = false;
}
HMultiplexSslSocket::HMultiplexSslSocket(SOCKET sock, struct sockaddr_in * psaiRemote, HMpsDispatcher * pDispatcher)
: HMultiplexTcpSocket(sock, psaiRemote, pDispatcher)
{
m_ssl_ctx = NULL;
m_ssl = NULL;
m_rbio = NULL;
m_pStreamBufferForDecrypt = new HStreamBuffer(65536);
m_wbio = NULL;
m_pStreamBufferForSend = new HStreamBuffer(SSL3_RT_MAX_PACKET_SIZE);
m_pBufferForRecv = (char *)malloc(g_nSocketReceiveBlockSize);
m_szDstServerName[0] = '\0';
m_bIsSslConnecting = false;
m_bEncryptRetry = false;
}
HMultiplexSslSocket::~HMultiplexSslSocket()
{
if (m_ssl)
SSL_free(m_ssl);
if (m_ssl_ctx != m_sslCtxServer)
ssl_ctx_destroy(m_ssl_ctx);
delete m_pStreamBufferForDecrypt;
delete m_pStreamBufferForSend;
free(m_pBufferForRecv);
}
bool HMultiplexSslSocket::Close()
{
if (m_nState == MPS_DISABLE ||
(m_nState == MPS_DELETE && m_fdSocket == INVALID_SOCKET))
//if (m_fdSocket == INVALID_SOCKET)
return false;
OnClose();
if (m_nState != MPS_LISTENING)
shutdown(m_fdSocket, SD_BOTH);
if (m_nState != MPS_DELETE)
m_nState = MPS_DISABLE;
SSL_free(m_ssl); // free the SSL object and its BIO's
m_ssl = NULL;
closesocket(m_fdSocket);
HLOGF(HLOG_INFO5, "INFO, SslSock, socket closed, socket = %d\n", m_fdSocket);
m_fdSocket = INVALID_SOCKET;
return true;
}
int HMultiplexSslSocket::Send(const char * pData, int nSize)
{
if ((size_t)nSize > m_pStreamBufferForSend->RemainSize())
{
SendBufferedData();
m_bEncryptRetry = true;
m_bSendRetry = true;
return 0;
}
if (!SSL_is_init_finished(m_ssl))
{
m_bEncryptRetry = true;
m_bSendRetry = true;
return 0;
}
const char * pDataOffset = pData;
int nRemainSize = nSize;
int nResult;
int nSslError;
while (nRemainSize > 0)
{
nResult = SSL_write(m_ssl, pDataOffset, nRemainSize);
nSslError = SSL_get_error(m_ssl, nResult);
if (nResult > 0)
{
pDataOffset += nResult;
nRemainSize -= nResult;
do
{
nResult = BIO_read(m_wbio, m_pStreamBufferForSend->Tail(), m_pStreamBufferForSend->RemainSize());
if (nResult > 0)
m_pStreamBufferForSend->MoveTail(nResult);
else if (!BIO_should_retry(m_wbio))
{
HLOGF(HLOG_ERROR, "SSL_TRACE, 1, socket = %d\n", m_fdSocket);
m_nState = MPS_CLOSING;
return SOCKET_ERROR;
}
} while (nResult > 0);
}
if (nSslError != SSL_ERROR_NONE && nSslError != SSL_ERROR_WANT_WRITE && nSslError != SSL_ERROR_WANT_READ)
{
HLOGF(HLOG_WARNING, "[WARN], SslSock, socket = %d, error = %d, %d\n", m_fdSocket, nSslError, nResult);
m_nState = MPS_CLOSING;
return SOCKET_ERROR;
}
if (nResult == 0)
break;
}
m_bEncryptRetry = false;
if (m_pStreamBufferForSend->StoredSize() > 0)
SendBufferedData();
if (nRemainSize > 0)
{
m_bEncryptRetry = true;
m_bSendRetry = true;
return nSize - nRemainSize;
}
return nSize;
}
int HMultiplexSslSocket::SendBufferedData()
{
if (m_pStreamBufferForSend->StoredSize() == 0)
return SOCKET_ERROR;
int nSentSize = HMultiplexTcpSocket::Send(m_pStreamBufferForSend->Head(), m_pStreamBufferForSend->StoredSize());
if (nSentSize <= 0)
return nSentSize;
m_pStreamBufferForSend->Pop(nSentSize);
return nSentSize;
}
int HMultiplexSslSocket::Receive()
{
int nReceivedSize = HMultiplexTcpSocket::Receive(m_pBufferForRecv, g_nSocketReceiveBlockSize);
if (nReceivedSize <= 0)
return nReceivedSize;
char * pBufferOffset = m_pBufferForRecv;
int nResult;
while (nReceivedSize > 0)
{
nResult = BIO_write(m_rbio, pBufferOffset, nReceivedSize);
if (nResult <= 0)
{
HLOGF(HLOG_INFO4, "INFO, SslSock, assume bio write failure is unrecoverable, socket = %d\n", m_fdSocket);
m_nState = MPS_CLOSING;
return SOCKET_ERROR;
}
pBufferOffset += nResult;
nReceivedSize -= nResult;
if (!SSL_is_init_finished(m_ssl))
{
if (ProcHandShake() == false)
{
if (m_bIsSslConnecting)
OnConnectChild(false);
return -1;
}
if (!SSL_is_init_finished(m_ssl))
return 0;
}
do {
nResult = SSL_read(m_ssl, m_pStreamBufferForDecrypt->Tail(), m_pStreamBufferForDecrypt->RemainSize());
if (nResult > 0)
m_pStreamBufferForDecrypt->MoveTail(nResult);
} while (nResult > 0);
int nSslError = SSL_get_error(m_ssl, nResult);
if (nSslError == SSL_ERROR_WANT_WRITE || nSslError == SSL_ERROR_WANT_READ)
{
do
{
nResult = BIO_read(m_wbio, m_pStreamBufferForSend->Tail(), m_pStreamBufferForSend->RemainSize());
if (nResult > 0)
m_pStreamBufferForSend->MoveTail(nResult);
else if (!BIO_should_retry(m_wbio))
{
HLOGF(HLOG_WARNING, "TRACE, SslSock, 1. Did SSL request to write bytes? This can happen if peer has requested SSL * renegotiation, socket = %d, %d, %d\n", m_fdSocket, nSslError, nResult);
m_nState = MPS_CLOSING;
return SOCKET_ERROR;
}
} while (nResult > 0);
}
else if (nSslError == SSL_ERROR_ZERO_RETURN || nSslError == SSL_ERROR_SYSCALL)
{
HLOGF(HLOG_WARNING, "TRACE, SslSock, 2. Did SSL request to write bytes? This can happen if peer has requested SSL * renegotiation, socket = %d, %d, %d\n", m_fdSocket, nSslError, nResult);
//...???
}
}
if (m_pStreamBufferForSend->StoredSize() > 0)
SendBufferedData();
if (m_bIsSslConnecting)
{
m_bIsSslConnecting = false;
OnConnectChild(true);
return 0;
}
return m_pStreamBufferForDecrypt->StoredSize();
}
bool HMultiplexSslSocket::SetRemoteAddressHostByName(const char * pszHostName, u_short nPort)
{
strcpy(m_szDstServerName, pszHostName);
return HMultiplexTcpSocket::SetRemoteAddressHostByName(pszHostName, nPort);
}
bool HMultiplexSslSocket::IsRemain()
{
if (m_ssl == NULL)
return false;
return SSL_pending(m_ssl) > 0;
}
void HMultiplexSslSocket::OnConnect(bool bIsSuccess)
{
if (bIsSuccess)
{
m_ssl_ctx = ssl_client_init(m_szDstServerName);
//tlsextcbp.biodebug = bio_err;
//SSL_CTX_set_tlsext_servername_callback(m_ssl_ctx, ssl_servername_cb);
//SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp);
if ((m_ssl = SSL_new(m_ssl_ctx)) == NULL)
{
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Faield to SSL_new 1, socket = %d\n", m_fdSocket);
OnConnectChild(false);
return;
}
if (m_szDstServerName[0] && !SSL_set_tlsext_host_name(m_ssl, m_szDstServerName))
{
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Unable to set TLS servername extension, socket = %d\n", m_fdSocket);
OnConnectChild(false);
return;
}
SSL_set_connect_state(m_ssl);
m_rbio = BIO_new(BIO_s_mem());
m_wbio = BIO_new(BIO_s_mem());
SSL_set_bio(m_ssl, m_rbio, m_wbio);
m_bIsSslConnecting = true;
ProcHandShake();
}
else
{
OnConnectChild(false);
}
}
void HMultiplexSslSocket::OnAccepted()
{
if ((m_ssl = SSL_new(m_sslCtxServer)) == NULL)
{
HLOGF(HLOG_ERROR, "[ERROR], SslSock, Faield to SSL_new 2, socket = %d\n", m_fdSocket);
return;
}
m_ssl_ctx = m_sslCtxServer;
SSL_set_accept_state(m_ssl);
m_rbio = BIO_new(BIO_s_mem());
m_wbio = BIO_new(BIO_s_mem());
SSL_set_bio(m_ssl, m_rbio, m_wbio);
//m_bIsSslConnecting = true;
}
bool HMultiplexSslSocket::ProcHandShake()
{
int nSslResult = SSL_do_handshake(m_ssl);
int nSslError = SSL_get_error(m_ssl, nSslResult);
if (nSslError == SSL_ERROR_WANT_WRITE || nSslError == SSL_ERROR_WANT_READ)
{
do
{
nSslResult = BIO_read(m_wbio, m_pStreamBufferForSend->Tail(), m_pStreamBufferForSend->RemainSize());
if (nSslResult > 0)
m_pStreamBufferForSend->MoveTail(nSslResult);
else if (!BIO_should_retry(m_wbio))
{
m_pStreamBufferForSend->Reset();
HLOGF(HLOG_WARNING, "[WARN], SslSock, Failed to HandShake 1, socket = %d, error = %d\n", m_fdSocket, nSslError);
return false;
}
} while (nSslResult > 0);
if (m_pStreamBufferForSend->StoredSize() > 0)
SendBufferedData();
}
else if (nSslError == SSL_ERROR_ZERO_RETURN || nSslError == SSL_ERROR_SYSCALL)
{
HLOGF(HLOG_WARNING, "[WARN], SslSock, Failed to HandShake 2, socket = %d, error = %d\n", m_fdSocket, nSslError);
return false;
}
return true;
}