summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alpine/alpine.c1
-rw-r--r--alpine/mailcmd.c10
-rw-r--r--alpine/mailcmd.h1
-rw-r--r--pith/options.h6
-rw-r--r--pith/pine.hlp14
-rw-r--r--pith/smime.c29
6 files changed, 49 insertions, 12 deletions
diff --git a/alpine/alpine.c b/alpine/alpine.c
index c7542da8..c3c5f86d 100644
--- a/alpine/alpine.c
+++ b/alpine/alpine.c
@@ -192,6 +192,7 @@ main(int argc, char **argv)
pith_opt_smime_get_passphrase = smime_get_passphrase;
pith_smime_import_certificate = smime_import_certificate;
pith_smime_enter_password = alpine_get_password;
+ pith_smime_confirm_save = alpine_smime_confirm_save;
#endif
#ifdef ENABLE_LDAP
pith_opt_save_ldap_entry = save_ldap_entry;
diff --git a/alpine/mailcmd.c b/alpine/mailcmd.c
index e134e8dc..36b92d78 100644
--- a/alpine/mailcmd.c
+++ b/alpine/mailcmd.c
@@ -302,6 +302,16 @@ static ESCKEY_S flag_text_opt[] = {
{-1, 0, NULL, NULL}
};
+int
+alpine_smime_confirm_save(char *email)
+{
+ char prompt[128];
+
+ snprintf(prompt, sizeof(prompt), _("Save certificate for <%s>"),
+ email ? email : _("missing address"));
+ return want_to(prompt, 'n', 'x', NO_HELP, WT_NORM) == 'y';
+}
+
int
alpine_get_password(char *prompt, char *pass, size_t len)
{
diff --git a/alpine/mailcmd.h b/alpine/mailcmd.h
index e0f31d3b..613b43f6 100644
--- a/alpine/mailcmd.h
+++ b/alpine/mailcmd.h
@@ -67,6 +67,7 @@ typedef enum {View, MsgIndx, ThrdIndx} CmdWhere;
/* exported protoypes */
int alpine_get_data_prompt(char *, char *, size_t);
int alpine_get_password(char *, char *, size_t);
+int alpine_smime_confirm_save(char *);
int smime_import_certificate(char *, char *, size_t);
int process_cmd(struct pine *, MAILSTREAM *, MSGNO_S *, int, CmdWhere, int *);
char *pretty_command(UCS);
diff --git a/pith/options.h b/pith/options.h
index f35bcfa3..bdaa252c 100644
--- a/pith/options.h
+++ b/pith/options.h
@@ -234,4 +234,10 @@ extern int (*pith_smime_import_certificate)(char *, char *, size_t);
*/
extern int (*pith_smime_enter_password)(char *, char *, size_t);
+/*
+ * required call to ask the user to confirm to save a certificate in the
+ * store
+ */
+extern int (*pith_smime_confirm_save)(char *);
+
#endif /* PITH_OPTIONS_INCLUDED */
diff --git a/pith/pine.hlp b/pith/pine.hlp
index 64216fcb..b5507329 100644
--- a/pith/pine.hlp
+++ b/pith/pine.hlp
@@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any
reasonable place to be called from.
Dummy change to get revision in pine.hlp
============= h_revision =================
-Alpine Commit 112 2015-11-18 09:02:07
+Alpine Commit 113 2015-12-05 02:13:57
============= h_news =================
<HTML>
<HEAD>
@@ -221,6 +221,11 @@ Additions include:
<LI> SMIME: sort certificates by some type of alphabetical order in the
displayed name.
+ <LI> SMIME: Alpine will ask users if they wish to save S/MIME
+ certificates included in signatures, when the option "Validate
+ Using Certificate Store Only" is enabled. If the user does not wish
+ to save it, validation will fail.
+
<LI> HTML: Add support for decoding entities in hexadecimal notation.
Suggested by Tulip&aacute;nt Gergely.
@@ -34953,7 +34958,12 @@ either use the certificates that come in the message, or the ones that
you have personally stored. If this feature is enabled (the default) then
Alpine will use certificates that you have already saved in your store
and not those that come in the message to validate the sender of the
-message. This behavior helps you prevent against impersonation, because
+message. In particular, the first time that you receive a signed message
+from a sender, and their certificate does not validate against your
+store, then you will be asked if you wish to save such certificate. If
+you do not wish to save the certificate, then Alpine will fail to validate
+the signature of the message. Otherwise, Alpine will proceed to validate
+the signature of the message. This behavior helps you prevent against impersonation, because
it is assumed that you trust the certificates that you have saved, and
might not trust those that came with the message that you are validating.
<P>
diff --git a/pith/smime.c b/pith/smime.c
index 01e0df09..30f42a22 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -71,7 +71,7 @@ static int copy_container_to_dir(WhichCerts which);
static int do_fiddle_smime_message(BODY *b, long msgno, char *section);
void setup_privatekey_storage(void);
int smime_path(char *rpath, char *fpath, size_t len);
-int smime_extract_and_save_cert(PKCS7 *p7);
+int smime_extract_and_save_cert(PKCS7 *p7, int check_cert);
int same_cert(X509 *, X509 *);
CertList * certlist_from_personal_certs(PERSONAL_CERT *pc);
#ifdef PASSFILE
@@ -85,6 +85,7 @@ int smime_validate_extra_test(char *mimetext, unsigned long mimelen, char
int (*pith_opt_smime_get_passphrase)(void);
int (*pith_smime_import_certificate)(char *, char *, size_t);
int (*pith_smime_enter_password)(char *prompt, char *, size_t);
+int (*pith_smime_confirm_save)(char *email);
static X509_STORE *s_cert_store;
@@ -2478,12 +2479,13 @@ int same_cert(X509 *x, X509 *cert)
* < 0 - certificate error is not recoverable, don't even think about it.
*/
-int smime_extract_and_save_cert(PKCS7 *p7)
+int smime_extract_and_save_cert(PKCS7 *p7, int check_cert)
{
STACK_OF(X509) *signers;
X509 *x, *cert;
char **email;
int i, j;
+ long error;
if((signers = PKCS7_get0_signers(p7, NULL, 0)) == NULL)
return -1;
@@ -2495,10 +2497,15 @@ int smime_extract_and_save_cert(PKCS7 *p7)
if((email = get_x509_subject_email(x)) != NULL){
for(j = 0; email[j] != NULL; j++){
if((cert = get_cert_for(email[j], Public)) == NULL
- || same_cert(x, cert) == 0)
- save_cert_for(email[j], x, Public);
- X509_free(cert);
- fs_give((void **) &email[i]);
+ || same_cert(x, cert) == 0){
+ if(check_cert == 0
+ || smime_validate_cert(x, &error) == 0
+ || (*pith_smime_confirm_save)(email[j]) == 1)
+ save_cert_for(email[j], x, Public);
+ }
+ if(cert != NULL)
+ X509_free(cert);
+ fs_give((void **) &email[j]);
}
fs_give((void **) email);
}
@@ -2521,8 +2528,7 @@ do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent)
{
STACK_OF(X509) *otherCerts = NULL;
CertList *cl;
- int result;
- int flags;
+ int result, flags;
const char *data;
long err;
@@ -2533,8 +2539,6 @@ do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent)
return -1;
}
- smime_extract_and_save_cert(p7);
-
flags = F_ON(F_USE_CERT_STORE_ONLY, ps_global) ? PKCS7_NOINTERN : 0;
if(ps_global->smime->publiccertlist == NULL){
@@ -2773,6 +2777,7 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
PART *p;
int result, modified_the_body = 0;
int flag; /* 1 silent, 0 not silent */
+ int saved = 0;
unsigned long mimelen, bodylen;
char newSec[100], *mimetext, *bodytext;
char *what_we_did;
@@ -2816,6 +2821,10 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
BIO_write(in, mimetext, mimelen);
BIO_write(in, bodytext, bodylen);
+ saved = smime_extract_and_save_cert(p7, F_ON(F_USE_CERT_STORE_ONLY, ps_global));
+ if(saved < 0 && F_ON(F_USE_CERT_STORE_ONLY, ps_global))
+ return modified_the_body;
+
if((result = do_signature_verify(p7, in, NULL, 1)) == 0){
flag = (mimelen == 0 || !IS_REMOTE(ps_global->mail_stream->mailbox))
? 0 : 1;