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);
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
class OpenSSLException : public Exception
|
||||
{
|
||||
public:
|
||||
inline OpenSSLException(const string& message, int errorCode)
|
||||
{
|
||||
SetMessage(message + ": " + FormatErrorCode(errorCode));
|
||||
}
|
||||
|
||||
static string FormatErrorCode(int code);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* EXCEPTION_H */
|
||||
|
|
|
@ -2,19 +2,22 @@
|
|||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -26,6 +29,19 @@ void TLSClient::Start(void)
|
|||
if (!m_SSL)
|
||||
; /* 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);
|
||||
SSL_set_bio(m_SSL.get(), bio, bio);
|
||||
|
||||
|
@ -53,7 +69,7 @@ int TLSClient::ReadableEventHandler(const EventArgs& ea)
|
|||
|
||||
return 0;
|
||||
default:
|
||||
/* TODO: deal with error */
|
||||
HandleSSLError();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -84,7 +100,7 @@ int TLSClient::WritableEventHandler(const EventArgs& ea)
|
|||
|
||||
return 0;
|
||||
default:
|
||||
/* TODO: deal with error */
|
||||
HandleSSLError();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,7 +129,39 @@ void TLSClient::CloseInternal(bool 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)
|
||||
{
|
||||
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> m_SSL;
|
||||
|
||||
static int m_SSLIndex;
|
||||
static bool m_SSLIndexInitialized;
|
||||
|
||||
virtual int ReadableEventHandler(const EventArgs& ea);
|
||||
virtual int WritableEventHandler(const EventArgs& ea);
|
||||
|
||||
virtual void CloseInternal(bool from_dtor);
|
||||
|
||||
static int SSLVerifyCertificate(int ok, X509_STORE_CTX *x509Context);
|
||||
|
||||
protected:
|
||||
void HandleSSLError(void);
|
||||
|
||||
public:
|
||||
TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
|
||||
|
||||
shared_ptr<X509> GetClientCertificate(void) const;
|
||||
shared_ptr<X509> GetPeerCertificate(void) const;
|
||||
X509 *GetClientCertificate(void) const;
|
||||
X509 *GetPeerCertificate(void) const;
|
||||
|
||||
virtual void Start(void);
|
||||
|
||||
|
|
Loading…
Reference in New Issue