Commit Graph

55 Commits

Author SHA1 Message Date
Gregory Szorc
8bc014a599 sslutil: further refactor sslkwargs
The logic here and what happens with web.cacerts is mind numbing.
Make the code even more explicit.
2016-05-04 23:01:49 -07:00
Gregory Szorc
4bc1239076 sslutil: document and slightly refactor sslkwargs
This will help me and any reviewers keep sane as this code
is refactored.
2016-05-05 00:31:11 -07:00
Gregory Szorc
ad77315d76 sslutil: restore old behavior not requiring a hostname argument (issue5210)
This effectively backs out changeset 60b56b3206cc.

The http library behind ui.http2=true isn't specifying the hostname.
It is the day before the expected 3.8 release and we don't want to ship
a regression.

I'll try to restore this requirement in the 3.9 release cycle as part
of planned improvements to Mercurial's SSL/TLS interactions.
2016-04-30 09:26:47 -07:00
Gregory Szorc
cec8c17960 sslutil: document and slightly refactor validation logic
This main purpose of this patch is to make it clearer that fingerprint
pinning takes precedence over CA verification. This will make
subsequent refactoring to the validation code easier to read.
2016-04-10 11:02:58 -07:00
Gregory Szorc
a8d6c2d5ca sslutil: require a server hostname when wrapping sockets (API)
All callers appear to be passing the hostname. So this shouldn't
break anything. By specifying the hostname, more validation options
from the ssl module are available to us. Although this patch stops
short of using them.
2016-04-10 11:00:41 -07:00
Gregory Szorc
fb3741de9b sslutil: move and document verify_mode assignment
Consolidating all the SSLContext options setting makes the code a
bit easier to read.
2016-04-10 10:59:45 -07:00
Gregory Szorc
b7edbc29ee sslutil: add docstring to wrapsocket()
Security should not be opaque.
2016-03-27 13:13:19 -07:00
Gregory Szorc
5ff877516b sslutil: remove indentation in wrapsocket declaration
It is no longer needed because we have a single code path.
2016-03-27 11:39:39 -07:00
Gregory Szorc
24502a149c sslutil: always use SSLContext
Now that we have a fake SSLContext instance, we can unify the code
paths for wrapping sockets to always use the SSLContext APIs.

Because this is security code, I've retained the try..except to
make the diff easier to read. It will be removed in the next patch.

I took the liberty of updating the inline docs about supported
protocols and how the constants work because this stuff is important
and needs to be explicitly documented.
2016-03-27 14:18:32 -07:00
Gregory Szorc
36e749aa82 sslutil: move _canloaddefaultcerts logic
We now have a newer block accessing SSLContext. Let's move this
code to make subsequent refactorings of the former block easier.
2016-03-27 14:08:52 -07:00
Gregory Szorc
93d8d2d711 sslutil: implement SSLContext class
Python <2.7.9 doesn't have a ssl.SSLContext class. In this patch,
we implement the interface to the class so we can have a unified
code path for all supported versions of Python.

This is similar to the approach that urllib3 takes.
2016-03-27 13:50:34 -07:00
Gregory Szorc
46d517af99 sslutil: store OP_NO_SSL* constants in module scope
An upcoming patch will introduce a global SSLContext type so we
have a single function used to wrap sockets. Prepare for that by
introducing module level constants for disabling SSLv2 and SSLv3.
2016-03-27 10:47:24 -07:00
Gregory Szorc
3f3e1d212c sslutil: better document state of security/ssl module
Pythons older than 2.7.9 are lacking the modern ssl module
and have horrible security. Let's document this explicitly.
2016-03-27 14:07:06 -07:00
Gregory Szorc
f57c8e82d3 sslutil: use preferred formatting for import syntax 2016-03-19 10:10:09 -07:00
Gregory Szorc
ab086daadb sslutil: allow multiple fingerprints per host
Certificate pinning via [hostfingerprints] is a useful security
feature. Currently, we only support one fingerprint per hostname.
This is simple but it fails in the real world:

* Switching certificates breaks clients until they change the
  pinned certificate fingerprint. This incurs client downtime
  and can require massive amounts of coordination to perform
  certificate changes.
* Some servers operate with multiple certificates on the same
  hostname.

This patch adds support for defining multiple certificate
fingerprints per host. This overcomes the deficiencies listed
above. I anticipate the primary use case of this feature will
be to define both the old and new certificate so a certificate
transition can occur with minimal interruption, so this scenario
has been called out in the help documentation.
2016-03-13 14:03:58 -07:00
Gábor Stefanik
75370c2faf sslutil: fix reversed logic (issue5034) 2016-01-08 16:27:25 +01:00
Gregory Szorc
6cc7d3daaa sslutil: expose attribute indicating whether SNI is supported
This will be used so clone bundles can advertise whether URLs require
SNI. This will be explained more in a subsequent patch.
2015-09-29 16:17:32 -07:00
Pierre-Yves David
30913031d4 error: get Abort from 'error' instead of 'util'
The home of 'Abort' is 'error' not 'util' however, a lot of code seems to be
confused about that and gives all the credit to 'util' instead of the
hardworking 'error'. In a spirit of equity, we break the cycle of injustice and
give back to 'error' the respect it deserves. And screw that 'util' poser.

For great justice.
2015-10-08 12:55:45 -07:00
Gregory Szorc
f7857488c7 sslutil: use absolute_import 2015-08-08 19:56:22 -07:00
Yuya Nishihara
44390015d9 ssl: remove CERT_REQUIRED constant that was necessary for compatibility 2015-06-05 21:45:44 +09:00
Yuya Nishihara
d9c4cfadad ssl: drop try-except clause that was necessary for ancient Python 2015-06-05 21:40:59 +09:00
Yuya Nishihara
c09636067e ssl: drop support for Python < 2.6, require ssl module
try-except clause is kept for readability of this patch, and it will be
removed soon.
2015-06-05 21:37:46 +09:00
Yuya Nishihara
d3afea0260 ssl: rename ssl_wrap_socket() to conform to our naming convention
I've removed ssl_ prefix because the module name contains ssl.
2015-06-05 21:25:28 +09:00
Yuya Nishihara
1bf0df3c69 ssl: prompt passphrase of client key file via ui.getpass() (issue4648)
This is necessary to communicate with third-party tools through command-server
channel. This requires SSLContext backported to Python 2.7.9+.

It doesn't look nice to pass ui by sslkwargs, but I think it is the only way
to do without touching various client codes including httpclient (aka http2).
ui is mandatory if certfile is specified, so it has no default value.

BTW, test-check-commit-hg.t complains that ssl_wrap_socket() has foo_bar
naming. Should I bulk-replace it to sslwrapsocket() ?
2015-05-07 17:15:24 +09:00
Yuya Nishihara
b5d207b100 ssl: resolve symlink before checking for Apple python executable (issue4588)
test-https.t was broken at d133034be253 if /usr/bin/pythonX.Y is used on
Mac OS X.

If python executable is not named as "python", run-tests.py creates a symlink
and hghave uses it. On the other hand, the installed hg executable knows the
real path to the system Python. Therefore, there was an inconsistency that
hghave said it was not an Apple python but hg knew it was.
2015-04-04 14:56:18 +09:00
Yuya Nishihara
c8f21e0174 ssl: load CA certificates from system's store by default on Python 2.7.9
This will make it easy to manage in-house CA certificates, which are often
used in corporate environment and installed into the Windows' certs store.

Unlike Apple python, the dummycert trick isn't necessary on Python 2.7.9.
The default web.cacerts will be set as follows:

  environment    web.cacerts  behavior
  -------------  -----------  -----------------------------------------
  Apple Python   dummycert    fall back to system's store
  Python 2.7.8   '!'          never use CA certs (show warning instead)
  Python 2.7.9+  None         load CA certs from system's store
2015-02-26 22:54:13 +09:00
Yuya Nishihara
29fb442439 ssl: set explicit symbol "!" to web.cacerts to disable SSL verification (BC)
The next patch will enable verification by using the system's CA store if
possible, which means we would have to distinguish None (=use default) from
'' (=--insecure). This smells bug-prone and provides no way to override
web.cacerts to forcibly use the system's store by --config argument.

This patch changes the meaning of web.cacerts as follows:

  value   behavior
  ------- ---------------------------------------
  None/'' use default
  '!'     never use CA certs (set by --insecure)
  <path>  verify by the specified CA certificates

Values other than <path> are for internal use and therefore undocumented.
2015-03-04 23:27:04 +09:00
Yuya Nishihara
84686f40f2 ssl: extract function that returns dummycert path on Apple python
This function will be the condition to switch DISABLEOSXDUMMYCERT in
test-https.t.
2015-03-04 22:27:01 +09:00
Augie Fackler
49db56dd00 sslutil: drop defunct ssl version constants
Nobody outside sslutil should be using these constants anyway.
2015-01-14 15:46:21 -05:00
Augie Fackler
b7dd73bb3d sslutil: use saner TLS settings on Python 2.7.9
Asking for TLSv1 locks us out of TLSv1_2 etc. This is at least less
bad. Ideally we'd use ssl.create_default_context(), but that causes
more mayhem in the testsuite than I really want to deal with right
now.
2015-01-14 15:46:00 -05:00
Augie Fackler
9eebaa8a72 sslutil: drop support for clients of sslutil specifying a TLS version
We really just want to support the newest thing possible, so we may as
well consolidate that knowledge into this module. Right now this
doesn't change any behavior, but a future change will fix the defaults
for Python 2.7.9 so we can use slightly better defaults there (which
is the only place it's possible at the moment.)
2015-01-14 15:31:16 -05:00
Alex Orange
04223e707f https: support tls sni (server name indication) for https urls (issue3090)
SNI is a common way of sharing servers across multiple domains using separate
SSL certificates. As of Python 2.7.9 SSLContext has been backported from
Python 3. This patch changes sslutil's ssl_wrap_socket to use SSLContext and
take a server hostname as and argument. It also changes the url module to make
use of this argument.

The new code for 2.7.9 achieves it's task by attempting to get the SSLContext
object from the ssl module. If this fails the try/except goes back to what was
there before with the exception that the ssl_wrap_socket functions take a
server_hostname argument that doesn't get used. Assuming the SSLContext
exists, the arguments to wrap_socket at the module level are emulated on the
SSLContext. The SSLContext is initialized with the specified ssl_version. If
certfile is not None load_cert_chain is called with certfile and keyfile.
keyfile being None is not a problem, load_cert_chain will simply expect the
private key to be in the certificate file. verify_mode is set to cert_reqs. If
ca_certs is not None load_verify_locations is called with ca_certs as the
cafile. Finally the wrap_socket method of the SSLContext is called with the
socket and server hostname.

Finally, this fails test-check-commit-hg.t because the "new" function
ssl_wrap_socket has underscores in its names and underscores in its arguments.
All the underscore identifiers are taken from the other functions and as such
can't be changed to match naming conventions.
2015-01-12 18:01:20 -07:00
Augie Fackler
e19e1a783c sslutil: only support TLS (BC)
In light of the POODLE[0] attack on SSLv3, let's just drop the ability to
use anything older than TLSv1 entirely.

This only fixes the client side. Another commit will fix the server
side. There are still a few SSLv[23] constants hiding in httpclient,
but I'll fix those separately upstream and import them when we're not
in a code freeze.


0: http://googleonlinesecurity.blogspot.com/2014/10/this-poodle-bites-exploiting-ssl-30.html
2014-10-21 17:01:23 -04:00
Mads Kiilerich
489de2727b ssl: only use the dummy cert hack if using an Apple Python (issue4410)
The hack for using certificate store in addition to the provided CAs resides in
Apple's OpenSSL. Apple's own Pythons will use it, but other custom built
Pythons might use a custom built OpenSSL without that hack and will fail when
exposed to the dummy cacert introduced in ee8b7fe5e119.

There do not seem to be a simple way to check from Python if we are using a
patched OpenSSL or if it is an Apple OpenSSL.

Instead, check if the Python executable resides in /usr/bin/python* or in
/System/Library/Frameworks/Python.framework/ and assume that all Pythons found
there will be native Pythons using the patched OpenSSL.

Custom built Pythons will not get the benefit of using the CAs from the
certificate store.
2014-10-17 18:56:12 +02:00
Mads Kiilerich
69f5c2ecc6 ssl: on OS X, use a dummy cert to trick Python/OpenSSL to use system CA certs
This will give PKI-secure behaviour out of the box, without any configuration.

Setting web.cacerts to any value or empty will disable this trick.

This dummy cert trick only works on OS X 10.6+, but 10.5 had Python 2.5 which
didn't have certificate validation at all.
2014-09-26 02:19:48 +02:00
Mads Kiilerich
9342c560fd ssl: refactor sslkwargs - move things around a bit, preparing for next change 2014-09-26 02:19:47 +02:00
Augie Fackler
006064bcd2 sslutil: make keyfile and certfile arguments consistent between 2.6+ and 2.5- 2013-09-20 09:15:43 -04:00
Augie Fackler
cb1c036518 sslutil: add a config knob to support TLS (default) or SSLv23 (bc) (issue4038)
Prior to this change, we default to SSLv23, which is insecure because
it allows use of SSLv2. Unfortunately, there's no constant for OpenSSL
to let us use SSLv3 or TLS - we have to pick one or the other. We
expose a knob to revert to pre-TLS SSL for the user that has an
ancient server that lacks proper TLS support.
2013-09-19 16:29:00 -04:00
Augie Fackler
fd194f3d5b sslutil: backed out changeset 2cb59fd7ebb6 (issue4038)
Python docs are a little unclear, but mpm reports reading the OpenSSL
source code shows that PROTOCOL_SSLv23 allows TLS whereas
PROTOCOL_SSLv3 does not.
2013-09-18 14:40:17 -04:00
Augie Fackler
9ec0b367aa sslutil: force SSLv3 on Python 2.6 and later (issue3905)
We can't (easily) force SSL version on older Pythons, but on 2.6 and
later we can force SSLv3, which is safer and widely supported. This
also appears to work around a bug in IIS detailed in issue 3905.
2013-07-24 14:51:13 -04:00
FUJIWARA Katsunori
36bc77eef3 sslutil: abort if peer certificate is not verified for secure use
Before this patch, "sslutil.validator" may returns successfully, even
if peer certificate is not verified because there is no information in
"[hostfingerprints]" and "[web] cacerts".

To prevent from sending authentication credential to untrustable SMTP
server, validation should be aborted if peer certificate is not
verified.

This patch introduces "strict" optional argument, and
"sslutil.validator" will abort if it is True and peer certificate is
not verified.
2013-03-26 02:28:10 +09:00
Matt Mackall
71c760e42b sslutil: try harder to avoid getpeercert problems
We wrap both calls to getpeercert in a try/except to make sure we
catch its bogus AttributeError.
2013-04-05 12:20:14 -05:00
Steven Stallion
af163e9811 ui: optionally quiesce ssl verification warnings on python 2.5
Some platforms, notably Plan 9 from Bell Labs are stuck on older
releases of Python. Due to restrictions in the platform, it is not
possible to backport the SSL library to the existing Python port.
This patch permits the UI to quiesce SSL verification warnings by
adding a configuration entry named reportoldssl to ui.
2012-04-09 14:36:16 -07:00
Matt Mackall
5a379a202e sslutil: more helpful fingerprint mismatch message
This will aid debugging for users of sites that renew certs.
2012-01-26 11:23:15 -06:00
Mads Kiilerich
53bbcb8a33 sslutil: abort properly if no certificate received for https connection
According to the documentation SSLSocket.getpeercert() can return None.
2012-01-09 14:56:05 +01:00
Mads Kiilerich
f23e3d95df sslutil: work around validator crash getting certificate on failed sockets
The previous workaround for correct handling of wrapping of failing connections
might be enough to prevent this from happening, but the check here makes this
function more robust.
2012-01-09 14:43:25 +01:00
Mads Kiilerich
78235f35f1 sslutil: reorder validator code to make it more readable 2012-01-09 14:43:24 +01:00
Mads Kiilerich
142d372dec sslutil: show fingerprint when cacerts validation fails 2012-01-09 14:43:24 +01:00
Mads Kiilerich
a41a6f6696 sslutil: handle setups without .getpeercert() early in the validator
This simplifies the code and makes the flow more obvious and reduces the
indentation level.
2012-01-09 14:43:23 +01:00
Mads Kiilerich
122292828b sslutil: verify that wrap_socket really wrapped the socket
This works around that ssl.wrap_socket silently skips ssl negotiation on
sockets that was connected but since then has been reset by the peer but not
yet closed at the Python level. That leaves the socket in a state where
.getpeercert() fails with an AttributeError on None. See
http://bugs.python.org/issue13721 .

A call to .cipher() is now used to verify that the wrapping really did succeed.
Otherwise it aborts with "ssl connection failed".
2012-01-09 14:43:15 +01:00