This one took me a considerable amount of time and had to figure some parts from scratch.
Unfortunately there doesn’t seem to exist an easy (out-of-the-box) way for checking whether a certificate is signed by another certificate in python.
After days of searching and despair, here is a solution without using M2Crypto:
import OpenSSL from Crypto.Util import asn1 c=OpenSSL.crypto # This is the certificate to validate # an OpenSSL.crypto.X509 object cert=... # This is the CA certificate to use for validation # again an OpenSSL.crypto.X509 object cacert=... # Get the signing algorithm algo=cert.get_signature_algorithm() # Get the ASN1 format of the certificate cert_asn1=c.dump_certificate(c.FILETYPE_ASN1, cert) # Decode the certificate der=asn1.DerSequence() der.decode(cert_asn1) # The certificate has three parts: # - certificate # - signature algorithm # - signature # http://usefulfor.com/nothing/2009/06/10/x509-certificate-basics/ der_cert=der[0] der_algo=der[1] der_sig=der[2] # The signature is a BIT STRING (Type 3) # Decode that as well der_sig_in=asn1.DerObject() der_sig_in.decode(der_sig) # Get the payload sig0=der_sig_in.payload # Do the following to see a validation error for tests # der_cert=der_cert[:20]+'1'+der_cert[21:] # First byte is the number of unused bits. This should be 0 # http://msdn.microsoft.com/en-us/library/windows/desktop/bb540792(v=vs.85).aspx if sig0[0]!='x00': raise Exception('Number of unused bits is strange') # Now get the signature itself sig=sig0[1:] # And verify the certificate try: c.verify(cacert, sig, der_cert, algo) print "Certificate looks good" except OpenSSL.crypto.Error, e: print "Sorry. Nope."
Note: You can use the above under the MIT license. If it doesn’t fit your needs let me know. My intention is to make this usable by anyone for any kind of use with no obligation.
Hi! I’ve been searching for sth like this for a long time. I tried to run your code using cert from “google.com” and loaded CA-certs from /etc/ssl/certs/ca-certificates.crt. Using your code I get following error:
Error: [(‘rsa routines’, ‘RSA_padding_check_PKCS1_type_1?, ‘block type is not 01?), (‘rsa routines’, ‘RSA_EAY_PUBLIC_DECRYPT’, ‘padding check failed’)]
Are you somehow familiar with this type of error code? Thanks in advance.
Cheers,
Victor
LikeLike
Hi
I’m Trying to use your cerificate validation in an MSc project. What format for the certificates does you routine expect to use? I get a failure at this part
# Get the signing algorithm
algo=cert.get_signature_algorithm()
algo=cert.get_signature_algorithm(0)
AttributeError: ‘str’ object has no attribute ‘get_signature_algorithm’
I think it’s because the cert and cacert are in the wrong format
Thanks
Bill Laing
LikeLike
It’s an OpenSSL.crypto.X509 object as mentioned in the comments above
LikeLike
OK I got it working. I had to “load” my certificates into cert and cacert.
Now I can retrieve a certificate (cert) from my web server and validate it with a self-signed certificate (cacert) from another source (a blockchain simulation.)
The project is about alternaive methods of certificate validataion.
You script is exactly what I needed so I thank you for taking the time to develop it.
LikeLike
Hello again
I’m presenting my certificates in pem format like this
—–BEGIN CERTIFICATE—–MIIDqDCCApACCQCU071Gj4NFbjANBgkqhkiG9w0BAQsFADCBlTELMAkGA1UEBhMCVUsxFjAUBgNVBAgMD …..
I’m now thinking it’s a problem with the OpenSSL crypto module.
algo=cert.get_signature_algorithm()
AttributeError: ‘str’ object has no attribute ‘get_signature_algorithm’
If I comment out algo=cert.get_signature_algorithm() the next error is similar
cert_asn1=c.dump_certificate(c.FILETYPE_ASN1, cert)
File “/usr/local/lib/python2.7/dist-packages/OpenSSL/crypto.py”, line 1711, in dump_certificate
result_code = _lib.i2d_X509_bio(bio, cert._x509)
AttributeError: ‘unicode’ object has no attribute ‘_x509’
I’m using
Name: pyOpenSSL
Version: 17.0.0
Name: cryptography
Version: 1.8.1
Any ideas?
Thanks
Bill
LikeLike