2013-12-31 19:36:07 +00:00
|
|
|
#include "session/TLSContext.hpp"
|
|
|
|
|
|
|
|
#include "common/StringUtils.hpp"
|
|
|
|
#include "common/EPPException.hpp"
|
|
|
|
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
2014-01-05 22:58:00 +00:00
|
|
|
#if (PRODUCTION==1)
|
|
|
|
#define sslCast
|
|
|
|
#define sslUncast
|
|
|
|
#else
|
|
|
|
#define sslCast const
|
|
|
|
#define sslUncast (SSL_CTX *)
|
|
|
|
#endif
|
|
|
|
|
2013-12-31 19:36:07 +00:00
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
int getPassword(char *buf, int size, int rwflag, void *password)
|
|
|
|
{
|
|
|
|
if ((unsigned)size < strlen ((char *)password) + 1) return 0;
|
|
|
|
strcpy(buf, (char *)password);
|
|
|
|
return (strlen (buf));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TLSContext::~TLSContext()
|
|
|
|
{
|
|
|
|
SSL_CTX_free(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
TLSContext::TLSContext(const string& private_key_file,
|
|
|
|
const string& cert_file,
|
|
|
|
const string& ca_file,
|
|
|
|
const string& pass)
|
|
|
|
: password(pass), ctx(NULL)
|
|
|
|
{
|
|
|
|
SSL_load_error_strings();
|
|
|
|
SSL_library_init();
|
2014-01-05 22:58:00 +00:00
|
|
|
|
|
|
|
sslCast SSL_METHOD *meth = TLSv1_client_method();
|
2013-12-31 19:36:07 +00:00
|
|
|
if (meth == NULL)
|
|
|
|
throw SSLException("Error initialising SSL method");
|
|
|
|
|
|
|
|
// SSL Context
|
2014-01-05 22:58:00 +00:00
|
|
|
sslCast SSL_CTX *local_ctx = SSL_CTX_new(meth);
|
2013-12-31 19:36:07 +00:00
|
|
|
if (local_ctx == NULL)
|
|
|
|
{
|
|
|
|
throw SSLException ("Error initialising SSL context");
|
|
|
|
}
|
|
|
|
|
|
|
|
// SSL Ciphers
|
2014-01-05 22:58:00 +00:00
|
|
|
int i = SSL_CTX_set_cipher_list( sslUncast local_ctx, "TLSv1");
|
2013-12-31 19:36:07 +00:00
|
|
|
if (i == -1)
|
|
|
|
{
|
2014-01-05 22:58:00 +00:00
|
|
|
SSL_CTX_free( sslUncast local_ctx);
|
2013-12-31 19:36:07 +00:00
|
|
|
throw SSLException(
|
|
|
|
"There was a problem initialising the SSL cipher list");
|
|
|
|
}
|
|
|
|
|
2014-01-05 22:58:00 +00:00
|
|
|
SSL_CTX_set_default_passwd_cb_userdata( sslUncast local_ctx,
|
2013-12-31 19:36:07 +00:00
|
|
|
static_cast<void*>(const_cast<char*>(password.c_str())));
|
2014-01-05 22:58:00 +00:00
|
|
|
SSL_CTX_set_default_passwd_cb( sslUncast local_ctx, getPassword);
|
2013-12-31 19:36:07 +00:00
|
|
|
|
2014-01-05 22:58:00 +00:00
|
|
|
i = SSL_CTX_use_PrivateKey_file( sslUncast local_ctx,
|
2013-12-31 19:36:07 +00:00
|
|
|
private_key_file.c_str(),
|
|
|
|
SSL_FILETYPE_PEM);
|
|
|
|
if (i == -1)
|
|
|
|
{
|
2014-01-05 22:58:00 +00:00
|
|
|
SSL_CTX_free( sslUncast local_ctx);
|
2013-12-31 19:36:07 +00:00
|
|
|
throw SSLException(
|
|
|
|
"There was a problem initialising SSL the private key '"
|
|
|
|
+ private_key_file + "'");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load the public certificate for our key.
|
|
|
|
// Replace with
|
2014-01-05 22:58:00 +00:00
|
|
|
i = SSL_CTX_use_certificate_chain_file( sslUncast local_ctx, cert_file.c_str());
|
2013-12-31 19:36:07 +00:00
|
|
|
if (i == -1)
|
|
|
|
{
|
2014-01-05 22:58:00 +00:00
|
|
|
SSL_CTX_free( sslUncast local_ctx);
|
2013-12-31 19:36:07 +00:00
|
|
|
throw SSLException("Error loading cert_file '" + cert_file + "'");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load the CA certificate(s)
|
2014-01-05 22:58:00 +00:00
|
|
|
i = SSL_CTX_load_verify_locations ( sslUncast local_ctx, ca_file.c_str(), NULL);
|
2013-12-31 19:36:07 +00:00
|
|
|
|
|
|
|
if (i == -1)
|
|
|
|
{
|
2014-01-05 22:58:00 +00:00
|
|
|
SSL_CTX_free( sslUncast local_ctx);
|
2013-12-31 19:36:07 +00:00
|
|
|
throw EPPException ("Could not load CA file '" + ca_file +"'");
|
|
|
|
}
|
|
|
|
|
2014-01-05 22:58:00 +00:00
|
|
|
ctx = sslUncast local_ctx;
|
2013-12-31 19:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto_ptr<TLSSocket> TLSContext::createSocket(const string& host, int port, int soTimeout)
|
|
|
|
{
|
|
|
|
int sock = tcpConnect(host, port, soTimeout);
|
|
|
|
return auto_ptr<TLSSocket>(new TLSSocket(ctx, sock, host, port, soTimeout));
|
|
|
|
}
|
|
|
|
|
|
|
|
int TLSContext::tcpConnect(const string& host, int port, int soTimeout)
|
|
|
|
{
|
|
|
|
struct hostent *hp = gethostbyname (host.c_str());
|
|
|
|
if (hp == NULL)
|
|
|
|
throw EPPException ("Could not resolve host: '" + host);
|
|
|
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
bzero ((char *)&addr, sizeof (addr));
|
|
|
|
addr.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
addr.sin_port = htons(port);
|
|
|
|
|
|
|
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
|
|
|
if (sock < 0)
|
|
|
|
throw EPPException("Could not create the socket.");
|
|
|
|
|
|
|
|
setSocketTimeout(sock, soTimeout);
|
|
|
|
|
|
|
|
if (connect(sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
|
|
|
|
{
|
|
|
|
close(sock);
|
|
|
|
throw EPPException ("Could not connect to host");
|
|
|
|
}
|
|
|
|
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TLSContext::setSocketTimeout(int sock, int timeoutPeriod)
|
|
|
|
{
|
|
|
|
struct timeval snd_rcv_to_val;
|
|
|
|
snd_rcv_to_val.tv_sec = timeoutPeriod;
|
|
|
|
snd_rcv_to_val.tv_usec = 0;
|
|
|
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &snd_rcv_to_val,
|
|
|
|
sizeof(snd_rcv_to_val));
|
|
|
|
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &snd_rcv_to_val,
|
|
|
|
sizeof(snd_rcv_to_val));
|
|
|
|
}
|