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)
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);
return 0;
default:
- /* TODO: deal with error */
+ HandleSSLError();
return 0;
}
return 0;
default:
- /* TODO: deal with error */
+ HandleSSLError();
return 0;
}
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;
+}
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);