I am trying to get data from the web using python. I imported urllib.request package for it but while executing, I get error:
certificate verify failed: unab
This page is the top google hit for "certificate verify failed: unable to get local issuer certificate", so while this doesn't directly answer the original question, below is a fix for a problem with the same symptom. I ran into this while trying to add TLS to an xmlrpc service. This requires use of the fairly low-level ssl.SSLContext
class. The error indicates that a certificate is missing. The fix was to do several things when constructing SSLContext
objects:
First, in the client:
def get_client():
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# Load the default certs:
context.load_default_certs()
# Optionally, install the intermediate certs.
# This _should_ be handled by the server, but
# maybe helpful in some cases.
# context.load_verify_locations('path/to/ca_bundle.crt')
return xmlrpc.client.ServerProxy('https://server.yourdomain.com/', context=context)
In the server, you need to install the intermediate certs in the context:
class SecureXMLRPCServer(socketserver.TCPServer,
xmlrpc.server.SimpleXMLRPCDispatcher):
# https://gist.github.com/monstermunchkin/1100226
allow_reuse_address = True
def __init__(self, addr, certfile, keyfile=None,
ca_bundle=None,
requestHandler=xmlrpc.server.SimpleXMLRPCRequestHandler,
logRequests=True, allow_none=False, encoding=None,
bind_and_activate=True, ssl_version=ssl.PROTOCOL_TLSv1_2):
self.logRequests = logRequests
# create an SSL context
self.context = ssl.SSLContext(ssl_version)
self.context.load_default_certs()
# The server is the correct place to load the intermediate CA certificates:
self.context.load_verify_locations(ca_bundle)
self.context.load_cert_chain(certfile=certfile, keyfile=keyfile)
xmlrpc.server.SimpleXMLRPCDispatcher.__init__(self, allow_none,
encoding)
# call TCPServer constructor
socketserver.TCPServer.__init__(self, addr, requestHandler,
bind_and_activate)
if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
def get_request(self):
newsocket, fromaddr = self.socket.accept()
# create an server-side SSL socket
sslsocket = self.context.wrap_socket(newsocket, server_side=True)
return sslsocket, fromaddr