49 supportedprotocols = {b'tls1.0'} |
49 supportedprotocols = {b'tls1.0'} |
50 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_1'): |
50 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_1'): |
51 supportedprotocols.add(b'tls1.1') |
51 supportedprotocols.add(b'tls1.1') |
52 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_2'): |
52 if util.safehasattr(ssl, b'PROTOCOL_TLSv1_2'): |
53 supportedprotocols.add(b'tls1.2') |
53 supportedprotocols.add(b'tls1.2') |
54 |
|
55 _canloaddefaultcerts = True |
|
56 |
54 |
57 |
55 |
58 def _hostsettings(ui, hostname): |
56 def _hostsettings(ui, hostname): |
59 """Obtain security settings for a hostname. |
57 """Obtain security settings for a hostname. |
60 |
58 |
225 |
223 |
226 s[b'cafile'] = cafile |
224 s[b'cafile'] = cafile |
227 |
225 |
228 # Require certificate validation if CA certs are being loaded and |
226 # Require certificate validation if CA certs are being loaded and |
229 # verification hasn't been disabled above. |
227 # verification hasn't been disabled above. |
230 if cafile or (_canloaddefaultcerts and s[b'allowloaddefaultcerts']): |
228 if cafile or s[b'allowloaddefaultcerts']: |
231 s[b'verifymode'] = ssl.CERT_REQUIRED |
229 s[b'verifymode'] = ssl.CERT_REQUIRED |
232 else: |
230 else: |
233 # At this point we don't have a fingerprint, aren't being |
231 # At this point we don't have a fingerprint, aren't being |
234 # explicitly insecure, and can't load CA certs. Connecting |
232 # explicitly insecure, and can't load CA certs. Connecting |
235 # is insecure. We allow the connection and abort during |
233 # is insecure. We allow the connection and abort during |
719 return exe.startswith(b'/usr/bin/python') or exe.startswith( |
717 return exe.startswith(b'/usr/bin/python') or exe.startswith( |
720 b'/system/library/frameworks/python.framework/' |
718 b'/system/library/frameworks/python.framework/' |
721 ) |
719 ) |
722 |
720 |
723 |
721 |
724 _systemcacertpaths = [ |
|
725 # RHEL, CentOS, and Fedora |
|
726 b'/etc/pki/tls/certs/ca-bundle.trust.crt', |
|
727 # Debian, Ubuntu, Gentoo |
|
728 b'/etc/ssl/certs/ca-certificates.crt', |
|
729 ] |
|
730 |
|
731 |
|
732 def _defaultcacerts(ui): |
722 def _defaultcacerts(ui): |
733 """return path to default CA certificates or None. |
723 """return path to default CA certificates or None. |
734 |
724 |
735 It is assumed this function is called when the returned certificates |
725 It is assumed this function is called when the returned certificates |
736 file will actually be used to validate connections. Therefore this |
726 file will actually be used to validate connections. Therefore this |
748 if os.path.exists(certs): |
738 if os.path.exists(certs): |
749 ui.debug(b'using ca certificates from certifi\n') |
739 ui.debug(b'using ca certificates from certifi\n') |
750 return pycompat.fsencode(certs) |
740 return pycompat.fsencode(certs) |
751 except (ImportError, AttributeError): |
741 except (ImportError, AttributeError): |
752 pass |
742 pass |
753 |
|
754 # On Windows, only the modern ssl module is capable of loading the system |
|
755 # CA certificates. If we're not capable of doing that, emit a warning |
|
756 # because we'll get a certificate verification error later and the lack |
|
757 # of loaded CA certificates will be the reason why. |
|
758 # Assertion: this code is only called if certificates are being verified. |
|
759 if pycompat.iswindows: |
|
760 if not _canloaddefaultcerts: |
|
761 ui.warn( |
|
762 _( |
|
763 b'(unable to load Windows CA certificates; see ' |
|
764 b'https://mercurial-scm.org/wiki/SecureConnections for ' |
|
765 b'how to configure Mercurial to avoid this message)\n' |
|
766 ) |
|
767 ) |
|
768 |
|
769 return None |
|
770 |
743 |
771 # Apple's OpenSSL has patches that allow a specially constructed certificate |
744 # Apple's OpenSSL has patches that allow a specially constructed certificate |
772 # to load the system CA store. If we're running on Apple Python, use this |
745 # to load the system CA store. If we're running on Apple Python, use this |
773 # trick. |
746 # trick. |
774 if _plainapplepython(): |
747 if _plainapplepython(): |
775 dummycert = os.path.join( |
748 dummycert = os.path.join( |
776 os.path.dirname(pycompat.fsencode(__file__)), b'dummycert.pem' |
749 os.path.dirname(pycompat.fsencode(__file__)), b'dummycert.pem' |
777 ) |
750 ) |
778 if os.path.exists(dummycert): |
751 if os.path.exists(dummycert): |
779 return dummycert |
752 return dummycert |
780 |
|
781 # The Apple OpenSSL trick isn't available to us. If Python isn't able to |
|
782 # load system certs, we're out of luck. |
|
783 if pycompat.isdarwin: |
|
784 # FUTURE Consider looking for Homebrew or MacPorts installed certs |
|
785 # files. Also consider exporting the keychain certs to a file during |
|
786 # Mercurial install. |
|
787 if not _canloaddefaultcerts: |
|
788 ui.warn( |
|
789 _( |
|
790 b'(unable to load CA certificates; see ' |
|
791 b'https://mercurial-scm.org/wiki/SecureConnections for ' |
|
792 b'how to configure Mercurial to avoid this message)\n' |
|
793 ) |
|
794 ) |
|
795 return None |
|
796 |
|
797 # / is writable on Windows. Out of an abundance of caution make sure |
|
798 # we're not on Windows because paths from _systemcacerts could be installed |
|
799 # by non-admin users. |
|
800 assert not pycompat.iswindows |
|
801 |
|
802 # Try to find CA certificates in well-known locations. We print a warning |
|
803 # when using a found file because we don't want too much silent magic |
|
804 # for security settings. The expectation is that proper Mercurial |
|
805 # installs will have the CA certs path defined at install time and the |
|
806 # installer/packager will make an appropriate decision on the user's |
|
807 # behalf. We only get here and perform this setting as a feature of |
|
808 # last resort. |
|
809 if not _canloaddefaultcerts: |
|
810 for path in _systemcacertpaths: |
|
811 if os.path.isfile(path): |
|
812 ui.warn( |
|
813 _( |
|
814 b'(using CA certificates from %s; if you see this ' |
|
815 b'message, your Mercurial install is not properly ' |
|
816 b'configured; see ' |
|
817 b'https://mercurial-scm.org/wiki/SecureConnections ' |
|
818 b'for how to configure Mercurial to avoid this ' |
|
819 b'message)\n' |
|
820 ) |
|
821 % path |
|
822 ) |
|
823 return path |
|
824 |
|
825 ui.warn( |
|
826 _( |
|
827 b'(unable to load CA certificates; see ' |
|
828 b'https://mercurial-scm.org/wiki/SecureConnections for ' |
|
829 b'how to configure Mercurial to avoid this message)\n' |
|
830 ) |
|
831 ) |
|
832 |
753 |
833 return None |
754 return None |
834 |
755 |
835 |
756 |
836 def validatesocket(sock): |
757 def validatesocket(sock): |