1

UPDATED: fixed/working code at bottom of question. Re-implemented to use wrap_socket() instead of SSL.Context(). Negotiated cipher seems unaffected by ssl.PROTOCOL_

I've got an XML service which listens on port 8388. The service has it's own CA built in and will issue a P12 file for any client configured on it's admin interface (I need to include a CA cert in my connections).

I've configured a client and downloaded the P12 file; also exported PEM files (for easier debugging) from the P12 and exported a PEM file for the server CA (which was a Java keystore).

If I use openssl s_client and feed it the client-side cert/key and CA file, things seem to work correctly; ie: verify return:1 in the truncated output below. The openssl process does not generate any certificate errors on the server (as does my Python script). From what I've read, this is supposed to mean the certs are all OK and valid.

# openssl s_client -connect srv.domain.net:8388 -CAfile server_ca.pem  -cert client_cert.pem -key client_key.pem
CONNECTED(00000003)
depth=1 ... emailAddress = [email protected]
verify return:1
depth=0 ...CN = srv.domain.net
verify return:1
---
Certificate chain
 0 s:/[email protected]=srv.domain.net
   i:/C=US/[email protected]
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIJRDCCByygAwIBAgIGAVGIopaoMA0GCSqGSIb3DQEBDQUAMIG...rV
-----END CERTIFICATE-----
subject=/[email protected]=srv.domain.net
issuer=/C=US/[email protected]
---
Acceptable client certificate CA names
/C=US/[email protected]
/.../CN=srv.domain.net
---
SSL handshake has read 3369 bytes and written 5705 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: ...DF6572FA00D62D83CF0B1A82F
    Session-ID-ctx: 
    Master-Key: ...7F685C0B163A7739C271E9722FC0554108175C4
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1461337153
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---

I am now attempting to hook up a Python (2.7.9) script to the XML service using the same cert, key and CA file but I can't get it working. Python is complaining about SSLv3 errors and the server says it can't verify the client. So, the connection works, but the handshake, certs or ciphers or something aren't right.

I've searched out numerous examples and implementations and this one seemed to be the simplest one so I started with it for a template. SSL3 is not the protocol I would stick with (POODLE), but it was supposed to be from a working example so I wanted to make as few changes as possible to get things working and then tweak from there. Anyone know what I've got wrong here? ouput/errors/logs are posted at the far bottom.

#!/usr/bin/python
# -*- coding: utf-8 -*- 

import socket
import OpenSSL
from OpenSSL import *
import sys

serverName = sys.argv[1]
print "Using server : " + serverName

ctx = SSL.Context(SSL.SSLv3_METHOD)

ctx.use_privatekey_file('client_key.pem')
ctx.use_certificate_file('client_cert.pem')
ctx.load_verify_locations(cafile='server_ca.pem')

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((serverName, 8388))
sslSocket = socket.ssl(s)

print repr(sslSocket.server())
print repr(sslSocket.issuer())

print ("writing socket..")
sslSocket.write('<transaction><data>14</data></transaction>\n')
s.close()

Python output:

Using server : localhost
Traceback (most recent call last):
  File "./test3.py", line 29, in <module>
    sslSocket = socket.ssl(s)
  File "/usr/lib/python2.7/socket.py", line 64, in ssl
    return _realssl.sslwrap_simple(sock, keyfile, certfile)
  File "/usr/lib/python2.7/ssl.py", line 993, in sslwrap_simple
    ssl_sock.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_BAD_CERTIFICATE] sslv3 alert bad certificate (_ssl.c:581)

Server logs after connection above:

Apr 22 10:39:56 srv.domain.net ERROR server.auth [Thread-183,run:233] Couldn't validate the client certificate.  Verify the validity and dates of the client cert.
Apr 22 10:39:56 srv.domain.net javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
Apr 22 10:39:56 srv.domain.net at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:431)
Apr 22 10:39:56 srv.domain.net at com.xml.server.auth.run(auth.java:226)
Apr 22 10:39:56 srv.domain.net at java.lang.Thread.run(Thread.java:745)

Working code:

#!/usr/bin/python
# -*- coding: utf-8 -*- 
import socket
import ssl
import sys
import os

serverName = sys.argv[1]
print "Using server : " + serverName

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# ssl.PROTOCOL_xxx does not seem to affect negotiated cipher??
wrapper = ssl.wrap_socket(s,
                           ca_certs = "server_ca.pem",
                           certfile = "client_cert.pem",
                           keyfile  = "client_key.pem",
                           cert_reqs=ssl.CERT_REQUIRED,
                           ssl_version=ssl.PROTOCOL_TLSv1)

wrapper.connect((serverName, 8388))

# some info on the connnection/cipher in use
print repr(wrapper.getpeername())
print repr(wrapper.cipher())
print repr(wrapper.getpeercert())

# send server command
print ("writing socket..")
wrapper.send ("<transaction><data>14</data></transaction>\n")

# read server reply
print "server reply: " +  wrapper.recv(4096)
wrapper.close()
s.close()
5
  • Maybe this is not the cause of the problem but you restrict the non-working python code to SSL 3.0 whereas openssl is successfully using TLS 1.2. Please retry with this restriction removed. Commented Apr 22, 2016 at 16:28
  • are you referring to ctx = SSL.Context(SSL.SSLv3_METHOD) ? No matter what protocol I set that too (SSL.SSLv23_METHOD, TLSv1_METHOD, TLSv1_2_METHOD) I still get the same sslv3 alert bad certificate error. I'm puzzled.. does the server dictate that? Commented Apr 22, 2016 at 18:58
  • From my understanding the server does not want to accept your client certificate. So at least you know now that this error is not specific to the SSL/TLS version. Commented Apr 22, 2016 at 19:05
  • From what I see you build the context but you don't use this context for your SSL connection. This way the client certificate is not used and that's why you get this error message. Why don't you simple use ssl.wrap_socket with the parameters for certificate, key and CA? Commented Apr 22, 2016 at 19:10
  • Ah! Much better! thank you. If you convert your suggestion to an answer I can mark this answered. Commented Apr 22, 2016 at 19:25

1 Answer 1

1
ctx.use_privatekey_file('client_key.pem')
ctx.use_certificate_file('client_cert.pem')
...
sslSocket = socket.ssl(s)

While you create an SSL context with the client certificate you don't use this context within your SSL connection. This means no client certificate will be send and the server complains accordingly.

A much simpler way to use client certificates is by using the certfile and keyfile parameter of ssl.wrap_socket, see the documentation.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I've updated the question with working code utilizing ssl.wrap_socket

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.