Sitelet https://github.com/python/cpython/issues/72209
Skip to content

SSL releated deprecation for 3.6 #72209

Description

@tiran
BPO 28022
Nosy @ncoghlan, @orsenthil, @vstinner, @giampaolo, @tiran, @kousu, @alex, @vadmium, @serhiy-storchaka, @dstufft, @Lukasa
Files
  • ssl_deprecations.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/tiran'
    closed_at = <Date 2021-04-17.10:48:13.818>
    created_at = <Date 2016-09-08.15:19:02.658>
    labels = ['type-security', 'expert-SSL', 'library', '3.10', 'docs']
    title = 'SSL releated deprecation for 3.6'
    updated_at = <Date 2021-08-08.19:17:15.658>
    user = 'https://github.com/tiran'

    bugs.python.org fields:

    activity = <Date 2021-08-08.19:17:15.658>
    actor = 'christian.heimes'
    assignee = 'christian.heimes'
    closed = True
    closed_date = <Date 2021-04-17.10:48:13.818>
    closer = 'christian.heimes'
    components = ['Documentation', 'Library (Lib)', 'SSL']
    creation = <Date 2016-09-08.15:19:02.658>
    creator = 'christian.heimes'
    dependencies = []
    files = ['44492']
    hgrepos = []
    issue_num = 28022
    keywords = ['patch']
    message_count = 30.0
    messages = ['275043', '275056', '275109', '275127', '275129', '275134', '275144', '275230', '275243', '275291', '275300', '275306', '275308', '275603', '275699', '275700', '275726', '275727', '275728', '275730', '275737', '275739', '275767', '275816', '275817', '275843', '275853', '304733', '399231', '399235']
    nosy_count = 13.0
    nosy_names = ['ncoghlan', 'janssen', 'orsenthil', 'vstinner', 'giampaolo.rodola', 'christian.heimes', 'kousu', 'alex', 'python-dev', 'martin.panter', 'serhiy.storchaka', 'dstufft', 'Lukasa']
    pr_nums = []
    priority = 'high'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'security'
    url = 'https://bugs.python.org/issue28022'
    versions = ['Python 3.10']

    Activity

    1. tiran commented on Sep 8, 2016

      @tiran
      MemberAuthor

      I like to deprecate some SSL related parts of Python:

      • ssl.wrap_socket() is a horrible abomination. People should use SSLContext.wrap_socket() instead
      • all certfile/cert_file, keyfile/key_file and check_hostname arguments. Use context / ssl_context instead.
      • make ftplib, imaplib, nntplib, pop3lib, smtplib etc. validate certs by default.
    2. self-assigned this
      on Sep 8, 2016
    3. added
      stdlibStandard Library Python modules in the Lib/ directory
      docsDocumentation in the Doc dir
      on Sep 8, 2016
    4. Lukasa commented on Sep 8, 2016

      Lukasamannequin
      Mannequin

      10/10, yes. I will happily provide code review for this.

    5. vstinner commented on Sep 8, 2016

      @vstinner
      Member
      • make ftplib, imaplib, nntplib, pop3lib, smtplib etc. validate certs by default.

      I'm not sure about this one:
      http://legacy.python.org/dev/peps/pep-0476/#other-protocols

    6. tiran commented on Sep 8, 2016

      @tiran
      MemberAuthor

      Another deprecation: I like to deprecate all arguments from SSLSocket.__init__() and require users to go through SSLContext.wrap_socket(). It's going to make the implementation much simpler. The argument list is just crazy:

      class SSLSocket(socket):
          def __init__(self, sock=None, keyfile=None, certfile=None,
                       server_side=False, cert_reqs=CERT_NONE,
                       ssl_version=PROTOCOL_TLS, ca_certs=None,
                       do_handshake_on_connect=True,
                       family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None,
                       suppress_ragged_eofs=True, npn_protocols=None, ciphers=None,
                       server_hostname=None,
                       _context=None):
    7. vstinner commented on Sep 8, 2016

      @vstinner
      Member

      I like the idea of using SSLContext as the obvious and only choice to
      "configure" SSL.

    8. tiran commented on Sep 8, 2016

      @tiran
      MemberAuthor

      memo to me: check if SSLContext.wrap_socket() can deal with a fileno as sock argument.

    9. tiran commented on Sep 8, 2016

      @tiran
      MemberAuthor
    10. vadmium commented on Sep 9, 2016

      @vadmium
      Member

      urllib.request.urlopen() should be affected too right?

    11. orsenthil commented on Sep 9, 2016

      @orsenthil
      Member

      Yes, urllib.request.urlopen needs an update too. It takes those certfile and keyfile and usage of those could be deprecated in favor of context.

    12. tiran commented on Sep 9, 2016

      @tiran
      MemberAuthor

      I have deprecated cafile, capath and cadefault for urlopen(). The function didn't pop up on my radar because I was looking for certfile and cert_file, not cafile. I also added deprecations to the documentation of SSLSocket.read and write.

    13. 10 remaining items

    14. tiran commented on Sep 11, 2016

      @tiran
      MemberAuthor

      The performance benefit is not worth the risk. For 10 httplib requests to pypi.python.org, a shared SSLContext is about 5% faster than a new context for each request. Session resumption improves the simple test case by another 20%.

    15. ncoghlan commented on Sep 11, 2016

      @ncoghlan
      Contributor

      Leaving the option of context caching entirely to the caller would definitely make things simpler - my main interest is just in avoiding a hard compatibility break for folks that aren't doing anything particularly wrong, by which I mean specifically cases where a wrap_socket() implementation like this one would continue to work for them:

          def wrap_socket(sock, *args, *kwds):
              return ssl.get_default_context().wrap_socket(sock, *args, **kwds)
    16. vadmium commented on Sep 11, 2016

      @vadmium
      Member

      New test failure when using -Werror:

      ======================================================================
      ERROR: test_local_bad_hostname (test.test_httplib.HTTPSTest)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "/media/disk/home/proj/python/cpython/Lib/test/test_httplib.py", line 1646, in test_local_bad_hostname
          check_hostname=True)
        File "/media/disk/home/proj/python/cpython/Lib/http/client.py", line 1373, in __init__
          DeprecationWarning, 2)
      DeprecationWarning: key_file, cert_file and check_hostname are deprecated, use a custom context instead.
    17. python-dev commented on Sep 11, 2016

      python-devmannequin
      Mannequin

      New changeset 2e541e994927 by Christian Heimes in branch 'default':
      bpo-28022: Catch deprecation warning in test_httplib, reported by Martin Panter
      https://hg.python.org/cpython/rev/2e541e994927

    18. tiran commented on Sep 11, 2016

      @tiran
      MemberAuthor

      Thanks for the report. "./python -Werror -m test -uall test_httplib" is now passing for me.

    19. serhiy-storchaka commented on Sep 11, 2016

      @serhiy-storchaka
      Member

      test_imaplib is failed too.

      ======================================================================
      ERROR: test_logincapa_with_client_certfile (test.test_imaplib.RemoteIMAP_SSLTest)
      ----------------------------------------------------------------------

      Traceback (most recent call last):
        File "/home/serhiy/py/cpython-debug/Lib/test/test_imaplib.py", line 641, in test_logincapa_with_client_certfile
          _server = self.imap_class(self.host, self.port, certfile=CERTFILE)
        File "/home/serhiy/py/cpython-debug/Lib/imaplib.py", line 1273, in __init__
          "custom ssl_context instead", DeprecationWarning, 2)
      DeprecationWarning: keyfile and certfile are deprecated, use acustom ssl_context instead

    20. python-dev commented on Sep 11, 2016

      python-devmannequin
      Mannequin

      New changeset 57e88d1159fc by Christian Heimes in branch 'default':
      Issue bpo-28022: Catch another deprecation warning in imaplib
      https://hg.python.org/cpython/rev/57e88d1159fc

    21. serhiy-storchaka commented on Oct 22, 2017

      @serhiy-storchaka
      Member

      Shouldn't this issue be closed?

      Since SSL context arguments are not supported in 2.7, the deprecated arguments can't be removed until EOL of 2.7.

    22. added and removed on Oct 21, 2020
    23. kousu commented on Aug 8, 2021

      kousumannequin
      Mannequin

      Hello everyone, and thank you as usual for all your hard work keeping the python ecosystem going.

      I saw that the start of this thread said it was going to

      • make ftplib, imaplib, nntplib, pop3lib, smtplib etc. validate certs by default.

      but this hasn't been done, at least not for imaplib. imaplib is still calling the undocumented "ssl._create_stdlib_context":

      ssl_context = ssl._create_stdlib_context(certfile=certfile,

      which is actually "ssl._create_unverified_context":

      _create_stdlib_context = _create_unverified_context

      which is indeed unverified: despite defaulting to PROTOCOL_TLS_CLIENT, which "enables CERT_REQUIRED and check_hostname by default.", it overrides that by setting check_hostname=False:

      context.check_hostname = check_hostname

      To demonstrate, check out this tester script:

      $ cat a.py 
      import os, imaplib
      with imaplib.IMAP4_SSL(os.environ.get('HOSTNAME')) as S: 
          print(S.login(os.environ.get('USERNAME'), os.environ.get('PASSWORD')))
      $ HOSTNAME=46.23.90.174 USERNAME=test1 PASSWORD=test1test1 python3 a.py 
      ('OK', [b'Logged in'])

      I don't have a cert for 46.23.90.174 (no one will give out certs for IPs!), so this is wrong!

      In order to actually enable verification you need to know the incantation. It's not that long but it is subtle and frighteningly easy to get wrong. Here it is:

      $ cat a.py 
      import os, ssl, imaplib
      ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
      ctx.load_default_certs()
      
      with imaplib.IMAP4_SSL(os.environ.get('HOSTNAME'), ssl_context=ctx) as S: 
          print(S.login(os.environ.get('USERNAME'), os.environ.get('PASSWORD')))
      $ HOSTNAME=46.23.90.174 USERNAME=test1 PASSWORD=test1test1 python3 a.py 
      Traceback (most recent call last):
        File "a.py", line 6, in <module>
          with imaplib.IMAP4_SSL(os.environ.get('HOSTNAME'), ssl_context=ctx) as S: 
        File "/usr/lib/python3.6/imaplib.py", line 1288, in __init__
          IMAP4.__init__(self, host, port)
        File "/usr/lib/python3.6/imaplib.py", line 198, in __init__
          self.open(host, port)
        File "/usr/lib/python3.6/imaplib.py", line 1301, in open
          IMAP4.open(self, host, port)
        File "/usr/lib/python3.6/imaplib.py", line 299, in open
          self.sock = self._create_socket()
        File "/usr/lib/python3.6/imaplib.py", line 1293, in _create_socket
          server_hostname=self.host)
        File "/usr/lib/python3.6/ssl.py", line 407, in wrap_socket
          _context=self, _session=session)
        File "/usr/lib/python3.6/ssl.py", line 817, in __init__
          self.do_handshake()
        File "/usr/lib/python3.6/ssl.py", line 1077, in do_handshake
          self._sslobj.do_handshake()
        File "/usr/lib/python3.6/ssl.py", line 694, in do_handshake
          match_hostname(self.getpeercert(), self.server_hostname)
        File "/usr/lib/python3.6/ssl.py", line 327, in match_hostname
          % (hostname, ', '.join(map(repr, dnsnames))))
      ssl.CertificateError: hostname '46.23.90.174' doesn't match either of 'comms.kousu.ca', 'comms3.kousu.ca'

      I can see from this thread there were some concerns about breaking people's self-signed certs back in 2016. But it's five years later now and letsencrypt is super common now, and most servers and clients are enforcing TLS, especially when credentials are involved.

      Could this be revisited?

      Thanks for any attention you have gifted to this :)

    24. tiran commented on Aug 8, 2021

      @tiran
      MemberAuthor

      The part with "make ftplib, imaplib, nntplib, pop3lib, smtplib etc. validate certs by default" was not implemented. These modules still default to unverified connections.

    25. transferred this issue fromon Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    3.10 (EOL)end of lifedocsDocumentation in the Doc dirstdlibStandard Library Python modules in the Lib/ directorytopic-SSLtype-securityA security issue

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions