As with any large system, there are a number of ways to do things.

Here's how we do it.  Hope you find it useful, if only for MapErrorcode. :)


============================================================================
                PARENT CLASS
============================================================================

//  This abstract type is the base class for (hopefully) all our
//  network-oriented I/O.  Any derived types must define their own
//  way of initializing their internal state.  It is NOT the intent
//  that this class require that the ctor and dtor encapsulate all
//  traditional open/close functionality.

class CIODispatch {
public:
    typedef enum _type {
        unknown, tcp, ssl
    } type;

    type            m_type;
    bool            m_valid;

public:
    virtual int     read(char *buff, int s) = 0;
    virtual int     write(char *buff, int s) = 0;
    virtual int     close(void) = 0;

    CIODispatch() : m_type(unknown), m_valid(false)
    {
    }
};

============================================================================
                SSL SUBCLASS
============================================================================

// Hide implementation-specific types.
typedef struct _SSL_STATE *ssl_state; 

//  I/O to-from a (TCP) client.
class CSSLClient : public CIODispatch {
protected:
    SOCKET          m_sd;
    ssl_state       m_sslstate;
    unsigned long   m_ipaddr;
    short           m_port;
public:
    //  Server-side:  accept a connection
    int     open(SOCKET s, SOCKADDR_IN& remaddr, int remsize);
    //  Client-side:  open a connection
    int     open(SOCKET s, int version = '2');
    int     read(char *buff, int s);
    int     write(char *buff, int s);
    int     close(void);
    int     getSocket()
    {
        return m_sd;
    }
    CSSLClient();
};

============================================================================
                SSL IMPLEMENTATION
============================================================================

struct _SSL_STATE {
    SSL*        s;
    SSL_CTX*    ctx;
    SSL_METHOD* m;
};

    //  Class globals.
char*   CSSL::CipherSpec  = "DEFAULT";
RSA*    CSSL::SecretKey;
X509*   CSSL::Certificate;



//  Make SSLeay error stuff as much like WINSOCK errors as possible.
static int MapErrorCode()
{
    unsigned long e = ERR_get_error();
    SetLastError((DWORD)e);
    return ERR_GET_FUNC(e);
}

int ssl_config()
{
    CSSL::CipherSpec = CConfigure::GetParam("Crypto", "SSLCipher", "DEFAULT");

    SSLeay_add_ssl_algorithms();

    // Load certificate and private key files.
    CSSL::SecretKey = ReadPrivateKeyFile();
    if (CSSL::SecretKey == NULL)
        return MapErrorCode();
    CSSL::Certificate = ReadCertificateFile();
    if (CSSL::Certificate == NULL)
        return MapErrorCode();

    // All done.
    return 0;
}

//  Client side of the connection.
int CSSLClient::open(SOCKET s, int version)
{
    //  The basic socket stuff.
    assert(m_valid == false);
    m_sd = s;

    //  Initialize SSL context.
    //m_sslstate->m = version == '2'
    //      ? SSLv2_client_method() : SSLv3_client_method();
    m_sslstate->m = SSLv2_client_method();
    m_sslstate->ctx = SSL_CTX_new(m_sslstate->m);
    if (m_sslstate->ctx == NULL)
        return MapErrorCode();

    //  Set up connection within this context.
    m_sslstate->s = SSL_new(m_sslstate->ctx);
    if (m_sslstate->s == NULL)
        return MapErrorCode();
    int st = SSL_set_fd(m_sslstate->s, s);
    if (st == 0)
        return MapErrorCode();
    st = SSL_connect(m_sslstate->s);
    if (st == -1)
        return MapErrorCode();

    //  All done.
    m_valid = true;
    return 0;
}

//  Server side of the connection.
int CSSLClient::open(SOCKET s, SOCKADDR_IN& remaddr, int remsize)
{
    //  The basic socket stuff.
    assert(m_valid == false);
    assert(remaddr.sin_family == AF_INET);
    assert(remsize == sizeof (struct sockaddr_in));
    m_ipaddr = remaddr.sin_addr.S_un.S_addr;
    m_port = remaddr.sin_port;
    m_sd = s;

    //  Initialize SSL context.
    m_sslstate->m = SSLv2_server_method();
    m_sslstate->ctx = SSL_CTX_new(m_sslstate->m);
    if (m_sslstate->ctx == NULL)
        return MapErrorCode();
    SSL_CTX_set_options(m_sslstate->ctx, SSL_OP_ALL);
    int st;
    st = SSL_CTX_use_RSAPrivateKey(m_sslstate->ctx, CSSL::SecretKey);
    if (st == -1)
        return MapErrorCode();
    st = SSL_CTX_use_certificate(m_sslstate->ctx, CSSL::Certificate);
    if (st == -1)
        return MapErrorCode();
    if (strcmp(CSSL::CipherSpec, "DEFAULT") != 0) {
        if (SSL_CTX_set_cipher_list(m_sslstate->ctx, CSSL::CipherSpec) == -1)
            return MapErrorCode();
    }

    //  Set up connection within this context.
    m_sslstate->s = SSL_new (m_sslstate->ctx);
    if (m_sslstate->s == NULL)
        return MapErrorCode();
    st = SSL_set_fd(m_sslstate->s, s);
    if (st == 0)
        return MapErrorCode();
    st = SSL_accept(m_sslstate->s);
    if (st == -1)
        return MapErrorCode();
    
    //  All done.
    m_valid = true;
    return 0;
}

+-------------------------------------------------------------------------+
| Administrative requests should be sent to [EMAIL PROTECTED] |
| List service provided by Open Software Associates, http://www.osa.com/  |
+-------------------------------------------------------------------------+

Reply via email to