asyncsslsocketlayer.cpp
来自「一个支持FTP,SFTP的客户端程序」· C++ 代码 · 共 1,981 行 · 第 1/4 页
CPP
1,981 行
/* CAsyncSslSocketLayer by Tim Kosse
mailto: tim.kosse@filezilla-project.org)
Version 2.0 (2005-02-27)
-------------------------------------------------------------
Introduction
------------
CAsyncSslSocketLayer is a layer class for CAsyncSocketEx which allows you to establish SSL secured
connections. Support for both client and server side is provided.
How to use
----------
Using this class is really simple. In the easiest case, just add an instance of
CAsyncSslSocketLayer to your socket and call InitClientSsl after creation of the socket.
This class only has a couple of public functions:
- InitSSLConnection(bool clientMode);
This functions establishes an SSL connection. The clientMode parameter specifies wether the SSL connection
is in server or in client mode.
Most likely you want to call this function right after calling Create for the socket.
But sometimes, you'll need to call this function later. One example is for an FTP connection
with explicit SSL: In this case you would have to call InitSSLConnection after receiving the reply
to an 'AUTH SSL' command.
- Is UsingSSL();
Returns true if you've previously called InitClientSsl()
- SetNotifyReply(SetNotifyReply(int nID, int nCode, int result);
You can call this function only after receiving a layerspecific callback with the SSL_VERIFY_CERT
id. Set result to 1 if you trust the certificate and 0 if you don't trust it.
nID has to be the priv_data element of the t_SslCertData structure and nCode has to be SSL_VERIFY_CERT.
- CreateSslCertificate(LPCTSTR filename, int bits, unsigned char* country, unsigned char* state,
unsigned char* locality, unsigned char* organization, unsigned char* unit, unsigned char* cname,
unsigned char *email, CString& err);
Creates a new self-signed SSL certificate and stores it in the given file
- SendRaw(const void* lpBuf, int nBufLen, int nFlags = 0)
Sends a raw, unencrypted message. This may be useful after successful initialization to tell the other
side that can use SSL.
This layer sends some layerspecific notifications to your socket instance, you can handle them in
OnLayerCallback of your socket class.
Valid notification IDs are:
- SSL_INFO 0
There are two possible values for param2:
SSL_INFO_ESTABLISHED 0 - You'll get this notification if the SSL negotiation was successful
SSL_INFO_SHUTDOWNCOMPLETE 1 - You'll get this notification if the SSL connection has been shut
down sucessfully. See below for details.
- SSL_FAILURE 1
This notification is sent if the SSL connection could not be established or if an existing
connection failed. Valid values for param2 are:
- SSL_FAILURE_UNKNOWN 0 - Details may have been sent with a SSL_VERBOSE_* notification.
- SSL_FAILURE_ESTABLISH 1 - Problem during SSL negotiation
- SSL_FAILURE_LOADDLLS 2
- SSL_FAILURE_INITSSL 4
- SSL_FAILURE_VERIFYCERT 8 - The remote SSL certificate was invalid
- SSL_FAILURE_CERTREJECTED 16 - The remote SSL certificate was rejected by user
- SSL_VERBOSE_WARNING 3
SSL_VERBOSE_INFO 4
This two notifications contain some additional information. The value given by param2 is a
pointer to a null-terminated char string (char *) with some useful information.
- SSL_VERIFY_CERT 2
This notification is sent each time a remote certificate has to be verified.
param2 is a pointer to a t_SslCertData structure which contains some information
about the remote certificate.
You have to set the reply to this message using the SetNotifyReply function.
Be careful with closing the connection after sending data, not all data may have been sent already.
Before closing the connection, you should call Shutdown() and wait for the SSL_INFO_SHUTDOWNCOMPLETE
notification. This assures that all encrypted data really has been sent.
License
-------
Feel free to use this class, as long as you don't claim that you wrote it
and this copyright notice stays intact in the source files.
If you want to use this class in a commercial application, a short message
to tim.kosse@filezilla-project.org would be appreciated but is not required.
This product includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit. (http://www.openssl.org/)
Version history
---------------
Version 2.0:
- Add server support
- a lot of bug fixes
*/
#include "stdafx.h"
#include "AsyncSslSocketLayer.h"
#if defined _DEBUG && defined _AFX
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// Simple macro to declare function type and function pointer based on the
// three given parametrs:
// r - return type,
// n - function name
// a - argument list
//
// Example:
// def(int, foo, (int x)) becomes the following:
// typedef int (*tfoo)(int x);
// static tfoo pfoo;
#define def(r, n, a) \
typedef r (*t##n) a; \
static t##n p##n;
// Macro to load the given macro from a dll:
#define load(dll, n) \
p##n = (t##n) GetProcAddress(dll, #n); \
if (!p##n) \
bError = true;
//The following functions from the SSL libraries are used:
def(int, SSL_state, (SSL *s));
def(char*, SSL_state_string_long, (SSL *s));
def(void, SSL_set_info_callback, (SSL *ssl, void(*cb)()));
def(void, SSL_set_bio, (SSL *s, BIO *rbio, BIO *wbio));
def(void, SSL_set_connect_state, (SSL *s));
def(int, SSL_set_session, (SSL *to, SSL_SESSION *session));
def(BIO_METHOD*, BIO_f_ssl, (void));
def(SSL*, SSL_new, (SSL_CTX *ctx));
def(SSL_CTX*, SSL_CTX_new, (SSL_METHOD *meth));
def(SSL_METHOD*, SSLv23_method, (void));
def(void, SSL_load_error_strings, (void));
def(int, SSL_library_init, (void));
def(void, SSL_CTX_free, (SSL_CTX *));
def(void, SSL_free, (SSL *ssl));
def(int, SSL_get_error, (SSL *s, int retcode));
def(int, SSL_shutdown, (SSL *s));
def(char*, SSL_alert_type_string_long, (int VALUE));
def(char*, SSL_alert_desc_string_long, (int value));
def(void, SSL_CTX_set_verify, (SSL_CTX *ctx, int mode, int (*callback)(int, X509_STORE_CTX *)));
def(X509_STORE*, SSL_CTX_get_cert_store, (SSL_CTX *));
def(long, SSL_get_verify_result, (SSL *ssl));
def(X509*, SSL_get_peer_certificate, (SSL *s));
def(const char*, SSL_get_version, (SSL *ssl));
def(SSL_CIPHER*, SSL_get_current_cipher, (SSL *ssl));
def(const char*, SSL_CIPHER_get_name, (SSL_CIPHER *cipher));
def(char*, SSL_CIPHER_get_version, (SSL_CIPHER *cipher));
def(int, SSL_get_ex_data_X509_STORE_CTX_idx, (void));
def(int, SSL_CTX_load_verify_locations, (SSL_CTX *ctx, const char *CAfile, const char *CApath));
def(long, SSL_ctrl, (SSL *ssl, int cmd, long larg, void *parg));
def(void, SSL_set_accept_state, (SSL *ssl));
def(int, SSL_CTX_use_PrivateKey_file, (SSL_CTX *ctx, const char *file, int type));
def(int, SSL_CTX_use_certificate_file, (SSL_CTX *ctx, const char *file, int type));
def(int, SSL_CTX_check_private_key, (SSL_CTX *ctx));
def(size_t, BIO_ctrl_pending, (BIO *b));
def(int, BIO_read, (BIO *b, void *data, int len));
def(long, BIO_ctrl, (BIO *bp, int cmd, long larg, void *parg));
def(int, BIO_write, (BIO *b, const void *data, int len));
def(size_t, BIO_ctrl_get_write_guarantee, (BIO *b));
def(int, BIO_new_bio_pair, (BIO **bio1, size_t writebuf1, BIO **bio2, size_t writebuf2));
def(BIO*, BIO_new, (BIO_METHOD *type));
def(int, BIO_free, (BIO *a));
def(int, i2t_ASN1_OBJECT, (char *buf, int buf_len, ASN1_OBJECT *a));
def(int, OBJ_obj2nid, (ASN1_OBJECT *o));
def(ASN1_OBJECT*, X509_NAME_ENTRY_get_object, (X509_NAME_ENTRY *ne));
def(X509_NAME_ENTRY*, X509_NAME_get_entry, (X509_NAME *name, int loc));
def(int, X509_NAME_entry_count, (X509_NAME *name));
def(X509_NAME*, X509_get_subject_name, (X509 *a));
def(X509_NAME*, X509_get_issuer_name, (X509 *a));
def(const char*, OBJ_nid2sn, (int n));
def(ASN1_STRING*, X509_NAME_ENTRY_get_data, (X509_NAME_ENTRY *ne));
def(void, X509_STORE_CTX_set_error, (X509_STORE_CTX *ctx, int s));
def(int, X509_digest, (const X509 *data, const EVP_MD *type, unsigned char *md, unsigned int *len));
def(EVP_MD*, EVP_sha1, (void));
def(X509*, X509_STORE_CTX_get_current_cert, (X509_STORE_CTX *ctx));
def(int, X509_STORE_CTX_get_error, (X509_STORE_CTX *ctx));
def(void, X509_free, (X509 *a));
def(EVP_PKEY*, X509_get_pubkey, (X509 *x));
def(int, BN_num_bits, (const BIGNUM *a));
def(void, EVP_PKEY_free, (EVP_PKEY *pkey));
def(SSL*, X509_STORE_CTX_get_ex_data, (X509_STORE_CTX *ctx, int idx));
def(char*, X509_NAME_oneline, (X509_NAME *a, char *buf, int size));
def(char*, X509_verify_cert_error_string, (int err));
def(int, X509_STORE_CTX_get_error_depth, (X509_STORE_CTX *ctx));
def(unsigned long, ERR_get_error, (void));
def(char, ERR_error_string, (unsigned long e, char *buf));
def(int, ASN1_STRING_to_UTF8, (unsigned char **out, ASN1_STRING *in));
def(void, CRYPTO_free, (void *p));
def(RSA*, RSA_generate_key, (int num, unsigned long e, void (*callback)(int,int,void *), void *cb_arg));
def(int, X509_set_version, (X509 *x,long version));
def(ASN1_TIME*, X509_gmtime_adj, (ASN1_TIME *s, long adj));
def(int, X509_set_pubkey, (X509 *x, EVP_PKEY *pkey));
def(int, X509_NAME_add_entry_by_txt, (X509_NAME *name, char *field, int type, unsigned char *bytes, int len, int loc, int set));
def(int, X509_NAME_add_entry_by_NID, (X509_NAME *name, int nid, int type, unsigned char *bytes, int len, int loc, int set));
def(int, X509_set_issuer_name, (X509 *x, X509_NAME *name));
def(int, X509_sign, (X509 *x, EVP_PKEY *pkey, const EVP_MD *md));
def(EVP_PKEY*, EVP_PKEY_new, (void));
def(int, EVP_PKEY_assign, (EVP_PKEY *pkey,int type,char *key));
def(X509*, X509_new, (void));
def(int, ASN1_INTEGER_set, (ASN1_INTEGER *a, long v));
def(ASN1_INTEGER*, X509_get_serialNumber, (X509 *x));
def(int, PEM_write_PrivateKey, (FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cb, void *u));
def(int, PEM_ASN1_write_bio, (int (*i2d)(),const char *name,BIO *bp,char *x, const EVP_CIPHER *enc,unsigned char *kstr,int klen, pem_password_cb *callback, void *u));
def(int, i2d_X509, (X509 *x, unsigned char **out));
def(BIO_METHOD *, BIO_s_mem, (void));
def(int, i2d_PrivateKey, (EVP_PKEY *a, unsigned char **pp));
// Critical section wrapper class
#ifndef CCRITICALSECTIONWRAPPERINCLUDED
class CCriticalSectionWrapper
{
public:
CCriticalSectionWrapper()
{
m_bInitialized = TRUE;
InitializeCriticalSection(&m_criticalSection);
}
~CCriticalSectionWrapper()
{
if (m_bInitialized)
DeleteCriticalSection(&m_criticalSection);
m_bInitialized = FALSE;
}
void Lock()
{
if (m_bInitialized)
EnterCriticalSection(&m_criticalSection);
}
void Unlock()
{
if (m_bInitialized)
LeaveCriticalSection(&m_criticalSection);
}
protected:
CRITICAL_SECTION m_criticalSection;
BOOL m_bInitialized;
};
#define CCRITICALSECTIONWRAPPERINCLUDED
#endif
/////////////////////////////////////////////////////////////////////////////
// CAsyncSslSocketLayer
CCriticalSectionWrapper CAsyncSslSocketLayer::m_sCriticalSection;
CAsyncSslSocketLayer::t_SslLayerList* CAsyncSslSocketLayer::m_pSslLayerList = 0;
int CAsyncSslSocketLayer::m_nSslRefCount = 0;
HMODULE CAsyncSslSocketLayer::m_hSslDll1 = 0;
HMODULE CAsyncSslSocketLayer::m_hSslDll2 = 0;
std::map<SSL_CTX *, int> CAsyncSslSocketLayer::m_contextRefCount;
CAsyncSslSocketLayer::CAsyncSslSocketLayer()
{
m_ssl = 0;
m_sslbio = 0;
m_ibio = 0;
m_nbio = 0;
m_ssl_ctx = 0;
m_bUseSSL = false;
m_bSslInitialized = FALSE;
m_bSslEstablished = FALSE;
m_nNetworkSendBufferLen = 0;
m_nNetworkSendBufferMaxLen = 0;
m_pNetworkSendBuffer = NULL;
m_nNetworkError = 0;
m_nShutDown = 0;
m_bBlocking = FALSE;
m_nSslAsyncNotifyId = 0;
m_bFailureSent = FALSE;
m_nVerificationResult = 0;
m_nVerificationDepth = 0;
m_mayTriggerRead = true;
m_mayTriggerWrite = true;
m_mayTriggerReadUp = true;
m_mayTriggerWriteUp = true;
m_onCloseCalled = false;
}
CAsyncSslSocketLayer::~CAsyncSslSocketLayer()
{
UnloadSSL();
delete [] m_pNetworkSendBuffer;
}
int CAsyncSslSocketLayer::InitSSL()
{
if (m_bSslInitialized)
return 0;
m_sCriticalSection.Lock();
if (!m_nSslRefCount)
{
m_hSslDll2=
LoadLibrary(_T("libeay32.dll"));
if (!m_hSslDll2)
{
if (m_hSslDll1)
FreeLibrary(m_hSslDll1);
m_hSslDll1=0;
m_sCriticalSection.Unlock();
return SSL_FAILURE_LOADDLLS;
}
bool bError = false;
load(m_hSslDll2, BIO_ctrl_pending);
load(m_hSslDll2, BIO_ctrl_pending);
load(m_hSslDll2, BIO_read);
load(m_hSslDll2, BIO_ctrl);
load(m_hSslDll2, BIO_write);
load(m_hSslDll2, BIO_ctrl_get_write_guarantee);
load(m_hSslDll2, BIO_new_bio_pair);
load(m_hSslDll2, BIO_new);
load(m_hSslDll2, BIO_free);
load(m_hSslDll2, i2t_ASN1_OBJECT);
load(m_hSslDll2, OBJ_obj2nid);
load(m_hSslDll2, X509_NAME_ENTRY_get_object);
load(m_hSslDll2, X509_NAME_get_entry);
load(m_hSslDll2, X509_NAME_entry_count);
load(m_hSslDll2, X509_get_subject_name);
load(m_hSslDll2, X509_get_issuer_name);
load(m_hSslDll2, OBJ_nid2sn);
load(m_hSslDll2, X509_NAME_ENTRY_get_data);
load(m_hSslDll2, X509_STORE_CTX_set_error);
load(m_hSslDll2, X509_digest);
load(m_hSslDll2, EVP_sha1);
load(m_hSslDll2, X509_STORE_CTX_get_current_cert);
load(m_hSslDll2, X509_STORE_CTX_get_error);
load(m_hSslDll2, X509_free);
load(m_hSslDll2, X509_get_pubkey);
load(m_hSslDll2, BN_num_bits);
load(m_hSslDll2, EVP_PKEY_free);
load(m_hSslDll2, X509_STORE_CTX_get_ex_data);
load(m_hSslDll2, X509_NAME_oneline);
load(m_hSslDll2, X509_verify_cert_error_string);
load(m_hSslDll2, X509_STORE_CTX_get_error_depth);
load(m_hSslDll2, ERR_get_error);
load(m_hSslDll2, ERR_error_string);
load(m_hSslDll2, ASN1_STRING_to_UTF8);
load(m_hSslDll2, CRYPTO_free);
load(m_hSslDll2, RSA_generate_key);
load(m_hSslDll2, X509_set_version);
load(m_hSslDll2, X509_gmtime_adj);
load(m_hSslDll2, X509_set_pubkey);
load(m_hSslDll2, X509_NAME_add_entry_by_txt);
load(m_hSslDll2, X509_NAME_add_entry_by_NID);
load(m_hSslDll2, X509_set_issuer_name);
load(m_hSslDll2, X509_sign);
load(m_hSslDll2, EVP_PKEY_new);
load(m_hSslDll2, EVP_PKEY_assign);
load(m_hSslDll2, X509_new);
load(m_hSslDll2, ASN1_INTEGER_set);
load(m_hSslDll2, X509_get_serialNumber);
load(m_hSslDll2, PEM_write_PrivateKey);
load(m_hSslDll2, PEM_ASN1_write_bio);
load(m_hSslDll2, i2d_X509);
load(m_hSslDll2, BIO_s_mem);
load(m_hSslDll2, i2d_PrivateKey);
if (bError)
{
FreeLibrary(m_hSslDll1);
m_hSslDll1 = 0;
FreeLibrary(m_hSslDll2);
m_hSslDll2 = 0;
m_sCriticalSection.Unlock();
return SSL_FAILURE_LOADDLLS;
}
m_hSslDll1 = LoadLibrary(_T("ssleay32.dll"));
if (!m_hSslDll1)
{
if (m_hSslDll2)
FreeLibrary(m_hSslDll2);
m_hSslDll2 = NULL;
m_sCriticalSection.Unlock();
return SSL_FAILURE_LOADDLLS;
}
load(m_hSslDll1, SSL_state_string_long);
load(m_hSslDll1, SSL_state);
load(m_hSslDll1, SSL_set_info_callback);
load(m_hSslDll1, SSL_set_bio);
load(m_hSslDll1, SSL_set_connect_state);
load(m_hSslDll1, SSL_set_session);
load(m_hSslDll1, BIO_f_ssl);
load(m_hSslDll1, SSL_new);
load(m_hSslDll1, SSL_CTX_new);
load(m_hSslDll1, SSLv23_method);
load(m_hSslDll1, SSL_load_error_strings);
load(m_hSslDll1, SSL_library_init);
load(m_hSslDll1, SSL_CTX_free);
load(m_hSslDll1, SSL_free);
load(m_hSslDll1, SSL_get_error);
load(m_hSslDll1, SSL_shutdown);
load(m_hSslDll1, SSL_alert_type_string_long);
load(m_hSslDll1, SSL_alert_desc_string_long);
load(m_hSslDll1, SSL_CTX_set_verify);
load(m_hSslDll1, SSL_CTX_get_cert_store);
load(m_hSslDll1, SSL_get_verify_result);
load(m_hSslDll1, SSL_get_peer_certificate);
load(m_hSslDll1, SSL_get_version);
load(m_hSslDll1, SSL_get_current_cipher);
load(m_hSslDll1, SSL_CIPHER_get_name);
load(m_hSslDll1, SSL_CIPHER_get_version);
load(m_hSslDll1, SSL_get_ex_data_X509_STORE_CTX_idx);
load(m_hSslDll1, SSL_CTX_load_verify_locations);
load(m_hSslDll1, SSL_ctrl);
load(m_hSslDll1, SSL_set_accept_state);
load(m_hSslDll1, SSL_CTX_use_PrivateKey_file);
load(m_hSslDll1, SSL_CTX_use_certificate_file);
load(m_hSslDll1, SSL_CTX_check_private_key);
if (bError)
{
FreeLibrary(m_hSslDll1);
m_hSslDll1=0;
if (m_hSslDll2)
FreeLibrary(m_hSslDll2);
m_hSslDll2=0;
m_sCriticalSection.Unlock();
return SSL_FAILURE_LOADDLLS;
}
pSSL_load_error_strings();
if (!pSSL_library_init())
{
FreeLibrary(m_hSslDll1);
m_hSslDll1=0;
FreeLibrary(m_hSslDll2);
m_hSslDll2=0;
m_sCriticalSection.Unlock();
return SSL_FAILURE_INITSSL;
}
}
m_nSslRefCount++;
m_sCriticalSection.Unlock();
m_bSslInitialized = true;
return 0;
}
void CAsyncSslSocketLayer::OnReceive(int nErrorCode)
{
if (m_bUseSSL)
{
if (m_bBlocking)
{
m_mayTriggerRead = true;
return;
}
if (m_nNetworkError)
return;
char buffer[16384];
m_mayTriggerRead = false;
//Get number of bytes we can receive and store in the network input bio
int len = pBIO_ctrl_get_write_guarantee(m_nbio);
if (len > 16384)
len = 16384;
else if (!len)
{
m_mayTriggerRead = true;
TriggerEvents();
return;
}
int numread = 0;
// Receive data
numread = ReceiveNext(buffer, len);
if (numread > 0)
{
//Store it in the network input bio and process data
int numwritten = pBIO_write(m_nbio, buffer, numread);
pBIO_ctrl(m_nbio, BIO_CTRL_FLUSH, 0, NULL);
//Look if input data was valid
int res = pBIO_read(m_sslbio, (void *)1, 0);
if (res < 0)
{
if (!m_sslbio || !BIO_should_retry(m_sslbio))
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?