mirror of https://github.com/Icinga/icinga2.git
Implemented error handling and certificate verification for SSL.
This commit is contained in:
parent
b89c6abab6
commit
4f6aa3236c
|
@ -44,3 +44,13 @@ string PosixException::FormatErrorCode(int code)
|
||||||
{
|
{
|
||||||
return strerror(code);
|
return strerror(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string OpenSSLException::FormatErrorCode(int code)
|
||||||
|
{
|
||||||
|
char *message = ERR_error_string(code, NULL);
|
||||||
|
|
||||||
|
if (message == NULL)
|
||||||
|
message = "Unknown error.";
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,17 @@ public:
|
||||||
static string FormatErrorCode(int code);
|
static string FormatErrorCode(int code);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class OpenSSLException : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline OpenSSLException(const string& message, int errorCode)
|
||||||
|
{
|
||||||
|
SetMessage(message + ": " + FormatErrorCode(errorCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
static string FormatErrorCode(int code);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* EXCEPTION_H */
|
#endif /* EXCEPTION_H */
|
||||||
|
|
|
@ -2,19 +2,22 @@
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
|
int I2_EXPORT TLSClient::m_SSLIndex;
|
||||||
|
bool I2_EXPORT TLSClient::m_SSLIndexInitialized = false;
|
||||||
|
|
||||||
TLSClient::TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext) : TCPClient(role)
|
TLSClient::TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext) : TCPClient(role)
|
||||||
{
|
{
|
||||||
m_SSLContext = sslContext;
|
m_SSLContext = sslContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<X509> TLSClient::GetClientCertificate(void) const
|
X509 *TLSClient::GetClientCertificate(void) const
|
||||||
{
|
{
|
||||||
return shared_ptr<X509>(SSL_get_certificate(m_SSL.get()), X509_free);
|
return SSL_get_certificate(m_SSL.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<X509> TLSClient::GetPeerCertificate(void) const
|
X509 *TLSClient::GetPeerCertificate(void) const
|
||||||
{
|
{
|
||||||
return shared_ptr<X509>(SSL_get_peer_certificate(m_SSL.get()), X509_free);
|
return SSL_get_peer_certificate(m_SSL.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TLSClient::Start(void)
|
void TLSClient::Start(void)
|
||||||
|
@ -26,6 +29,19 @@ void TLSClient::Start(void)
|
||||||
if (!m_SSL)
|
if (!m_SSL)
|
||||||
; /* TODO: deal with error */
|
; /* TODO: deal with error */
|
||||||
|
|
||||||
|
if (!GetClientCertificate())
|
||||||
|
throw InvalidArgumentException("No X509 client certificate was specified.");
|
||||||
|
|
||||||
|
if (!m_SSLIndexInitialized) {
|
||||||
|
m_SSLIndex = SSL_get_ex_new_index(0, (void *)"TLSClient", NULL, NULL, NULL);
|
||||||
|
m_SSLIndexInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_set_ex_data(m_SSL.get(), m_SSLIndex, this);
|
||||||
|
|
||||||
|
SSL_set_verify(m_SSL.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||||
|
&TLSClient::SSLVerifyCertificate);
|
||||||
|
|
||||||
BIO *bio = BIO_new_socket(GetFD(), 0);
|
BIO *bio = BIO_new_socket(GetFD(), 0);
|
||||||
SSL_set_bio(m_SSL.get(), bio, bio);
|
SSL_set_bio(m_SSL.get(), bio, bio);
|
||||||
|
|
||||||
|
@ -53,7 +69,7 @@ int TLSClient::ReadableEventHandler(const EventArgs& ea)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
/* TODO: deal with error */
|
HandleSSLError();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +100,7 @@ int TLSClient::WritableEventHandler(const EventArgs& ea)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
/* TODO: deal with error */
|
HandleSSLError();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +129,39 @@ void TLSClient::CloseInternal(bool from_dtor)
|
||||||
TCPClient::CloseInternal(from_dtor);
|
TCPClient::CloseInternal(from_dtor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TLSClient::HandleSSLError(void)
|
||||||
|
{
|
||||||
|
int code = ERR_get_error();
|
||||||
|
|
||||||
|
if (code != 0) {
|
||||||
|
SocketErrorEventArgs sea;
|
||||||
|
sea.Code = code;
|
||||||
|
sea.Message = OpenSSLException::FormatErrorCode(sea.Code);
|
||||||
|
OnError(sea);
|
||||||
|
}
|
||||||
|
|
||||||
|
Close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TCPClient::Ptr icinga::TLSClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
|
TCPClient::Ptr icinga::TLSClientFactory(TCPClientRole role, shared_ptr<SSL_CTX> sslContext)
|
||||||
{
|
{
|
||||||
return make_shared<TLSClient>(role, sslContext);
|
return make_shared<TLSClient>(role, sslContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TLSClient::SSLVerifyCertificate(int ok, X509_STORE_CTX *x509Context)
|
||||||
|
{
|
||||||
|
SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(x509Context, SSL_get_ex_data_X509_STORE_CTX_idx());
|
||||||
|
TLSClient *client = (TLSClient *)SSL_get_ex_data(ssl, m_SSLIndex);
|
||||||
|
|
||||||
|
if (client == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
VerifyCertificateEventArgs vcea;
|
||||||
|
vcea.Source = client->shared_from_this();
|
||||||
|
vcea.ValidCertificate = (ok != 0);
|
||||||
|
vcea.Context = x509Context;
|
||||||
|
client->OnVerifyCertificate(vcea);
|
||||||
|
|
||||||
|
return (int)vcea.ValidCertificate;
|
||||||
|
}
|
||||||
|
|
|
@ -16,16 +16,24 @@ private:
|
||||||
shared_ptr<SSL_CTX> m_SSLContext;
|
shared_ptr<SSL_CTX> m_SSLContext;
|
||||||
shared_ptr<SSL> m_SSL;
|
shared_ptr<SSL> m_SSL;
|
||||||
|
|
||||||
|
static int m_SSLIndex;
|
||||||
|
static bool m_SSLIndexInitialized;
|
||||||
|
|
||||||
virtual int ReadableEventHandler(const EventArgs& ea);
|
virtual int ReadableEventHandler(const EventArgs& ea);
|
||||||
virtual int WritableEventHandler(const EventArgs& ea);
|
virtual int WritableEventHandler(const EventArgs& ea);
|
||||||
|
|
||||||
virtual void CloseInternal(bool from_dtor);
|
virtual void CloseInternal(bool from_dtor);
|
||||||
|
|
||||||
|
static int SSLVerifyCertificate(int ok, X509_STORE_CTX *x509Context);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void HandleSSLError(void);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
|
TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
|
||||||
|
|
||||||
shared_ptr<X509> GetClientCertificate(void) const;
|
X509 *GetClientCertificate(void) const;
|
||||||
shared_ptr<X509> GetPeerCertificate(void) const;
|
X509 *GetPeerCertificate(void) const;
|
||||||
|
|
||||||
virtual void Start(void);
|
virtual void Start(void);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue