Added SSL support module based on OpenSSL.

git-svn-id: http://yate.null.ro/svn/yate/trunk@1862 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2008-03-31 14:23:31 +00:00
parent 7ad9a9690b
commit d5cbc677c9
2 changed files with 243 additions and 0 deletions

View File

@ -92,6 +92,10 @@ ifneq (@HAVE_SPEEX@,no)
PROGS := $(PROGS) speexcodec.yate
endif
ifneq (@HAVE_OPENSSL@,no)
PROGS := $(PROGS) openssl.yate
endif
ifeq (@HAVE_GTK2@_@HAVE_GMOZ@,yes_yes)
PROGS := $(PROGS) gtk2/gtk2mozilla.yate
endif
@ -253,6 +257,9 @@ yrtpchan.yate: ../libs/yrtp/libyatertp.a
yrtpchan.yate: LOCALFLAGS = -I@top_srcdir@/libs/yrtp
yrtpchan.yate: LOCALLIBS = ../libs/yrtp/libyatertp.a
openssl.yate: LOCALFLAGS = @OPENSSL_INC@
openssl.yate: LOCALLIBS = @OPENSSL_LIB@
gtk2/gtk2mozilla.yate: @top_srcdir@/clients/gtk2/gtk2client.h
gtk2/gtk2mozilla.yate: LOCALFLAGS = @GTK2_INC@ @GMOZ_INC@ -I@top_srcdir@/clients/gtk2
gtk2/gtk2mozilla.yate: LOCALLIBS = @GMOZ_LIB@

236
modules/openssl.cpp Normal file
View File

@ -0,0 +1,236 @@
/**
* openssl.cpp
* This file is part of the YATE Project http://YATE.null.ro
*
* OpenSSL based SSL/TLS socket support
*
* Yet Another Telephony Engine - a fully featured software PBX and IVR
* Copyright (C) 2004-2006 Null Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <yatengine.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
using namespace TelEngine;
namespace { // anonymous
class SslSocket : public Socket, public Mutex
{
public:
SslSocket(SOCKET handle, bool server);
virtual ~SslSocket();
virtual bool terminate();
virtual bool valid();
virtual int writeData(const void* buffer, int length);
virtual int readData(void* buffer, int length);
private:
int sslError(int retcode);
SSL* m_ssl;
};
class SslHandler : public MessageHandler
{
public:
inline SslHandler()
: MessageHandler("socket.ssl")
{ }
virtual bool received(Message& msg);
};
class OpenSSL : public Plugin
{
public:
OpenSSL();
~OpenSSL();
virtual void initialize();
protected:
SslHandler* m_handler;
};
INIT_PLUGIN(OpenSSL);
static SSL_CTX* s_context = 0;
// Attempt to add randomness from system time when called
static void addRand(u_int64_t usec)
{
// a rough estimation of 2 bytes of entropy
::RAND_add(&usec,sizeof(usec),2);
}
// Create a SSL socket from a regular socket handle
SslSocket::SslSocket(SOCKET handle, bool server)
: Socket(handle),
m_ssl(0)
{
DDebug(DebugAll,"SslSocket::SslSocket(%d,%s) [%p]",
handle,String::boolText(server),this);
if (Socket::valid()) {
m_ssl = ::SSL_new(s_context);
::SSL_set_fd(m_ssl,handle);
if (server)
::SSL_set_accept_state(m_ssl);
else
::SSL_set_connect_state(m_ssl);
}
}
// Destructor, clean up early
SslSocket::~SslSocket()
{
DDebug(DebugAll,"SslSocket::~SslSocket() handle=%d [%p]",handle(),this);
clearFilters();
terminate();
}
// Terminate the socket and the SSL session around it
bool SslSocket::terminate()
{
lock();
if (m_ssl) {
::SSL_shutdown(m_ssl);
::SSL_free(m_ssl);
m_ssl = 0;
// SSL_free also destroys the BIO and the socket so get rid of them
detach();
}
unlock();
return Socket::terminate();
}
// Check if the socket is valid
bool SslSocket::valid()
{
return m_ssl && Socket::valid();
}
// Write unencrypted data through the SSL stream
int SslSocket::writeData(const void* buffer, int length)
{
if (!buffer)
length = 0;
Lock lock(this);
return sslError(::SSL_write(m_ssl,buffer,length));
}
// Read decrypted data from the SSL stream
int SslSocket::readData(void* buffer, int length)
{
if (!buffer)
length = 0;
Lock lock(this);
return sslError(::SSL_read(m_ssl,buffer,length));
}
// Deal with the various SSL error codes
int SslSocket::sslError(int retcode)
{
if (retcode <= 0) {
switch (::SSL_get_error(m_ssl,retcode)) {
case SSL_ERROR_ZERO_RETURN:
clearError();
retcode = 0;
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_CONNECT:
case SSL_ERROR_WANT_ACCEPT:
m_error = EAGAIN;
retcode = 0;
break;
case SSL_ERROR_SYSCALL:
copyError();
break;
default:
m_error = EINVAL;
retcode = -1;
break;
}
}
else
clearError();
return retcode;
}
// Handler for the socket.ssl message - turns regular sockets into SSL
bool SslHandler::received(Message& msg)
{
addRand(msg.msgTime());
Socket** ppSock = static_cast<Socket**>(msg.userObject("Socket*"));
if (!ppSock) {
Debug("openssl",DebugGoOn,"SslHandler: No pointer to Socket");
return false;
}
Socket* pSock = *ppSock;
if (!pSock) {
Debug("openssl",DebugGoOn,"SslHandler: NULL Socket pointer");
return false;
}
if (!pSock->valid()) {
Debug("openssl",DebugWarn,"SslHandler: Invalid Socket");
return false;
}
SslSocket* sSock = new SslSocket(pSock->handle(),msg.getBoolValue("server",false));
if (!sSock->valid()) {
Debug("openssl",DebugWarn,"SslHandler: Invalid SSL Socket");
// detach and destroy new socket, preserve old one
sSock->detach();
delete sSock;
return false;
}
// replace socket, detach and destroy old one
*ppSock = sSock;
pSock->detach();
delete pSock;
return true;
}
OpenSSL::OpenSSL()
: Plugin("openssl",true),
m_handler(0)
{
Output("Loaded module OpenSSL - based on " OPENSSL_VERSION_TEXT);
}
OpenSSL::~OpenSSL()
{
Output("Unloading module OpenSSL");
::SSL_CTX_free(s_context);
}
void OpenSSL::initialize()
{
if (m_handler)
return;
Output("Initializing module OpenSSL");
::SSL_load_error_strings();
::SSL_library_init();
addRand(Time::now());
s_context = ::SSL_CTX_new(::SSLv23_method());
m_handler = new SslHandler;
Engine::install(m_handler);
}
}; // anonymous namespace
/* vi: set ts=8 sw=4 sts=4 noet: */