Fetch the repository succeeded.
This action will force synchronization from 伤神小怪兽/HP-Socket, which will overwrite any changes that you have made since you forked the repository, and can not be recovered!!!
Synchronous operation will process in the background and will refresh the page when finishing processing. Please be patient.
/*
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
*
* Author : Bruce Liang
* Website : https://github.com/ldcsaa
* Project : https://github.com/ldcsaa/HP-Socket
* Blog : http://www.cnblogs.com/ldcsaa
* Wiki : http://www.oschina.net/p/hp-socket
* QQ Group : 44636872, 75375912
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SSLHelper.h"
#ifdef _SSL_SUPPORT
#include "SocketHelper.h"
#include "common/FileHelper.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/engine.h"
#include "openssl/x509v3.h"
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
int CSSLInitializer::sm_iLockNum = 0;
CSimpleRWLock* CSSLInitializer::sm_pcsLocks = nullptr;
#endif
CSSLInitializer CSSLInitializer::sm_instance;
const DWORD CSSLSessionPool::DEFAULT_ITEM_CAPACITY = CItemPool::DEFAULT_ITEM_CAPACITY;
const DWORD CSSLSessionPool::DEFAULT_ITEM_POOL_SIZE = CItemPool::DEFAULT_POOL_SIZE;
const DWORD CSSLSessionPool::DEFAULT_ITEM_POOL_HOLD = CItemPool::DEFAULT_POOL_HOLD;
const DWORD CSSLSessionPool::DEFAULT_SESSION_LOCK_TIME = DEFAULT_OBJECT_CACHE_LOCK_TIME;
const DWORD CSSLSessionPool::DEFAULT_SESSION_POOL_SIZE = DEFAULT_OBJECT_CACHE_POOL_SIZE;
const DWORD CSSLSessionPool::DEFAULT_SESSION_POOL_HOLD = DEFAULT_OBJECT_CACHE_POOL_HOLD;
CSSLInitializer::CSSLInitializer()
{
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
sm_iLockNum = CRYPTO_num_locks();
if(sm_iLockNum > 0)
sm_pcsLocks = new CSimpleRWLock[sm_iLockNum];
/*
#ifdef _DEBUG
CRYPTO_malloc_debug_init();
CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
#endif
*/
CRYPTO_set_locking_callback (&ssl_lock_callback);
CRYPTO_set_dynlock_create_callback (&ssl_lock_dyn_create_callback);
CRYPTO_set_dynlock_destroy_callback (&ssl_lock_dyn_destroy_callback);
CRYPTO_set_dynlock_lock_callback (&ssl_lock_dyn_callback);
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
#else
OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, nullptr);
#endif
}
CSSLInitializer::~CSSLInitializer()
{
CleanupThreadState();
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
CONF_modules_free();
ENGINE_cleanup();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
#if OPENSSL_VERSION_NUMBER >= OPENSSL_VERSION_1_0_2
SSL_COMP_free_compression_methods();
#endif
CRYPTO_set_locking_callback (nullptr);
CRYPTO_set_dynlock_create_callback (nullptr);
CRYPTO_set_dynlock_destroy_callback (nullptr);
CRYPTO_set_dynlock_lock_callback (nullptr);
if(sm_iLockNum > 0)
{
delete[] sm_pcsLocks;
sm_pcsLocks = nullptr;
sm_iLockNum = 0;
}
#endif
}
void CSSLInitializer::CleanupThreadState(THR_ID dwThreadID)
{
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
CRYPTO_THREADID tid = {nullptr, dwThreadID};
CRYPTO_THREADID_current(&tid);
ERR_remove_thread_state(&tid);
#else
OPENSSL_thread_stop();
#endif
}
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
void CSSLInitializer::ssl_lock_callback(int mode, int n, const char *file, int line)
{
mode & CRYPTO_LOCK
? (mode & CRYPTO_READ
? sm_pcsLocks[n].lock_shared()
: sm_pcsLocks[n].lock())
: (mode & CRYPTO_READ
? sm_pcsLocks[n].unlock_shared()
: sm_pcsLocks[n].unlock());
}
CRYPTO_dynlock_value* CSSLInitializer::ssl_lock_dyn_create_callback(const char *file, int line)
{
return new DynamicLock;
}
void CSSLInitializer::ssl_lock_dyn_callback(int mode, CRYPTO_dynlock_value* l, const char *file, int line)
{
mode & CRYPTO_LOCK
? (mode & CRYPTO_READ
? l->cs.lock_shared()
: l->cs.lock())
: (mode & CRYPTO_READ
? l->cs.unlock_shared()
: l->cs.unlock());
}
void CSSLInitializer::ssl_lock_dyn_destroy_callback(CRYPTO_dynlock_value* l, const char *file, int line)
{
delete l;
}
#endif
BOOL CSSLContext::Initialize(EnSSLSessionMode enSessionMode, int iVerifyMode, BOOL bMemory, LPVOID lpPemCert, LPVOID lpPemKey, LPVOID lpKeyPasswod, LPVOID lpCAPemCert, HP_Fn_SNI_ServerNameCallback fnServerNameCallback)
{
ASSERT(!IsValid());
if(IsValid())
{
::SetLastError(ERROR_INVALID_STATE);
return FALSE;
}
m_enSessionMode = enSessionMode;
if(AddContext(iVerifyMode, bMemory, lpPemCert, lpPemKey, lpKeyPasswod, lpCAPemCert) == 0)
m_sslCtx = GetContext(0);
else
{
EXECUTE_RESTORE_ERROR(Cleanup());
return FALSE;
}
SetServerNameCallback(fnServerNameCallback);
return TRUE;
}
int CSSLContext::AddServerContext(int iVerifyMode, BOOL bMemory, LPVOID lpPemCert, LPVOID lpPemKey, LPVOID lpKeyPasswod, LPVOID lpCAPemCert)
{
ASSERT(IsValid());
if(!IsValid())
{
::SetLastError(ERROR_INVALID_STATE);
return FALSE;
}
if(m_enSessionMode != SSL_SM_SERVER)
{
::SetLastError(ERROR_INVALID_OPERATION);
return FALSE;
}
return AddContext(iVerifyMode, bMemory, lpPemCert, lpPemKey, lpKeyPasswod, lpCAPemCert);
}
BOOL CSSLContext::BindServerName(LPCTSTR lpszServerName, int iContextIndex)
{
ASSERT(lpszServerName && iContextIndex >= 0 && !::IsIPAddress(lpszServerName));
if(!lpszServerName || iContextIndex < 0 || ::IsIPAddress(lpszServerName))
{
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
int iLen = lstrlen(lpszServerName);
LPCTSTR lpszSep = ::StrChr(lpszServerName, SSL_DOMAIN_SEP_CHAR);
if(lpszSep == nullptr || lpszSep == lpszServerName || lpszSep == (lpszServerName + iLen - 1))
{
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
int iSize = (int)m_lsSslCtxs.size();
if(iSize <= iContextIndex)
{
::SetLastError(ERROR_INVALID_INDEX);
return FALSE;
}
m_sslServerNames[lpszServerName] = iContextIndex;
return TRUE;
}
int CSSLContext::AddContext(int iVerifyMode, BOOL bMemory, LPVOID lpPemCert, LPVOID lpPemKey, LPVOID lpKeyPasswod, LPVOID lpCAPemCert)
{
USES_CONVERSION;
int iIndex = -1;
#if OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_1_1_0
SSL_CTX* sslCtx = SSL_CTX_new(SSLv23_method());
#else
SSL_CTX* sslCtx = SSL_CTX_new(TLS_method());
#endif
SSL_CTX_set_quiet_shutdown(sslCtx, 1);
SSL_CTX_set_verify(sslCtx, iVerifyMode, nullptr);
if(!SSL_CTX_set_cipher_list(sslCtx, T2CA(m_strCipherList)))
::SetLastError(ERROR_EMPTY);
else
{
if(m_enSessionMode == SSL_SM_SERVER)
{
static volatile ULONG s_session_id_context = 0;
ULONG session_id_context = ::InterlockedIncrement(&s_session_id_context);
SSL_CTX_set_session_id_context(sslCtx, (BYTE*)&session_id_context, sizeof(session_id_context));
}
if(LoadCertAndKey(sslCtx, iVerifyMode, bMemory, lpPemCert, lpPemKey, lpKeyPasswod, lpCAPemCert))
{
iIndex = (int)m_lsSslCtxs.size();
m_lsSslCtxs.push_back(sslCtx);
}
}
if(iIndex < 0)
EXECUTE_RESTORE_ERROR(SSL_CTX_free(sslCtx));
return iIndex;
}
BOOL CSSLContext::LoadCertAndKey(SSL_CTX* sslCtx, int iVerifyMode, BOOL bMemory, LPVOID lpPemCert, LPVOID lpPemKey, LPVOID lpKeyPasswod, LPVOID lpCAPemCert)
{
if(bMemory)
return LoadCertAndKeyByMemory(sslCtx, iVerifyMode, (LPCSTR)lpPemCert, (LPCSTR)lpPemKey, (LPCSTR)lpKeyPasswod, (LPCSTR)lpCAPemCert);
else
return LoadCertAndKeyByFile(sslCtx, iVerifyMode, (LPCTSTR)lpPemCert, (LPCTSTR)lpPemKey, (LPCTSTR)lpKeyPasswod, (LPCTSTR)lpCAPemCert);
}
BOOL CSSLContext::LoadCertAndKeyByFile(SSL_CTX* sslCtx, int iVerifyMode, LPCTSTR lpszPemCertFile, LPCTSTR lpszPemKeyFile, LPCTSTR lpszKeyPassword, LPCTSTR lpszCAPemCertFileOrPath)
{
USES_CONVERSION;
if(::IsStrNotEmpty(lpszCAPemCertFileOrPath))
{
LPCTSTR lpszCAPemCertFile = nullptr;
LPCTSTR lpszCAPemCertPath = nullptr;
CFile fCAPemCertFile(lpszCAPemCertFileOrPath, O_RDONLY | O_CLOEXEC);
if(!fCAPemCertFile.IsExist())
{
::SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}
if(fCAPemCertFile.IsFile())
lpszCAPemCertFile = lpszCAPemCertFileOrPath;
else if(fCAPemCertFile.IsDirectory())
lpszCAPemCertPath = lpszCAPemCertFileOrPath;
else
{
::SetLastError(ERROR_BAD_FILE_TYPE);
return FALSE;
}
if(!SSL_CTX_load_verify_locations(sslCtx, T2CA(lpszCAPemCertFile), T2CA(lpszCAPemCertPath)))
{
::SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
if(!SSL_CTX_set_default_verify_paths(sslCtx))
{
::SetLastError(ERROR_FUNCTION_FAILED);
return FALSE;
}
if(m_enSessionMode == SSL_SM_SERVER && (iVerifyMode & SSL_VM_PEER) && lpszCAPemCertFile != nullptr)
{
STACK_OF(X509_NAME)* caCertNames = SSL_load_client_CA_file(T2CA(lpszCAPemCertFile));
if(caCertNames == nullptr)
{
::SetLastError(ERROR_EMPTY);
return FALSE;
}
SSL_CTX_set_client_CA_list(sslCtx, caCertNames);
}
}
if(::IsStrNotEmpty(lpszPemCertFile))
{
CFile fPemCertFile(lpszPemCertFile, O_RDONLY | O_CLOEXEC);
if(!fPemCertFile.IsFile())
{
::SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}
if(::IsStrEmpty(lpszPemKeyFile))
{
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
CFile fPemKeyFile(lpszPemKeyFile, O_RDONLY | O_CLOEXEC);
if(!fPemKeyFile.IsFile())
{
::SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}
if(::IsStrNotEmpty(lpszKeyPassword))
SSL_CTX_set_default_passwd_cb_userdata(sslCtx, (void*)T2CA(lpszKeyPassword));
if(!SSL_CTX_use_PrivateKey_file(sslCtx, T2CA(lpszPemKeyFile), SSL_FILETYPE_PEM))
{
::SetLastError(ERROR_INVALID_PASSWORD);
return FALSE;
}
if(!SSL_CTX_use_certificate_chain_file(sslCtx, T2CA(lpszPemCertFile)))
{
::SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
if(!SSL_CTX_check_private_key(sslCtx))
{
::SetLastError(ERROR_INVALID_ACCESS);
return FALSE;
}
}
return TRUE;
}
BOOL CSSLContext::LoadCertAndKeyByMemory(SSL_CTX* sslCtx, int iVerifyMode, LPCSTR lpszPemCert, LPCSTR lpszPemKey, LPCSTR lpszKeyPassword, LPCSTR lpszCAPemCert)
{
if(!LoadCAPemCertByMemory(sslCtx, iVerifyMode, lpszCAPemCert))
return FALSE;
if(!LoadPemCertAndKeyByMemory(sslCtx, lpszPemCert, lpszPemKey, lpszKeyPassword))
return FALSE;
return TRUE;
}
BOOL CSSLContext::LoadCAPemCertByMemory(SSL_CTX* sslCtx, int iVerifyMode, LPCSTR lpszCAPemCert)
{
if(::IsStrEmptyA(lpszCAPemCert))
return TRUE;
if(!AddCAPemCertToStoreByMemory(sslCtx, lpszCAPemCert))
return FALSE;
if(!SSL_CTX_set_default_verify_paths(sslCtx))
{
::SetLastError(ERROR_FUNCTION_FAILED);
return FALSE;
}
if(m_enSessionMode == SSL_SM_SERVER && (iVerifyMode & SSL_VM_PEER))
{
if(!SetClientCAListByMemory(sslCtx, lpszCAPemCert))
return FALSE;
}
return TRUE;
}
BOOL CSSLContext::LoadPemCertAndKeyByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert, LPCSTR lpszPemKey, LPCSTR lpszKeyPassword)
{
if(::IsStrEmptyA(lpszPemCert))
return TRUE;
if(::IsStrEmptyA(lpszPemKey))
{
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if(::IsStrNotEmptyA(lpszKeyPassword))
SSL_CTX_set_default_passwd_cb_userdata(sslCtx, (void*)(lpszKeyPassword));
if(!SetPrivateKeyByMemory(sslCtx, lpszPemKey))
return FALSE;
if(!SetCertChainByMemory(sslCtx, lpszPemCert))
return FALSE;
if(!SSL_CTX_check_private_key(sslCtx))
{
::SetLastError(ERROR_INVALID_ACCESS);
return FALSE;
}
return TRUE;
}
BOOL CSSLContext::AddCAPemCertToStoreByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert)
{
BOOL isOK = FALSE;
int iCount = 0;
BIO* pBIO = BIO_new_mem_buf(lpszPemCert, -1);
X509_STORE* pStore = SSL_CTX_get_cert_store(sslCtx);
STACK_OF(X509_INFO) * pStack = nullptr;
if(pBIO == nullptr)
{
::SetLastError(ERROR_CREATE_FAILED);
goto _END;
}
if(pStore == nullptr)
{
::SetLastError(ERROR_NOT_FOUND);
goto _END;
}
pStack = PEM_X509_INFO_read_bio(pBIO, nullptr, nullptr, nullptr);
if(pStack == nullptr)
{
::SetLastError(ERROR_NO_DATA);
goto _END;
}
for(int i = 0; i < sk_X509_INFO_num(pStack); i++)
{
X509_INFO* pInfo = sk_X509_INFO_value(pStack, i);
if(pInfo->x509)
{
if(!X509_STORE_add_cert(pStore, pInfo->x509))
{
::SetLastError(ERROR_INVALID_DATA);
goto _END;
}
++iCount;
}
if(pInfo->crl)
{
if(!X509_STORE_add_crl(pStore, pInfo->crl))
{
::SetLastError(ERROR_INVALID_DATA);
goto _END;
}
++iCount;
}
}
if(iCount > 0)
isOK = TRUE;
else
::SetLastError(ERROR_EMPTY);
_END:
if(pStack != nullptr)
sk_X509_INFO_pop_free(pStack, X509_INFO_free);
if(pBIO != nullptr)
BIO_free(pBIO);
return isOK;
}
BOOL CSSLContext::SetClientCAListByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert)
{
BOOL isOK = FALSE;
X509* pX509 = nullptr;
X509_NAME* pName = nullptr;
STACK_OF(X509_NAME)* pStack = nullptr;
BIO* pBIO = BIO_new_mem_buf(lpszPemCert, -1);
OPENSSL_LHASH* pNameHash = (OPENSSL_LHASH*)OPENSSL_LH_new((OPENSSL_LH_HASHFUNC)FN_X509_NAME_HASH, (OPENSSL_LH_COMPFUNC)X509_NAME_cmp);
if(pBIO == nullptr || pNameHash == nullptr)
{
::SetLastError(ERROR_CREATE_FAILED);
goto _ERR;
}
while(TRUE)
{
if(PEM_read_bio_X509(pBIO, &pX509, nullptr, nullptr) == nullptr)
break;
if(pStack == nullptr)
{
pStack = sk_X509_NAME_new_null();
if(pStack == nullptr)
{
::SetLastError(ERROR_CREATE_FAILED);
goto _ERR;
}
}
if((pName = X509_get_subject_name(pX509)) == nullptr)
{
::SetLastError(ERROR_NO_DATA);
goto _ERR;
}
if((pName = X509_NAME_dup(pName)) == nullptr)
{
::SetLastError(ERROR_CREATE_FAILED);
goto _ERR;
}
if(OPENSSL_LH_retrieve(pNameHash, pName) != nullptr)
{
X509_NAME_free(pName);
pName = nullptr;
}
else
{
OPENSSL_LH_insert(pNameHash, pName);
if(!sk_X509_NAME_push(pStack, pName))
{
::SetLastError(ERROR_WRITE_FAULT);
goto _ERR;
}
}
}
if(pStack == nullptr)
{
::SetLastError(ERROR_EMPTY);
goto _ERR;
}
SSL_CTX_set_client_CA_list(sslCtx, pStack);
isOK = TRUE;
goto _END;
_ERR:
if(pName != nullptr)
X509_NAME_free(pName);
if(pStack != nullptr)
{
sk_X509_NAME_pop_free(pStack, X509_NAME_free);
pStack = nullptr;
}
_END:
if(pX509 != nullptr)
X509_free(pX509);
if(pNameHash != nullptr)
OPENSSL_LH_free(pNameHash);
if(pBIO != nullptr)
BIO_free(pBIO);
if(pStack != nullptr)
ERR_clear_error();
return isOK;
}
BOOL CSSLContext::SetPrivateKeyByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemKey)
{
BOOL isOK = FALSE;
BIO* pBIO = BIO_new_mem_buf(lpszPemKey, -1);
EVP_PKEY* pKey = nullptr;
if(pBIO == nullptr)
{
::SetLastError(ERROR_CREATE_FAILED);
goto _END;
}
pKey = PEM_read_bio_PrivateKey(pBIO, nullptr, SSL_CTX_get_default_passwd_cb(sslCtx), SSL_CTX_get_default_passwd_cb_userdata(sslCtx));
if(pKey == nullptr)
{
::SetLastError(ERROR_INVALID_PASSWORD);
goto _END;
}
if(!SSL_CTX_use_PrivateKey(sslCtx, pKey))
{
::SetLastError(ERROR_INVALID_DATA);
goto _END;
}
isOK = TRUE;
_END:
if(pKey != nullptr)
EVP_PKEY_free(pKey);
if(pBIO != nullptr)
BIO_free(pBIO);
return isOK;
}
BOOL CSSLContext::SetCertChainByMemory(SSL_CTX* sslCtx, LPCSTR lpszPemCert)
{
BOOL isOK = FALSE;
ULONG err = 0;
BIO* pBIO = BIO_new_mem_buf(lpszPemCert, -1);
X509* pX509 = nullptr;
pem_password_cb* cb = SSL_CTX_get_default_passwd_cb(sslCtx);
LPVOID userdata = SSL_CTX_get_default_passwd_cb_userdata(sslCtx);
if(pBIO == nullptr)
{
::SetLastError(ERROR_CREATE_FAILED);
goto _END;
}
pX509 = PEM_read_bio_X509_AUX(pBIO, nullptr, cb, userdata);
if(pX509 == nullptr)
{
::SetLastError(ERROR_NO_DATA);
goto _END;
}
if(!SSL_CTX_use_certificate(sslCtx, pX509) || (ERR_peek_error() != 0))
{
::SetLastError(ERROR_INVALID_DATA);
goto _END;
}
if(!SSL_CTX_clear_chain_certs(sslCtx))
{
::SetLastError(ERROR_FUNCTION_FAILED);
goto _END;
}
X509* pCA;
while((pCA = PEM_read_bio_X509(pBIO, nullptr, cb, userdata)) != nullptr)
{
if(!SSL_CTX_add0_chain_cert(sslCtx, pCA))
{
X509_free(pCA);
::SetLastError(ERROR_FUNCTION_FAILED);
goto _END;
}
}
err = ERR_peek_last_error();
if(ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
ERR_clear_error();
else
{
::SetLastError(ERROR_FUNCTION_FAILED);
goto _END;
}
isOK = TRUE;
_END:
if(pX509 != nullptr)
X509_free(pX509);
if(pBIO != nullptr)
BIO_free(pBIO);
return isOK;
}
void CSSLContext::Cleanup()
{
if(IsValid())
{
int iCount = (int)m_lsSslCtxs.size();
for(int i = 0; i < iCount; i++)
SSL_CTX_free(m_lsSslCtxs[i]);
m_lsSslCtxs.clear();
m_sslServerNames.clear();
m_sslCtx = nullptr;
}
m_fnServerNameCallback = nullptr;
RemoveThreadLocalState();
}
void CSSLContext::SetServerNameCallback(Fn_SNI_ServerNameCallback fn)
{
if(m_enSessionMode != SSL_SM_SERVER)
return;
if(fn == nullptr)
m_fnServerNameCallback = DefaultServerNameCallback;
else
m_fnServerNameCallback = fn;
VERIFY(SSL_CTX_set_tlsext_servername_callback(m_sslCtx, InternalServerNameCallback));
VERIFY(SSL_CTX_set_tlsext_servername_arg(m_sslCtx, this));
}
int CSSLContext::InternalServerNameCallback(SSL* ssl, int* ad, void* arg)
{
USES_CONVERSION;
CSSLContext* pThis = (CSSLContext*)arg;
ASSERT(pThis->m_fnServerNameCallback != nullptr);
const char* lpszServerName = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if(lpszServerName == nullptr)
return SSL_TLSEXT_ERR_NOACK;
int iIndex = pThis->m_fnServerNameCallback(A2CT(lpszServerName), pThis);
if(iIndex == 0)
return SSL_TLSEXT_ERR_OK;
if(iIndex < 0)
{
::SetLastError(ERROR_INVALID_NAME);
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
SSL_CTX* sslCtx = pThis->GetContext(iIndex);
if(sslCtx == nullptr)
{
::SetLastError(ERROR_INVALID_INDEX);
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
SSL_set_SSL_CTX(ssl, sslCtx);
return SSL_TLSEXT_ERR_OK;
}
int __HP_CALL CSSLContext::DefaultServerNameCallback(LPCTSTR lpszServerName, PVOID pContext)
{
CSSLContext* pThis = (CSSLContext*)pContext;
if(pThis->m_sslServerNames.empty())
return 0;
LPCTSTR lpszTmp = lpszServerName;
LPCTSTR lpszSep = ::StrChr(lpszTmp, SSL_DOMAIN_SEP_CHAR);
while(lpszSep != nullptr)
{
CServerNameMap::const_iterator it = pThis->m_sslServerNames.find(lpszTmp);
if(it != pThis->m_sslServerNames.end())
return it->second;
lpszTmp = (lpszSep + 1);
lpszSep = ::StrChr(lpszTmp, SSL_DOMAIN_SEP_CHAR);
}
return 0;
}
SSL_CTX* CSSLContext::GetContext(int i) const
{
SSL_CTX* sslCtx = nullptr;
if(i >= 0 && i < (int)m_lsSslCtxs.size())
sslCtx = m_lsSslCtxs[i];
return sslCtx;
}
BOOL CSSLSession::WriteRecvChannel(const BYTE* pData, int iLength)
{
ASSERT(pData && iLength > 0);
BOOL isOK = TRUE;
int bytes = BIO_write(m_bioRecv, pData, iLength);
if(bytes > 0)
ASSERT(bytes == iLength);
else if(!BIO_should_retry(m_bioRecv))
{
::SetLastError(ERROR_INVALID_DATA);
isOK = FALSE;
}
return isOK;
}
BOOL CSSLSession::ReadRecvChannel()
{
BOOL isOK = TRUE;
int bytes = SSL_read(m_ssl, m_bufRecv.buf, m_pitRecv->Capacity());
if(bytes > 0)
m_bufRecv.len = bytes;
else if(!IsFatalError(bytes))
m_bufRecv.len = 0;
else
isOK = FALSE;
if(isOK && m_enStatus == SSL_HSS_PROC && SSL_is_init_finished(m_ssl))
m_enStatus = SSL_HSS_SUCC;
return isOK;
}
BOOL CSSLSession::WriteSendChannel(const BYTE* pData, int iLength)
{
ASSERT(IsReady());
ASSERT(pData && iLength > 0);
BOOL isOK = TRUE;
int bytes = SSL_write(m_ssl, pData, iLength);
if(bytes > 0)
ASSERT(bytes == iLength);
else if(IsFatalError(bytes))
isOK = FALSE;
return isOK;
}
BOOL CSSLSession::WriteSendChannel(const WSABUF pBuffers[], int iCount)
{
ASSERT(pBuffers && iCount > 0);
BOOL isOK = TRUE;
for(int i = 0; i < iCount; i++)
{
const WSABUF& buffer = pBuffers[i];
if(buffer.len > 0)
{
if(!WriteSendChannel((const BYTE*)buffer.buf, buffer.len))
{
isOK = FALSE;
break;
}
}
}
return isOK;
}
BOOL CSSLSession::ReadSendChannel()
{
if(BIO_pending(m_bioSend) == 0)
{
m_bufSend.len = 0;
return TRUE;
}
BOOL isOK = TRUE;
int bytes = BIO_read(m_bioSend, m_bufSend.buf, m_pitSend->Capacity());
if(bytes > 0)
m_bufSend.len = bytes;
else if(BIO_should_retry(m_bioSend))
m_bufSend.len = 0;
else
{
::SetLastError(ERROR_INVALID_DATA);
isOK = FALSE;
}
return isOK;
}
CSSLSession* CSSLSession::Renew(const CSSLContext& sslCtx, LPCSTR lpszHostName)
{
ASSERT(!IsValid());
ResetCount();
m_ssl = SSL_new(sslCtx.GetDefaultContext());
m_bioSend = BIO_new(BIO_s_mem());
m_bioRecv = BIO_new(BIO_s_mem());
SSL_set_bio(m_ssl, m_bioRecv, m_bioSend);
if(sslCtx.GetSessionMode() == SSL_SM_SERVER)
SSL_accept(m_ssl);
else
{
USES_CONVERSION;
if(lpszHostName && lpszHostName[0] != 0 && !::IsIPAddress(A2CT(lpszHostName)))
SSL_set_tlsext_host_name(m_ssl, lpszHostName);
SSL_connect(m_ssl);
}
m_pitSend = m_itPool.PickFreeItem();
m_pitRecv = m_itPool.PickFreeItem();
m_bufSend.buf = m_pitSend->Ptr();
m_bufRecv.buf = m_pitRecv->Ptr();
m_enStatus = SSL_HSS_PROC;
return this;
}
BOOL CSSLSession::Reset()
{
BOOL isOK = FALSE;
if(IsValid())
{
CCriSecLock locallock(m_csSend);
if(IsValid())
{
m_enStatus = SSL_HSS_INIT;
SSL_shutdown(m_ssl);
SSL_free(m_ssl);
m_itPool.PutFreeItem(m_pitSend);
m_itPool.PutFreeItem(m_pitRecv);
m_pitSend = nullptr;
m_pitRecv = nullptr;
m_ssl = nullptr;
m_bioSend = nullptr;
m_bioRecv = nullptr;
m_dwFreeTime= ::TimeGetTime();
isOK = TRUE;
}
}
ERR_clear_error();
return isOK;
}
inline BOOL CSSLSession::IsFatalError(int iBytes)
{
int iErrorCode = SSL_get_error(m_ssl, iBytes);
if( iErrorCode == SSL_ERROR_NONE ||
iErrorCode == SSL_ERROR_WANT_READ ||
iErrorCode == SSL_ERROR_WANT_WRITE ||
iErrorCode == SSL_ERROR_WANT_CONNECT ||
iErrorCode == SSL_ERROR_WANT_ACCEPT )
return FALSE;
#ifdef _DEBUG
char szBuffer[512];
#endif
int i = 0;
ULONG iCode = iErrorCode;
for(; iCode != SSL_ERROR_NONE; i++)
{
#ifdef _DEBUG
ERR_error_string_n(iCode, szBuffer, sizeof(szBuffer));
TRACE(" > SSL Error: %ld - %s\n", iCode, szBuffer);
#endif
iCode = ERR_get_error();
}
if(iErrorCode == SSL_ERROR_SYSCALL && i == 1)
return FALSE;
::SetLastError(ERROR_INVALID_DATA);
return TRUE;
}
BOOL CSSLSession::GetSessionInfo(EnSSLSessionInfo enInfo, LPVOID* lppInfo)
{
ASSERT(lppInfo != nullptr);
*lppInfo = nullptr;
if(enInfo < SSL_SSI_MIN || enInfo > SSL_SSI_MAX)
{
::SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if(!IsValid())
{
::SetLastError(ERROR_INVALID_STATE);
return FALSE;
}
SSL_CTX* pContext = SSL_get_SSL_CTX(m_ssl);
switch(enInfo)
{
case SSL_SSI_CTX:
{
*lppInfo = (LPVOID)(pContext);
}
break;
case SSL_SSI_CTX_METHOD:
{
if(pContext != nullptr)
*lppInfo = (LPVOID)(SSL_CTX_get_ssl_method(pContext));
}
break;
case SSL_SSI_CTX_CIPHERS:
{
if(pContext != nullptr)
*lppInfo = (LPVOID)(SSL_CTX_get_ciphers(pContext));
}
break;
case SSL_SSI_CTX_CERT_STORE:
{
if(pContext != nullptr)
*lppInfo = (LPVOID)(SSL_CTX_get_cert_store(pContext));
}
break;
case SSL_SSI_SERVER_NAME_TYPE:
{
*lppInfo = (LPVOID)(UINT_PTR)(SSL_get_servername_type(m_ssl));
}
break;
case SSL_SSI_SERVER_NAME:
{
int type = SSL_get_servername_type(m_ssl);
if(type != -1)
*lppInfo = (LPVOID)(SSL_get_servername(m_ssl, type));
}
break;
case SSL_SSI_VERSION:
{
*lppInfo = (LPVOID)(SSL_get_version(m_ssl));
}
break;
case SSL_SSI_METHOD:
{
*lppInfo = (LPVOID)(SSL_get_ssl_method(m_ssl));
}
break;
case SSL_SSI_CERT:
{
*lppInfo = (LPVOID)(SSL_get_certificate(m_ssl));
}
break;
case SSL_SSI_PKEY:
{
*lppInfo = (LPVOID)(SSL_get_privatekey(m_ssl));
}
break;
case SSL_SSI_CURRENT_CIPHER:
{
*lppInfo = (LPVOID)(SSL_get_current_cipher(m_ssl));
}
break;
case SSL_SSI_CIPHERS:
{
*lppInfo = (LPVOID)(SSL_get_ciphers(m_ssl));
}
break;
case SSL_SSI_CLIENT_CIPHERS:
{
*lppInfo = (LPVOID)(SSL_get_client_ciphers(m_ssl));
}
break;
case SSL_SSI_PEER_CERT:
{
X509* pCert = SSL_get_peer_certificate(m_ssl);
if(pCert != nullptr)
{
*lppInfo = (LPVOID*)pCert;
X509_free(pCert);
}
}
break;
case SSL_SSI_PEER_CERT_CHAIN:
{
*lppInfo = (LPVOID)(SSL_get_peer_cert_chain(m_ssl));
}
break;
case SSL_SSI_VERIFIED_CHAIN:
{
*lppInfo = (LPVOID)(SSL_get0_verified_chain(m_ssl));
}
break;
}
return TRUE;
}
CSSLSession* CSSLSessionPool::PickFreeSession(LPCSTR lpszHostName)
{
DWORD dwIndex;
CSSLSession* pSession = nullptr;
if(m_lsFreeSession.TryLock(&pSession, dwIndex))
{
if(::GetTimeGap32(pSession->GetFreeTime()) >= m_dwSessionLockTime)
VERIFY(m_lsFreeSession.ReleaseLock(nullptr, dwIndex));
else
{
VERIFY(m_lsFreeSession.ReleaseLock(pSession, dwIndex));
pSession = nullptr;
}
}
if(!pSession) pSession = CSSLSession::Construct(m_itPool);
ASSERT(pSession);
return pSession->Renew(m_sslCtx, lpszHostName);
}
void CSSLSessionPool::PutFreeSession(CSSLSession* pSession)
{
if(pSession->Reset())
{
ReleaseGCSession();
if(!m_lsFreeSession.TryPut(pSession))
m_lsGCSession.PushBack(pSession);
}
}
void CSSLSessionPool::Prepare()
{
m_itPool.Prepare();
m_lsFreeSession.Reset(m_dwSessionPoolSize);
}
void CSSLSessionPool::Clear()
{
m_lsFreeSession.Clear();
ReleaseGCSession(TRUE);
VERIFY(m_lsGCSession.IsEmpty());
m_itPool.Clear();
}
void CSSLSessionPool::ReleaseGCSession(BOOL bForce)
{
::ReleaseGCObj(m_lsGCSession, m_dwSessionLockTime, bForce);
}
#endif
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。