]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/helper.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ssl / helper.cc
CommitLineData
bbc27441 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
bbc27441
AJ
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"
24438ec5 10#include "../helper.h"
502bcc7b 11#include "anyp/PortCfg.h"
b3f7fd88 12#include "fs_io.h"
24438ec5 13#include "helper/Reply.h"
602d9612 14#include "SquidConfig.h"
f9b6ff6e 15#include "SquidString.h"
95d2589c 16#include "SquidTime.h"
14798e73 17#include "ssl/cert_validate_message.h"
602d9612
A
18#include "ssl/Config.h"
19#include "ssl/helper.h"
fc54b8d2 20#include "wordlist.h"
95d2589c 21
0e208dad 22Ssl::CertValidationHelper::LruCache *Ssl::CertValidationHelper::HelperCache = nullptr;
14798e73 23
4a77bb4e 24#if USE_SSL_CRTD
95d2589c
CT
25Ssl::Helper * Ssl::Helper::GetInstance()
26{
27 static Ssl::Helper sslHelper;
28 return &sslHelper;
29}
30
fad2588a 31Ssl::Helper::Helper() : ssl_crtd(NULL)
95d2589c 32{
95d2589c
CT
33}
34
35Ssl::Helper::~Helper()
36{
37 Shutdown();
38}
39
40void Ssl::Helper::Init()
41{
586089cd
CT
42 assert(ssl_crtd == NULL);
43
f0763147
AJ
44 // we need to start ssl_crtd only if some port(s) need to bump SSL *and* generate certificates
45 // TODO: generate host certificates for SNI enabled accel ports
24e6c8f1 46 bool found = false;
fa720bfb 47 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != NULL; s = s->next)
f0763147 48 found = s->flags.tunnelSslBumping && s->generateHostCertificates;
24e6c8f1 49 if (!found)
586089cd
CT
50 return;
51
051da40c 52 ssl_crtd = new helper(Ssl::TheConfig.ssl_crtd);
1af735c7 53 ssl_crtd->childs.updateLimits(Ssl::TheConfig.ssl_crtdChildren);
95d2589c 54 ssl_crtd->ipc_type = IPC_STREAM;
0af9303a
CT
55 // The crtd messages may contain the eol ('\n') character. We are
56 // going to use the '\1' char as the end-of-message mark.
57 ssl_crtd->eom = '\1';
95d2589c
CT
58 assert(ssl_crtd->cmdline == NULL);
59 {
60 char *tmp = xstrdup(Ssl::TheConfig.ssl_crtd);
61 char *tmp_begin = tmp;
ba5d55c1 62 char *token = NULL;
95d2589c
CT
63 while ((token = strwordtok(NULL, &tmp))) {
64 wordlistAdd(&ssl_crtd->cmdline, token);
95d2589c
CT
65 }
66 safe_free(tmp_begin);
67 }
95d2589c
CT
68 helperOpenServers(ssl_crtd);
69}
70
71void Ssl::Helper::Shutdown()
72{
73 if (!ssl_crtd)
74 return;
75 helperShutdown(ssl_crtd);
76 wordlistDestroy(&ssl_crtd->cmdline);
95d2589c
CT
77 delete ssl_crtd;
78 ssl_crtd = NULL;
79}
80
81void Ssl::Helper::sslSubmit(CrtdMessage const & message, HLPCB * callback, void * data)
82{
586089cd 83 assert(ssl_crtd);
95d2589c 84
6825b101
CT
85 std::string msg = message.compose();
86 msg += '\n';
87 if (!ssl_crtd->trySubmit(msg.c_str(), callback, data)) {
ddc77a2e 88 ::Helper::Reply failReply(::Helper::BrokenHelper);
fd7f26ea 89 failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
12f7e09b 90 callback(data, failReply);
95d2589c
CT
91 return;
92 }
95d2589c 93}
4a77bb4e 94#endif //USE_SSL_CRTD
2cef0ca6 95
2cef0ca6
AR
96Ssl::CertValidationHelper * Ssl::CertValidationHelper::GetInstance()
97{
98 static Ssl::CertValidationHelper sslHelper;
99 if (!Ssl::TheConfig.ssl_crt_validator)
100 return NULL;
101 return &sslHelper;
102}
103
104Ssl::CertValidationHelper::CertValidationHelper() : ssl_crt_validator(NULL)
105{
106}
107
108Ssl::CertValidationHelper::~CertValidationHelper()
109{
110 Shutdown();
111}
112
113void Ssl::CertValidationHelper::Init()
114{
115 assert(ssl_crt_validator == NULL);
116
117 // we need to start ssl_crtd only if some port(s) need to bump SSL
118 bool found = false;
fa720bfb 119 for (AnyP::PortCfgPointer s = HttpPortList; !found && s != NULL; s = s->next)
6a25a046 120 found = s->flags.tunnelSslBumping;
2cef0ca6
AR
121 if (!found)
122 return;
123
124 ssl_crt_validator = new helper("ssl_crt_validator");
125 ssl_crt_validator->childs.updateLimits(Ssl::TheConfig.ssl_crt_validator_Children);
126 ssl_crt_validator->ipc_type = IPC_STREAM;
127 // The crtd messages may contain the eol ('\n') character. We are
128 // going to use the '\1' char as the end-of-message mark.
129 ssl_crt_validator->eom = '\1';
130 assert(ssl_crt_validator->cmdline == NULL);
14798e73
CT
131
132 int ttl = 60;
133 size_t cache = 2048;
2cef0ca6
AR
134 {
135 char *tmp = xstrdup(Ssl::TheConfig.ssl_crt_validator);
136 char *tmp_begin = tmp;
137 char * token = NULL;
14798e73 138 bool parseParams = true;
2cef0ca6 139 while ((token = strwordtok(NULL, &tmp))) {
14798e73
CT
140 if (parseParams) {
141 if (strncmp(token, "ttl=", 4) == 0) {
142 ttl = atoi(token + 4);
143 continue;
144 } else if (strncmp(token, "cache=", 6) == 0) {
145 cache = atoi(token + 6);
146 continue;
147 } else
148 parseParams = false;
149 }
2cef0ca6
AR
150 wordlistAdd(&ssl_crt_validator->cmdline, token);
151 }
4a77bb4e 152 xfree(tmp_begin);
2cef0ca6
AR
153 }
154 helperOpenServers(ssl_crt_validator);
14798e73
CT
155
156 //WARNING: initializing static member in an object initialization method
157 assert(HelperCache == NULL);
0e208dad 158 HelperCache = new Ssl::CertValidationHelper::LruCache(ttl, cache);
2cef0ca6
AR
159}
160
161void Ssl::CertValidationHelper::Shutdown()
162{
163 if (!ssl_crt_validator)
164 return;
165 helperShutdown(ssl_crt_validator);
166 wordlistDestroy(&ssl_crt_validator->cmdline);
167 delete ssl_crt_validator;
168 ssl_crt_validator = NULL;
4c304fb9 169
14798e73 170 // CertValidationHelper::HelperCache is a static member, it is not good policy to
4c304fb9 171 // reset it here. Will work because the current Ssl::CertValidationHelper is
14798e73
CT
172 // always the same static object.
173 delete HelperCache;
174 HelperCache = NULL;
175}
176
5c2f68b7
AJ
177class submitData
178{
179 CBDATA_CLASS(submitData);
180
181public:
14798e73 182 std::string query;
0e208dad 183 AsyncCall::Pointer callback;
e601ca5d 184 Security::SessionPointer ssl;
14798e73
CT
185};
186CBDATA_CLASS_INIT(submitData);
187
188static void
24438ec5 189sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
14798e73
CT
190{
191 Ssl::CertValidationMsg replyMsg(Ssl::CrtdMessage::REPLY);
0e208dad 192 Ssl::CertValidationResponse::Pointer validationResponse = new Ssl::CertValidationResponse;
14798e73
CT
193 std::string error;
194
195 submitData *crtdvdData = static_cast<submitData *>(data);
e601ca5d 196 STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(crtdvdData->ssl.get());
2428ce02 197 if (reply.result == ::Helper::BrokenHelper) {
14798e73 198 debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content());
2428ce02 199 validationResponse->resultCode = ::Helper::BrokenHelper;
ddc77a2e
CT
200 } else if (!reply.other().hasContent()) {
201 debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper returned NULL response");
202 validationResponse->resultCode = ::Helper::BrokenHelper;
14798e73 203 } else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
4c304fb9 204 !replyMsg.parseResponse(*validationResponse, peerCerts, error) ) {
14798e73
CT
205 debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
206 debugs(83, DBG_IMPORTANT, "Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
2428ce02 207 validationResponse->resultCode = ::Helper::BrokenHelper;
4c304fb9 208 } else
14798e73
CT
209 validationResponse->resultCode = reply.result;
210
0e208dad
CT
211 Ssl::CertValidationHelper::CbDialer *dialer = dynamic_cast<Ssl::CertValidationHelper::CbDialer*>(crtdvdData->callback->getDialer());
212 Must(dialer);
213 dialer->arg1 = validationResponse;
214 ScheduleCallHere(crtdvdData->callback);
14798e73
CT
215
216 if (Ssl::CertValidationHelper::HelperCache &&
2428ce02 217 (validationResponse->resultCode == ::Helper::Okay || validationResponse->resultCode == ::Helper::Error)) {
0e208dad 218 Ssl::CertValidationResponse::Pointer *item = new Ssl::CertValidationResponse::Pointer(validationResponse);
f235c94b
CT
219 if (!Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query.c_str(), item))
220 delete item;
0e208dad 221 }
14798e73 222
14798e73 223 delete crtdvdData;
2cef0ca6
AR
224}
225
0e208dad 226void Ssl::CertValidationHelper::sslSubmit(Ssl::CertValidationRequest const &request, AsyncCall::Pointer &callback)
2cef0ca6 227{
2cef0ca6
AR
228 assert(ssl_crt_validator);
229
14798e73
CT
230 Ssl::CertValidationMsg message(Ssl::CrtdMessage::REQUEST);
231 message.setCode(Ssl::CertValidationMsg::code_cert_validate);
232 message.composeRequest(request);
233 debugs(83, 5, "SSL crtvd request: " << message.compose().c_str());
234
235 submitData *crtdvdData = new submitData;
236 crtdvdData->query = message.compose();
237 crtdvdData->query += '\n';
238 crtdvdData->callback = callback;
e601ca5d 239 crtdvdData->ssl.resetAndLock(request.ssl);
0e208dad 240 Ssl::CertValidationResponse::Pointer const*validationResponse;
14798e73
CT
241
242 if (CertValidationHelper::HelperCache &&
4c304fb9 243 (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query.c_str()))) {
0e208dad
CT
244
245 CertValidationHelper::CbDialer *dialer = dynamic_cast<CertValidationHelper::CbDialer*>(callback->getDialer());
bac324a9 246 Must(dialer);
0e208dad
CT
247 dialer->arg1 = *validationResponse;
248 ScheduleCallHere(callback);
14798e73
CT
249 delete crtdvdData;
250 return;
251 }
6825b101
CT
252
253 if (!ssl_crt_validator->trySubmit(crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData)) {
0e208dad
CT
254 Ssl::CertValidationResponse::Pointer resp = new Ssl::CertValidationResponse;;
255 resp->resultCode = ::Helper::BrokenHelper;
256 Ssl::CertValidationHelper::CbDialer *dialer = dynamic_cast<Ssl::CertValidationHelper::CbDialer*>(callback->getDialer());
bac324a9 257 Must(dialer);
0e208dad
CT
258 dialer->arg1 = resp;
259 ScheduleCallHere(callback);
6825b101
CT
260 delete crtdvdData;
261 return;
262 }
2cef0ca6 263}
f53969cc 264