Update gnutls code (require at least 2.2.0).

This commit is contained in:
Gabriel VLASIU 2013-04-08 15:55:25 +03:00 committed by Carlos R. Mafra
parent b00adb9607
commit 4e9e018b22
9 changed files with 114 additions and 58 deletions

View file

@ -77,7 +77,7 @@ AC_ARG_ENABLE(crypto, AC_HELP_STRING([ --disable-crypto ], [ disable gnutls/gcry
GNUTLS_MAN_STATUS="This copy of WMBiff was not compiled with GNUTLS." GNUTLS_MAN_STATUS="This copy of WMBiff was not compiled with GNUTLS."
if test "$gnutls" = "ok"; then if test "$gnutls" = "ok"; then
PKG_CHECK_MODULES([LIBGNUTLS], [gnutls > 1.0.4], [LIBS="$LIBS $LIBGNUTLS_LIBS" PKG_CHECK_MODULES([LIBGNUTLS], [gnutls > 2.2.0], [LIBS="$LIBS $LIBGNUTLS_LIBS"
CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS" CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS"
CPPFLAGS="$CPPFLAGS $LIBGNUTLS_CFLAGS" CPPFLAGS="$CPPFLAGS $LIBGNUTLS_CFLAGS"
GNUTLS_COMMON_O="gnutls-common.o" GNUTLS_COMMON_O="gnutls-common.o"

View file

@ -507,16 +507,7 @@ int imap4Create( /*@notnull@ */ Pop3 pc, const char *const str)
/* If 'str' line is badly formatted, wmbiff won't display the mailbox. */ /* If 'str' line is badly formatted, wmbiff won't display the mailbox. */
if (strncmp("sslimap:", str, 8) == 0 || strncmp("imaps:", str, 6) == 0) { if (strncmp("sslimap:", str, 8) == 0 || strncmp("imaps:", str, 6) == 0) {
#ifdef HAVE_GNUTLS_GNUTLS_H #ifdef HAVE_GNUTLS_GNUTLS_H
static int haveBeenWarned;
PCU.dossl = 1; PCU.dossl = 1;
if (!haveBeenWarned) {
printf("wmbiff uses gnutls for TLS/SSL encryption support:\n"
" If you distribute software that uses gnutls, don't forget\n"
" to warn the users of your software that gnutls is at a\n"
" testing phase and may be totally insecure.\n"
"\nConsider yourself warned.\n");
haveBeenWarned = 1;
}
#else #else
printf("This copy of wmbiff was not compiled with gnutls;\n" printf("This copy of wmbiff was not compiled with gnutls;\n"
"imaps is unavailable. Exiting to protect your\n" "imaps is unavailable. Exiting to protect your\n"

View file

@ -233,16 +233,7 @@ int pop3Create(Pop3 pc, const char *str)
if (strncmp("pop3s:", str, 6) == 0) { if (strncmp("pop3s:", str, 6) == 0) {
#ifdef HAVE_GNUTLS_GNUTLS_H #ifdef HAVE_GNUTLS_GNUTLS_H
static int haveBeenWarned;
PCU.dossl = 1; PCU.dossl = 1;
if (!haveBeenWarned) {
printf("wmbiff uses gnutls for TLS/SSL encryption support:\n"
" If you distribute software that uses gnutls, don't forget\n"
" to warn the users of your software that gnutls is at a\n"
" testing phase and may be totally insecure.\n"
"\nConsider yourself warned.\n");
haveBeenWarned = 1;
}
#else #else
printf("This copy of wmbiff was not compiled with gnutls;\n" printf("This copy of wmbiff was not compiled with gnutls;\n"
"imaps is unavailable. Exiting to protect your\n" "imaps is unavailable. Exiting to protect your\n"

View file

@ -336,17 +336,20 @@ void print_openpgp_info(gnutls_session session, const char* hostname)
void print_cert_vrfy(gnutls_session session) void print_cert_vrfy(gnutls_session session)
{ {
int status; unsigned int status;
status = gnutls_certificate_verify_peers(session); int ret;
ret = gnutls_certificate_verify_peers2(session, &status);
printf("\n"); printf("\n");
if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) { if(ret < 0)
printf("- Peer did not send any certificate.\n"); {
return; if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND)
} printf("- Peer did not send any certificate.\n");
if (status < 0) { else
printf("- Could not verify certificate (err: %s)\n", printf("- Could not verify certificate (err: %s (%d))\n",
gnutls_strerror(status)); gnutls_strerror(ret), ret);
return; return;
} }

View file

@ -9,6 +9,8 @@
int debug_default = 2; int debug_default = 2;
int SkipCertificateCheck = 0; int SkipCertificateCheck = 0;
const char *certificate_filename = NULL; const char *certificate_filename = NULL;
const char *tls = "NORMAL";
int exists(const char *filename __attribute__ ((unused))) int exists(const char *filename __attribute__ ((unused)))
{ {
return (0); return (0);

View file

@ -398,6 +398,7 @@ int print_info(UNUSED(void *state))
return (0); return (0);
} }
const char *certificate_filename = NULL; const char *certificate_filename = NULL;
const char *tls = "NORMAL";
int SkipCertificateCheck = 0; int SkipCertificateCheck = 0;
int exists(UNUSED(const char *filename)) int exists(UNUSED(const char *filename))
{ {

View file

@ -38,6 +38,9 @@ extern const char *certificate_filename;
/* if set, don't fail when dealing with a bad certificate. /* if set, don't fail when dealing with a bad certificate.
(continue to whine, though, as bad certs should be fixed) */ (continue to whine, though, as bad certs should be fixed) */
extern int SkipCertificateCheck; extern int SkipCertificateCheck;
/* gnutls: specify the priorities to use on the ciphers, key exchange methods,
macs and compression methods. */
extern const char *tls;
/* WARNING: implcitly uses scs to gain access to the mailbox /* WARNING: implcitly uses scs to gain access to the mailbox
that holds the per-mailbox debug flag. */ that holds the per-mailbox debug flag. */
@ -342,6 +345,16 @@ bad_certificate(const struct connection_state *scs, const char *msg)
} }
} }
static void
warn_certificate(const struct connection_state *scs, const char *msg)
{
if (!SkipCertificateCheck) {
TDM(DEBUG_ERROR, "%s", msg);
TDM(DEBUG_ERROR, "to ignore this warning, run wmbiff "
"with the -skip-certificate-check option\n");
}
}
/* a start of a hack at verifying certificates. does not /* a start of a hack at verifying certificates. does not
provide any security at all. I'm waiting for either provide any security at all. I'm waiting for either
gnutls to make this as easy as it should be, or someone gnutls to make this as easy as it should be, or someone
@ -412,7 +425,8 @@ static void
tls_check_certificate(struct connection_state *scs, tls_check_certificate(struct connection_state *scs,
const char *remote_hostname) const char *remote_hostname)
{ {
int certstat; int ret;
unsigned int certstat;
const gnutls_datum *cert_list; const gnutls_datum *cert_list;
unsigned int cert_list_size = 0; unsigned int cert_list_size = 0;
gnutls_x509_crt cert; gnutls_x509_crt cert;
@ -421,23 +435,35 @@ tls_check_certificate(struct connection_state *scs,
bad_certificate(scs, "Unable to get certificate from peer.\n"); bad_certificate(scs, "Unable to get certificate from peer.\n");
return; /* bad_cert will exit if -skip-certificate-check was not given */ return; /* bad_cert will exit if -skip-certificate-check was not given */
} }
certstat = gnutls_certificate_verify_peers(scs->tls_state); ret = gnutls_certificate_verify_peers2(scs->tls_state, &certstat);
if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND) {
bad_certificate(scs, "server presented no certificate.\n"); if (ret < 0) {
char errbuf[1024];
snprintf(errbuf, 1024, "could not verify certificate: %s (%d).\n",
gnutls_strerror(ret), ret);
bad_certificate(scs, (ret == GNUTLS_E_NO_CERTIFICATE_FOUND ?
"server presented no certificate.\n" :
errbuf));
return;
#ifdef GNUTLS_CERT_CORRUPTED #ifdef GNUTLS_CERT_CORRUPTED
} else if (certstat & GNUTLS_CERT_CORRUPTED) { } else if (certstat & GNUTLS_CERT_CORRUPTED) {
bad_certificate(scs, "server's certificate is corrupt.\n"); bad_certificate(scs, "server's certificate is corrupt.\n");
#endif #endif
} else if (certstat & GNUTLS_CERT_REVOKED) { } else if (certstat & GNUTLS_CERT_REVOKED) {
bad_certificate(scs, "server's certificate has been revoked.\n"); bad_certificate(scs, "server's certificate has been revoked.\n");
} else if (certstat & GNUTLS_CERT_EXPIRED) {
bad_certificate(scs, "server's certificate is expired.\n");
} else if (certstat & GNUTLS_CERT_INSECURE_ALGORITHM) {
warn_certificate(scs, "server's certificate use an insecure algorithm.\n");
} else if (certstat & GNUTLS_CERT_INVALID) { } else if (certstat & GNUTLS_CERT_INVALID) {
if (gnutls_certificate_type_get(scs->tls_state) == GNUTLS_CRT_X509) { if (gnutls_certificate_type_get(scs->tls_state) == GNUTLS_CRT_X509) {
/* bad_certificate(scs, "server's certificate is not trusted.\n" /* bad_certificate(scs, "server's certificate is not trusted.\n"
"there may be a problem with the certificate stored in your certfile\n"); */ "there may be a problem with the certificate stored in your certfile\n"); */
} else { } else {
bad_certificate(scs, bad_certificate(scs,
"server's certificate is invalid or not X.509.\n" "server's certificate is invalid or not X.509.\n"
"there may be a problem with the certificate stored in your certfile\n"); "there may be a problem with the certificate stored in your certfile\n");
} }
#if defined(GNUTLS_CERT_SIGNER_NOT_FOUND) #if defined(GNUTLS_CERT_SIGNER_NOT_FOUND)
} else if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) { } else if (certstat & GNUTLS_CERT_SIGNER_NOT_FOUND) {
@ -456,7 +482,7 @@ tls_check_certificate(struct connection_state *scs,
if (gnutls_x509_crt_init(&cert) < 0) { if (gnutls_x509_crt_init(&cert) < 0) {
bad_certificate(scs, bad_certificate(scs,
"Unable to initialize certificate data structure"); "Unable to initialize certificate data structure");
} }
@ -504,7 +530,7 @@ tls_check_certificate(struct connection_state *scs,
if (certificate_filename != NULL && if (certificate_filename != NULL &&
tls_compare_certificates(&cert_list[0]) == 0) { tls_compare_certificates(&cert_list[0]) == 0) {
bad_certificate(scs, bad_certificate(scs,
"server's certificate was not found in the certificate file.\n"); "server's certificate was not found in the certificate file.\n");
} }
gnutls_x509_crt_deinit(cert); gnutls_x509_crt_deinit(cert);
@ -532,25 +558,16 @@ struct connection_state *initialize_gnutls(int sd, char *name, Pop3 pc,
assert(gnutls_init(&scs->tls_state, GNUTLS_CLIENT) == 0); assert(gnutls_init(&scs->tls_state, GNUTLS_CLIENT) == 0);
{ {
const int protocols[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; const char *err_pos;
const int ciphers[] = if (GNUTLS_E_SUCCESS != gnutls_priority_set_direct(scs->tls_state, tls, &err_pos)) {
{ GNUTLS_CIPHER_RIJNDAEL_128_CBC, GNUTLS_CIPHER_3DES_CBC, DMA(DEBUG_ERROR,
GNUTLS_CIPHER_RIJNDAEL_256_CBC, "Unable to set the priorities to use on the ciphers, "
GNUTLS_CIPHER_ARCFOUR, 0 "key exchange methods, macs and/or compression methods.\n"
}; "See 'tls' parameter in config file: '%s'.\n",
const int compress[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; err_pos);
const int key_exch[] = { GNUTLS_KX_RSA, GNUTLS_KX_DHE_DSS, exit(1);
GNUTLS_KX_DHE_RSA, 0 }
};
/* mutt with gnutls doesn't use kx_srp or kx_anon_dh */
const int mac[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
assert(gnutls_protocol_set_priority(scs->tls_state, protocols) ==
0);
assert(gnutls_cipher_set_priority(scs->tls_state, ciphers) == 0);
assert(gnutls_compression_set_priority(scs->tls_state, compress) ==
0);
assert(gnutls_kx_set_priority(scs->tls_state, key_exch) == 0);
assert(gnutls_mac_set_priority(scs->tls_state, mac) == 0);
/* no client private key */ /* no client private key */
if (gnutls_certificate_allocate_credentials(&scs->xcred) < 0) { if (gnutls_certificate_allocate_credentials(&scs->xcred) < 0) {
DMA(DEBUG_ERROR, "gnutls memory error\n"); DMA(DEBUG_ERROR, "gnutls memory error\n");
@ -566,9 +583,9 @@ struct connection_state *initialize_gnutls(int sd, char *name, Pop3 pc,
exit(1); exit(1);
} }
zok = gnutls_certificate_set_x509_trust_file(scs->xcred, zok = gnutls_certificate_set_x509_trust_file(scs->xcred,
(char *) (char *)
certificate_filename, certificate_filename,
GNUTLS_X509_FMT_PEM); GNUTLS_X509_FMT_PEM);
if (zok < 0) { if (zok < 0) {
DMA(DEBUG_ERROR, DMA(DEBUG_ERROR,
"GNUTLS did not like your certificate file %s (%d).\n", "GNUTLS did not like your certificate file %s (%d).\n",

View file

@ -69,6 +69,10 @@ static const char *globalnotify = NULL;
static const char *skin_search_path = DEFAULT_SKIN_PATH; static const char *skin_search_path = DEFAULT_SKIN_PATH;
/* for gnutls */ /* for gnutls */
const char *certificate_filename = NULL; const char *certificate_filename = NULL;
/* gnutls: specify the priorities to use on the ciphers, key exchange methods,
macs and compression methods. */
const char *tls = NULL;
/* it could be argued that a better default exists. */ /* it could be argued that a better default exists. */
#define DEFAULT_FONT "-*-fixed-*-r-*-*-10-*-*-*-*-*-*-*" #define DEFAULT_FONT "-*-fixed-*-r-*-*-10-*-*-*-*-*-*-*"
@ -260,6 +264,9 @@ static int Read_Config_File(char *filename, int *loopinterval)
} else if (!strcmp(setting, "globalnotify")) { } else if (!strcmp(setting, "globalnotify")) {
globalnotify = strdup_ordie(value); globalnotify = strdup_ordie(value);
continue; continue;
} else if (!strcmp(setting, "tls")) {
tls = strdup_ordie(value);
continue;
} else if (mbox_index == -1) { } else if (mbox_index == -1) {
DMA(DEBUG_INFO, "Unknown global setting '%s'\n", setting); DMA(DEBUG_INFO, "Unknown global setting '%s'\n", setting);
continue; /* Didn't read any setting.[0-5] value */ continue; /* Didn't read any setting.[0-5] value */
@ -375,6 +382,11 @@ static int Read_Config_File(char *filename, int *loopinterval)
} }
} }
(void) fclose(fp); (void) fclose(fp);
if (!tls)
// use GnuTLS's default ciphers.
tls = "NORMAL";
for (i = 0; i < num_mailboxes; i++) for (i = 0; i < num_mailboxes; i++)
if (mbox[i].label[0] != '\0') if (mbox[i].label[0] != '\0')
parse_mbox_path(i); parse_mbox_path(i);

View file

@ -43,6 +43,45 @@ example, if mutt is your mailreader, you may add:
certfile=/home/<me>/.muttsslcerts certfile=/home/<me>/.muttsslcerts
.RE .RE
.TP .TP
\fBtls\fP
Specify cipher suite preferences on a TLS session. Can be a
predefined value from gnults or a custom value. Default value
is: \fINORMAL\fP.
gnutls predefined values:
.SP
.RS 8
\fIPERFORMANCE\fP (gnutls >= 2.2.0)
.RE
.RS 8
\fINORMAL\fP (gnutls >= 2.2.0)
.RE
.RS 8
\fISECURE128\fP (gnutls >= 2.2.0)
.RE
.RS 8
\fISECURE192\fP (gnutls >= 3.0.0)
.RE
.RS 8
\fISECURE256\fP (gnutls >= 2.2.0)
.RE
.RS 8
\fISUITEB128\fP (gnutls >= 3.0.0)
.RE
.RS 8
\fISUITEB192\fP (gnutls >= 3.0.0)
.RE
.RS 8
\fIEXPORT\fP (gnutls >= 2.2.0)
.RE
.RS 8
\fINONE\fP (gnutls >= 2.2.0)
.RE
.RS
.TP
See \fBhttp://gnutls.org/manual/gnutls.html#Priority-Strings\fR for more details.
.RE
.TP
\fBinterval\fP \fBinterval\fP
Global interval between mailbox checking. Value is the number of seconds, 5 Global interval between mailbox checking. Value is the number of seconds, 5
is the default. is the default.