Bug 1284930 - [PATCH] Latest ssl.py breaks certificate validation for wildcard domains, e.g. *.s3.amazonaws.com
Summary: [PATCH] Latest ssl.py breaks certificate validation for wildcard domains, e.g...
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Software Collections
Classification: Red Hat
Component: python33
Version: devassist09
Hardware: Unspecified
OS: Unspecified
low
low
Target Milestone: rc
: ---
Assignee: Python Maintainers
QA Contact: BaseOS QE - Apps
URL:
Whiteboard:
Depends On: 1284916
Blocks:
TreeView+ depends on / blocked
 
Reported: 2015-11-24 13:27 UTC by Alexander Todorov
Modified: 2015-11-24 15:01 UTC (History)
6 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of: 1284916
Environment:
Last Closed: 2015-11-24 14:51:39 UTC
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Python 25722 0 None None None Never

Description Alexander Todorov 2015-11-24 13:27:23 UTC
Filing here for Python3 with updated steps to reproduce and updated patch.

+++ This bug was initially created as a clone of Bug #1284916 +++

Description of problem:

The latest ssl.py file tries to validate hostnames vs certificates but includes a faulty regexp which causes any wildcard domains (e.g. *.s3.amazonaws.com) to fail validation. 

Version-Release number of selected component (if applicable):
python3-libs-3.3.0-1.el7.x86_64

How reproducible:
Always

Steps to Reproduce:

>>> import ssl
>>> ssl._dnsname_to_pat("*.s3.amazonaws.com").match("planet.sofiavalley.com.s3.amazonaws.com")
>>>

Actual results:


Expected results:
<_sre.SRE_Match object at 0x1474030> - the function should match the provided domain and hostname.

Additional info:

The following patch fixes the issue:

--- ssl.py.orig	2015-11-24 15:22:37.392416265 +0200
+++ ssl.py	2015-11-24 15:24:48.253470872 +0200
@@ -135,7 +135,7 @@
         if frag == '*':
             # When '*' is a fragment by itself, it matches a non-empty dotless
             # fragment.
-            pats.append('[^.]+')
+            pats.append('^.+')
         else:
             # Otherwise, '*' matches any dotless fragment.
             frag = re.escape(frag)


From Python's documentation:

[]

    Used to indicate a set of characters. In a set:

...
        Special characters lose their special meaning inside sets. For example, [(+*)] will match any of the literal characters '(', '+', '*', or ')'.

^^^^^^^^^ this is the cause of the error

Comment 1 Christian Heimes 2015-11-24 14:02:30 UTC
The Python ssl module behaves correctly and as designed. Since recently it conforms to RFC 6125 section 6.4.3. (https://tools.ietf.org/html/rfc6125#section-6.4.3). The RFC restricts wildcards in several ways. Most importantly only one wildcard on the left-most label is supported. The suggested fix will break RFC 6125 compatibility and introduce a security bug.

By the way I'm a Python core committer, maintainer of the SSL module and the person that made the SSL module RFC 6125 conform. I closed the upstream issue https://bugs.python.org/issue25722 

I've seen multiple people complaining about cert validation errors with AWS certs. AWS violates standards here. You have to roll your own custom host name verification in order to validate AWS certs.

Comment 2 Alexander Todorov 2015-11-24 14:47:09 UTC
Christian,
indeed you are right, sorry for the false alarm. I've managed to track down the issue further. There's also a change in httplib.py and the calling code wasn't aware of that. I've managed to create a fix for the caller:
https://github.com/s3tools/s3cmd/pull/668

Probably this one should be closed.

Comment 3 Christian Heimes 2015-11-24 14:56:15 UTC
You are welcome!

Your fix in https://github.com/s3tools/s3cmd/pull/668/files is dangerous and insecure. It allows MITM attacks on the connection. All it takes is a valid X.509 certificate that is signed by a trusted root CA. Without hostname checks your code will trust a certificate for e.g. www.example.com.

You must add additional checks, e.g. for Subject CN and X509v3 SAN field.

Comment 4 Alexander Todorov 2015-11-24 15:01:57 UTC
For the record:

There are custom hostname checks that conform to the AWS behavior, see match_hostname_aws() on line 74 in ConnMan.py. It's executed later in the code, after the connection has been established. I've only made sure that stock validation doesn't execute and blow things up on line 180.


Originally I hit the exception at line 180, you see the custom check performed on line 182:

    180             conn.c.connect()
    181             if conn.ssl and cfg.check_ssl_certificate and cfg.check_ssl_hostname:
    182                 conn.match_hostname()


Note You need to log in before you can comment on or make changes to this bug.