Alex Rousskov [Fri, 24 Feb 2012 22:29:40 +0000 (15:29 -0700)]
Ssl::ServerPeeker must become a store_client to prevent [error] entry trimming
We do not need a store client during the certificate peeking stage because we
do not send the error to the client and only accumulate what is being written
to the store. However, if there is no store client then Store will trim the
entry and we will hit a
setCommonName sets CN, but that is not enough when the fake certificate containsalternative names (which Squid mimics): The browser does not accept the
resulting fake certificate because it does not contains at least one alternativename that matches the domain name.
This patch stop mimicking of "Certificate Subject Alt Name" extensions when the
setCommonName adaptation algorithm used
If a certificate verification error is honored by Squid (i.e., a Squid error
page is returned to the user), the user gets a browser warning and then, after
ignoring the warning, the squid error message (about the same kind of problem). This happens because the fake certificate mimics details of the true server
certificate, which is "broken".
When Squid serves its own error page it is no longer trying to hide its presencefrom the user. Thus, it is probably better to serve all Squid-generated SSL
handshake and validation error responses with a trusted certificate containing
minimal details, like we already do for the DNS_FAIL errors.
This patch fixing the above problem.
NOTE: The fix will not work for domain mismatch errors. We are checking
for domain mismatch after we have establish the SSL connection with the web
client , and after we got the http request, because we need the HTTP request
Host header to check for SSL domain mismatch errors.
- Handle the case the signing certificate changed. The ssl_crtd daemon
must drop cached certificates which has signed with older signing
certificates and generate new one using the current signing certificate
- We need to generate certificates with different serial numbers, if the
signing certificate has changes in any way, even if the certificates has
exactly the same fields.
To achieve this we are firstly generating a temporary fake certificate with
serial number the hash digest of signing certificates public key. The digest
of the temporary fake certificate used as serial key to the final certificate
- Bug fix: A cached certificate which has adaptated with one or more algorithms
(setNotAfter, setNotBefore, setCommonName etc) did not used and always a new
certificate generated. This patch fixes this bug.
Notes:
- Ssl::ssl_match_certificates replaced with Ssl::certificateMatchesProperties
function which checks if a given certificate matches given properties:
Checks if the certificate signed with current signing certificate, and
check if mimicked certificate matches the given certificate.
- The Ssl::CertificateDb::purgeCert method added to delete a certificate from
database.
Two different certificates of the same fake Issuer must have the same serial
number. Otherwise, Firefox and possibly others will display a
sec_error_reused_issuer_and_serial error. Similarly, the same two certificates
should have the same serial number, even if generated on different
non-communicating (but identically configured) Squid boxes.
To produce unique serial numbers a temporary fake certificate with serial number
zero created, and its fingerprint used as the serial number of the final fake
certificate.
The old Ssl::CertificateDb code which was responsible to produce a serial number
for generated certificates removed.
Bug fix: sslpassword_program for ssl-bump http ports
Currently the sslpassword_program configuration parameter does not work
for encrypted certificate keys on ssl-bump enabled http ports, and user
always asked to give the SSL key password.
Alex Rousskov [Mon, 20 Feb 2012 21:05:28 +0000 (14:05 -0700)]
Use broken instead of a peer certificate info for error detail formatting.
This change has no visible effect when the peer certificate is a broken one.
Eventually, we may have to add more formatting codes to give admin access to
both peer and broken certificate details, but it may be difficult to use such
two sets of formatting codes on one static error page that does not "know"
whether the peer certificate is broken.
Alex Rousskov [Mon, 20 Feb 2012 19:32:58 +0000 (12:32 -0700)]
Retry requests that failed due to a persistent connection race
instead of replying with ERR_ZERO_SIZE_OBJECT "Bad Gateway".
Trunk r12050 code contains a portion of these changes. The rest is code
to re-pin a bump-server-first connection if a bumped pinned pconn fails
due to a race. We use a new canRePin flag to mark connections that can
be repinned and assume that pinned connections unrelated to SslBump
cannot be repinned.
Alex Rousskov [Mon, 20 Feb 2012 19:10:54 +0000 (12:10 -0700)]
Retry requests that failed due to a persistent connection race
instead of replying with ERR_ZERO_SIZE_OBJECT "Bad Gateway".
The ERR_ZERO_SIZE_OBJECT errors were visible to the client when the
destination had only one address because serverDestinations.shift()
made the list of destination empty and startConnectionOrFail() failed.
When FwdState starts to use a pinned connection, the connection is treated as
an idle persistent connection as far as race detection is concerned.
Currently, pinned connections cannot be reopened, repinned, and retried after
a pconn race. This will change when server-side bumped connections become
pinned.
It felt wrong that a failed serverConn may remain set while we are opening a
new connection so I set it to NULL after a squid-dev discussion indicating
that doing so should be safe.
We also now reset the local port number to zero in case it was set to the
actual source port by ConnOpener or other code working with the previous
connection to the same serverDestinations[0] address, although simple tests
worked (and showed changing source port) without this reset.
Bug fix: sslpassword_program for ssl-bump http ports
Currently the sslpassword_program configuration parameter does not work
for encrypted certificate keys on ssl-bump enabled http ports, and user
always asked to give the SSL key password.
Changes to make fake certificates "stable" and "unique".
This patch modify bump-server-first branch to:
- use configured trusted CA private key for generating all fake certificates,
including trusted, untrusted, and self-signed fake certificates.
- use untrusted CA certificate which be deterministically derived from
the trusted CA certificate to both reduce configuration effort (compared to
a configuration option) and to generate identical untrusted CA certificates
given identical Squid configurations.
Alex Rousskov [Fri, 10 Feb 2012 00:32:44 +0000 (17:32 -0700)]
Do not cache partially loaded entries in shared mem cache (and then serve them)
When handling a conditional request, Squid may load the beginning of a cached
object from disk, realize that the client has the same fresh copy, and respond
with 304 Not Modified. After that, Squid was checking whether the partially
loaded object should be kept in shared memory cache (if enabled). There were
no checks preventing memory caching of the partially loaded object.
Later, partially cached objects were served to clients, resulting in truncated
responses. I believe this happens because shared memory cache does not keep
all the StoreEntry data (just like a disk cache does not do that) so the fact
that only a part of the object was available was lost.
Alex Rousskov [Fri, 10 Feb 2012 00:01:17 +0000 (17:01 -0700)]
Do not swap out swapped out objects.
I noticed that sometimes Squid would start swapping out an entry that was
recently loaded from disk and was still on disk. That wastes disk
resources (at best).
The old StoreEntry::mayStartSwapOut() code assumed that when swap_status is
not SWAPOUT_NONE it is SWAPOUT_WRITING, but SWAPOUT_WRITING is impossible
after recent StoreEntry::swapOut() modifications because mayStartSwapOut() is
only called when we are not swappingOut() already. SWAPOUT_DONE is possible.
Amos Jeffries [Thu, 9 Feb 2012 13:27:51 +0000 (06:27 -0700)]
Drop dead code in reply parsing
This code has not been used/needed in some time. It can die.
It is also no clear why it existed in the first place. The RFC is not
mentioned by number and RFC 2068/2616 only talk about tolerance for
whitespace before request lines, not replies.
Amos Jeffries [Mon, 6 Feb 2012 01:01:23 +0000 (18:01 -0700)]
SourceLayout: shuffle CommIO into DiskThreads library
While investigating the Windows port problems it became clear that the
CommIO object is not actually related to the rest of comm systems. It is
instead a dedicated higher level disk I/O pipe manager for DiskThreads.
Given that it causes build errors in comm.cc on Windows and does not
even need to be there this patch shuffles it into the DiskThreads
library. The build issues on Windows still exist but are now limited to
just that threads library and can be avoided temporarily with simple
./configure options.
Alex Rousskov [Sun, 5 Feb 2012 22:27:05 +0000 (15:27 -0700)]
Forward bumped server connection-close signal to the bumped client.
Technically, the two connections can be maintained independently, but since we
are pretending to be a dumb tunnel to the origin server, it is useful to have
the client close when the server does because it reduces both the number of
persistent connection races (zero replies on the server side that force us to
re-connect and re-forward the failed request) and the possibility that we will
reconnect to the wrong HTTPS server without client knowing.
Alex Rousskov [Sun, 5 Feb 2012 21:55:51 +0000 (14:55 -0700)]
Use peer certificate to set the requested host name on failures.
Even if an intermediate certificate fails, the "which URL failed" information
on the error report should be based on the server certificate CN. Intermediate
certificate CN may not even be a host name.
Add the following methods:
- Ssl::CrtdMessage::parseRequest: Parse a ssl_crtd "new certificate" request and
store the requested certificate properties to a CertificateProperties object
- Ssl::CrtdMessage::composeRequest: Generate a "new certificate" ssl_crtd
request using the certificate properties given by a CertificateProperties
object
- Ssl::CertificateProperties::dbKey: Return a valid key for the generated
certificate to be used with a (memory or disk) database, based on its
properties
Others:
- The ssl_crtd.cc code simplified using the above methods
- The ConnStateData::buildSslCertGenerationParams and ConnStateData::getSslContextStart
simplified using the above methods
Alex Rousskov [Fri, 3 Feb 2012 18:01:27 +0000 (11:01 -0700)]
Disable persistent connections after client-side-detected errors.
HTTP does not require to close the connection after most errors, but some
client-side-detected errors (those detected by clientProcessRequest) are about
HTTP message framing and should result in connection closure. For other
client-side-detected errors (those detected in serveDelayedError), the
client-side code is just not ready to handle persistency well:
* If we leave flags.readMore as true, then a new request on the same
connection may find bumpErrorEntry set and think there is a delayed error
that needs to be served, but that StoreEntry object has been already used.
And we should not simply clear bumpErrorEntry because it is not locked by
the error writing code using it. There may be other problems as well (and it
is likely the connection is not usable anyway because the fake certificate
was rejected by the client).
* If we set flags.readMore to false then we will not resume reading after
serving the error, causing "abandoning such and such connection" errors
and stuck ConnStateData jobs.
Thus, in summary, we should set flags.readMore to false and, if we do that, we
should also set proxy_keepalive to zero so that we close the connection after
serving the error to the client.
This add a bit more leniency to the Host: header validation without
re-opening Squid to the cache poisoning risks involved.Resolving most
issues with websites using geo-based DNS results and/or short DNS TTL for
load balancing.
It alters host_verify_strict directive to allow requests which fail Host:
validation to continue through processing. The default remains OFF.
* blocks caching on the response to protect all other network clients
against one compromised client spreading infections.
* forces the original (untrusted) destination IP to be used instead of
any alternative Squid might find. Preventing Squid or peer DNS lookup
being the point of vulnerability for the same-origin bypass. For any
client to be vulnerable it must be vulnerable inside the browser agent
where the original TCP connection is established.
Also add a new error template ERR_CONFLICT_HOST to replace the confusing
"invalid request" message with a clear explanation of the problem and
some client workarounds.
FUTURE WORK:
* adapt processing to allow these requests to safely be passed to peers.
* adapt caching to permit safe sharing between clients making identical
requests to same sources.
Replace the hard coded implementation for default signing algorithm applied
to generated certificates which does not match the configured sslproxy_cert_sign
access list, with default acl lines.
The new tag POSTSCRIPTUM added to the cf.data.pre file which can be used to
append to the user configuration some default config lines.
This patch add the following ACLs to test the condition of the origin server
certificate: ssl::certHasExpired, ssl::certNotYetValid, ssl::certDomainMismatch,
ssl::certUntrusted and ssl::certSelfSigned.
The above in this patch are predifined acl lists or/and can be used as error
name shortcuts with ssl_error ACL lists
Implementation details:
1) The ssl::certHasExpired, ssl::certNotYetValid, ssl::certDomainMismatch
ssl::certUntrusted and ssl::certSelfSign acl lists are predifined in cf.data.pre
2) The above names can also used as error names. The ssl-error parser
(Ssl::ParseErrorString function) replace them with the appropriate SSL error
list.
3) The Ssl::ParseErrorString function modified to return a list of errors, not
just an error code.
4) I implement the IFDEF /ENDIF block support for cf.data.pre file.
Bug fix: broken intermediate certificate is mimicked instead of the origin server certificate
In the case of SSL error we are trying to get the server ssl certificate from
the Ssl::ErrorDetail object using the Ssl::ErrorDetail::peerCert method.
But with the current implementation this method does not return the peer
certificate but instead the broken certificate which may be different than the
peer certificate.
This patch:
1) Stores both server and broken certificate in Ssl::ErrorDetail objects
2) Fix the Ssl::ErrorDetail::peerCert method to return always server certificate
3) Add a new method the Ssl::ErrorDetail::brokenCert which return the broken
certificate
Alex Rousskov [Wed, 1 Feb 2012 19:12:41 +0000 (12:12 -0700)]
Set logged status code (%<Hs) to 200 when establishing a bumped tunnel.
Bumped CONNECT requests are logged separately and we always use 200 status
code when bumping them. Eventually, tunnel and bumping code should use
real HttpReply objects instead of writing hard-coded reply strings that
logging code has no access to.
Alex Rousskov [Wed, 1 Feb 2012 06:05:08 +0000 (23:05 -0700)]
Add FwdState close handler to pinned connections.
Without a close handler, we will not notice when Server forcefully closed the
connection (e.g., when receiving a zero-size response due to a pconn race)
and, hence, will not retry the connection (or server an error), resulting in a
stuck client (e.g., again, when the server received a zero-size response).
Alex Rousskov [Wed, 1 Feb 2012 05:13:24 +0000 (22:13 -0700)]
Replaced PROTO_SSL_PEEK with request_flags::sslPeek and disabled server SNI
for bump-server-first connections.
While PROTO_SSL_PEEK was a safer design option because requests with the
"wrong" protocol scheme would be less likely to leave Squid, it required
all error-generation code to replace the protocol with PROTO_HTTPS so
that error make more sense to end users. We no longer have to do that.
The server-side SNI for bump-server-first connections has to be disabled
because bump-server-first code does not yet know the true intended server name
(even for those CONNECT requests that have server name, it would be a little
risky to use CONNECT info for SNI). That name could be eventually obtained
from the client before we peek at the server certificate but that work
is outside this project scope.
Alex Rousskov [Wed, 1 Feb 2012 05:06:08 +0000 (22:06 -0700)]
Do not set request->flags.no_direct for bumped CONNECT requests
because it precludes them from reaching their [direct] destination
unless allow-direct is set on http_port.