从python中的PKCS7信封中提取userCertificate

时间:2012-11-14 13:35:54

标签: python x509 m2crypto pkcs#7

好的,我正在尝试使用Python验证来自PKCS7信封的数据。

我有Java的工作代码:http://nyal.developpez.com/tutoriel/java/bouncycastle/#L4.2

我想要的是先从信封中获取证书。

我可以用该命令打开它:

openssl pkcs7 -in pkcs7 -print_certs -text

然后我想验证数据是否正常。

我试过了:

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)

我认为其中一个/etc/ssl/certs/ca-certificates.crt应该是userCertificate。

获得证书后,我想检查它是否仍然有效(使用验证日期)并根据CRL和CPS进行验证以进行撤销。

我希望你能帮助我。

2 个答案:

答案 0 :(得分:4)

所以我几乎在那里:

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]

然后您可能也对CRL和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是ROOT.crt和ISSUER.crt连接在一起的文件。 cert_parent_crl是ROOT.crt,ISSUER.crt和CRL连接在一起的文件。

要将CRL与我使用的其他证书连接起来:

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

答案 1 :(得分:2)

另请尝试https://github.com/erny/pyx509。这需要pyasn1&amp; pyasn1模块。它只是python:

./pkcs7_parse <pkcs7 signature in DER format>