From 09599b52d4e295c380512ba39958a11994d63401 Mon Sep 17 00:00:00 2001 From: "Dr. Stephen Henson" Date: Wed, 22 Jan 2014 16:22:48 +0000 Subject: [PATCH] Auto DH support. Add auto DH parameter support. This is roughly equivalent to the ECDH auto curve selection but for DH. An application can just call SSL_CTX_set_auto_dh(ctx, 1); and appropriate DH parameters will be used based on the size of the server key. Unlike ECDH there is no way a peer can indicate the range of DH parameters it supports. Some peers cannot handle DH keys larger that 1024 bits for example. In this case if you call: SSL_CTX_set_auto_dh(ctx, 2); Only 1024 bit DH parameters will be used. If the server key is 7680 bits or more in size then 8192 bit DH parameters will be used: these will be *very* slow. The old export ciphersuites aren't supported but those are very insecure anyway. --- apps/s_server.c | 49 ++++++++++++++++++------------------------------- ssl/s3_lib.c | 6 ++++++ ssl/s3_srvr.c | 17 +++++++++++++++-- ssl/ssl.h | 7 +++++++ ssl/ssl_cert.c | 1 + ssl/ssl_lib.c | 4 ++-- ssl/ssl_locl.h | 4 ++++ ssl/t1_lib.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 101 insertions(+), 35 deletions(-) diff --git a/apps/s_server.c b/apps/s_server.c index eb3c866963..9db57dff3c 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -218,7 +218,6 @@ static void init_session_cache_ctx(SSL_CTX *sctx); static void free_sessions(void); #ifndef OPENSSL_NO_DH static DH *load_dh_param(const char *dhfile); -static DH *get_dh512(void); #endif #ifdef MONOLITH @@ -239,33 +238,6 @@ static int client_provided_client_authz = 0; #endif -#ifndef OPENSSL_NO_DH -static unsigned char dh512_p[]={ - 0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75, - 0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F, - 0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3, - 0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12, - 0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C, - 0x47,0x74,0xE8,0x33, - }; -static unsigned char dh512_g[]={ - 0x02, - }; - -static DH *get_dh512(void) - { - DH *dh=NULL; - - if ((dh=DH_new()) == NULL) return(NULL); - dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); - dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); - if ((dh->p == NULL) || (dh->g == NULL)) - return(NULL); - return(dh); - } -#endif - - /* static int load_CA(SSL_CTX *ctx, char *file);*/ #undef BUFSIZZ @@ -1931,11 +1903,18 @@ bad: else { BIO_printf(bio_s_out,"Using default temp DH parameters\n"); - dh=get_dh512(); } (void)BIO_flush(bio_s_out); - SSL_CTX_set_tmp_dh(ctx,dh); + if (dh == NULL) + SSL_CTX_set_dh_auto(ctx, 1); + else if (!SSL_CTX_set_tmp_dh(ctx,dh)) + { + BIO_puts(bio_err, "Error setting temp DH parameters\n"); + ERR_print_errors(bio_err); + DH_free(dh); + goto end; + } #ifndef OPENSSL_NO_TLSEXT if (ctx2) { @@ -1951,7 +1930,15 @@ bad: dh = dh2; } } - SSL_CTX_set_tmp_dh(ctx2,dh); + if (dh == NULL) + SSL_CTX_set_dh_auto(ctx2, 1); + else if (!SSL_CTX_set_tmp_dh(ctx2,dh)) + { + BIO_puts(bio_err, "Error setting temp DH parameters\n"); + ERR_print_errors(bio_err); + DH_free(dh); + goto end; + } } #endif DH_free(dh); diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 5a1b80bdc2..517b1a27d1 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3254,6 +3254,9 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) return(ret); } break; + case SSL_CTRL_SET_DH_AUTO: + s->cert->dh_tmp_auto = larg; + return 1; #endif #ifndef OPENSSL_NO_ECDH case SSL_CTRL_SET_TMP_ECDH: @@ -3759,6 +3762,9 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) return(0); } break; + case SSL_CTRL_SET_DH_AUTO: + ctx->cert->dh_tmp_auto = larg; + return 1; #endif #ifndef OPENSSL_NO_ECDH case SSL_CTRL_SET_TMP_ECDH: diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index a787c6d32d..f048b76dca 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1679,7 +1679,18 @@ int ssl3_send_server_key_exchange(SSL *s) #ifndef OPENSSL_NO_DH if (type & SSL_kDHE) { - dhp=cert->dh_tmp; + if (s->cert->dh_tmp_auto) + { + dhp = ssl_get_auto_dh(s); + if (dhp == NULL) + { + al=SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto f_err; + } + } + else + dhp=cert->dh_tmp; if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL)) dhp=s->cert->dh_tmp_cb(s, SSL_C_IS_EXPORT(s->s3->tmp.new_cipher), @@ -1697,7 +1708,9 @@ int ssl3_send_server_key_exchange(SSL *s) goto err; } - if ((dh=DHparams_dup(dhp)) == NULL) + if (s->cert->dh_tmp_auto) + dh = dhp; + else if ((dh=DHparams_dup(dhp)) == NULL) { SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB); goto err; diff --git a/ssl/ssl.h b/ssl/ssl.h index 27dcb09aae..c6b1ac35f9 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -1957,6 +1957,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CERT_SET_NEXT 2 #define SSL_CERT_SET_SERVER 3 +#define SSL_CTRL_SET_DH_AUTO 118 + #define DTLSv1_get_timeout(ssl, arg) \ SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg) #define DTLSv1_handle_timeout(ssl) \ @@ -1982,6 +1984,11 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) +#define SSL_CTX_set_dh_auto(ctx, onoff) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_DH_AUTO,onoff,NULL) +#define SSL_set_dh_auto(s, onoff) \ + SSL_ctrl(s,SSL_CTRL_SET_DH_AUTO,onoff,NULL) + #define SSL_need_tmp_RSA(ssl) \ SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL) #define SSL_set_tmp_rsa(ssl,rsa) \ diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 3ad0f8bca3..665623eed8 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -257,6 +257,7 @@ CERT *ssl_cert_dup(CERT *cert) } } ret->dh_tmp_cb = cert->dh_tmp_cb; + ret->dh_tmp_auto = cert->dh_tmp_auto; #endif #ifndef OPENSSL_NO_ECDH diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index eeed24de10..cc9b965778 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2353,8 +2353,8 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher) rsa_tmp=rsa_tmp_export=0; #endif #ifndef OPENSSL_NO_DH - dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL); - dh_tmp_export=(c->dh_tmp_cb != NULL || + dh_tmp=(c->dh_tmp != NULL || c->dh_tmp_cb != NULL || c->dh_tmp_auto); + dh_tmp_export= !c->dh_tmp_auto && (c->dh_tmp_cb != NULL || (dh_tmp && DH_size(c->dh_tmp)*8 <= kl)); #else dh_tmp=dh_tmp_export=0; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 1a2aef70e4..cd397f45d2 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -557,6 +557,7 @@ typedef struct cert_st #ifndef OPENSSL_NO_DH DH *dh_tmp; DH *(*dh_tmp_cb)(SSL *ssl,int is_export,int keysize); + int dh_tmp_auto; #endif #ifndef OPENSSL_NO_ECDH EC_KEY *ecdh_tmp; @@ -1310,6 +1311,9 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, int idx); void tls1_set_cert_validity(SSL *s); +#endif +#ifndef OPENSSL_NO_DH +DH *ssl_get_auto_dh(SSL *s); #endif EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; void ssl_clear_hash_ctx(EVP_MD_CTX **hash); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 31fc70e05e..c9e489898a 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -115,6 +115,10 @@ #include #include #include +#ifndef OPENSSL_NO_DH +#include +#include +#endif #include "ssl_locl.h" const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; @@ -4439,3 +4443,47 @@ int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain) } #endif + +#ifndef OPENSSL_NO_DH +DH *ssl_get_auto_dh(SSL *s) + { + int dh_secbits = 80; + if (s->cert->dh_tmp_auto == 2) + return DH_get_1024_160(); + if (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) + { + if (s->s3->tmp.new_cipher->strength_bits == 256) + dh_secbits = 128; + else + dh_secbits = 80; + } + else + { + CERT_PKEY *cpk = ssl_get_server_send_pkey(s); + dh_secbits = EVP_PKEY_security_bits(cpk->privatekey); + } + + if (dh_secbits >= 128) + { + DH *dhp = DH_new(); + if (!dhp) + return NULL; + dhp->g = BN_new(); + if (dhp->g) + BN_set_word(dhp->g, 2); + if (dh_secbits >= 192) + dhp->p = get_rfc3526_prime_8192(NULL); + else + dhp->p = get_rfc3526_prime_3072(NULL); + if (!dhp->p || !dhp->g) + { + DH_free(dhp); + return NULL; + } + return dhp; + } + if (dh_secbits >= 112) + return DH_get_2048_224(); + return DH_get_1024_160(); + } +#endif -- 2.40.0