s->in_handshake++;
if (!SSL_in_init(s) || SSL_in_before(s)) SSL_clear(s);
+#ifndef OPENSSL_NO_HEARTBEATS
+ /* If we're awaiting a HeartbeatResponse, pretend we
+ * already got and don't await it anymore, because
+ * Heartbeats don't make sense during handshakes anyway.
+ */
+ if (s->tlsext_hb_pending)
+ {
+ s->tlsext_hb_pending = 0;
+ s->tlsext_hb_seq++;
+ }
+#endif
+
for (;;)
{
state=s->state;
case SSL3_ST_CR_SRVR_HELLO_A:
case SSL3_ST_CR_SRVR_HELLO_B:
ret=ssl3_get_server_hello(s);
-#ifndef OPENSSL_NO_SRP
- if ((ret == 0) && (s->s3->warn_alert == SSL_AD_MISSING_SRP_USERNAME))
- {
- if (!SRP_have_to_put_srp_username(s))
- {
- SSLerr(SSL_F_SSL3_CONNECT,SSL_R_MISSING_SRP_USERNAME);
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_USER_CANCELLED);
- goto end;
- }
- s->state=SSL3_ST_CW_CLNT_HELLO_A;
- if (!ssl_init_wbio_buffer(s,0)) { ret= -1; goto end; }
- break;
- }
-#endif
if (ret <= 0) goto end;
if (s->hit)
+ {
s->state=SSL3_ST_CR_FINISHED_A;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_ticket_expected)
+ {
+ /* receive renewed session ticket */
+ s->state=SSL3_ST_CR_SESSION_TICKET_A;
+ }
+#endif
+ }
else
s->state=SSL3_ST_CR_CERT_A;
s->init_num=0;
#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
s->state=SSL3_ST_CW_FINISHED_A;
#else
- if (s->next_proto_negotiated)
+ if (s->s3->next_proto_neg_seen)
s->state=SSL3_ST_CW_NEXT_PROTO_A;
else
s->state=SSL3_ST_CW_FINISHED_A;
/* wrong packet length */
al=SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_BAD_PACKET_LENGTH);
- goto err;
+ goto f_err;
}
return(1);
if (n < 6)
{
/* need at least ticket_lifetime_hint + ticket length */
- al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+ al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
/* ticket_lifetime_hint + ticket_length + ticket */
if (ticklen + 6 != n)
{
- al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR;
+ al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
{
DH *dh_srvr,*dh_clnt;
+ SESS_CERT *scert = s->session->sess_cert;
- if (s->session->sess_cert == NULL)
+ if (scert == NULL)
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_UNEXPECTED_MESSAGE);
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNEXPECTED_MESSAGE);
goto err;
}
- if (s->session->sess_cert->peer_dh_tmp != NULL)
- dh_srvr=s->session->sess_cert->peer_dh_tmp;
+ if (scert->peer_dh_tmp != NULL)
+ dh_srvr=scert->peer_dh_tmp;
else
{
/* we get them from the cert */
- ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE);
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS);
- goto err;
+ int idx = scert->peer_cert_type;
+ EVP_PKEY *spkey = NULL;
+ dh_srvr = NULL;
+ if (idx >= 0)
+ spkey = X509_get_pubkey(
+ scert->peer_pkeys[idx].x509);
+ if (spkey)
+ {
+ dh_srvr = EVP_PKEY_get1_DH(spkey);
+ EVP_PKEY_free(spkey);
+ }
+ if (dh_srvr == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ 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
* make sure to clear it out afterwards */
n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
+ if (scert->peer_dh_tmp == NULL)
+ DH_free(dh_srvr);
if (n <= 0)
{
/* 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);
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;
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 */
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)
alg_a=s->s3->tmp.new_cipher->algorithm_auth;
/* we don't have a certificate */
- if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
+ if ((alg_a & (SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
return(1);
sc=s->session->sess_cert;
}
#endif
#ifndef OPENSSL_NO_DH
- if ((alg_k & SSL_kEDH) &&
+ if ((alg_k & SSL_kEDH) &&
!(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL)))
{
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY);
goto f_err;
}
- else if ((alg_k & SSL_kDHr) && !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
+ else if ((alg_k & SSL_kDHr) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+ !has_bits(i,EVP_PK_DH|EVP_PKS_RSA))
{
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_RSA_CERT);
goto f_err;
}
#ifndef OPENSSL_NO_DSA
- else if ((alg_k & SSL_kDHd) && !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
+ else if ((alg_k & SSL_kDHd) && (TLS1_get_version(s) < TLS1_2_VERSION) &&
+ !has_bits(i,EVP_PK_DH|EVP_PKS_DSA))
{
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_DSA_CERT);
goto f_err;