summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2014-05-31 21:37:10 -0600
committerEduardo Chappa <chappa@washington.edu>2014-05-31 21:37:10 -0600
commit60b67de2ba4be4d2bfeeeea685869e9a5a7363c0 (patch)
tree20831a8341dfe86c0f4c247df9ac5b5ec61b41db
parentd8f387ef722cfb9e694d25c1ab182d01501f1b9d (diff)
downloadalpine-60b67de2ba4be4d2bfeeeea685869e9a5a7363c0.tar.xz
* new version 2.19.9991
* S/MIME Alpine would compute incorrectly the signature of a message that contains 8bit if the option "Enable 8bit ESMTP Negotiation" is enabled, the message contains 8bit characters and the smtp server supports 8bit sending. * Crash while redrawing S/MIME configuration screen when importing a certificate * When forwarding a message before opening it, the message might not be found. The problem is in the forward_body function, where the section of the body is not correctly set in all instances. * When forwarding a signed message Alpine might forward the message as a multipart message, instead of just selecting the body of the message. Change to forward the signed part only. This aligns Alpine with what it does when it replies to a similar message.
-rw-r--r--VERSION2
-rw-r--r--alpine/confscroll.c2
-rw-r--r--alpine/osdep/mswin.rc8
-rw-r--r--alpine/smime.c77
-rwxr-xr-xconfigure20
-rw-r--r--doc/alpine.12
-rw-r--r--doc/tech-notes/index.html2
-rw-r--r--doc/tech-notes/tech-notes.txt2
-rw-r--r--mapi/pmapi.c2
-rw-r--r--mapi/pmapi.rc8
-rw-r--r--pith/pine.hlp9
-rw-r--r--pith/reply.c23
-rw-r--r--pith/send.c31
-rw-r--r--pith/smime.c216
-rw-r--r--pith/smime.h3
-rw-r--r--pith/smkeys.c25
-rw-r--r--pith/smkeys.h3
17 files changed, 340 insertions, 95 deletions
diff --git a/VERSION b/VERSION
index f14b0551..52397008 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.19.999
+2.19.9991
diff --git a/alpine/confscroll.c b/alpine/confscroll.c
index 71648202..8d1940a9 100644
--- a/alpine/confscroll.c
+++ b/alpine/confscroll.c
@@ -3042,6 +3042,8 @@ update_option_screen(struct pine *ps, OPT_SCREEN_S *screen, Pos *cursor_pos)
if(screen == NULL || BODY_LINES(ps) < 1)
return;
+ opt_screen = screen;
+
if(cursor_pos){
cursor_pos->col = 0;
cursor_pos->row = -1; /* to tell us if we've set it yet */
diff --git a/alpine/osdep/mswin.rc b/alpine/osdep/mswin.rc
index a6ae8c6c..370044fe 100644
--- a/alpine/osdep/mswin.rc
+++ b/alpine/osdep/mswin.rc
@@ -244,8 +244,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,19,999,0
- PRODUCTVERSION 2,19,999,0
+ FILEVERSION 2,19,9991,0
+ PRODUCTVERSION 2,19,9991,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -267,12 +267,12 @@ BEGIN
#else
VALUE "FileDescription", "Alpine\0"
#endif
- VALUE "FileVersion", "2.19.999\0"
+ VALUE "FileVersion", "2.19.9991\0"
VALUE "InternalName", "alpine\0"
VALUE "LegalCopyright", "Copyright 2006-2009 University of Washington, Copyright 2013-2014\0"
VALUE "OriginalFilename", "alpine.exe\0"
VALUE "ProductName", "alpine\0"
- VALUE "ProductVersion", "2.19.999\0"
+ VALUE "ProductVersion", "2.19.9991\0"
END
END
BLOCK "VarFileInfo"
diff --git a/alpine/smime.c b/alpine/smime.c
index 1249ec72..caf0581a 100644
--- a/alpine/smime.c
+++ b/alpine/smime.c
@@ -332,7 +332,8 @@ output_cert_info(X509 *cert, gf_io_t pc)
char buf[256];
STORE_S *left,*right;
gf_io_t spc;
- int len;
+ int len, error;
+ STACK_OF(X509) *chain;
left = so_get(CharStar, NULL, EDIT_ACCESS);
right = so_get(CharStar, NULL, EDIT_ACCESS);
@@ -435,16 +436,84 @@ output_cert_info(X509 *cert, gf_io_t pc)
gf_puts_uline("SHA1 Fingerprint", pc);
gf_puts(NEWLINE, pc);
- get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf));
+ get_fingerprint(cert, EVP_sha1(), buf, sizeof(buf), ":");
gf_puts(buf, pc);
gf_puts(NEWLINE, pc);
gf_puts_uline("MD5 Fingerprint", pc);
gf_puts(NEWLINE, pc);
- get_fingerprint(cert, EVP_md5(), buf, sizeof(buf));
+ get_fingerprint(cert, EVP_md5(), buf, sizeof(buf), ":");
gf_puts(buf, pc);
gf_puts(NEWLINE, pc);
+ gf_puts(NEWLINE, pc);
+
+ gf_puts_uline("Certificate Chain Information", pc);
+ gf_puts(NEWLINE, pc);
+ if((chain = get_chain_for_cert(cert, &error, &len)) != NULL){
+ X509 *x;
+ X509_NAME_ENTRY *e;
+ int i, offset = 2;
+ char space[256];
+
+ for(i = 0; i < offset; i++) space[i] = ' ';
+
+ for(i = -1; i < sk_X509_num(chain); i++){
+ char buf[256];
+
+ x = i == -1 ? cert : sk_X509_value(chain, i);
+
+ if(x && x->cert_info){
+ if(i>=0){
+ space[offset + i + 0] = ' ';
+ space[offset + i + 1] = '\\';
+ space[offset + i + 2] = '-';
+ space[offset + i + 3] = ' ';
+ space[offset + i + 4] = '\0';
+ gf_puts(space, pc);
+ }
+ else{
+ space[offset] = '\0';
+ gf_puts(space, pc);
+ }
+ if(i >= 0)
+ gf_puts_uline("Signed by: ", pc);
+ else
+ gf_puts_uline("Issued to: ", pc);
+
+ e = X509_NAME_get_entry(x->cert_info->subject,
+ X509_NAME_entry_count(x->cert_info->subject)-1);
+
+ if(e){
+ X509_NAME_get_text_by_OBJ(x->cert_info->subject, e->object, buf, sizeof(buf));
+ gf_puts(buf, pc);
+ gf_puts(NEWLINE, pc);
+ }
+ }
+ else{
+ gf_puts("No certificate info found", pc);
+ gf_puts(NEWLINE, pc);
+ break;
+ }
+ }
+ e = X509_NAME_get_entry(x->cert_info->issuer,
+ X509_NAME_entry_count(x->cert_info->issuer)-1);
+ if(e){
+ X509_NAME_get_text_by_OBJ(x->cert_info->issuer, e->object, buf, sizeof(buf));
+ space[offset + i + 0] = ' ';
+ space[offset + i + 1] = '\\';
+ space[offset + i + 2] = '-';
+ space[offset + i + 3] = ' ';
+ space[offset + i + 4] = '\0';
+ gf_puts(space, pc);
+ gf_puts_uline("Signed by: ", pc);
+ gf_puts(buf, pc);
+ gf_puts(NEWLINE, pc);
+ }
+ sk_X509_pop_free(chain, X509_free);
+ }
+ gf_puts(NEWLINE, pc);
+
so_give(&left);
so_give(&right);
}
@@ -939,6 +1008,8 @@ smime_config_init_display(struct pine *ps, CONF_S **ctmp, CONF_S **first_line)
(*ctmp)->help = h_config_smime_certificate_authorities;
(*ctmp)->value = cpystr(_("Manage Certificate Authorities"));
(*ctmp)->varmem = 11;
+
+ (*ctmp)->next = NULL;
}
void display_certificate_information(struct pine *ps, X509 *cert, char *email, WhichCerts ctype, int num)
diff --git a/configure b/configure
index dccad1d1..67d6ea38 100755
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
#! /bin/sh
# From configure.ac Rev:14 by chappa@washington.edu.
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for alpine 2.19.999.
+# Generated by GNU Autoconf 2.69 for alpine 2.19.9991.
#
# Report bugs to <chappa@washington.edu>.
#
@@ -730,8 +730,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='alpine'
PACKAGE_TARNAME='alpine'
-PACKAGE_VERSION='2.19.999'
-PACKAGE_STRING='alpine 2.19.999'
+PACKAGE_VERSION='2.19.9991'
+PACKAGE_STRING='alpine 2.19.9991'
PACKAGE_BUGREPORT='chappa@washington.edu'
PACKAGE_URL=''
@@ -1596,7 +1596,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures alpine 2.19.999 to adapt to many kinds of systems.
+\`configure' configures alpine 2.19.9991 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1666,7 +1666,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of alpine 2.19.999:";;
+ short | recursive ) echo "Configuration of alpine 2.19.9991:";;
esac
cat <<\_ACEOF
@@ -1953,7 +1953,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-alpine configure 2.19.999
+alpine configure 2.19.9991
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2559,7 +2559,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by alpine $as_me 2.19.999, which was
+It was created by alpine $as_me 2.19.9991, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3380,7 +3380,7 @@ fi
# Define the identity of the package.
PACKAGE='alpine'
- VERSION='2.19.999'
+ VERSION='2.19.9991'
cat >>confdefs.h <<_ACEOF
@@ -20355,7 +20355,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by alpine $as_me 2.19.999, which was
+This file was extended by alpine $as_me 2.19.9991, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -20421,7 +20421,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-alpine config.status 2.19.999
+alpine config.status 2.19.9991
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/doc/alpine.1 b/doc/alpine.1
index 51e8a70a..a0e78957 100644
--- a/doc/alpine.1
+++ b/doc/alpine.1
@@ -1,4 +1,4 @@
-.TH alpine 1 "Version 2.19.999"
+.TH alpine 1 "Version 2.19.9991"
.SH NAME
alpine \- an Alternatively Licensed Program for Internet News and Email
.SH SYNTAX
diff --git a/doc/tech-notes/index.html b/doc/tech-notes/index.html
index 5a05c1e4..3ec86306 100644
--- a/doc/tech-notes/index.html
+++ b/doc/tech-notes/index.html
@@ -3,7 +3,7 @@
<BODY>
<H1>Alpine Technical Notes</H1>
-Version 2.19.999, May 2014
+Version 2.19.9991, May 2014
<H2><A NAME="TOC">Table of Contents</A></H2><P>
diff --git a/doc/tech-notes/tech-notes.txt b/doc/tech-notes/tech-notes.txt
index e9bed323..356e49c5 100644
--- a/doc/tech-notes/tech-notes.txt
+++ b/doc/tech-notes/tech-notes.txt
@@ -1,7 +1,7 @@
Alpine Technical Notes
- Version 2.19.999, May 2014
+ Version 2.19.9991, May 2014
Table of Contents
diff --git a/mapi/pmapi.c b/mapi/pmapi.c
index 4d4b3101..036e19ef 100644
--- a/mapi/pmapi.c
+++ b/mapi/pmapi.c
@@ -1952,7 +1952,7 @@ BOOL APIENTRY DllMain(
now = time((time_t *)0);
tm_now = localtime(&now);
- fprintf(ms_global->dfd, "pmapi32.dll for Alpine Version 2.19.999\r\n");
+ fprintf(ms_global->dfd, "pmapi32.dll for Alpine Version 2.19.9991\r\n");
fprintf(ms_global->dfd, " Build date: %s\r\n", datestamp);
fprintf(ms_global->dfd,
" please report all bugs to chappa@gmx.com\r\n");
diff --git a/mapi/pmapi.rc b/mapi/pmapi.rc
index ed2e7b7e..815a7a4e 100644
--- a/mapi/pmapi.rc
+++ b/mapi/pmapi.rc
@@ -98,8 +98,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,19,999,0
- PRODUCTVERSION 2,19,999,0
+ FILEVERSION 2,19,9991,0
+ PRODUCTVERSION 2,19,9991,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x29L
@@ -117,14 +117,14 @@ BEGIN
VALUE "Comments", "alpine info: http://patches.freeiz.com/alpine\0"
VALUE "CompanyName", "Patches for Alpine\0"
VALUE "FileDescription", "Simple MAPI DLL for Alpine for Windows\0"
- VALUE "FileVersion", "2.19.999\0"
+ VALUE "FileVersion", "2.19.9991\0"
VALUE "InternalName", "pmapi32\0"
VALUE "LegalCopyright", "Copyright ? University of Washington 2006-2009, Eduardo Chappa 2013-2014\0"
VALUE "LegalTrademarks", "Apache License, Version 2.0\0"
VALUE "OriginalFilename", "pmapi32.dll\0"
VALUE "PrivateBuild", " \0"
VALUE "ProductName", "Simple MAPI for Alpine for Windows\0"
- VALUE "ProductVersion", "2.19.999\0"
+ VALUE "ProductVersion", "2.19.9991\0"
VALUE "SpecialBuild", " \0"
END
END
diff --git a/pith/pine.hlp b/pith/pine.hlp
index 91762910..90be0132 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 63 2014-05-17 18:18:38
+Alpine Commit 64 2014-05-31 21:36:57
============= h_news =================
<HTML>
<HEAD>
@@ -202,6 +202,9 @@ Additions include:
container with default names PublicContainer, PrivateContainer and
CAContainer, as appropriate for these files, unless the user has
provided some other names.
+ <LI> S/MIME: Forwarding a message will include the signed part as part
+ of the text and not as a multipart message, just as the reply
+ command does.
<LI> Add support to selective expunge through a subcommand of the
select-apply commands. Read more in the <A
HREF="h_index_cmd_expunge">help</A> for the expunge command.
@@ -283,6 +286,10 @@ Bugs that have been addressed include:
<LI> S/MIME: Forwarding a signed message might make the body contain mime
information that is not part of the body, and hence making the body
of the message seem wrong.
+ <LI> S/MIME Alpine would compute incorrectly the signature of a message
+ that contains 8bit if the option "Enable 8bit ESMTP Negotiation" is
+ enabled, the message contains 8bit characters and the smtp server
+ supports 8bit sending.
<LI> Crash when tcp connection to NNTP server was lost after connection
had been established, but lost immediately afterwards.
<LI> Crash with message &quot;lock when already locked&quot;, when painting
diff --git a/pith/reply.c b/pith/reply.c
index 60a7c489..2a8ab158 100644
--- a/pith/reply.c
+++ b/pith/reply.c
@@ -4,8 +4,8 @@ static char rcsid[] = "$Id: reply.c 1074 2008-06-04 00:08:43Z hubert@u.washingto
/*
* ========================================================================
- * Copyright 2006-2008 University of Washington
* Copyright 2013-2014 Eduardo Chappa
+ * Copyright 2006-2008 University of Washington
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,6 +46,9 @@ static char rcsid[] = "$Id: reply.c 1074 2008-06-04 00:08:43Z hubert@u.washingto
#include "../pith/ablookup.h"
#include "../pith/mailcmd.h"
#include "../pith/margin.h"
+#ifdef SMIME
+#include "../pith/smime.h"
+#endif /* SMIME */
/*
@@ -2249,11 +2252,23 @@ forward_body(MAILSTREAM *stream, ENVELOPE *env, struct mail_bodystruct *orig_bod
}
}
else if(orig_body->type == TYPEMULTIPART) {
- if(orig_body->subtype && !strucmp(orig_body->subtype, "signed")
- && orig_body->nested.part){
+ if(orig_body->subtype
+ && ((!strucmp(orig_body->subtype, "signed") && orig_body->nested.part)
+#ifdef SMIME
+ || (!strucmp(orig_body->subtype, "mixed")
+ && orig_body->nested.part
+ && orig_body->nested.part->body.type == TYPEMULTIPART
+ && orig_body->nested.part->body.subtype
+ && (!strucmp(orig_body->nested.part->body.subtype, OUR_PKCS7_ENCLOSURE_SUBTYPE)
+ || !strucmp(orig_body->nested.part->body.subtype, "signed")))
+ || !strucmp(orig_body->subtype, OUR_PKCS7_ENCLOSURE_SUBTYPE))
+#endif /* SMIME */
+ ){
/* only operate on the signed data (not the signature) */
body = forward_body(stream, env, &orig_body->nested.part->body,
- msgno, section, msgtext, flags);
+ msgno,
+ orig_body->nested.part->body.type == TYPEMULTIPART
+ ? section : sect_prefix, msgtext, flags);
}
/*---- Message is multipart ----*/
else if(!(orig_body->subtype && !strucmp(orig_body->subtype,
diff --git a/pith/send.c b/pith/send.c
index 191e186d..b01ff7e5 100644
--- a/pith/send.c
+++ b/pith/send.c
@@ -1762,21 +1762,23 @@ call_mailer(METAENV *header, struct mail_bodystruct *body, char **alt_smtp_serve
#ifdef SMIME
if(ps_global->smime && (ps_global->smime->do_encrypt || ps_global->smime->do_sign)){
int result;
-
+
STORE_S *so = lmc.so;
lmc.so = NULL;
-
+
result = 1;
-
- if(ps_global->smime->do_sign)
- result = sign_outgoing_message(header, &body, 0);
-
+
+ if(ps_global->smime->do_sign){
+ bp = F_ON(F_ENABLE_8BIT, ps_global) ? first_text_8bit(body) : NULL;
+ result = sign_outgoing_message(header, &body, 0, &bp);
+ }
+
/* need to free new body from encrypt if sign fails? */
if(result && ps_global->smime->do_encrypt)
result = encrypt_outgoing_message(header, &body);
-
+
lmc.so = so;
-
+
if(!result)
return 0;
}
@@ -1999,6 +2001,19 @@ call_mailer(METAENV *header, struct mail_bodystruct *body, char **alt_smtp_serve
body_encodings[added_encoding] = body_encodings[ENC8BIT];
save_encoding = bp->encoding;
bp->encoding = added_encoding;
+#ifdef SMIME
+ if(ps_global->smime && ps_global->smime->do_sign
+ && body->nested.part->next
+ && body->nested.part->next->body.contents.text.data
+ && body->nested.part->next->body.mime.text.data){
+ STORE_S *so;
+
+ so = (STORE_S *) body->nested.part->next->body.contents.text.data;
+ so_give(&so);
+ body->nested.part->next->body.contents.text.data = body->nested.part->next->body.mime.text.data;
+ body->nested.part->next->body.mime.text.data = NULL;
+ }
+#endif /* SMIME */
}
}
diff --git a/pith/smime.c b/pith/smime.c
index 5a86f318..44cc1955 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -77,8 +77,10 @@ CertList * certlist_from_personal_certs(PERSONAL_CERT *pc);
#ifdef PASSFILE
void load_key_and_cert(char *pathkeydir, char *pathcertdir, char **keyfile, char **certfile, EVP_PKEY **pkey, X509 **pcert);
#endif /* PASSFILE */
-STACK_OF(X509) *get_chain_for_cert(X509 *cert, int *error);
EVP_PKEY *load_pkey_with_prompt(char *fpath, char *text, char *prompt);
+void smime_remove_trailing_crlf(char **mimetext, unsigned long *mimelen, char **bodytext, unsigned long *bodylen);
+void smime_remove_folding_space(char **mimetext, unsigned long *mimelen, char **bodytext, unsigned long *bodylen);
+int smime_validate_extra_test(char *mimetext, unsigned long mimelen, char *bodytext, unsigned long bodylen, PKCS7 *p7, int nflag);
int (*pith_opt_smime_get_passphrase)(void);
int (*pith_smime_import_certificate)(char *, char *, size_t);
@@ -2421,8 +2423,8 @@ int same_cert(X509 *x, X509 *cert)
char bufcert[256], bufx[256];
int rv = 0;
- get_fingerprint(cert, EVP_md5(), bufcert, sizeof(bufcert));
- get_fingerprint(x, EVP_md5(), bufx, sizeof(bufx));
+ get_fingerprint(cert, EVP_md5(), bufcert, sizeof(bufcert), ":");
+ get_fingerprint(x, EVP_md5(), bufx, sizeof(bufx), ":");
if(strcmp(bufx, bufcert) == 0)
rv = 1;
@@ -2644,6 +2646,85 @@ free_smime_body_sparep(void **sparep)
should be safe to do so.
*/
+typedef struct smime_filter_s {
+ void (*filter)();
+} SMIME_FILTER_S;
+
+SMIME_FILTER_S sig_filter[] = {
+ {smime_remove_trailing_crlf},
+ {smime_remove_folding_space}
+};
+
+#define TOTAL_FILTERS (sizeof(sig_filter)/sizeof(sig_filter[0]))
+#define TOTAL_SIGFLTR (1 << TOTAL_FILTERS) /* not good, keep filters to a low number */
+
+void
+smime_remove_trailing_crlf(char **mimetext, unsigned long *mimelen,
+ char **bodytext, unsigned long *bodylen)
+{
+ if(*bodylen > 2 && !strncmp(*bodytext+*bodylen-2, "\r\n", 2))
+ *bodylen -= 2;
+}
+
+void
+smime_remove_folding_space(char **mimetext, unsigned long *mimelen,
+ char **bodytext, unsigned long *bodylen)
+{
+ char *s = NULL, *t;
+ unsigned long mlen = *mimelen;
+
+ if(*mimetext){
+ for (s = t = *mimetext; t - *mimetext < *mimelen; ){
+ if(*t == '\r' && *(t+1) == '\n' && (*(t+2) == '\t' || *(t+2) == ' ')){
+ *s++ = ' ';
+ t += 3;
+ mlen -= 2;
+ }
+ else
+ *s++ = *t++;
+ }
+ *mimelen = mlen;
+ }
+}
+
+int
+smime_validate_extra_test(char *mimetext, unsigned long mimelen, char *bodytext, unsigned long bodylen, PKCS7 *p7, int nflag)
+{
+ int result, i, j, flag;
+ char *mtext, *btext;
+ unsigned long mlen, blen;
+ BIO *in;
+
+ mtext = mimelen ? fs_get(mimelen+1) : NULL;
+ btext = fs_get(bodylen+1);
+
+ flag = 1; /* silence all failures */
+ for(i = 1; result == 0 && i < TOTAL_SIGFLTR; i++){
+ if((in = BIO_new(BIO_s_mem())) == NULL)
+ return -1;
+
+ (void) BIO_reset(in);
+
+ if(i+1 == TOTAL_SIGFLTR)
+ flag = nflag;
+
+ if(mimelen)
+ strncpy(mtext, mimetext, mlen = mimelen);
+ strncpy(btext, bodytext, blen = bodylen);
+ for(j = 0; j < TOTAL_FILTERS; j++)
+ if((i >> j) & 1)
+ (sig_filter[j].filter)(&mtext, &mlen, &btext, &blen);
+ if(mtext != NULL)
+ BIO_write(in, mtext, mlen);
+ BIO_write(in, btext, blen);
+ result = do_signature_verify(p7, in, NULL, flag);
+ BIO_free(in);
+ }
+ if(mtext) fs_give((void **)&mtext);
+ if(btext) fs_give((void **)&btext);
+ return result;
+}
+
/*
* Given a multipart body of type multipart/signed, attempt to verify it.
* Returns non-zero if the body was changed.
@@ -2699,36 +2780,20 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
BIO_write(in, mimetext, mimelen);
BIO_write(in, bodytext, bodylen);
- /* Try compatibility with the past and check if this message
- * validates when we remove the last two characters. Silence
- * any failures first.
- */
- flag = (bodylen <= 2 || strncmp(bodytext+bodylen-2, "\r\n", 2))
- ? 0 : 1;
- if(((result = do_signature_verify(p7, in, NULL, flag)) == 0)
- && bodylen > 2
- && (strncmp(bodytext+bodylen-2,"\r\n", 2) == 0)){
- BUF_MEM *biobuf = NULL;
-
- BIO_get_mem_ptr(in, &biobuf);
- if(biobuf)
- BUF_MEM_grow(biobuf, mimelen + bodylen - 2);
-
- /* test one more time in case this is a remote connection and the
- * server massages the message to the point that it sends bogus
- * information. In this case, we fetch the message and we process
- * it by hand.
- */
- flag = (mimelen == 0 || !IS_REMOTE(ps_global->mail_stream->mailbox))
+ if((result = do_signature_verify(p7, in, NULL, 1)) == 0){
+ flag = (mimelen == 0 || !IS_REMOTE(ps_global->mail_stream->mailbox))
? 0 : 1;
- if((result = do_signature_verify(p7, in, NULL, flag)) == 0
+ result = smime_validate_extra_test(mimetext, mimelen, bodytext, bodylen, p7, flag);
+ if(result < 0)
+ return modified_the_body;
+ if(result == 0
&& mimelen > 0 /* do not do this for encrypted messages */
&& IS_REMOTE(ps_global->mail_stream->mailbox)){
char *fetch;
unsigned long hlen, tlen;
STORE_S *msg_so;
- BIO_free(in);
+ BIO_free(in);
if((in = BIO_new(BIO_s_mem())) != NULL
&& (fetch = mail_fetch_header(ps_global->mail_stream, msgno, NULL,
NULL, &hlen, FT_PEEK)) != NULL
@@ -2773,15 +2838,10 @@ do_detached_signature_verify(BODY *b, long msgno, char *section)
BIO_write(in, bodytext, bodylen);
so_give(&msg_so);
- if(((result = do_signature_verify(p7, in, NULL, 1)) == 0)
- && bodylen > 2
- && (strncmp(bodytext+bodylen-2,"\r\n", 2) == 0)){
- BUF_MEM *biobuf = NULL;
-
- BIO_get_mem_ptr(in, &biobuf);
- if(biobuf)
- BUF_MEM_grow(biobuf, mimelen + bodylen - 2);
- result = do_signature_verify(p7, in, NULL, 0);
+ if((result = do_signature_verify(p7, in, NULL, 1)) == 0){
+ result = smime_validate_extra_test(mimetext, mimelen, bodytext, bodylen, p7, 0);
+ if(result < 0)
+ return modified_the_body;
}
}
}
@@ -3248,16 +3308,16 @@ gf_puts_uline(char *txt, gf_io_t pc)
pc(TAG_EMBED); pc(TAG_BOLDOFF);
}
-
+/* get_chain_for_cert: error and level are mandatory arguments */
STACK_OF(X509) *
-get_chain_for_cert(X509 *cert, int *error)
+get_chain_for_cert(X509 *cert, int *error, int *level)
{
STACK_OF(X509) *chain = NULL;
X509_STORE_CTX *ctx;
X509 *x, *xtmp;
int rc; /* return code */
- int level = -1;
-
+
+ *level = -1;
*error = 0;
ERR_clear_error();
if((ctx = X509_STORE_CTX_new()) != NULL){
@@ -3266,7 +3326,7 @@ get_chain_for_cert(X509 *cert, int *error)
*error = X509_STORE_CTX_get_error(ctx);
else if((chain = sk_X509_new_null()) != NULL){
for(x = cert; ; x = xtmp){
- if(++level > 0)
+ if(++*level > 0)
sk_X509_push(chain, X509_dup(x));
rc = X509_STORE_CTX_get1_issuer(&xtmp, ctx, x);
if(rc < 0)
@@ -3277,10 +3337,6 @@ get_chain_for_cert(X509 *cert, int *error)
break;
}
}
- if((*error && chain != NULL) || level == 0){
- sk_X509_pop_free(chain, X509_free);
- chain = NULL;
- }
X509_STORE_CTX_free(ctx);
}
return chain;
@@ -3292,22 +3348,37 @@ get_chain_for_cert(X509 *cert, int *error)
*
* This takes the header for the outgoing message as well as a pointer
* to the current body (which may be reallocated).
+ * The last argument (BODY **bp) is an argument that tells Alpine
+ * if the body has 8 bit. if *bp is not null we compute two signatures
+ * one for the quoted-printable encoded message, and another for the
+ * 8bit encoded message. We return the signature for the 8bit encoded
+ * part in p2->body.mime.text.data.
+ * The reason why we compute two signatures is so that we can decide
+ * which one to use later, and we only do it in the case that *bp is
+ * not null. If we did not do this, then we might not be able to sign
+ * a message until we log in to the smtp server, so instead of doing
+ * that, we get ready for any possible situation we might find.
*/
int
-sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach)
+sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach, BODY **bp)
{
STORE_S *outs = NULL;
+ STORE_S *outs_2 = NULL;
BODY *body = *bodyP;
BODY *newBody = NULL;
PART *p1 = NULL;
PART *p2 = NULL;
PERSONAL_CERT *pcert;
BIO *in = NULL;
+ BIO *in_2 = NULL;
BIO *out = NULL;
+ BIO *out_2 = NULL;
PKCS7 *p7 = NULL;
+ PKCS7 *p7_2 = NULL;
STACK_OF(X509) *chain;
int result = 0, error;
int flags = dont_detach ? 0 : PKCS7_DETACHED;
+ int level;
dprint((9, "sign_outgoing_message()"));
@@ -3332,13 +3403,43 @@ sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach)
if(!pcert->key)
goto end;
-
- in = body_to_bio(body);
- chain = get_chain_for_cert(pcert->cert, &error);
+ if(((chain = get_chain_for_cert(pcert->cert, &error, &level)) != NULL && error)
+ || level == 0){
+ sk_X509_pop_free(chain, X509_free);
+ chain = NULL;
+ }
+
+ if(error)
+ q_status_message(SM_ORDER, 1, 1,
+ _("Not all certificates needed to verify signature included in signed message"));
+
+ in = body_to_bio(body);
p7 = PKCS7_sign(pcert->cert, pcert->key, chain, in, flags);
+ if(bp && *bp){
+ int i, save_encoding;
+
+ for(i = 0; (i <= ENCMAX) && body_encodings[i]; i++);
+
+ if(i > ENCMAX){ /* no empty encoding slots! */
+ *bp = NULL;
+ }
+ else {
+ save_encoding = (*bp)->encoding;
+ body_encodings[(*bp)->encoding = i] = body_encodings[ENC8BIT];
+
+ in_2 = body_to_bio(body);
+
+ body_encodings[i] = NULL;
+ (*bp)->encoding = save_encoding;
+ }
+ }
+
+ if(bp && *bp)
+ p7_2 = PKCS7_sign(pcert->cert, pcert->key, chain, in_2, flags);
+
if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE,ps_global))
forget_private_keys();
@@ -3350,9 +3451,6 @@ sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach)
goto end;
}
- if(error)
- q_status_message(SM_ORDER, 1, 1, _("Not all certificates needed to verify signature included in signed message"));
-
outs = so_get(BioType, NULL, EDIT_ACCESS);
out = bio_from_store(outs);
@@ -3360,6 +3458,16 @@ sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach)
(void) BIO_flush(out);
so_seek(outs, 0, SEEK_SET);
+
+ if(bp && *bp && p7_2){
+ outs_2 = so_get(BioType, NULL, EDIT_ACCESS);
+ out_2 = bio_from_store(outs_2);
+
+ i2d_PKCS7_bio(out_2, p7_2);
+ (void) BIO_flush(out_2);
+
+ so_seek(outs_2, 0, SEEK_SET);
+ }
if((flags&PKCS7_DETACHED)==0){
@@ -3408,6 +3516,7 @@ sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach)
p1->next = p2;
setup_pkcs7_body_for_signature(&p2->body, "S/MIME Cryptographic Signature", "pkcs7-signature", "smime.p7s", NULL);
+ p2->body.mime.text.data = (unsigned char *) outs_2;
p2->body.contents.text.data = (unsigned char *) outs;
newBody->nested.part = p1;
@@ -3422,6 +3531,11 @@ end:
PKCS7_free(p7);
BIO_free(in);
+ if(bp && *bp){
+ if(p7_2) PKCS7_free(p7_2);
+ BIO_free(in_2);
+ }
+
dprint((9, "sign_outgoing_message returns %d", result));
return result;
}
diff --git a/pith/smime.h b/pith/smime.h
index a2d2c805..f917daf4 100644
--- a/pith/smime.h
+++ b/pith/smime.h
@@ -50,7 +50,7 @@ int is_pkcs7_body(BODY *b);
int fiddle_smime_message(BODY *b, long msgno);
int encrypt_outgoing_message(METAENV *header, BODY **bodyP);
void free_smime_body_sparep(void **sparep);
-int sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach);
+int sign_outgoing_message(METAENV *header, BODY **bodyP, int dont_detach, BODY **bp);
void gf_puts_uline(char *txt, gf_io_t pc);
PERSONAL_CERT *find_certificate_matching_recip_info(PKCS7_RECIP_INFO *ri);
PERSONAL_CERT *get_personal_certs(char *path);
@@ -84,6 +84,7 @@ int add_file_to_container(WhichCerts ctype, char *fpath, char *altname);
void *create_smime_sparep(SpareType stype, void *s);
SpareType get_smime_sparep_type(void *s);
void *get_smime_sparep_data(void *s);
+STACK_OF(X509) *get_chain_for_cert(X509 *cert, int *error, int *level);
#endif /* PITH_SMIME_INCLUDED */
#endif /* SMIME */
diff --git a/pith/smkeys.c b/pith/smkeys.c
index 23c9d21a..18ed6f1b 100644
--- a/pith/smkeys.c
+++ b/pith/smkeys.c
@@ -46,8 +46,27 @@ static char rcsid[] = "$Id: smkeys.c 1266 2009-07-14 18:39:12Z hubert@u.washingt
static char *emailstrclean(char *string);
static int mem_add_extra_cacerts(char *contents, X509_LOOKUP *lookup);
+/* given a certificate and an email address, add the
+ * extension and md5 key to the name. return an allocated
+ * name, freed by caller
+ */
+char *
+smime_name(char *email, X509 *x, WhichCerts ctype)
+{
+ char bufx[256];
+ char *rv;
+
+ snprintf(bufx, sizeof(bufx), "%08lx",X509_subject_name_hash(x));
+ rv = cpystr(bufx);
+// get_fingerprint(x, EVP_md5(), bufx, sizeof(bufx), NULL);
+// rv = fs_get(strlen(email) + 4 + 2 + strlen(bufx) + 1);
+// sprintf(rv, "%s%s.%s", email, EXTCERT(ctype), bufx);
+
+ return rv;
+}
+
void
-get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t maxLen)
+get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t maxLen, char *s)
{
unsigned char md[128];
char *b;
@@ -63,8 +82,8 @@ get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t maxLen)
if(b-buf+3>=maxLen)
break;
- if(i != 0)
- *b++ = ':';
+ if(i != 0 && s && *s)
+ *b++ = *s;
snprintf(b, maxLen - (b-buf), "%02x", md[i]);
b+=2;
diff --git a/pith/smkeys.h b/pith/smkeys.h
index 0781a018..0fe8faad 100644
--- a/pith/smkeys.h
+++ b/pith/smkeys.h
@@ -57,9 +57,10 @@ void add_to_end_of_certlist(CertList **cl, char *name, X509 *cert);
void free_certlist(CertList **cl);
PERSONAL_CERT *mem_to_personal_certs(char *contents);
void free_personal_certs(PERSONAL_CERT **pc);
-void get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t maxLen);
+void get_fingerprint(X509 *cert, const EVP_MD *type, char *buf, size_t maxLen, char *s);
int certlist_to_file(char *filename, CertList *certlist);
int load_cert_for_key(char *pathdir, EVP_PKEY *pkey, char **certfile, X509 **pcert);
+char *smime_name(char *email, X509 *x, WhichCerts ctype);
#endif /* PITH_SMKEYS_INCLUDED */