cryptography icon indicating copy to clipboard operation
cryptography copied to clipboard

Add support for decrypting S/MIME messages

Open nitneuqr opened this issue 1 year ago • 7 comments

As discussed on #6263, I'm opening this PR with an initial implementation of S/MIME decryption, in order to better discuss the API design, the algorithms we want to support, and how we want to approach testing.

My essential thoughts for testing were to do the round-trip: encryption using the PKCS7EnvelopeBuilder and decryption using the PKCS7EnvelopeDecryptor (or whatever its name will be). No tests were made against openssl, even though it might interesting.

For the Python API, I've tried to stick as much as possible with the current API design (PKCS7SignatureBuilder, PKCS7EnvelopeBuilder).

I'm new to rust, so please let me know if you see some issues in variable lifetime, or some unnecessary copying between Python & Rust.

During development, I've realized that we could migrate PKCS7 unpadding to rust instead of using types, so I did migrate it. I'll probably open another smaller PR for that matter (if that makes sense?). I still have some code using PKCS7 Unpadding on Python if needed.

cc @alex

nitneuqr avatar Sep 06 '24 17:09 nitneuqr

Thanks for working on this! I haven't had a chance to look in depth, but re: PKCS7Unpadder, it'd be great to have that in a stand-alone PR.

alex avatar Sep 06 '24 17:09 alex

Thanks for working on this! I haven't had a chance to look in depth, but re: PKCS7Unpadder, it'd be great to have that in a stand-alone PR.

Sure! Opened #11556 for that matter.

nitneuqr avatar Sep 06 '24 17:09 nitneuqr

Rebased to main after integration of #11556. Should I split it again in smaller PRs? Maybe around symmetric_decrypt or other subfunctions in the code.

nitneuqr avatar Sep 08 '24 09:09 nitneuqr

We're always happy to have smaller PRs split out (though it can sometimes be complicated due to coverage). I'm hoping to have time to review this today, though it might be tomorrow.

alex avatar Sep 08 '24 16:09 alex

@facutuesca FYI, if you're interested

alex avatar Sep 10 '24 03:09 alex

@alex @reaperhulk took into account the first comments and adapted the tests / coverage accordingly.

Do you have any time for another review? Do you need anything else from me before reviewing? 😊

nitneuqr avatar Sep 26 '24 07:09 nitneuqr

Sorry I got behind, will have a look now. Thanks for your patience!

alex avatar Oct 05 '24 19:10 alex

(Thanks for updating, I'm going to pause on reviewing until https://github.com/pyca/cryptography/pull/11843 is merged, hopefully that'll be quick.)

alex avatar Oct 28 '24 16:10 alex

#11843 is merged, I've rebased the branch onto main to take the new changes into account. It should b ready to review again!

nitneuqr avatar Nov 06 '24 08:11 nitneuqr

Great, will try to get to it this evening. Thanks!

On Wed, Nov 6, 2024 at 3:37 AM Quentin Retourne @.***> wrote:

#11843 is merged, I've rebased the branch onto main to take the new changes into account. It should b ready to review again!

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>

-- All that is necessary for evil to succeed is for good people to do nothing.

alex avatar Nov 06 '24 12:11 alex

Hey, any news on this? Do you need anything else from me? 😊

nitneuqr avatar Nov 17 '24 11:11 nitneuqr

Ooops, sorry this fell off my radar. I will get to it today!

alex avatar Nov 17 '24 15:11 alex

@nitneuqr Could you rebase this to fix the conflict? 😄

reaperhulk avatar Nov 17 '24 15:11 reaperhulk

Hey, we're getting closer now, but this conversation just raised new issue:

https://github.com/pyca/cryptography/pull/11555#discussion_r1845593139

Using the openssl executable, a round-trip (encryption + decryption) seems to transform Hello, world!\n into Hello, world!\r\r\n. This issue did not seem to happen in the old test_support.pkcs7_decrypt function (using openssl on Rust): the round-trip seemed to work fine. Is it correct that we should stick to this behavior instead of the other one?

In any cases, I'm going to add more tests cases when some data is encrypted with some options, and decrypted with some others.

nitneuqr avatar Nov 19 '24 15:11 nitneuqr

Are you sure the old version round tripped in that way? If you look at the tests, it looks to me like this PR changes them -- they used to have things like:

        # New lines are canonicalized to '\r\n' when not using Binary
        expected_data = (
            data
            if pkcs7.PKCS7Options.Binary in options
            else data.replace(b"\n", b"\r\n")
        )
        assert decrypted_bytes == expected_data

and now they have

        assert decrypted_bytes == data

alex avatar Nov 19 '24 15:11 alex

Are you sure the old version round tripped in that way? If you look at the tests, it looks to me like this PR changes them -- they used to have things like:

        # New lines are canonicalized to '\r\n' when not using Binary
        expected_data = (
            data
            if pkcs7.PKCS7Options.Binary in options
            else data.replace(b"\n", b"\r\n")
        )
        assert decrypted_bytes == expected_data

That's correct. I'll check this out. It might be yet another way, as it seems only one "\r" is added.

nitneuqr avatar Nov 19 '24 15:11 nitneuqr

That's correct. I'll check this out. It might be yet another way, as it seems only one "\r" is added.

Should be good now. decanonicalize function was way too complicated, -binary option does not seem to be handled by openssl smime -decrypt. I should have compared with test_support function way sooner, and should not have changed the previous tests assertions 😞 I'll move what's possible to pkcs7.rs and let you know when you can do a (hopefully!) final review.

nitneuqr avatar Nov 20 '24 09:11 nitneuqr

@alex @reaperhulk took most comments into account, still have some minor questions but would love a (hopefully!) final review.

nitneuqr avatar Nov 20 '24 10:11 nitneuqr

Besides these unwrap comments and @reaperhulk's on text, I think this is ready. Thanks so much for your continued work on it.

Thanks for your reviews! Should be good now, header removal is now tested in test_pkcs7_decrypt_der_text_handmade_header, and unwraps have been removed.

nitneuqr avatar Nov 25 '24 10:11 nitneuqr

One final nit + Paul's comments and we can merge!

Should be done now! Merci beaucoup! Also added some documentation 🛩️

nitneuqr avatar Nov 26 '24 08:11 nitneuqr

Yes, thank you for sticking with this and being so responsive. It's a pleasure having contributors like you!

reaperhulk avatar Nov 26 '24 16:11 reaperhulk

My pleasure! I might come back in a few days / weeks to tackle some more problems (namely, pkcs verify and encrypt/decrypt with other content encryption algorithms)

nitneuqr avatar Nov 26 '24 16:11 nitneuqr