开发者

SMIME.smime_load_pkcs7 (_bio): M2Crypto.SMIME.SMIME_Error: no content type

I have problems loading a pkcs#7 file and ask your help to figure out what I'm doing wrong.

I run M2Crypto-0.21.1 with OpenSSL 0.9.8g (as present in Ubuntu 9.4) and built with SWIG 1.3.36 and python 2.6.2.

"python setup.py test --test-suite=tests.test_smime" runs 15 tests with exit status "OK"; so the installation seems to be ok.

I created a pkcs#7 file in PEM format with a digital signature program and tested it with OpenSSL from the command line:

openssl smime -verify -inform PEM -in mandato-PEM.p7m -noverify

which prints the co开发者_JAVA百科ntent contained in the envelope (a text file that I signed) and "Verification successful". So OpenSSL (same version as used by M2Crypto) seems to like my file.

However, when I try the same in M2Crypto, it chocks right in the beginning on:

p7, data = SMIME.smime_load_pkcs7('mandato-PEM.p7m')

I get the following exception:

Traceback (most recent call last):
File "./sign.py", line 110, in <module>
p7, data = SMIME.smime_load_pkcs7('mandato-PEM.p7m') 
File "/usr/local/lib/python2.6/dist-packages/M2Crypto-0.21.1-py2.6-linux-i686.egg/M2Crypto/SMIME.py", line 91, in smime_load_pkcs7
p7_ptr, bio_ptr = m2.smime_read_pkcs7(bio)
M2Crypto.SMIME.SMIME_Error: no content type

While I have found information of a problem in Ubuntu (https://lists.ubuntu.com/archives/ubuntu-server-bugs/2010-July/038683.html), it seems to me that this cannot apply here since I built the latest M2Crypto manually and the test suite works fine.

Any help in resolving my problem would be highly appreciated!

many thanks

-bud


After a lot of sweat, here the solution for others who run into the same issue.

I was following the recipe http://code.activestate.com/recipes/285211/ and found many discussions on the web that just "verify(p7)" [method of SMIME] wasn't correct and "verify(p7, data)" was the right thing to do.

This applies only to SMIME documents where the signature is detached. My pkcs#7 file, and all other Italian digitally signed documents, are pkcs#7 envelopes that contain both the signature and the file content (in DER format).

Enveloped p7m files have to be verified as follows:

s=SMIME.SMIME()    
st = X509.X509_Store()   
st.load_info(trustedCAsPEMfileName)    
s.set_x509_store(st)    
p7bio = BIO.MemoryBuffer(p7strPEM)
p7 = SMIME.load_pkcs7_bio(p7bio)
certStack = p7.get0_signers(X509.X509_Stack())
s.set_x509_stack(certStack)
try:
    docContent = s.verify(p7)
except SMIME.PKCS7_Error, e:
    print "An exception occurred!!!!"
    print e

To test that this works, I edited the p7m file such that the signature doesn't verify anymore and it correctly prints out "digest failure".


You can also verify a .p7m file (attached DER format) directly but you need to load PKCS #7 object from DER format by m2 direct call to OpenSSL (m2.pkcs7_read_bio_der(input_bio._ptr())) because there is no function for this inside M2Crypto SMIME module. For a proposed patch see Small patch to SMIME.py.

Here a sample code:

import logging

from M2Crypto import SMIME, X509, m2, BIO

certstore_path = "/etc/ssl/certs/ca-certificates.crt"
file_descriptor = open('test_file.p7m', 'rb')
input_bio = BIO.File(file_descriptor)
signer = SMIME.SMIME()
cert_store = X509.X509_Store()
cert_store.load_info(certstore_path)
signer.set_x509_store(cert_store)
try: 
    p7 = SMIME.PKCS7(m2.pkcs7_read_bio_der(input_bio._ptr()), 1)
except SMIME.SMIME_Error, e:
    logging.error('load pkcs7 error: ' + str(e))
sk3 = p7.get0_signers(X509.X509_Stack())
signer.set_x509_stack(sk3)
data_bio = None
try:
    v = signer.verify(p7, data_bio)
except SMIME.SMIME_Error, e:
    logging.error('smime error: ' + str(e))
except SMIME.PKCS7_Error, e:
    logging.error('pkcs7 error: ' + str(e))

Code Source: pysmime core


If you only want to extract the original file from the .p7m one (without verifying it), you need to install M2Crypto with pip install M2Crypto (you must probably run sudo apt-get install libssl-dev before) and then run this Python code:

from M2Crypto import BIO, SMIME, X509

# Load file in memory just to showcase BIO usage
with open('file.p7m', 'rb') as file:
    p7m = file.read()

smime = SMIME.SMIME()
smime.set_x509_store(X509.X509_Store())
smime.set_x509_stack(X509.X509_Stack())
original_file_content = smime.verify(
    SMIME.load_pkcs7_bio_der(BIO.MemoryBuffer(p7m)),
    flags=SMIME.PKCS7_NOVERIFY
)

You can use SMIME.load_pkcs7, SMIME.load_pkcs7_bio, SMIME.load_pkcs7_der instead of SMIME.load_pkcs7_bio_der according to your use case: in-memory (_bio) or on file system .p7m file, and PEM or DER (_der) format.


The best reference I found to sign and unsign is the M2Crypto tests here:

http://svn.osafoundation.org/m2crypto/trunk/tests/test_smime.py

def test_sign(self):
    buf = BIO.MemoryBuffer(self.cleartext)
    s = SMIME.SMIME()
    s.load_key('tests/signer_key.pem', 'tests/signer.pem')
    p7 = s.sign(buf, SMIME.PKCS7_DETACHED)
    assert len(buf) == 0
    assert p7.type() == SMIME.PKCS7_SIGNED, p7.type()
    assert isinstance(p7, SMIME.PKCS7), p7
    out = BIO.MemoryBuffer()
    p7.write(out)

    buf = out.read()

    assert buf[:len('-----BEGIN PKCS7-----')] == '-----BEGIN PKCS7-----'
    buf = buf.strip()
    assert buf[-len('-----END PKCS7-----'):] == '-----END PKCS7-----', buf[-len('-----END PKCS7-----'):]
    assert len(buf) > len('-----END PKCS7-----') + len('-----BEGIN PKCS7-----')

    s.write(out, p7, BIO.MemoryBuffer(self.cleartext))
    return out

def test_verify(self):
    s = SMIME.SMIME()

    x509 = X509.load_cert('tests/signer.pem')
    sk = X509.X509_Stack()
    sk.push(x509)
    s.set_x509_stack(sk)

    st = X509.X509_Store()
    st.load_info('tests/ca.pem')
    s.set_x509_store(st)

    p7, data = SMIME.smime_load_pkcs7_bio(self.signed)

    assert isinstance(p7, SMIME.PKCS7), p7
    v = s.verify(p7, data)
    assert v == self.cleartext

    t = p7.get0_signers(sk)
    assert len(t) == 1
    assert t[0].as_pem() == x509.as_pem(), t[0].as_text()

Be carefull with the documentation (http://svn.osafoundation.org/m2crypto/trunk/doc/howto.smime.html) because it is not updated.

See this patch:

https://bugzilla.osafoundation.org/show_bug.cgi?id=13020

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜