}
#ifndef OPENSSL_NO_SRP
-static int SSL_check_srp_ext_ClientHello(SSL *s, int *ad)
+static int ssl_check_srp_ext_ClientHello(SSL *s, int *al)
{
int ret = SSL_ERROR_NONE;
- *ad = SSL_AD_UNRECOGNIZED_NAME;
+ *al = SSL_AD_UNRECOGNIZED_NAME;
if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) &&
(s->srp_ctx.TLS_ext_srp_username_callback != NULL))
{
if(s->srp_ctx.login == NULL)
{
- /* There isn't any srp login extension !!! */
- ret = SSL3_AL_WARNING;
- *ad = SSL_AD_MISSING_SRP_USERNAME;
+ /* RFC 5054 says SHOULD reject,
+ we do so if There is no srp login name */
+ ret = SSL3_AL_FATAL;
+ *al = SSL_AD_UNKNOWN_PSK_IDENTITY;
}
else
{
- ret = SSL_srp_server_param_with_username(s,ad);
+ ret = SSL_srp_server_param_with_username(s,al);
}
}
return ret;
void (*cb)(const SSL *ssl,int type,int val)=NULL;
int ret= -1;
int new_state,state,skip=0;
-#ifndef OPENSSL_NO_SRP
- int srp_no_username=0;
- int extension_error,al;
-#endif
RAND_add(&Time,sizeof(Time),0);
ERR_clear_error();
return(-1);
}
+#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;
}
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)
{
case SSL3_ST_SR_CLNT_HELLO_A:
case SSL3_ST_SR_CLNT_HELLO_B:
case SSL3_ST_SR_CLNT_HELLO_C:
-#ifndef OPENSSL_NO_SRP
- case SSL3_ST_SR_CLNT_HELLO_SRP_USERNAME:
-#endif
s->shutdown=0;
ret=ssl3_get_client_hello(s);
if (ret <= 0) goto end;
#ifndef OPENSSL_NO_SRP
- extension_error = 0;
- if ((al = SSL_check_srp_ext_ClientHello(s,&extension_error)) != SSL_ERROR_NONE)
- {
- ssl3_send_alert(s,al,extension_error);
- if (extension_error == SSL_AD_MISSING_SRP_USERNAME)
+ s->state = SSL3_ST_SR_CLNT_HELLO_D;
+ case SSL3_ST_SR_CLNT_HELLO_D:
+ {
+ int al;
+ if ((ret = ssl_check_srp_ext_ClientHello(s,&al)) < 0)
{
- if (srp_no_username) goto end;
- ERR_clear_error();
- srp_no_username = 1;
- s->state=SSL3_ST_SR_CLNT_HELLO_SRP_USERNAME;
- if (cb != NULL) cb(s,SSL_CB_HANDSHAKE_START,1);
- if ((ret=BIO_flush(s->wbio)) <= 0) goto end;
- s->init_num=0;
- break;
+ /* callback indicates firther work to be done */
+ s->rwstate=SSL_X509_LOOKUP;
+ goto end;
}
- ret = -1;
- SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
- goto end;
+ if (ret != SSL_ERROR_NONE)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ /* This is not really an error but the only means to
+ for a client to detect whether srp is supported. */
+ if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY)
+ SSLerr(SSL_F_SSL3_ACCEPT,SSL_R_CLIENTHELLO_TLSEXT);
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ ret= -1;
+ goto end;
}
-#endif
+ }
+#endif
s->renegotiate = 2;
s->state=SSL3_ST_SW_SRVR_HELLO_A;
s->state=SSL3_ST_SW_CHANGE_A;
#endif
else
- s->state=SSL3_ST_SW_CERT_A;
- s->init_num=0;
+#ifndef OPENSSL_NO_TLSEXT
+ s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_A;
+#else
+ s->state = SSL3_ST_SW_CERT_A;
+#endif
+ s->init_num = 0;
+ break;
+
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_SW_SUPPLEMENTAL_DATA_A:
+ case SSL3_ST_SW_SUPPLEMENTAL_DATA_B:
+ ret = tls1_send_server_supplemental_data(s, &skip);
+ if (ret <= 0) goto end;
+
+ s->state = SSL3_ST_SW_CERT_A;
+ s->init_num = 0;
break;
+#endif
case SSL3_ST_SW_CERT_A:
case SSL3_ST_SW_CERT_B:
/* SRP: send ServerKeyExchange */
|| (alg_k & SSL_kSRP)
#endif
- || (alg_k & (SSL_kDHr|SSL_kDHd|SSL_kEDH))
+ || (alg_k & SSL_kEDH)
|| (alg_k & SSL_kEECDH)
|| ((alg_k & SSL_kRSA)
&& (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
skip=1;
s->s3->tmp.cert_request=0;
s->state=SSL3_ST_SW_SRVR_DONE_A;
+ if (s->s3->handshake_buffer)
+ if (!ssl3_digest_cached_records(s))
+ return -1;
}
else
{
s->state=s->s3->tmp.next_state;
break;
-
+#ifndef OPENSSL_NO_TLSEXT
+ case SSL3_ST_SR_SUPPLEMENTAL_DATA_A:
+ case SSL3_ST_SR_SUPPLEMENTAL_DATA_B:
+ ret=tls1_get_client_supplemental_data(s);
+ if (ret <= 0) goto end;
+ s->s3->tmp.next_state=SSL3_ST_SR_CERT_A;
+ s->state=SSL3_ST_SW_FLUSH;
+ s->init_num=0;
+ break;
+#endif
case SSL3_ST_SR_CERT_A:
case SSL3_ST_SR_CERT_B:
/* Check for second client hello (MS SGC) */
goto end;
if (ret == 2)
s->state = SSL3_ST_SR_CLNT_HELLO_C;
+#ifndef OPENSSL_NO_TLSEXT
+ else if (ret == 3)
+ s->state = SSL3_ST_SR_SUPPLEMENTAL_DATA_A;
+#endif
else {
if (s->s3->tmp.cert_request)
{
* the client uses its key from the certificate
* for key exchange.
*/
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
s->state=SSL3_ST_SR_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ s->state=SSL3_ST_SR_NEXT_PROTO_A;
+ else
+ s->state=SSL3_ST_SR_FINISHED_A;
+#endif
s->init_num = 0;
}
+ else if (SSL_USE_SIGALGS(s))
+ {
+ s->state=SSL3_ST_SR_CERT_VRFY_A;
+ s->init_num=0;
+ if (!s->session->peer)
+ break;
+ /* For sigalgs freeze the handshake buffer
+ * at this point and digest cached records.
+ */
+ if (!s->s3->handshake_buffer)
+ {
+ SSLerr(SSL_F_SSL3_ACCEPT,ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+ s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE;
+ if (!ssl3_digest_cached_records(s))
+ return -1;
+ }
else
{
int offset=0;
ret=ssl3_get_cert_verify(s);
if (ret <= 0) goto end;
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
s->state=SSL3_ST_SR_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ s->state=SSL3_ST_SR_NEXT_PROTO_A;
+ else
+ s->state=SSL3_ST_SR_FINISHED_A;
+#endif
s->init_num=0;
break;
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG)
+ case SSL3_ST_SR_NEXT_PROTO_A:
+ case SSL3_ST_SR_NEXT_PROTO_B:
+ ret=ssl3_get_next_proto(s);
+ if (ret <= 0) goto end;
+ s->init_num = 0;
+ s->state=SSL3_ST_SR_FINISHED_A;
+ break;
+#endif
+
case SSL3_ST_SR_FINISHED_A:
case SSL3_ST_SR_FINISHED_B:
ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A,
SSL3_ST_SR_FINISHED_B);
if (ret <= 0) goto end;
-#ifndef OPENSSL_NO_TLSEXT
- if (s->tlsext_ticket_expected)
- s->state=SSL3_ST_SW_SESSION_TICKET_A;
- else if (s->hit)
- s->state=SSL_ST_OK;
-#else
if (s->hit)
s->state=SSL_ST_OK;
+#ifndef OPENSSL_NO_TLSEXT
+ else if (s->tlsext_ticket_expected)
+ s->state=SSL3_ST_SW_SESSION_TICKET_A;
#endif
else
s->state=SSL3_ST_SW_CHANGE_A;
if (ret <= 0) goto end;
s->state=SSL3_ST_SW_FLUSH;
if (s->hit)
+ {
+#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG)
s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#else
+ if (s->s3->next_proto_neg_seen)
+ s->s3->tmp.next_state=SSL3_ST_SR_NEXT_PROTO_A;
+ else
+ s->s3->tmp.next_state=SSL3_ST_SR_FINISHED_A;
+#endif
+ }
else
s->s3->tmp.next_state=SSL_ST_OK;
s->init_num=0;
if (s->renegotiate == 2) /* skipped if we just sent a HelloRequest */
{
- /* actually not necessarily a 'new' session unless
- * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
-
s->renegotiate=0;
s->new_session=0;
int ssl3_send_hello_request(SSL *s)
{
- unsigned char *p;
if (s->state == SSL3_ST_SW_HELLO_REQ_A)
{
- p=(unsigned char *)s->init_buf->data;
- *(p++)=SSL3_MT_HELLO_REQUEST;
- *(p++)=0;
- *(p++)=0;
- *(p++)=0;
-
+ ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0);
s->state=SSL3_ST_SW_HELLO_REQ_B;
- /* number of bytes to write */
- s->init_num=4;
- s->init_off=0;
}
/* SSL3_ST_SW_HELLO_REQ_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
}
int ssl3_check_client_hello(SSL *s)
&ok);
if (!ok) return((int)n);
s->s3->tmp.reuse_message = 1;
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->s3->tmp.message_type == SSL3_MT_SUPPLEMENTAL_DATA)
+ return 3;
+#endif
if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO)
{
+ /* We only allow the client to restart the handshake once per
+ * negotiation. */
+ if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE)
+ {
+ SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS);
+ return -1;
+ }
/* Throw away what we have done so far in the current handshake,
- * which will now be aborted. (A full SSL_clear would be too much.)
- * I hope that tmp.dh is the only thing that may need to be cleared
- * when a handshake is not completed ... */
+ * which will now be aborted. (A full SSL_clear would be too much.) */
#ifndef OPENSSL_NO_DH
if (s->s3->tmp.dh != NULL)
{
s->s3->tmp.dh = NULL;
}
#endif
+#ifndef OPENSSL_NO_ECDH
+ if (s->s3->tmp.ecdh != NULL)
+ {
+ EC_KEY_free(s->s3->tmp.ecdh);
+ s->s3->tmp.ecdh = NULL;
+ }
+#endif
+ s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE;
return 2;
}
return 1;
int ssl3_get_client_hello(SSL *s)
{
- int i,j,ok,al,ret= -1;
+ int i,j,ok,al=SSL_AD_INTERNAL_ERROR,ret= -1;
unsigned int cookie_len;
long n;
unsigned long id;
- unsigned char *p,*d,*q;
+ unsigned char *p,*d;
SSL_CIPHER *c;
#ifndef OPENSSL_NO_COMP
+ unsigned char *q;
SSL_COMP *comp=NULL;
#endif
STACK_OF(SSL_CIPHER) *ciphers=NULL;
+ if (s->state == SSL3_ST_SR_CLNT_HELLO_C)
+ goto retry_cert;
+
/* We do this so that we will respond with our native type.
* If we are TLSv1 and we get SSLv3, we will respond with TLSv1,
* This down switching should be handled by a different method.
* TLSv1.
*/
if (s->state == SSL3_ST_SR_CLNT_HELLO_A
-#ifndef OPENSSL_NO_SRP
- || (s->state == SSL3_ST_SR_CLNT_HELLO_SRP_USERNAME)
-#endif
)
{
s->state=SSL3_ST_SR_CLNT_HELLO_B;
s->client_version=(((int)p[0])<<8)|(int)p[1];
p+=2;
- if ((s->version == DTLS1_VERSION && s->client_version > s->version) ||
- (s->version != DTLS1_VERSION && s->client_version < s->version))
+ if (SSL_IS_DTLS(s) ? (s->client_version > s->version &&
+ s->method->version != DTLS_ANY_VERSION)
+ : (s->client_version < s->version))
{
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
- if ((s->client_version>>8) == SSL3_VERSION_MAJOR)
+ if ((s->client_version>>8) == SSL3_VERSION_MAJOR &&
+ !s->enc_write_ctx && !s->write_hash)
{
/* similar to ssl3_get_record, send alert using remote version number */
s->version = s->client_version;
j= *(p++);
s->hit=0;
- /* Versions before 0.9.7 always allow session reuse during renegotiation
- * (i.e. when s->new_session is true), option
- * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is new with 0.9.7.
- * Maybe this optional behaviour should always have been the default,
- * but we cannot safely change the default behaviour (or new applications
- * might be written that become totally unsecure when compiled with
- * an earlier library version)
+ /* Versions before 0.9.7 always allow clients to resume sessions in renegotiation.
+ * 0.9.7 and later allow this by default, but optionally ignore resumption requests
+ * with flag SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag rather
+ * than a change to default behavior so that applications relying on this for security
+ * won't even compile against older library versions).
+ *
+ * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() to request
+ * renegotiation but not a new session (s->new_session remains unset): for servers,
+ * this essentially just means that the SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ * setting will be ignored.
*/
if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)))
{
p+=j;
- if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER)
+ if (SSL_IS_DTLS(s))
{
/* cookie stuff */
cookie_len = *(p++);
SSL_R_COOKIE_MISMATCH);
goto f_err;
}
-
- ret = 2;
+ /* Set to -2 so if successful we return 2 */
+ ret = -2;
}
p += cookie_len;
+ if (s->method->version == DTLS_ANY_VERSION)
+ {
+ /* Select version to use */
+ if (s->client_version <= DTLS1_2_VERSION &&
+ !(s->options & SSL_OP_NO_DTLSv1_2))
+ {
+ s->version = DTLS1_2_VERSION;
+ s->method = DTLSv1_2_server_method();
+ }
+ else if (tls1_suiteb(s))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE);
+ s->version = s->client_version;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+ else if (s->client_version <= DTLS1_VERSION &&
+ !(s->options & SSL_OP_NO_DTLSv1))
+ {
+ s->version = DTLS1_VERSION;
+ s->method = DTLSv1_server_method();
+ }
+ else
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
+ s->version = s->client_version;
+ al = SSL_AD_PROTOCOL_VERSION;
+ goto f_err;
+ }
+ s->session->ssl_version = s->version;
+ }
}
n2s(p,i);
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_LENGTH_MISMATCH);
goto f_err;
}
+#ifndef OPENSSL_NO_COMP
q=p;
+#endif
for (j=0; j<i; j++)
{
if (p[j] == 0) break;
/* TLS extensions*/
if (s->version >= SSL3_VERSION)
{
- if (!ssl_parse_clienthello_tlsext(s,&p,d,n, &al))
+ if (!ssl_parse_clienthello_tlsext(s,&p,d,n))
{
- /* 'al' set by ssl_parse_clienthello_tlsext */
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT);
- goto f_err;
- }
- }
- if (ssl_check_clienthello_tlsext(s) <= 0) {
- SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
goto err;
+ }
}
/* Check if we want to use external pre-shared secret for this
* server_random before calling tls_session_secret_cb in order to allow
* SessionTicket processing to use it in key derivation. */
{
- unsigned long Time;
unsigned char *pos;
- Time=(unsigned long)time(NULL); /* Time */
pos=s->s3->server_random;
- l2n(Time,pos);
- if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
+ if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0)
{
- al=SSL_AD_INTERNAL_ERROR;
goto f_err;
}
}
/* Can't disable compression */
if (s->options & SSL_OP_NO_COMPRESSION)
{
- al=SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
goto f_err;
}
}
if (s->s3->tmp.new_compression == NULL)
{
- al=SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INVALID_COMPRESSION_ALGORITHM);
goto f_err;
}
*/
if (s->session->compress_meth != 0)
{
- al=SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_INCONSISTENT_COMPRESSION);
goto f_err;
}
goto f_err;
}
ciphers=NULL;
+ /* Let cert callback update server certificates if required */
+ retry_cert:
+ if (s->cert->cert_cb)
+ {
+ int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg);
+ if (rv == 0)
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CERT_CB_ERROR);
+ goto f_err;
+ }
+ if (rv < 0)
+ {
+ s->rwstate=SSL_X509_LOOKUP;
+ return -1;
+ }
+ s->rwstate = SSL_NOTHING;
+ }
c=ssl3_choose_cipher(s,s->session->ciphers,
SSL_get_ciphers(s));
s->s3->tmp.new_cipher=s->session->cipher;
}
- if (!ssl3_digest_cached_records(s))
- goto f_err;
+ if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER))
+ {
+ if (!ssl3_digest_cached_records(s))
+ goto f_err;
+ }
/* we now have the following setup.
* client_random
* s->tmp.new_cipher - the new cipher to use.
*/
- if (ret < 0) ret=1;
+ /* Handles TLS extensions that we couldn't check earlier */
+ if (s->version >= SSL3_VERSION)
+ {
+ if (ssl_check_clienthello_tlsext_late(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
+ }
+
+ if (ret < 0) ret=-ret;
if (0)
{
f_err:
}
err:
if (ciphers != NULL) sk_SSL_CIPHER_free(ciphers);
- return(ret);
+ return ret < 0 ? -1 : ret;
}
int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p,*d;
int i,sl;
+ int al = 0;
unsigned long l;
-#ifdef OPENSSL_NO_TLSEXT
- unsigned long Time;
-#endif
if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
{
buf=(unsigned char *)s->init_buf->data;
#ifdef OPENSSL_NO_TLSEXT
p=s->s3->server_random;
- /* Generate server_random if it was not needed previously */
- 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, 1, p, SSL3_RANDOM_SIZE) <= 0)
return -1;
#endif
/* Do the message type and length last */
- d=p= &(buf[4]);
+ d=p= ssl_handshake_start(s);
*(p++)=s->version>>8;
*(p++)=s->version&0xff;
memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
p+=SSL3_RANDOM_SIZE;
- /* now in theory we have 3 options to sending back the
- * session id. If it is a re-use, we send back the
- * old session-id, if it is a new session, we send
- * back the new session-id or we send back a 0 length
- * session-id if we want it to be single use.
- * Currently I will not implement the '0' length session-id
- * 12-Jan-98 - I'll now support the '0' length stuff.
- *
- * We also have an additional case where stateless session
- * resumption is successful: we always send back the old
- * session id. In this case s->hit is non zero: this can
- * only happen if stateless session resumption is succesful
- * if session caching is disabled so existing functionality
- * is unaffected.
+ /* There are several cases for the session ID to send
+ * back in the server hello:
+ * - For session reuse from the session cache,
+ * we send back the old session ID.
+ * - If stateless session reuse (using a session ticket)
+ * is successful, we send back the client's "session ID"
+ * (which doesn't actually identify the session).
+ * - If it is a new session, we send back the new
+ * session ID.
+ * - However, if we want the new session to be single-use,
+ * we send back a 0-length session ID.
+ * s->hit is non-zero in either case of session reuse,
+ * so the following won't overwrite an ID that we're supposed
+ * to send back.
*/
if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)
&& !s->hit)
SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT);
return -1;
}
- if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL)
+ if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, &al)) == NULL)
{
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR);
return -1;
}
#endif
/* do the header */
l=(p-d);
- d=buf;
- *(d++)=SSL3_MT_SERVER_HELLO;
- l2n3(l,d);
-
+ ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l);
s->state=SSL3_ST_SW_SRVR_HELLO_B;
- /* number of bytes to write */
- s->init_num=p-buf;
- s->init_off=0;
}
/* SSL3_ST_SW_SRVR_HELLO_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
}
int ssl3_send_server_done(SSL *s)
{
- unsigned char *p;
if (s->state == SSL3_ST_SW_SRVR_DONE_A)
{
- p=(unsigned char *)s->init_buf->data;
-
- /* do the header */
- *(p++)=SSL3_MT_SERVER_DONE;
- *(p++)=0;
- *(p++)=0;
- *(p++)=0;
-
- s->state=SSL3_ST_SW_SRVR_DONE_B;
- /* number of bytes to write */
- s->init_num=4;
- s->init_off=0;
+ ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0);
+ s->state = SSL3_ST_SW_SRVR_DONE_B;
}
/* SSL3_ST_SW_SRVR_DONE_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
}
int ssl3_send_server_key_exchange(SSL *s)
if (s->s3->tmp.dh != NULL)
{
- DH_free(dh);
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
goto err;
}
const EC_GROUP *group;
ecdhp=cert->ecdh_tmp;
- if ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL))
+ if (s->cert->ecdh_tmp_auto)
+ {
+ /* Get NID of appropriate shared curve */
+ int nid = tls1_shared_curve(s, -2);
+ if (nid != NID_undef)
+ ecdhp = EC_KEY_new_by_curve_name(nid);
+ }
+ else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb)
{
ecdhp=s->cert->ecdh_tmp_cb(s,
SSL_C_IS_EXPORT(s->s3->tmp.new_cipher),
if (s->s3->tmp.ecdh != NULL)
{
- EC_KEY_free(s->s3->tmp.ecdh);
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
goto err;
}
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
goto err;
}
- if (!EC_KEY_up_ref(ecdhp))
+ if (s->cert->ecdh_tmp_auto)
+ ecdh = ecdhp;
+ else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL)
{
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB);
goto err;
}
- ecdh = ecdhp;
s->s3->tmp.ecdh=ecdh;
if ((EC_KEY_get0_public_key(ecdh) == NULL) ||
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE);
goto f_err;
}
- for (i=0; r[i] != NULL && i<4; i++)
+ for (i=0; i < 4 && r[i] != NULL; i++)
{
nr[i]=BN_num_bytes(r[i]);
#ifndef OPENSSL_NO_SRP
kn=0;
}
- if (!BUF_MEM_grow_clean(buf,n+4+kn))
+ if (!BUF_MEM_grow_clean(buf,n+SSL_HM_HEADER_LENGTH(s)+kn))
{
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF);
goto err;
}
- d=(unsigned char *)s->init_buf->data;
- p= &(d[4]);
+ d = p = ssl_handshake_start(s);
- for (i=0; r[i] != NULL && i<4; i++)
+ for (i=0; i < 4 && r[i] != NULL; i++)
{
#ifndef OPENSSL_NO_SRP
if ((i == 2) && (type & SSL_kSRP))
/* n is the length of the params, they start at &(d[4])
* and p points to the space at the end. */
#ifndef OPENSSL_NO_RSA
- if (pkey->type == EVP_PKEY_RSA
- && s->version < TLS1_2_VERSION)
+ if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s))
{
q=md_buf;
j=0;
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);
EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_DigestUpdate(&md_ctx,&(d[4]),n);
+ EVP_DigestUpdate(&md_ctx,d,n);
EVP_DigestFinal_ex(&md_ctx,q,
(unsigned int *)&i);
q+=i;
#endif
if (md)
{
- /* For TLS1.2 and later send signature
- * algorithm */
- if (s->version >= TLS1_2_VERSION)
+ /* send signature algorithm */
+ if (SSL_USE_SIGALGS(s))
{
if (!tls12_get_sigandhash(p, pkey, md))
{
EVP_SignInit_ex(&md_ctx, md, NULL);
EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(d[4]),n);
+ EVP_SignUpdate(&md_ctx,d,n);
if (!EVP_SignFinal(&md_ctx,&(p[2]),
(unsigned int *)&i,pkey))
{
}
s2n(i,p);
n+=i+2;
- if (s->version >= TLS1_2_VERSION)
+ if (SSL_USE_SIGALGS(s))
n+= 2;
}
else
}
}
- *(d++)=SSL3_MT_SERVER_KEY_EXCHANGE;
- l2n3(n,d);
-
- /* we should now have things packed up, so lets send
- * it off */
- s->init_num=n+4;
- s->init_off=0;
+ ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n);
}
s->state = SSL3_ST_SW_KEY_EXCH_B;
EVP_MD_CTX_cleanup(&md_ctx);
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
f_err:
ssl3_send_alert(s,SSL3_AL_FATAL,al);
err:
{
buf=s->init_buf;
- d=p=(unsigned char *)&(buf->data[4]);
+ d=p=ssl_handshake_start(s);
/* get the list of acceptable cert types */
p++;
p+=n;
n++;
+ if (SSL_USE_SIGALGS(s))
+ {
+ const unsigned char *psigs;
+ nl = tls12_get_psigalgs(s, &psigs);
+ s2n(nl, p);
+ memcpy(p, psigs, nl);
+ p += nl;
+ n += nl + 2;
+ }
+
off=n;
p+=2;
n+=2;
{
name=sk_X509_NAME_value(sk,i);
j=i2d_X509_NAME(name,NULL);
- if (!BUF_MEM_grow_clean(buf,4+n+j+2))
+ if (!BUF_MEM_grow_clean(buf,SSL_HM_HEADER_LENGTH(s)+n+j+2))
{
SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB);
goto err;
}
- p=(unsigned char *)&(buf->data[4+n]);
+ p = ssl_handshake_start(s) + n;
if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
{
s2n(j,p);
}
}
/* else no CA names */
- p=(unsigned char *)&(buf->data[4+off]);
+ p = ssl_handshake_start(s) + off;
s2n(nl,p);
- d=(unsigned char *)buf->data;
- *(d++)=SSL3_MT_CERTIFICATE_REQUEST;
- l2n3(n,d);
-
- /* we should now have things packed up, so lets send
- * it off */
+ ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n);
- s->init_num=n+4;
- s->init_off=0;
#ifdef NETSCAPE_HANG_BUG
- p=(unsigned char *)s->init_buf->data + s->init_num;
-
- /* do the header */
- *(p++)=SSL3_MT_SERVER_DONE;
- *(p++)=0;
- *(p++)=0;
- *(p++)=0;
- s->init_num += 4;
+ if (!SSL_IS_DTLS(s))
+ {
+ p=(unsigned char *)s->init_buf->data + s->init_num;
+ /* do the header */
+ *(p++)=SSL3_MT_SERVER_DONE;
+ *(p++)=0;
+ *(p++)=0;
+ *(p++)=0;
+ s->init_num += 4;
+ }
#endif
s->state = SSL3_ST_SW_CERT_REQ_B;
}
/* SSL3_ST_SW_CERT_REQ_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
err:
return(-1);
}
#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;
#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);
+ else
+ i = 0;
+ if (n && n != i+2)
{
if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG))
{
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)
{
- if (s->s3->tmp.dh == NULL)
+ /* 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;
}
- 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);
if (i <= 0)
{
SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB);
+ BN_clear_free(pub);
goto err;
}
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
/* Get encoded point length */
i = *p;
p += 1;
+ if (n != 1 + i)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
if (EC_POINT_oct2point(group,
clnt_ecpoint, p, i, bn_ctx) == 0)
{
long n;
int type=0,i,j;
X509 *peer;
+ const EVP_MD *md = NULL;
+ EVP_MD_CTX mctx;
+ EVP_MD_CTX_init(&mctx);
n=s->method->ssl_get_message(s,
SSL3_ST_SR_CERT_VRFY_A,
SSL3_ST_SR_CERT_VRFY_B,
-1,
- 514, /* 514? */
+ 516, /* Enough for 4096 bit RSA key with TLS v1.2 */
&ok);
if (!ok) return((int)n);
if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY)
{
s->s3->tmp.reuse_message=1;
- if ((peer != NULL) && (type | EVP_PKT_SIGN))
+ if ((peer != NULL) && (type & EVP_PKT_SIGN))
{
al=SSL_AD_UNEXPECTED_MESSAGE;
SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_MISSING_VERIFY_MESSAGE);
}
else
{
+ if (SSL_USE_SIGALGS(s))
+ {
+ int rv = tls12_check_peer_sigalg(&md, s, p, pkey);
+ if (rv == -1)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ else if (rv == 0)
+ {
+ 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;
+ }
n2s(p,i);
n-=2;
if (i > n)
goto f_err;
}
+ if (SSL_USE_SIGALGS(s))
+ {
+ long hdatalen = 0;
+ void *hdata;
+ hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+ if (hdatalen <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+#ifdef SSL_DEBUG
+ fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n",
+ EVP_MD_name(md));
+#endif
+ if (!EVP_VerifyInit_ex(&mctx, md, NULL)
+ || !EVP_VerifyUpdate(&mctx, hdata, hdatalen))
+ {
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_EVP_LIB);
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+
+ if (EVP_VerifyFinal(&mctx, p , i, pkey) <= 0)
+ {
+ al=SSL_AD_DECRYPT_ERROR;
+ SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_BAD_SIGNATURE);
+ goto f_err;
+ }
+ }
+ else
#ifndef OPENSSL_NO_RSA
if (pkey->type == EVP_PKEY_RSA)
{
ssl3_send_alert(s,SSL3_AL_FATAL,al);
}
end:
+ if (s->s3->handshake_buffer)
+ {
+ BIO_free(s->s3->handshake_buffer);
+ s->s3->handshake_buffer = NULL;
+ s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
+ }
+ EVP_MD_CTX_cleanup(&mctx);
EVP_PKEY_free(pkey);
return(ret);
}
al=SSL_AD_HANDSHAKE_FAILURE;
goto f_err;
}
+ /* No client certificate so digest cached records */
+ if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
+ {
+ al=SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
}
else
{
if (i <= 0)
{
al=ssl_verify_alarm_type(s->verify_result);
- SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_NO_CERTIFICATE_RETURNED);
+ SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE,SSL_R_CERTIFICATE_VERIFY_FAILED);
goto f_err;
}
}
int ssl3_send_server_certificate(SSL *s)
{
- unsigned long l;
- X509 *x;
+ CERT_PKEY *cpk;
if (s->state == SSL3_ST_SW_CERT_A)
{
- x=ssl_get_server_send_cert(s);
- if (x == NULL)
+ cpk=ssl_get_server_send_pkey(s);
+ if (cpk == NULL)
{
/* VRS: allow null cert if auth == KRB5 */
if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) ||
}
}
- l=ssl3_output_cert_chain(s,x);
+ ssl3_output_cert_chain(s,cpk);
s->state=SSL3_ST_SW_CERT_B;
- s->init_num=(int)l;
- s->init_off=0;
}
/* SSL3_ST_SW_CERT_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
}
+
#ifndef OPENSSL_NO_TLSEXT
+/* send a new session ticket (not necessarily for a new session) */
int ssl3_send_newsession_ticket(SSL *s)
{
if (s->state == SSL3_ST_SW_SESSION_TICKET_A)
{
unsigned char *p, *senc, *macstart;
- int len, slen;
+ const unsigned char *const_p;
+ int len, slen_full, slen;
+ SSL_SESSION *sess;
unsigned int hlen;
EVP_CIPHER_CTX ctx;
HMAC_CTX hctx;
unsigned char key_name[16];
/* get session encoding length */
- slen = i2d_SSL_SESSION(s->session, NULL);
+ slen_full = i2d_SSL_SESSION(s->session, NULL);
/* Some length values are 16 bits, so forget it if session is
* too long
*/
- if (slen > 0xFF00)
+ if (slen_full > 0xFF00)
+ return -1;
+ senc = OPENSSL_malloc(slen_full);
+ if (!senc)
+ return -1;
+ p = senc;
+ i2d_SSL_SESSION(s->session, &p);
+
+ /* create a fresh copy (not shared with other threads) to clean up */
+ const_p = senc;
+ sess = d2i_SSL_SESSION(NULL, &const_p, slen_full);
+ if (sess == NULL)
+ {
+ OPENSSL_free(senc);
+ return -1;
+ }
+ sess->session_id_length = 0; /* ID is irrelevant for the ticket */
+
+ slen = i2d_SSL_SESSION(sess, NULL);
+ if (slen > slen_full) /* shouldn't ever happen */
+ {
+ OPENSSL_free(senc);
return -1;
+ }
+ p = senc;
+ i2d_SSL_SESSION(sess, &p);
+ SSL_SESSION_free(sess);
+
/* Grow buffer if need be: the length calculation is as
- * follows 1 (size of message name) + 3 (message length
- * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) +
+ * follows handshake_header_length +
+ * 4 (ticket lifetime hint) + 2 (ticket length) +
* 16 (key name) + max_iv_len (iv length) +
* session_length + max_enc_block_size (max encrypted session
* length) + max_md_size (HMAC).
*/
if (!BUF_MEM_grow(s->init_buf,
- 26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH +
- EVP_MAX_MD_SIZE + slen))
- return -1;
- senc = OPENSSL_malloc(slen);
- if (!senc)
+ SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH +
+ EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen))
return -1;
- p = senc;
- i2d_SSL_SESSION(s->session, &p);
-
- p=(unsigned char *)s->init_buf->data;
- /* do the header */
- *(p++)=SSL3_MT_NEWSESSION_TICKET;
- /* Skip message length for now */
- p += 3;
+ p = ssl_handshake_start(s);
EVP_CIPHER_CTX_init(&ctx);
HMAC_CTX_init(&hctx);
/* Initialize HMAC and cipher contexts. If callback present
tlsext_tick_md(), NULL);
memcpy(key_name, tctx->tlsext_tick_key_name, 16);
}
- l2n(s->session->tlsext_tick_lifetime_hint, p);
+
+ /* Ticket lifetime hint (advisory only):
+ * We leave this unspecified for resumed session (for simplicity),
+ * and guess that tickets for new sessions will live as long
+ * as their sessions. */
+ l2n(s->hit ? 0 : s->session->timeout, p);
+
/* Skip ticket length for now */
p += 2;
/* Output key name */
p += hlen;
/* Now write out lengths: p points to end of data written */
/* Total length */
- len = p - (unsigned char *)s->init_buf->data;
- p=(unsigned char *)s->init_buf->data + 1;
- l2n3(len - 4, p); /* Message length */
- p += 4;
- s2n(len - 10, p); /* Ticket length */
-
- /* number of bytes to write */
- s->init_num= len;
+ len = p - ssl_handshake_start(s);
+ ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len);
+ /* Skip ticket lifetime hint */
+ p = ssl_handshake_start(s) + 4;
+ s2n(len - 6, p);
s->state=SSL3_ST_SW_SESSION_TICKET_B;
- s->init_off=0;
OPENSSL_free(senc);
}
/* SSL3_ST_SW_SESSION_TICKET_B */
- return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ return ssl_do_write(s);
}
int ssl3_send_cert_status(SSL *s)
/* SSL3_ST_SW_CERT_STATUS_B */
return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
}
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+/* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It
+ * sets the next_proto member in s if found */
+int ssl3_get_next_proto(SSL *s)
+ {
+ int ok;
+ int proto_len, padding_len;
+ long n;
+ const unsigned char *p;
+
+ /* Clients cannot send a NextProtocol message if we didn't see the
+ * extension in their ClientHello */
+ if (!s->s3->next_proto_neg_seen)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION);
+ return -1;
+ }
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_NEXT_PROTO_A,
+ SSL3_ST_SR_NEXT_PROTO_B,
+ SSL3_MT_NEXT_PROTO,
+ 514, /* See the payload format below */
+ &ok);
+
+ if (!ok)
+ return((int)n);
+
+ /* s->state doesn't reflect whether ChangeCipherSpec has been received
+ * in this handshake, but s->s3->change_cipher_spec does (will be reset
+ * by ssl3_get_finished). */
+ if (!s->s3->change_cipher_spec)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS);
+ return -1;
+ }
+
+ if (n < 2)
+ return 0; /* The body must be > 1 bytes long */
+
+ p=(unsigned char *)s->init_msg;
+
+ /* The payload looks like:
+ * uint8 proto_len;
+ * uint8 proto[proto_len];
+ * uint8 padding_len;
+ * uint8 padding[padding_len];
+ */
+ proto_len = p[0];
+ if (proto_len + 2 > s->init_num)
+ return 0;
+ padding_len = p[proto_len + 1];
+ if (proto_len + padding_len + 2 != s->init_num)
+ return 0;
+
+ s->next_proto_negotiated = OPENSSL_malloc(proto_len);
+ if (!s->next_proto_negotiated)
+ {
+ SSLerr(SSL_F_SSL3_GET_NEXT_PROTO,ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memcpy(s->next_proto_negotiated, p + 1, proto_len);
+ s->next_proto_negotiated_len = proto_len;
+
+ return 1;
+ }
+# endif
+
+int tls1_send_server_supplemental_data(SSL *s, int *skip)
+ {
+ int al = 0;
+ if (s->ctx->srv_supp_data_records_count)
+ {
+ unsigned char *p = NULL;
+ unsigned char *size_loc = NULL;
+ srv_supp_data_record *record = NULL;
+ size_t length = 0;
+ size_t i = 0;
+
+ for (i = 0; i < s->ctx->srv_supp_data_records_count; i++)
+ {
+ const unsigned char *out = NULL;
+ unsigned short outlen = 0;
+ int cb_retval = 0;
+ record = &s->ctx->srv_supp_data_records[i];
+
+ /* NULL callback or -1 omits supp data entry */
+ if (!record->fn1)
+ continue;
+ cb_retval = record->fn1(s, record->supp_data_type,
+ &out, &outlen, &al, record->arg);
+ if (cb_retval == -1)
+ continue; /* skip this supp data entry */
+ if (cb_retval == 0)
+ {
+ SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+ goto f_err;
+ }
+ if (outlen == 0 || TLSEXT_MAXLEN_supplemental_data < outlen + 4 + length)
+ {
+ SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+ return 0;
+ }
+ /* write supp data entry...
+ * if first entry, write handshake message type
+ * jump back to write length at end */
+ if (length == 0)
+ {
+ /* 1 byte message type + 3 bytes for
+ * message length */
+ if (!BUF_MEM_grow_clean(s->init_buf, 4))
+ {
+ SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+ return 0;
+ }
+ p = (unsigned char *)s->init_buf->data;
+ *(p++) = SSL3_MT_SUPPLEMENTAL_DATA;
+ /* hold on to length field to update later */
+ size_loc = p;
+ /* skip over handshake length field (3
+ * bytes) and supp_data length field
+ * (3 bytes) */
+ p += 3 + 3;
+ length += 1 +3 +3;
+ }
+ /* 2 byte supp data type + 2 byte length + outlen */
+ if (!BUF_MEM_grow(s->init_buf, outlen + 4))
+ {
+ SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB);
+ return 0;
+ }
+ s2n(record->supp_data_type, p);
+ s2n(outlen, p);
+ memcpy(p, out, outlen);
+ /* update length to supp data type (2 bytes) +
+ * supp data length (2 bytes) + supp data */
+ length += (outlen + 4);
+ p += outlen;
+ }
+ if (length > 0)
+ {
+ /* write handshake length */
+ l2n3(length - 4, size_loc);
+ /* supp_data length */
+ l2n3(length - 7, size_loc);
+ s->state = SSL3_ST_SW_SUPPLEMENTAL_DATA_B;
+ s->init_num = length;
+ s->init_off = 0;
+
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+ }
+ }
+
+ /* no supp data message sent */
+ *skip = 1;
+ s->init_num = 0;
+ s->init_off = 0;
+ return 1;
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return 0;
+ }
+
+int tls1_get_client_supplemental_data(SSL *s)
+ {
+ int al = 0;
+ int cb_retval = 0;
+ int ok;
+ long n;
+ const unsigned char *p, *d;
+ unsigned short supp_data_entry_type = 0;
+ unsigned short supp_data_entry_len = 0;
+ unsigned long supp_data_len = 0;
+ size_t i = 0;
+
+ n=s->method->ssl_get_message(s,
+ SSL3_ST_SR_SUPPLEMENTAL_DATA_A,
+ SSL3_ST_SR_SUPPLEMENTAL_DATA_B,
+ SSL3_MT_SUPPLEMENTAL_DATA,
+ /* use default limit */
+ TLSEXT_MAXLEN_supplemental_data,
+ &ok);
+
+ if (!ok) return((int)n);
+
+ p = (unsigned char *)s->init_msg;
+ d = p;
+
+ /* The message cannot be empty */
+ if (n < 3)
+ {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS1_GET_CLIENT_SUPPLEMENTAL_DATA,SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+ n2l3(p, supp_data_len);
+ while (p<d+supp_data_len)
+ {
+ n2s(p, supp_data_entry_type);
+ n2s(p, supp_data_entry_len);
+ /* if there is a callback for this supp data type, send it */
+ for (i=0; i < s->ctx->srv_supp_data_records_count; i++)
+ {
+ if (s->ctx->srv_supp_data_records[i].supp_data_type == supp_data_entry_type && s->ctx->srv_supp_data_records[i].fn2)
+ {
+ cb_retval = s->ctx->srv_supp_data_records[i].fn2(s, supp_data_entry_type, p, supp_data_entry_len, &al, s->ctx->srv_supp_data_records[i].arg);
+ if (cb_retval == 0)
+ {
+ SSLerr(SSL_F_TLS1_GET_CLIENT_SUPPLEMENTAL_DATA, ERR_R_SSL_LIB);
+ goto f_err;
+ }
+ }
+ }
+ p+=supp_data_entry_len;
+ }
+ return 1;
+f_err:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+ }
#endif