Commit 0d609395 authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

add support for use of fixed DH client certificates

parent 2ff5ac55
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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]
+73 −19
Original line number Diff line number Diff line
@@ -2428,7 +2428,21 @@ int ssl3_send_client_key_exchange(SSL *s)
					goto err;
					}
				}

			if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
				{
				/* 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;
					}
				}
			else
				{
				/* generate a new random key */
				if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL)
					{
@@ -2441,6 +2455,7 @@ int ssl3_send_client_key_exchange(SSL *s)
					DH_free(dh_clnt);
					goto err;
					}
				}

			/* use the 'p' output buffer for the DH key, but
			 * make sure to clear it out afterwards */
@@ -2463,11 +2478,16 @@ int ssl3_send_client_key_exchange(SSL *s)
			/* clean up */
			memset(p,0,n);

			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)
+46 −30
Original line number Diff line number Diff line
@@ -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))
		{
		int idx = -1;
		EVP_PKEY *skey = NULL;
		if (n)
			n2s(p,i);
		if (n != i+2)
		if (n && n != i+2)
			{
			if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
				{
@@ -2280,23 +2284,13 @@ int ssl3_get_client_key_exchange(SSL *s)
				i=(int)n;
				}
			}

		if (n == 0L) /* the parameters are in the cert */
			{
			al=SSL_AD_HANDSHAKE_FAILURE;
			SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS);
			goto f_err;
			}
		else
			{
			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;
			skey = s->cert->pkeys[idx].privatekey;
			if ((skey == NULL) ||
				(skey->type != EVP_PKEY_DH) ||
				(skey->pkey.dh == NULL))
@@ -2315,8 +2309,26 @@ int ssl3_get_client_key_exchange(SSL *s)
			}
		else
			dh_srvr=s->s3->tmp.dh;
			}

		if (n == 0L)
			{
			/* 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);
				}
			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;
				}
			EVP_PKEY_free(clkey);
			pub = dh_clnt->pub_key;
			}
		else
			pub=BN_bin2bn(p,i,NULL);
		if (pub == NULL)
			{
@@ -2335,13 +2347,17 @@ int ssl3_get_client_key_exchange(SSL *s)

		DH_free(s->s3->tmp.dh);
		s->s3->tmp.dh=NULL;

		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