]> git.ipfire.org Git - thirdparty/squid.git/blob - src/security/ServerOptions.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / security / ServerOptions.cc
1 /*
2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #include "squid.h"
10 #include "base/Packable.h"
11 #include "globals.h"
12 #include "security/ServerOptions.h"
13 #if USE_OPENSSL
14 #include "ssl/support.h"
15 #endif
16
17 #if HAVE_OPENSSL_ERR_H
18 #include <openssl/err.h>
19 #endif
20 #if HAVE_OPENSSL_X509_H
21 #include <openssl/x509.h>
22 #endif
23
24 void
25 Security::ServerOptions::parse(const char *token)
26 {
27 if (!*token) {
28 // config says just "ssl" or "tls" (or "tls-")
29 encryptTransport = true;
30 return;
31 }
32
33 // parse the server-only options
34 if (strncmp(token, "dh=", 3) == 0) {
35 // clear any previous Diffi-Helman configuration
36 dh.clear();
37 dhParamsFile.clear();
38 eecdhCurve.clear();
39
40 dh.append(token + 3);
41
42 if (!dh.isEmpty()) {
43 auto pos = dh.find(':');
44 if (pos != SBuf::npos) { // tls-dh=eecdhCurve:dhParamsFile
45 eecdhCurve = dh.substr(0,pos);
46 dhParamsFile = dh.substr(pos+1);
47 } else { // tls-dh=dhParamsFile
48 dhParamsFile = dh;
49 // empty eecdhCurve means "do not use EECDH"
50 }
51 }
52
53 loadDhParams();
54
55 } else if (strncmp(token, "dhparams=", 9) == 0) {
56 if (!eecdhCurve.isEmpty()) {
57 debugs(83, DBG_PARSE_NOTE(1), "UPGRADE WARNING: EECDH settings in tls-dh= override dhparams=");
58 return;
59 }
60
61 // backward compatibility for dhparams= configuration
62 dh.clear();
63 dh.append(token + 9);
64 dhParamsFile = dh;
65
66 loadDhParams();
67
68 } else {
69 // parse generic TLS options
70 Security::PeerOptions::parse(token);
71 }
72 }
73
74 void
75 Security::ServerOptions::dumpCfg(Packable *p, const char *pfx) const
76 {
77 // dump out the generic TLS options
78 Security::PeerOptions::dumpCfg(p, pfx);
79
80 if (!encryptTransport)
81 return; // no other settings are relevant
82
83 // dump the server-only options
84 if (!dh.isEmpty())
85 p->appendf(" %sdh=" SQUIDSBUFPH, pfx, SQUIDSBUFPRINT(dh));
86 }
87
88 Security::ContextPointer
89 Security::ServerOptions::createBlankContext() const
90 {
91 Security::ContextPointer ctx;
92 #if USE_OPENSSL
93 Ssl::Initialize();
94
95 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
96 SSL_CTX *t = SSL_CTX_new(TLS_server_method());
97 #else
98 SSL_CTX *t = SSL_CTX_new(SSLv23_server_method());
99 #endif
100 if (!t) {
101 const auto x = ERR_get_error();
102 debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << Security::ErrorString(x));
103 }
104 ctx.resetWithoutLocking(t);
105
106 #elif USE_GNUTLS
107 // Initialize for X.509 certificate exchange
108 gnutls_certificate_credentials_t t;
109 if (const int x = gnutls_certificate_allocate_credentials(&t)) {
110 debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << Security::ErrorString(x));
111 }
112 ctx.resetWithoutLocking(t);
113
114 #else
115 debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: No TLS library");
116
117 #endif
118
119 return ctx;
120 }
121
122 bool
123 Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &port)
124 {
125 updateTlsVersionLimits();
126
127 Security::ContextPointer t(createBlankContext());
128 if (t) {
129 #if USE_OPENSSL
130 if (!Ssl::InitServerContext(t, port))
131 return false;
132 #endif
133 }
134
135 staticContext = std::move(t);
136 return bool(staticContext);
137 }
138
139 void
140 Security::ServerOptions::loadDhParams()
141 {
142 if (dhParamsFile.isEmpty())
143 return;
144
145 #if USE_OPENSSL
146 DH *dhp = nullptr;
147 if (FILE *in = fopen(dhParamsFile.c_str(), "r")) {
148 dhp = PEM_read_DHparams(in, NULL, NULL, NULL);
149 fclose(in);
150 }
151
152 if (!dhp) {
153 debugs(83, DBG_IMPORTANT, "WARNING: Failed to read DH parameters '" << dhParamsFile << "'");
154 return;
155 }
156
157 int codes;
158 if (DH_check(dhp, &codes) == 0) {
159 if (codes) {
160 debugs(83, DBG_IMPORTANT, "WARNING: Failed to verify DH parameters '" << dhParamsFile << "' (" << std::hex << codes << ")");
161 DH_free(dhp);
162 dhp = nullptr;
163 }
164 }
165
166 parsedDhParams.resetWithoutLocking(dhp);
167 #endif
168 }
169
170 void
171 Security::ServerOptions::updateContextEecdh(Security::ContextPointer &ctx)
172 {
173 // set Elliptic Curve details into the server context
174 if (!eecdhCurve.isEmpty()) {
175 debugs(83, 9, "Setting Ephemeral ECDH curve to " << eecdhCurve << ".");
176
177 #if USE_OPENSSL && OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_ECDH)
178 int nid = OBJ_sn2nid(eecdhCurve.c_str());
179 if (!nid) {
180 debugs(83, DBG_CRITICAL, "ERROR: Unknown EECDH curve '" << eecdhCurve << "'");
181 return;
182 }
183
184 auto ecdh = EC_KEY_new_by_curve_name(nid);
185 if (!ecdh) {
186 const auto x = ERR_get_error();
187 debugs(83, DBG_CRITICAL, "ERROR: Unable to configure Ephemeral ECDH: " << Security::ErrorString(x));
188 return;
189 }
190
191 if (!SSL_CTX_set_tmp_ecdh(ctx.get(), ecdh)) {
192 const auto x = ERR_get_error();
193 debugs(83, DBG_CRITICAL, "ERROR: Unable to set Ephemeral ECDH: " << Security::ErrorString(x));
194 }
195 EC_KEY_free(ecdh);
196
197 #else
198 debugs(83, DBG_CRITICAL, "ERROR: EECDH is not available in this build." <<
199 " Please link against OpenSSL>=0.9.8 and ensure OPENSSL_NO_ECDH is not set.");
200 #endif
201 }
202
203 // set DH parameters into the server context
204 #if USE_OPENSSL
205 if (parsedDhParams) {
206 SSL_CTX_set_tmp_dh(ctx.get(), parsedDhParams.get());
207 }
208 #endif
209 }
210