Extract userCertificate from PKCS7 in python

Ok, I'm trying to verify data from PKCS7 shell using Python.

I have working code in Java: http://nyal.developpez.com/tutoriel/java/bouncycastle/#L4.2

I want to get the certificate from the envelope first.

I can open it with this command:

openssl pkcs7 -in pkcs7 -print_certs -text 

Then I want to check that the data is ok.

I tried this:

 import base64 from M2Crypto import SMIME, X509, BIO raw_sig = """base64 PKCS7 envelop""" msg = "challenge message to verify" sm_obj = SMIME.SMIME() x509 = X509.load_cert('/etc/ssl/certs/ca-certificates.crt') # public key cert used by the remote # client when signing the message sk = X509.X509_Stack() sk.push(x509) sm_obj.set_x509_stack(sk) st = X509.X509_Store() st.load_info('/etc/ssl/certs/ca-certificates.crt') # Public cert for the CA which signed # the above certificate sm_obj.set_x509_store(st) # re-wrap signature so that it fits base64 standards cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76)) # now, wrap the signature in a PKCS7 block sig = """ -----BEGIN PKCS7----- %s -----END PKCS7----- """ % cooked_sig # print sig # and load it into an SMIME p7 object through the BIO I/O buffer: buf = BIO.MemoryBuffer(sig) p7 = SMIME.load_pkcs7_bio(buf) # do the same for the message text data_bio = BIO.MemoryBuffer(msg) cert = sm_obj.verify(p7, data_bio) 

I think one of / etc / ssl / certs / ca -certificates.crt should be userCertificate.

After receiving the certificate, I want to check that it is still valid (using the validity date) and check it against CRL and CPS for revocation.

I hope you help me.

+4
source share
2 answers

So I was almost there:

 import base64 from M2Crypto import SMIME, X509, BIO raw_sig = """base64 PKCS7 envelop""" msg = "challenge message to verify" sm_obj = SMIME.SMIME() x509 = X509.load_cert('ISSUER.crt') # public key cert used by the remote # client when signing the message sk = X509.X509_Stack() sk.push(x509) sm_obj.set_x509_stack(sk) st = X509.X509_Store() st.load_info('ROOT.crt') # Public cert for the CA which signed # the above certificate sm_obj.set_x509_store(st) # re-wrap signature so that it fits base64 standards cooked_sig = '\n'.join(raw_sig[pos:pos+76] for pos in xrange(0, len(raw_sig), 76)) # now, wrap the signature in a PKCS7 block sig = """ -----BEGIN PKCS7----- %s -----END PKCS7----- """ % cooked_sig # print sig # and load it into an SMIME p7 object through the BIO I/O buffer: buf = BIO.MemoryBuffer(sig) p7 = SMIME.load_pkcs7_bio(buf) signers = p7.get0_signers(sk) certificat = signers[0] 

Then you might also be interested in checking CRL and OCSP:

 from os.path import basename import re from tempfile import NamedTemporaryFile try: from subprocess import check_output, CalledProcessError, STDOUT except ImportError: # check_output new in 2.7, so use a backport for <=2.6 from subprocess32 import check_output, CalledProcessError, STDOUT class OpenSSLError(Exception): pass def info_extension_cert(cert): """ This function take a certificate and return the extensions in dict. @type cert : M2Crypto.X509 @param cert : Certificate """ certificateExtensions = {} for index in range(cert.get_ext_count()): ext = cert.get_ext_at(index) certificateExtensions[ext.get_name()] = ext.get_value() return certificateExtensions def get_cert_url_ocsp(cert): """ Get the OCSP url of a certificate @type cert : M2Crypto.X509 @parm cert : Certificat @rtype : string @return : The OSCP url """ infos = [x.strip() for x in info_extension_cert(cert)["authorityInfoAccess"].split('\n')] ocsp_url = None for info in infos: if re.match(r"^OCSP - URI:", info): ocsp_url = info.replace("OCSP - URI:","") break return ocsp_url.strip() def is_revoked(cert, cert_parent): """ Check if the certificate has been revoked. @type cert : M2Crypto.X509 @param cert : The certificate @type cert_parent : string @param cert_parent : Issuer certificate file path @rtype : boolean @return : True if revoked or False """ ocsp_url = get_cert_url_ocsp(cert) if re.match(r"^http", ocsp_url) is None: return False data = {'cert_parent': cert_parent, 'ocsp_url': ocsp_url, 'serial': cert.get_serial_number()} cmd = "openssl ocsp -issuer %(cert_parent)s -CAfile %(cert_parent)s -url %(ocsp_url)s -serial %(serial)s" % data print cmd try: output = check_output(cmd, shell=True, stderr=STDOUT).lower() except CalledProcessError, e: msg = u"[OpenSSL] Error while checking ocsp %s: %s. Output: %r" % ( cmd, e, e.output) raise OpenSSLError(msg) return not ('response verify ok' in output and '%s: good' % data['serial'] in output) def is_revoked_crl(cert, cert_parent_with_crl): """ Check if the certificate as been revoked with the crl. @type cert : M2Crypto.X509 @param cert : The certificate @type cert_parent : string @param cert_parent : Issuer certificate file path @rtype : boolean @return : True if revoked or False """ tmp_file = NamedTemporaryFile(prefix='cert') cert.save(tmp_file.name) data = {'cert': tmp_file.name, 'cert_parent_with_crl': cert_parent_with_crl} cmd = "openssl verify -crl_check -CAfile %(cert_parent_with_crl)s %(cert)s" % data print cmd try: output = check_output(cmd, shell=True, stderr=STDOUT).lower() except CalledProcessError, e: msg = u"[OpenSSL] Error while checking ocsp %s: %s. Output: %r" % ( cmd, e, e.output) raise OpenSSLError(msg) print output return '%s: ok' % data['cert'] not in output def get_cert_url_crl(cert): """ Return the crl url from the certificate @type cert : M2Crypto.X509 @parm cert : Certificate @rtype : string @return : CRL url """ infos = [x.strip() for x in info_extension_cert(cert)["crlDistributionPoints"].split('\n')] crl_url = None for info in infos: print info if re.match(r"^URI:", info): crl_url = info.replace("URI:","") break return crl_url.strip() 

cert_parent - the file with ROOT.crt and ISSUER.crt are merged together. cert_parent_crl - file with ROOT.crt, ISSUER.crt and CRL combined together.

To reconcile the CRL with another certificate, I use:

 rm FILE.crl wget http://URL/FILE.crl cat ROOT_ISSUER.crt > ROOT_ISSUER_CRL.crt echo "-----BEGIN X509 CRL-----" >> ROOT_ISSUER_CRL.crt openssl enc -base64 -in FILE.crl >> ROOT_ISSUER_CRL.crt echo "-----END X509 CRL-----" >> ROOT_ISSUER_CRL.crt 
+4
source

Try also https://github.com/erny/pyx509 . This requires the pyasn1 and pyasn1 modules. And this is just python:

 ./pkcs7_parse <pkcs7 signature in DER format> 
+2
source

Source: https://habr.com/ru/post/1446003/


All Articles