From 999de3146c7bec7ca9e2c55f1f4143b527ba98c4 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 23 Jun 2015 00:51:07 +0200 Subject: add support for ECDH as well as custom ec+dh params in certificate --- qmail-smtpd.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 6 deletions(-) (limited to 'qmail-smtpd.c') diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 817524d..fe33249 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c @@ -1148,15 +1148,14 @@ void smtp_tls(char *arg) static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) { DH *dh = DH_new(); + if (!dh) + return NULL; - if (!dh) { - return NULL; - } dh->p = prime(NULL); BN_dec2bn(&dh->g, gen); if (!dh->p || !dh->g) { - DH_free(dh); - return NULL; + DH_free(dh); + return NULL; } return dh; } @@ -1182,7 +1181,7 @@ static struct dhparam { * 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) +static DH *tmp_dh_cb(SSL *ssl, int export, int keylen) { EVP_PKEY *pkey = SSL_get_privatekey(ssl); int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; @@ -1214,6 +1213,37 @@ DH *tmp_dh_cb(SSL *ssl, int export, int keylen) return NULL; /* impossible to reach. */ } +static DH *ssl_dh_GetParamFromFile(const char *file) +{ + DH *dh = NULL; + BIO *bio; + + if ((bio = BIO_new_file(file, "r")) == NULL) + return NULL; + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + BIO_free(bio); + return dh; +} + +#ifdef HAVE_ECC +static EC_GROUP *ssl_ec_GetParamFromFile(const char *file) +{ + EC_GROUP *group = NULL; + BIO *bio; + + if ((bio = BIO_new_file(file, "r")) == NULL) + return NULL; + group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); + BIO_free(bio); + return group; +} + +static EC_KEY *tmp_ecdh_cb(SSL *ssl, int export, int keylen) +{ + return EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); +} +#endif + /* don't want to fail handshake if cert isn't verifiable */ int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } @@ -1324,6 +1354,12 @@ void tls_init() X509_STORE *store; X509_LOOKUP *lookup; const char *servercert; + DH *dhparams; +#ifdef HAVE_ECC + EC_GROUP *ecparams; + int nid; + EC_KEY *eckey = NULL; +#endif /* if set, use servercert selected through SMTP_SERVERCERT env var */ servercert = env_get("SMTP_SERVERCERT"); @@ -1376,6 +1412,30 @@ void tls_init() alloc_free(saciphers.s); SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); + + /* try to read DH parameters from certificate */ + if ((dhparams = ssl_dh_GetParamFromFile(servercert))) + SSL_set_tmp_dh(myssl, dhparams); + +#ifdef HAVE_ECC + /* similarly, try to read the ECDH curve name from certificate... */ + if ((ecparams = ssl_ec_GetParamFromFile(servercert)) && + (nid = EC_GROUP_get_curve_name(ecparams)) && + (eckey = EC_KEY_new_by_curve_name(nid))) { + SSL_set_tmp_ecdh(myssl, eckey); + } + else { +#if defined(SSL_set_ecdh_auto) + /* ...otherwise, enable auto curve selection (OpenSSL 1.0.2 and later) */ + SSL_set_ecdh_auto(myssl, 1); +#else + /* or set callback, which will configure NIST P-256 */ + SSL_set_tmp_ecdh_callback(myssl, tmp_ecdh_cb); +#endif + } + EC_KEY_free(eckey); +#endif + SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); -- cgit v1.2.3