Fix hostname validation in the SSL verification code (CVE-2012-3446). Reported by researchers
from the University of Texas at Austin (Martin Georgiev, Suman Jana and Vitaly Shmatikov).
For more info, see http://libcloud.apache.org/security.html.
git-svn-id: https://svn.apache.org/repos/asf/libcloud/branches/0.11.x@1368323 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/CHANGES b/CHANGES
index 9e9b4c5..ad39981 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,14 @@
-*- coding: utf-8 -*-
+Changes with Apache Libcloud 0.11.1:
+
+ *) General
+
+ - Fix hostname validation in the SSL verification code (CVE-2012-3446).
+
+ Reported by researchers from the University of Texas at Austin (Martin
+ Georgiev, Suman Jana and Vitaly Shmatikov).
+
Changes with Apache Libcloud 0.11.0:
*) Compute
@@ -139,7 +148,7 @@
CloudFiles driver.
[Tomaz Muraus]
- - Fix a bug with content_type and and encoding of object and path names in
+ - Fix a bug with content_type and and encoding of object and path names in
the Atmos driver.
[Russell Keith-Magee]
@@ -234,7 +243,7 @@
- Add ex_rescue and ex_unrescue method to OpenStack 1.1 driver. ;
LIBCLOUD-193
- [Shawn Smith]
+ [Shawn Smith]
- Include 'password' in the node extra dictionary when calling deploy_node
if the password auth is used.
@@ -419,7 +428,7 @@
- Enable ex_delete_image method in the OpenStack 1.1 driver.
[Shawn Smith]
- - Return NodeImage instance in OpenStack 1.1 driver ex_save_image method
+ - Return NodeImage instance in OpenStack 1.1 driver ex_save_image method
; LIBCLOUD-138
[Shawn Smith]
diff --git a/libcloud/__init__.py b/libcloud/__init__.py
index ed68165..a3421fd 100644
--- a/libcloud/__init__.py
+++ b/libcloud/__init__.py
@@ -20,7 +20,7 @@
"""
__all__ = ['__version__', 'enable_debug']
-__version__ = '0.11.0'
+__version__ = '0.11.1'
try:
import paramiko
diff --git a/libcloud/httplib_ssl.py b/libcloud/httplib_ssl.py
index 012e191..8e6cf56 100644
--- a/libcloud/httplib_ssl.py
+++ b/libcloud/httplib_ssl.py
@@ -122,13 +122,8 @@
# replace * with alphanumeric and dash
# replace . with literal .
valid_patterns = [
- re.compile(
- pattern.replace(
- r".", r"\."
- ).replace(
- r"*", r"[0-9A-Za-z]+"
- )
- )
+ re.compile('^' + pattern.replace(r".", r"\.") \
+ .replace(r"*", r"[0-9A-Za-z]+") + '$')
for pattern in (set(common_name) | set(alt_names))]
return any(
diff --git a/libcloud/test/test_httplib_ssl.py b/libcloud/test/test_httplib_ssl.py
index 6c8d48e..dbbe866 100644
--- a/libcloud/test/test_httplib_ssl.py
+++ b/libcloud/test/test_httplib_ssl.py
@@ -45,16 +45,49 @@
'subjectAltName': ((('DNS', 'foo.alt.name')),
(('DNS', 'foo.alt.name.1')))}
+ cert3 = {'notAfter': 'Feb 16 16:54:50 2013 GMT',
+ 'subject': ((('countryName', 'US'),),
+ (('stateOrProvinceName', 'Delaware'),),
+ (('localityName', 'Wilmington'),),
+ (('organizationName', 'Python Software Foundation'),),
+ (('organizationalUnitName', 'SSL'),),
+ (('commonName', 'python.org'),))}
+
self.assertFalse(self.httplib_object._verify_hostname(
hostname='invalid', cert=cert1))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='machine.python.org', cert=cert1))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='foomachine.python.org', cert=cert1))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='somesomemachine.python.org', cert=cert1))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='somemachine.python.orga', cert=cert1))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='somemachine.python.org.org', cert=cert1))
self.assertTrue(self.httplib_object._verify_hostname(
hostname='somemachine.python.org', cert=cert1))
self.assertFalse(self.httplib_object._verify_hostname(
hostname='invalid', cert=cert2))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='afoo.alt.name.1', cert=cert2))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='a.foo.alt.name.1', cert=cert2))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='foo.alt.name.1.2', cert=cert2))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='afoo.alt.name.1.2', cert=cert2))
self.assertTrue(self.httplib_object._verify_hostname(
hostname='foo.alt.name.1', cert=cert2))
+ self.assertTrue(self.httplib_object._verify_hostname(
+ hostname='python.org', cert=cert3))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='opython.org', cert=cert3))
+ self.assertFalse(self.httplib_object._verify_hostname(
+ hostname='ython.org', cert=cert3))
+
def test_get_subject_alt_names(self):
cert1 = {'notAfter': 'Feb 16 16:54:50 2013 GMT',
'subject': ((('countryName', 'US'),),