An M2Crypto S/MIME Tutorial

Introduction

M2Crypto == Python + OpenSSL + SWIG.

M2Crypto makes available to the Python programmer the following:

This document is a brief tutorial on using M2Crypto's S/MIME functionality.

S/MIME

S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC 2312] - provides a consistent way to send and receive secure MIME data. Based on the popular Internet MIME standard, S/MIME provides the following cryptographic security services for electronic messaging applications - authentication, message integrity and non-repudiation of origin (using digital signatures) and privacy and data security (using encryption).

S/MIME is built on the PKCS #7 standard. [PKCS7]

S/MIME implemented in Netscape Messenger and Microsoft Outlook.

M2Crypto S/MIME

The Python programmer accesses M2Crypto's S/MIME functionality through the M2Crypto.SMIME.SMIME class. Typically, an SMIME object is instantiated; the object is then set up for the relevant operation (sign, encrypt, decrypt or verify); finally, the operation is invoked on the object.

M2Crypto.SMIME.SMIME makes extensive use of M2Crypto.BIO: M2Crypto.BIO is a Python abstraction of the BIO abstraction in OpenSSL. A commonly used BIO abstraction in M2Crypto is M2Crypto.BIO.MemoryBuffer, which implements a memory-based file-like object, similar to StringIO.

Signing

To generate a digital signature, a signer's private key and public key certificate are required; both must be in PEM format, although they need not be in separate files.

Suppose the signer's private key is in signer-key.pem, his certificate is in signer-cert.pem and the message to be signed is the following text string: "a sign of our times". The following code demonstrates how to generate a signature:

            from M2Crypto import BIO, Rand, SMIME, X509

            def makebuf(text):
                return BIO.MemoryBuffer(text)

            # Make a MemoryBuffer of the message.
            buf = makebuf('a sign of our times')

            # Instantiate an SMIME object; set it up; sign the buffer.
            s = SMIME.SMIME()
            s.load_key('signer-key.pem', 'signer-cert.pem')
            p7 = s.sign(buf)

Now p7 contains a PKCS#7 signature blob, wrapped in an SMIME.PKCS7 object. Note that buf has been consumed by sign() and has to be recreated.

Next, we send the signed message via SMTP:

            # Recreate buf.
            buf = makebuf('a sign of our times')

            # Output p7 in mail-friendly format.
            out = BIO.MemoryBuffer()
            out.write('To: ngps@post1.com')
            out.write('Subject: M2Crypto S/MIME')
            s.write(out, p7, buf)

            # Send via SMTP.
            import smtplib
            smtp = smtplib.SMTP()
            smtp.connect('localhost')
            smtp.sendmail('ngps@post1.com', 'ngps@post1.com', out.read())
            smtp.quit()