summaryrefslogtreecommitdiff
path: root/lib/server/TLSContext.cpp
blob: 9c01452bf8280655420aacae0085201d573aa762 (plain)
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;
}