如何使用Python输出仅限证书的PKCS#7

时间:2013-08-25 21:16:29

标签: python ruby openssl

我在Python中实现了一个SCEP服务器。 SCEP规范要求我使用“仅证书的PKCS#7”来回复PKIOperation。 Apple在Ruby中有一个参考实现,可以执行以下操作。

require 'openssl'

@@root_cert = OpenSSL::X509::Certificate.new(File.read("ca_cert.pem"))
@@ra_cert = OpenSSL::X509::Certificate.new(File.read("ra_cert.pem"))

scep_certs = OpenSSL::PKCS7.new()
scep_certs.type="signed"
scep_certs.certificates=[@@root_cert, @@ra_cert]

File.open('from_ruby.der', 'w') { |file| file.write(scep_certs.to_der)}

该代码正确输出包含CA和RA证书的PCKS7 DER文件。我正在尝试将此代码移植到Python。我正在使用M2Crypto库来访问OpenSSL。我正在努力解决M2Crypto.SMIME.PKCS7没有certificates方法的事实。到目前为止,我已经提出以下建议。

from M2Crypto import X509

ca_cert = X509.load_cert('ca_cert.pem')
ra_cert = X509.load_cert('ra_cert.pem')

stack = X509.X509_Stack()
stack.push(ca_cert)
stack.push(ra_cert)

derFile = open('from_python.der', 'w')
derFile.write(stack.as_der())

这个Python代码输出的DER编码文件看起来确实包含两个证书。但是,OpenSSL无法读取此文件。

openssl pkcs7 -in from_ruby.der -inform DER -print_certs

从Ruby脚本中打印出来的证书就好了,而

openssl pkcs7 -in from_python.der -inform DER -print_certs

抛出此错误

unable to load PKCS7 object
89377:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong             tag:/SourceCache/OpenSSL098/OpenSSL098-47.1/src/crypto/asn1/tasn_dec.c:1315:
89377:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:/SourceCache/OpenSSL098/OpenSSL098-47.1/src/crypto/asn1/tasn_dec.c:827:
89377:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:/SourceCache/OpenSSL098/OpenSSL098-47.1/src/crypto/asn1/tasn_dec.c:747:Field=type, Type=PKCS7

如何让Python以与Ruby相同的格式输出CA和RA证书?

I have posted the test certs I'm using as a gist.

更新: 我想出了将生成相同文件的openssl命令。

openssl crl2pkcs7 -nocrl -certfile ca_cert.pem -certfile ra_cert.pem -out crl.der -outform DER

现在,我如何在Python中做到这一点。这与this question

相同

3 个答案:

答案 0 :(得分:1)

有相同的要求,最终要求M2Crypto添加一个新函数来创建一个退化的PKCS7对象。 https://github.com/HanSooloo/M2Crypto-martinpaljak

所涉及的步骤如下:

  1. 将来自Martin Paljak的回购的M2Crypto转换为新的回购。
  2. 修改_pkcs7.i SWIG接口文件以添加以下功能。
  3. _pkcs7.i修改

    // Adding X.509 related header files to be able to use their data types.
    #include <openssl/x509.h>
    #include <openssl/x509v3.h>
    
    // Adding PKCS7_SIGNED data type to help create the degenerate data structure.
    %apply Pointer NONNULL { PKCS7_SIGNED * };
    
    // Additional interface definitions for degenerate PKCS#7 object creation.
    // Inspired by the crl2p7.c file from OpenSSL.  Will need to clean up a bit for function returns.
    %threadallow pkcs7_create_degenerate;
    %inline %{
    int pkcs7_create_degenerate(STACK_OF(X509) *cert_stack, BIO *bio) {
        int ret=1;
        PKCS7 *p7=NULL;
        PKCS7_SIGNED *p7s=NULL;
        X509_CRL *crl=NULL;
        STACK_OF(X509_CRL) *crl_stack=NULL;
    
        if ((p7=PKCS7_new()) == NULL) goto end;
        if ((p7s=PKCS7_SIGNED_new()) == NULL) goto end;  
    
        p7->type=OBJ_nid2obj(NID_pkcs7_signed);
        p7->d.sign=p7s;
        p7s->contents->type=OBJ_nid2obj(NID_pkcs7_data);
    
        if (!ASN1_INTEGER_set(p7s->version,1)) goto end;
        if ((crl_stack=sk_X509_CRL_new_null()) == NULL) goto end;
        p7s->crl=crl_stack;
        p7s->cert=cert_stack;
    
        ret=i2d_PKCS7_bio(bio, p7);
    
    end:
        p7s->cert=NULL;
    
        if (p7 != NULL) {
    //      printf("about to free p7: ");
            PKCS7_free(p7);
    //      printf("freed.\n");
        }
    
        return ret;
    
    }
    %}
    

    功能详细信息

    该函数将X509堆栈指针和BIO指针作为输入,并返回一个表示成功的整数。

    X509堆栈指针需要指向一个堆栈,其中包含希望放入简并PKCS#7对象的证书。

    BIO指针需要指向一个空的BIO结构,稍后将使用PKCS#7对象进行填充。

    使用上述函数的Python代码示例:

    from M2Crypto import X509, BIO, m2
    
    sk = X509.X509_Stack()
    
    cert = X509.load_cert('ra.crt')
    num = sk.push(cert)
    cert = X509.load_cert('ca.crt')
    num = sk.push(cert)
    
    # At this point, the X509 stack contains 2 certificates.
    print('num: %d' %num)
    
    # Create the BIO that will hold the PKCS#7 object.    
    bio = BIO.MemoryBuffer()
    
    # Request to create the degenerate PCKS#7 object.
    ret = m2.pkcs7_create_degenerate(sk._ptr(), bio._ptr())
    
    # Open the file for writing.
    f = open('deg.p7s', 'w')
    
    # Read from BIO and write to file.
    b = bio.read()
    f.write(b)
    
    # Close the file.
    f.close()
    

答案 1 :(得分:1)

您可以使用Python ctypes直接调用OpenSSL共享库函数来完成此操作。 Here's an example

答案 2 :(得分:-1)

我有一种感觉(完全未经测试),就像这样:

an_smime = M2Crypto.SMIME.SMIME()
an_smime.set_x509_stack(stack)
an_smime.write(M2Crypto.BIO.File('from_python.der'), pkcs7=True)