summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsteve <steve>2012-01-25 14:51:48 +0000
committersteve <steve>2012-01-25 14:51:48 +0000
commit0ef32363ed5e4f90664ae17ba0173690a57bf2f0 (patch)
tree713c0218b5857f8ca8ea2762a65454beb177cc21
parentf0ed564529e9d78b55711f3c8b9dc739839b102b (diff)
downloadopenssl-0ef32363ed5e4f90664ae17ba0173690a57bf2f0.tar.gz
add support for use of fixed DH client certificates
-rw-r--r--CHANGES4
-rw-r--r--ssl/s3_clnt.c92
-rw-r--r--ssl/s3_srvr.c76
3 files changed, 123 insertions, 49 deletions
diff --git a/CHANGES b/CHANGES
index bd16d8b55..39fa10f29 100644
--- a/CHANGES
+++ b/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]
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 62648fe54..4f884c69c 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -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)
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index a23d36f02..a3343a562 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -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)
- {
- 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;
+ /* Get pubkey from cert */
+ EVP_PKEY *clkey=X509_get_pubkey(s->session->peer);
+ if (clkey)
+ {
+ 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