From 4e9e018b2236e00aa591f1d5d99ec59f74475480 Mon Sep 17 00:00:00 2001 From: Gabriel VLASIU Date: Mon, 8 Apr 2013 15:55:25 +0300 Subject: [PATCH] Update gnutls code (require at least 2.2.0). --- wmbiff/configure.ac | 2 +- wmbiff/wmbiff/Imap4Client.c | 9 ----- wmbiff/wmbiff/Pop3Client.c | 9 ----- wmbiff/wmbiff/gnutls-common.c | 21 +++++++----- wmbiff/wmbiff/test_tlscomm.c | 2 ++ wmbiff/wmbiff/test_wmbiff.c | 1 + wmbiff/wmbiff/tlsComm.c | 77 ++++++++++++++++++++++++++----------------- wmbiff/wmbiff/wmbiff.c | 12 +++++++ wmbiff/wmbiff/wmbiffrc.5.in | 39 ++++++++++++++++++++++ 9 files changed, 114 insertions(+), 58 deletions(-) diff --git a/wmbiff/configure.ac b/wmbiff/configure.ac index b8960ce..941e704 100644 --- a/wmbiff/configure.ac +++ b/wmbiff/configure.ac @@ -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." 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" CPPFLAGS="$CPPFLAGS $LIBGNUTLS_CFLAGS" GNUTLS_COMMON_O="gnutls-common.o" diff --git a/wmbiff/wmbiff/Imap4Client.c b/wmbiff/wmbiff/Imap4Client.c index be5d972..c4115e7 100644 --- a/wmbiff/wmbiff/Imap4Client.c +++ b/wmbiff/wmbiff/Imap4Client.c @@ -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 (strncmp("sslimap:", str, 8) == 0 || strncmp("imaps:", str, 6) == 0) { #ifdef HAVE_GNUTLS_GNUTLS_H - static int haveBeenWarned; 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 printf("This copy of wmbiff was not compiled with gnutls;\n" "imaps is unavailable. Exiting to protect your\n" diff --git a/wmbiff/wmbiff/Pop3Client.c b/wmbiff/wmbiff/Pop3Client.c index 0f642cb..6792c42 100644 --- a/wmbiff/wmbiff/Pop3Client.c +++ b/wmbiff/wmbiff/Pop3Client.c @@ -233,16 +233,7 @@ int pop3Create(Pop3 pc, const char *str) if (strncmp("pop3s:", str, 6) == 0) { #ifdef HAVE_GNUTLS_GNUTLS_H - static int haveBeenWarned; 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 printf("This copy of wmbiff was not compiled with gnutls;\n" "imaps is unavailable. Exiting to protect your\n" diff --git a/wmbiff/wmbiff/gnutls-common.c b/wmbiff/wmbiff/gnutls-common.c index db6bd17..5f2bf76 100644 --- a/wmbiff/wmbiff/gnutls-common.c +++ b/wmbiff/wmbiff/gnutls-common.c @@ -336,17 +336,20 @@ void print_openpgp_info(gnutls_session session, const char* hostname) void print_cert_vrfy(gnutls_session session) { - int status; - status = gnutls_certificate_verify_peers(session); + unsigned int status; + int ret; + + ret = gnutls_certificate_verify_peers2(session, &status); + printf("\n"); - if (status == GNUTLS_E_NO_CERTIFICATE_FOUND) { - printf("- Peer did not send any certificate.\n"); - return; - } - if (status < 0) { - printf("- Could not verify certificate (err: %s)\n", - gnutls_strerror(status)); + if(ret < 0) + { + if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) + printf("- Peer did not send any certificate.\n"); + else + printf("- Could not verify certificate (err: %s (%d))\n", + gnutls_strerror(ret), ret); return; } diff --git a/wmbiff/wmbiff/test_tlscomm.c b/wmbiff/wmbiff/test_tlscomm.c index 2c15652..5b89530 100644 --- a/wmbiff/wmbiff/test_tlscomm.c +++ b/wmbiff/wmbiff/test_tlscomm.c @@ -9,6 +9,8 @@ int debug_default = 2; int SkipCertificateCheck = 0; const char *certificate_filename = NULL; +const char *tls = "NORMAL"; + int exists(const char *filename __attribute__ ((unused))) { return (0); diff --git a/wmbiff/wmbiff/test_wmbiff.c b/wmbiff/wmbiff/test_wmbiff.c index 950cbb6..5add324 100644 --- a/wmbiff/wmbiff/test_wmbiff.c +++ b/wmbiff/wmbiff/test_wmbiff.c @@ -398,6 +398,7 @@ int print_info(UNUSED(void *state)) return (0); } const char *certificate_filename = NULL; +const char *tls = "NORMAL"; int SkipCertificateCheck = 0; int exists(UNUSED(const char *filename)) { diff --git a/wmbiff/wmbiff/tlsComm.c b/wmbiff/wmbiff/tlsComm.c index 05e6dd8..90fbc68 100644 --- a/wmbiff/wmbiff/tlsComm.c +++ b/wmbiff/wmbiff/tlsComm.c @@ -38,6 +38,9 @@ extern const char *certificate_filename; /* if set, don't fail when dealing with a bad certificate. (continue to whine, though, as bad certs should be fixed) */ 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 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 provide any security at all. I'm waiting for either 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, const char *remote_hostname) { - int certstat; + int ret; + unsigned int certstat; const gnutls_datum *cert_list; unsigned int cert_list_size = 0; 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"); return; /* bad_cert will exit if -skip-certificate-check was not given */ } - certstat = gnutls_certificate_verify_peers(scs->tls_state); - if (certstat == GNUTLS_E_NO_CERTIFICATE_FOUND) { - bad_certificate(scs, "server presented no certificate.\n"); + ret = gnutls_certificate_verify_peers2(scs->tls_state, &certstat); + + 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 } else if (certstat & GNUTLS_CERT_CORRUPTED) { bad_certificate(scs, "server's certificate is corrupt.\n"); #endif } else if (certstat & GNUTLS_CERT_REVOKED) { 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) { if (gnutls_certificate_type_get(scs->tls_state) == GNUTLS_CRT_X509) { /* bad_certificate(scs, "server's certificate is not trusted.\n" "there may be a problem with the certificate stored in your certfile\n"); */ } else { bad_certificate(scs, - "server's certificate is invalid or not X.509.\n" - "there may be a problem with the certificate stored in your certfile\n"); + "server's certificate is invalid or not X.509.\n" + "there may be a problem with the certificate stored in your certfile\n"); } #if defined(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) { 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 && tls_compare_certificates(&cert_list[0]) == 0) { 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); @@ -532,25 +558,16 @@ struct connection_state *initialize_gnutls(int sd, char *name, Pop3 pc, assert(gnutls_init(&scs->tls_state, GNUTLS_CLIENT) == 0); { - const int protocols[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; - const int ciphers[] = - { GNUTLS_CIPHER_RIJNDAEL_128_CBC, GNUTLS_CIPHER_3DES_CBC, - GNUTLS_CIPHER_RIJNDAEL_256_CBC, - GNUTLS_CIPHER_ARCFOUR, 0 - }; - const int compress[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; - const int key_exch[] = { GNUTLS_KX_RSA, GNUTLS_KX_DHE_DSS, - 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); + const char *err_pos; + if (GNUTLS_E_SUCCESS != gnutls_priority_set_direct(scs->tls_state, tls, &err_pos)) { + DMA(DEBUG_ERROR, + "Unable to set the priorities to use on the ciphers, " + "key exchange methods, macs and/or compression methods.\n" + "See 'tls' parameter in config file: '%s'.\n", + err_pos); + exit(1); + } + /* no client private key */ if (gnutls_certificate_allocate_credentials(&scs->xcred) < 0) { DMA(DEBUG_ERROR, "gnutls memory error\n"); @@ -566,9 +583,9 @@ struct connection_state *initialize_gnutls(int sd, char *name, Pop3 pc, exit(1); } zok = gnutls_certificate_set_x509_trust_file(scs->xcred, - (char *) - certificate_filename, - GNUTLS_X509_FMT_PEM); + (char *) + certificate_filename, + GNUTLS_X509_FMT_PEM); if (zok < 0) { DMA(DEBUG_ERROR, "GNUTLS did not like your certificate file %s (%d).\n", diff --git a/wmbiff/wmbiff/wmbiff.c b/wmbiff/wmbiff/wmbiff.c index 8a4fa07..f0b8136 100644 --- a/wmbiff/wmbiff/wmbiff.c +++ b/wmbiff/wmbiff/wmbiff.c @@ -69,6 +69,10 @@ static const char *globalnotify = NULL; static const char *skin_search_path = DEFAULT_SKIN_PATH; /* for gnutls */ 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. */ #define DEFAULT_FONT "-*-fixed-*-r-*-*-10-*-*-*-*-*-*-*" @@ -260,6 +264,9 @@ static int Read_Config_File(char *filename, int *loopinterval) } else if (!strcmp(setting, "globalnotify")) { globalnotify = strdup_ordie(value); continue; + } else if (!strcmp(setting, "tls")) { + tls = strdup_ordie(value); + continue; } else if (mbox_index == -1) { DMA(DEBUG_INFO, "Unknown global setting '%s'\n", setting); 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); + + if (!tls) + // use GnuTLS's default ciphers. + tls = "NORMAL"; + for (i = 0; i < num_mailboxes; i++) if (mbox[i].label[0] != '\0') parse_mbox_path(i); diff --git a/wmbiff/wmbiff/wmbiffrc.5.in b/wmbiff/wmbiff/wmbiffrc.5.in index 0443bc5..66924e3 100644 --- a/wmbiff/wmbiff/wmbiffrc.5.in +++ b/wmbiff/wmbiff/wmbiffrc.5.in @@ -43,6 +43,45 @@ example, if mutt is your mailreader, you may add: certfile=/home//.muttsslcerts .RE .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 Global interval between mailbox checking. Value is the number of seconds, 5 is the default. -- 2.11.4.GIT