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