]> granicus.if.org Git - mutt/commitdiff
smime: allow signing message digest algorithm to be specified.
authorKevin McCarthy <kevin@8t8.us>
Mon, 30 Nov 2015 23:52:30 +0000 (15:52 -0800)
committerKevin McCarthy <kevin@8t8.us>
Mon, 30 Nov 2015 23:52:30 +0000 (15:52 -0800)
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
globals.h
init.h
smime.c

index 0f85421ed6e06a4ec5c0dbc79c49c375edb60423..532ac9ec004a11827cf7044c9cf29bbae4112369 100644 (file)
@@ -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:
 #
index e77030c71e252d8256d4e0a1d467cf7ae8a48a46..245902c202610d0ee9005840e815e3d84643fe4b 100644 (file)
--- 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 8f5aac5dde00a2ce5327c82d86022d0029b3d7fe..b0402a1f66d0aa21e25bb4506961438d63fe0225 100644 (file)
--- 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 97e77e757bbeddeb4e84dfb109817e005dc88aaf..9192f842060bdcde074c1f7d7bcb06161b3fdb7a 100644 (file)
--- 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);
 }