]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/helper.cc
Cleanup: drop helper::flags.busy
[thirdparty/squid.git] / src / ssl / helper.cc
CommitLineData
bbc27441
AJ
1/*
2 * Copyright (C) 1996-2014 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
f7f3304a 9#include "squid.h"
18f37f42 10#include "anyp/PortCfg.h"
602d9612 11#include "SquidConfig.h"
f9b6ff6e 12#include "SquidString.h"
95d2589c 13#include "SquidTime.h"
14798e73 14#include "ssl/cert_validate_message.h"
602d9612
A
15#include "ssl/Config.h"
16#include "ssl/helper.h"
17#include "SwapDir.h"
fc54b8d2 18#include "wordlist.h"
95d2589c 19
14798e73
CT
20LruMap<Ssl::CertValidationResponse> *Ssl::CertValidationHelper::HelperCache = NULL;
21
4a77bb4e 22#if USE_SSL_CRTD
95d2589c
CT
23Ssl::Helper * Ssl::Helper::GetInstance()
24{
25 static Ssl::Helper sslHelper;
26 return &sslHelper;
27}
28
fad2588a 29Ssl::Helper::Helper() : ssl_crtd(NULL)
95d2589c 30{
95d2589c
CT
31}
32
33Ssl::Helper::~Helper()
34{
35 Shutdown();
36}
37
38void Ssl::Helper::Init()
39{
586089cd
CT
40 assert(ssl_crtd == NULL);
41
24e6c8f1
AR
42 // we need to start ssl_crtd only if some port(s) need to bump SSL
43 bool found = false;
fa720bfb 44 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != NULL; s = s->next)
6a25a046 45 found = s->flags.tunnelSslBumping;
fa720bfb 46 for (AnyP::PortCfgPointer s = HttpsPortList; !found && s != NULL; s = s->next)
6a25a046 47 found = s->flags.tunnelSslBumping;
24e6c8f1 48 if (!found)
586089cd
CT
49 return;
50
51 ssl_crtd = new helper("ssl_crtd");
1af735c7 52 ssl_crtd->childs.updateLimits(Ssl::TheConfig.ssl_crtdChildren);
95d2589c 53 ssl_crtd->ipc_type = IPC_STREAM;
0af9303a
CT
54 // The crtd messages may contain the eol ('\n') character. We are
55 // going to use the '\1' char as the end-of-message mark.
56 ssl_crtd->eom = '\1';
95d2589c
CT
57 assert(ssl_crtd->cmdline == NULL);
58 {
59 char *tmp = xstrdup(Ssl::TheConfig.ssl_crtd);
60 char *tmp_begin = tmp;
61 char * token = NULL;
62 bool db_path_was_found = false;
63 bool block_size_was_found = false;
64 char buffer[20] = "2048";
65 while ((token = strwordtok(NULL, &tmp))) {
66 wordlistAdd(&ssl_crtd->cmdline, token);
67 if (!strcmp(token, "-b"))
68 block_size_was_found = true;
69 if (!strcmp(token, "-s")) {
70 db_path_was_found = true;
71 } else if (db_path_was_found) {
72 db_path_was_found = false;
73 int fs_block_size = 0;
74 storeDirGetBlkSize(token, &fs_block_size);
75 snprintf(buffer, sizeof(buffer), "%i", fs_block_size);
76 }
77 }
78 if (!block_size_was_found) {
79 wordlistAdd(&ssl_crtd->cmdline, "-b");
80 wordlistAdd(&ssl_crtd->cmdline, buffer);
81 }
82 safe_free(tmp_begin);
83 }
95d2589c
CT
84 helperOpenServers(ssl_crtd);
85}
86
87void Ssl::Helper::Shutdown()
88{
89 if (!ssl_crtd)
90 return;
91 helperShutdown(ssl_crtd);
92 wordlistDestroy(&ssl_crtd->cmdline);
95d2589c
CT
93 delete ssl_crtd;
94 ssl_crtd = NULL;
95}
96
97void Ssl::Helper::sslSubmit(CrtdMessage const & message, HLPCB * callback, void * data)
98{
99 static time_t first_warn = 0;
586089cd 100 assert(ssl_crtd);
95d2589c
CT
101
102 if (ssl_crtd->stats.queue_size >= (int)(ssl_crtd->childs.n_running * 2)) {
103 if (first_warn == 0)
104 first_warn = squid_curtime;
105 if (squid_curtime - first_warn > 3 * 60)
106 fatal("SSL servers not responding for 3 minutes");
e0236918 107 debugs(34, DBG_IMPORTANT, HERE << "Queue overload, rejecting");
3c2c35d3
AJ
108 HelperReply failReply;
109 failReply.result = HelperReply::BrokenHelper;
fd7f26ea 110 failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
12f7e09b 111 callback(data, failReply);
95d2589c
CT
112 return;
113 }
114
115 first_warn = 0;
0af9303a
CT
116 std::string msg = message.compose();
117 msg += '\n';
118 helperSubmit(ssl_crtd, msg.c_str(), callback, data);
95d2589c 119}
4a77bb4e 120#endif //USE_SSL_CRTD
2cef0ca6 121
2cef0ca6
AR
122Ssl::CertValidationHelper * Ssl::CertValidationHelper::GetInstance()
123{
124 static Ssl::CertValidationHelper sslHelper;
125 if (!Ssl::TheConfig.ssl_crt_validator)
126 return NULL;
127 return &sslHelper;
128}
129
130Ssl::CertValidationHelper::CertValidationHelper() : ssl_crt_validator(NULL)
131{
132}
133
134Ssl::CertValidationHelper::~CertValidationHelper()
135{
136 Shutdown();
137}
138
139void Ssl::CertValidationHelper::Init()
140{
141 assert(ssl_crt_validator == NULL);
142
143 // we need to start ssl_crtd only if some port(s) need to bump SSL
144 bool found = false;
fa720bfb 145 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != NULL; s = s->next)
6a25a046 146 found = s->flags.tunnelSslBumping;
fa720bfb 147 for (AnyP::PortCfgPointer s = HttpsPortList; !found && s != NULL; s = s->next)
6a25a046 148 found = s->flags.tunnelSslBumping;
2cef0ca6
AR
149 if (!found)
150 return;
151
152 ssl_crt_validator = new helper("ssl_crt_validator");
153 ssl_crt_validator->childs.updateLimits(Ssl::TheConfig.ssl_crt_validator_Children);
154 ssl_crt_validator->ipc_type = IPC_STREAM;
155 // The crtd messages may contain the eol ('\n') character. We are
156 // going to use the '\1' char as the end-of-message mark.
157 ssl_crt_validator->eom = '\1';
158 assert(ssl_crt_validator->cmdline == NULL);
14798e73
CT
159
160 int ttl = 60;
161 size_t cache = 2048;
2cef0ca6
AR
162 {
163 char *tmp = xstrdup(Ssl::TheConfig.ssl_crt_validator);
164 char *tmp_begin = tmp;
165 char * token = NULL;
14798e73 166 bool parseParams = true;
2cef0ca6 167 while ((token = strwordtok(NULL, &tmp))) {
14798e73
CT
168 if (parseParams) {
169 if (strncmp(token, "ttl=", 4) == 0) {
170 ttl = atoi(token + 4);
171 continue;
172 } else if (strncmp(token, "cache=", 6) == 0) {
173 cache = atoi(token + 6);
174 continue;
175 } else
176 parseParams = false;
177 }
2cef0ca6
AR
178 wordlistAdd(&ssl_crt_validator->cmdline, token);
179 }
4a77bb4e 180 xfree(tmp_begin);
2cef0ca6
AR
181 }
182 helperOpenServers(ssl_crt_validator);
14798e73
CT
183
184 //WARNING: initializing static member in an object initialization method
185 assert(HelperCache == NULL);
186 HelperCache = new LruMap<Ssl::CertValidationResponse>(ttl, cache);
2cef0ca6
AR
187}
188
189void Ssl::CertValidationHelper::Shutdown()
190{
191 if (!ssl_crt_validator)
192 return;
193 helperShutdown(ssl_crt_validator);
194 wordlistDestroy(&ssl_crt_validator->cmdline);
195 delete ssl_crt_validator;
196 ssl_crt_validator = NULL;
4c304fb9 197
14798e73 198 // CertValidationHelper::HelperCache is a static member, it is not good policy to
4c304fb9 199 // reset it here. Will work because the current Ssl::CertValidationHelper is
14798e73
CT
200 // always the same static object.
201 delete HelperCache;
202 HelperCache = NULL;
203}
204
205struct submitData {
206 std::string query;
207 Ssl::CertValidationHelper::CVHCB *callback;
208 void *data;
209 SSL *ssl;
210 CBDATA_CLASS2(submitData);
211};
212CBDATA_CLASS_INIT(submitData);
213
214static void
215sslCrtvdHandleReplyWrapper(void *data, const HelperReply &reply)
216{
217 Ssl::CertValidationMsg replyMsg(Ssl::CrtdMessage::REPLY);
218 Ssl::CertValidationResponse *validationResponse = new Ssl::CertValidationResponse;
219 std::string error;
220
221 submitData *crtdvdData = static_cast<submitData *>(data);
222 STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(crtdvdData->ssl);
223 if (reply.result == HelperReply::BrokenHelper) {
224 debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content());
225 validationResponse->resultCode = HelperReply::BrokenHelper;
226 } else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
4c304fb9 227 !replyMsg.parseResponse(*validationResponse, peerCerts, error) ) {
14798e73
CT
228 debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
229 debugs(83, DBG_IMPORTANT, "Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
230 validationResponse->resultCode = HelperReply::BrokenHelper;
4c304fb9 231 } else
14798e73
CT
232 validationResponse->resultCode = reply.result;
233
234 crtdvdData->callback(crtdvdData->data, *validationResponse);
235
236 if (Ssl::CertValidationHelper::HelperCache &&
4c304fb9 237 (validationResponse->resultCode == HelperReply::Okay || validationResponse->resultCode == HelperReply::Error)) {
14798e73
CT
238 Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query.c_str(), validationResponse);
239 } else
240 delete validationResponse;
241
242 cbdataReferenceDone(crtdvdData->data);
243 SSL_free(crtdvdData->ssl);
244 delete crtdvdData;
2cef0ca6
AR
245}
246
14798e73 247void Ssl::CertValidationHelper::sslSubmit(Ssl::CertValidationRequest const &request, Ssl::CertValidationHelper::CVHCB * callback, void * data)
2cef0ca6
AR
248{
249 static time_t first_warn = 0;
250 assert(ssl_crt_validator);
251
252 if (ssl_crt_validator->stats.queue_size >= (int)(ssl_crt_validator->childs.n_running * 2)) {
253 if (first_warn == 0)
254 first_warn = squid_curtime;
255 if (squid_curtime - first_warn > 3 * 60)
4a77bb4e
CT
256 fatal("ssl_crtvd queue being overloaded for long time");
257 debugs(83, DBG_IMPORTANT, "WARNING: ssl_crtvd queue overload, rejecting");
14798e73
CT
258 Ssl::CertValidationResponse resp;
259 resp.resultCode = HelperReply::BrokenHelper;
260 callback(data, resp);
2cef0ca6
AR
261 return;
262 }
2cef0ca6 263 first_warn = 0;
14798e73
CT
264
265 Ssl::CertValidationMsg message(Ssl::CrtdMessage::REQUEST);
266 message.setCode(Ssl::CertValidationMsg::code_cert_validate);
267 message.composeRequest(request);
268 debugs(83, 5, "SSL crtvd request: " << message.compose().c_str());
269
270 submitData *crtdvdData = new submitData;
271 crtdvdData->query = message.compose();
272 crtdvdData->query += '\n';
273 crtdvdData->callback = callback;
274 crtdvdData->data = cbdataReference(data);
275 crtdvdData->ssl = request.ssl;
276 CRYPTO_add(&crtdvdData->ssl->references,1,CRYPTO_LOCK_SSL);
277 Ssl::CertValidationResponse const*validationResponse;
278
279 if (CertValidationHelper::HelperCache &&
4c304fb9 280 (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query.c_str()))) {
14798e73
CT
281 callback(data, *validationResponse);
282 cbdataReferenceDone(crtdvdData->data);
283 SSL_free(crtdvdData->ssl);
284 delete crtdvdData;
285 return;
286 }
287 helperSubmit(ssl_crt_validator, crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData);
2cef0ca6 288}