python - M2Crypto: extract message from opaque signed S/MIME (pkcs7-mime) -


i have problem extracting message data opaque signed s/mime message, like:

to: ngps@post1.com from: ngps@mpost1.com subject: testing mime-version: 1.0 content-disposition: attachment; filename="smime.p7m" content-type: application/pkcs7-mime; smime-type=signed-data; name="smime.p7m" content-transfer-encoding: base64  miihqwyjkozihvcnaqccoiihndccbzacaqexczajbgurdgmcgguamiicqwyjkozi hvcnaqcboiicnascajanclmvtulnrsatifnly3vyzsbndwx0axb1cnbvc2ugsw50 zxjuzxqgtwfpbcbfehrlbnnpb25ziftsrkmgmjmxmswgukzdidizmtjdic0gdqpw cm92awrlcybhignvbnnpc3rlbnqgd2f5ihrvihnlbmqgyw5kihjly2vpdmugc2vj dxjlie1jtuugzgf0ys4gqmfzzwqgb24gdghldqpwb3b1bgfyieludgvybmv0ie1j tuugc3rhbmrhcmqsifmvtulnrsbwcm92awrlcyb0agugzm9sbg93aw5nignyexb0 b2dyyxboawmncnnly3vyaxr5ihnlcnzpy2vzigzvciblbgvjdhjvbmljig1lc3nh z2luzybhchbsawnhdglvbnmglsbhdxrozw50awnhdglvbiwncm1lc3nhz2ugaw50 zwdyaxr5igfuzcbub24tcmvwdwrpyxrpb24gb2ygb3jpz2luich1c2luzybkawdp dgfsihnpz25hdhvyzxmpdqphbmqgchjpdmfjesbhbmqgzgf0ysbzzwn1cml0esao dxnpbmcgzw5jcnlwdglvbikudqonclmvtulnrsbpcybidwlsdcbvbib0aguguetd uyajnybzdgfuzgfyzc4gw1blq1m3xq0kdqptl01jtuugaxmgaw1wbgvtzw50zwqg aw4gtmv0c2nhcgugtwvzc2vuz2vyigfuzcbnawnyb3nvznqgt3v0bg9vay4ncqcc axawggmmmiicdaadagecagecma0gcsqgsib3dqebbauamhsxczajbgnvbaytalnh mrewdwydvqqkewhnmknyexb0bzeumbiga1uecxmlttjdcnlwdg8gq0exjdaibgnv bamtg00yq3j5chrvienlcnrpzmljyxrlie1hc3rlcjedmbsgcsqgsib3dqejaryo bmdwc0bwb3n0ms5jb20whhcnmdawotewmdk1odiwwhcnmdiwotewmdk1odiwwjbz mqswcqydvqqgewjtrzerma8ga1uechmittjdcnlwdg8xgdawbgnvbamtd00yq3j5 chrviensawvuddedmbsgcsqgsib3dqejaryobmdwc0bwb3n0ms5jb20wxdanbgkq hkig9w0baqefaanladbiakeaoz3zuf0dmxsu+1fso+etdmjdy71gwnexwx28qsbj 0ufmq4jctw7gv4fj0tzgqhvirxgkruvzsquu8eivjup/nwidaqabo4ibbdccaqaw cqydvr0tbaiwadasbglghkgbhvhcaq0ehxydt3blblnttcbhzw5lcmf0zwqgq2vy dglmawnhdguwhqydvr0obbyefmcqheej1x9d+8rzag9yjciutykomiglbgnvhsme gz0wgzqafpuhi2nrndqtfexfvylrt/7tkdgbox+kftb7mqswcqydvqqgewjtrzer ma8ga1uechmittjdcnlwdg8xfdasbgnvbastc00yq3j5chrvienbmsqwigydvqqd extnmknyexb0bybdzxj0awzpy2f0zsbnyxn0zxixhtabbgkqhkig9w0bcqewdm5n chnacg9zddeuy29tggeama0gcsqgsib3dqebbauaa4gbaky2cwa2bf6cbbpe4ici //woqkldbsi3yzyusj7zpnefghx9ewrjflb3/sxef78ohl7yv6imrveveajcys+3 w/lspcmjc0hoomxnt0vjyccd0jeaewihqgboo9v0rexzruy8ynkwo1w8mmsbivqh +d5utb0jkl/ml1evlw3njf68myibwtccab0caqewgyawezelmakga1uebhmcu0cx etapbgnvbaotce0yq3j5chrvmrqwegydvqqlewtnmknyexb0bybdqtekmciga1ue axmbttjdcnlwdg8gq2vydglmawnhdgugtwfzdgvymr0wgwyjkozihvcnaqkbfg5u z3bzqhbvc3qxlmnvbqibajajbgurdgmcgguaoihymbggcsqgsib3dqejazelbgkq hkig9w0bbwewhayjkozihvcnaqkfmq8xdtezmdcxnte1mdkzn1owiwyjkozihvcn aqkemryefi/kcwjxhig0brzylfatdhxrmzghmhkgcsqgsib3dqejdzfsmgowcwyj yiziawudbaeqmasgcwcgsaflawqbfjalbglghkgbzqmeaqiwcgyikozihvcnawcw dgyikozihvcnawicagcama0gccqgsib3dqmcagfamacgbssoawihma0gccqgsib3 dqmcageoma0gcsqgsib3dqebaquabeaprw12pt+5t9kftixvi+mze/slznojqw9x 2q1ycztjy4droji6ch8bholfb1nxr/mbquijla5wfl22pdgtrlz5 

which opaque s/mime signed (not encrypted) message opaque.p7 generated m2crypto's (0.21.1) sign function demo/smime/test.py. data contains message, can revealed e.g. by: openssl smime -verify -noverify -in opaque.p7.

unfortunately, when want data with:

p7, data = m2crypto.smime.smime_load_pkcs7('opaque.p7') 

unfortunately, data none. it's problem opaque s/mime variant, because same works clear.p7.

i guess might compatibility problem, openssl version 1.0.1e (debian wheezy).. wonder if got working.

update

here output modified test.py (original here), demonstrate both clear , opaque s/mime messages, m2crypto correctly extracts signer certificate, extracts no data opaque smime:

test encrypt/decrypt... ok test sign & save... ok test load & verify opaque... ok   data: ''   signers: ['c=au, st=some-state, o=internet widgits pty ltd'] test load & verify clear... ok   data: 'actual message'   signers: ['c=au, st=some-state, o=internet widgits pty ltd'] test sign/verify... ok 

test.py patched, because failing on many places..

--- m2crypto-0.21.1.orig/demo/smime/test.py 2011-01-15 20:10:06.000000000 +0100 +++ m2crypto-0.21.1/demo/smime/test.py  2013-07-16 16:37:57.224845942 +0200 @@ -6,18 +6,7 @@   m2crypto import bio, rand, smime, x509  -ptxt = """ -s/mime - secure multipurpose internet mail extensions [rfc 2311, rfc 2312] -  -provides consistent way send , receive secure mime data. based on -popular internet mime standard, s/mime provides following cryptographic -security services electronic messaging applications - authentication, -message integrity , non-repudiation of origin (using digital signatures) -and privacy , data security (using encryption). - -s/mime built on pkcs #7 standard. [pkcs7] - -s/mime implemented in netscape messenger , microsoft outlook. -""" +ptxt = 'actual message'   def makebuf():      buf = bio.memorybuffer(ptxt) @@ -27,14 +16,14 @@      print 'test sign & save...',      buf = makebuf()      s = smime.smime() -    s.load_key('client.pem') -    p7 = s.sign(buf) +    s.load_key('client_.pem') +    p7 = s.sign(buf, flags=smime.pkcs7_detached)      out = bio.openfile('clear.p7', 'w')      out.write('to: ngps@post1.com\n')      out.write('from: ngps@post1.com\n')      out.write('subject: testing\n')      buf = makebuf() # recreate buf, because sign() has consumed it. -    s.write(out, p7, buf) +    s.write(out, p7, buf, flags=smime.pkcs7_detached)      out.close()       buf = makebuf() @@ -50,36 +39,42 @@  def verify_clear():      print 'test load & verify clear...',      s = smime.smime() -    x509 = x509.load_cert('client.pem') +    x509 = x509.load_cert('client_.pem')      sk = x509.x509_stack()      sk.push(x509)      s.set_x509_stack(sk)      st = x509.x509_store() -    st.load_info('ca.pem') +    st.load_info('client_.pem')      s.set_x509_store(st)      p7, data = smime.smime_load_pkcs7('clear.p7') -    v = s.verify(p7) -    if v: +    data_s = data.read() if isinstance(data, bio.bio) else '' +    v = s.verify(p7, bio.memorybuffer(data_s)) +    if v , (v == ptxt):          print 'ok'      else:          print 'not ok' +    print '  data: %r' % (data_s,) +    print '  signers: %r' % ([ x.get_subject().as_text() x in p7.get0_signers(sk)],)   def verify_opaque():      print 'test load & verify opaque...',      s = smime.smime() -    x509 = x509.load_cert('client.pem') +    x509 = x509.load_cert('client_.pem')      sk = x509.x509_stack()      sk.push(x509)      s.set_x509_stack(sk)      st = x509.x509_store() -    st.load_info('ca.pem') +    st.load_info('client_.pem')      s.set_x509_store(st)      p7, data = smime.smime_load_pkcs7('opaque.p7') -    v = s.verify(p7, data) -    if v: +    data_s = data.read() if isinstance(data, bio.bio) else '' +    v = s.verify(p7, makebuf()) # here verify against ptxt, since no data +    if v , (v == ptxt):          print 'ok'      else:          print 'not ok' +    print '  data: %r' % (data_s,) +    print '  signers: %r' % ([ x.get_subject().as_text() x in p7.get0_signers(sk)],)   def verify_netscape():      print 'test load & verify netscape messager output...', @@ -102,31 +97,32 @@      s = smime.smime()       # load private key. -    s.load_key('client.pem') +    s.load_key('client_.pem')       # sign. -    p7 = s.sign(buf) +    p7 = s.sign(buf, flags=smime.pkcs7_detached)       # output stuff. +    buf = makebuf()      bio = bio.memorybuffer() -    s.write(bio, p7, buf) +    s.write(bio, p7, buf, flags=smime.pkcs7_detached)       # plumbing verification: ca's cert.      st = x509.x509_store() -    st.load_info('ca.pem') +    st.load_info('client_.pem')      s.set_x509_store(st)       # plumbing verification: signer's cert. -    x509 = x509.load_cert('client.pem') +    x509 = x509.load_cert('client_.pem')      sk = x509.x509_stack()      sk.push(x509)      s.set_x509_stack(sk)       # verify.      p7, buf = smime.smime_load_pkcs7_bio(bio) -    v = s.verify(p7, flags=smime.pkcs7_detached) -     -    if v: +    v = s.verify(p7, buf, flags=smime.pkcs7_detached) + +    if v , (v == ptxt):          print 'ok'      else:          print 'not ok' 

client.pem contains expired certificate, using self-signed client_.pem, generated openssl req -new -x509 -newkey rsa -nodes -keyout client_.pem -out client_.pem

(please note test load & verify opaque testcase pretends succeeding, since verify step changed verifying against original known text)

what think main misunderstanding here in case of mime types other "multipart/signed", smime_load_pkcs7() meant return none in second part of tuple, , smime.smime.verify() meant take none second parameter.

when call s.verify(a, b), doesn't mean "verify signature in a matches message b", means "verify pkcs7 structure a has valid signature, given x509 store , stack on smime object s. oh, , if a has detached message, can find message part in b."

if you'd fix verify_opaque() function, take out data_s stuff altogether, , put original s.verify(p7, data) call. if v == ptxt, extraction of original message went expected and signature verified. if still want print out "data:" line, use v instead of data_s.

if question how original message data arbitrary opaque signed message, looks expected valid m2crypto.smime.smime context s , call s.verify() it! not operation i've needed myself before, might missing simple api, far can tell m2crypto doesn't expose simpler way. @ least, if don't have valid set of certs check against, or don't care, can pass pkcs7_noverify flag s.verify() call did openssl cmdline tool.


Comments