I am very new to python and cannot seem to figure out how to accomplish this task. I want to connect to a website and extract the certificate information such as issuer and expiration dates.
I have looked all over, tried all kinds of steps but because I am new I am getting lost in the socket, wrapper etc.
To make matters worse, I am in a proxy environment and it seems to really complicate things.
Does anyone know how I could connect and extract the information while behind the proxy?
As explained in this Answer:
You can still the server certificate with the
ssl.get_server_certificate() function, but it returns it in PEM
format.
import ssl
print ssl.get_server_certificate(('server.test.com', 443))
From here, I would use M2Crypto or OpenSSL to read the cert and get values:
# M2Crypto
cert = ssl.get_server_certificate(('www.google.com', 443))
x509 = M2Crypto.X509.load_cert_string(cert)
x509.get_subject().as_text()
# 'C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com'
Python SSL lib don't deal with proxies.
Related
I am using python request module to hit rest api. I have to use SSL for security measures.
I see that i can set
requests.get(url,verify=/path/ca/bundle/)
However i am confused as to what needs to be passed as CA_BUNDLE?
I get the server certificate using
cert = ssl.get_server_certificate((server,port))
Can someone let me know, how i should use this certificate in my request? Should i convert the cert to X509/.pem/.der/.crt file ?
Solved it. Apparently i needed to get the entire certificate chain and create a CA bundle out of it.
So, I have a problem and 2 hours of research haven't helped.
I want to write a method that will return me a Boolean if a web-domain(e.g. "google.com", without http/s) has an ssl-certificate.
I have a big csv of domain names, which I need to process and check if the domains have a ssl-certificate, is there a method maybe in pythons ssl module?
Thank you for your help, TomiiPomii.
By using module ssl you can call ssl.get_server_certificate((host, port)) to retrieve SSL of specified host in PEM format. You will then have to parse the PEM file to actually retrieve the certificate values, but if you only care about the website having or not having it, simply check the return value.
import OpenSSL
key = ...
signature = ...
data = ...
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, key)
OpenSSL.crypto.verify(x509, signature, data, 'sha1')
So far, I am able to do all of this without any problems. However, it doesn't feel like this is enough security, since the key itself is given to me via an URL (that I am supposed to trust*), and the method to build the signature is publicly available.
So, say the key is said to be verified by "VeriSign Class 3 Code Signing 2010 CA", can anyone tell me how I can go about checking that this is a valid claim?
I'm guessing I need to have the VeriSign certificate locally on my machine. Assuming that I do, where do I go from there?
Thanks!
*the URL is given to me as a parameter in a JSON request. Sure, the URL will be HTTPS and I can check the domain name and all that. But it seems like I should be doing checks on the certificate itself
You are right that you should check the certificate itself. And yes, you need the VeriSign root certificate(s) (and any other intermediate certificates to have the complete chain of trust) which signed the certificate to be checked.
Current Symantec (VeriSign) root certificates can be found here in zipfile.
Download and unzip the zip file and find all certificates you wish to trust and put them together (in pem format) into one certificate bundle file.
Now you need to do the actual verification. Unfortunately, the OpenSSL call you need is X509_verify_certificate. I looked at the source for both pyopenssl and M2Crypto and neither expose that call, so there's no direct Python code you can call to verify the certificate with either of those packages.
However, since you are using pyopenssl you obviously have the openssl library available. Thus you probably already have or can easily install the openssl command-line tool set. If so, you can call the openssl verify command through a pipe by doing something like this:
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, key)
# the command like likes pem format
cert_pem = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
# the bundle that you created from the zip extraction
certificate_bundle = 'verisign-root-bundle.pem'
# Pipe the cert to the openssl verify command and check the return code
# a return code of 0 is successful verify
import subprocess
p = subprocess.Popen(['openssl', 'verify', '-CAfile', certificate_bundle],
stdin=subprocess.PIPE)
p.communicate(input=cert_pem)
p.wait()
if (p.returncode == 0):
print('Certificate Verified.')
else:
print('Problem with certificate')
The above pipe runs the command
openssl verify -CAfile ca.bundle certificate.pem
Finally, if you're not familiar with openssl, the command to show certificates is
openssl x509 -inform PEM -text -in certificate.pem
Hope this helps!
Maybe I only partly address your question. It seems that your largest worry is the security of the channel via which you obtain the key. You do not show any code of how you obtain that key, but you said that you retrieve it via HTTPS and now you want to verify the authenticity of this connection by certificate verification.
You can comfortably do so using the well-established third-party web client framework requests.
Quote from the docs:
Requests can verify SSL certificates for HTTPS requests, just like a
web browser. To check a host’s SSL certificate, you can use the verify
argument:
requests.get(url, verify=True)
Also:
You can pass verify the path to a CA_BUNDLE file with certificates of
trusted CAs.
The latter could look like
requests.get(url, verify='/path/to/cert.pem')
In case you really want to take control (and reduce complexity), then load the right file from http://www.symantec.com/page.jsp?id=roots and take the verify='/path/to/cert.pem' approach. I guess you need http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority-G2.pem
I have the following code to use:
def createCon(host,auth):
con = httplib.HTTPSConnection(host)
return con
def _readJson(con,url):
con.putrequest("GET",url)
...
r = con.getresponse()
It is working on a specific server, but on another I'm getting SSLError. If I open the url from browser, I need to accept the certificate and it is working well. But how can I either accept the certificate or disable it's validation? This is a self-signed certificate stored in a java keystore, so I would prefer to disable the verification...
The code is meant to reuse the connection between the requests, so I would prefer not to modify it deeply.
How could I do this? I tried to modify the examples but haven't beend succeded.
con.putrequest("GET",url, verify=False)
or
con.request.verify=False
I do not know how could I access the session or request objects or modify the default settings.
UPDATE this does not help:
socket.ssl.cert_reqs='CERT_NONE'
well, the actual error message is weird...:
SSLError:'[Errno 1] _ssl.c:492: error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group'
Regards:
Bence
Your error message points to a bug in the openssl version you use. See https://bugzilla.redhat.com/show_bug.cgi?id=1022468. In short: the client advertises capabilities it does not have and if the server picks such capability you get this error message. Needs to be fixed by upgrading your local openssl installation. A workaround on the server side should be possible too, if you have control over the server.
I have a problem.I'm testing some tips about Apple passbook with python. I'm using M2Crypto to obtain the signature.
The code is:
def passwordCallback(*args, **kwds):
return password
smime = SMIME.SMIME()
smime.load_key(key, certificate, callback=passwordCallback)
pk7 = smime.sign(SMIME.BIO.MemoryBuffer(manifest), flags=SMIME.PKCS7_DETACHED | SMIME.PKCS7_BINARY)
pem = SMIME.BIO.MemoryBuffer()
pk7.write(pem)
der = ''.join(l.strip() for l in pem.read().split('-----')[2].splitlines()).decode('base64')
The code is supposed to work well and generate the signature content, the problem is with the "key" and the "certificate".
This two variable are the name of certificate.pem and key.pem, but I have donwloaded only the pass.cert file from the Apple Developer portal.
How is possible to obtain this two files, with openssl or something similar?
SOLVED:
I have solved with this link
http://www.raywenderlich.com/3443/apple-push-notification-services-tutorial-part-12
You need to either obtain a certificate from a third-party certification authority (CA) or create a self-signed certificate using something like the process described in openSSL. If you are just testing some code a self-signed cert will work, but a CA-issued cert provides other users some indication that you are who you the cert says you are. You could create a self-signed cert claiming to be Tim_Cook#apple.com, but no reputable CA would issue you such a cert.