Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

S/MIME signature: "Content-Type: text/plain" added to message (39.0.0) #8298

Closed
dirksammel opened this issue Feb 15, 2023 · 5 comments · Fixed by #8389
Closed

S/MIME signature: "Content-Type: text/plain" added to message (39.0.0) #8298

dirksammel opened this issue Feb 15, 2023 · 5 comments · Fixed by #8389

Comments

@dirksammel
Copy link

Hey,

I'm observing a weird behavior when signing with S/MIME since version 39.0.0: it seems like an additional "Content-Type: text/plain" is added to the message after signing it.

My code looks like this:

from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.serialization import pkcs7

with open("test.cert", "rb") as cc:
    cert = x509.load_pem_x509_certificate(cc.read())

with open("test.key", "rb") as ck:
    key = serialization.load_pem_private_key(ck.read(), None)

msg = "test"

options = [pkcs7.PKCS7Options.DetachedSignature, pkcs7.PKCS7Options.Text]

signed_msg = (
    pkcs7.PKCS7SignatureBuilder()
    .set_data(bytes(msg, "utf-8"))
    .add_signer(cert, key, hashes.SHA256())
    .sign(serialization.Encoding.SMIME, options)
)

with open("/tmp/msg.txt", "wb") as msg_file:
    msg_file.write(signed_msg)

With cryptography 38.0.4, the relevant part is

This is an S/MIME signed message

------A78EE028A05FC73322259A20ED9EAAAE
Content-Type: text/plain

test
------A78EE028A05FC73322259A20ED9EAAAE

and openssl smime -verify -in /tmp/msg.txt -noverify is successful.

With cryptography 39.0.0, I get

This is an S/MIME signed message

--===============0873037622973214044==
Content-Type: text/plain

Content-Type: text/plain

test
--===============0873037622973214044==

and the verification with openssl fails.
After manually removing the additional "Content-Type: text/plain" from the file, it succeeds again.

@reaperhulk
Copy link
Member

Thanks for the report. This is our bug. In 39 we rewrote part of the S/MIME code and introduced this issue. We canonicalize the input in text mode (which consists of converting line endings to \r\n) and we add the text/plain value in the same function. This is useful since we need to sign over the content-type as well as the payload, but then we call another smime_encode function if you pass serialization.Encoding.SMIME, which duplicates it. The tests failed to catch it because they looked for the presence of text/plain and did not assert the number of them and our verification test passed too because we don't extract the signature test value from the output.

We'll get a fix up soon.

@alex alex added this to the Fortieth release milestone Feb 16, 2023
@alex
Copy link
Member

alex commented Feb 16, 2023

I'm not sure I understand why our verification tests still pass here.

@reaperhulk
Copy link
Member

They pass because we sign the right thing but embed the wrong thing into the larger smime payload and then the verify call doesn't use what's in the smime payload. The test is

assert b"text/plain" in sig_pem
# When passing the Text option the header is prepended so the actual
# signed data is this.
signed_data = b"Content-Type: text/plain\r\n\r\nhello world"
_pkcs7_verify(
serialization.Encoding.SMIME,
sig_pem,
signed_data,
[cert],
options,
backend,
)

but it should be:

        assert sig_pem.count(b"text/plain") == 1
        # Parse the message to get the signed data, which is the
        # first payload in the message
        message = email.parser.BytesParser().parsebytes(sig_pem)
        signed_data = message.get_payload()[0].as_bytes()
        _pkcs7_verify(...)

Either of the changes to the test above would have caught this bug.

@alex
Copy link
Member

alex commented Feb 16, 2023 via email

@dirksammel
Copy link
Author

@reaperhulk Thanks for the answer and explanation!

alex added a commit to alex/cryptography that referenced this issue Feb 26, 2023
alex added a commit to alex/cryptography that referenced this issue Feb 26, 2023
alex added a commit to alex/cryptography that referenced this issue Feb 26, 2023
alex added a commit to alex/cryptography that referenced this issue Feb 26, 2023
alex added a commit to alex/cryptography that referenced this issue Feb 26, 2023
reaperhulk pushed a commit to reaperhulk/cryptography that referenced this issue Feb 26, 2023
alex added a commit that referenced this issue Feb 26, 2023
* fixes #8298 -- correctly generate content-type header in PKCS#7 SMIME (#8389)

* add changelog

* better changelog

---------

Co-authored-by: Alex Gaynor <alex.gaynor@gmail.com>
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging a pull request may close this issue.

3 participants