[PATCH 5 of 8] sslutil: use certificates provided by certifi if available

Gregory Szorc gregory.szorc at gmail.com
Fri Jul 1 22:57:41 EDT 2016


# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1467340479 25200
#      Thu Jun 30 19:34:39 2016 -0700
# Node ID 101e040f8b014fe938803c68b502e7b72b4726f8
# Parent  ab3d545871efb2e0405d576f3bda1c935d6b6d31
sslutil: use certificates provided by certifi if available

The "certifi" Python package provides a distribution of the
Mozilla trusted CA certificates as a Python package. If it is
present, we assume the user intends it to be used and we use
it to provide the default CA certificates when certificates
are otherwise not configured.

It's worth noting that this behavior roughly matches the popular
"requests" package, which also attempts to use "certifi" if
present.

diff --git a/mercurial/sslutil.py b/mercurial/sslutil.py
--- a/mercurial/sslutil.py
+++ b/mercurial/sslutil.py
@@ -12,16 +12,17 @@ from __future__ import absolute_import
 import hashlib
 import os
 import re
 import ssl
 import sys
 
 from .i18n import _
 from . import (
+    demandimport,
     error,
     util,
 )
 
 # Python 2.7.9+ overhauled the built-in SSL/TLS features of Python. It added
 # support for TLS 1.1, TLS 1.2, SNI, system CA stores, etc. These features are
 # all exposed via the "ssl" module.
 #
@@ -427,16 +428,26 @@ def _plainapplepython():
     if sys.platform != 'darwin' or util.mainfrozen() or not sys.executable:
         return False
     exe = os.path.realpath(sys.executable).lower()
     return (exe.startswith('/usr/bin/python') or
             exe.startswith('/system/library/frameworks/python.framework/'))
 
 def _defaultcacerts(ui):
     """return path to default CA certificates or None."""
+    # The "certifi" Python package provides certificates. If it is installed,
+    # assume the user intends it to be used and use it.
+    with demandimport.deactivated():
+        try:
+            import certifi
+            ui.debug('using ca certificates from certifi\n')
+            return certifi.where()
+        except Exception:
+            pass
+
     if _plainapplepython():
         dummycert = os.path.join(os.path.dirname(__file__), 'dummycert.pem')
         if os.path.exists(dummycert):
             return dummycert
 
     return None
 
 def validatesocket(sock):


More information about the Mercurial-devel mailing list