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/ |
+-------------------------------------------------------------------------+