emailcurlopensslsmime

How to use OPENSSL to sign an email message and CURL to send it?


I would like to know how to sign it with an email digital certificate and then use CURL to send this signed email message.

Below is an example of a simple TEXT/PLAIN email message that I would like to sign.

Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 7bit
MIME-Version: 1.0 (Created with SublimeText 3)
Date: Fri, 01 Jan 2021 23:59:59 -0700
Message-ID: <aade2ef2-960f-4e0d-94e4-d100f5270d28@initech.com>
Subject: TPS Report #1001
From: "Michael @ Initech" <michael@initech.com>
To: "Peter @ Initech" <peter@initech.com>
User-Agent: CURL/7.75.0

Good morning.

This is a message in plain text format.

It contains no inline images or attachments.

Each line is no more than 76 characters in length.

Please reach out if you have any questions.


Thank you,

Michael Bolton
SENIOR DEVELOPER
michael@initech.com
P | 801.555.1234

I place the entire message in a file called singlepart--text-plain.eml and then I use CURL to send it.

curl --verbose -ssl smtps://secure.email.com:465 --login-options AUTH=PLAIN --user michael@initech.com:Letmein --mail-from michael@initech.com --mail-rcpt peter@initech.com --mail-rcpt-allowfails --upload-file singlepart--text-plain.eml

Bam. That is all it takes.

Now the following link describes how to sign mime messages with OPENSSL.

https://www.misterpki.com/openssl-smime/

openssl smime -sign -in singlepart--text-plain.eml -text -out signed-singlepart--text-plain.eml -signer michael-digital-signature.pem

RFC 8551 Section 3.5, 3.5.1 & 3.5.2 shows limited examples on how to structure the message and my question is how to correctly do this.

https://www.rfc-editor.org/rfc/rfc8551#section-3.5

What I don't know is, what am I signing? The entire content? Just the literal body of the message? Is this supposed to be a multipart message containing the body of text unchanged and a digital signature as a base64 attachment?

Or is it supposed to contain modified/signed text within a single part just like text/plain?

As you know, RFC documents are not for the faint of heart.


Solution

  • Only the message body is signed. That is everything after the blank line that comes after the headers.

    Headers cannot be included because they can be changed (existing ones modified, or new ones added) by mail servers and mail clients on their way to the recipient.

    However, there are approaches to include some important headers (like To and Subject) by copying them to the body, but they're not widely supported (yet?).

    openssl smime knows how to handle the S/MIME message correctly, so its input is the complete message (singlepart--text-plain.eml in your example).


    Here's a load of useful openssl smime examples which I've copied from the page http://openssl.cs.utah.edu/docs/apps/smime.html which, much to my regret, seems to be gone:

    Create a cleartext signed message:

    openssl smime -sign -in message.txt -text -out mail.msg \
        -signer mycert.pem
    

    Create an opaque signed message:

    openssl smime -sign -in message.txt -text -out mail.msg -nodetach \
        -signer mycert.pem
    

    Create a signed message, include some additional certificates and read the private key from another file:

    openssl smime -sign -in in.txt -text -out mail.msg \
        -signer mycert.pem -inkey mykey.pem -certfile mycerts.pem
    

    Create a signed message with two signers:

    openssl smime -sign -in message.txt -text -out mail.msg \
        -signer mycert.pem -signer othercert.pem
    

    Send a signed message under Unix directly to sendmail, including headers:

    openssl smime -sign -in in.txt -text -signer mycert.pem \
        -from steve@openssl.org -to someone@somewhere \
        -subject "Signed message" | sendmail someone@somewhere
    

    Verify a message and extract the signer's certificate if successful:

    openssl smime -verify -in mail.msg -signer user.pem -out signedtext.txt
    

    Send encrypted mail using triple DES:

    openssl smime -encrypt -in in.txt -from steve@openssl.org \
        -to someone@somewhere -subject "Encrypted message" \
        -des3 user.pem -out mail.msg
    

    Sign and encrypt mail:

    openssl smime -sign -in ml.txt -signer my.pem -text \
        | openssl smime -encrypt -out mail.msg \
        -from steve@openssl.org -to someone@somewhere \
        -subject "Signed and Encrypted message" -des3 user.pem
    

    Note: the encryption command does not include the -text option because the message being encrypted already has MIME headers.

    Decrypt mail:

    openssl smime -decrypt -in mail.msg -recip mycert.pem -inkey key.pem
    

    The output from Netscape form signing is a PKCS#7 structure with the detached signature format. You can use this program to verify the signature by line wrapping the base64 encoded structure and surrounding it with:

    -----BEGIN PKCS7-----
    -----END PKCS7-----
    

    and using the command:

     openssl smime -verify -inform PEM -in signature.pem -content content.txt
    

    Alternatively you can base64 decode the signature and use:

    openssl smime -verify -inform DER -in signature.der -content content.txt
    

    Create an encrypted message using 128 bit Camellia:

    openssl smime -encrypt -in plain.txt -camellia128 -out mail.msg cert.pem
    

    Add a signer to an existing message:

     openssl smime -resign -in mail.msg -signer newsign.pem -out mail2.msg