6
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

badideas
  • 3,189
  • 3
  • 25
  • 26

2 Answers2

2

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

Dr. Jan-Philip Gehrcke
  • 33,287
  • 14
  • 85
  • 130
  • 1
    It does not validate the payload, if that is what you mean. I do not know exactly what that "key" is that you obtain via this HTTPS connection. But I can assure you this key is treated as any other payload data transmitted via HTTPS. – Dr. Jan-Philip Gehrcke Jan 23 '15 at 17:31
2

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!

random8
  • 81
  • 1
  • 5