Search code examples
pythonrsasigningpycryptopyopenssl

Non-detached PKCS#7 SHA1+RSA signature without M2Crypto


I'm trying to create a non-detached signature on python3. I currently have code that does this on python2 with m2crypto, but m2crypto isn't available for python3.

I've been trying rsa, pycrypto and openssl, but haven't seen to find how.

Here's the equivalent OpenSSL command:

openssl smime -sign -signer $CRTFILE -inkey $KEYFILE -outformDER -nodetach

It's the nodetach option that I can't imitate with either rsa, pyopenssl or pycrypto.

Has anyone does this on python3? I'd like to avoid using Popen+openssl as much as possible.


Solution

  • I actually ended up solving this with OpenSSL.crypto, albeit, with some internal methods:

    from OpenSSL import crypto
    
    PKCS7_NOSIGS = 0x4  # defined in pkcs7.h
    
    
    def create_embeded_pkcs7_signature(data, cert, key):
        """
        Creates an embeded ("nodetached") pkcs7 signature.
    
        This is equivalent to the output of::
    
            openssl smime -sign -signer cert -inkey key -outform DER -nodetach < data
    
        :type data: bytes
        :type cert: str
        :type key: str
        """  # noqa: E501
    
        assert isinstance(data, bytes)
        assert isinstance(cert, str)
    
        try:
            pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, key)
            signcert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
        except crypto.Error as e:
            raise ValueError('Certificates files are invalid') from e
    
        bio_in = crypto._new_mem_buf(data)
        pkcs7 = crypto._lib.PKCS7_sign(
            signcert._x509, pkey._pkey, crypto._ffi.NULL, bio_in, PKCS7_NOSIGS
        )
        bio_out = crypto._new_mem_buf()
        crypto._lib.i2d_PKCS7_bio(bio_out, pkcs7)
        signed_data = crypto._bio_to_string(bio_out)
    
        return signed_data