Add a bunch of SSL_xxx() functions for configuring the temporary RSA and DH private keys and/or callback functions which directly correspond to their SSL_CTX_xxx() counterparts but work on a per-connection basis. This is needed for applications which have to configure certificates on a per-connection basis (e.g. Apache+mod_ssl) instead of a per-context basis (e.g. s_server). For the RSA certificate situation is makes no difference, but for the DSA certificate situation this fixes the "no shared cipher" problem where the OpenSSL cipher selection procedure failed because the temporary keys were not overtaken from the context and the API provided no way to reconfigure them. The new functions now let applications reconfigure the stuff and they are in detail: SSL_need_tmp_RSA, SSL_set_tmp_rsa, SSL_set_tmp_dh, SSL_set_tmp_rsa_callback and SSL_set_tmp_dh_callback. Additionally a new non-public-API function ssl_cert_instantiate() is used as a helper function and also to reduce code redundancy inside ssl_rsa.c. Submitted by: Ralf S. Engelschall Reviewed by: Ben Laurie
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 1dd03b1..3687862 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c
@@ -546,6 +546,26 @@ { int ret=0; +#if !defined(NO_DSA) || !defined(NO_RSA) + if ( +#ifndef NO_RSA + cmd == SSL_CTRL_SET_TMP_RSA || + cmd == SSL_CTRL_SET_TMP_RSA_CB || +#endif +#ifndef NO_DSA + cmd == SSL_CTRL_SET_TMP_DH || + cmd == SSL_CTRL_SET_TMP_DH_CB || +#endif + 0) + { + if (!ssl_cert_instantiate(&s->cert, s->ctx->default_cert)) + { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_MALLOC_FAILURE); + return(0); + } + } +#endif + switch (cmd) { case SSL_CTRL_GET_SESSION_REUSED: @@ -566,6 +586,69 @@ case SSL_CTRL_GET_FLAGS: ret=(int)(s->s3->flags); break; +#ifndef NO_RSA + case SSL_CTRL_NEED_TMP_RSA: + if ((s->cert != NULL) && (s->cert->rsa_tmp == NULL) && + ((s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) || + (EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey) > (512/8)))) + ret = 1; + break; + case SSL_CTRL_SET_TMP_RSA: + { + RSA *rsa = (RSA *)parg; + if (rsa == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER); + return(ret); + } + if ((rsa = RSAPrivateKey_dup(rsa)) == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_RSA_LIB); + return(ret); + } + if (s->cert->rsa_tmp != NULL) + RSA_free(s->cert->rsa_tmp); + s->cert->rsa_tmp = rsa; + ret = 1; + } + break; + case SSL_CTRL_SET_TMP_RSA_CB: +#ifndef NOPROTO + s->cert->rsa_tmp_cb = (RSA *(*)(SSL *, int, int))parg; +#else + s->cert->rsa_tmp_cb = (RSA *(*)())parg; +#endif + break; +#endif +#ifndef NO_DH + case SSL_CTRL_SET_TMP_DH: + { + DH *dh = (DH *)parg; + if (dh == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER); + return(ret); + } + if ((dh = DHparams_dup(dh)) == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_DH_LIB); + return(ret); + } + if (!DH_generate_key(dh)) { + DH_free(dh); + SSLerr(SSL_F_SSL3_CTRL, ERR_R_DH_LIB); + return(ret); + } + if (s->cert->dh_tmp != NULL) + DH_free(s->cert->dh_tmp); + s->cert->dh_tmp = dh; + ret = 1; + } + break; + case SSL_CTRL_SET_TMP_DH_CB: +#ifndef NOPROTO + s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))parg; +#else + s->cert->dh_tmp_cb = (DH *(*)())parg; +#endif + break; +#endif default: break; }