]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-ssl-iostream: Added support for ECDH/ECDHE cipher suites
authorTimo Sirainen <tss@iki.fi>
Wed, 10 Jul 2013 05:58:36 +0000 (08:58 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 10 Jul 2013 05:58:36 +0000 (08:58 +0300)
Based on the login-common patch by David Hicks.

src/lib-ssl-iostream/iostream-openssl-context.c

index 150c724cbddfff47d120560d42c20c7c0744ad6b..12e44ebdf292891c3117fef7ebc7fe7a46d0ef02 100644 (file)
@@ -406,6 +406,84 @@ ssl_iostream_context_set(struct ssl_iostream_context *ctx,
        return 0;
 }
 
+#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
+static int
+ssl_proxy_ctx_get_pkey_ec_curve_name(const struct ssl_iostream_settings *set,
+                                    int *nid_r, const char **error_r)
+{
+       int nid = 0;
+       EVP_PKEY *pkey;
+       const char *password;
+       EC_KEY *eckey;
+       const EC_GROUP *ecgrp;
+
+       password = set->key_password[0] != '\0' ? set->key_password : NULL;
+       if (openssl_iostream_load_key(set, &pkey, error_r) < 0)
+               return -1;
+
+       if ((eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL &&
+           (ecgrp = EC_KEY_get0_group(eckey)) != NULL)
+               nid = EC_GROUP_get_curve_name(ecgrp);
+       EVP_PKEY_free(pkey);
+
+       *nid_r = nid;
+       return 0;
+}
+#endif
+
+static int
+ssl_proxy_ctx_set_crypto_params(SSL_CTX *ssl_ctx,
+                               const struct ssl_iostream_settings *set,
+                               const char **error_r)
+{
+#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
+       EC_KEY *ecdh;
+       int nid;
+       const char *curve_name;
+#endif
+       if (SSL_CTX_need_tmp_RSA(ssl_ctx))
+               SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
+       SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
+#if !defined(OPENSSL_NO_ECDH)
+       /* In the non-recommended situation where ECDH cipher suites are being
+          used instead of ECDHE, do not reuse the same ECDH key pair for
+          different sessions. This option improves forward secrecy. */
+       SSL_CTX_set_options(ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
+#endif
+#if !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10002000L
+       /* OpenSSL >= 1.0.2 automatically handles ECDH temporary key parameter
+          selection. */
+       SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
+#elif !defined(OPENSSL_NO_ECDH) && OPENSSL_VERSION_NUMBER >= 0x10000000L
+       /* For OpenSSL < 1.0.2, ECDH temporary key parameter selection must be
+          performed manually. Attempt to select the same curve as that used
+          in the server's private EC key file. Otherwise fall back to the
+          NIST P-384 (secp384r1) curve to be compliant with RFC 6460 when
+          AES-256 TLS cipher suites are in use. This fall back option does
+          however make Dovecot non-compliant with RFC 6460 which requires
+          curve NIST P-256 (prime256v1) be used when AES-128 TLS cipher
+          suites are in use. At least the non-compliance is in the form of
+          providing too much security rather than too little. */
+       if (ssl_proxy_ctx_get_pkey_ec_curve_name(set, &nid, error_r) < 0)
+               return -1;
+       ecdh = EC_KEY_new_by_curve_name(nid);
+       if (ecdh == NULL) {
+               /* Fall back option */
+               nid = NID_secp384r1;
+               ecdh = EC_KEY_new_by_curve_name(nid);
+       }
+       if ((curve_name = OBJ_nid2sn(nid)) != NULL && set->verbose) {
+               i_debug("SSL: elliptic curve %s will be used for ECDH and"
+                       " ECDHE key exchanges", curve_name);
+       }
+       if (ecdh != NULL) {
+               SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
+               EC_KEY_free(ecdh);
+       }
+#endif
+       return 0;
+}
+
 static int
 ssl_iostream_context_init_common(struct ssl_iostream_context *ctx,
                                 const struct ssl_iostream_settings *set,
@@ -417,9 +495,8 @@ ssl_iostream_context_init_common(struct ssl_iostream_context *ctx,
           makes SSL more vulnerable against attacks */
        SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2 |
                            (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS));
-       if (SSL_CTX_need_tmp_RSA(ctx->ssl_ctx))
-               SSL_CTX_set_tmp_rsa_callback(ctx->ssl_ctx, ssl_gen_rsa_key);
-       SSL_CTX_set_tmp_dh_callback(ctx->ssl_ctx, ssl_tmp_dh_callback);
+       if (ssl_proxy_ctx_set_crypto_params(ctx->ssl_ctx, set, error_r) < 0)
+               return -1;
 
        return ssl_iostream_context_set(ctx, set, error_r);
 }