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

Request: Add example how to sign a mail #11489

Open
ikreb7 opened this issue Aug 26, 2024 · 6 comments
Open

Request: Add example how to sign a mail #11489

ikreb7 opened this issue Aug 26, 2024 · 6 comments

Comments

@ikreb7
Copy link

ikreb7 commented Aug 26, 2024

Hello,

I try to sign a mail with cryptography but I have still problems. There was the issue #4488. But at that time, S/MIME support was not yet so advanced.

This is my code, but I have still the problem, that Thunderbird show that the mail isn't signed and outlook shows that the mail is signed, but don't open the mail.

import smtplib
from email.header import Header
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formataddr, formatdate, parseaddr

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

from_addr = "[email protected]"
to_addr = "[email protected]"

message = MIMEMultipart()
message["Subject"] = Header("Signed Mail", "utf-8").encode()
message["From"] = formataddr(parseaddr(f"Github <{from_addr}>"))
message["To"] = to_addr
message["Date"] = formatdate(localtime=True)
message["Auto-Submitted"] = "auto-generated"
message.preamble = "This is an S/MIME signed message"

body = "This a plain text body!"
message.attach(MIMEText(body, "utf-8"))

ca_cert = open("cert.pem", "rb").read()
ca_key = open("key.pem", "rb").read()

cert = x509.load_pem_x509_certificate(ca_cert)
key = serialization.load_pem_private_key(ca_key, None)
options = [pkcs7.PKCS7Options.DetachedSignature]

signed_message = (
    pkcs7.PKCS7SignatureBuilder()
    .set_data(message.as_bytes())
    .add_signer(cert, key, hashes.SHA256())
    .sign(serialization.Encoding.SMIME, options)
)

server_name = "localhost"
with smtplib.SMTP() as server:
    server.set_debuglevel(True)
    server.connect(server_name, port=25)
    server.sendmail(from_addr, to_addr, signed_message)
@pyca pyca deleted a comment Aug 26, 2024
@alex
Copy link
Member

alex commented Aug 26, 2024

I'm pretty sure that you're double-SMIME-encoding the data.

@ikreb7
Copy link
Author

ikreb7 commented Aug 26, 2024

I'm pretty sure that you're double-SMIME-encoding the data.

Thanks for your response! What do you mean exactly?

@alex
Copy link
Member

alex commented Aug 26, 2024

I mean that you're both using the SMIME encoding option with the PKCS7SignatureBuilder and also doing your own SMIME encoding. I think this may be duplicating portions of it.

@ikreb7
Copy link
Author

ikreb7 commented Aug 26, 2024

I mean that you're both using the SMIME encoding option with the PKCS7SignatureBuilder and also doing your own SMIME encoding. I think this may be duplicating portions of it.

Right. I updated the code. But it still doesn't work.

@ikreb7
Copy link
Author

ikreb7 commented Aug 26, 2024

OK. I make the example more simple, but here are the From, To and Subject headers invisible.

message = EmailMessage()
message["From"] = formataddr(parseaddr(f"Github <{from_addr}>"))
message["To"] = to_addr
message["Date"] = formatdate(localtime=True)
message["Auto-Submitted"] = "auto-generated"
message["Subject"] = Header("Signed Mail", "utf-8").encode()
message.preamble = "This is an S/MIME signed message"

body = "This a plain text body!"
message.set_content(body)

ca_cert = open("cert.pem", "rb").read()
ca_key = open("key.pem", "rb").read()

cert = x509.load_pem_x509_certificate(ca_cert)
key = serialization.load_pem_private_key(ca_key, None)
options = [pkcs7.PKCS7Options.DetachedSignature]

signed_text = (
    pkcs7.PKCS7SignatureBuilder()
    .set_data(message.as_bytes())
    .add_signer(cert, key, hashes.SHA256())
    .sign(serialization.Encoding.SMIME, options)
)


server_name = "localhost"
with smtplib.SMTP() as server:
    server.set_debuglevel(True)
    server.connect(server_name, port=25)
    server.sendmail(from_addr, to_addr, signed_text)

This is the mail text

MIME-Version: 1.0
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="===============5864291155697480492=="

# the headers have to be here. Then it works.

This is an S/MIME signed message

--===============5864291155697480492==
From: No-reply <[email protected]>
To: [email protected]
Date: Mon, 26 Aug 2024 20:58:25 +0100
Auto-Submitted: auto-generated

This is the same problem like #10664.

@ikreb7
Copy link
Author

ikreb7 commented Aug 27, 2024

The problem is that the header is in the body of the message and is then not taken into account by the mail program. So this solves the problem but seems to be a dirty hack.

header = f"""From: {formataddr(parseaddr(f"Github <{from_addr}>"))}
To: {to_addr}
Date: {formatdate(localtime=True)}
Auto-Submitted: auto-generated
Subject: {Header("Signed Mail", "utf-8").encode()}
"""

signed_text = header.encode() + signed_text

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants
@alex @ikreb7 and others