#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/md5.h>
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
#ifndef OPENSSL_NO_DH
#include <openssl/dh.h>
#endif
#include <openssl/bn.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
static const SSL_METHOD *ssl3_get_client_method(int ver);
static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b);
{
BUF_MEM *buf=NULL;
unsigned long Time=(unsigned long)time(NULL);
- long num1;
void (*cb)(const SSL *ssl,int type,int val)=NULL;
int ret= -1;
- int new_state,state,skip=0;;
+ int new_state,state,skip=0;
RAND_add(&Time,sizeof(Time),0);
ERR_clear_error();
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;
switch(s->state)
{
case SSL_ST_RENEGOTIATE:
- s->new_session=1;
+ s->renegotiate=1;
s->state=SSL_ST_CONNECT;
s->ctx->stats.sess_connect_renegotiate++;
/* break */
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;
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
+#ifndef OPENSSL_NO_TLSEXT
+ ret=ssl3_check_finished(s);
+ if (ret <= 0) goto end;
+ if (ret == 2)
+ {
+ s->hit = 1;
+ if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
+ s->state=SSL3_ST_CR_FINISHED_A;
+ s->init_num=0;
+ break;
+ }
+#endif
/* Check if it is anon DH/ECDH */
/* or PSK */
if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) &&
{
ret=ssl3_get_server_certificate(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_status_expected)
+ s->state=SSL3_ST_CR_CERT_STATUS_A;
+ else
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ }
+ else
+ {
+ skip = 1;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ }
+#else
}
else
skip=1;
+
s->state=SSL3_ST_CR_KEY_EXCH_A;
+#endif
s->init_num=0;
break;
case SSL3_ST_CR_SRVR_DONE_B:
ret=ssl3_get_server_done(s);
if (ret <= 0) goto end;
+#ifndef OPENSSL_NO_SRP
+ if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP)
+ {
+ if ((ret = SRP_Calc_A_param(s))<=0)
+ {
+ SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SRP_A_CALC);
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_INTERNAL_ERROR);
+ goto end;
+ }
+ }
+#endif
if (s->s3->tmp.cert_req)
s->state=SSL3_ST_CW_CERT_A;
else
s->state=SSL3_ST_CW_CHANGE_A;
s->s3->change_cipher_spec=0;
}
+ if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
+ {
+ s->state=SSL3_ST_CW_CHANGE_A;
+ s->s3->change_cipher_spec=0;
+ }
s->init_num=0;
break;
ret=ssl3_send_change_cipher_spec(s,
SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B);
if (ret <= 0) goto end;
+
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
s->state=SSL3_ST_CW_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ s->state=SSL3_ST_CW_NEXT_PROTO_A;
+ else
+ s->state=SSL3_ST_CW_FINISHED_A;
+#endif
s->init_num=0;
s->session->cipher=s->s3->tmp.new_cipher;
break;
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ case SSL3_ST_CW_NEXT_PROTO_A:
+ case SSL3_ST_CW_NEXT_PROTO_B:
+ ret=ssl3_send_next_proto(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CW_FINISHED_A;
+ break;
+#endif
+
case SSL3_ST_CW_FINISHED_A:
case SSL3_ST_CW_FINISHED_B:
ret=ssl3_send_finished(s,
}
else
{
+#ifndef OPENSSL_NO_TLSEXT
+ /* Allow NewSessionTicket if ticket expected */
+ if (s->tlsext_ticket_expected)
+ s->s3->tmp.next_state=SSL3_ST_CR_SESSION_TICKET_A;
+ else
+#endif
+
s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
}
s->init_num=0;
break;
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_CR_SESSION_TICKET_A:
+ case SSL3_ST_CR_SESSION_TICKET_B:
+ ret=ssl3_get_new_session_ticket(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_FINISHED_A;
+ s->init_num=0;
+ break;
+
+ case SSL3_ST_CR_CERT_STATUS_A:
+ case SSL3_ST_CR_CERT_STATUS_B:
+ ret=ssl3_get_cert_status(s);
+ if (ret <= 0) goto end;
+ s->state=SSL3_ST_CR_KEY_EXCH_A;
+ s->init_num=0;
+ break;
+#endif
+
case SSL3_ST_CR_FINISHED_A:
case SSL3_ST_CR_FINISHED_B:
break;
case SSL3_ST_CW_FLUSH:
- /* number of bytes to be flushed */
- num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL);
- if (num1 > 0)
+ s->rwstate=SSL_WRITING;
+ if (BIO_flush(s->wbio) <= 0)
{
- s->rwstate=SSL_WRITING;
- num1=BIO_flush(s->wbio);
- if (num1 <= 0) { ret= -1; goto end; }
- s->rwstate=SSL_NOTHING;
+ ret= -1;
+ goto end;
}
-
+ s->rwstate=SSL_NOTHING;
s->state=s->s3->tmp.next_state;
break;
/* else do it later in ssl3_write */
s->init_num=0;
+ s->renegotiate=0;
s->new_session=0;
ssl_update_cache(s,SSL_SESS_CACHE_CLIENT);
unsigned char *buf;
unsigned char *p,*d;
int i;
- unsigned long Time,l;
+ unsigned long l;
#ifndef OPENSSL_NO_COMP
int j;
SSL_COMP *comp;
buf=(unsigned char *)s->init_buf->data;
if (s->state == SSL3_ST_CW_CLNT_HELLO_A)
{
- if ((s->session == NULL) ||
- (s->session->ssl_version != s->version) ||
- (s->session->not_resumable))
+ SSL_SESSION *sess = s->session;
+ if ((sess == NULL) ||
+ (sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+ !sess->session_id_length ||
+#else
+ (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+ (sess->not_resumable))
{
if (!ssl_get_new_session(s,0))
goto err;
/* else use the pre-loaded session */
p=s->s3->client_random;
- Time=(unsigned long)time(NULL); /* Time */
- l2n(Time,p);
- if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+
+ if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0)
goto err;
/* Do the message type and length last */
d=p= &(buf[4]);
+ /* version indicates the negotiated version: for example from
+ * an SSLv2/v3 compatible client hello). The client_version
+ * field is the maximum version we permit and it is also
+ * used in RSA encrypted premaster secrets. Some servers can
+ * choke if we initially report a higher version then
+ * renegotiate to a lower one in the premaster secret. This
+ * didn't happen with TLS 1.0 as most servers supported it
+ * but it can with TLS 1.1 or later if the server only supports
+ * 1.0.
+ *
+ * Possible scenario with previous logic:
+ * 1. Client hello indicates TLS 1.2
+ * 2. Server hello says TLS 1.0
+ * 3. RSA encrypted premaster secret uses 1.2.
+ * 4. Handhaked proceeds using TLS 1.0.
+ * 5. Server sends hello request to renegotiate.
+ * 6. Client hello indicates TLS v1.0 as we now
+ * know that is maximum server supports.
+ * 7. Server chokes on RSA encrypted premaster secret
+ * containing version 1.0.
+ *
+ * For interoperability it should be OK to always use the
+ * maximum version we support in client hello and then rely
+ * on the checking of version to ensure the servers isn't
+ * being inconsistent: for example initially negotiating with
+ * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
+ * client_version in client hello and not resetting it to
+ * the negotiated version.
+ */
+#if 0
*(p++)=s->version>>8;
*(p++)=s->version&0xff;
s->client_version=s->version;
+#else
+ *(p++)=s->client_version>>8;
+ *(p++)=s->client_version&0xff;
+#endif
/* Random stuff */
memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE);
SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE);
goto err;
}
+#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH
+ /* Some servers hang if client hello > 256 bytes
+ * as hack workaround chop number of supported ciphers
+ * to keep it well below this if we use TLS v1.2
+ */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION
+ && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH)
+ i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1;
+#endif
s2n(i,p);
p+=i;
}
#endif
*(p++)=0; /* Add the NULL method */
+
#ifndef OPENSSL_NO_TLSEXT
+ /* TLS extensions*/
if (ssl_prepare_clienthello_tlsext(s) <= 0)
{
SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
int ssl3_get_server_hello(SSL *s)
{
STACK_OF(SSL_CIPHER) *sk;
- SSL_CIPHER *c;
+ const SSL_CIPHER *c;
unsigned char *p,*d;
int i,al,ok;
unsigned int j;
SSL3_ST_CR_SRVR_HELLO_A,
SSL3_ST_CR_SRVR_HELLO_B,
-1,
- 300, /* ?? */
+ 20000, /* ?? */
&ok);
if (!ok) return((int)n);
- if ( SSL_version(s) == DTLS1_VERSION)
+ if ( SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER)
{
if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
{
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
+ {
+ SSL_CIPHER *pref_cipher=NULL;
+ s->session->master_key_length=sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key,
+ &s->session->master_key_length,
+ NULL, &pref_cipher,
+ s->tls_session_secret_cb_arg))
+ {
+ s->session->cipher = pref_cipher ?
+ pref_cipher : ssl_get_cipher_by_char(s, p+j);
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
if (j != 0 && j == s->session->session_id_length
&& memcmp(p,s->session->session_id,j) == 0)
{
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNKNOWN_CIPHER_RETURNED);
goto f_err;
}
+ /* TLS v1.2 only ciphersuites require v1.2 or later */
+ if ((c->algorithm_ssl & SSL_TLSV1_2) &&
+ (TLS1_get_version(s) < TLS1_2_VERSION))
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED);
+ goto f_err;
+ }
p+=ssl_put_cipher_by_char(s,NULL,NULL);
sk=ssl_get_ciphers_by_id(s);
s->session->cipher_id = s->session->cipher->id;
if (s->hit && (s->session->cipher_id != c->id))
{
+/* Workaround is now obsolete */
+#if 0
if (!(s->options &
SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
+#endif
{
al=SSL_AD_ILLEGAL_PARAMETER;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
}
}
s->s3->tmp.new_cipher=c;
-
+ /* Don't digest cached records if TLS v1.2: we may need them for
+ * client authentication.
+ */
+ if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s))
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
/* lets get the compression algorithm */
/* COMPRESSION */
#ifdef OPENSSL_NO_COMP
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
goto f_err;
}
+ /* If compression is disabled we'd better not try to resume a session
+ * using compression.
+ */
+ if (s->session->compress_meth != 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
+ goto f_err;
+ }
#else
j= *(p++);
- if ((j == 0) || (s->options & SSL_OP_NO_COMPRESSION))
+ if (s->hit && j != s->session->compress_meth)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
+ goto f_err;
+ }
+ if (j == 0)
comp=NULL;
+ else if (s->options & SSL_OP_NO_COMPRESSION)
+ {
+ al=SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_COMPRESSION_DISABLED);
+ goto f_err;
+ }
else
comp=ssl3_comp_find(s->ctx->comp_methods,j);
s->s3->tmp.new_compression=comp;
}
#endif
+
#ifndef OPENSSL_NO_TLSEXT
/* TLS extensions*/
- if (s->version > SSL3_VERSION)
+ if (s->version >= SSL3_VERSION)
{
if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al))
{
}
if (ssl_check_serverhello_tlsext(s) <= 0)
{
- SSLerr(SSL_F_SSL3_CONNECT,SSL_R_SERVERHELLO_TLSEXT);
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
goto err;
}
}
/* 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 (!ok) return((int)n);
- if (s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE)
+ if ((s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) ||
+ ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) &&
+ (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)))
{
s->s3->tmp.reuse_message=1;
return(1);
}
i=ssl_verify_cert_chain(s,sk);
- if ((s->verify_mode != SSL_VERIFY_NONE) && (!i)
+ if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)
#ifndef OPENSSL_NO_KRB5
&& !((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) &&
(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5))
int al,i,j,param_len,ok;
long n,alg_k,alg_a;
EVP_PKEY *pkey=NULL;
+ const EVP_MD *md = NULL;
#ifndef OPENSSL_NO_RSA
RSA *rsa=NULL;
#endif
}
else
#endif /* !OPENSSL_NO_PSK */
+#ifndef OPENSSL_NO_SRP
+ if (alg_k & SSL_kSRP)
+ {
+ n2s(p,i);
+ param_len=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_N_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.N=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ n2s(p,i);
+ param_len+=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_G_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.g=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ i = (unsigned int)(p[0]);
+ p++;
+ param_len+=i+1;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_S_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.s=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+
+ n2s(p,i);
+ param_len+=i+2;
+ if (param_len > n)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_B_LENGTH);
+ goto f_err;
+ }
+ if (!(s->srp_ctx.B=BN_bin2bn(p,i,NULL)))
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB);
+ goto err;
+ }
+ p+=i;
+ n-=param_len;
+
+/* We must check if there is a certificate */
+#ifndef OPENSSL_NO_RSA
+ if (alg_a & SSL_aRSA)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
+#else
+ if (0)
+ ;
+#endif
+#ifndef OPENSSL_NO_DSA
+ else if (alg_a & SSL_aDSS)
+ pkey=X509_get_pubkey(s->session->sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN].x509);
+#endif
+ }
+ else
+#endif /* !OPENSSL_NO_SRP */
#ifndef OPENSSL_NO_RSA
if (alg_k & SSL_kRSA)
{
s->session->sess_cert->peer_ecdh_tmp=ecdh;
ecdh=NULL;
BN_CTX_free(bn_ctx);
+ bn_ctx = NULL;
EC_POINT_free(srvr_ecpoint);
srvr_ecpoint = NULL;
}
/* if it was signed, check the signature */
if (pkey != NULL)
{
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ int sigalg = tls12_get_sigid(pkey);
+ /* Should never happen */
+ if (sigalg == -1)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ /* Check key type is consistent with signature */
+ if (sigalg != (int)p[1])
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+ md = tls12_get_hash(p[0]);
+ if (md == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST);
+ al=SSL_AD_DECODE_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
+#endif
+ p += 2;
+ n -= 2;
+ }
+ else
+ md = EVP_sha1();
+
n2s(p,i);
n-=2;
j=EVP_PKEY_size(pkey);
}
#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA)
+ if (pkey->type == EVP_PKEY_RSA && TLS1_get_version(s) < TLS1_2_VERSION)
{
int num;
q=md_buf;
for (num=2; num > 0; num--)
{
+ EVP_MD_CTX_set_flags(&md_ctx,
+ EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
EVP_DigestInit_ex(&md_ctx,(num == 2)
?s->ctx->md5:s->ctx->sha1, NULL);
EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
}
else
#endif
-#ifndef OPENSSL_NO_DSA
- if (pkey->type == EVP_PKEY_DSA)
- {
- /* lets do DSS */
- EVP_VerifyInit_ex(&md_ctx,EVP_dss1(), NULL);
- EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_VerifyUpdate(&md_ctx,param,param_len);
- if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey))
- {
- /* bad signature */
- al=SSL_AD_DECRYPT_ERROR;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE);
- goto f_err;
- }
- }
- else
-#endif
-#ifndef OPENSSL_NO_ECDSA
- if (pkey->type == EVP_PKEY_EC)
{
- /* let's do ECDSA */
- EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), NULL);
+ EVP_VerifyInit_ex(&md_ctx, md, NULL);
EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
EVP_VerifyUpdate(&md_ctx,param,param_len);
- if (!EVP_VerifyFinal(&md_ctx,p,(int)n,pkey))
+ if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0)
{
/* bad signature */
al=SSL_AD_DECRYPT_ERROR;
goto f_err;
}
}
- else
-#endif
- {
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
- goto err;
- }
}
else
{
{
int ok,ret=0;
unsigned long n,nc,l;
- unsigned int llen,ctype_num,i;
+ unsigned int llen, ctype_num,i;
X509_NAME *xn=NULL;
const unsigned char *p,*q;
unsigned char *d;
if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE)
{
s->s3->tmp.reuse_message=1;
+ /* If we get here we don't need any cached handshake records
+ * as we wont be doing client auth.
+ */
+ if (s->s3->handshake_buffer)
+ {
+ if (!ssl3_digest_cached_records(s))
+ goto err;
+ }
return(1);
}
for (i=0; i<ctype_num; i++)
s->s3->tmp.ctype[i]= p[i];
p+=ctype_num;
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ n2s(p, llen);
+ /* Check we have enough room for signature algorithms and
+ * following length value.
+ */
+ if ((unsigned long)(p - d + llen + 2) > n)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_DATA_LENGTH_TOO_LONG);
+ goto err;
+ }
+ if ((llen & 1) || !tls1_process_sigalgs(s, p, llen))
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_SIGNATURE_ALGORITHMS_ERROR);
+ goto err;
+ }
+ p += llen;
+ }
/* get the CA RDNs */
n2s(p,llen);
}
#endif
- if ((llen+ctype_num+2+1) != n)
+ if ((unsigned long)(p - d + llen) != n)
{
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR);
SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST,SSL_R_LENGTH_MISMATCH);
{
return(X509_NAME_cmp(*a,*b));
}
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_get_new_session_ticket(SSL *s)
+ {
+ int ok,al,ret=0, ticklen;
+ long n;
+ const unsigned char *p;
+ unsigned char *d;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_SESSION_TICKET_A,
+ SSL3_ST_CR_SESSION_TICKET_B,
+ -1,
+ 16384,
+ &ok);
+
+ if (!ok)
+ return((int)n);
+
+ if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
+ {
+ s->s3->tmp.reuse_message=1;
+ return(1);
+ }
+ if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET)
+ {
+ al=SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_BAD_MESSAGE_TYPE);
+ goto f_err;
+ }
+ if (n < 6)
+ {
+ /* need at least ticket_lifetime_hint + ticket length */
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+
+ p=d=(unsigned char *)s->init_msg;
+ n2l(p, s->session->tlsext_tick_lifetime_hint);
+ n2s(p, ticklen);
+ /* ticket_lifetime_hint + ticket_length + ticket */
+ if (ticklen + 6 != n)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (s->session->tlsext_tick)
+ {
+ OPENSSL_free(s->session->tlsext_tick);
+ s->session->tlsext_ticklen = 0;
+ }
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memcpy(s->session->tlsext_tick, p, ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ /* There are two ways to detect a resumed ticket sesion.
+ * One is to set an appropriate session ID and then the server
+ * must return a match in ServerHello. This allows the normal
+ * client session ID matching to work and we know much
+ * earlier that the ticket has been accepted.
+ *
+ * The other way is to set zero length session ID when the
+ * ticket is presented and rely on the handshake to determine
+ * session resumption.
+ *
+ * We choose the former approach because this fits in with
+ * assumptions elsewhere in OpenSSL. The session ID is set
+ * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the
+ * ticket.
+ */
+ EVP_Digest(p, ticklen,
+ s->session->session_id, &s->session->session_id_length,
+#ifndef OPENSSL_NO_SHA256
+ EVP_sha256(), NULL);
+#else
+ EVP_sha1(), NULL);
+#endif
+ ret=1;
+ return(ret);
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+err:
+ return(-1);
+ }
+
+int ssl3_get_cert_status(SSL *s)
+ {
+ int ok, al;
+ unsigned long resplen,n;
+ const unsigned char *p;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_STATUS_A,
+ SSL3_ST_CR_CERT_STATUS_B,
+ SSL3_MT_CERTIFICATE_STATUS,
+ 16384,
+ &ok);
+
+ if (!ok) return((int)n);
+ if (n < 4)
+ {
+ /* need at least status type + length */
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ p = (unsigned char *)s->init_msg;
+ if (*p++ != TLSEXT_STATUSTYPE_ocsp)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_UNSUPPORTED_STATUS_TYPE);
+ goto f_err;
+ }
+ n2l3(p, resplen);
+ if (resplen + 4 != n)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ if (s->tlsext_ocsp_resp)
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
+ if (!s->tlsext_ocsp_resp)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ s->tlsext_ocsp_resplen = resplen;
+ if (s->ctx->tlsext_status_cb)
+ {
+ int ret;
+ ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (ret == 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,SSL_R_INVALID_STATUS_RESPONSE);
+ goto f_err;
+ }
+ if (ret < 0)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_STATUS,ERR_R_MALLOC_FAILURE);
+ goto f_err;
+ }
+ }
+ return 1;
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return(-1);
+ }
+#endif
int ssl3_get_server_done(SSL *s)
{
krb5_data *enc_ticket;
krb5_data authenticator, *authp = NULL;
EVP_CIPHER_CTX ciph_ctx;
- EVP_CIPHER *enc = NULL;
+ const EVP_CIPHER *enc = NULL;
unsigned char iv[EVP_MAX_IV_LENGTH];
unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH
#ifdef KSSL_DEBUG
printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
- l, SSL_kKRB5);
+ alg_k, SSL_kKRB5);
#endif /* KSSL_DEBUG */
authp = NULL;
sizeof tmp_buf);
EVP_EncryptFinal_ex(&ciph_ctx,&(epms[outl]),&padl);
outl += padl;
- if (outl > sizeof epms)
+ if (outl > (int)sizeof epms)
{
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
goto err;
{
DH *dh_srvr,*dh_clnt;
+ if (s->session->sess_cert == 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;
else
if (!DH_generate_key(dh_clnt))
{
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ DH_free(dh_clnt);
goto err;
}
if (n <= 0)
{
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ DH_free(dh_clnt);
goto err;
}
EVP_PKEY_free(srvr_pub_pkey);
}
#endif /* !OPENSSL_NO_ECDH */
+ else if (alg_k & SSL_kGOST)
+ {
+ /* GOST key exchange message creation */
+ EVP_PKEY_CTX *pkey_ctx;
+ X509 *peer_cert;
+ size_t msglen;
+ unsigned int md_len;
+ int keytype;
+ unsigned char premaster_secret[32],shared_ukm[32], tmp[256];
+ EVP_MD_CTX *ukm_hash;
+ EVP_PKEY *pub_key;
+
+ /* Get server sertificate PKEY and create ctx from it */
+ peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST01)].x509;
+ if (!peer_cert)
+ peer_cert=s->session->sess_cert->peer_pkeys[(keytype=SSL_PKEY_GOST94)].x509;
+ if (!peer_cert) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+ goto err;
+ }
+
+ pkey_ctx=EVP_PKEY_CTX_new(pub_key=X509_get_pubkey(peer_cert),NULL);
+ /* If we have send a certificate, and certificate key
+
+ * parameters match those of server certificate, use
+ * certificate key for key exchange
+ */
+
+ /* Otherwise, generate ephemeral key pair */
+
+ EVP_PKEY_encrypt_init(pkey_ctx);
+ /* Generate session key */
+ RAND_bytes(premaster_secret,32);
+ /* If we have client certificate, use its secret as peer key */
+ if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
+ if (EVP_PKEY_derive_set_peer(pkey_ctx,s->cert->key->privatekey) <=0) {
+ /* If there was an error - just ignore it. Ephemeral key
+ * would be used
+ */
+ ERR_clear_error();
+ }
+ }
+ /* Compute shared IV and store it in algorithm-specific
+ * context data */
+ ukm_hash = EVP_MD_CTX_create();
+ EVP_DigestInit(ukm_hash,EVP_get_digestbynid(NID_id_GostR3411_94));
+ EVP_DigestUpdate(ukm_hash,s->s3->client_random,SSL3_RANDOM_SIZE);
+ EVP_DigestUpdate(ukm_hash,s->s3->server_random,SSL3_RANDOM_SIZE);
+ EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len);
+ EVP_MD_CTX_destroy(ukm_hash);
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx,-1,EVP_PKEY_OP_ENCRYPT,EVP_PKEY_CTRL_SET_IV,
+ 8,shared_ukm)<0) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+ /* Make GOST keytransport blob message */
+ /*Encapsulate it into sequence */
+ *(p++)=V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
+ msglen=255;
+ if (EVP_PKEY_encrypt(pkey_ctx,tmp,&msglen,premaster_secret,32)<0) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+ if (msglen >= 0x80)
+ {
+ *(p++)=0x81;
+ *(p++)= msglen & 0xff;
+ n=msglen+3;
+ }
+ else
+ {
+ *(p++)= msglen & 0xff;
+ n=msglen+2;
+ }
+ memcpy(p, tmp, msglen);
+ /* Check if pubkey from client certificate was used */
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+ {
+ /* Set flag "skip certificate verify" */
+ s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+ }
+ EVP_PKEY_CTX_free(pkey_ctx);
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,premaster_secret,32);
+ EVP_PKEY_free(pub_key);
+
+ }
+#ifndef OPENSSL_NO_SRP
+ else if (alg_k & SSL_kSRP)
+ {
+ if (s->srp_ctx.A != NULL)
+ {
+ /* send off the data */
+ n=BN_num_bytes(s->srp_ctx.A);
+ s2n(n,p);
+ BN_bn2bin(s->srp_ctx.A,p);
+ n+=2;
+ }
+ else
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if (s->session->srp_username != NULL)
+ OPENSSL_free(s->session->srp_username);
+ s->session->srp_username = BUF_strdup(s->srp_ctx.login);
+ if (s->session->srp_username == NULL)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if ((s->session->master_key_length = SRP_generate_client_master_secret(s,s->session->master_key))<0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+#endif
#ifndef OPENSSL_NO_PSK
else if (alg_k & SSL_kPSK)
{
unsigned char *p,*d;
unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH];
EVP_PKEY *pkey;
-#ifndef OPENSSL_NO_RSA
+ EVP_PKEY_CTX *pctx=NULL;
+ EVP_MD_CTX mctx;
unsigned u=0;
-#endif
unsigned long n;
-#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA)
int j;
-#endif
+
+ EVP_MD_CTX_init(&mctx);
if (s->state == SSL3_ST_CW_CERT_VRFY_A)
{
d=(unsigned char *)s->init_buf->data;
p= &(d[4]);
pkey=s->cert->key->privatekey;
-
- s->method->ssl3_enc->cert_verify_mac(s,&(s->s3->finish_dgst2),
- &(data[MD5_DIGEST_LENGTH]));
-
+/* Create context from key and test if sha1 is allowed as digest */
+ pctx = EVP_PKEY_CTX_new(pkey,NULL);
+ EVP_PKEY_sign_init(pctx);
+ if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0)
+ {
+ if (TLS1_get_version(s) < TLS1_2_VERSION)
+ s->method->ssl3_enc->cert_verify_mac(s,
+ NID_sha1,
+ &(data[MD5_DIGEST_LENGTH]));
+ }
+ else
+ {
+ ERR_clear_error();
+ }
+ /* For TLS v1.2 send signature algorithm and signature
+ * using agreed digest and cached handshake records.
+ */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ {
+ long hdatalen = 0;
+ void *hdata;
+ const EVP_MD *md = s->cert->key->digest;
+ hdatalen = BIO_get_mem_data(s->s3->handshake_buffer,
+ &hdata);
+ if (hdatalen <= 0 || !tls12_get_sigandhash(p, pkey, md))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ p += 2;
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Using TLS 1.2 with client alg %s\n",
+ EVP_MD_name(md));
+#endif
+ if (!EVP_SignInit_ex(&mctx, md, NULL)
+ || !EVP_SignUpdate(&mctx, hdata, hdatalen)
+ || !EVP_SignFinal(&mctx, p + 2, &u, pkey))
+ {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_EVP_LIB);
+ goto err;
+ }
+ s2n(u,p);
+ n = u + 4;
+ if (!ssl3_digest_cached_records(s))
+ goto err;
+ }
+ else
#ifndef OPENSSL_NO_RSA
if (pkey->type == EVP_PKEY_RSA)
{
s->method->ssl3_enc->cert_verify_mac(s,
- &(s->s3->finish_dgst1),&(data[0]));
+ NID_md5,
+ &(data[0]));
if (RSA_sign(NID_md5_sha1, data,
MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
&(p[2]), &u, pkey->pkey.rsa) <= 0 )
}
else
#endif
- {
+ if (pkey->type == NID_id_GostR3410_94 || pkey->type == NID_id_GostR3410_2001)
+ {
+ unsigned char signbuf[64];
+ int i;
+ size_t sigsize=64;
+ s->method->ssl3_enc->cert_verify_mac(s,
+ NID_id_GostR3411_94,
+ data);
+ if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ for (i=63,j=0; i>=0; j++, i--) {
+ p[2+j]=signbuf[i];
+ }
+ s2n(j,p);
+ n=j+2;
+ }
+ else
+ {
SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR);
goto err;
- }
+ }
*(d++)=SSL3_MT_CERTIFICATE_VERIFY;
l2n3(n,d);
s->init_num=(int)n+4;
s->init_off=0;
}
+ EVP_MD_CTX_cleanup(&mctx);
+ EVP_PKEY_CTX_free(pctx);
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
err:
+ EVP_MD_CTX_cleanup(&mctx);
+ EVP_PKEY_CTX_free(pctx);
return(-1);
}
* ssl->rwstate=SSL_X509_LOOKUP; return(-1);
* We then get retied later */
i=0;
- if (s->ctx->client_cert_cb != NULL)
- i=s->ctx->client_cert_cb(s,&(x509),&(pkey));
+ i = ssl_do_client_cert_cb(s, &x509, &pkey);
if (i < 0)
{
s->rwstate=SSL_X509_LOOKUP;
DH *dh;
#endif
- sc=s->session->sess_cert;
- if (sc == NULL)
- {
- SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,ERR_R_INTERNAL_ERROR);
- goto err;
- }
-
alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
alg_a=s->s3->tmp.new_cipher->algorithm_auth;
if ((alg_a & (SSL_aDH|SSL_aNULL|SSL_aKRB5)) || (alg_k & SSL_kPSK))
return(1);
+ sc=s->session->sess_cert;
+ if (sc == NULL)
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
#ifndef OPENSSL_NO_RSA
rsa=s->session->sess_cert->peer_rsa_tmp;
#endif
if (idx == SSL_PKEY_ECC)
{
if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509,
- s->s3->tmp.new_cipher) == 0)
+ s) == 0)
{ /* check failed */
SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_BAD_ECC_CERT);
goto f_err;
err:
return(0);
}
+
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+int ssl3_send_next_proto(SSL *s)
+ {
+ unsigned int len, padding_len;
+ unsigned char *d;
+
+ if (s->state == SSL3_ST_CW_NEXT_PROTO_A)
+ {
+ len = s->next_proto_negotiated_len;
+ padding_len = 32 - ((len + 2) % 32);
+ d = (unsigned char *)s->init_buf->data;
+ d[4] = len;
+ memcpy(d + 5, s->next_proto_negotiated, len);
+ d[5 + len] = padding_len;
+ memset(d + 6 + len, 0, padding_len);
+ *(d++)=SSL3_MT_NEXT_PROTO;
+ l2n3(2 + len + padding_len, d);
+ s->state = SSL3_ST_CW_NEXT_PROTO_B;
+ s->init_num = 4 + 2 + len + padding_len;
+ s->init_off = 0;
+ }
+
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+}
+#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */
+
+/* Check to see if handshake is full or resumed. Usually this is just a
+ * case of checking to see if a cache hit has occurred. In the case of
+ * session tickets we have to check the next message to be sure.
+ */
+
+#ifndef OPENSSL_NO_TLSEXT
+int ssl3_check_finished(SSL *s)
+ {
+ int ok;
+ long n;
+ /* If we have no ticket it cannot be a resumed session. */
+ if (!s->session->tlsext_tick)
+ return 1;
+ /* this function is called when we really expect a Certificate
+ * message, so permit appropriate message length */
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_A,
+ SSL3_ST_CR_CERT_B,
+ -1,
+ s->max_cert_list,
+ &ok);
+ if (!ok) return((int)n);
+ s->s3->tmp.reuse_message = 1;
+ if ((s->s3->tmp.message_type == SSL3_MT_FINISHED)
+ || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET))
+ return 2;
+
+ return 1;
+ }
+#endif
+
+int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey)
+ {
+ int i = 0;
+#ifndef OPENSSL_NO_ENGINE
+ if (s->ctx->client_cert_engine)
+ {
+ i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s,
+ SSL_get_client_CA_list(s),
+ px509, ppkey, NULL, NULL, NULL);
+ if (i != 0)
+ return i;
+ }
+#endif
+ if (s->ctx->client_cert_cb)
+ i = s->ctx->client_cert_cb(s,px509,ppkey);
+ return i;
+ }