encryptionopensslsendmailsmime

openssl SMIME and multipart messages


I need to send an encrypted email with a binary attachment from bash. I've read the RFC, and the openssl docs as well as a couple additional posts here in SF to no avail.

So far the process I understand goes like this:

  1. Create a MIME message
  2. use openssl smime to encrypt it generating additional headers for the envelope. This should be signed with my own private key but encrypted with the recipient's public key.
  3. pipe this output to sendmail
  4. The receiver should be able to decrypt the whole thing in outlook.

However what I'm seeing is a bit of garbled text. If anyone can shine some light where I'm messing up, I'd be thankful.

What follows are the nitty gritty details:

1. MIME Message

From: <FROM>
To: <TO>
Subject: <SUBJECT>
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="<BOUNDARY>"

--<BOUNDARY>
Content-Type: text/plain; charset=utf-8

<TEXT>

--<BOUNDARY>
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
 filename= "<FILENAME>"

<BASE64_DATA>

--<BOUNDARY>

2. The signing & Encrypting:

SIGNED=$(openssl smime -sign -in mime.txt -signer MyPublic.cer -inkey MyPrivate.key)
ENCRYPTED=$(openssl smime -encrypt -subject "Work damn you" RecipientPublic.cer <<< $SIGNED)

3. The Sending

echo "$ENCRYPTED" | sendmail recipient@hush-hush.com

Solution

  • so... after blood and tears it is done.

    Lessons learned:

    1. Also the Content-Type: multipart/alternative; should be Content-Type: multipart/mixed; else the email clients will be confused and show garbage.
    2. @dave_thompson_085 's comment of the missing -- at the end were spot on. That was part of the whole drama. be any funky word-wrapping that will mess up the encoding (don't ask me why).
    3. In Bash, as in real-life, quotes are important. So ENCRYPTED=$(openssl smime -encrypt -subject "Work damn you" RecipientPublic.cer <<< $SIGNED) should really be ENCRYPTED=$(openssl smime -encrypt -subject "Work damn you" RecipientPublic.cer <<< "$SIGNED")
    4. Openssl will take care of enveloping the appropriate headers, so there's no need to do anything here except the -subject flag.