!C99Shell v. 1.0 pre-release build #13!

Software: Apache. PHP/5.5.15 

uname -a: Windows NT SVR-DMZ 6.1 build 7600 (Windows Server 2008 R2 Enterprise Edition) i586 

SYSTEM 

Safe-mode: OFF (not secure)

C:\dmz\FileZillaFTP\source\   drwxrwxrwx
Free 4.08 GB of 39.52 GB (10.32%)
Detected drives: [ a ] [ c ] [ d ] [ e ] [ f ]
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     AsyncSslSocketLayer.cpp (60.12 KB)      -rw-rw-rw-
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*           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, (const SSL *s));
def(const char*, SSL_state_string_long, (const SSL *s));
def(void, SSL_set_info_callback, (SSL *ssl, void (*cb)(const SSL *ssl,int type,int val)));
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, (const SSL *s, int retcode));
def(int, SSL_shutdown, (SSL *s));
def(int, SSL_get_shutdown, (const SSL *ssl));
def(const char*, SSL_alert_type_string_long, (int value));
def(const 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, (const SSL_CTX *));
def(long, SSL_get_verify_result, (const SSL *ssl));
def(X509*, SSL_get_peer_certificate, (const SSL *s));
def(const char*, SSL_get_version, (const SSL *ssl));
def(SSL_CIPHER*, SSL_get_current_cipher, (const SSL *ssl));
def(const char*, SSL_CIPHER_get_name, (const SSL_CIPHER *cipher));
def(char*, SSL_CIPHER_get_version, (const 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, (const SSL_CTX *ctx));
def(void, SSL_CTX_set_default_passwd_cb, (SSL_CTX *ctx, pem_password_cb *cb));
def(void, SSL_CTX_set_default_passwd_cb_userdata, (SSL_CTX *ctx, void *u));
def(int, SSL_CTX_use_certificate_chain_file, (SSL_CTX *ctx, const char *file));
def(long, SSL_CTX_ctrl, (SSL_CTX *ctx, int cmd, long larg, void *parg));
def(int, SSL_set_cipher_list, (SSL *ssl, const char *str));
def(const char*, SSL_get_cipher_list, (const SSL *ssl, int priority));

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, (const 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(const 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(void*, 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(const char*, X509_verify_cert_error_string, (long n));
def(int, X509_STORE_CTX_get_error_depth, (X509_STORE_CTX *ctx));
def(unsigned long, ERR_get_error, (void));
def(const 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 bits, 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, const char *field, int type, const 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_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));
def(int, BIO_test_flags, (const BIO *b, int flags));


// 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_pRetrySendBuffer = 0;
    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;
    m_pKeyPassword = 0;
}

CAsyncSslSocketLayer::~CAsyncSslSocketLayer()
{
    UnloadSSL();
    delete [] m_pNetworkSendBuffer;
    delete [] m_pRetrySendBuffer;
    delete [] m_pKeyPassword;
}

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_ASN1_write_bio);
        load(m_hSslDll2, i2d_X509);
        load(m_hSslDll2, BIO_s_mem);
        load(m_hSslDll2, i2d_PrivateKey);
        load(m_hSslDll2, BIO_test_flags);

        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_get_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);
        load(m_hSslDll1, SSL_CTX_set_default_passwd_cb_userdata);
        load(m_hSslDll1, SSL_CTX_set_default_passwd_cb);
        load(m_hSslDll1, SSL_CTX_use_certificate_chain_file);
        load(m_hSslDll1, SSL_CTX_ctrl);
        load(m_hSslDll1, SSL_get_cipher_list);
        load(m_hSslDll1, SSL_set_cipher_list);

        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;

        m_mayTriggerRead = false;
        
        //Get number of bytes we can receive and store in the network input bio
        size_t len = pBIO_ctrl_get_write_guarantee(m_nbio);
        if (!len)
        {
            m_mayTriggerRead = true;
            TriggerEvents();
            return;
        }

        char *buffer = new char[len];

        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);

            // I have no idea why this call is needed, but without it, connections
            // will stall. Perhaps it triggers some internal processing.
            // Also, ignore return value, don't do any error checking. This function
            // can report errors, even though a later call can succeed.
            char dummy;
            pBIO_read(m_sslbio, &dummy, 0);
        }
        else if (!numread)
        {
            if (GetLayerState() == connected)
                TriggerEvent(FD_CLOSE, nErrorCode, TRUE);
        }
        else if (numread == SOCKET_ERROR)
        {
            int nError = GetLastError();
            if (nError != WSAEWOULDBLOCK && nError != WSAENOTCONN)
            {
                m_nNetworkError = GetLastError();
                TriggerEvent(FD_CLOSE, 0, TRUE);

                delete [] buffer;
                return;
            }
        }
        delete [] buffer;

        if (m_pRetrySendBuffer)
        {
            int numwrite = pBIO_write(m_sslbio, m_pRetrySendBuffer, m_nRetrySendBufferLen);
            if (numwrite >= 0)
            {
                pBIO_ctrl(m_sslbio, BIO_CTRL_FLUSH, 0, NULL);
                delete [] m_pRetrySendBuffer;
                m_pRetrySendBuffer = 0;
            }
            else if (numwrite == -1)
            {
                if (!pBIO_test_flags(m_sslbio, BIO_FLAGS_SHOULD_RETRY))
                {
                    if (PrintLastErrorMsg())
                    {
                        delete [] m_pRetrySendBuffer;
                        m_pRetrySendBuffer = 0;

                        SetLastError(WSAECONNABORTED);
                        TriggerEvent(FD_CLOSE, 0, TRUE);
                        return;
                    }
                }
            }
        }

        if (!m_nShutDown && pSSL_get_shutdown(m_ssl) && pBIO_ctrl_pending(m_sslbio) <= 0)
        {
            if (ShutDown() || GetLastError() == WSAEWOULDBLOCK)
            {
                if (ShutDownComplete())
                    TriggerEvent(FD_CLOSE, 0, TRUE);
            }
            else
            {
                m_nNetworkError = WSAECONNABORTED;
                WSASetLastError(WSAECONNABORTED);
                TriggerEvent(FD_CLOSE, WSAECONNABORTED, TRUE);
            }
            return;
        }

        if (m_nShutDown == 1)
            ShutDown();
        if (ShutDownComplete() && m_nShutDown == 2)
        {
            //Send shutdown notification if all pending data has been sent
            TriggerEvent(FD_WRITE, 0, 0);
            DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_INFO, SSL_INFO_SHUTDOWNCOMPLETE);
            m_nShutDown++;
        }

        TriggerEvents();
    }
    else
        TriggerEvent(FD_READ, nErrorCode, TRUE);
}

void CAsyncSslSocketLayer::OnSend(int nErrorCode)
{
    if (m_bUseSSL)
    {
        if (m_nNetworkError)
            return;

        m_mayTriggerWrite = false;

        //Send data in the send buffer
        while (m_nNetworkSendBufferLen)
        {
            int numsent = SendNext(m_pNetworkSendBuffer, m_nNetworkSendBufferLen);
            if (numsent == SOCKET_ERROR)
            {
                int nError = GetLastError();
                if (nError != WSAEWOULDBLOCK && nError != WSAENOTCONN)
                {
                    m_nNetworkError = nError;
                    TriggerEvent(FD_CLOSE, 0, TRUE);
                }
                return;
            }
            else if (!numsent)
            {
                if (GetLayerState() == connected)
                    TriggerEvent(FD_CLOSE, nErrorCode, TRUE);
            }
            if (numsent == m_nNetworkSendBufferLen)
                m_nNetworkSendBufferLen = 0;
            else
            {
                memmove(m_pNetworkSendBuffer, m_pNetworkSendBuffer + numsent, m_nNetworkSendBufferLen - numsent);
                m_nNetworkSendBufferLen -= numsent;
            }
        }

        //Send the data waiting in the network bio
        size_t len = pBIO_ctrl_pending(m_nbio);
        char *buffer = new char[len];
        int numread = pBIO_read(m_nbio, buffer, len);
        if (numread <= 0)
            m_mayTriggerWrite = true;
        while (numread > 0)
        {
            int numsent = SendNext(buffer, numread);
            if (!numsent)
            {
                if (GetLayerState() == connected)
                    TriggerEvent(FD_CLOSE, nErrorCode, TRUE);
            }
            if (numsent == SOCKET_ERROR || numsent < numread)
            {
                if (numsent == SOCKET_ERROR)
                {
                    if (GetLastError() != WSAEWOULDBLOCK && GetLastError() != WSAENOTCONN)
                    {
                        m_nNetworkError = GetLastError();
                        TriggerEvent(FD_CLOSE, 0, TRUE);
                        delete [] buffer;
                        return;
                    }
                    else
                        numsent = 0;
                }

                // Add all data that was retrieved from the network bio but could not be sent to the send buffer.
                if (m_nNetworkSendBufferMaxLen < (m_nNetworkSendBufferLen + numread - numsent))
                {
                    char * tmp = m_pNetworkSendBuffer;
                    m_nNetworkSendBufferMaxLen = static_cast<int>((m_nNetworkSendBufferLen + numread - numsent) * 1.5);
                    m_pNetworkSendBuffer = new char[m_nNetworkSendBufferMaxLen];                    
                    if (tmp)
                    {
                        memcpy(m_pNetworkSendBuffer, tmp, m_nNetworkSendBufferLen);
                        delete [] tmp;
                    }
                }
                ASSERT(m_pNetworkSendBuffer);
                memcpy(m_pNetworkSendBuffer + m_nNetworkSendBufferLen, buffer, numread-numsent);
                m_nNetworkSendBufferLen += numread - numsent;
            }
            if (!numsent)
                break;
            len = pBIO_ctrl_pending(m_nbio);
            if (!len)
            {
                m_mayTriggerWrite = true;
                break;
            }
            delete [] buffer;
            buffer = new char[len];
            numread = pBIO_read(m_nbio, buffer, len);
            if (numread <= 0)
                m_mayTriggerWrite = true;
        }
        delete [] buffer;

        if (m_pRetrySendBuffer)
        {
            int numwrite = pBIO_write(m_sslbio, m_pRetrySendBuffer, m_nRetrySendBufferLen);
            if (numwrite >= 0)
            {
                pBIO_ctrl(m_sslbio, BIO_CTRL_FLUSH, 0, NULL);
                delete [] m_pRetrySendBuffer;
                m_pRetrySendBuffer = 0;
            }
            else if (numwrite == -1)
            {
                if (!pBIO_test_flags(m_sslbio, BIO_FLAGS_SHOULD_RETRY))
                {
                    if (PrintLastErrorMsg())
                    {
                        delete [] m_pRetrySendBuffer;
                        m_pRetrySendBuffer = 0;

                        SetLastError(WSAECONNABORTED);
                        TriggerEvent(FD_CLOSE, 0, TRUE);
                        return;
                    }
                }
            }
        }

        // No more data available, ask for more.
        TriggerEvents();
        if (m_nShutDown == 1)
            ShutDown();
        if (m_nShutDown == 2 && ShutDownComplete())
        {
            //Send shutdown notification if all pending data has been sent
            TriggerEvent(FD_WRITE, 0, 0);
            DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_INFO, SSL_INFO_SHUTDOWNCOMPLETE);
            m_nShutDown++;
        }
    }
    else
        TriggerEvent(FD_WRITE, nErrorCode, TRUE);
}

int CAsyncSslSocketLayer::Send(const void* lpBuf, int nBufLen, int nFlags)
{
    if (m_bUseSSL)
    {
        if (!lpBuf)
            return 0;
        if (m_bBlocking || m_pRetrySendBuffer)
        {
            m_mayTriggerWriteUp = true;
            SetLastError(WSAEWOULDBLOCK);
            return SOCKET_ERROR;
        }
        if (m_nNetworkError)
        {
            SetLastError(m_nNetworkError);
            return SOCKET_ERROR;
        }
        if (m_nShutDown)
        {
            SetLastError(WSAESHUTDOWN);
            return SOCKET_ERROR;
        }
        if (!m_bSslEstablished)
        {
            m_mayTriggerWriteUp = true;
            SetLastError(WSAEWOULDBLOCK);
            return SOCKET_ERROR;
        }
        if (!nBufLen)
            return 0;

        if (m_onCloseCalled)
        {
            TriggerEvent(FD_CLOSE, 0, TRUE);
            return 0;
        }

        int len = pBIO_ctrl_get_write_guarantee(m_sslbio);
        if (nBufLen > len)
            nBufLen = len;
        if (!len)
        {
            m_mayTriggerWriteUp = true;
            TriggerEvents();                
            SetLastError(WSAEWOULDBLOCK);
        }

        m_pRetrySendBuffer = new char[nBufLen];
        m_nRetrySendBufferLen = nBufLen;
        memcpy(m_pRetrySendBuffer, lpBuf, nBufLen);

        int numwrite = pBIO_write(m_sslbio, m_pRetrySendBuffer, m_nRetrySendBufferLen);
        if (numwrite >= 0)
        {
            pBIO_ctrl(m_sslbio, BIO_CTRL_FLUSH, 0, NULL);
            delete [] m_pRetrySendBuffer;
            m_pRetrySendBuffer = 0;
        }
        else if (numwrite == -1)
        {
            if (pBIO_test_flags(m_sslbio, BIO_FLAGS_SHOULD_RETRY))
            {
                if (GetLayerState() == closed)
                    return 0;
                else if (GetLayerState() != connected)
                {
                    SetLastError(m_nNetworkError);
                    return SOCKET_ERROR;
                }

                TriggerEvents();

                return nBufLen;
            }
            else
            {
                bool fatal = PrintLastErrorMsg();
                if (fatal)
                {
                    delete [] m_pRetrySendBuffer;
                    m_pRetrySendBuffer = 0;

                    SetLastError(WSAECONNABORTED);
                }
                else
                    SetLastError(WSAEWOULDBLOCK);
            }
            return SOCKET_ERROR;
        }

        m_mayTriggerWriteUp = true;
        TriggerEvents();

        return numwrite;
    }
    else
    {
        return SendNext(lpBuf, nBufLen, nFlags);
    }
}

int CAsyncSslSocketLayer::Receive(void* lpBuf, int nBufLen, int nFlags)
{
    if (m_bUseSSL)
    {
        if (m_bBlocking)
        {
            m_mayTriggerReadUp = true;
            SetLastError(WSAEWOULDBLOCK);
            return SOCKET_ERROR;
        }
        if (m_nNetworkError)
        {
            if (pBIO_ctrl(m_sslbio, BIO_CTRL_PENDING, 0, NULL) && !m_nShutDown)
            {
                m_mayTriggerReadUp = true;
                TriggerEvents();
                return pBIO_read(m_sslbio, lpBuf,nBufLen);
            }
            WSASetLastError(m_nNetworkError);
            return SOCKET_ERROR;
        }
        if (m_nShutDown)
        {
            SetLastError(WSAESHUTDOWN);
            return SOCKET_ERROR;
        }
        if (!nBufLen)
            return 0;
        if (!pBIO_ctrl(m_sslbio, BIO_CTRL_PENDING, 0, NULL))
        {
            if (GetLayerState() == closed)
                return 0;
            if (m_onCloseCalled)
            {
                TriggerEvent(FD_CLOSE, 0, TRUE);
                return 0;
            }
            else if (GetLayerState() != connected)
            {
                SetLastError(m_nNetworkError);
                return SOCKET_ERROR;
            }
            else if (pSSL_get_shutdown(m_ssl))
            {
                if (ShutDown() || GetLastError() == WSAEWOULDBLOCK)
                {
                    if (ShutDownComplete())
                    {
                        TriggerEvent(FD_CLOSE, 0, TRUE);
                        return 0;
                    }
                    else
                        WSASetLastError(WSAEWOULDBLOCK);
                }
                else
                {
                    m_nNetworkError = WSAECONNABORTED;
                    WSASetLastError(WSAECONNABORTED);
                    TriggerEvent(FD_CLOSE, WSAECONNABORTED, TRUE);
                }
                return SOCKET_ERROR;
            }
            m_mayTriggerReadUp = true;
            TriggerEvents();
            SetLastError(WSAEWOULDBLOCK);
            return SOCKET_ERROR;
        }
        int numread = pBIO_read(m_sslbio, lpBuf, nBufLen);
        if (!numread)
        {
            if (pSSL_get_shutdown(m_ssl))
            {
                if (ShutDown() || GetLastError() == WSAEWOULDBLOCK)
                {
                    if (ShutDownComplete())
                    {
                        TriggerEvent(FD_CLOSE, 0, TRUE);
                        return 0;
                    }
                    else
                        WSASetLastError(WSAEWOULDBLOCK);
                }
                else
                {
                    m_nNetworkError = WSAECONNABORTED;
                    WSASetLastError(WSAECONNABORTED);
                    TriggerEvent(FD_CLOSE, WSAECONNABORTED, TRUE);
                }
                return SOCKET_ERROR;
            }
            m_mayTriggerReadUp = true;
            TriggerEvents();
            SetLastError(WSAEWOULDBLOCK);
            return SOCKET_ERROR;
        }
        if (numread < 0)
        {
            if (!pBIO_test_flags(m_sslbio, BIO_FLAGS_SHOULD_RETRY))
            {
                bool fatal = PrintLastErrorMsg();
                if (fatal)
                {
                    m_nNetworkError = WSAECONNABORTED;
                    WSASetLastError(WSAECONNABORTED);
                    TriggerEvent(FD_CLOSE, 0, TRUE);
                    return SOCKET_ERROR;
                }
            }

            if (pSSL_get_shutdown(m_ssl))
            {
                if (ShutDown() || GetLastError() == WSAEWOULDBLOCK)
                {
                    if (ShutDownComplete())
                    {
                        TriggerEvent(FD_CLOSE, 0, TRUE);
                        return 0;
                    }
                    else
                        WSASetLastError(WSAEWOULDBLOCK);
                }
                else
                {
                    m_nNetworkError = WSAECONNABORTED;
                    WSASetLastError(WSAECONNABORTED);
                    TriggerEvent(FD_CLOSE, 0, TRUE);
                }
                return SOCKET_ERROR;
            }
            m_mayTriggerReadUp = true;
            TriggerEvents();
            SetLastError(WSAEWOULDBLOCK);
            return SOCKET_ERROR;
        }

        m_mayTriggerReadUp = true;
        TriggerEvents();
        return numread;
    }
    else
        return ReceiveNext(lpBuf, nBufLen, nFlags);
}

void CAsyncSslSocketLayer::Close()
{
    m_nShutDown = 0;
    m_onCloseCalled = false;
    ResetSslSession();
    CloseNext();
}

BOOL CAsyncSslSocketLayer::Connect(const SOCKADDR *lpSockAddr, int nSockAddrLen)
{
    BOOL res = ConnectNext(lpSockAddr, nSockAddrLen);
    if (!res)
        if (GetLastError() != WSAEWOULDBLOCK)
            ResetSslSession();
    return res;
}

BOOL CAsyncSslSocketLayer::Connect(LPCTSTR lpszHostAddress, UINT nHostPort)
{
    BOOL res = ConnectNext(lpszHostAddress, nHostPort);
    if (!res)
        if (GetLastError()!=WSAEWOULDBLOCK)
            ResetSslSession();
    return res;
}

int CAsyncSslSocketLayer::InitSSLConnection(bool clientMode, void* pSslContext /*=0*/)
{
    if (m_bUseSSL)
        return 0;
    int res = InitSSL();
    if (res)
        return res;

    m_sCriticalSection.Lock();
    if ((SSL_CTX*)pSslContext)
    {
        if (m_ssl_ctx)
        {
            m_sCriticalSection.Unlock();
            ResetSslSession();
            return SSL_FAILURE_INITSSL;
        }

        std::map<SSL_CTX *, int>::iterator& iter = m_contextRefCount.find((SSL_CTX*)pSslContext);
        if (iter == m_contextRefCount.end() || iter->second < 1)
        {
            m_sCriticalSection.Unlock();
            ResetSslSession();
            return SSL_FAILURE_INITSSL;
        }
        m_ssl_ctx = (SSL_CTX*)pSslContext;
        iter->second++;
    }
    else if (!m_ssl_ctx)
    {
        // Create new context if none given
        if (!(m_ssl_ctx = pSSL_CTX_new( pSSLv23_method())))
        {
            m_sCriticalSection.Unlock();
            ResetSslSession();
            return SSL_FAILURE_INITSSL;
        }
        m_contextRefCount[m_ssl_ctx] = 1;

        long options = pSSL_CTX_ctrl(m_ssl_ctx, SSL_CTRL_OPTIONS, 0, NULL);
        pSSL_CTX_ctrl(m_ssl_ctx, SSL_CTRL_OPTIONS, options | SSL_OP_NO_SSLv2, NULL);

        if (clientMode)
        {
            USES_CONVERSION;
            pSSL_CTX_set_verify(m_ssl_ctx, SSL_VERIFY_PEER, verify_callback);
            pSSL_CTX_load_verify_locations(m_ssl_ctx, T2CA(m_CertStorage), 0);
        }
    }

    //Create new SSL session
    if (!(m_ssl = pSSL_new(m_ssl_ctx)))
    {
        m_sCriticalSection.Unlock();
        ResetSslSession();
        return SSL_FAILURE_INITSSL;
    }

    // Disable DES and other weak and export ciphers
    pSSL_set_cipher_list(m_ssl, "DEFAULT:!DES:!WEAK:!EXP");
    
    //Add current instance to list of active instances
    t_SslLayerList *tmp = m_pSslLayerList;
    m_pSslLayerList = new t_SslLayerList;
    m_pSslLayerList->pNext = tmp;
    m_pSslLayerList->pLayer = this;
    m_sCriticalSection.Unlock();

    pSSL_set_info_callback(m_ssl, apps_ssl_info_callback);

    //Create bios
    m_sslbio = pBIO_new(pBIO_f_ssl());
    pBIO_new_bio_pair(&m_ibio, 4096, &m_nbio, 4096);

    if (!m_sslbio || !m_nbio || !m_ibio)
    {
        ResetSslSession();
        return SSL_FAILURE_INITSSL;
    }

    long options = pSSL_ctrl(m_ssl, SSL_CTRL_OPTIONS, 0, NULL);
    options |= SSL_OP_ALL;
    pSSL_ctrl(m_ssl, SSL_CTRL_OPTIONS, options, NULL);

    //Init SSL connection
    pSSL_set_session(m_ssl, NULL);
    if (clientMode)
        pSSL_set_connect_state(m_ssl);
    else
        pSSL_set_accept_state(m_ssl);
    pSSL_set_bio(m_ssl, m_ibio, m_ibio);
    pBIO_ctrl(m_sslbio, BIO_C_SET_SSL, BIO_NOCLOSE, m_ssl);
    pBIO_read(m_sslbio, (void *)1, 0);

    // Trigger FD_WRITE so that we can initialize SSL negotiation
    if (GetLayerState() == connected || GetLayerState() == attached)
    {
        TriggerEvent(FD_READ, 0);
        TriggerEvent(FD_WRITE, 0);
        TriggerEvent(FD_READ, 0, TRUE);
        TriggerEvent(FD_WRITE, 0, TRUE);
    }

    m_bUseSSL = true;

    return 0;
}

void CAsyncSslSocketLayer::ResetSslSession()
{
    if (m_pRetrySendBuffer)
    {
        delete [] m_pRetrySendBuffer;
        m_pRetrySendBuffer = 0;
    }

    m_bFailureSent = FALSE;
    m_bBlocking = FALSE;
    m_nSslAsyncNotifyId++;
    m_nNetworkError = 0;
    m_bUseSSL = FALSE;
    m_nVerificationResult = 0;
    m_nVerificationDepth = 0;

    m_bSslEstablished = FALSE;
    if (m_sslbio)
        pBIO_free(m_sslbio);
    if (m_ssl)
        pSSL_set_session(m_ssl,NULL);
    if (m_nbio)
        pBIO_free(m_nbio);
    if (m_ibio)
        pBIO_free(m_ibio);

    m_nNetworkSendBufferLen = 0;

    m_nbio = 0;
    m_ibio = 0;
    m_sslbio = 0;

    if (m_ssl)
        pSSL_free(m_ssl);

    m_sCriticalSection.Lock();

    if (m_ssl_ctx)
    {
        std::map<SSL_CTX *, int>::iterator& iter = m_contextRefCount.find(m_ssl_ctx);
        if (iter != m_contextRefCount.end())
        {
            if (iter->second <= 1)
            {
                pSSL_CTX_free(m_ssl_ctx);
                m_contextRefCount.erase(iter);
            }
            else
                iter->second--;
        }
        m_ssl_ctx = 0;
    }

    delete [] m_pKeyPassword;
    m_pKeyPassword = 0;

    m_ssl = 0;
    t_SslLayerList *cur = m_pSslLayerList;
    if (!cur)
    {
        m_sCriticalSection.Unlock();
        return;
    }

    if (cur->pLayer == this)
    {
        m_pSslLayerList = cur->pNext;
        delete cur;
    }
    else
        while (cur->pNext)
        {
            if (cur->pNext->pLayer == this)
            {
                t_SslLayerList *tmp = cur->pNext;
                cur->pNext = cur->pNext->pNext;
                delete tmp;

                m_sCriticalSection.Unlock();
                return;
            }
            cur = cur->pNext;
        }
    m_sCriticalSection.Unlock();
}

bool CAsyncSslSocketLayer::IsUsingSSL()
{
    return m_bUseSSL;
}

BOOL CAsyncSslSocketLayer::ShutDown(int nHow /*=sends*/)
{
    if (m_bUseSSL)
    {
        if (m_pRetrySendBuffer)
        {
            if (!m_nShutDown)
                m_nShutDown = 1;
            WSASetLastError(WSAEWOULDBLOCK);
            return false;
        }
        if (m_nShutDown != 2)
            m_nShutDown = 2;
        else
        {
            if (ShutDownComplete())
                return ShutDownNext();
            else
            {
                TriggerEvents();
                WSASetLastError(WSAEWOULDBLOCK);
                return false;
            }
        }
        
        int res = pSSL_shutdown(m_ssl);
        if (res != -1)
        {
            if (!res)
                pSSL_shutdown(m_ssl);
            if (ShutDownComplete())
                return ShutDownNext();
            else
            {
                TriggerEvents();
                WSASetLastError(WSAEWOULDBLOCK);
                return FALSE;
            }
        }
        else
        {
            int error = pSSL_get_error(m_ssl, -1);
            if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)
            {
                TriggerEvents();
                WSASetLastError(WSAEWOULDBLOCK);
                return FALSE;
            }
            else if (ShutDownComplete())
                return ShutDownNext();
            else
            {
                TriggerEvents();
                WSASetLastError(WSAEWOULDBLOCK);
                return FALSE;
            }
        }
    }
    else
    {
        if (!m_nShutDown)
            m_nShutDown = 2;
        return ShutDownNext(nHow);
    }
}

BOOL CAsyncSslSocketLayer::ShutDownComplete()
{
    //If a ShutDown was issued, has the connection already been shut down?
    if (!m_nShutDown)
        return FALSE;
    else if (!m_bUseSSL)
        return FALSE;
    else if (m_nNetworkSendBufferLen)
        return FALSE;
    else if (m_pRetrySendBuffer)
        return FALSE;
    
    // Empty read buffer
    char buffer[1000];
    int numread;
    do
    {
        numread = pBIO_read(m_sslbio, buffer, 1000);
    } while (numread > 0);

    if (pBIO_ctrl_pending(m_nbio))
        return FALSE;

    return TRUE;
}

void CAsyncSslSocketLayer::apps_ssl_info_callback(const SSL *s, int where, int ret)
{
    CAsyncSslSocketLayer *pLayer = 0;
    m_sCriticalSection.Lock();
    t_SslLayerList *cur = m_pSslLayerList;
    while (cur)
    {
        if (cur->pLayer->m_ssl == s)
            break;
        cur = cur->pNext;
    }
    if (!cur)
    {
        m_sCriticalSection.Unlock();
        //MessageBox(0, _T("Can't lookup SSL session!"), _T("Critical error"), MB_ICONEXCLAMATION);
        return;
    }
    else
        pLayer = cur->pLayer;
    m_sCriticalSection.Unlock();

    // Called while unloading?
    if (!pLayer->m_bUseSSL)
        return;

    char * str;
    int w;

    w = where& ~SSL_ST_MASK;

    if (w & SSL_ST_CONNECT)
        str = "SSL_connect";
    else if (w & SSL_ST_ACCEPT)
        str = "SSL_accept";
    else
        str = "undefined";

    if (where & SSL_CB_LOOP)
    {
        char *buffer = new char[4096];
        sprintf(buffer, "%s: %s",
                str,
                pSSL_state_string_long(s));
        pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_INFO, 0, buffer);
    }
    else if (where & SSL_CB_ALERT)
    {
        str=(where & SSL_CB_READ)? "read" : "write";
        const char* desc = pSSL_alert_desc_string_long(ret);

        // Don't send close notify warning
        if (desc && strcmp(desc, "close notify"))
        {
            char *buffer = new char[4096];
            sprintf(buffer, "SSL3 alert %s: %s: %s",
                    str,
                    pSSL_alert_type_string_long(ret),
                    desc);
            pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_WARNING, 0, buffer);
        }
    }

    else if (where & SSL_CB_EXIT)
    {
        if (ret == 0)
        {
            char *buffer = new char[4096];
            sprintf(buffer, "%s: failed in %s",
                    str,
                    pSSL_state_string_long(s));
            pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_WARNING, 0, buffer);
            if (!pLayer->m_bFailureSent)
            {
                pLayer->m_bFailureSent=TRUE;
                pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_FAILURE, pLayer->m_bSslEstablished ? SSL_FAILURE_UNKNOWN : SSL_FAILURE_ESTABLISH);
            }
        }
        else if (ret < 0)
        {
            int error = pSSL_get_error(s,ret);
            if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE)
            {
                char *buffer = new char[4096];
                sprintf(buffer, "%s: error in %s",
                        str,
                        pSSL_state_string_long(s));
                pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_WARNING, 0, buffer);
                if (!pLayer->m_bFailureSent)
                {
                    pLayer->m_bFailureSent=TRUE;
                    pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_FAILURE, pLayer->m_bSslEstablished ? SSL_FAILURE_UNKNOWN : SSL_FAILURE_ESTABLISH);
                }
            }
        }
    }
    if (where & SSL_CB_HANDSHAKE_DONE)
    {
        int error = pSSL_get_verify_result(pLayer->m_ssl);
        if (error)
        {
            pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERIFY_CERT, error);
            pLayer->m_bBlocking = TRUE;
            return;
        }
        pLayer->m_bSslEstablished = TRUE;
        pLayer->PrintSessionInfo();
        pLayer->DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_INFO, SSL_INFO_ESTABLISHED);
        pLayer->TriggerEvents();
    }
}


void CAsyncSslSocketLayer::UnloadSSL()
{
    if (!m_bSslInitialized)
        return;
    ResetSslSession();

    m_bSslInitialized = false;

    m_sCriticalSection.Lock();
    m_nSslRefCount--;
    if (m_nSslRefCount)
    {
        m_sCriticalSection.Unlock();
        return;
    }

    if (m_hSslDll1)
        FreeLibrary(m_hSslDll1);
    if (m_hSslDll2)
    {
        FreeLibrary(m_hSslDll2);
        FreeLibrary(m_hSslDll2);
    }
    m_hSslDll1 = NULL;
    m_hSslDll2 = NULL;
    m_sCriticalSection.Unlock();
}

BOOL CAsyncSslSocketLayer::GetPeerCertificateData(t_SslCertData &SslCertData)
{
    X509 *pX509=pSSL_get_peer_certificate(m_ssl);
    if (!pX509)
        return FALSE;

    //Reset the contents of SslCertData
    memset(&SslCertData, 0, sizeof(t_SslCertData));

    //Set subject data fields
    X509_NAME *pX509Name=pX509_get_subject_name(pX509);

    if (pX509Name)
    {
        int count=pX509_NAME_entry_count(pX509Name);
        for (int i=0;i<count;i++)
        {
            X509_NAME_ENTRY *pX509NameEntry=pX509_NAME_get_entry(pX509Name,i);
            if (!pX509NameEntry)
                continue;
            ASN1_OBJECT *pObject = pX509_NAME_ENTRY_get_object(pX509NameEntry);
            ASN1_STRING *pString = pX509_NAME_ENTRY_get_data(pX509NameEntry);
            CString str;

            unsigned char *out;
            int len = pASN1_STRING_to_UTF8(&out, pString);
            if (len > 0)
            {
                // Keep it huge
                LPWSTR unicode = new WCHAR[len * 10];
                memset(unicode, 0, sizeof(WCHAR) * len * 10);
                int unicodeLen = MultiByteToWideChar(CP_UTF8, 0, (const char *)out, len, unicode, len * 10);
                if (unicodeLen > 0)
                {
#ifdef _UNICODE
                    str = unicode;
#else
                    LPSTR ansi = new CHAR[len * 10];
                    memset(ansi, 0, sizeof(CHAR) * len * 10);
                    int ansiLen = WideCharToMultiByte(CP_ACP, 0, unicode, unicodeLen, ansi, len * 10, 0, 0);
                    if (ansiLen > 0)
                        str = ansi;

                    delete [] ansi;
#endif
                }
                delete [] unicode;
                pCRYPTO_free(out);
            }

            switch(pOBJ_obj2nid(pObject))
            {
            case NID_organizationName:
                _tcsncpy(SslCertData.subject.Organization, str, 255);
                SslCertData.subject.Organization[255] = 0;
                break;
            case NID_organizationalUnitName:
                _tcsncpy(SslCertData.subject.Unit, str, 255);
                SslCertData.subject.Unit[255] = 0;
                break;
            case NID_commonName:
                _tcsncpy(SslCertData.subject.CommonName, str, 255);
                SslCertData.subject.CommonName[255] = 0;
                break;
            case NID_pkcs9_emailAddress:
                _tcsncpy(SslCertData.subject.Mail, str, 255);
                SslCertData.subject.Mail[255] = 0;
                break;
            case NID_countryName:
                _tcsncpy(SslCertData.subject.Country, str, 255);
                SslCertData.subject.Country[255] = 0;
                break;
            case NID_stateOrProvinceName:
                _tcsncpy(SslCertData.subject.StateProvince, str, 255);
                SslCertData.subject.StateProvince[255] = 0;
                break;
            case NID_localityName:
                _tcsncpy(SslCertData.subject.Town, str, 255);
                SslCertData.subject.Town[255] = 0;
                break;
            default:
                if ( !pOBJ_nid2sn(pOBJ_obj2nid(pObject)) )
                {
                    TCHAR tmp[20];
                    _stprintf(tmp, _T("%d"), pOBJ_obj2nid(pObject));
                    int maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), tmp, maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), _T("="), maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), str, maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), _T(";"), maxlen);
                }
                else
                {
                    int maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;

                    USES_CONVERSION;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), A2CT(pOBJ_nid2sn(pOBJ_obj2nid(pObject))), maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), _T("="), maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), str, maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.subject.Other)-1;
                    _tcsncpy(SslCertData.subject.Other+_tcslen(SslCertData.subject.Other), _T(";"), maxlen);
                }
                break;
            }
        }
    }

    //Set issuer data fields
    pX509Name=pX509_get_issuer_name(pX509);
    if (pX509Name)
    {
        int count=pX509_NAME_entry_count(pX509Name);
        for (int i=0;i<count;i++)
        {
            X509_NAME_ENTRY *pX509NameEntry=pX509_NAME_get_entry(pX509Name,i);
            if (!pX509NameEntry)
                continue;
            ASN1_STRING *pString=pX509_NAME_ENTRY_get_data(pX509NameEntry);
            ASN1_OBJECT *pObject=pX509_NAME_ENTRY_get_object(pX509NameEntry);

            CString str;

            unsigned char *out;
            int len = pASN1_STRING_to_UTF8(&out, pString);
            if (len > 0)
            {
                // Keep it huge
                LPWSTR unicode = new WCHAR[len * 10];
                memset(unicode, 0, sizeof(WCHAR) * len * 10);
                int unicodeLen = MultiByteToWideChar(CP_UTF8, 0, (const char *)out, len, unicode, len * 10);
                if (unicodeLen > 0)
                {
#ifdef _UNICODE
                    str = unicode;
#else
                    LPSTR ansi = new CHAR[len * 10];
                    memset(ansi, 0, sizeof(CHAR) * len * 10);
                    int ansiLen = WideCharToMultiByte(CP_ACP, 0, unicode, unicodeLen, ansi, len * 10, 0, 0);
                    if (ansiLen > 0)
                        str = ansi;

                    delete [] ansi;
#endif
                }
                delete [] unicode;
                pCRYPTO_free(out);
            }

            switch(pOBJ_obj2nid(pObject))
            {
            case NID_organizationName:
                _tcsncpy(SslCertData.issuer.Organization, str, 255);
                SslCertData.issuer.Organization[255] = 0;
                break;
            case NID_organizationalUnitName:
                _tcsncpy(SslCertData.issuer.Unit, str, 255);
                SslCertData.issuer.Unit[255] = 0;
                break;
            case NID_commonName:
                _tcsncpy(SslCertData.issuer.CommonName, str, 255);
                SslCertData.issuer.CommonName[255] = 0;
                break;
            case NID_pkcs9_emailAddress:
                _tcsncpy(SslCertData.issuer.Mail, str, 255);
                SslCertData.issuer.Mail[255] = 0;
                break;
            case NID_countryName:
                _tcsncpy(SslCertData.issuer.Country, str, 255);
                SslCertData.issuer.Country[255] = 0;
                break;
            case NID_stateOrProvinceName:
                _tcsncpy(SslCertData.issuer.StateProvince, str, 255);
                SslCertData.issuer.StateProvince[255] = 0;
                break;
            case NID_localityName:
                _tcsncpy(SslCertData.issuer.Town, str, 255);
                SslCertData.issuer.Town[255] = 0;
                break;
            default:
                if ( !pOBJ_nid2sn(pOBJ_obj2nid(pObject)) )
                {
                    TCHAR tmp[20];
                    _stprintf(tmp, _T("%d"), pOBJ_obj2nid(pObject));
                    int maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), tmp, maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), _T("="), maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), str, maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), _T(";"), maxlen);
                }
                else
                {
                    int maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;

                    USES_CONVERSION;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), A2CT(pOBJ_nid2sn(pOBJ_obj2nid(pObject))), maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), _T("="), maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), str, maxlen);

                    maxlen = 1024 - _tcslen(SslCertData.issuer.Other)-1;
                    _tcsncpy(SslCertData.issuer.Other+_tcslen(SslCertData.issuer.Other), _T(";"), maxlen);
                }
                break;
            }
        }
    }

    //Set date fields

    static const char *mon[12]=
    {
    "Jan","Feb","Mar","Apr","May","Jun",
    "Jul","Aug","Sep","Oct","Nov","Dec"
    };

    //Valid from
    ASN1_UTCTIME *pTime=X509_get_notBefore(pX509);
    if (!pTime)
    {
        pX509_free(pX509);
        return FALSE;
    }

    char *v;
    int gmt = 0;
    int i;
    int y=0, M=0, d=0, h=0, m=0, s=0;

    i = pTime->length;
    v = (char *)pTime->data;

    if (i < 10)
    {
        pX509_free(pX509);
        return FALSE;
    }
    if (v[i-1] == 'Z') gmt=1;
    for (i=0; i<10; i++)
        if ((v[i] > '9') || (v[i] < '0'))
        {
            pX509_free(pX509);
            return FALSE;
        }
    y= (v[0]-'0')*10+(v[1]-'0');
    if (y < 50) y+=100;
    M= (v[2]-'0')*10+(v[3]-'0');
    if ((M > 12) || (M < 1))
    {
        pX509_free(pX509);
        return FALSE;
    }
    d= (v[4]-'0')*10+(v[5]-'0');
    h= (v[6]-'0')*10+(v[7]-'0');
    m=  (v[8]-'0')*10+(v[9]-'0');
    if (    (v[10] >= '0') && (v[10] <= '9') &&
        (v[11] >= '0') && (v[11] <= '9'))
        s=  (v[10]-'0')*10+(v[11]-'0');

    SslCertData.validFrom.y = y+1900;
    SslCertData.validFrom.M = M;
    SslCertData.validFrom.d = d;
    SslCertData.validFrom.h = h;
    SslCertData.validFrom.m = m;
    SslCertData.validFrom.s = s;

    //Valid until
    pTime = X509_get_notAfter(pX509);
    if (!pTime)
    {
        pX509_free(pX509);
        return FALSE;
    }

    gmt = 0;
    i;
    y=0,M=0,d=0,h=0,m=0,s=0;

    i=pTime->length;
    v=(char *)pTime->data;

    if (i < 10)
    {
        pX509_free(pX509);
        return FALSE;
    }
    if (v[i-1] == 'Z') gmt=1;
    for (i=0; i<10; i++)
        if ((v[i] > '9') || (v[i] < '0'))
        {
            pX509_free(pX509);
            return FALSE;
        }
    y= (v[0]-'0')*10+(v[1]-'0');
    if (y < 50) y+=100;
    M= (v[2]-'0')*10+(v[3]-'0');
    if ((M > 12) || (M < 1))
    {
        pX509_free(pX509);
        return FALSE;
    }
    d= (v[4]-'0')*10+(v[5]-'0');
    h= (v[6]-'0')*10+(v[7]-'0');
    m=  (v[8]-'0')*10+(v[9]-'0');
    if (    (v[10] >= '0') && (v[10] <= '9') &&
        (v[11] >= '0') && (v[11] <= '9'))
        s=  (v[10]-'0')*10+(v[11]-'0');

    SslCertData.validUntil.y = y+1900;
    SslCertData.validUntil.M = M;
    SslCertData.validUntil.d = d;
    SslCertData.validUntil.h = h;
    SslCertData.validUntil.m = m;
    SslCertData.validUntil.s = s;

    unsigned int length = 20;
    pX509_digest(pX509, pEVP_sha1(), SslCertData.hash, &length);

    SslCertData.priv_data = m_nSslAsyncNotifyId;

    pX509_free(pX509);

    SslCertData.verificationResult = m_nVerificationResult;
    SslCertData.verificationDepth = m_nVerificationDepth;

    return TRUE;
}

void CAsyncSslSocketLayer::SetNotifyReply(int nID, int nCode, int result)
{
    if (!m_bBlocking)
        return;
    if (nID != m_nSslAsyncNotifyId)
        return;
    if (nCode != SSL_VERIFY_CERT)
        return;

    m_bBlocking = FALSE;

    if (!result)
    {
        m_nNetworkError = WSAECONNABORTED;
        WSASetLastError(WSAECONNABORTED);
        if (!m_bFailureSent)
        {
            m_bFailureSent = TRUE;
            DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_FAILURE, SSL_FAILURE_CERTREJECTED);
        }
        TriggerEvent(FD_CLOSE, 0, TRUE);
        return;
    }
    m_bSslEstablished = TRUE;
    PrintSessionInfo();
    DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_INFO, SSL_INFO_ESTABLISHED);

    TriggerEvents();
}

void CAsyncSslSocketLayer::PrintSessionInfo()
{
    SSL_CIPHER *ciph;
    X509 *cert;

    ciph = pSSL_get_current_cipher(m_ssl);
    char enc[4096] = {0};
    cert=pSSL_get_peer_certificate(m_ssl);

    if (cert != NULL)
    {
        EVP_PKEY *pkey = pX509_get_pubkey(cert);
        if (pkey != NULL)
        {
            if (0)
                ;
#ifndef NO_RSA
            else if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL
                && pkey->pkey.rsa->n != NULL)
                sprintf(enc,    "%d bit RSA", pBN_num_bits(pkey->pkey.rsa->n));
#endif
#ifndef NO_DSA
            else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL
                    && pkey->pkey.dsa->p != NULL)
                sprintf(enc,    "%d bit DSA", pBN_num_bits(pkey->pkey.dsa->p));
#endif
            pEVP_PKEY_free(pkey);
        }
        pX509_free(cert);
        /* The SSL API does not allow us to look at temporary RSA/DH keys,
         * otherwise we should print their lengths too */
    }

    char *buffer = new char[4096];
    sprintf(buffer, "Using %s, cipher %s: %s, %s",
            pSSL_get_version(m_ssl),
            pSSL_CIPHER_get_version(ciph),
            pSSL_CIPHER_get_name(ciph),
            enc);
    DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_INFO, 0, buffer);
}

void CAsyncSslSocketLayer::OnConnect(int nErrorCode)
{
    if (m_bUseSSL && nErrorCode)
        TriggerEvent(FD_WRITE, 0);
    TriggerEvent(FD_CONNECT, nErrorCode, TRUE);
}

int CAsyncSslSocketLayer::verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
{
    X509   *err_cert;
    int     err, depth;
    SSL    *ssl;

    err_cert = pX509_STORE_CTX_get_current_cert(ctx);
    err = pX509_STORE_CTX_get_error(ctx);
    depth = pX509_STORE_CTX_get_error_depth(ctx);

    /*
     * Retrieve the pointer to the SSL of the connection currently treated
     * and the application specific data stored into the SSL object.
     */
    ssl = (SSL *)pX509_STORE_CTX_get_ex_data(ctx, pSSL_get_ex_data_X509_STORE_CTX_idx());

    // Lookup CAsyncSslSocketLayer instance
    CAsyncSslSocketLayer *pLayer = 0;
    m_sCriticalSection.Lock();
    t_SslLayerList *cur = m_pSslLayerList;
    while (cur)
    {
        if (cur->pLayer->m_ssl == ssl)
            break;
        cur = cur->pNext;
    }
    if (!cur)
    {
        m_sCriticalSection.Unlock();
        //MessageBox(0, _T("Can't lookup SSL session!"), _T("Critical error"), MB_ICONEXCLAMATION);
        return 1;
    }
    else
        pLayer = cur->pLayer;
    m_sCriticalSection.Unlock();

    /*
     * Catch a too long certificate chain. The depth limit set using
     * SSL_CTX_set_verify_depth() is by purpose set to "limit+1" so
     * that whenever the "depth>verify_depth" condition is met, we
     * have violated the limit and want to log this error condition.
     * We must do it here, because the CHAIN_TOO_LONG error would not
     * be found explicitly; only errors introduced by cutting off the
     * additional certificates would be logged.
     */
    if (depth > 10) {//mydata->verify_depth) {
        preverify_ok = 0;
        err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
        pX509_STORE_CTX_set_error(ctx, err);
    }

    if (!preverify_ok)
    {
        if (!pLayer->m_nVerificationResult)
        {
            pLayer->m_nVerificationDepth = depth;
            pLayer->m_nVerificationResult = err;
        }
    }
    return 1;
}

BOOL CAsyncSslSocketLayer::SetCertStorage(CString file)
{
    m_CertStorage = file;
    return TRUE;
}

void CAsyncSslSocketLayer::OnClose(int nErrorCode)
{
    m_onCloseCalled = true;
    if (m_bUseSSL && pBIO_ctrl && pBIO_ctrl(m_sslbio, BIO_CTRL_PENDING, 0, NULL) > 0)
    {
        TriggerEvents();
    }
    else
        TriggerEvent(FD_CLOSE, nErrorCode, TRUE);
}

bool CAsyncSslSocketLayer::PrintLastErrorMsg()
{
    bool fatal = false;
    int err = pERR_get_error();
    while (err)
    {
        // Something about an undefined const function or
        // so, no idea where that comes from. OpenSSL is a mess
        if (err != 336539714)
            fatal = true;
        char *buffer = new char[512];
        pERR_error_string(err, buffer);
        err = pERR_get_error();
        DoLayerCallback(LAYERCALLBACK_LAYERSPECIFIC, SSL_VERBOSE_WARNING, 0, buffer);
    }

    return fatal;
}

void CAsyncSslSocketLayer::ClearErrors()
{
    int err = pERR_get_error();
    while (err)
        err = pERR_get_error();
}

bool CAsyncSslSocketLayer::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)
{
    // Certificate valid for a year
    int days = 365;

    CAsyncSslSocketLayer layer;
    if (layer.InitSSL())
    {
        err = _T("Failed to initialize SSL library");
        return false;
    }

    X509 *x;
    EVP_PKEY *pk;
    RSA *rsa;
    X509_NAME *name = NULL;
    
    if ((pk = pEVP_PKEY_new()) == NULL)
    {
        err = _T("Could not create key object");
        return false;
    }

    if ((x = pX509_new()) == NULL)
    {
        err = _T("Could not create certificate object");
        return false;
    }

    rsa = pRSA_generate_key(bits, RSA_F4, 0/*callback*/, NULL);
    
    if (!pEVP_PKEY_assign(pk, EVP_PKEY_RSA, (char *)(rsa)))
    {
        err = _T("Failed to assign rsa key to key object");
        return false;
    }

    rsa = NULL;

    pX509_set_version(x,2);
    pASN1_INTEGER_set(pX509_get_serialNumber(x), 0/*serial*/);
    pX509_gmtime_adj(X509_get_notBefore(x),0);
    pX509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days);
    pX509_set_pubkey(x,pk);

    name = pX509_get_subject_name(x);

    /* This function creates and adds the entry, working out the
     * correct string type and performing checks on its length.
     * Normally we'd check the return value for errors...
     */
    pX509_NAME_add_entry_by_txt(name, "CN",
                MBSTRING_ASC, cname, -1, -1, 0);
    pX509_NAME_add_entry_by_txt(name, "C",
                MBSTRING_ASC, country, -1, -1, 0);
    pX509_NAME_add_entry_by_txt(name, "ST",
                MBSTRING_ASC, state, -1, -1, 0);
    pX509_NAME_add_entry_by_txt(name, "L",
                MBSTRING_ASC, locality, -1, -1, 0);
    pX509_NAME_add_entry_by_txt(name, "O",
                MBSTRING_ASC, organization, -1, -1, 0);
    pX509_NAME_add_entry_by_txt(name, "OU",
                MBSTRING_ASC, unit, -1, -1, 0);
    pX509_NAME_add_entry_by_NID(name, NID_pkcs9_emailAddress,
                MBSTRING_ASC, email, -1, -1, 0);

    /* Its self signed so set the issuer name to be the same as the
      * subject.
     */
    pX509_set_issuer_name(x,name);

    if (!pX509_sign(x, pk, pEVP_sha1()))
    {
        err = _T("Failed to sign certificate");
        return false;
    }

    // Write key and certificate to file
    // We use a memory bio, since the OpenSSL functions accepting a filepointer 
    // do crash for no obvious reason.

#ifndef _UNICODE
    FILE* file = fopen(filename, "w+");
#else
    FILE* file = _wfopen(filename, _T("w+"));
#endif

    if (!file)
    {
        err = _T("Failed to open output file");
        return false;
    }

    BIO* bio = pBIO_new(pBIO_s_mem());
    pPEM_ASN1_write_bio((int (*)())pi2d_PrivateKey, (((pk)->type == EVP_PKEY_DSA)?PEM_STRING_DSA:PEM_STRING_RSA), bio, (char *)pk, NULL, NULL, 0, NULL, NULL);
    pPEM_ASN1_write_bio((int (*)())pi2d_X509, PEM_STRING_X509, bio, (char *)x, NULL, NULL, 0, NULL, NULL);
    
    char buffer[1001];
    int len;
    while ((len = pBIO_read(bio, buffer, 1000)) > 0)
    {
        buffer[len] = 0;
        fprintf(file, buffer);
    }

    fclose(file);

    pX509_free(x);
    pEVP_PKEY_free(pk);

    pBIO_free(bio);

    layer.UnloadSSL();

    return true;
}

int CAsyncSslSocketLayer::SetCertKeyFile(const char* cert, const char* key, const char* pass, CString* error /*=0*/)
{
    int res = InitSSL();
    if (res)
        return res;

    m_sCriticalSection.Lock();
    
    if (!m_ssl_ctx)
    {
        // Create new context
        if (!(m_ssl_ctx = pSSL_CTX_new( pSSLv23_method())))
        {
            m_sCriticalSection.Unlock();
            return SSL_FAILURE_INITSSL;
        }
        m_contextRefCount[m_ssl_ctx] = 1;

        long options = pSSL_CTX_ctrl(m_ssl_ctx, SSL_CTRL_OPTIONS, 0, NULL);
        pSSL_CTX_ctrl(m_ssl_ctx, SSL_CTRL_OPTIONS, options | SSL_OP_NO_SSLv2, NULL);
    }

    pSSL_CTX_set_default_passwd_cb(m_ssl_ctx, pem_passwd_cb);
    pSSL_CTX_set_default_passwd_cb_userdata(m_ssl_ctx, this);

    if (pass)
    {
        size_t len = strlen(pass);
        m_pKeyPassword = new char[len + 1];
        strcpy(m_pKeyPassword, pass);
    }
    else
    {
        delete [] m_pKeyPassword;
        m_pKeyPassword = 0;
    }

    ClearErrors();
    if (pSSL_CTX_use_certificate_chain_file(m_ssl_ctx, cert) <= 0)
    //if (pSSL_CTX_use_certificate_file(m_ssl_ctx, cert, SSL_FILETYPE_PEM) <= 0)
    {
        if (error)
            *error = _T("Could not load certificate file.");
        m_sCriticalSection.Unlock();
        return SSL_FAILURE_VERIFYCERT;
    }

    if (pSSL_CTX_use_PrivateKey_file(m_ssl_ctx, key, SSL_FILETYPE_PEM) <= 0)
    {
        if (error)
            *error = _T("Could not load key file.");
        m_sCriticalSection.Unlock();
        return SSL_FAILURE_VERIFYCERT;
    }

    if (!pSSL_CTX_check_private_key(m_ssl_ctx))
    {
        if (error)
            *error = _T("Private key does not match the certificate public key.");
        m_sCriticalSection.Unlock();
        return SSL_FAILURE_VERIFYCERT;
    }

    m_sCriticalSection.Unlock();

    return 0;
}

int CAsyncSslSocketLayer::SendRaw(const void* lpBuf, int nBufLen, int nFlags)
{
    if (!m_bUseSSL)
    {
        SetLastError(WSANOTINITIALISED);
        return SOCKET_ERROR;
    }

    if (!lpBuf)
        return 0;
    
    if (m_nNetworkError)
    {
        SetLastError(m_nNetworkError);
        return SOCKET_ERROR;
    }
    if (m_nShutDown)
    {
        SetLastError(WSAESHUTDOWN);
        return SOCKET_ERROR;
    }
    if (m_nNetworkSendBufferLen)
    {
        SetLastError(WSAEINPROGRESS);
        return SOCKET_ERROR;
    }
    if (!nBufLen)
        return 0;

    if (m_nNetworkSendBufferMaxLen < nBufLen)
        m_nNetworkSendBufferMaxLen = nBufLen;
    delete [] m_pNetworkSendBuffer;
    m_pNetworkSendBuffer = new char[m_nNetworkSendBufferMaxLen];
    memcpy(m_pNetworkSendBuffer, lpBuf, nBufLen);
    m_nNetworkSendBufferLen = nBufLen;
    TriggerEvent(FD_WRITE, 0);

    return nBufLen;
}

void CAsyncSslSocketLayer::TriggerEvents()
{
    if (pBIO_ctrl_pending(m_nbio) > 0)
    {
        if (m_mayTriggerWrite)
        {
            m_mayTriggerWrite = false;
            TriggerEvent(FD_WRITE, 0);
        }
    }
    else if (!m_nNetworkSendBufferLen && m_bSslEstablished && !m_pRetrySendBuffer && pBIO_ctrl_get_write_guarantee(m_sslbio) > 0 && m_mayTriggerWriteUp)
    {
        m_mayTriggerWriteUp = false;
        TriggerEvent(FD_WRITE, 0, TRUE);
    }

    if (m_bSslEstablished && pBIO_ctrl_pending(m_sslbio) > 0)
    {
        if (m_mayTriggerReadUp && !m_bBlocking)
        {
            m_mayTriggerReadUp = false;
            TriggerEvent(FD_READ, 0, TRUE);
        }
    }
    else if (pBIO_ctrl_get_write_guarantee(m_nbio) > 0 && m_mayTriggerRead)
    {
        m_mayTriggerRead = false;
        TriggerEvent(FD_READ, 0);
    }

    if (m_onCloseCalled && m_bSslEstablished && pBIO_ctrl_pending(m_sslbio) <= 0)
        TriggerEvent(FD_CLOSE, 0, TRUE);
}

int CAsyncSslSocketLayer::pem_passwd_cb(char *buf, int size, int rwflag, void *userdata)
{
    CAsyncSslSocketLayer* pThis = (CAsyncSslSocketLayer*)userdata;

    if (!pThis || !pThis->m_pKeyPassword)
        return 0;

    int len = strlen(pThis->m_pKeyPassword);
    if (len >= size)
        len = size - 1;

    memcpy(buf, pThis->m_pKeyPassword, len);
    buf[len] = 0;

    return len;
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0312 ]--