mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
TLSClient: add hostname verifcation
The CN or subjectAltNames of the TLS certification is now matched with the hostname connected to. taskd.trust is now a tristate value (allow all, ignore hostname, strict) to optionally disable the new hostname verification.
This commit is contained in:
parent
fdcc04d13e
commit
7fb1487993
5 changed files with 73 additions and 17 deletions
|
@ -45,6 +45,7 @@
|
||||||
#include <TLSClient.h>
|
#include <TLSClient.h>
|
||||||
#include <text.h>
|
#include <text.h>
|
||||||
#include <i18n.h>
|
#include <i18n.h>
|
||||||
|
#include <gnutls/x509.h>
|
||||||
|
|
||||||
#define MAX_BUF 16384
|
#define MAX_BUF 16384
|
||||||
|
|
||||||
|
@ -68,11 +69,13 @@ TLSClient::TLSClient ()
|
||||||
: _ca ("")
|
: _ca ("")
|
||||||
, _cert ("")
|
, _cert ("")
|
||||||
, _key ("")
|
, _key ("")
|
||||||
|
, _host ("")
|
||||||
|
, _port ("")
|
||||||
, _session(0)
|
, _session(0)
|
||||||
, _socket (0)
|
, _socket (0)
|
||||||
, _limit (0)
|
, _limit (0)
|
||||||
, _debug (false)
|
, _debug (false)
|
||||||
, _trust(false)
|
, _trust(strict)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,13 +112,15 @@ void TLSClient::debug (int level)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void TLSClient::trust (bool value)
|
void TLSClient::trust (const enum trust_level value)
|
||||||
{
|
{
|
||||||
_trust = value;
|
_trust = value;
|
||||||
if (_debug)
|
if (_debug)
|
||||||
{
|
{
|
||||||
if (_trust)
|
if (_trust == allow_all)
|
||||||
std::cout << "c: INFO Server certificate trusted automatically.\n";
|
std::cout << "c: INFO Server certificate trusted automatically.\n";
|
||||||
|
else if (_trust == ignore_hostname)
|
||||||
|
std::cout << "c: INFO Server certificate trust verified but hostname ignored.\n";
|
||||||
else
|
else
|
||||||
std::cout << "c: INFO Server certificate trust verified.\n";
|
std::cout << "c: INFO Server certificate trust verified.\n";
|
||||||
}
|
}
|
||||||
|
@ -179,6 +184,9 @@ void TLSClient::init (
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void TLSClient::connect (const std::string& host, const std::string& port)
|
void TLSClient::connect (const std::string& host, const std::string& port)
|
||||||
{
|
{
|
||||||
|
_host = host;
|
||||||
|
_port = port;
|
||||||
|
|
||||||
// Store the TLSClient instance, so that the verification callback can access
|
// Store the TLSClient instance, so that the verification callback can access
|
||||||
// it during the handshake below and call the verifcation method.
|
// it during the handshake below and call the verifcation method.
|
||||||
gnutls_session_set_ptr (_session, (void*) this);
|
gnutls_session_set_ptr (_session, (void*) this);
|
||||||
|
@ -273,19 +281,55 @@ void TLSClient::bye ()
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int TLSClient::verify_certificate () const
|
int TLSClient::verify_certificate () const
|
||||||
{
|
{
|
||||||
if (_trust)
|
if (_trust == TLSClient::allow_all)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// This verification function uses the trusted CAs in the credentials
|
// This verification function uses the trusted CAs in the credentials
|
||||||
// structure. So you must have installed one or more CA certificates.
|
// structure. So you must have installed one or more CA certificates.
|
||||||
unsigned int status = 0;
|
unsigned int status = 0;
|
||||||
|
|
||||||
|
const char* hostname = _host.c_str();
|
||||||
#if GNUTLS_VERSION_NUMBER >= 0x030104
|
#if GNUTLS_VERSION_NUMBER >= 0x030104
|
||||||
int ret = gnutls_certificate_verify_peers3 (_session, NULL, &status);
|
if (_trust == TLSClient::ignore_hostname)
|
||||||
#else
|
hostname = NULL;
|
||||||
int ret = gnutls_certificate_verify_peers2 (_session, &status);
|
|
||||||
#endif
|
int ret = gnutls_certificate_verify_peers3 (_session, hostname, &status);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
#else
|
||||||
|
int ret = gnutls_certificate_verify_peers2 (_session, &status);
|
||||||
|
if (ret < 0)
|
||||||
|
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
|
||||||
|
if ((status == 0) && (_trust != TLSClient::ignore_hostname))
|
||||||
|
{
|
||||||
|
if (gnutls_certificate_type_get (_session) == GNUTLS_CRT_X509)
|
||||||
|
{
|
||||||
|
const gnutls_datum* cert_list;
|
||||||
|
unsigned int cert_list_size;
|
||||||
|
gnutls_x509_crt cert;
|
||||||
|
|
||||||
|
cert_list = gnutls_certificate_get_peers (_session, &cert_list_size);
|
||||||
|
if (cert_list_size == 0)
|
||||||
|
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
|
||||||
|
ret = gnutls_x509_crt_init (&cert);
|
||||||
|
if (ret < 0)
|
||||||
|
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
|
||||||
|
ret = gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER);
|
||||||
|
if (ret < 0)
|
||||||
|
gnutls_x509_crt_deinit(cert);
|
||||||
|
status = GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
|
||||||
|
if (gnutls_x509_crt_check_hostname (cert, hostname) == 0)
|
||||||
|
gnutls_x509_crt_deinit(cert);
|
||||||
|
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if GNUTLS_VERSION_NUMBER >= 0x030105
|
#if GNUTLS_VERSION_NUMBER >= 0x030105
|
||||||
gnutls_certificate_type_t type = gnutls_certificate_type_get (_session);
|
gnutls_certificate_type_t type = gnutls_certificate_type_get (_session);
|
||||||
|
|
|
@ -34,11 +34,13 @@
|
||||||
class TLSClient
|
class TLSClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum trust_level { strict, ignore_hostname, allow_all };
|
||||||
|
|
||||||
TLSClient ();
|
TLSClient ();
|
||||||
~TLSClient ();
|
~TLSClient ();
|
||||||
void limit (int);
|
void limit (int);
|
||||||
void debug (int);
|
void debug (int);
|
||||||
void trust (bool);
|
void trust (const enum trust_level);
|
||||||
void ciphers (const std::string&);
|
void ciphers (const std::string&);
|
||||||
void init (const std::string&, const std::string&, const std::string&);
|
void init (const std::string&, const std::string&, const std::string&);
|
||||||
void connect (const std::string&, const std::string&);
|
void connect (const std::string&, const std::string&);
|
||||||
|
@ -53,12 +55,14 @@ private:
|
||||||
std::string _cert;
|
std::string _cert;
|
||||||
std::string _key;
|
std::string _key;
|
||||||
std::string _ciphers;
|
std::string _ciphers;
|
||||||
|
std::string _host;
|
||||||
|
std::string _port;
|
||||||
gnutls_certificate_credentials_t _credentials;
|
gnutls_certificate_credentials_t _credentials;
|
||||||
gnutls_session_t _session;
|
gnutls_session_t _session;
|
||||||
int _socket;
|
int _socket;
|
||||||
int _limit;
|
int _limit;
|
||||||
bool _debug;
|
bool _debug;
|
||||||
bool _trust;
|
enum trust_level _trust;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -232,8 +232,12 @@ int CmdDiagnostics::execute (std::string& output)
|
||||||
? " (readable)" : " (not readable)")
|
? " (readable)" : " (not readable)")
|
||||||
<< "\n";
|
<< "\n";
|
||||||
|
|
||||||
if (context.config.get ("taskd.trust") != "")
|
if (context.config.get ("taskd.trust") == "allow all")
|
||||||
out << " Trust: override\n";
|
out << " Trust: allow all\n";
|
||||||
|
else if (context.config.get ("taskd.trust") == "ignore hostname")
|
||||||
|
out << " Trust: ignore hostanme\n";
|
||||||
|
else
|
||||||
|
out << " Trust: strict\n";
|
||||||
|
|
||||||
out << " Cert: "
|
out << " Cert: "
|
||||||
<< context.config.get ("taskd.certificate")
|
<< context.config.get ("taskd.certificate")
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <Context.h>
|
#include <Context.h>
|
||||||
#include <TLSClient.h>
|
|
||||||
#include <Color.h>
|
#include <Color.h>
|
||||||
#include <text.h>
|
#include <text.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
@ -87,14 +86,18 @@ int CmdSync::execute (std::string& output)
|
||||||
if (credentials.size () != 3)
|
if (credentials.size () != 3)
|
||||||
throw std::string (STRING_CMD_SYNC_BAD_CRED);
|
throw std::string (STRING_CMD_SYNC_BAD_CRED);
|
||||||
|
|
||||||
bool trust = context.config.getBoolean ("taskd.trust");
|
enum TLSClient::trust_level trust = TLSClient::strict;
|
||||||
|
if (context.config.get ("taskd.trust") == "allow all")
|
||||||
|
trust = TLSClient::allow_all;
|
||||||
|
else if (context.config.get ("taskd.trust") == "ignore hostname")
|
||||||
|
trust = TLSClient::ignore_hostname;
|
||||||
|
|
||||||
// CA must exist, if provided.
|
// CA must exist, if provided.
|
||||||
File ca (context.config.get ("taskd.ca"));
|
File ca (context.config.get ("taskd.ca"));
|
||||||
if (ca._data != "" && ! ca.exists ())
|
if (ca._data != "" && ! ca.exists ())
|
||||||
throw std::string (STRING_CMD_SYNC_BAD_CA);
|
throw std::string (STRING_CMD_SYNC_BAD_CA);
|
||||||
|
|
||||||
if (trust && ca._data != "")
|
if (trust == TLSClient::allow_all && ca._data != "")
|
||||||
throw std::string (STRING_CMD_SYNC_TRUST_CA);
|
throw std::string (STRING_CMD_SYNC_TRUST_CA);
|
||||||
|
|
||||||
File certificate (context.config.get ("taskd.certificate"));
|
File certificate (context.config.get ("taskd.certificate"));
|
||||||
|
@ -319,7 +322,7 @@ bool CmdSync::send (
|
||||||
const std::string& ca,
|
const std::string& ca,
|
||||||
const std::string& certificate,
|
const std::string& certificate,
|
||||||
const std::string& key,
|
const std::string& key,
|
||||||
bool trust,
|
const enum TLSClient::trust_level trust,
|
||||||
const Msg& request,
|
const Msg& request,
|
||||||
Msg& response)
|
Msg& response)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <Command.h>
|
#include <Command.h>
|
||||||
#include <Msg.h>
|
#include <Msg.h>
|
||||||
|
#include <TLSClient.h>
|
||||||
|
|
||||||
class CmdSync : public Command
|
class CmdSync : public Command
|
||||||
{
|
{
|
||||||
|
@ -38,7 +39,7 @@ public:
|
||||||
int execute (std::string&);
|
int execute (std::string&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool send (const std::string&, const std::string&, const std::string&, const std::string&, bool, const Msg&, Msg&);
|
bool send (const std::string&, const std::string&, const std::string&, const std::string&, const enum TLSClient::trust_level, const Msg&, Msg&);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue