source: TI12-security/branches/Dependencies/m2crypto/contrib/smimeplus.py @ 2172

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/branches/Dependencies/m2crypto/contrib/smimeplus.py@2237
Revision 2172, 5.6 KB checked in by pjkersha, 13 years ago (diff)
Line 
1import sys, os, tempfile
2import UserDict
3from email import Message
4import M2Crypto
5
6if not (sys.version_info[0] >= 2 and sys.version_info[1] >= 2):
7    class object:
8        pass
9    True=1
10    False=0
11
12
13class smimeplus(object):
14    def __init__(self, cert, privkey, passphrase, cacert, randfile=None):
15        self.cipher = 'des_ede3_cbc'   # XXX make it configable??
16        self.setsender(cert, privkey, passphrase)
17        self.setcacert(cacert)
18        self.randfile = randfile
19        self.__loadrand()
20       
21    def __passcallback(self, v):
22        """private key passphrase callback function"""
23        return self.passphrase
24
25    def __loadrand(self):
26        """Load random number file"""
27        if self.randfile:
28            M2Crypto.Rand.load_file(self.randfile, -1)
29
30    def __saverand(self):
31        """Save random number file"""
32        if self.randfile:
33            M2Crypto.Rand.save_file(self.randfile)
34
35    def __gettext(self, msg):
36        """Return a string representation of 'msg'"""
37        _data = ''
38        if isinstance(msg, Message.Message):
39            for _p in msg.walk():
40                _data = _data + _p.as_string()
41        else:
42            _data = str(msg)
43        return _data
44
45    def __pack(self, msg):
46        """Convert 'msg' to string and put it into an memory buffer for
47           openssl operation"""
48        return M2Crypto.BIO.MemoryBuffer(self.__gettext(msg))
49
50    def setsender(self, cert=None, privkey=None, passphrase=None):
51        if cert:
52            self.cert = cert
53        if privkey:
54            self.key  = privkey
55        if passphrase:
56            self.passphrase  = passphrase
57
58    def setcacert(self, cacert):
59        self.cacert = cacert
60
61    def sign(self, msg):
62        """Sign a message"""
63        _sender = M2Crypto.SMIME.SMIME()
64        _sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert),
65                callback=self.__passcallback)
66
67        _signed = _sender.sign(self.__pack(msg))
68
69        _out = self.__pack(None)
70        _sender.write(_out, _signed, self.__pack(msg))
71        return _out.read()
72
73    def verify(self, smsg, scert):
74        """Verify to see if 'smsg' was signed by 'scert', and scert was
75           issued by cacert of this object.  Return message signed if success,
76           None otherwise"""
77        # Load signer's cert.
78        _x509 = M2Crypto.X509.load_cert_bio(self.__pack(scert))
79        _stack = M2Crypto.X509.X509_Stack()
80        _stack.push(_x509)
81
82        # Load CA cert.
83        _tmpfile = persistdata(self.cacert)
84        _store = M2Crypto.X509.X509_Store()
85        _store.load_info(_tmpfile)
86        os.remove(_tmpfile)
87
88        # prepare SMIME object
89        _sender = M2Crypto.SMIME.SMIME()
90        _sender.set_x509_stack(_stack)
91        _sender.set_x509_store(_store)
92   
93        # Load signed message, verify it, and return result
94        _p7, _data = M2Crypto.SMIME.smime_load_pkcs7_bio(self.__pack(smsg))
95        try:
96            return _sender.verify(_p7, flags=M2Crypto.SMIME.PKCS7_SIGNED)
97        except M2Crypto.SMIME.SMIME_Error, _msg:
98            return None
99
100    def encrypt(self, rcert, msg):
101        # Instantiate an SMIME object.
102        _sender = M2Crypto.SMIME.SMIME()
103   
104        # Load target cert to encrypt to.
105        _x509 = M2Crypto.X509.load_cert_bio(self.__pack(rcert))
106        _stack = M2Crypto.X509.X509_Stack()
107        _stack.push(_x509)
108        _sender.set_x509_stack(_stack)
109   
110        _sender.set_cipher(M2Crypto.SMIME.Cipher(self.cipher))
111   
112        # Encrypt the buffer.
113        _buf = self.__pack(self.__gettext(msg))
114        _p7 = _sender.encrypt(_buf)
115       
116        # Output p7 in mail-friendly format.
117        _out = self.__pack('')
118        _sender.write(_out, _p7)
119   
120        # Save the PRNG's state.
121        self.__saverand()
122
123        return _out.read()
124
125    def decrypt(self, emsg):
126        """decrypt 'msg'.  Return decrypt message if success, None
127           otherwise"""
128        # Load private key and cert.
129        _sender = M2Crypto.SMIME.SMIME()
130        _sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert),
131                callback=self.__passcallback)
132   
133        # Load the encrypted data.
134        _p7, _data = M2Crypto.SMIME.smime_load_pkcs7_bio(self.__pack(emsg))
135   
136        # Decrypt p7.
137        try:
138            return _sender.decrypt(_p7)
139        except M2Crypto.SMIME.SMIME_Error, _msg:
140            return None
141
142    def addHeader(self, rcert, content, subject=''):
143        """Add To, From, Subject Header to 'content'"""
144        _scert = M2Crypto.X509.load_cert_bio(self.__pack(self.cert))
145        _scertsubj = X509_Subject(str(_scert.get_subject()))
146        _rcert = M2Crypto.X509.load_cert_bio(self.__pack(rcert))
147        _rcertsubj = X509_Subject(str(_rcert.get_subject()))
148
149        _out = 'From: "%(CN)s" <%(emailAddress)s>\n' % _scertsubj
150        _out = _out + 'To: "%(CN)s" <%(emailAddress)s>\n' % _rcertsubj
151        _out = _out + 'Subject: %s\n' % subject
152        _out = _out + content
153
154        return _out
155
156
157class X509_Subject(UserDict.UserDict):
158    # This class needed to be rewritten or merge with X509_Name
159    def __init__(self, substr):
160        UserDict.UserDict.__init__(self)
161        try:
162            _data = substr.strip().split('/')
163        except AttributeError, _msg:
164            pass
165        else:
166            for _i in _data:
167                try:
168                    _k, _v = _i.split('=')
169                    self[_k] = _v
170                except ValueError, _msg:
171                    pass
172
173
174def persistdata(data, file=None, isbinary=False):
175    if not file:
176        file = tempfile.mktemp()
177    if isbinary:
178        _flag = 'wb'
179    else:
180        _flag = 'w'
181
182    _fh = open(file, _flag)
183    _fh.write(data)
184    _fh.close()
185    return file
186
187
Note: See TracBrowser for help on using the repository browser.