blob: 47d8f5b75b66e23a6a96b0212eb8c629f8a8e40e [file] [log] [blame]
/*
* Copyright 2003-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* @author damitha Kumarage (damitha@hsenid.lk, damitha@opensource.lk)
*
*/
#include "OpenSSLChannel.hpp"
#include <openssl/ssl.h>
#include <openssl/err.h>
char* m_pcError;
SSL_CTX* m_sslContext;
SSL* m_sslHandle;
/* "global" init done? */
static bool g_InitSSL = false;
/* We have the "SSL is seeded" boolean global for the application to
prevent multiple time-consuming seedings in vain */
static bool g_sslSeeded = false;
static
int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
{
X509 *err_cert;
char buf[256];
err_cert=X509_STORE_CTX_get_current_cert(ctx);
X509_NAME_oneline(X509_get_subject_name(err_cert),buf,256);
return ok;
}
OpenSSLChannel::OpenSSLChannel()
{
if(!g_InitSSL)
{
/* Lets get nice error messages */
SSL_load_error_strings();
/* Setup all the global SSL stuff */
SSLeay_add_ssl_algorithms();
g_InitSSL = true;
}
}
OpenSSLChannel::~OpenSSLChannel()
{
}
bool OpenSSLChannel::open() throw (AxisTransportException&)
{
Channel::open();
openSecureSocket();
return true;
}
int OpenSSLChannel::openSecureSocket()
{
SSL_METHOD* req_method = SSLv23_client_method();
SSL_SESSION* ssl_sessionid = NULL;
m_sslContext = SSL_CTX_new(req_method);
if(!m_sslContext)
{
int sslerror = ERR_get_error();
/* OpenSSL documents that this must be at least 120 bytes long. */
char error_buffer[120];
ERR_error_string(sslerror, error_buffer);
closeSecureSocket();
throw AxisSSLChannelException(CLIENT_SSLCHANNEL_CONTEXT_CREATE_ERROR, error_buffer);
}
SSL_CTX_set_verify(m_sslContext, /*SSL_VERIFY_PEER*/SSL_VERIFY_NONE,
cert_verify_callback);
/* Lets make an SSL structure */
m_sslHandle = SSL_new(m_sslContext);
SSL_set_connect_state(m_sslHandle);
/* pass the raw socket into the SSL layers */
SSL_set_fd(m_sslHandle, m_Sock);
int iError = SSL_connect(m_sslHandle);
/*
* 1 is fine
* 0 is "not successful but was shut down controlled"
* <0 is "handshake was not successful, because a fatal error occurred"
*/
if(iError <= 0)
setSecureError(iError);
return 0;
}
const Channel & SecureChannel::operator << (const char * msg) throw (AxisTransportException)
{
writeSecureSocket(msg);
return *this;
}
const Channel &SecureChannel::operator >> (std::string & msg) throw (AxisTransportException)
{
int iBuffSize = 4096;
char buff[iBuffSize];
readSecureSocket(buff, iBuffSize);
msg = buff;
return *this;
}
bool OpenSSLChannel::readSecureSocket(char* pcMsg, int piSize)
{
int nByteRecv = 0;
//const int BUF_SIZE = 4096;
char buf[BUF_SIZE];
nByteRecv = SSL_read(m_sslHandle, buf, BUF_SIZE - 1);
if(nByteRecv < 0)
{
char error_string[256];
/* failed SSL_read */
int iError = SSL_get_error(m_sslHandle, nByteRecv);
setSecureError(iError);
closeSecureSocket();
}
if(nByteRecv)
{
buf[nByteRecv] = '\0';
/* got a part of the message, so add it to form */
pcMsg = buf;
}
else
printf("execution break\n");
return true;
}
bool OpenSSLChannel::writeSecureSocket(const char* pcMsg)
{
if(INVALID_SOCKET == m_Sock)
{
throw AxisSSLChannelException(CLIENT_SSLCHANNEL_INVALID_SOCKET_ERROR,"");
}
int size = strlen(pcMsg), nByteSent;
nByteSent = SSL_write(m_sslHandle, (char *)pcMsg, size);
if(nByteSent < 0)
{
char error_string[256];
int iError = SSL_get_error(m_sslHandle, nByteSent);
setSecureError(iError);
closeSecureSocket();
}
return true;
}
void OpenSSLChannel::setSecureError(int iError)
{
switch(iError)
{
case SSL_ERROR_NONE: /* this is not an error */
case SSL_ERROR_ZERO_RETURN: /* no more data */
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_SYSCALL:
{
#ifdef WIN32
iError = ::GetLastError();
#else
iError = errno;
#endif
closeSecureSocket();
throw AxisSSLChannelException(CLIENT_SSLCHANNEL_ERROR, "SSL_ERROR_SYSCALL");
}
case SSL_ERROR_SSL:
{
/* A failure in the SSL library occurred, usually a
protocol error. The OpenSSL error queue contains more
information on the error. */
int sslerror = ERR_get_error();
/* OpenSSL documents that this must be at least 120
* bytes long.
*/
char error_buffer[120];
ERR_error_string(sslerror, error_buffer);
closeSecureSocket();
throw AxisSSLChannelException(CLIENT_SSLCHANNEL_ERROR, error_buffer);
}
default:
/* openssl/ssl.h says "look at error stack/return value/errno"*/
{
/* A failure in the SSL library occurred, usually a
protocol error. The OpenSSL error queue contains more
information on the error. */
int sslerror = ERR_get_error();
/* OpenSSL documents that this must be at least 120 bytes
* long.
*/
char error_buffer[120];
ERR_error_string(sslerror, error_buffer);
closeSecureSocket();
throw AxisSSLChannelException(CLIENT_SSLCHANNEL_ERROR, error_buffer);
}
}
}
char* OpenSSLChannel::getSecureError()
{
return m_pcError;
}
/**
* Close, and clean-up any OS specific stuff
*
*/
int OpenSSLChannel::closeSecureSocket()
{
if(m_sslHandle)
{
SSL_shutdown(m_sslHandle);
SSL_set_connect_state(m_sslHandle);
SSL_free(m_sslHandle);
m_sslHandle = NULL;
}
if(m_sslContext)
{
SSL_CTX_free (m_sslContext);
m_sslContext = NULL;
}
}