From: Thomas Roessler Date: Sat, 2 Mar 2002 09:17:40 +0000 (+0000) Subject: smime.c: X-Git-Tag: mutt-1-5-1-rel~55 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=40f96d386ba185ef342fa6270eba4434869fdfdf;p=mutt smime.c: - 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.) --- diff --git a/contrib/smime.rc b/contrib/smime.rc index edbbf368..0aacbd09 100644 --- a/contrib/smime.rc +++ b/contrib/smime.rc @@ -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 9794150b..9056630b 100644 --- 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 6a34feb8..59285227 100644 --- 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 5727b36b..416044c1 100644 --- 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 2f56e6d5..90f7fe1a 100644 --- a/smime.h +++ b/smime.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Oliver Ehli + * Copyright (C) 2001,2002 Oliver Ehli * * 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 diff --git a/smime_keys.pl b/smime_keys.pl index 584c3b3e..3677e73d 100755 --- a/smime_keys.pl +++ b/smime_keys.pl @@ -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 = ); - if ($trust_q =~ /^y/i) { - return 't'; - } elsif ($trust_q =~ /^n/i) { - return 'v'; - } - print "That made no sense.\n"; - } + return 't'; } return $result;