title: Why won't this Python code connect over SSL?
body: <p><strong>UPDATED</strong>: fixed/working code at bottom of question. Re-implemented to use <code>wrap_socket()</code> instead of <code>SSL.Context()</code>. Negotiated cipher seems unaffected by <code>ssl.PROTOCOL_</code></p>
  
  <p>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).</p>
  
  <p>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).</p>
  
  <p>If I use <code>openssl s_client</code> and feed it the client-side cert/key and CA file, things seem to work correctly; ie: <strong>verify return:1</strong> 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.</p>
  
  <pre><code># 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 = ca@SERVERsystems.com
  verify return:1
  depth=0 ...CN = srv.domain.net
  verify return:1
  ---
  Certificate chain
   0 s:/emailAddress=help@mydomain.net...CN=srv.domain.net
     i:/C=US/...emailAddress=ca@SERVERsystems.com
  ---
  Server certificate
  -----BEGIN CERTIFICATE-----
  MIIJRDCCByygAwIBAgIGAVGIopaoMA0GCSqGSIb3DQEBDQUAMIG...rV
  -----END CERTIFICATE-----
  subject=/emailAddress=help@mydomain.net...CN=srv.domain.net
  issuer=/C=US/...emailAddress=ca@SERVERsystems.com
  ---
  Acceptable client certificate CA names
  /C=US/...emailAddress=ca@SERVERsystems.com
  /.../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)
  ---
  </code></pre>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <pre><code>#!/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('&lt;transaction&gt;&lt;data&gt;14&lt;/data&gt;&lt;/transaction&gt;\n')
  s.close()
  </code></pre>
  
  <p>Python output:</p>
  
  <pre><code>Using server : localhost
  Traceback (most recent call last):
    File "./test3.py", line 29, in &lt;module&gt;
      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)
  </code></pre>
  
  <p>Server logs after connection above:</p>
  
  <pre><code>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)
  </code></pre>
  
  <p>Working code:</p>
  
  <pre><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 ("&lt;transaction&gt;&lt;data&gt;14&lt;/data&gt;&lt;/transaction&gt;\n")
  
  # read server reply
  print "server reply: " +  wrapper.recv(4096)
  wrapper.close()
  s.close()
  </code></pre>