Package: s3cmd Version: 1.5.0~rc1-2 Severity: important Tags: patch upstream
When running on a bucket like "foo.luke.wf", s3cmd will print an error like this: WARNING: Retrying failed request: /?prefix=ops/ (hostname 'foo.luke.wf.s3.amazonaws.com' doesn't match either of '*.s3.amazonaws.com', 's3.amazonaws.com') Fixed upstream in https://github.com/s3tools/s3cmd/commit/ecee692cbc355f775508b7d769493a3b56f12656 -- System Information: Debian Release: 8.0 APT prefers unstable APT policy: (500, 'unstable') Architecture: amd64 (x86_64) Kernel: Linux 3.19.0-10-generic (SMP w/8 CPU cores) Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968) Shell: /bin/sh linked to /bin/dash Init: unable to detect Versions of packages s3cmd depends on: ii python-dateutil 2.2-2 pn python:any <none> Versions of packages s3cmd recommends: ii python-magic 1:5.22+15-2 s3cmd suggests no packages. -- no debconf information
>From ecee692cbc355f775508b7d769493a3b56f12656 Mon Sep 17 00:00:00 2001 From: Matt Domsch <[email protected]> Date: Thu, 15 Jan 2015 10:42:42 -0600 Subject: [PATCH] fix S3 wildcard certificate checking First, the implementation had a bug, and did not actually disable the ssl.match_hostname() check like we originally believed, because the change to the context.check_hostname=False flag occurred too late. Second, we want to do the hostname checking ourselves, so we can continue when presented with an S3 wildcard certificate. We invoke the SSLContext.match_hostname() function for all connections, and if it fails, we check if we're actually looking at an S3 wildcard certificate and communicating with an S3 host. If so, this is permissible. If not, we fail the connection immediately. This should resolve the concern over disabling SSL certificate hostname checking. This patch was backported from upstream to apply on the packaged version by Luke Faraone <[email protected]>. --- S3/ConnMan.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) --- a/S3/ConnMan.py +++ b/S3/ConnMan.py @@ -8,6 +8,7 @@ from urlparse import urlparse from threading import Semaphore from logging import debug, info, warning, error +import ssl as ssllib from Config import Config from Exceptions import ParameterError @@ -25,7 +26,36 @@ elif not ssl: self.c = httplib.HTTPConnection(hostname) else: - self.c = httplib.HTTPSConnection(hostname) + context = ssllib.create_default_context() + # S3's wildcart certificate doesn't work with DNS-style named buckets. + if hostname.endswith('.amazonaws.com') and context: + # this merely delays running the hostname check until + # after the connection is made and we get control + # back. We then run the same check, relaxed for S3's + # wildcard certificates. + context.check_hostname = False + self.c = httplib.HTTPSConnection(hostname, context=context) + + + + @staticmethod + def match_hostname_aws(cert, hostname, e): + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if value.startswith('*.s3') and value.endswith('.amazonaws.com') and hostname.endswith('.amazonaws.com'): + return + raise e + + @staticmethod + def match_hostname(conn): + cert = conn.c.sock.getpeercert() + hostname = conn.c.sock.server_hostname + try: + ssllib.match_hostname(cert, hostname) + except ssllib.CertificateError, e: + http_connection.match_hostname_aws(cert, hostname, e) + class ConnMan(object): conn_pool_sem = Semaphore() @@ -55,6 +85,8 @@ debug("ConnMan.get(): creating new connection: %s" % conn_id) conn = http_connection(conn_id, hostname, ssl, cfg) conn.c.connect() + if conn.ssl: + http_connection.match_hostname(conn) conn.counter += 1 return conn

