Commit 40f96d38 authored by Thomas Roessler's avatar Thomas Roessler

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.)
parent 850d0cf0
......@@ -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
......
......@@ -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},
/*
......
......@@ -429,6 +429,7 @@ enum
OPTCRYPTTIMESTAMP,
#ifdef HAVE_SMIME
OPTSMIMEISDEFAULT,
OPTASKCERTLABEL,
#endif
#ifdef HAVE_PGP
OPTPGPIGNORESUB,
......
......@@ -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);
......
/*
* 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
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment