changeset: 6534:428a92464d5b
user:      Kevin McCarthy <[email protected]>
date:      Mon Nov 30 15:52:30 2015 -0800
link:      http://dev.mutt.org/hg/mutt/rev/428a92464d5b

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.

diffs (244 lines):

diff -r ff560d1f3f7a -r 428a92464d5b contrib/smime.rc
--- a/contrib/smime.rc  Thu Nov 26 11:01:19 2015 -0800
+++ b/contrib/smime.rc  Mon Nov 30 15:52:30 2015 -0800
@@ -65,8 +65,12 @@
 # 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 @@
 
 # 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 -r ff560d1f3f7a -r 428a92464d5b globals.h
--- a/globals.h Thu Nov 26 11:01:19 2015 -0800
+++ b/globals.h Mon Nov 30 15:52:30 2015 -0800
@@ -258,6 +258,7 @@
 WHERE char *SmimeVerifyOpaqueCommand;
 WHERE char *SmimeDecryptCommand;
 WHERE char *SmimeSignCommand;
+WHERE char *SmimeDigestAlg;
 WHERE char *SmimeSignOpaqueCommand;
 WHERE char *SmimeEncryptCommand;
 WHERE char *SmimeGetSignerCertCommand;
diff -r ff560d1f3f7a -r 428a92464d5b init.h
--- a/init.h    Thu Nov 26 11:01:19 2015 -0800
+++ b/init.h    Mon Nov 30 15:52:30 2015 -0800
@@ -2720,6 +2720,7 @@
   ** .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 @@
   ** 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 -r ff560d1f3f7a -r 428a92464d5b smime.c
--- a/smime.c   Thu Nov 26 11:01:19 2015 -0800
+++ b/smime.c   Mon Nov 30 15:52:30 2015 -0800
@@ -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 @@
       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 @@
                           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 @@
   cctx.sig_fname       = sig_fname;
   cctx.key            = key;
   cctx.cryptalg               = cryptalg;
+  cctx.digestalg       = digestalg;
   cctx.certificates    = certificates;
   cctx.intermediates   = intermediates;
   
@@ -936,7 +950,7 @@
 
   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 @@
   */
   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 @@
    */
   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 @@
    */
   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 @@
   
     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 @@
 {
   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 @@
                         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 @@
 }
 
 
+/* 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 @@
   pid_t thepid;
   smime_key_t *default_key;
   char *intermediates;
+  char *micalg;
 
   if (!SmimeDefaultKey)
   {
@@ -1586,8 +1628,11 @@
   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 @@
                           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 @@
                            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);
 }
 

Reply via email to