我在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
相同答案 0 :(得分:1)
有相同的要求,最终要求M2Crypto添加一个新函数来创建一个退化的PKCS7对象。 https://github.com/HanSooloo/M2Crypto-martinpaljak
所涉及的步骤如下:
_pkcs7.i
SWIG接口文件以添加以下功能。// 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对象进行填充。
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)