1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
// --------------------------------------------------------------------------
//
// File
// Name: TLSContext.h
// Purpose: TLS (SSL) context for connections
// Created: 2003/08/06
//
// --------------------------------------------------------------------------
#include "Box.h"
#define TLS_CLASS_IMPLEMENTATION_CPP
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "autogen_ConnectionException.h"
#include "autogen_ServerException.h"
#include "BoxPortsAndFiles.h"
#include "CryptoUtils.h"
#include "SSLLib.h"
#include "TLSContext.h"
#include "MemLeakFindOn.h"
#define MAX_VERIFICATION_DEPTH 2
#define CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
// Macros to allow compatibility with OpenSSL 1.0 and 1.1 APIs. See
// https://github.com/charybdis-ircd/charybdis/blob/release/3.5/libratbox/src/openssl_ratbox.h
// for the gory details.
#if defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER >= 0x10100000L) // OpenSSL >= 1.1
# define BOX_TLS_SERVER_METHOD TLS_server_method
# define BOX_TLS_CLIENT_METHOD TLS_client_method
#else // OpenSSL < 1.1
# define BOX_TLS_SERVER_METHOD TLSv1_server_method
# define BOX_TLS_CLIENT_METHOD TLSv1_client_method
#endif
// --------------------------------------------------------------------------
//
// Function
// Name: TLSContext::TLSContext()
// Purpose: Constructor
// Created: 2003/08/06
//
// --------------------------------------------------------------------------
TLSContext::TLSContext()
: mpContext(0)
{
}
// --------------------------------------------------------------------------
//
// Function
// Name: TLSContext::~TLSContext()
// Purpose: Destructor
// Created: 2003/08/06
//
// --------------------------------------------------------------------------
TLSContext::~TLSContext()
{
if(mpContext != 0)
{
::SSL_CTX_free(mpContext);
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: TLSContext::Initialise(bool, const char *, const char *, const char *)
// Purpose: Initialise the context, loading in the specified certificate and private key files
// Created: 2003/08/06
//
// --------------------------------------------------------------------------
void TLSContext::Initialise(bool AsServer, const char *CertificatesFile, const char *PrivateKeyFile,
const char *TrustedCAsFile, int SSLSecurityLevel)
{
if(mpContext != 0)
{
::SSL_CTX_free(mpContext);
}
mpContext = ::SSL_CTX_new(AsServer ? BOX_TLS_SERVER_METHOD() : BOX_TLS_CLIENT_METHOD());
if(mpContext == NULL)
{
THROW_EXCEPTION(ServerException, TLSAllocationFailed)
}
#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
if(SSLSecurityLevel == -1)
{
BOX_WARNING("SSLSecurityLevel not set. Your connection may not be secure. "
"Please see https://github.com/boxbackup/boxbackup/wiki/WeakSSLCertificates "
"for details");
SSLSecurityLevel = 1; // Default for now. Unsafe, but we warned the user.
// TODO: upgrade to level 2 soon.
}
SSL_CTX_set_security_level(mpContext, SSLSecurityLevel);
#else
if(SSLSecurityLevel != BOX_DEFAULT_SSL_SECURITY_LEVEL)
{
BOX_WARNING("SSLSecurityLevel is set, but this Box Backup is not compiled with "
"OpenSSL 1.1 or higher, so will be ignored (compiled with "
OPENSSL_VERSION_TEXT ")");
}
#endif
// Setup our identity
if(::SSL_CTX_use_certificate_chain_file(mpContext, CertificatesFile) != 1)
{
#if HAVE_DECL_SSL_R_EE_KEY_TOO_SMALL
int err_reason = ERR_GET_REASON(ERR_peek_error());
if(err_reason == SSL_R_EE_KEY_TOO_SMALL)
{
THROW_EXCEPTION_MESSAGE(ServerException, TLSServerWeakCertificate,
"Failed to load certificates from " << CertificatesFile << ": "
"key too short for current security level");
}
else if(err_reason == SSL_R_CA_MD_TOO_WEAK)
{
THROW_EXCEPTION_MESSAGE(ServerException, TLSServerWeakCertificate,
"Failed to load certificates from " << CertificatesFile << ": "
"hash too weak for current security level");
}
else
#endif // HAVE_DECL_SSL_R_EE_KEY_TOO_SMALL
{
THROW_EXCEPTION_MESSAGE(ServerException, TLSLoadCertificatesFailed,
"Failed to load certificates from " << CertificatesFile << ": " <<
CryptoUtils::LogError("loading certificates"));
}
}
if(::SSL_CTX_use_PrivateKey_file(mpContext, PrivateKeyFile, SSL_FILETYPE_PEM) != 1)
{
THROW_EXCEPTION_MESSAGE(ServerException, TLSLoadPrivateKeyFailed,
"Failed to load private key from " << PrivateKeyFile << ": " <<
CryptoUtils::LogError("loading private key"));
}
// Setup the identify of CAs we trust
if(::SSL_CTX_load_verify_locations(mpContext, TrustedCAsFile, NULL) != 1)
{
THROW_EXCEPTION_MESSAGE(ServerException, TLSLoadTrustedCAsFailed,
"Failed to load CA certificate from " << TrustedCAsFile << ": " <<
CryptoUtils::LogError("loading CA cert"));
}
// Setup options to require these certificates
::SSL_CTX_set_verify(mpContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
// and a sensible maximum depth
::SSL_CTX_set_verify_depth(mpContext, MAX_VERIFICATION_DEPTH);
// Setup allowed ciphers
if(::SSL_CTX_set_cipher_list(mpContext, CIPHER_LIST) != 1)
{
THROW_EXCEPTION_MESSAGE(ServerException, TLSSetCiphersFailed,
"Failed to set cipher list to " << CIPHER_LIST << ": " <<
CryptoUtils::LogError("setting cipher list"));
}
}
// --------------------------------------------------------------------------
//
// Function
// Name: TLSContext::GetRawContext()
// Purpose: Get the raw context for OpenSSL API
// Created: 2003/08/06
//
// --------------------------------------------------------------------------
SSL_CTX *TLSContext::GetRawContext() const
{
if(mpContext == 0)
{
THROW_EXCEPTION(ServerException, TLSContextNotInitialised)
}
return mpContext;
}
|