]> granicus.if.org Git - neomutt/commitdiff
smime.c:
authorThomas Roessler <roessler@does-not-exist.org>
Sat, 2 Mar 2002 09:17:40 +0000 (09:17 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Sat, 2 Mar 2002 09:17:40 +0000 (09:17 +0000)
 - the getkeys() function was broken and deleted the last char
   of the certfilename
 - it now lets me use more than one key for the same mailbox
   ie select these.
 - some display output was garbled when the email didn't match.
   i posted some fix to mutt-users, but i don't like that sleep()
   so i dropped the first error message, which basically repeated
   the from/sender field only. so now there's just the message: they
   don't match.

smime_keys:
 - i modified the add_chain to continue even if no roo-cert
   is present (david collantes received som chain that got
   exported from outlook. obiously they don't (always ?)
   include the root cert) it will now abort if neither root
   nor intermediate certs are present.
 - add_cert created index entries with '-' as issuer cert, when
   it should have been '?'. thus verify would fail. (obviously
   nobody ever used that command (add_cert, that is) :)

the feature above obsoletes the hash_cert and fingerprint_cert commands,
adds import_cert command and ask_cert_label bool. i modified the output
of smime_keys (a little) so it doesn't look too garbled when supplying
the label (it is actually interactive :) furthermore, i do a verify
after the cert was added and modified the verify routine to make the
cerificate trusted in case of success. (we discussed this in another
message) that is ok so far, but perhaps this requires some better root
certificate handling, ie the trust should be somehow connected to the
root certificate, that maybe added (if the user trusts it and its not
present already) to the ca-file. i'll think about that some more ... but
then, there already is the add_root command. hmmm... (btw, you'll now
never get asked to trust a certificate)

i have not yet deleted the email handling from the import key stuff (in
smime.c/crypt.c), for i'm thinking about smime_keys using it as an
additional arg. otoh i don't think users would press ^k if verification
failed...hmmm... but still, smime_keys does extract the email from the
certificate either way and does verify it by itself, so the only thing
that would happen is to have some invalid certificates, that mutt'll
refuse to use anyways, left in the database....

(From Oliver Ehli.)

contrib/smime.rc
init.h
mutt.h
smime.c
smime.h
smime_keys.pl

index edbbf3681823923121199c063daa97d8c2f553af..0aacbd09dcccf0e5e39c3a0eb81d0d7d8f5d13df 100644 (file)
@@ -6,6 +6,9 @@
 # will be the default method unless the following option is set
 set smime_is_default
 
+# Uncoment this if you don't want to set labels for certificates you add.
+# unset smime_ask_cert_label
+
 # Passphrase expiration
 set smime_timeout=300
 
@@ -41,17 +44,12 @@ set smime_get_cert_command="openssl pkcs7 -print_certs -in %f"
 # Extract the signer's certificate only from a S/MIME signature (sender verification)
 set smime_get_signer_cert_command="openssl smime -verify -in %f -noverify -signer %c -out /dev/null"
 
-# This is used to get a filename for certificates that get stored in the
-# above directory
-set smime_hash_cert_command="openssl x509 -in  %f -noout -hash"
-
-# This is used to get a md5-fingerprint of a certificate for purpose
-# of comparism
-set smime_fingerprint_cert_command="openssl x509 -in  %f -noout -fingerprint"
-
 # This is used to get the email address the certificate was issued to.
 set smime_get_cert_email_command="openssl x509 -in  %f -noout -email"
 
+# Add a certificate to the database using smime_keys.
+set smime_import_cert_command="smime_keys add_cert %f"
+
 
 
 # Sction B: Outgoing messages
diff --git a/init.h b/init.h
index 9794150b8bc21e064189c5d4135c4ccc6c23b2e0..9056630bb2602e9316e4a35c3d4b5069186a9d59 100644 (file)
--- a/init.h
+++ b/init.h
@@ -1278,6 +1278,12 @@ struct option_t MuttVars[] = {
   ** select the same application that was used to sign/encrypt the original
   ** message.
   */
+  { "smime_ask_cert_label",    DT_BOOL, R_NONE, OPTASKCERTLABEL, 1 },
+  /*
+  ** .pp
+  ** This flag controls wether you want to be asked to enter a label for a certificate
+  ** about to be added to the database or not. It is set by default.
+  */
 #endif
 #ifdef HAVE_PGP
   { "pgp_entry_format", DT_STR,  R_NONE, UL &PgpEntryFormat, UL "%4n %t%f %4l/0x%k %-4a %2c %u" },
@@ -1606,17 +1612,10 @@ struct option_t MuttVars[] = {
   **  signature, so that the certificate's owner may get compared to the email's 
   ** 'From'-field.
   */
-  { "smime_hash_cert_command",         DT_STR, R_NONE, UL &SmimeHashCertCommand, 0},
-  /*
-  ** .pp
-  ** This command is used to calculate a hash value used for storing
-  ** X509 certificates. (The value is derived from the cert's subject field)
-  */
-  { "smime_fingerprint_cert_command",  DT_STR, R_NONE, UL &SmimeFingerprintCertCommand, 0},
+  { "smime_import_cert_command",       DT_STR, R_NONE, UL &SmimeImportCertCommand, 0},
   /*
   ** .pp
-  ** This command returns a md5-fingerprint of the certificate.
-  ** That way, certificates with an identical subject field can get compared.
+  ** This command is used to import a certificate via smime_keys.
   */
   { "smime_get_cert_email_command",    DT_STR, R_NONE, UL &SmimeGetCertEmailCommand, 0},
   /*
diff --git a/mutt.h b/mutt.h
index 6a34feb84dd4895a0c721a0523cbe43863064292..59285227b11c64032d9059a1a75ff9dd0007c0dc 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -429,6 +429,7 @@ enum
   OPTCRYPTTIMESTAMP,
 #ifdef HAVE_SMIME
   OPTSMIMEISDEFAULT,
+  OPTASKCERTLABEL,
 #endif
 #ifdef HAVE_PGP
   OPTPGPIGNORESUB,
diff --git a/smime.c b/smime.c
index 5727b36b3bb23559dde341cc87142da2ee0ef1f5..416044c1166bdd4174f1868856cd1da211687fba 100644 (file)
--- a/smime.c
+++ b/smime.c
@@ -598,7 +598,7 @@ char *smime_get_field_from_db (char *mailbox, char *query, short public, short m
          }
          else if (choice == M_YES)
          {
-           snprintf (key,mutt_strlen(key), fields[1]);
+           snprintf (key,mutt_strlen(key)+1, fields[1]);
            ask = 0;
            break;
          }
@@ -682,7 +682,7 @@ char *smime_get_field_from_db (char *mailbox, char *query, short public, short m
 
   if (key)
   {
-    key[mutt_strlen(key)+1] = 0;
+    key[mutt_strlen(key)+1] = '\0';
     key[mutt_strlen(key)] = '\n';
   }
 
@@ -699,7 +699,7 @@ char *smime_get_field_from_db (char *mailbox, char *query, short public, short m
 
 void _smime_getkeys (char *mailbox)
 {
-  char *k = smime_get_field_from_db (mailbox, NULL, 0, 0);     /* XXX - or sohuld we ask? */
+  char *k = smime_get_field_from_db (mailbox, NULL, 0, 1);
   char buf[STRING];
 
   if (!k)
@@ -729,15 +729,7 @@ void _smime_getkeys (char *mailbox)
              NONULL(SmimeCertificates), k);
 
     if (mutt_strcasecmp (k, SmimeSignAs))
-    {
-      endwin ();
-      mutt_clear_error ();
-      snprintf (buf, sizeof (buf), _("This message seems to require key"
-                                     " %s. (Any key to continue)"), k);
-      mutt_any_key_to_continue (buf);
-      endwin ();
       smime_void_passphrase ();
-    }
 
     safe_free ((void **) &k);
     return;
@@ -915,17 +907,13 @@ static int smime_handle_cert_email (char *certificate, char *mailbox,
 
   if (ret == -1)
   {
-    mutt_copy_stream (fperr, stdout);
     mutt_endwin(NULL);
-    mutt_error (_("Alert: No mailbox specified in certificate.\n"));
+    mutt_copy_stream (fperr, stdout);
+    mutt_any_key_to_continue (_("Error: unable to create OpenSSL subprocess!"));
     ret = 1;
   }
   else if (!ret)
-  {
-    mutt_endwin(NULL);
-    mutt_error (_("Alert: Certificate does *NOT* belong to \"%s\".\n"), mailbox);
     ret = 1;
-  }
   else ret = 0;
 
   if(copy && buffer && num)
@@ -1129,18 +1117,20 @@ static char *smime_extract_signer_certificate (char *infile)
 
 
 
-static int smime_compare_fingerprint (char *certificate, char *hashval, char *dest)
+
+/* Add a certificate and update index file (externally). */
+
+void smime_invoke_import (char *infile, char *mailbox)
 {
-  FILE *fpout = NULL, *fperr = NULL;
-  char tmpfname[_POSIX_PATH_MAX];
-  char md5New[STRING], md5Old[STRING];
-  pid_t thepid;
+  char tmpfname[_POSIX_PATH_MAX], *certfile = NULL, buf[STRING];
+  FILE *smimein=NULL, *fpout = NULL, *fperr = NULL;
+  pid_t thepid=-1;
 
   mutt_mktemp (tmpfname);
   if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
   {
     mutt_perror (tmpfname);
-    return -1;
+    return;
   }
   mutt_unlink (tmpfname);
 
@@ -1149,268 +1139,49 @@ static int smime_compare_fingerprint (char *certificate, char *hashval, char *de
   {
     fclose (fperr);
     mutt_perror (tmpfname);
-    return -1;
+    return;
   }
   mutt_unlink (tmpfname);
 
-  /* fingerprint the certificate to add */
-  if ((thepid =  smime_invoke (NULL, NULL, NULL,
-                              -1, fileno (fpout), fileno (fperr),
-                              certificate, NULL, NULL, NULL, NULL, NULL,
-                              SmimeFingerprintCertCommand))== -1)
-  {
-    mutt_message (_("Error: unable to create OpenSSL subprocess!"));
-    fclose (fperr);
-    fclose (fpout);
-    return -1;
-  }
-
-  mutt_wait_filter (thepid);
-  
-  fflush (fpout);
-  rewind (fpout);
-  fflush (fperr);
-  rewind (fperr);
 
-  if (!(fgets (md5New, sizeof (md5New), fpout)))
-  {
-    mutt_copy_stream (fperr, stdout);
-    fclose (fpout);
-    fclose (fperr);
-    return -1;
-  }
+  buf[0] = '\0';
+  if (option (OPTASKCERTLABEL))
+    mutt_get_field ("Label for certificate:", buf, sizeof (buf), 0);
 
-  /* fingerprint the certificate already installed */
-  if ((thepid =  smime_invoke (NULL, NULL, NULL,
-                              -1, fileno (fpout), fileno (fperr),
-                              dest, NULL, NULL, NULL, NULL, NULL,
-                              SmimeFingerprintCertCommand))== -1)
+  mutt_endwin (NULL);
+  if ((certfile = smime_extract_certificate(infile)))
   {
-    mutt_message (_("Error: unable to create OpenSSL subprocess!"));
-    fclose (fperr);
-    fclose (fpout);
-    return -1;
-  }
-
-  mutt_wait_filter (thepid);
+    mutt_endwin (NULL);
   
-  fflush (fpout);
-  rewind (fpout);
-  fflush (fperr);
-  rewind (fperr);
-
-  if (!(fgets (md5Old, sizeof (md5Old), fpout)))
-  {
-    mutt_copy_stream (fperr, stdout);
-    fclose (fpout);
-    fclose (fperr);
-    return -1;
-  }
-
-  fclose (fpout);
-  fclose (fperr);
-
-  return ((mutt_strcasecmp (md5Old, md5New) == 0));
-}
-
-
-/* Add a certificate and update index file. */
-
-static int smime_add_certificate (char *certificate, char *mailbox)
-{
-  FILE *fpin = NULL, *fpout = NULL, *fperr = NULL;
-  char tmpfname[_POSIX_PATH_MAX], dest[_POSIX_PATH_MAX];
-  char buf[LONG_STRING], hashval[STRING], *tmpKey;
-  struct stat info;
-  int i = 0, certExists=0;
-  pid_t thepid;
-
-  mutt_mktemp (tmpfname);
-  if ((fperr = safe_fopen (tmpfname, "w+")) == NULL)
-  {
-    mutt_perror (tmpfname);
-    return 1;
-  }
-  mutt_unlink (tmpfname);
-
-  mutt_mktemp (tmpfname);
-  if ((fpout = safe_fopen (tmpfname, "w+")) == NULL)
-  {
-    fclose (fperr);
-    mutt_perror (tmpfname);
-    return 1;
-  }
-  mutt_unlink (tmpfname);
-
-  /* 
-     OpenSSl can create a hash value of the certificate's subject.
-     This and a concatenated integer make up the certificate's
-     'unique id' and also its filename.
-  */
+    if ((thepid =  smime_invoke (&smimein, NULL, NULL,
+                                -1, fileno(fpout), fileno(fperr),
+                                certfile, NULL, NULL, NULL, NULL, NULL,
+                                SmimeImportCertCommand))== -1)
+    {
+      mutt_message (_("Error: unable to create OpenSSL subprocess!"));
+      return;
+    }
+    fputs (buf, smimein);
+    fputc ('\n', smimein);
+    fclose(smimein);
 
-  mutt_endwin (NULL);
+    mutt_wait_filter (thepid);
   
-  if ((thepid =  smime_invoke (NULL, NULL, NULL,
-                              -1, fileno (fpout), fileno (fperr),
-                              certificate, NULL, NULL, NULL, NULL, NULL,
-                              SmimeHashCertCommand))== -1)
-  {
-    mutt_message (_("Error: unable to create OpenSSL subprocess!"));
-    fclose (fperr);
-    fclose (fpout);
-    return 1;
+    mutt_unlink (certfile);
+    safe_free((void **)&certfile);
   }
 
-  mutt_wait_filter (thepid);
-  
   fflush (fpout);
   rewind (fpout);
   fflush (fperr);
   rewind (fperr);
 
-  if (!(fgets (hashval, sizeof (hashval), fpout)))
-  {
-    mutt_copy_stream (fperr, stdout);
-    fclose (fpout);
-    fclose (fperr);
-    return 1;
-  }
+  mutt_copy_stream (fpout, stdout);
+  mutt_copy_stream (fperr, stdout);
+
   fclose (fpout);
   fclose (fperr);
 
-  *(hashval+mutt_strlen(hashval)-1) = '\0';
-
-  while (1)
-  {
-    snprintf (dest, sizeof (dest), "%s/%s.%d", NONULL(SmimeCertificates),
-             hashval, i);
-
-    if (stat (dest, &info))
-      break;
-    else { /* check wether this certificate already exists. */
-      if((certExists = smime_compare_fingerprint (certificate, hashval, dest)) == 1)
-      {
-       break;
-      }
-      else
-      {
-       if(!certExists)
-         i++;
-       else  /* some error: abort. */
-         return 1;
-      }
-    }
-  }
-  
-  if(!certExists)
-  {
-    if ((fpout = safe_fopen (dest, "w+")) == NULL)
-    {
-      mutt_perror (dest);
-      return 1;
-    }
-
-    if ((fpin = safe_fopen (certificate, "r")) == NULL)
-    {
-      mutt_perror (certificate);
-      fclose (fpout);
-      mutt_unlink (dest);
-      return 1;
-    }
-    
-    mutt_copy_stream (fpin, fpout);
-    fclose (fpout);
-    fclose (fpin);
-  }
-
-
-  /*
-    Now check if the mailbox is already found with the certificate's
-    hash value and/or md5 fingerprint.
-  */
-  
-  tmpKey = smime_get_field_from_db (mailbox, NULL, 1, 0); /* _always_ public! */
-
-  /* check if hash is identical => same certificate! */
-  /* perhaps we should ask for permission to overwrite ? */
-  /* what about revoked certificates anyway ? */
-
-  if (tmpKey && !mutt_strncmp (tmpKey, hashval, mutt_strlen (hashval)))
-  {
-    mutt_message (_("Certificate \"%s\" exists for \"%s\"."), hashval, mailbox);
-    return 0;
-  }
-    
-  /* doesn't exist or is a new one, so append to index. */
-  snprintf (tmpfname, sizeof (tmpfname), "%s/.index",
-           NONULL(SmimeCertificates)); /* _always_ public: we don't add keys here */
-  
-  if (!stat (tmpfname, &info))
-  {
-    if ((fpout = safe_fopen (tmpfname, "a")) == NULL)
-    {
-      mutt_perror (tmpfname);
-      mutt_unlink (dest);
-      return 1;
-    }
-    /*
-       ? = unknown issuer, - = unassigned label,
-       v = undefined trust settings (else we wouldn't have got that far).
-    */
-    snprintf (buf, sizeof (buf), "%s %s.%d - ? u\n", mailbox, hashval, i);
-    fputs (buf, fpout);
-    fclose (fpout);
-    
-    mutt_message (_("Successfully added certificate \"%s\" for \"%s\". "), hashval, mailbox);
-  }
-
-  return 0;
-}
-
-
-
-void smime_invoke_import (char *infile, char *mailbox)
-{
-  char *certfile = NULL, **addrList=0;
-  int i, addrCount=0, ret = 0;
-  certfile = smime_extract_signer_certificate(infile);
-  
-  if (certfile)
-  { 
-    i = smime_handle_cert_email (certfile, mailbox, 1, &addrList, &addrCount);
-  
-    mutt_unlink(certfile);
-  
-    if (i)
-    {
-      mutt_message _("Certificate *NOT* added.");
-      return;
-    }
-    if ((certfile = smime_extract_certificate(infile)))
-    {
-      for (i = 0; i < addrCount; i++)
-      {
-       /* perhaps we shouldn't abort completley ? */
-
-       if(!ret)
-         ret = smime_add_certificate (certfile, addrList[i]);
-
-       safe_free((void **)&(addrList[i]));
-      }
-      mutt_unlink (certfile);
-      safe_free((void **)&certfile);
-      safe_free((void **)&addrList);
-    }
-    if(!ret)
-      return;
-  }  
-
-  if(isendwin())
-  {
-    mutt_any_key_to_continue(NULL);
-    mutt_message _("Certificate *NOT* added.");
-  }
-  return;
 }
 
 
@@ -1455,7 +1226,10 @@ int smime_verify_sender(HEADER *h)
     {
       mutt_unlink(tempfname);
       if (smime_handle_cert_email (certfile, mbox, 0, NULL, NULL))
-       mutt_any_key_to_continue(NULL);
+      {
+       if(isendwin())
+         mutt_any_key_to_continue(NULL);
+      }
       else
        retval = 0;
       mutt_unlink(certfile);
diff --git a/smime.h b/smime.h
index 2f56e6d518b513b8432cf60ccfccce44c52a54c9..90f7fe1a93f4460815f67bd0f8b9c3a8a9bcbc92 100644 (file)
--- a/smime.h
+++ b/smime.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2001 Oliver Ehli <elmy@acm.org>
+ * Copyright (C) 2001,2002 Oliver Ehli <elmy@acm.org>
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
@@ -42,8 +42,7 @@ WHERE char *SmimeEncryptCommand;
 WHERE char *SmimeGetSignerCertCommand;
 WHERE char *SmimePk7outCommand;
 WHERE char *SmimeGetCertCommand;
-WHERE char *SmimeHashCertCommand;
-WHERE char *SmimeFingerprintCertCommand;
+WHERE char *SmimeImportCertCommand;
 WHERE char *SmimeGetCertEmailCommand;
 
 
@@ -66,30 +65,28 @@ void smime_void_passphrase (void);
 int mutt_is_application_smime (BODY *);
 
 
+int   smime_decrypt_mime (FILE *, FILE **, BODY *, BODY **);
 
+void  smime_application_smime_handler (BODY *, STATE *);
 
-int smime_decrypt_mime (FILE *, FILE **, BODY *, BODY **);
 
-void smime_application_smime_handler (BODY *, STATE *);
+BODY* smime_sign_message (BODY *);
 
-int smime_verify_sender(HEADER *);
+BODY* smime_build_smime_entity (BODY *, char *);
 
+int   smime_verify_one(BODY *, STATE *, const char *);
 
 
+int   smime_verify_sender(HEADER *);
 
-char *smime_get_field_from_db (char *, char *, short, short);
 
-char* smime_ask_for_key (char *, char *, short);
-
-void smime_getkeys (ENVELOPE *);
+char* smime_get_field_from_db (char *, char *, short, short);
 
-/* private ? */
+void  smime_getkeys (ENVELOPE *);
 
-void smime_invoke_import (char *, char *);
+char* smime_ask_for_key (char *, char *, short);
 
-int smime_verify_one(BODY *, STATE *, const char *);
 
-BODY *smime_sign_message (BODY *);
+void  smime_invoke_import (char *, char *);
 
-BODY *smime_build_smime_entity (BODY *, char *);
 #endif
index 584c3b3e01e96cc1c5c5c1ccde5683f7395cba13..3677e73d0bc2a6ae9b34f7db968c3cdda47cec4f 100755 (executable)
@@ -82,7 +82,7 @@ elsif(@ARGV == 2 and $ARGV[0] eq "add_cert") {
     $? and die "'$cmd' returned $?";
     chomp($cert_hash); 
     my $label = query_label;
-    &add_certificate($ARGV[1], \$cert_hash, 1, $label, '-');
+    &add_certificate($ARGV[1], \$cert_hash, 1, $label, '?');
 }
 elsif(@ARGV == 2 and $ARGV[0] eq "add_pem") {
     -e $ARGV[1] and -s $ARGV[1] or die("$ARGV[1] is nonexistent or empty.");
@@ -462,7 +462,10 @@ sub add_certificate ($$$$;$) {
     }
     $$hashvalue .= ".$iter";
     
-    unless (-e "$certificates_path/$$hashvalue") {
+    if (-e "$certificates_path/$$hashvalue") {
+            print "\nCertificate: $certificates_path/$$hashvalue already installed.\n";
+    }
+    else {
         mycopy $filename, "$certificates_path/$$hashvalue";
 
         if ($add_to_index) {
@@ -475,8 +478,9 @@ sub add_certificate ($$$$;$) {
              chomp($mailbox);
              add_entry($mailbox, $$hashvalue, 1, $label, $issuer_hash);
 
-             print "added certificate: $certificates_path/$$hashvalue for $mailbox.\n";
+             print "\ncertificate $$hashvalue ($label) for $mailbox added.\n";
            }
+           verify_cert($$hashvalue, undef);
         }
         else {
             print "added certificate: $certificates_path/$$hashvalue.\n";
@@ -627,7 +631,10 @@ sub handle_pem (@) {
         }
         $iter++;
     }
-    ($iter > $#pem_contents / 4) and die("Couldn't identify root certificate!");
+    if ($iter > $#pem_contents / 4) {
+      print "Couldn't identify root certificate!\n";
+      $root_cert = -1;      
+    }
 
     # what's left are intermediate certificates.
     $iter = 0;
@@ -652,8 +659,10 @@ sub handle_pem (@) {
         $iter++;
     }
 
-    # no intermediate certificates ? use root-cert instead
+    # no intermediate certificates ? use root-cert instead (if that was found...)
     if($intermediate == $root_cert) {
+        $root_cert == -1 and
+         die("No root and no intermediate certificates. Can't continue.");
         mycopy "cert_tmp.$root_cert", 'tmp_issuer_cert';
     }
 
@@ -878,17 +887,7 @@ sub do_verify($$$) {
   print "\n";
 
   if ($result eq 'v') {
-    print "Certificate was successfully verified.\n";
-    while(1) {
-      print "Do you choose to trust this certificate ? (yes/no) ";
-      chomp($trust_q = <STDIN>);
-      if ($trust_q =~ /^y/i) {
-        return 't';
-      } elsif ($trust_q =~ /^n/i) {
-        return 'v';
-      }
-      print "That made no sense.\n";
-    }   
+    return 't';
   }
 
   return $result;