Adding support for sending early data on the client.
BUG=76
Change-Id: If58a73da38e46549fd55f84a9104e2dfebfda43f
Reviewed-on: https://boringssl-review.googlesource.com/14164
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index b3e397d..d936633 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -757,19 +757,23 @@
return -1;
}
- /* If necessary, complete the handshake implicitly. */
- if (!ssl_can_write(ssl)) {
- int ret = SSL_do_handshake(ssl);
- if (ret < 0) {
- return ret;
+ int ret = 0, needs_handshake = 0;
+ do {
+ /* If necessary, complete the handshake implicitly. */
+ if (!ssl_can_write(ssl)) {
+ ret = SSL_do_handshake(ssl);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return -1;
+ }
}
- if (ret == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_HANDSHAKE_FAILURE);
- return -1;
- }
- }
- return ssl->method->write_app_data(ssl, buf, num);
+ ret = ssl->method->write_app_data(ssl, &needs_handshake, buf, num);
+ } while (needs_handshake);
+ return ret;
}
int SSL_shutdown(SSL *ssl) {
@@ -842,10 +846,35 @@
ssl->cert->enable_early_data = !!enabled;
}
+int SSL_in_early_data(const SSL *ssl) {
+ if (ssl->s3->hs == NULL) {
+ return 0;
+ }
+ return ssl->s3->hs->in_early_data;
+}
+
int SSL_early_data_accepted(const SSL *ssl) {
return ssl->early_data_accepted;
}
+void SSL_reset_early_data_reject(SSL *ssl) {
+ SSL_HANDSHAKE *hs = ssl->s3->hs;
+ if (hs == NULL ||
+ hs->wait != ssl_hs_early_data_rejected) {
+ abort();
+ }
+
+ hs->wait = ssl_hs_ok;
+ hs->in_early_data = 0;
+ SSL_SESSION_free(hs->early_session);
+ hs->early_session = NULL;
+
+ /* Discard any unfinished writes from the perspective of |SSL_write|'s
+ * retry. The handshake will transparently flush out the pending record
+ * (discarded by the server) to keep the framing correct. */
+ ssl->s3->wpend_pending = 0;
+}
+
static int bio_retry_reason_to_error(int reason) {
switch (reason) {
case BIO_RR_CONNECT:
@@ -938,6 +967,9 @@
case SSL_PENDING_TICKET:
return SSL_ERROR_PENDING_TICKET;
+
+ case SSL_EARLY_DATA_REJECTED:
+ return SSL_ERROR_EARLY_DATA_REJECTED;
}
return SSL_ERROR_SYSCALL;
@@ -1737,13 +1769,11 @@
void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **out_data,
unsigned *out_len) {
- *out_data = NULL;
- if (ssl->s3) {
- *out_data = ssl->s3->alpn_selected;
- }
- if (*out_data == NULL) {
- *out_len = 0;
+ if (SSL_in_early_data(ssl) && !ssl->server) {
+ *out_data = ssl->s3->hs->early_session->early_alpn;
+ *out_len = ssl->s3->hs->early_session->early_alpn_len;
} else {
+ *out_data = ssl->s3->alpn_selected;
*out_len = ssl->s3->alpn_selected_len;
}
}
@@ -1934,7 +1964,7 @@
}
int SSL_session_reused(const SSL *ssl) {
- return ssl->s3->session_reused;
+ return ssl->s3->session_reused || SSL_in_early_data(ssl);
}
const COMP_METHOD *SSL_get_current_compression(SSL *ssl) { return NULL; }