From 15a5232629a37b3df8a476f984343375950fa2ff Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 22 Jun 2015 21:28:22 +0200 Subject: Use DH parameters from OpenSSL and remove support for ephemeral RSA This adds support for DH parameters from 1024 to 8192 bits. --- Makefile | 18 ++--------- README.starttls | 8 ----- TARGETS | 1 - hier.c | 3 -- qmail-control.9 | 3 -- qmail-smtpd.8 | 17 ---------- qmail-smtpd.c | 92 +++++++++++++++++++++++++++++++++++++----------------- update_tmprsadh.sh | 25 --------------- 8 files changed, 66 insertions(+), 101 deletions(-) delete mode 100644 update_tmprsadh.sh diff --git a/Makefile b/Makefile index eac4649..70df80d 100644 --- a/Makefile +++ b/Makefile @@ -812,7 +812,7 @@ dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \ forward preline condredirect bouncesaying except maildirmake \ maildir2mbox maildirwatch qail elq pinq idedit install-big install \ instcheck home home+df proc proc+df binm1 binm1+df binm2 binm2+df \ -binm3 binm3+df update_tmprsadh +binm3 binm3+df load: \ make-load warn-auto.sh systype @@ -1915,8 +1915,7 @@ date822fmt.h date822fmt.c dns.h dns.c trylsock.c tryrsolv.c ip.h ip.c \ ipalloc.h ipalloc.c select.h1 select.h2 trysysel.c ndelay.h ndelay.c \ ndelay_off.c direntry.3 direntry.h1 direntry.h2 trydrent.c prot.h \ prot.c chkshsgr.c warn-shsgr tryshsgr.c ipme.h ipme.c trysalen.c \ -maildir.5 maildir.h maildir.c constmap.h constmap.c \ -update_tmprsadh +maildir.5 maildir.h maildir.c constmap.h constmap.c shar -m `cat FILES` > shar chmod 400 shar @@ -2247,16 +2246,3 @@ conf-qmail conf-users conf-groups Makefile-cert.mk @cat Makefile-cert.mk \ | sed s}QMAIL}"`head -n 1 conf-qmail`"}g \ > $@ - -update_tmprsadh: \ -conf-qmail conf-users conf-groups update_tmprsadh.sh - @cat update_tmprsadh.sh\ - | sed s}UGQMAILD}"`head -n 2 conf-users|tail -n 1`:`head -n 1 conf-groups`"}g \ - | sed s}QMAIL}"`head -n 1 conf-qmail`"}g \ - > $@ - chmod 755 update_tmprsadh - -tmprsadh: \ -update_tmprsadh - echo "Creating new temporary RSA and DH parameters" - ./update_tmprsadh diff --git a/README.starttls b/README.starttls index 0286632..07ee275 100644 --- a/README.starttls +++ b/README.starttls @@ -30,12 +30,6 @@ Optional: - when DEBUG is defined, some extra TLS info will be logged /var/qmail/control/clientcert.pem. By preference this is the same as servercert.pem, where nsCertType should be == server,client or be a generic certificate (no usage specified). - - when a 512 bit RSA key is provided in /var/qmail/control/rsa512.pem, - this key will be used instead of (slow) on-the-fly generation by - qmail-smtpd. Idem for 512 and 1024 DH params in control/dh512.pem - and control/dh1024.pem. `make tmprsadh` does this. - Periodical replacement can be done by crontab: - 01 01 * * * /var/qmail/bin/update_tmprsadh > /dev/null 2>&1 - server authentication: qmail-remote requires authentication from servers for which /var/qmail/control/tlshosts/host.dom.ain.pem exists. @@ -86,8 +80,6 @@ Caveats: - do a `make clean` after patching will fail. This error can be ignored. Packagers should cut the first 12 lines of this patch to make a happy patch - - `make tmprsadh` is recommended (or should I say required), - otherwise DH generation can be unpredictably slow - some need "-I/usr/kerberos/include" to be added in conf-cc Copyright: GPL diff --git a/TARGETS b/TARGETS index 9edaea4..469dca4 100644 --- a/TARGETS +++ b/TARGETS @@ -403,4 +403,3 @@ forgeries.0 man setup check -update_tmprsadh diff --git a/hier.c b/hier.c index 9fb518f..c586065 100644 --- a/hier.c +++ b/hier.c @@ -149,9 +149,6 @@ void hier() c(auto_qmail,"bin","qail",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","elq",auto_uido,auto_gidq,0755); c(auto_qmail,"bin","pinq",auto_uido,auto_gidq,0755); -#ifdef TLS - c(auto_qmail,"bin","update_tmprsadh",auto_uido,auto_gidq,0755); -#endif c(auto_qmail,"man/man5","addresses.5",auto_uido,auto_gidq,0644); c(auto_qmail,"man/cat5","addresses.0",auto_uido,auto_gidq,0644); diff --git a/qmail-control.9 b/qmail-control.9 index 28c4ecf..9c6edd8 100644 --- a/qmail-control.9 +++ b/qmail-control.9 @@ -58,8 +58,6 @@ control default used by .I defaultdomain \fIme \fRqmail-inject .I defaulthost \fIme \fRqmail-inject .I databytes \fR0 \fRqmail-smtpd -.I dh1024.pem \fR(none) \fRqmail-smtpd -.I dh512.pem \fR(none) \fRqmail-smtpd .I doublebouncehost \fIme \fRqmail-send .I doublebounceto \fRpostmaster \fRqmail-send .I envnoathost \fIme \fRqmail-send @@ -74,7 +72,6 @@ control default used by .I qmqpservers \fR(none) \fRqmail-qmqpc .I queuelifetime \fR604800 \fRqmail-send .I rcpthosts \fR(none) \fRqmail-smtpd -.I rsa512.pem \fR(none) \fRqmail-smtpd .I servercert.pem \fR(none) \fRqmail-smtpd .I smtpgreeting \fIme \fRqmail-smtpd .I smtproutes \fR(none) \fRqmail-remote diff --git a/qmail-smtpd.8 b/qmail-smtpd.8 index d1c9820..05d1239 100644 --- a/qmail-smtpd.8 +++ b/qmail-smtpd.8 @@ -170,17 +170,6 @@ If the environment variable is set, it overrides .IR databytes . -.TP 5 -.I dh1024.pem -If these 1024 bit DH parameters are provided, -.B qmail-smtpd -will use them for TLS sessions instead of generating one on-the-fly -(which is very timeconsuming). -.TP 5 -.I dh512.pem -512 bit counterpart for -.B dh1024.pem. - .TP 5 .I localiphost Replacement host name for local IP addresses. @@ -280,12 +269,6 @@ may include wildcards: Envelope recipient addresses without @ signs are always allowed through. -.TP 5 -.I rsa512.pem -If this 512 bit RSA key is provided, -.B qmail-smtpd -will use it for TLS sessions instead of generating one on-the-fly. - .TP 5 .I servercert.pem SSL certificate to be presented to clients in TLS-encrypted sessions. diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 3360cfe..817524d 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c @@ -1141,41 +1141,78 @@ void smtp_tls(char *arg) else tls_init(); } -RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen) +/* + * Grab well-defined DH parameters from OpenSSL, see the get_rfc* + * functions in for all available primes. + */ +static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) { - if (!export) keylen = 512; - if (keylen == 512) { - FILE *in = fopen("control/rsa512.pem", "r"); - if (in) { - RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL); - fclose(in); - if (rsa) return rsa; + DH *dh = DH_new(); + + if (!dh) { + return NULL; } - } - return RSA_generate_key(keylen, RSA_F4, NULL, NULL); + dh->p = prime(NULL); + BN_dec2bn(&dh->g, gen); + if (!dh->p || !dh->g) { + DH_free(dh); + return NULL; + } + return dh; } +/* Storage and initialization for DH parameters. */ +static struct dhparam { + BIGNUM *(*const prime)(BIGNUM *); /* function to generate... */ + DH *dh; /* ...this, used for keys.... */ + const unsigned int min; /* ...of length >= this. */ +} dhparams[] = { + { get_rfc3526_prime_8192, NULL, 6145 }, + { get_rfc3526_prime_6144, NULL, 4097 }, + { get_rfc3526_prime_4096, NULL, 3073 }, + { get_rfc3526_prime_3072, NULL, 2049 }, + { get_rfc3526_prime_2048, NULL, 1025 }, + { get_rfc2409_prime_1024, NULL, 0 } +}; + +/* Hand out the same DH structure though once generated as we leak + * memory otherwise and freeing the structure up after use would be + * hard to track and in fact is not needed at all as it is safe to + * use the same parameters over and over again security wise (in + * contrast to the keys itself) and code safe as the returned structure + * is duplicated by OpenSSL anyway. Hence no modification happens + * to our copy. */ DH *tmp_dh_cb(SSL *ssl, int export, int keylen) { - if (!export) keylen = 1024; - if (keylen == 512) { - FILE *in = fopen("control/dh512.pem", "r"); - if (in) { - DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL); - fclose(in); - if (dh) return dh; + EVP_PKEY *pkey = SSL_get_privatekey(ssl); + int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; + unsigned n; + + /* + * OpenSSL will call us with either keylen == 512 or keylen == 1024 + * (see the definition of SSL_EXPORT_PKEYLENGTH in ssl_locl.h). + * Adjust the DH parameter length according to the size of the + * RSA/DSA private key used for the current connection, and always + * use at least 1024-bit parameters. + * Note: This may cause interoperability issues with implementations + * which limit their DH support to 1024 bit - e.g. Java 7 and earlier. + * In this case, SSLCertificateFile can be used to specify fixed + * 1024-bit DH parameters (with the effect that OpenSSL skips this + * callback). + */ + if (type == EVP_PKEY_RSA || type == EVP_PKEY_DSA) + keylen = EVP_PKEY_bits(pkey); + + for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) { + if (keylen >= dhparams[n].min) { + if (dhparams[n].dh == NULL) + dhparams[n].dh = make_dh_params(dhparams[n].prime, "2"); + return dhparams[n].dh; } } - if (keylen == 1024) { - FILE *in = fopen("control/dh1024.pem", "r"); - if (in) { - DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL); - fclose(in); - if (dh) return dh; - } - } - return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL); -} + + return NULL; /* impossible to reach. */ +} /* don't want to fail handshake if cert isn't verifiable */ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } @@ -1338,7 +1375,6 @@ void tls_init() SSL_set_cipher_list(myssl, ciphers); alloc_free(saciphers.s); - SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb); SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); diff --git a/update_tmprsadh.sh b/update_tmprsadh.sh deleted file mode 100644 index 563fcfb..0000000 --- a/update_tmprsadh.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# Update temporary RSA and DH keys -# Frederik Vermeulen 2004-05-31 GPL - -umask 0077 || exit 0 - -export PATH="$PATH:/usr/local/bin/ssl:/usr/sbin" - -openssl genrsa -out QMAIL/control/rsa512.new 512 && -chmod 600 QMAIL/control/rsa512.new && -chown UGQMAILD QMAIL/control/rsa512.new && -mv -f QMAIL/control/rsa512.new QMAIL/control/rsa512.pem -echo - -openssl dhparam -2 -out QMAIL/control/dh512.new 512 && -chmod 600 QMAIL/control/dh512.new && -chown UGQMAILD QMAIL/control/dh512.new && -mv -f QMAIL/control/dh512.new QMAIL/control/dh512.pem -echo - -openssl dhparam -2 -out QMAIL/control/dh1024.new 1024 && -chmod 600 QMAIL/control/dh1024.new && -chown UGQMAILD QMAIL/control/dh1024.new && -mv -f QMAIL/control/dh1024.new QMAIL/control/dh1024.pem -- cgit v1.2.3