From 2d93a6a7bab08f2cdbb94f396955e8d99a4a137d Mon Sep 17 00:00:00 2001 From: Apollon Oikonomopoulos <apollon@noc.grnet.gr> Date: Tue, 12 Oct 2010 18:08:06 +0300 Subject: [PATCH] Set list of trusted SSL CAs for client to verify As per SSL_CTX_set_client_CA_list(3SSL), set the list of acceptable CAs advertised to SSL clients to include the server's own certificate. This evidently fixes the pycurl/gnutls RPC client. During the TLS Handshake, when client verification is requested, the Server sends a CertificateRequest message which states that the client should send a valid certificate as a response. The CertificateRequest message contains a section called "certificate_authorities", which, according to the standard, is a list of the Distinguished Names (DNs) of acceptable certification authorities. The client uses this list to send a certificate signed by one of the acceptable CAs. Under OpenSSL's server implementation, this list must be set manually using some appropriate call, otherwise the list is empty. TLS 1.0[1] does not state whether the list may be left blank, whereas TLS 1.1[2] and 1.2[3] state that in case the list is blank, then the client *may* send any certificate of a valid type (valid types are specified elsewhere in the handshake). OpenSSL clients seem to obey the behaviour specified in TLS 1.1+, whereas at least curl+GnuTLS does not send any certificates if the list is empty (which is not wrong per the spec, but also evidently not configurable). [1] http://tools.ietf.org/html/rfc2246 [2] http://tools.ietf.org/html/rfc4346 [3] http://tools.ietf.org/html/rfc5246 Signed-off-by: Apollon Oikonomopoulos <apollon@noc.grnet.gr> Reviewed-by: Michael Hanselmann <hansmi@google.com> Reviewed-by: Guido Trotter <ultrotter@google.com> --- lib/http/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/http/__init__.py b/lib/http/__init__.py index 8767272be..036c13f6d 100644 --- a/lib/http/__init__.py +++ b/lib/http/__init__.py @@ -550,6 +550,7 @@ class HttpSslParams(object): """ self.ssl_key_pem = utils.ReadFile(ssl_key_path) self.ssl_cert_pem = utils.ReadFile(ssl_cert_path) + self.ssl_cert_path = ssl_cert_path def GetKey(self): return OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, @@ -609,6 +610,15 @@ class HttpBase(object): OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self._SSLVerifyCallback) + # Also add our certificate as a trusted CA to be sent to the client. + # This is required at least for GnuTLS clients to work. + try: + # This will fail for PyOpenssl versions before 0.10 + ctx.add_client_ca(self._ssl_cert) + except AttributeError: + # Fall back to letting OpenSSL read the certificate file directly. + ctx.load_client_ca(ssl_params.ssl_cert_path) + return OpenSSL.SSL.Connection(ctx, sock) def GetSslCiphers(self): # pylint: disable-msg=R0201 -- GitLab