helper.cc
Go to the documentation of this file.
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 "../helper.h"
11 #include "anyp/PortCfg.h"
12 #include "fs_io.h"
13 #include "helper/Reply.h"
14 #include "SquidConfig.h"
15 #include "SquidString.h"
16 #include "SquidTime.h"
18 #include "ssl/Config.h"
19 #include "ssl/helper.h"
20 #include "wordlist.h"
21 
22 Ssl::CertValidationHelper::LruCache *Ssl::CertValidationHelper::HelperCache = nullptr;
23 
24 #if USE_SSL_CRTD
25 
26 namespace Ssl {
27 
30 public:
31  GeneratorRequestor(HLPCB *aCallback, void *aData): callback(aCallback), data(aData) {}
34 };
35 
39 
40 public:
42  void emplace(HLPCB *callback, void *data) { requestors.emplace_back(callback, data); }
43 
45 
47  typedef std::vector<GeneratorRequestor> GeneratorRequestors;
49 };
50 
52 typedef std::unordered_map<SBuf, GeneratorRequest*> GeneratorRequests;
53 
54 static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply);
55 
56 } // namespace Ssl
57 
58 CBDATA_NAMESPACED_CLASS_INIT(Ssl, GeneratorRequest);
59 
61 static std::ostream &
62 operator <<(std::ostream &os, const Ssl::GeneratorRequest &gr)
63 {
64  return os << "crtGenRq" << gr.query.id.value << "/" << gr.requestors.size();
65 }
66 
69 
71 {
72  static Ssl::Helper sslHelper;
73  return &sslHelper;
74 }
75 
77 {
78 }
79 
81 {
82  Shutdown();
83 }
84 
86 {
87  assert(ssl_crtd == NULL);
88 
89  // we need to start ssl_crtd only if some port(s) need to bump SSL *and* generate certificates
90  // TODO: generate host certificates for SNI enabled accel ports
91  bool found = false;
92  for (AnyP::PortCfgPointer s = HttpPortList; !found && s != NULL; s = s->next)
93  found = s->flags.tunnelSslBumping && s->secure.generateHostCertificates;
94  if (!found)
95  return;
96 
97  ssl_crtd = new helper(Ssl::TheConfig.ssl_crtd);
98  ssl_crtd->childs.updateLimits(Ssl::TheConfig.ssl_crtdChildren);
99  ssl_crtd->ipc_type = IPC_STREAM;
100  // The crtd messages may contain the eol ('\n') character. We are
101  // going to use the '\1' char as the end-of-message mark.
102  ssl_crtd->eom = '\1';
103  assert(ssl_crtd->cmdline == NULL);
104  {
105  char *tmp = xstrdup(Ssl::TheConfig.ssl_crtd);
106  char *tmp_begin = tmp;
107  char *token = NULL;
108  while ((token = strwordtok(NULL, &tmp))) {
109  wordlistAdd(&ssl_crtd->cmdline, token);
110  }
111  safe_free(tmp_begin);
112  }
113  helperOpenServers(ssl_crtd);
114 }
115 
117 {
118  if (!ssl_crtd)
119  return;
120  helperShutdown(ssl_crtd);
121  wordlistDestroy(&ssl_crtd->cmdline);
122  delete ssl_crtd;
123  ssl_crtd = NULL;
124 }
125 
126 void Ssl::Helper::sslSubmit(CrtdMessage const & message, HLPCB * callback, void * data)
127 {
128  assert(ssl_crtd);
129 
130  SBuf rawMessage(message.compose().c_str()); // XXX: helpers cannot use SBuf
131  rawMessage.append("\n", 1);
132 
133  const auto pending = TheGeneratorRequests.find(rawMessage);
134  if (pending != TheGeneratorRequests.end()) {
135  pending->second->emplace(callback, data);
136  debugs(83, 5, "collapsed request from " << data << " onto " << *pending->second);
137  return;
138  }
139 
141  request->query = rawMessage;
142  request->emplace(callback, data);
143  TheGeneratorRequests.emplace(request->query, request);
144  debugs(83, 5, "request from " << data << " as " << *request);
145  if (ssl_crtd->trySubmit(request->query.c_str(), HandleGeneratorReply, request))
146  return;
147 
149  failReply.notes.add("message", "error 45 Temporary network problem, please retry later");
150  HandleGeneratorReply(request, failReply);
151 }
152 
154 static void
155 Ssl::HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
156 {
157  const std::unique_ptr<Ssl::GeneratorRequest> request(static_cast<Ssl::GeneratorRequest*>(data));
158  assert(request);
159  const auto erased = TheGeneratorRequests.erase(request->query);
160  assert(erased);
161 
162  for (auto &requestor: request->requestors) {
163  if (void *cbdata = requestor.data.validDone()) {
164  debugs(83, 5, "to " << cbdata << " in " << *request);
165  requestor.callback(cbdata, reply);
166  }
167  }
168 }
169 #endif //USE_SSL_CRTD
170 
172 {
173  static Ssl::CertValidationHelper sslHelper;
174  if (!Ssl::TheConfig.ssl_crt_validator)
175  return NULL;
176  return &sslHelper;
177 }
178 
180 {
181 }
182 
184 {
185  Shutdown();
186 }
187 
189 {
190  assert(ssl_crt_validator == NULL);
191 
192  // we need to start ssl_crtd only if some port(s) need to bump SSL
193  bool found = false;
194  for (AnyP::PortCfgPointer s = HttpPortList; !found && s != NULL; s = s->next)
195  found = s->flags.tunnelSslBumping;
196  if (!found)
197  return;
198 
199  ssl_crt_validator = new helper("ssl_crt_validator");
200  ssl_crt_validator->childs.updateLimits(Ssl::TheConfig.ssl_crt_validator_Children);
201  ssl_crt_validator->ipc_type = IPC_STREAM;
202  // The crtd messages may contain the eol ('\n') character. We are
203  // going to use the '\1' char as the end-of-message mark.
204  ssl_crt_validator->eom = '\1';
205  assert(ssl_crt_validator->cmdline == NULL);
206 
207  int ttl = 60;
208  size_t cache = 2048;
209  {
210  char *tmp = xstrdup(Ssl::TheConfig.ssl_crt_validator);
211  char *tmp_begin = tmp;
212  char * token = NULL;
213  bool parseParams = true;
214  while ((token = strwordtok(NULL, &tmp))) {
215  if (parseParams) {
216  if (strncmp(token, "ttl=", 4) == 0) {
217  ttl = atoi(token + 4);
218  continue;
219  } else if (strncmp(token, "cache=", 6) == 0) {
220  cache = atoi(token + 6);
221  continue;
222  } else
223  parseParams = false;
224  }
225  wordlistAdd(&ssl_crt_validator->cmdline, token);
226  }
227  xfree(tmp_begin);
228  }
229  helperOpenServers(ssl_crt_validator);
230 
231  //WARNING: initializing static member in an object initialization method
232  assert(HelperCache == NULL);
233  HelperCache = new Ssl::CertValidationHelper::LruCache(ttl, cache);
234 }
235 
237 {
238  if (!ssl_crt_validator)
239  return;
240  helperShutdown(ssl_crt_validator);
241  wordlistDestroy(&ssl_crt_validator->cmdline);
242  delete ssl_crt_validator;
243  ssl_crt_validator = NULL;
244 
245  // CertValidationHelper::HelperCache is a static member, it is not good policy to
246  // reset it here. Will work because the current Ssl::CertValidationHelper is
247  // always the same static object.
248  delete HelperCache;
249  HelperCache = NULL;
250 }
251 
253 {
255 
256 public:
257  SBuf query;
260 };
262 
263 static void
264 sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
265 {
267  std::string error;
268 
269  submitData *crtdvdData = static_cast<submitData *>(data);
270  assert(crtdvdData->ssl.get());
271  Ssl::CertValidationResponse::Pointer validationResponse = new Ssl::CertValidationResponse(crtdvdData->ssl);
272  if (reply.result == ::Helper::BrokenHelper) {
273  debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content());
274  validationResponse->resultCode = ::Helper::BrokenHelper;
275  } else if (!reply.other().hasContent()) {
276  debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper returned NULL response");
277  validationResponse->resultCode = ::Helper::BrokenHelper;
278  } else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
279  !replyMsg.parseResponse(*validationResponse, error) ) {
280  debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
281  debugs(83, DBG_IMPORTANT, "Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
282  validationResponse->resultCode = ::Helper::BrokenHelper;
283  } else
284  validationResponse->resultCode = reply.result;
285 
287  Must(dialer);
288  dialer->arg1 = validationResponse;
289  ScheduleCallHere(crtdvdData->callback);
290 
291  if (Ssl::CertValidationHelper::HelperCache &&
292  (validationResponse->resultCode == ::Helper::Okay || validationResponse->resultCode == ::Helper::Error)) {
294  if (!Ssl::CertValidationHelper::HelperCache->add(crtdvdData->query, item))
295  delete item;
296  }
297 
298  delete crtdvdData;
299 }
300 
302 {
303  assert(ssl_crt_validator);
304 
307  message.composeRequest(request);
308  debugs(83, 5, "SSL crtvd request: " << message.compose().c_str());
309 
310  submitData *crtdvdData = new submitData;
311  crtdvdData->query.assign(message.compose().c_str());
312  crtdvdData->query.append('\n');
313  crtdvdData->callback = callback;
314  crtdvdData->ssl = request.ssl;
315  Ssl::CertValidationResponse::Pointer const*validationResponse;
316 
318  (validationResponse = CertValidationHelper::HelperCache->get(crtdvdData->query))) {
319 
320  CertValidationHelper::CbDialer *dialer = dynamic_cast<CertValidationHelper::CbDialer*>(callback->getDialer());
321  Must(dialer);
322  dialer->arg1 = *validationResponse;
323  ScheduleCallHere(callback);
324  delete crtdvdData;
325  return;
326  }
327 
328  if (!ssl_crt_validator->trySubmit(crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData)) {
330  resp->resultCode = ::Helper::BrokenHelper;
332  Must(dialer);
333  dialer->arg1 = resp;
334  ScheduleCallHere(callback);
335  delete crtdvdData;
336  return;
337  }
338 }
339 
#define CBDATA_NAMESPACED_CLASS_INIT(namespace, type)
Definition: cbdata.h:326
#define assert(EX)
Definition: assert.h:17
void const char HLPCB * callback
Definition: stub_helper.cc:16
const char * wordlistAdd(wordlist **list, const char *key)
Definition: wordlist.cc:25
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:94
std::string const & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
Definition: cbdata.cc:60
static LruCache * HelperCache
cache for cert validation helper
Definition: helper.h:65
static const std::string code_cert_validate
String code for "cert_validate" messages.
Definition: SBuf.h:87
void composeRequest(CertValidationRequest const &vcert)
static CertValidationHelper * GetInstance()
Instance class.
Definition: helper.cc:171
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
void add(const SBuf &key, const SBuf &value)
Definition: Notes.cc:278
void error(char *format,...)
#define xstrdup
SBuf & append(const SBuf &S)
Definition: SBuf.cc:207
Security::SessionPointer ssl
Definition: helper.cc:259
void Init()
Init helper structure.
Definition: helper.cc:85
Definition: helper.h:60
AsyncCall::Pointer callback
Definition: helper.cc:258
#define safe_free(x)
Definition: xalloc.h:73
void Shutdown()
Definition: helper.cc:116
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
void helperShutdown(helper *hlp)
Definition: helper.cc:616
std::unordered_map< SBuf, GeneratorRequest * > GeneratorRequests
Ssl::Helper query:GeneratorRequest map.
Definition: helper.cc:52
SBuf query
Definition: helper.cc:254
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:21
GeneratorRequestor(HLPCB *aCallback, void *aData)
Definition: helper.cc:31
char * strwordtok(char *buf, char **t)
Definition: String.cc:407
void HLPCB(void *, const Helper::Reply &)
Definition: forward.h:27
void sslSubmit(Ssl::CertValidationRequest const &request, AsyncCall::Pointer &)
Submit crtd request message to external crtd server.
Definition: helper.cc:301
void const char HLPCB void * data
Definition: stub_helper.cc:16
NotePairs notes
Definition: Reply.h:61
virtual CallDialer * getDialer()=0
Security::SessionPointer ssl
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define DBG_IMPORTANT
Definition: Debug.h:45
void sslSubmit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition: helper.cc:126
std::vector< GeneratorRequestor > GeneratorRequestors
Ssl::Helper request initiators waiting for the same answer (FIFO).
Definition: helper.cc:47
static void HandleGeneratorReply(void *data, const ::Helper::Reply &reply)
receives helper response
Definition: helper.cc:155
#define IPC_STREAM
Definition: defines.h:161
Definition: LruMap.h:17
#define CBDATA_CLASS(type)
Definition: cbdata.h:302
CallbackData data
Definition: helper.cc:33
Value value
instance identifier
Definition: InstanceId.h:42
void emplace(HLPCB *callback, void *data)
adds a GeneratorRequestor
Definition: helper.cc:42
const char * c_str()
Definition: SBuf.cc:546
void helperOpenServers(helper *hlp)
Definition: helper.cc:125
void setCode(std::string const &aCode)
Set new request/reply code to compose.
#define Must(cond)
Definition: TextException.h:89
static Ssl::GeneratorRequests TheGeneratorRequests
pending Ssl::Helper requests (to all certificate generator helpers combined)
Definition: helper.cc:68
std::string compose() const
LruMap< SBuf, Ssl::CertValidationResponse::Pointer, sizeof(Ssl::CertValidationResponse::Pointer)+sizeof(Ssl::CertValidationResponse)> LruCache
Definition: helper.h:64
static std::ostream & operator<<(std::ostream &os, const Ssl::GeneratorRequest &gr)
prints Ssl::GeneratorRequest for debugging
Definition: helper.cc:62
GeneratorRequestors requestors
Definition: helper.cc:48
#define ScheduleCallHere(call)
Definition: AsyncCall.h:166
an old-style void* callback parameter
Definition: cbdata.h:376
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
static Helper * GetInstance()
Instance class.
Definition: helper.cc:70
ParseResult parse(const char *buffer, size_t len)
Definition: crtd_message.cc:21
void * data
Definition: cbdata.cc:123
RefCount< CertValidationResponse > Pointer
void Init()
Init helper structure.
Definition: helper.cc:188
Initiator of an Ssl::Helper query.
Definition: helper.cc:29
SBuf query
Ssl::Helper request message (GeneratorRequests key)
Definition: helper.cc:44
#define xfree
Config TheConfig
Definition: Config.cc:12
const InstanceId< SBuf > id
Definition: SBuf.h:595
A pending Ssl::Helper request, combining the original and collapsed queries.
Definition: helper.cc:37
#define NULL
Definition: types.h:166
static void sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
Definition: helper.cc:264
bool parseResponse(CertValidationResponse &resp, std::string &error)
Parse a response message and fill the resp object with parsed informations.
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:41

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors