add support for use of fixed DH client certificates
This commit is contained in:
parent
2ff5ac55c5
commit
0d60939515
4
CHANGES
4
CHANGES
@ -4,6 +4,10 @@
|
||||
|
||||
Changes between 1.0.1 and 1.1.0 [xx XXX xxxx]
|
||||
|
||||
*) Support for fixed DH ciphersuite client authentication: where both
|
||||
server and client use DH certificates with common parameters.
|
||||
[Steve Henson]
|
||||
|
||||
*) Support for fixed DH ciphersuites: those requiring DH server
|
||||
certificates.
|
||||
[Steve Henson]
|
||||
|
@ -2428,18 +2428,33 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a new random key */
|
||||
if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
|
||||
if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
|
||||
goto err;
|
||||
/* Use client certificate key */
|
||||
EVP_PKEY *clkey = s->cert->key->privatekey;
|
||||
if (clkey)
|
||||
dh_clnt = EVP_PKEY_get1_DH(clkey);
|
||||
if (dh_clnt == NULL)
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
|
||||
ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (!DH_generate_key(dh_clnt))
|
||||
else
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
|
||||
DH_free(dh_clnt);
|
||||
goto err;
|
||||
/* generate a new random key */
|
||||
if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
|
||||
goto err;
|
||||
}
|
||||
if (!DH_generate_key(dh_clnt))
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
|
||||
DH_free(dh_clnt);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* use the 'p' output buffer for the DH key, but
|
||||
@ -2463,11 +2478,16 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
/* clean up */
|
||||
memset(p,0,n);
|
||||
|
||||
/* send off the data */
|
||||
n=BN_num_bytes(dh_clnt->pub_key);
|
||||
s2n(n,p);
|
||||
BN_bn2bin(dh_clnt->pub_key,p);
|
||||
n+=2;
|
||||
if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
|
||||
n = 0;
|
||||
else
|
||||
{
|
||||
/* send off the data */
|
||||
n=BN_num_bytes(dh_clnt->pub_key);
|
||||
s2n(n,p);
|
||||
BN_bn2bin(dh_clnt->pub_key,p);
|
||||
n+=2;
|
||||
}
|
||||
|
||||
DH_free(dh_clnt);
|
||||
|
||||
@ -3054,6 +3074,40 @@ err:
|
||||
return(-1);
|
||||
}
|
||||
|
||||
/* Check a certificate can be used for client authentication. Currently
|
||||
* just check cert exists and if static DH client certificates can be used.
|
||||
*/
|
||||
static int ssl3_check_client_certificate(SSL *s)
|
||||
{
|
||||
unsigned long alg_k;
|
||||
if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey)
|
||||
return 0;
|
||||
alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
|
||||
/* See if we can use client certificate for fixed DH */
|
||||
if (alg_k & (SSL_kDHr|SSL_kDHd))
|
||||
{
|
||||
SESS_CERT *scert = s->session->sess_cert;
|
||||
int i = scert->peer_cert_type;
|
||||
EVP_PKEY *clkey = NULL, *spkey = NULL;
|
||||
clkey = s->cert->key->privatekey;
|
||||
/* If client key not DH assume it can be used */
|
||||
if (EVP_PKEY_id(clkey) != EVP_PKEY_DH)
|
||||
return 1;
|
||||
if (i >= 0)
|
||||
spkey = X509_get_pubkey(scert->peer_pkeys[i].x509);
|
||||
if (spkey)
|
||||
{
|
||||
/* Compare server and client parameters */
|
||||
i = EVP_PKEY_cmp_parameters(clkey, spkey);
|
||||
EVP_PKEY_free(spkey);
|
||||
if (i != 1)
|
||||
return 0;
|
||||
}
|
||||
s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ssl3_send_client_certificate(SSL *s)
|
||||
{
|
||||
X509 *x509=NULL;
|
||||
@ -3063,12 +3117,10 @@ int ssl3_send_client_certificate(SSL *s)
|
||||
|
||||
if (s->state == SSL3_ST_CW_CERT_A)
|
||||
{
|
||||
if ((s->cert == NULL) ||
|
||||
(s->cert->key->x509 == NULL) ||
|
||||
(s->cert->key->privatekey == NULL))
|
||||
s->state=SSL3_ST_CW_CERT_B;
|
||||
else
|
||||
if (ssl3_check_client_certificate(s))
|
||||
s->state=SSL3_ST_CW_CERT_C;
|
||||
else
|
||||
s->state=SSL3_ST_CW_CERT_B;
|
||||
}
|
||||
|
||||
/* We need to get a client cert */
|
||||
@ -3100,6 +3152,8 @@ int ssl3_send_client_certificate(SSL *s)
|
||||
|
||||
if (x509 != NULL) X509_free(x509);
|
||||
if (pkey != NULL) EVP_PKEY_free(pkey);
|
||||
if (i && !ssl3_check_client_certificate(s))
|
||||
i = 0;
|
||||
if (i == 0)
|
||||
{
|
||||
if (s->version == SSL3_VERSION)
|
||||
|
@ -298,6 +298,7 @@ int ssl3_accept(SSL *s)
|
||||
|
||||
s->init_num=0;
|
||||
s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE;
|
||||
s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY;
|
||||
|
||||
if (s->state != SSL_ST_RENEGOTIATE)
|
||||
{
|
||||
@ -2132,7 +2133,7 @@ int ssl3_get_client_key_exchange(SSL *s)
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_DH
|
||||
BIGNUM *pub=NULL;
|
||||
DH *dh_srvr;
|
||||
DH *dh_srvr, *dh_clnt = NULL;
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_KRB5
|
||||
KSSL_ERR kssl_err;
|
||||
@ -2266,8 +2267,11 @@ int ssl3_get_client_key_exchange(SSL *s)
|
||||
#ifndef OPENSSL_NO_DH
|
||||
if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
|
||||
{
|
||||
n2s(p,i);
|
||||
if (n != i+2)
|
||||
int idx = -1;
|
||||
EVP_PKEY *skey = NULL;
|
||||
if (n)
|
||||
n2s(p,i);
|
||||
if (n && n != i+2)
|
||||
{
|
||||
if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
|
||||
{
|
||||
@ -2280,44 +2284,52 @@ int ssl3_get_client_key_exchange(SSL *s)
|
||||
i=(int)n;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0L) /* the parameters are in the cert */
|
||||
if (alg_k & SSL_kDHr)
|
||||
idx = SSL_PKEY_DH_RSA;
|
||||
else if (alg_k & SSL_kDHd)
|
||||
idx = SSL_PKEY_DH_DSA;
|
||||
if (idx >= 0)
|
||||
{
|
||||
skey = s->cert->pkeys[idx].privatekey;
|
||||
if ((skey == NULL) ||
|
||||
(skey->type != EVP_PKEY_DH) ||
|
||||
(skey->pkey.dh == NULL))
|
||||
{
|
||||
al=SSL_AD_HANDSHAKE_FAILURE;
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
|
||||
goto f_err;
|
||||
}
|
||||
dh_srvr = skey->pkey.dh;
|
||||
}
|
||||
else if (s->s3->tmp.dh == NULL)
|
||||
{
|
||||
al=SSL_AD_HANDSHAKE_FAILURE;
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS);
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
|
||||
goto f_err;
|
||||
}
|
||||
else
|
||||
dh_srvr=s->s3->tmp.dh;
|
||||
|
||||
if (n == 0L)
|
||||
{
|
||||
int idx = -1;
|
||||
if (alg_k & SSL_kDHr)
|
||||
idx = SSL_PKEY_DH_RSA;
|
||||
else if (alg_k & SSL_kDHd)
|
||||
idx = SSL_PKEY_DH_DSA;
|
||||
if (idx >= 0)
|
||||
/* Get pubkey from cert */
|
||||
EVP_PKEY *clkey=X509_get_pubkey(s->session->peer);
|
||||
if (clkey)
|
||||
{
|
||||
EVP_PKEY *skey = s->cert->pkeys[idx].privatekey;
|
||||
if ((skey == NULL) ||
|
||||
(skey->type != EVP_PKEY_DH) ||
|
||||
(skey->pkey.dh == NULL))
|
||||
{
|
||||
al=SSL_AD_HANDSHAKE_FAILURE;
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_RSA_CERTIFICATE);
|
||||
goto f_err;
|
||||
}
|
||||
dh_srvr = skey->pkey.dh;
|
||||
if (EVP_PKEY_cmp_parameters(clkey, skey) == 1)
|
||||
dh_clnt = EVP_PKEY_get1_DH(clkey);
|
||||
}
|
||||
else if (s->s3->tmp.dh == NULL)
|
||||
if (dh_clnt == NULL)
|
||||
{
|
||||
al=SSL_AD_HANDSHAKE_FAILURE;
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY);
|
||||
goto f_err;
|
||||
}
|
||||
else
|
||||
dh_srvr=s->s3->tmp.dh;
|
||||
EVP_PKEY_free(clkey);
|
||||
pub = dh_clnt->pub_key;
|
||||
}
|
||||
|
||||
pub=BN_bin2bn(p,i,NULL);
|
||||
else
|
||||
pub=BN_bin2bn(p,i,NULL);
|
||||
if (pub == NULL)
|
||||
{
|
||||
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BN_LIB);
|
||||
@ -2335,13 +2347,17 @@ int ssl3_get_client_key_exchange(SSL *s)
|
||||
|
||||
DH_free(s->s3->tmp.dh);
|
||||
s->s3->tmp.dh=NULL;
|
||||
|
||||
BN_clear_free(pub);
|
||||
if (dh_clnt)
|
||||
DH_free(dh_clnt);
|
||||
else
|
||||
BN_clear_free(pub);
|
||||
pub=NULL;
|
||||
s->session->master_key_length=
|
||||
s->method->ssl3_enc->generate_master_secret(s,
|
||||
s->session->master_key,p,i);
|
||||
OPENSSL_cleanse(p,i);
|
||||
if (dh_clnt)
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user