【问题标题】:Extract userCertificate from PKCS7 envelop in python从python中的PKCS7信封中提取userCertificate
【发布时间】:2012-11-03 00:13:42
【问题描述】:

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

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

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

我可以用那个命令打开它:

openssl pkcs7 -in pkcs7 -print_certs -text

那我要验证一下数据是否ok。

我试过这个:

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 验证它以进行撤销。

我希望你能帮助我。

【问题讨论】:

    标签: python x509 m2crypto pkcs#7


    【解决方案1】:

    所以我就快到了:

    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
    

    【讨论】:

    • 确保传递给BIO.MemoryBuffer 的任何内容都是字节字符串,而不是unicode。
    【解决方案2】:

    也可以试试https://github.com/erny/pyx509。这需要 pyasn1 & pyasn1-modules。而且它只是 python:

    ./pkcs7_parse <pkcs7 signature in DER format>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多