Juan Hernandez has uploaded a new change for review.

Change subject: sdk: Check SSL server certificate
......................................................................

sdk: Check SSL server certificate

Currently we don't check that the host name provided in the URL matches
the host name contained in the server certificate. This is a common
feature of most SSL clients, but it isn't well supported by the SSL
implementation in Python 2.6. To improve security this patch explicitly
checks the host name given in the URL against the subject common name
attribute and the subject alternative names extension. This check will
be enabled by default and disabled when using "insecure=True" in the
constructor of the entry point object.

Change-Id: I6a08179288fd564fbb79f5731c3e32251e560d81
Signed-off-by: Juan Hernandez <juan.hernan...@redhat.com>
---
M src/ovirtsdk/web/connection.py
M src/ovirtsdk/web/httpsconnection.py
2 files changed, 59 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine-sdk refs/changes/71/26271/1

diff --git a/src/ovirtsdk/web/connection.py b/src/ovirtsdk/web/connection.py
index 5bd84d7..646f36b 100644
--- a/src/ovirtsdk/web/connection.py
+++ b/src/ovirtsdk/web/connection.py
@@ -233,7 +233,8 @@
                        cert_file=cert_file,
                        ca_file=ca_file,
                        strict=strict,
-                       timeout=timeout
+                       timeout=timeout,
+                       insecure=insecure
                    )
         return HTTPConnection(
                   host=u.hostname,
diff --git a/src/ovirtsdk/web/httpsconnection.py 
b/src/ovirtsdk/web/httpsconnection.py
index 4d60b34..8ec8d4a 100644
--- a/src/ovirtsdk/web/httpsconnection.py
+++ b/src/ovirtsdk/web/httpsconnection.py
@@ -15,6 +15,7 @@
 #
 
 import httplib
+import re
 import socket
 import ssl
 
@@ -26,10 +27,12 @@
     '''
 
     def __init__(self, host, port=None, key_file=None, cert_file=None, 
ca_file=None,
-                 strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
+                 strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+                 insecure=False):
         httplib.HTTPSConnection.__init__(self, host=host, port=port, 
key_file=key_file,
                                          cert_file=cert_file, strict=strict, 
timeout=timeout)
         self.ca_file = ca_file
+        self.insecure = insecure
 
     def connect(self):
         '''
@@ -58,3 +61,56 @@
                 self.cert_file,
                 cert_reqs=ssl.CERT_NONE
             )
+
+        # Check that the host name contained in the URL matches at least one of
+        # the host names contained in the server certificate:
+        if not self.insecure:
+            self.__check_hostname()
+
+    def __check_hostname(self):
+        # Get the names contained in the common name and in the subject
+        # alternative names of the certificate:
+        hostnames = self.__get_certificate_hosts()
+
+        # Transform each name into a pattern taking into account
+        # that they can be wildcard names:
+        patterns = []
+        for hostname in hostnames:
+            pattern = None
+            if hostname.startswith("*."):
+                pattern = "[^.]+" + re.escape(hostname[1:])
+            else:
+                pattern = re.escape(hostname)
+            pattern = "^" + pattern + "$"
+            patterns.append(pattern)
+
+        # Check if the host name matches any of the patterns:
+        for pattern in patterns:
+            if re.match(pattern, self.host, flags=re.IGNORECASE):
+                return
+        raise httplib.HTTPException("The host name \"%s\" contained in the "
+                "URL doesn't match any of the DNS names in the server "
+                "certificate." % self.host)
+
+    def __get_certificate_hosts(self):
+        hosts = []
+
+        # Get the server certificate:
+        certificate = self.sock.getpeercert()
+
+        # Get the common name:
+        names = certificate.get("subject")
+        if names is not None:
+            for rdn in names:
+                for key, value in rdn:
+                    if key == "commonName":
+                        hosts.append(value)
+
+        # Get the DNS subject alternative names:
+        names = certificate.get("subjectAltName")
+        if names is not None:
+            for key, value in names:
+                if key == "DNS":
+                    hosts.append(value)
+
+        return hosts


-- 
To view, visit http://gerrit.ovirt.org/26271
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6a08179288fd564fbb79f5731c3e32251e560d81
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine-sdk
Gerrit-Branch: master
Gerrit-Owner: Juan Hernandez <juan.hernan...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to