client ssl verification
Robin Becker
robin at reportlab.com
Thu Mar 15 10:31:03 EDT 2012
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
More information about the Python-list
mailing list