From 2520e7189c515887ef0d7d73866e3c0b130e8c56 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Mon, 30 Nov 2015 15:52:30 -0800 Subject: [PATCH] smime: allow signing message digest algorithm to be specified. Currently, Mutt hardcodes micalg=sha1 for signed messages. Unfortunately, the actual message digest algorithm used defaults to the value in the "Signature Algorithm" field in the signing key's certificate. Add a new configuration option $smime_sign_digest_alg, defaulting to sha256. Add a new printf format string, %d, to be used in the signing command to specify the digest algorithm. Modify the sample $smime_sign_command to include "-md %d". Note: This solution requires using the modified $smime_sign_command, or else the micalg parameter again may not match the algorithm used. An alternative solution would be to query the certificate "Signature Algorithm" field and try to change the micalg to match it, but this method is easier to implement and provides better control for the user to configure, in any case. --- contrib/smime.rc | 8 ++++-- globals.h | 1 + init.h | 8 ++++++ smime.c | 67 ++++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/contrib/smime.rc b/contrib/smime.rc index 0f85421ed..532ac9ec0 100644 --- a/contrib/smime.rc +++ b/contrib/smime.rc @@ -65,8 +65,12 @@ set smime_encrypt_with="aes256" # Encrypt a message. Input file is a MIME entity. set smime_encrypt_command="openssl smime -encrypt -%a -outform DER -in %f %c" +# Algorithm for the signature message digest. +# Valid choices are md5, sha1, sha224, sha256, sha384, sha512. +set smime_sign_digest_alg="sha256" + # Sign. -set smime_sign_command="openssl smime -sign -signer %c -inkey %k -passin stdin -in %f -certfile %i -outform DER" +set smime_sign_command="openssl smime -sign -md %d -signer %c -inkey %k -passin stdin -in %f -certfile %i -outform DER" @@ -89,7 +93,7 @@ openssl smime -verify -inform DER -in %s -noverify 2>/dev/null" # Sign. If you wish to NOT include the certificate your CA used in signing # your public key, use this command instead. -# set smime_sign_command="openssl smime -sign -signer %c -inkey %k -passin stdin -in %f -outform DER" +# set smime_sign_command="openssl smime -sign -md %d -signer %c -inkey %k -passin stdin -in %f -outform DER" # # In order to verify the signature only and skip checking the certificate chain: # diff --git a/globals.h b/globals.h index e77030c71..245902c20 100644 --- a/globals.h +++ b/globals.h @@ -258,6 +258,7 @@ WHERE char *SmimeVerifyCommand; WHERE char *SmimeVerifyOpaqueCommand; WHERE char *SmimeDecryptCommand; WHERE char *SmimeSignCommand; +WHERE char *SmimeDigestAlg; WHERE char *SmimeSignOpaqueCommand; WHERE char *SmimeEncryptCommand; WHERE char *SmimeGetSignerCertCommand; diff --git a/init.h b/init.h index 8f5aac5dd..b0402a1f6 100644 --- a/init.h +++ b/init.h @@ -2720,6 +2720,7 @@ struct option_t MuttVars[] = { ** .dt %k .dd The key-pair specified with $$smime_default_key ** .dt %c .dd One or more certificate IDs. ** .dt %a .dd The algorithm used for encryption. + ** .dt %d .dd The message digest algorithm specified with $$smime_sign_digest_alg. ** .dt %C .dd CA location: Depending on whether $$smime_ca_location ** . points to a directory or file, this expands to ** . ``-CApath $$smime_ca_location'' or ``-CAfile $$smime_ca_location''. @@ -2843,6 +2844,13 @@ struct option_t MuttVars[] = { ** possible \fCprintf(3)\fP-like sequences. ** (S/MIME only) */ + { "smime_sign_digest_alg", DT_STR, R_NONE, UL &SmimeDigestAlg, UL "sha256" }, + /* + ** .pp + ** This sets the algorithm that should be used for the signature message digest. + ** Valid choices are ``md5'', ``sha1'', ``sha224'', ``sha256'', ``sha384'', ``sha512''. + ** (S/MIME only) + */ { "smime_sign_opaque_command", DT_STR, R_NONE, UL &SmimeSignOpaqueCommand, 0}, /* ** .pp diff --git a/smime.c b/smime.c index 97e77e757..9192f8420 100644 --- a/smime.c +++ b/smime.c @@ -56,6 +56,7 @@ struct smime_command_context { const char *key; /* %k */ const char *cryptalg; /* %a */ + const char *digestalg; /* %d */ const char *fname; /* %f */ const char *sig_fname; /* %s */ const char *certificates; /* %c */ @@ -266,6 +267,17 @@ static const char *_mutt_fmt_smime_command (char *dest, break; } + case 'd': + { /* algorithm for the signature message digest */ + if (!optional) { + snprintf (fmt, sizeof (fmt), "%%%ss", prefix); + snprintf (dest, destlen, fmt, NONULL (cctx->digestalg)); + } + else if (!cctx->key) + optional = 0; + break; + } + default: *dest = '\0'; break; @@ -299,6 +311,7 @@ static pid_t smime_invoke (FILE **smimein, FILE **smimeout, FILE **smimeerr, const char *fname, const char *sig_fname, const char *cryptalg, + const char *digestalg, const char *key, const char *certificates, const char *intermediates, @@ -316,6 +329,7 @@ static pid_t smime_invoke (FILE **smimein, FILE **smimeout, FILE **smimeerr, cctx.sig_fname = sig_fname; cctx.key = key; cctx.cryptalg = cryptalg; + cctx.digestalg = digestalg; cctx.certificates = certificates; cctx.intermediates = intermediates; @@ -936,7 +950,7 @@ static int smime_handle_cert_email (char *certificate, char *mailbox, if ((thepid = smime_invoke (NULL, NULL, NULL, -1, fileno (fpout), fileno (fperr), - certificate, NULL, NULL, NULL, NULL, NULL, + certificate, NULL, NULL, NULL, NULL, NULL, NULL, SmimeGetCertEmailCommand))== -1) { mutt_message (_("Error: unable to create OpenSSL subprocess!")); @@ -1033,7 +1047,7 @@ static char *smime_extract_certificate (char *infile) */ if ((thepid = smime_invoke (NULL, NULL, NULL, -1, fileno (fpout), fileno (fperr), - infile, NULL, NULL, NULL, NULL, NULL, + infile, NULL, NULL, NULL, NULL, NULL, NULL, SmimePk7outCommand))== -1) { mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!")); @@ -1077,7 +1091,7 @@ static char *smime_extract_certificate (char *infile) */ if ((thepid = smime_invoke (NULL, NULL, NULL, -1, fileno (fpout), fileno (fperr), - pk7out, NULL, NULL, NULL, NULL, NULL, + pk7out, NULL, NULL, NULL, NULL, NULL, NULL, SmimeGetCertCommand))== -1) { mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!")); @@ -1142,7 +1156,7 @@ static char *smime_extract_signer_certificate (char *infile) */ if ((thepid = smime_invoke (NULL, NULL, NULL, -1, -1, fileno (fperr), - infile, NULL, NULL, NULL, certfile, NULL, + infile, NULL, NULL, NULL, NULL, certfile, NULL, SmimeGetSignerCertCommand))== -1) { mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!")); @@ -1217,7 +1231,7 @@ void smime_invoke_import (char *infile, char *mailbox) if ((thepid = smime_invoke (&smimein, NULL, NULL, -1, fileno(fpout), fileno(fperr), - certfile, NULL, NULL, NULL, NULL, NULL, + certfile, NULL, NULL, NULL, NULL, NULL, NULL, SmimeImportCertCommand))== -1) { mutt_message (_("Error: unable to create OpenSSL subprocess!")); @@ -1329,7 +1343,7 @@ pid_t smime_invoke_encrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr, { return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd, smimeerrfd, - fname, NULL, SmimeCryptAlg, NULL, uids, NULL, + fname, NULL, SmimeCryptAlg, NULL, NULL, uids, NULL, SmimeEncryptCommand); } @@ -1340,7 +1354,7 @@ pid_t smime_invoke_sign (FILE **smimein, FILE **smimeout, FILE **smimeerr, const char *fname) { return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd, - smimeerrfd, fname, NULL, NULL, SmimeKeyToUse, + smimeerrfd, fname, NULL, NULL, SmimeDigestAlg, SmimeKeyToUse, SmimeCertToUse, SmimeIntermediateToUse, SmimeSignCommand); } @@ -1467,6 +1481,33 @@ BODY *smime_build_smime_entity (BODY *a, char *certlist) } +/* The openssl -md doesn't want hyphens: + * md5, sha1, sha224, sha256, sha384, sha512 + * However, the micalg does: + * md5, sha-1, sha-224, sha-256, sha-384, sha-512 + */ +static char *openssl_md_to_smime_micalg(char *md) +{ + char *micalg; + size_t l; + + if (!md) + return 0; + + if (mutt_strncasecmp ("sha", md, 3) == 0) + { + l = strlen (md) + 2; + micalg = (char *)safe_malloc (l); + snprintf (micalg, l, "sha-%s", md +3); + } + else + { + micalg = safe_strdup (md); + } + + return micalg; +} + BODY *smime_sign_message (BODY *a ) @@ -1480,6 +1521,7 @@ BODY *smime_sign_message (BODY *a ) pid_t thepid; smime_key_t *default_key; char *intermediates; + char *micalg; if (!SmimeDefaultKey) { @@ -1586,8 +1628,11 @@ BODY *smime_sign_message (BODY *a ) t->disposition = DISPINLINE; mutt_generate_boundary (&t->parameter); - /* check if this can be extracted from private key somehow.... */ - mutt_set_parameter ("micalg", "sha1", &t->parameter); + + micalg = openssl_md_to_smime_micalg (SmimeDigestAlg); + mutt_set_parameter ("micalg", micalg, &t->parameter); + FREE (&micalg); + mutt_set_parameter ("protocol", "application/x-pkcs7-signature", &t->parameter); @@ -1629,7 +1674,7 @@ pid_t smime_invoke_verify (FILE **smimein, FILE **smimeout, FILE **smimeerr, const char *fname, const char *sig_fname, int opaque) { return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd, - smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL, + smimeerrfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL, (opaque ? SmimeVerifyOpaqueCommand : SmimeVerifyCommand)); } @@ -1640,7 +1685,7 @@ pid_t smime_invoke_decrypt (FILE **smimein, FILE **smimeout, FILE **smimeerr, const char *fname) { return smime_invoke (smimein, smimeout, smimeerr, smimeinfd, smimeoutfd, - smimeerrfd, fname, NULL, NULL, SmimeKeyToUse, + smimeerrfd, fname, NULL, NULL, NULL, SmimeKeyToUse, SmimeCertToUse, NULL, SmimeDecryptCommand); } -- 2.40.0