Fix unsafe SSL connection on TrustedFilter
TrustedFilter was using httplib which doesn't check for CAs. Here the change is using Requests and verifies local CAs by default (or another one if provided) This effort is related to CVE 2013-2255. SecurityImpact Closes-Bug: #1373993 Change-Id: I0b8e6319a4cc39876b1e396ef705f0fc5def1e44
This commit is contained in:
parent
3c13c9e941
commit
30871e8702
|
@ -43,11 +43,8 @@ the Open Attestation project at:
|
|||
https://github.com/OpenAttestation/OpenAttestation
|
||||
"""
|
||||
|
||||
import httplib
|
||||
import socket
|
||||
import ssl
|
||||
|
||||
from oslo.config import cfg
|
||||
import requests
|
||||
|
||||
from nova import context
|
||||
from nova import db
|
||||
|
@ -74,6 +71,9 @@ trusted_opts = [
|
|||
cfg.IntOpt('attestation_auth_timeout',
|
||||
default=60,
|
||||
help='Attestation status cache valid period length'),
|
||||
cfg.BoolOpt('attestation_insecure_ssl',
|
||||
default=False,
|
||||
help='Disable SSL cert verification for Attestation service')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
@ -82,37 +82,6 @@ CONF.register_group(trust_group)
|
|||
CONF.register_opts(trusted_opts, group=trust_group)
|
||||
|
||||
|
||||
class HTTPSClientAuthConnection(httplib.HTTPSConnection):
|
||||
"""Class to make a HTTPS connection, with support for full client-based
|
||||
SSL Authentication
|
||||
"""
|
||||
|
||||
def __init__(self, host, port, key_file, cert_file, ca_file, timeout=None):
|
||||
httplib.HTTPSConnection.__init__(self, host,
|
||||
key_file=key_file,
|
||||
cert_file=cert_file)
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.key_file = key_file
|
||||
self.cert_file = cert_file
|
||||
self.ca_file = ca_file
|
||||
self.timeout = timeout
|
||||
|
||||
def connect(self):
|
||||
"""Connect to a host on a given (SSL) port.
|
||||
If ca_file is pointing somewhere, use it to check Server Certificate.
|
||||
|
||||
Redefined/copied and extended from httplib.py:1105 (Python 2.6.x).
|
||||
This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter to
|
||||
ssl.wrap_socket(), which forces SSL to check server certificate
|
||||
against our client certificate.
|
||||
"""
|
||||
sock = socket.create_connection((self.host, self.port), self.timeout)
|
||||
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
|
||||
ca_certs=self.ca_file,
|
||||
cert_reqs=ssl.CERT_REQUIRED)
|
||||
|
||||
|
||||
class AttestationService(object):
|
||||
# Provide access wrapper to attestation server to get integrity report.
|
||||
|
||||
|
@ -125,29 +94,36 @@ class AttestationService(object):
|
|||
self.cert_file = None
|
||||
self.ca_file = CONF.trusted_computing.attestation_server_ca_file
|
||||
self.request_count = 100
|
||||
# If the CA file is not provided, let's check the cert if verification
|
||||
# asked
|
||||
self.verify = (not CONF.trusted_computing.attestation_insecure_ssl
|
||||
and self.ca_file or True)
|
||||
self.cert = (self.cert_file, self.key_file)
|
||||
|
||||
def _do_request(self, method, action_url, body, headers):
|
||||
# Connects to the server and issues a request.
|
||||
# :returns: result data
|
||||
# :raises: IOError if the request fails
|
||||
|
||||
action_url = "%s/%s" % (self.api_url, action_url)
|
||||
action_url = "https://%s:%d%s/%s" % (self.host, self.port,
|
||||
self.api_url, action_url)
|
||||
try:
|
||||
c = HTTPSClientAuthConnection(self.host, self.port,
|
||||
key_file=self.key_file,
|
||||
cert_file=self.cert_file,
|
||||
ca_file=self.ca_file)
|
||||
c.request(method, action_url, body, headers)
|
||||
res = c.getresponse()
|
||||
status_code = res.status
|
||||
if status_code in (httplib.OK,
|
||||
httplib.CREATED,
|
||||
httplib.ACCEPTED,
|
||||
httplib.NO_CONTENT):
|
||||
return httplib.OK, res
|
||||
res = requests.request(method, action_url, data=body,
|
||||
headers=headers, cert=self.cert,
|
||||
verify=self.verify)
|
||||
status_code = res.status_code
|
||||
# pylint: disable=E1101
|
||||
if status_code in (requests.codes.OK,
|
||||
requests.codes.CREATED,
|
||||
requests.codes.ACCEPTED,
|
||||
requests.codes.NO_CONTENT):
|
||||
try:
|
||||
return requests.codes.OK, jsonutils.loads(res.text)
|
||||
except ValueError:
|
||||
return requests.codes.OK, res.text
|
||||
return status_code, None
|
||||
|
||||
except (socket.error, IOError):
|
||||
except requests.exceptions.RequestException:
|
||||
return IOError, None
|
||||
|
||||
def _request(self, cmd, subcmd, hosts):
|
||||
|
@ -161,11 +137,7 @@ class AttestationService(object):
|
|||
if self.auth_blob:
|
||||
headers['x-auth-blob'] = self.auth_blob
|
||||
status, res = self._do_request(cmd, subcmd, cooked, headers)
|
||||
if status == httplib.OK:
|
||||
data = res.read()
|
||||
return status, jsonutils.loads(data)
|
||||
else:
|
||||
return status, None
|
||||
return status, res
|
||||
|
||||
def do_attestation(self, hosts):
|
||||
"""Attests compute nodes through OAT service.
|
||||
|
|
|
@ -15,10 +15,9 @@
|
|||
Tests For Scheduler Host Filters.
|
||||
"""
|
||||
|
||||
import httplib
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
import requests
|
||||
import six
|
||||
import stubout
|
||||
|
||||
|
@ -253,7 +252,7 @@ class HostFiltersTestCase(test.NoDBTestCase):
|
|||
"""Stubs out the response from OAT service."""
|
||||
self.oat_attested = True
|
||||
self.oat_hosts = args[2]
|
||||
return httplib.OK, self.oat_data
|
||||
return requests.codes.OK, self.oat_data
|
||||
|
||||
def setUp(self):
|
||||
super(HostFiltersTestCase, self).setUp()
|
||||
|
|
Loading…
Reference in New Issue