# HG changeset patch # User Mads Kiilerich # Date 1411690788 -7200 # Node ID d7f7f1860f00a74d755ef0b26bc8e468e7c358fb # Parent a00a7951b20c67a473a9afd18692b9648b776789 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. diff -r a00a7951b20c -r d7f7f1860f00 mercurial/dummycert.pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mercurial/dummycert.pem Fri Sep 26 02:19:48 2014 +0200 @@ -0,0 +1,56 @@ +A dummy certificate that will make OS X 10.6+ Python use the system CA +certificate store: + +-----BEGIN CERTIFICATE----- +MIIBIzCBzgIJANjmj39sb3FmMA0GCSqGSIb3DQEBBQUAMBkxFzAVBgNVBAMTDmhn +LmV4YW1wbGUuY29tMB4XDTE0MDgzMDA4NDU1OVoXDTE0MDgyOTA4NDU1OVowGTEX +MBUGA1UEAxMOaGcuZXhhbXBsZS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA +mh/ZySGlcq0ALNLmA1gZqt61HruywPrRk6WyrLJRgt+X7OP9FFlEfl2tzHfzqvmK +CtSQoPINWOdAJMekBYFgKQIDAQABMA0GCSqGSIb3DQEBBQUAA0EAF9h49LkSqJ6a +IlpogZuUHtihXeKZBsiktVIDlDccYsNy0RSh9XxUfhk+XMLw8jBlYvcltSXdJ7We +aKdQRekuMQ== +-----END CERTIFICATE----- + +This certificate was generated to be syntactically valid but never be usable; +it expired before it became valid. + +Created as: + + $ cat > cn.conf << EOT + > [req] + > distinguished_name = req_distinguished_name + > [req_distinguished_name] + > commonName = Common Name + > commonName_default = no.example.com + > EOT + $ openssl req -nodes -new -x509 -keyout /dev/null \ + > -out dummycert.pem -days -1 -config cn.conf -subj '/CN=hg.example.com' + +To verify the content of this certificate: + + $ openssl x509 -in dummycert.pem -noout -text + Certificate: + Data: + Version: 1 (0x0) + Serial Number: 15629337334278746470 (0xd8e68f7f6c6f7166) + Signature Algorithm: sha1WithRSAEncryption + Issuer: CN=hg.example.com + Validity + Not Before: Aug 30 08:45:59 2014 GMT + Not After : Aug 29 08:45:59 2014 GMT + Subject: CN=hg.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (512 bit) + Modulus: + 00:9a:1f:d9:c9:21:a5:72:ad:00:2c:d2:e6:03:58: + 19:aa:de:b5:1e:bb:b2:c0:fa:d1:93:a5:b2:ac:b2: + 51:82:df:97:ec:e3:fd:14:59:44:7e:5d:ad:cc:77: + f3:aa:f9:8a:0a:d4:90:a0:f2:0d:58:e7:40:24:c7: + a4:05:81:60:29 + Exponent: 65537 (0x10001) + Signature Algorithm: sha1WithRSAEncryption + 17:d8:78:f4:b9:12:a8:9e:9a:22:5a:68:81:9b:94:1e:d8:a1: + 5d:e2:99:06:c8:a4:b5:52:03:94:37:1c:62:c3:72:d1:14:a1: + f5:7c:54:7e:19:3e:5c:c2:f0:f2:30:65:62:f7:25:b5:25:dd: + 27:b5:9e:68:a7:50:45:e9:2e:31 diff -r a00a7951b20c -r d7f7f1860f00 mercurial/sslutil.py --- a/mercurial/sslutil.py Fri Sep 26 02:19:47 2014 +0200 +++ b/mercurial/sslutil.py Fri Sep 26 02:19:48 2014 +0200 @@ -6,7 +6,7 @@ # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import os +import os, sys from mercurial import util from mercurial.i18n import _ @@ -104,6 +104,13 @@ cacerts = util.expandpath(cacerts) if not os.path.exists(cacerts): raise util.Abort(_('could not find web.cacerts: %s') % cacerts) + elif cacerts is None and sys.platform == 'darwin' and not util.mainfrozen(): + dummycert = os.path.join(os.path.dirname(__file__), 'dummycert.pem') + if os.path.exists(dummycert): + ui.debug('using %s to enable OS X system CA\n' % dummycert) + ui.setconfig('web', 'cacerts', dummycert, 'dummy') + cacerts = dummycert + if cacerts: kws.update({'ca_certs': cacerts, 'cert_reqs': CERT_REQUIRED, }) diff -r a00a7951b20c -r d7f7f1860f00 setup.py --- a/setup.py Fri Sep 26 02:19:47 2014 +0200 +++ b/setup.py Fri Sep 26 02:19:48 2014 +0200 @@ -481,7 +481,8 @@ cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo', - 'help/*.txt']} + 'help/*.txt', + 'dummycert.pem']} def ordinarypath(p): return p and p[0] != '.' and p[-1] != '~' diff -r a00a7951b20c -r d7f7f1860f00 tests/hghave.py --- a/tests/hghave.py Fri Sep 26 02:19:47 2014 +0200 +++ b/tests/hghave.py Fri Sep 26 02:19:48 2014 +0200 @@ -332,6 +332,10 @@ def has_aix(): return sys.platform.startswith("aix") +@check("osx", "OS X") +def has_osx(): + return sys.platform == 'darwin' + @check("absimport", "absolute_import in __future__") def has_absimport(): import __future__ diff -r a00a7951b20c -r d7f7f1860f00 tests/test-https.t --- a/tests/test-https.t Fri Sep 26 02:19:47 2014 +0200 +++ b/tests/test-https.t Fri Sep 26 02:19:48 2014 +0200 @@ -115,9 +115,20 @@ #endif $ cd .. +OS X has a dummy CA cert that enables use of the system CA store + + $ DISABLEOSXDUMMYCERT= +#if osx + $ hg clone https://localhost:$HGPORT/ copy-pull + abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob) + [255] + + $ DISABLEOSXDUMMYCERT="--config=web.cacerts=" +#endif + clone via pull - $ hg clone https://localhost:$HGPORT/ copy-pull + $ hg clone https://localhost:$HGPORT/ copy-pull $DISABLEOSXDUMMYCERT warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting) requesting all changes adding changesets @@ -143,7 +154,7 @@ $ cd copy-pull $ echo '[hooks]' >> .hg/hgrc $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc - $ hg pull + $ hg pull $DISABLEOSXDUMMYCERT warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting) pulling from https://localhost:$HGPORT/ searching for changes