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.
This commit is contained in:
Dr. Stephen Henson 2014-01-22 16:22:48 +00:00
parent 2514fa79ac
commit 09599b52d4
8 changed files with 101 additions and 35 deletions

View file

@ -218,7 +218,6 @@ static void init_session_cache_ctx(SSL_CTX *sctx);
static void free_sessions(void); static void free_sessions(void);
#ifndef OPENSSL_NO_DH #ifndef OPENSSL_NO_DH
static DH *load_dh_param(const char *dhfile); static DH *load_dh_param(const char *dhfile);
static DH *get_dh512(void);
#endif #endif
#ifdef MONOLITH #ifdef MONOLITH
@ -239,33 +238,6 @@ static int client_provided_client_authz = 0;
#endif #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);*/ /* static int load_CA(SSL_CTX *ctx, char *file);*/
#undef BUFSIZZ #undef BUFSIZZ
@ -1931,11 +1903,18 @@ bad:
else else
{ {
BIO_printf(bio_s_out,"Using default temp DH parameters\n"); BIO_printf(bio_s_out,"Using default temp DH parameters\n");
dh=get_dh512();
} }
(void)BIO_flush(bio_s_out); (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 #ifndef OPENSSL_NO_TLSEXT
if (ctx2) if (ctx2)
{ {
@ -1951,7 +1930,15 @@ bad:
dh = dh2; 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 #endif
DH_free(dh); DH_free(dh);

View file

@ -3254,6 +3254,9 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
return(ret); return(ret);
} }
break; break;
case SSL_CTRL_SET_DH_AUTO:
s->cert->dh_tmp_auto = larg;
return 1;
#endif #endif
#ifndef OPENSSL_NO_ECDH #ifndef OPENSSL_NO_ECDH
case SSL_CTRL_SET_TMP_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); return(0);
} }
break; break;
case SSL_CTRL_SET_DH_AUTO:
ctx->cert->dh_tmp_auto = larg;
return 1;
#endif #endif
#ifndef OPENSSL_NO_ECDH #ifndef OPENSSL_NO_ECDH
case SSL_CTRL_SET_TMP_ECDH: case SSL_CTRL_SET_TMP_ECDH:

View file

@ -1679,7 +1679,18 @@ int ssl3_send_server_key_exchange(SSL *s)
#ifndef OPENSSL_NO_DH #ifndef OPENSSL_NO_DH
if (type & SSL_kDHE) 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)) if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL))
dhp=s->cert->dh_tmp_cb(s, dhp=s->cert->dh_tmp_cb(s,
SSL_C_IS_EXPORT(s->s3->tmp.new_cipher), SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
@ -1697,7 +1708,9 @@ int ssl3_send_server_key_exchange(SSL *s)
goto err; 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); SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB);
goto err; goto err;

View file

@ -1957,6 +1957,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CERT_SET_NEXT 2 #define SSL_CERT_SET_NEXT 2
#define SSL_CERT_SET_SERVER 3 #define SSL_CERT_SET_SERVER 3
#define SSL_CTRL_SET_DH_AUTO 118
#define DTLSv1_get_timeout(ssl, arg) \ #define DTLSv1_get_timeout(ssl, arg) \
SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg) SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
#define DTLSv1_handle_timeout(ssl) \ #define DTLSv1_handle_timeout(ssl) \
@ -1982,6 +1984,11 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \ #define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)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) \ #define SSL_need_tmp_RSA(ssl) \
SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL) SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL)
#define SSL_set_tmp_rsa(ssl,rsa) \ #define SSL_set_tmp_rsa(ssl,rsa) \

View file

@ -257,6 +257,7 @@ CERT *ssl_cert_dup(CERT *cert)
} }
} }
ret->dh_tmp_cb = cert->dh_tmp_cb; ret->dh_tmp_cb = cert->dh_tmp_cb;
ret->dh_tmp_auto = cert->dh_tmp_auto;
#endif #endif
#ifndef OPENSSL_NO_ECDH #ifndef OPENSSL_NO_ECDH

View file

@ -2353,8 +2353,8 @@ void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher)
rsa_tmp=rsa_tmp_export=0; rsa_tmp=rsa_tmp_export=0;
#endif #endif
#ifndef OPENSSL_NO_DH #ifndef OPENSSL_NO_DH
dh_tmp=(c->dh_tmp != NULL || 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_cb != NULL || dh_tmp_export= !c->dh_tmp_auto && (c->dh_tmp_cb != NULL ||
(dh_tmp && DH_size(c->dh_tmp)*8 <= kl)); (dh_tmp && DH_size(c->dh_tmp)*8 <= kl));
#else #else
dh_tmp=dh_tmp_export=0; dh_tmp=dh_tmp_export=0;

View file

@ -557,6 +557,7 @@ typedef struct cert_st
#ifndef OPENSSL_NO_DH #ifndef OPENSSL_NO_DH
DH *dh_tmp; DH *dh_tmp;
DH *(*dh_tmp_cb)(SSL *ssl,int is_export,int keysize); DH *(*dh_tmp_cb)(SSL *ssl,int is_export,int keysize);
int dh_tmp_auto;
#endif #endif
#ifndef OPENSSL_NO_ECDH #ifndef OPENSSL_NO_ECDH
EC_KEY *ecdh_tmp; 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); int idx);
void tls1_set_cert_validity(SSL *s); void tls1_set_cert_validity(SSL *s);
#endif
#ifndef OPENSSL_NO_DH
DH *ssl_get_auto_dh(SSL *s);
#endif #endif
EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ; EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
void ssl_clear_hash_ctx(EVP_MD_CTX **hash); void ssl_clear_hash_ctx(EVP_MD_CTX **hash);

View file

@ -115,6 +115,10 @@
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <openssl/ocsp.h> #include <openssl/ocsp.h>
#include <openssl/rand.h> #include <openssl/rand.h>
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#include <openssl/bn.h>
#endif
#include "ssl_locl.h" #include "ssl_locl.h"
const char tls1_version_str[]="TLSv1" OPENSSL_VERSION_PTEXT; 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 #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