13

I need to verify that a certificate was signed by my custom CA. Using OpenSSL command-line utilities this is easy to do:

# Custom CA file: ca-cert.pem
# Cert signed by above CA: bob.cert
$ openssl verify -CAfile test-ca-cert.pem bob.cert
bob.cert: OK

But I need to do the same thing in Python, and I really don't want to call out to command-line utilities. As far as I'm aware, M2Crypto is the "most complete" python wrapper for OpenSSL, but I can't figure out how to accomplish what the command-line utility does!

Referencing this question for how to accomplish this same task in C code, I've been able to get about half-way. The variable names I chose are the same ones used in the source code for the openssl verify command-line utility, see openssl-xxx/apps/verify.c.

import M2Crypto as m2
# Load the certificates
cacert = m2.X509.load_cert('test-ca-cert.pem')   # Create cert object from CA cert file
bobcert = m2.X509.load_cert('bob.cert')     # Create cert object from Bob's cert file
cert_ctx = m2.X509.X509_Store()             # Step 1 from referenced C code steps
csc = m2.X509.X509_Store_Context(cert_ctx)  # Step 2 & 5
cert_ctx.add_cert(cacert)                   # Step 3
cert_ctx.add_cert(bobcert)                  # ditto
# Skip step 4 (no CRLs to add)
# Step 5 is combined with step 2...I think. (X509_STORE_CTX_init: Python creates and 
#   initialises an object in the same step)
# Skip step 6? (can't find anything corresponding to 
#   X509_STORE_CTX_set_purpose, not sure if we need to anyway???)
# 
# It all falls apart at this point, as steps 7 and 8 don't have any corresponding
# functions in M2Crypto -- I even grepped the entire source code of M2Crypto, and
# neither of the following functions are present in it:
# Step 7: X509_STORE_CTX_set_cert - Tell the context which certificate to validate.
# Step 8: X509_verify_cert - Finally, validate it

So I'm halfway there, but I can't seem to actually get the validation done! Am I missing something? Is there some other function I should be using from M2Crypto? Should I be looking for a completely different python wrapper of OpenSSL? How can I accomplish this task in python!?!?

Note that I'm using certificates to encrypt/decrypt FILES, so I'm not interested in using the SSL-connection-based peer certificate verification (which has already been answered), because I don't have any SSL connections going.

Community
  • 1
  • 1
Nathan Stocks
  • 2,096
  • 3
  • 20
  • 31
  • 1
    Is there any reason you don't want to call out to command-line utilities? Seems you could save yourself a _lot_ of headache... – Katriel Dec 09 '10 at 21:08
  • 2
    Yes, this is for software that will be deployed across many different operating systems, new and old, large and small -- including potentially embedded systems (large enough to include python on them). I want maximum portability and maximum performance. I don't want to be making potentially thousands of calls out to the command-line if I can possibly avoid it. Large numbers of certificates are involved. – Nathan Stocks Dec 09 '10 at 22:20
  • related http://stackoverflow.com/q/2626792/4279 – jfs Dec 16 '10 at 05:34
  • Duplicate of http://stackoverflow.com/questions/2626792/how-do-i-use-m2crypto-to-validate-a-x509-certificate-chain-in-a-non-ssl-setting – Heikki Toivonen Dec 16 '10 at 03:28

4 Answers4

5

You can't do this with plain M2Crypto, since it does not wrap some of the required functions. Good news is if you have SWIG installed you can wrap those yourself and use with M2Crypto code. I've made a module with some extra functions for myself some time ago, and decided to publish it now, since it does this kind of validation. You can check it here: https://github.com/abbot/m2ext. This is an example how to validate a certificate using this module:

import sys
from m2ext import SSL
from M2Crypto import X509

print "Validating certificate %s using CApath %s" % (sys.argv[1], sys.argv[2])
cert = X509.load_cert(sys.argv[1])
ctx = SSL.Context()
ctx.load_verify_locations(capath=sys.argv[2])
if ctx.validate_certificate(cert):
    print "valid"
else:
    print "invalid"

Unfortunately M2Crypto development seems to be stagnant (no closed issues in bug tracker for the last two years) and the maintainer was ignoring my bugs and emails with these and some other patches...

abbot
  • 27,408
  • 6
  • 54
  • 57
  • There *are* closed issues in the bug tracker in the last 2 years http://is.gd/iPhP6 (the https://bugzilla.osafoundation.org url is too long for the comment). @Heikki Toivonen (the maintainer) answers some questions about M2Crypto http://stackoverflow.com/questions/4403012/how-do-i-verify-an-ssl-certificate-in-python/4457189#4457189 – jfs Dec 16 '10 at 05:50
0

Use this command: /Applications/Python\ 3.9/Install\ Certificates.command

do not alter the spaces, just be sure to replace with your version of python

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 03 '22 at 23:14
-1

You can use the unfortunately undocumented X509.verify method to check whether the certificate was signed with the CA's private key. As this calls OpenSSL's x509_verify in the background, I'm sure this also checks all parameters (like expiration) correctly:

from M2Crypto X509

cert = X509.load_cert("certificate-filename")

caCertificate = X509.load_cert("trusted-ca-filename")
caPublic = caCertificate.get_pubkey()

if cert.verify(caPublic) == 1:
     # Certificate is okay!
else:
     # not okay
AndiDog
  • 68,631
  • 21
  • 159
  • 205
  • You are wrong, check the source: http://goo.gl/fRhou X509_verify checks only the signature. – abbot Dec 13 '10 at 09:37
-3

Like you said, OpenSSL requires connection

M2Crypto doesn't have good verification

How about this ingenious idea:

import os 
os.system('openssl verify -CAfile ../ca-cert.pem bob.cert')

Its ugly, but it works!

Vladiuz
  • 39
  • 2