Convert ssl3_send_server_hello to CBB.
BUG=468889
Change-Id: I899d67addbff01c64175f47b19ca2b688626405b
Reviewed-on: https://boringssl-review.googlesource.com/6191
Reviewed-by: Adam Langley <alangley@gmail.com>
diff --git a/ssl/internal.h b/ssl/internal.h
index 7f13ebc..fe6ee24 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1123,7 +1123,7 @@
int ssl3_get_initial_bytes(SSL *s);
int ssl3_get_v2_client_hello(SSL *s);
int ssl3_get_client_hello(SSL *s);
-int ssl3_send_server_hello(SSL *s);
+int ssl3_send_server_hello(SSL *ssl);
int ssl3_send_server_key_exchange(SSL *s);
int ssl3_send_certificate_request(SSL *s);
int ssl3_send_server_done(SSL *s);
@@ -1214,8 +1214,7 @@
* length. (It does not include the record header.) */
int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len);
-uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf,
- uint8_t *const limit);
+int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out);
int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs);
int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs);
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 935edae..25ab802 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -944,8 +944,15 @@
session = NULL;
s->verify_result = s->session->verify_result;
- } else if (!ssl_get_new_session(s, 1)) {
- goto err;
+ } else {
+ if (!ssl_get_new_session(s, 1)) {
+ goto err;
+ }
+
+ /* Clear the session ID if we want the session to be single-use. */
+ if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
+ s->session->session_id_length = 0;
+ }
}
if (s->ctx->dos_protection_cb != NULL && s->ctx->dos_protection_cb(&early_ctx) == 0) {
@@ -1106,90 +1113,55 @@
return ret;
}
-int ssl3_send_server_hello(SSL *s) {
- uint8_t *buf;
- uint8_t *p, *d;
- int sl;
- unsigned long l;
-
- if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
- /* We only accept ChannelIDs on connections with ECDHE in order to avoid a
- * known attack while we fix ChannelID itself. */
- if (s->s3->tlsext_channel_id_valid &&
- (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kECDHE) == 0) {
- s->s3->tlsext_channel_id_valid = 0;
- }
-
- /* If this is a resumption and the original handshake didn't support
- * ChannelID then we didn't record the original handshake hashes in the
- * session and so cannot resume with ChannelIDs. */
- if (s->hit && s->session->original_handshake_hash_len == 0) {
- s->s3->tlsext_channel_id_valid = 0;
- }
-
- buf = (uint8_t *)s->init_buf->data;
- /* Do the message type and length last */
- d = p = ssl_handshake_start(s);
-
- *(p++) = s->version >> 8;
- *(p++) = s->version & 0xff;
-
- /* Random stuff */
- if (!ssl_fill_hello_random(s->s3->server_random, SSL3_RANDOM_SIZE,
- 1 /* server */)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
- p += SSL3_RANDOM_SIZE;
-
- /* 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) {
- s->session->session_id_length = 0;
- }
-
- sl = s->session->session_id_length;
- if (sl > (int)sizeof(s->session->session_id)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- *(p++) = sl;
- memcpy(p, s->session->session_id, sl);
- p += sl;
-
- /* put the cipher */
- s2n(ssl_cipher_get_value(s->s3->tmp.new_cipher), p);
-
- /* put the compression method */
- *(p++) = 0;
-
- p = ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH);
- if (p == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- /* do the header */
- l = (p - d);
- if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l)) {
- return -1;
- }
- s->state = SSL3_ST_SW_SRVR_HELLO_B;
+int ssl3_send_server_hello(SSL *ssl) {
+ if (ssl->state == SSL3_ST_SW_SRVR_HELLO_B) {
+ return ssl_do_write(ssl);
}
- /* SSL3_ST_SW_SRVR_HELLO_B */
- return ssl_do_write(s);
+ assert(ssl->state == SSL3_ST_SW_SRVR_HELLO_A);
+
+ /* We only accept ChannelIDs on connections with ECDHE in order to avoid a
+ * known attack while we fix ChannelID itself. */
+ if (ssl->s3->tlsext_channel_id_valid &&
+ (ssl->s3->tmp.new_cipher->algorithm_mkey & SSL_kECDHE) == 0) {
+ ssl->s3->tlsext_channel_id_valid = 0;
+ }
+
+ /* If this is a resumption and the original handshake didn't support
+ * ChannelID then we didn't record the original handshake hashes in the
+ * session and so cannot resume with ChannelIDs. */
+ if (ssl->hit && ssl->session->original_handshake_hash_len == 0) {
+ ssl->s3->tlsext_channel_id_valid = 0;
+ }
+
+ if (!ssl_fill_hello_random(ssl->s3->server_random, SSL3_RANDOM_SIZE,
+ 1 /* server */)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return -1;
+ }
+
+ CBB cbb, session_id;
+ size_t length;
+ CBB_zero(&cbb);
+ if (!CBB_init_fixed(&cbb, ssl_handshake_start(ssl),
+ ssl->init_buf->max - SSL_HM_HEADER_LENGTH(ssl)) ||
+ !CBB_add_u16(&cbb, ssl->version) ||
+ !CBB_add_bytes(&cbb, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_u8_length_prefixed(&cbb, &session_id) ||
+ !CBB_add_bytes(&session_id, ssl->session->session_id,
+ ssl->session->session_id_length) ||
+ !CBB_add_u16(&cbb, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
+ !CBB_add_u8(&cbb, 0 /* no compression */) ||
+ !ssl_add_serverhello_tlsext(ssl, &cbb) ||
+ !CBB_finish(&cbb, NULL, &length) ||
+ !ssl_set_handshake_header(ssl, SSL3_MT_SERVER_HELLO, length)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ CBB_cleanup(&cbb);
+ return -1;
+ }
+
+ ssl->state = SSL3_ST_SW_SRVR_HELLO_B;
+ return ssl_do_write(ssl);
}
int ssl3_send_certificate_status(SSL *ssl) {
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index b521d06..c133e51 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -2311,53 +2311,44 @@
return 0;
}
-uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf,
- uint8_t *const limit) {
- CBB cbb, extensions;
- CBB_zero(&cbb);
- if (!CBB_init_fixed(&cbb, buf, limit - buf) ||
- !CBB_add_u16_length_prefixed(&cbb, &extensions)) {
+int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out) {
+ const size_t orig_len = CBB_len(out);
+
+ CBB extensions;
+ if (!CBB_add_u16_length_prefixed(out, &extensions)) {
goto err;
}
unsigned i;
for (i = 0; i < kNumExtensions; i++) {
- if (!(s->s3->tmp.extensions.received & (1u << i))) {
+ if (!(ssl->s3->tmp.extensions.received & (1u << i))) {
/* Don't send extensions that were not received. */
continue;
}
- if (!kExtensions[i].add_serverhello(s, &extensions)) {
+ if (!kExtensions[i].add_serverhello(ssl, &extensions)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
goto err;
}
}
- if (!custom_ext_add_serverhello(s, &extensions)) {
+ if (!custom_ext_add_serverhello(ssl, &extensions)) {
goto err;
}
- if (!CBB_flush(&cbb)) {
- goto err;
- }
-
- uint8_t *ret = buf;
- const size_t cbb_len = CBB_len(&cbb);
/* If only two bytes have been written then the extensions are actually empty
* and those two bytes are the zero length. In that case, we don't bother
* sending the extensions length. */
- if (cbb_len > 2) {
- ret += cbb_len;
+ if (CBB_len(&extensions) - orig_len == 2) {
+ CBB_discard_child(out);
}
- CBB_cleanup(&cbb);
- return ret;
+ return CBB_flush(out);
err:
- CBB_cleanup(&cbb);
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return NULL;
+ return 0;
}
static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {