[NEW PATCH] Replace m2crypto with python's standard ssl (via gerrit-bot)
Dan Kenigsberg
danken at redhat.com
Wed Sep 14 20:01:01 UTC 2011
New patch submitted by Dan Kenigsberg (danken at redhat.com)
You can review this change at: http://gerrit.usersys.redhat.com/797
commit 77f5eccd6b427e94bfe72452b51fd44365470c0d
Author: Dan Kenigsberg <danken at redhat.com>
Date: Fri Oct 1 15:43:43 2010 +0200
Replace m2crypto with python's standard ssl
Change-Id: Ie2162f72c914dc6c7832ca2951bbf151ed058859
diff --git a/vdsm.spec.in b/vdsm.spec.in
index f1a3473..e076cd8 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -18,7 +18,7 @@ Requires: python which
Requires: sudo >= 1.7.3
Requires: qemu-kvm
Requires: qemu-img >= 2:0.12.1.2-2.172
-Requires: m2crypto ethtool logrotate
+Requires: ethtool logrotate
Requires: iscsi-initiator-utils >= 6.2.0.872-15
Requires: nfs-utils dmidecode
Requires: lvm2 >= 2.02.72-8.el6_0.4
@@ -181,7 +181,6 @@ Used by the trained monkeys at Red Hat to insert chaos and mayhem in to VDSM
%package cli
Summary: VDSM command line interface
Group: Applications/System
-Requires: m2crypto
%description cli
Call VDSM commands from the command line. Used for testing and debugging.
@@ -372,7 +371,8 @@ machines without running real guests.
%{_sysconfdir}/bash_completion.d/vdsClient
%{_datadir}/%{vdsm_name}/vdscli.py*
%{_datadir}/%{vdsm_name}/dumpStorageTable.py*
-%{_bindir}/vdsClient
+%{_datadir}/%{vdsm_name}/SecureXMLRPCServer.py*
+%attr (755,root,root) %{_bindir}/vdsClient
%{_mandir}/man1/vdsClient.1*
%files bootstrap
diff --git a/vdsm/SecureXMLRPCServer.py b/vdsm/SecureXMLRPCServer.py
index c092296..3fbecc8 100644
--- a/vdsm/SecureXMLRPCServer.py
+++ b/vdsm/SecureXMLRPCServer.py
@@ -1,5 +1,4 @@
# Copyright 2008 Red Hat, Inc. and/or its affiliates.
-# Copyright 2001 Brian Quinlan.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -7,7 +6,7 @@
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
-#
+#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
@@ -28,106 +27,133 @@
"""SecureXMLRPCServer.py - simple XML RPC server supporting SSL.
-
-Based on this article: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81549
-
-For windows users: http://webcleaner.sourceforge.net/pyOpenSSL-0.6.win32-py2.4.exe
"""
-import SocketServer
-import BaseHTTPServer
import SimpleXMLRPCServer
-
+import xmlrpclib
+import ssl
+import httplib
import socket
-from M2Crypto import SSL
-
-class PoliteSSLConnection(SSL.Connection):
-
- def gettimeout(self):
- return self.socket.gettimeout()
-
- def accept(self):
- """Do a simple tcp accept only"""
- sock, addr = self.socket.accept()
- return PoliteSSLConnection(self.ctx, sock), addr
-
- def _finish_accept_ssl(self, sock, addr):
- """Finish ssl accept (possibly on a new thread)
- Code based on accept() of M2Crypto/SSL/Connection.py 0.18-2"""
- sock.addr = addr
- sock.setup_ssl()
- sock.set_accept_state()
- # Here is the change from M2Crpyto's code.
- # make sure sock.accept_ssl() does not block if self in nonblocking.
- sock.settimeout(self.socket.gettimeout())
- # On exception, I'm being nice to my peer (possible attacker?) and
- # close his socket.
- try:
- sock.accept_ssl()
- check = getattr(self, 'postConnectionCheck', self.serverPostConnectionCheck)
- if check is not None:
- if not check(self.get_peer_cert(), sock.addr[0]):
- raise SSL.Checker.SSLVerificationError, 'post connection check failed'
- except Exception, e:
- e.addr = addr
- sock.close()
- raise
- return sock, addr
-
-class SecureXMLRpcRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- """Secure XML-RPC request handler class.
-
- It it very similar to SimpleXMLRPCRequestHandler but it uses HTTPS for transporting XML data.
- """
- wbufsize = -1
-
- def do_POST(self):
- """Handles the HTTPS POST request."""
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
- # I dont understand why the inherited
- # self.connection.shutdown(SSL_SENT_SHUTDOWN) without .close()
- # makes me hang
- self.connection.shutdown(0)
- self.connection.close()
-
-class SecureXMLRPCServer(BaseHTTPServer.HTTPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
- def __init__(self, server_address, keyFile, certFile, caCert,
- logRequests=False, timeout=None, requestHandler=SecureXMLRpcRequestHandler):
- """Secure XML-RPC server.
-
- It it very similar to SimpleXMLRPCServer but it uses HTTPS for transporting XML data.
- """
- self.logRequests = logRequests
-
- try:
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self, False, None)
- except TypeError:
- # older versions of SimpleXMLRPCServer had a different API
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
-
- SocketServer.BaseServer.__init__(self, server_address, requestHandler)
- ctx = SSL.Context()
-
- ctx.load_cert_chain(certFile, keyFile)
-
- ctx.set_client_CA_list_from_file(caCert)
- ctx.load_verify_info(caCert)
-
- ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 10)
- ctx.set_session_id_ctx ('vdsm-ssl')
- self.socket = PoliteSSLConnection(ctx, socket.socket(
- self.address_family, self.socket_type))
- self.socket.settimeout(timeout)
- self.server_bind()
- self.server_activate()
+import SocketServer
+
+class VerificationError(RuntimeError): pass
+
+def verify_commonName(sock, name):
+ """Verify that commonName field in peer's certiface matches peer's address"""
+
+ cert = sock.getpeercert()
+ if not cert:
+ raise VerificationError('peer gave no certificate')
+
+ cn = dict([ rdn[0] for rdn in cert['subject'] ])['commonName']
+ try:
+ hosts = socket.gethostbyname_ex(cn)[2]
+ except:
+ hosts = []
+ if name not in hosts + [cn]:
+ raise VerificationError('peer %s does not match its commonName %s'
+ % (name, cn))
+
+SecureXMLRPCRequestHandler = SimpleXMLRPCServer.SimpleXMLRPCRequestHandler
+
+class SecureXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
+ def __init__(self, addr,
+ requestHandler=SimpleXMLRPCServer.SimpleXMLRPCRequestHandler,
+ logRequests=True, allow_none=False, encoding=None,
+ bind_and_activate=True,
+ keyfile=None, certfile=None, ca_certs=None):
+ """Initialize a SimpleXMLRPCServer instance but wrap its .socket member with ssl."""
+
+ SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, addr,
+ requestHandler,
+ logRequests, allow_none, encoding,
+ bind_and_activate=False)
+ self.socket = ssl.wrap_socket(self.socket,
+ keyfile=keyfile, certfile=certfile,
+ ca_certs=ca_certs, server_side=True,
+ cert_reqs=ssl.CERT_REQUIRED,
+ do_handshake_on_connect=False)
+ if bind_and_activate:
+ self.server_bind()
+ self.server_activate()
def finish_request(self, request, client_address):
- """Finish one request by doing ssl handshake and instantiating RequestHandlerClass."""
- request, client_address = self.socket._finish_accept_ssl(request, client_address)
- self.RequestHandlerClass(request, client_address, self)
+ request.do_handshake()
+
+ if self._verifyCommonName:
+ verify_commonName(request, client_address[0])
+
+ return SimpleXMLRPCServer.SimpleXMLRPCServer.finish_request(self, request,
+ client_address)
+
+ def handle_error(self, request, client_address):
+ import logging
+ logging.error('client %s', client_address, exc_info=True)
+
+
+class SecureThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
+ SecureXMLRPCServer): pass
+
+class VerifyingHTTPSConnection(httplib.HTTPSConnection):
+ def __init__(self, host, port=None, key_file=None, cert_file=None,
+ strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+ ca_certs=None, cert_reqs=ssl.CERT_REQUIRED):
+ httplib.HTTPSConnection.__init__(self, host, port, key_file, cert_file,
+ strict, timeout)
+ self.ca_certs = ca_certs
+ self.cert_reqs = cert_reqs
+
+ def connect(self):
+ "Connect to a host on a given (SSL) port."
+
+ sock = socket.create_connection((self.host, self.port), self.timeout)
+ if self._tunnel_host:
+ self.sock = sock
+ self._tunnel()
+ # DK added: pass ca_cert to sslsocket
+ self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
+ ca_certs=self.ca_certs, server_side=False,
+ cert_reqs=self.cert_reqs)
+ verify_commonName(self.sock, self.host)
+
+class VerifyingSafeTransport(xmlrpclib.SafeTransport):
+ def __init__(self, use_datetime=0, key_file=None, cert_file=None,
+ ca_certs=None, cert_reqs=ssl.CERT_REQUIRED):
+ xmlrpclib.SafeTransport.__init__(self, use_datetime)
+ self.key_file = key_file
+ self.cert_file = cert_file
+ self.ca_certs = ca_certs
+ self.cert_reqs = cert_reqs
+
+ def make_connection(self, host):
+ """Return VerifyingHTTPS object that is aware of ca_certs, and will create VerifyingHTTPSConnection"""
+ chost, self._extra_headers, x509 = self.get_host_info(host)
+ return VerifyingHTTPS(
+ chost, None, key_file=self.key_file,
+ cert_file=self.cert_file, ca_certs=self.ca_certs,
+ cert_reqs=self.cert_reqs)
+
+
+class VerifyingHTTPS(httplib.HTTPS):
+ _connection_class = VerifyingHTTPSConnection
+
+ def __init__(self, host='', port=None, key_file=None, cert_file=None,
+ strict=None, ca_certs=None, cert_reqs=ssl.CERT_REQUIRED):
+ """A ca_cert-aware HTTPS object, that creates a VerifyingHTTPSConnection"""
+ # provide a default host, pass the X509 cert info
+
+ # urf. compensate for bad input.
+ if port == 0:
+ port = None
+ self._setup(self._connection_class(host, port, key_file,
+ cert_file, strict, ca_certs=ca_certs,
+ cert_reqs=cert_reqs))
+
+ # we never actually use these for anything, but we keep them
+ # here for compatibility with post-1.5.2 CVS.
+ self.key_file = key_file
+ self.cert_file = cert_file
-class SecureThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SecureXMLRPCServer):
- pass
class __Test(object):
"""Self-signed key, generated with
@@ -141,40 +167,25 @@ class __Test(object):
def server(self):
"""Test xml rpc over https server"""
class xmlrpc_registers:
- def __init__(self):
- import string
- self.python_string = string
-
def add(self, x, y):
return x + y
- def mult(self,x,y):
- return x*y
-
- def div(self,x,y):
- return x//y
-
def wait(self):
import time
time.sleep(10)
return 1
- server = SecureThreadedXMLRPCServer((self.host, self.port), self.KEYFILE, self.CERTFILE, self.CACERT)
+ server = SecureXMLRPCServer((self.host, self.port),
+ keyfile=self.KEYFILE, certfile=self.CERTFILE, ca_certs=self.CACERT)
server.register_instance(xmlrpc_registers())
print "Serving HTTPS on", self.host, "port", self.port
server.serve_forever()
def client(self):
- from M2Crypto.m2xmlrpclib import Server, SSL_Transport
- from M2Crypto import SSL
-
- ctx = SSL.Context()
-
- ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 16)
- ctx.load_verify_locations(self.CACERT)
- ctx.load_cert(self.CERTFILE, self.KEYFILE)
-
- s = Server('https://%s:%s' % (self.host, self.port), SSL_Transport(ctx))
+ vtransport=VerifyingSafeTransport(key_file=self.KEYFILE,
+ cert_file=self.CERTFILE, ca_certs=self.CACERT)
+ s = xmlrpclib.ServerProxy('https://%s:%s' % (self.host, self.port),
+ transport=vtransport)
print s.add(2, 3)
if __name__ == '__main__':
diff --git a/vdsm/clientIF.py b/vdsm/clientIF.py
index 241a86a..e6ef62f 100644
--- a/vdsm/clientIF.py
+++ b/vdsm/clientIF.py
@@ -32,8 +32,6 @@ import SimpleXMLRPCServer
from xml.dom import minidom
import uuid
-import M2Crypto.threading
-
from storage.dispatcher import StorageDispatcher
import storage.misc
import storage.hba
@@ -219,15 +217,14 @@ class clientIF:
server_address = (self.serverIP, int(self.serverPort))
if config.getboolean('vars', 'ssl'):
- class LoggingHandler(LoggingMixIn, SecureXMLRPCServer.SecureXMLRpcRequestHandler):
+ class LoggingHandler(LoggingMixIn, SecureXMLRPCServer.SecureXMLRPCRequestHandler):
def setup(self):
cif.threadLocal.client = self.client_address[0]
- return SecureXMLRPCServer.SecureXMLRpcRequestHandler.setup(self)
- M2Crypto.threading.init()
+ return SecureXMLRPCServer.SecureXMLRPCRequestHandler.setup(self)
KEYFILE, CERTFILE, CACERT = self.getKeyCertFilenames()
s = SecureXMLRPCServer.SecureThreadedXMLRPCServer(server_address,
KEYFILE, CERTFILE, CACERT,
- timeout=config.getint('vars', 'vds_responsiveness_timeout'),
+# timeout=config.getint('vars', 'vds_responsiveness_timeout'),
requestHandler=LoggingHandler)
utils.closeOnExec(s.socket.socket.fileno())
else:
diff --git a/vdsm/vm.py b/vdsm/vm.py
index 8a87db6..f270e34 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -117,17 +117,9 @@ class MigrationSourceThread(threading.Thread):
except:
pass
if config.getboolean('vars', 'ssl'):
- from M2Crypto import SSL
-
- KEYFILE, CERTFILE, CACERT = self._vm.cif.getKeyCertFilenames()
-
- ctx = SSL.Context()
- ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 16)
- ctx.load_verify_locations(CACERT)
- ctx.load_cert(CERTFILE, KEYFILE)
-
+ import vdscli
serverAddress = 'https://' + self.remoteHost + ':' + self.remotePort
- self.destServer = kaxmlrpclib.SslServer(serverAddress, ctx)
+ self.destServer = vdscli.connect(serverAddress, useSSL=True)
else:
serverAddress = 'http://' + self.remoteHost + ':' + self.remotePort
self.destServer = kaxmlrpclib.Server(serverAddress)
diff --git a/vdsm_cli/vdscli.py.in b/vdsm_cli/vdscli.py.in
index 5644a50..2a6ebd9 100644
--- a/vdsm_cli/vdscli.py.in
+++ b/vdsm_cli/vdscli.py.in
@@ -22,6 +22,7 @@
import xmlrpclib
import subprocess
import os
+import SecureXMLRPCServer
d_useSSL = False
d_tsPath = '@TRUSTSTORE@'
@@ -86,9 +87,6 @@ def connect(addrport=None, useSSL=None, tsPath=None):
if useSSL is None: useSSL = d_useSSL
if tsPath is None: tsPath = d_tsPath
if useSSL:
- from M2Crypto.m2xmlrpclib import SSL_Transport
- from M2Crypto import SSL
-
if os.name == 'nt':
KEYFILE = tsPath + '\\keys\\rhevm.pem'
CERTFILE = tsPath + '\\certs\\rhevm.cer'
@@ -98,14 +96,10 @@ def connect(addrport=None, useSSL=None, tsPath=None):
CERTFILE = tsPath + '/certs/vdsmcert.pem'
CACERT = tsPath + '/certs/cacert.pem'
- ctx = SSL.Context ('sslv3')
-
- ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 16)
- ctx.load_verify_locations(CACERT)
- ctx.load_cert(CERTFILE, KEYFILE, lambda v: "mypass")
-
- server = xmlrpclib.Server('https://%s' % addrport,
- SSL_Transport(ctx))
+ transport=SecureXMLRPCServer.VerifyingSafeTransport(key_file=KEYFILE,
+ cert_file=CERTFILE, ca_certs=CACERT)
+ server = xmlrpclib.ServerProxy('https://%s' % addrport,
+ transport=transport)
else:
server = xmlrpclib.Server('http://%s' % addrport)
return server
More information about the vdsm-patches
mailing list