This example shows you how to build an SSL enabled server using OpenSSL
. This example uses our OpenSSL Tools Library
to integrate the OpenSSL code with our asynchronous I/O requirements. The basic structure of the server is very similar to the Basic Echo Server
example and you should go and read about that first and have a good understanding of how everything fits together. This document will only cover the differences between the Basic Echo Server
example and this example.
This example requires the "SSL/TLS (OpenSSL)" licensing option of The Server Framework and it requires libraries that only ship with that option (see here
for licensing options). You can always download the latest version of this example from here
; and although you will need the correct libraries to be able to build it you can look at the example code and see how it works and perhaps get ideas from it. A compiled, unicode release, build of this example is available on request if you require it for performance analysis of the framework.
This project assumes that you have OpenSSL 0.9.8e (or later) installed and that the environment variable OPEN_SSL_ROOT is set to point to the root directory of your OpenSSL installation. If you have any problems please contact us for help. You can download an OpenSSL source tree to build against from here
This server uses a custom command line parsing class which extends the standard command line parsing class and adds support for SSL options,
The first thing that we do differently is that we initialise the OpenSSL libraries by creating an instance of the
class. This sets us up for using OpenSSL in a multi-threaded environment and cleans up resources when the object goes out of scope; it's an scope based
library initialisation object.
Next we create an SSL Context
which contains various SSL configuration options. This needs to be passed in to the code that performs the SSL work and it's created in the CreateSSLContext() function, shown below. This is all standard OpenSSL stuff and it's adapted from the standard OpenSSL examples. You should adjust this as you see fit to configure OpenSSL to your requirements. This function and the other OpenSSL setup code that lives in ServerMain.cpp is purely to demonstrate how you could configure the system to work, it's not, in any way, an indication of HOW you SHOULD configure the system to work.
static SSL_CTX *CreateSSLContext(
const _tstring certificatePath)
SSL_METHOD *pMethod = SSLv23_method();
SSL_CTX *pContext = SSL_CTX_new(pMethod);
RAND_seed(rnd_seed, sizeof rnd_seed);
const string serverPemFile = CStringConverter::TtoA(certificatePath) + "server.pem";
throw CException(_T("CreateSSLContext()"), _T("Failed to load server certificate file: \"") + CStringConverter::AtoT(serverPemFile) + _T("\""));
if(!(SSL_CTX_use_PrivateKey_file(pContext, serverPemFile.c_str(), SSL_FILETYPE_PEM)))
throw CException(_T("CreateSSLContext()"), _T("Failed to load private key file: \"") + CStringConverter::AtoT(serverPemFile) + _T("\""));
DH *dh = get_dh1024();
const string rootPemFile = CStringConverter::TtoA(certificatePath) + "root.pem";
if(!(SSL_CTX_load_verify_locations(pContext, rootPemFile.c_str(), 0)))
throw CException(_T("CreateSSLContext()"), _T("Failed to load root CA file: \"") + CStringConverter::AtoT(rootPemFile) + _T("\""));
throw CException(_T("CreateSSLContext()"), _T("Failed to set verification paths"));
#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
The code above requires that you have
files in your 'certificate path'. The test harness that ships with the example contains demonstration files and the OpenSSL documentation should explain how to create your own.
Once the context is created the rest of the server setup code is pretty standard. The only thing that differs between this example and the standard Echo Server
example is that we have to use sequenced sockets
due to how the OpenSSL server works. The server class requires an instance of JetByteTools::Socket::IAllocateSequencedStreamSockets
rather than just an instance of JetByteTools::Socket::IAllocateStreamSockets
as it needs to add its own sequence id's to the sockets used.
const CFullAddress address(
const ListenBacklog listenBacklog = commandLine.ListenBacklog();
Our CSocketServer class should look pretty familiar, but you'll notice that it implements methods from the JetByteTools::OpenSSL::CStreamSocketServerCallback
class rather than just from JetByteTools::Socket::CStreamSocketServerCallback
. This provides it with the option of dealing with the following events which are unique to OpenSSL enabled servers.
OnSecureConnectionEstablished() is called before the normal OnConnectionEstablished() and OnSecureSocketReleased() is called after the normal OnSocketReleased(). They give you the chance to process secure connections differently to non secure connections. We do nothing special in these callbacks but implement them to output a debug trace when they're called.
In fact, if you ignore the callbacks that are implemented purely to provide informational debug tracing as the server runs then you'll find that the only place where this server differs from the standard server example is in its constructor.
const CContext &sslContext,
const bool verifyPeer,
const IFullAddress &address,
const ListenBacklog listenBacklog,
: JetByteTools::OpenSSL::CStreamSocketServer(sslContext, verifyPeer, address, listenBacklog, *this, pool, socketAllocator, bufferAllocator)
And those differences are purely to do with passing the
flag through to the SSL enabled base class
A major part of our design descisions for the OpenSSL Tools Library
were to make sure that the integration of SSL into a server was painless and didn't affect the design of the server. In fact, if you use the correct constructors for the JetByteTools::OpenSSL::CStreamSocketServer
class you use the same server for both SSL enabled and clear-text servers.