2

我正在用 Python 实现SCEP服务器。SCEP 规范要求我PKIOperation使用“仅证书 PKCS#7”来响应。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 证书?

我已经发布了我用作要点的测试证书。

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

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

那么现在,我该如何在 Python 中做到这一点。这与这个问题相同

4

3 回答 3

1

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

所涉及的步骤如下:

  1. 将 Martin Paljak 的 repo 中的 M2Crypto 分叉到一个新的。
  2. 修改_pkcs7.iSWIG 接口文件以添加以下功能。

_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()
于 2014-05-26T03:37:41.807 回答
1

您可以使用Python ctypes直接调用 OpenSSL 共享库函数来完成此操作。这是一个例子

于 2016-03-16T23:51:27.313 回答
-1

我有一种感觉(完全未经测试)是这样的:

an_smime = M2Crypto.SMIME.SMIME()
an_smime.set_x509_stack(stack)
an_smime.write(M2Crypto.BIO.File('from_python.der'), pkcs7=True)
于 2013-08-25T23:53:02.243 回答