summaryrefslogtreecommitdiffstats
path: root/src/ssl/s3_srvr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl/s3_srvr.c')
-rw-r--r--src/ssl/s3_srvr.c231
1 files changed, 81 insertions, 150 deletions
diff --git a/src/ssl/s3_srvr.c b/src/ssl/s3_srvr.c
index 3cc3032..a72e17e 100644
--- a/src/ssl/s3_srvr.c
+++ b/src/ssl/s3_srvr.c
@@ -207,79 +207,11 @@ int ssl3_accept(SSL *s) {
state = s->state;
switch (s->state) {
- case SSL_ST_RENEGOTIATE:
- /* This state is the renegotiate entry point. It sends a HelloRequest
- * and nothing else. */
- s->renegotiate = 1;
-
- if (cb != NULL) {
- cb(s, SSL_CB_HANDSHAKE_START, 1);
- }
-
- if (s->init_buf == NULL) {
- buf = BUF_MEM_new();
- if (!buf || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
- ret = -1;
- goto end;
- }
- s->init_buf = buf;
- buf = NULL;
- }
- s->init_num = 0;
-
- if (!s->s3->send_connection_binding &&
- !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
- /* Server attempting to renegotiate with client that doesn't support
- * secure renegotiation. */
- OPENSSL_PUT_ERROR(SSL, ssl3_accept,
- SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- ret = -1;
- goto end;
- }
-
- s->state = SSL3_ST_SW_HELLO_REQ_A;
- break;
-
- case SSL3_ST_SW_HELLO_REQ_A:
- case SSL3_ST_SW_HELLO_REQ_B:
- s->shutdown = 0;
- ret = ssl3_send_hello_request(s);
- if (ret <= 0) {
- goto end;
- }
- s->s3->tmp.next_state = SSL3_ST_SW_HELLO_REQ_C;
- s->state = SSL3_ST_SW_FLUSH;
- s->init_num = 0;
-
- if (!ssl3_init_finished_mac(s)) {
- OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
- ret = -1;
- goto end;
- }
- break;
-
- case SSL3_ST_SW_HELLO_REQ_C:
- s->state = SSL_ST_OK;
- break;
-
case SSL_ST_ACCEPT:
- case SSL_ST_BEFORE | SSL_ST_ACCEPT:
- /* This state is the entry point for the handshake itself (initial and
- * renegotiation). */
if (cb != NULL) {
cb(s, SSL_CB_HANDSHAKE_START, 1);
}
- if ((s->version >> 8) != 3) {
- /* TODO(davidben): Some consumers clear |s->version| to break the
- * handshake in a callback. Remove this when they're using proper
- * APIs. */
- OPENSSL_PUT_ERROR(SSL, ssl3_accept, ERR_R_INTERNAL_ERROR);
- ret = -1;
- goto end;
- }
-
if (s->init_buf == NULL) {
buf = BUF_MEM_new();
if (!buf || !BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
@@ -337,7 +269,6 @@ int ssl3_accept(SSL *s) {
if (ret <= 0) {
goto end;
}
- s->renegotiate = 2;
s->state = SSL3_ST_SW_SRVR_HELLO_A;
s->init_num = 0;
break;
@@ -406,35 +337,16 @@ int ssl3_accept(SSL *s) {
case SSL3_ST_SW_CERT_REQ_A:
case SSL3_ST_SW_CERT_REQ_B:
- if (/* don't request cert unless asked for it: */
- !(s->verify_mode & SSL_VERIFY_PEER) ||
- /* Don't request a certificate if an obc was presented */
- ((s->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
- s->s3->tlsext_channel_id_valid) ||
- /* if SSL_VERIFY_CLIENT_ONCE is set,
- * don't request cert during re-negotiation: */
- ((s->session->peer != NULL) &&
- (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) ||
- /* With normal PSK Certificates and
- * Certificate Requests are omitted */
- (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) {
- /* no cert request */
- skip = 1;
- s->s3->tmp.cert_request = 0;
- s->state = SSL3_ST_SW_SRVR_DONE_A;
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- return -1;
- }
- } else {
- s->s3->tmp.cert_request = 1;
+ if (s->s3->tmp.cert_request) {
ret = ssl3_send_certificate_request(s);
if (ret <= 0) {
goto end;
}
- s->state = SSL3_ST_SW_SRVR_DONE_A;
- s->init_num = 0;
+ } else {
+ skip = 1;
}
+ s->state = SSL3_ST_SW_SRVR_DONE_A;
+ s->init_num = 0;
break;
case SSL3_ST_SW_SRVR_DONE_A:
@@ -640,16 +552,12 @@ int ssl3_accept(SSL *s) {
s->session->peer = NULL;
}
- if (s->renegotiate == 2) {
- /* skipped if we just sent a HelloRequest */
- s->renegotiate = 0;
- s->new_session = 0;
+ s->s3->initial_handshake_complete = 1;
- ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
+ ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
- if (cb != NULL) {
- cb(s, SSL_CB_HANDSHAKE_DONE, 1);
- }
+ if (cb != NULL) {
+ cb(s, SSL_CB_HANDSHAKE_DONE, 1);
}
ret = 1;
@@ -898,20 +806,8 @@ int ssl3_get_v2_client_hello(SSL *s) {
return 1;
}
-int ssl3_send_hello_request(SSL *s) {
- if (s->state == SSL3_ST_SW_HELLO_REQ_A) {
- if (!ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0)) {
- return -1;
- }
- s->state = SSL3_ST_SW_HELLO_REQ_B;
- }
-
- /* SSL3_ST_SW_HELLO_REQ_B */
- return ssl_do_write(s);
-}
-
int ssl3_get_client_hello(SSL *s) {
- int i, ok, al = SSL_AD_INTERNAL_ERROR, ret = -1;
+ int ok, al = SSL_AD_INTERNAL_ERROR, ret = -1;
long n;
const SSL_CIPHER *c;
STACK_OF(SSL_CIPHER) *ciphers = NULL;
@@ -1011,6 +907,11 @@ int ssl3_get_client_hello(SSL *s) {
}
}
+ /* Note: This codepath may run twice if |ssl_get_prev_session| completes
+ * asynchronously.
+ *
+ * TODO(davidben): Clean up the order of events around ClientHello
+ * processing. */
if (!s->s3->have_version) {
/* Select version to use */
uint16_t version = ssl3_get_mutual_version(s, client_version);
@@ -1034,41 +935,49 @@ int ssl3_get_client_hello(SSL *s) {
}
s->hit = 0;
- /* 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)) {
- if (!ssl_get_new_session(s, 1)) {
- goto err;
- }
- } else {
- i = ssl_get_prev_session(s, &early_ctx);
- if (i == PENDING_SESSION) {
- s->rwstate = SSL_PENDING_SESSION;
- goto err;
- } else if (i == -1) {
- goto err;
- }
+ int session_ret = ssl_get_prev_session(s, &early_ctx);
+ if (session_ret == PENDING_SESSION) {
+ s->rwstate = SSL_PENDING_SESSION;
+ goto err;
+ } else if (session_ret == -1) {
+ goto err;
+ }
- /* Only resume if the session's version matches the negotiated version:
- * most clients do not accept a mismatch. */
- if (i == 1 && s->version == s->session->ssl_version) {
- s->hit = 1;
- } else {
- /* No session was found or it was unacceptable. */
- if (!ssl_get_new_session(s, 1)) {
- goto err;
- }
+ /* The EMS state is needed when making the resumption decision, but
+ * extensions are not normally parsed until later. This detects the EMS
+ * extension for the resumption decision and it's checked against the result
+ * of the normal parse later in this function. */
+ const uint8_t *ems_data;
+ size_t ems_len;
+ int have_extended_master_secret =
+ s->version != SSL3_VERSION &&
+ SSL_early_callback_ctx_extension_get(&early_ctx,
+ TLSEXT_TYPE_extended_master_secret,
+ &ems_data, &ems_len) &&
+ ems_len == 0;
+
+ if (session_ret == 1) {
+ if (s->session->extended_master_secret &&
+ !have_extended_master_secret) {
+ /* A ClientHello without EMS that attempts to resume a session with EMS
+ * is fatal to the connection. */
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello,
+ SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+ goto f_err;
}
+
+ s->hit =
+ /* Only resume if the session's version matches the negotiated version:
+ * most clients do not accept a mismatch. */
+ s->version == s->session->ssl_version &&
+ /* If the client offers the EMS extension, but the previous session
+ * didn't use it, then negotiate a new session. */
+ have_extended_master_secret == s->session->extended_master_secret;
+ }
+
+ if (!s->hit && !ssl_get_new_session(s, 1)) {
+ goto err;
}
if (s->ctx->dos_protection_cb != NULL && s->ctx->dos_protection_cb(&early_ctx) == 0) {
@@ -1141,6 +1050,12 @@ int ssl3_get_client_hello(SSL *s) {
goto f_err;
}
+ if (have_extended_master_secret != s->s3->tmp.extended_master_secret) {
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_EMS_STATE_INCONSISTENT);
+ goto f_err;
+ }
+
/* Given ciphers and SSL_get_ciphers, we must pick a cipher */
if (!s->hit) {
if (ciphers == NULL) {
@@ -1171,12 +1086,27 @@ int ssl3_get_client_hello(SSL *s) {
goto f_err;
}
s->s3->tmp.new_cipher = c;
+
+ /* Determine whether to request a client certificate. */
+ s->s3->tmp.cert_request = !!(s->verify_mode & SSL_VERIFY_PEER);
+ /* Only request a certificate if Channel ID isn't negotiated. */
+ if ((s->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) &&
+ s->s3->tlsext_channel_id_valid) {
+ s->s3->tmp.cert_request = 0;
+ }
+ /* Plain PSK forbids Certificate and CertificateRequest. */
+ if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) {
+ s->s3->tmp.cert_request = 0;
+ }
} else {
/* Session-id reuse */
s->s3->tmp.new_cipher = s->session->cipher;
+ s->s3->tmp.cert_request = 0;
}
- if ((!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) &&
+ /* In TLS 1.2, client authentication requires hashing the handshake transcript
+ * under a different hash. Otherwise, release the handshake buffer. */
+ if ((!SSL_USE_SIGALGS(s) || !s->s3->tmp.cert_request) &&
!ssl3_digest_cached_records(s, free_handshake_buffer)) {
goto f_err;
}
@@ -1235,7 +1165,8 @@ int ssl3_send_server_hello(SSL *s) {
*(p++) = s->version & 0xff;
/* Random stuff */
- if (!ssl_fill_hello_random(s, 1, s->s3->server_random, SSL3_RANDOM_SIZE)) {
+ if (!ssl_fill_hello_random(s->s3->server_random, SSL3_RANDOM_SIZE,
+ 1 /* server */)) {
OPENSSL_PUT_ERROR(SSL, ssl3_send_server_hello, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -1268,7 +1199,7 @@ int ssl3_send_server_hello(SSL *s) {
p += sl;
/* put the cipher */
- s2n(ssl3_get_cipher_value(s->s3->tmp.new_cipher), p);
+ s2n(ssl_cipher_get_value(s->s3->tmp.new_cipher), p);
/* put the compression method */
*(p++) = 0;