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