I'm trying to do client ssl verification with code that looks like the sample below. I am able to reach and read urls that are secure and have no client certificate requirement OK. If I set explicit_check to True then verbose output indicates that the server certs are being checked fine ie I see the correct cert details and am able to check them.

However, when I try to reach an apache location like

<Location /media/secret>
    sslverifyclient require
    sslverifydepth 10
</Location>

I am getting an error from  urllib2 that goes like this

urllib2.py", line 1148, in do_open
    raise URLError(err)
URLError: <urlopen error [Errno 1] _ssl.c:1347: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca

I am using the server.crt and server.key (both in PEM format) from the target server itself; I reasoned that should be the easiest combo for the client & server to match, but I am obviously wrong. Any obvious stupidities to be pointed out? I suppose I could create a new cert/key based on a self signed ca, but that would not work properly for the other parts of the server.

import socket, ssl, fnmatch, datetime, urllib2, httplib
verbose=False

# wraps https connections with ssl certificate verification
class SecuredHTTPSHandler(urllib2.HTTPSHandler):
  def 
__init__(self,key_file=None,cert_file=None,ca_certs=None,explicit_check=False):
    class SecuredHTTPSConnection(httplib.HTTPSConnection):
      def connect(self):
        # overrides the version in httplib so that we do
        #  certificate verification
        sock = socket.create_connection((self.host, self.port), self.timeout)
        if self._tunnel_host:
          self.sock = sock
          self._tunnel()
        # wrap the socket using verification with the root
        #  certs in ca_certs
        if verbose:
          print ca_certs, key_file, cert_file
        self.sock = ssl.wrap_socket(sock,
                      cert_reqs=ssl.CERT_REQUIRED,
                      ca_certs=ca_certs,
                      keyfile=key_file,
                      certfile=cert_file,
                      )
        if explicit_check:
          cert = self.sock.getpeercert()
          if verbose:
            import pprint
            pprint.pprint(cert)
          for key,field in cert.iteritems():
            if key=='subject':
              sd = dict([x[0] for x in field])
              certhost = sd.get('commonName')
              if not fnmatch.fnmatch(self.host,certhost):
                raise ssl.SSLError("Host name '%s' doesn't match certificate host 
'%s'"
                     % (self.host, certhost))
              if verbose:
                print 'matched "%s" to "%s"'  % (self.host,certhost)
            elif key=='notAfter':
              now = datetime.datetime.now()
              crttime = datetime.datetime.strptime(field,'%b %d %H:%M:%S %Y %Z')
              if verbose:
                print 'crttime=%s now=%s' % (crttime,now)
              if now>=crttime:
                raise ssl.SSLError("Host '%s' certificate expired on %s"
                       % (self.host, field))
    self.specialized_conn_class = SecuredHTTPSConnection
    urllib2.HTTPSHandler.__init__(self)

  def https_open(self, req):
    return self.do_open(self.specialized_conn_class, req)

def secureDataGet(uri,ca_certs='cacert.pem',key_file=None,cert_file=None, 
explicit_check=False):
  https_handler = SecuredHTTPSHandler(key_file=key_file,cert_file=cert_file,
            ca_certs=ca_certs,explicit_check=explicit_check)
  url_opener = urllib2.build_opener(https_handler)
  handle = url_opener.open(uri)
  response = handle.readlines()
  handle.close()
  return response


--
Robin Becker

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to