Make all read errors idempotent.
Now that we've gotten everything, test this by just making bssl_shim run
all errors twice. The manual tests added to ssl_test.cc may now be
removed.
Bug: 206
Change-Id: Iefa0eae83ba59b476e6b6c6f0f921d5d1b72cbfb
Reviewed-on: https://boringssl-review.googlesource.com/21886
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
Reviewed-by: Steven Valdez <svaldez@google.com>
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index ee7406d..e3f8a88 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -212,6 +212,14 @@
ssl->s3->read_error = ERR_save_state();
}
+static bool check_read_error(const SSL *ssl) {
+ if (ssl->s3->read_shutdown == ssl_shutdown_error) {
+ ERR_restore_state(ssl->s3->read_error);
+ return false;
+ }
+ return true;
+}
+
int ssl_can_write(const SSL *ssl) {
return !SSL_in_init(ssl) || ssl->s3->hs->can_early_write;
}
@@ -220,6 +228,51 @@
return !SSL_in_init(ssl) || ssl->s3->hs->can_early_read;
}
+ssl_open_record_t ssl_open_handshake(SSL *ssl, size_t *out_consumed,
+ uint8_t *out_alert, Span<uint8_t> in) {
+ *out_consumed = 0;
+ if (!check_read_error(ssl)) {
+ *out_alert = 0;
+ return ssl_open_record_error;
+ }
+ auto ret = ssl->method->open_handshake(ssl, out_consumed, out_alert, in);
+ if (ret == ssl_open_record_error) {
+ ssl_set_read_error(ssl);
+ }
+ return ret;
+}
+
+ssl_open_record_t ssl_open_change_cipher_spec(SSL *ssl, size_t *out_consumed,
+ uint8_t *out_alert,
+ Span<uint8_t> in) {
+ *out_consumed = 0;
+ if (!check_read_error(ssl)) {
+ *out_alert = 0;
+ return ssl_open_record_error;
+ }
+ auto ret =
+ ssl->method->open_change_cipher_spec(ssl, out_consumed, out_alert, in);
+ if (ret == ssl_open_record_error) {
+ ssl_set_read_error(ssl);
+ }
+ return ret;
+}
+
+ssl_open_record_t ssl_open_app_data(SSL *ssl, Span<uint8_t> *out,
+ size_t *out_consumed, uint8_t *out_alert,
+ Span<uint8_t> in) {
+ *out_consumed = 0;
+ if (!check_read_error(ssl)) {
+ *out_alert = 0;
+ return ssl_open_record_error;
+ }
+ auto ret = ssl->method->open_app_data(ssl, out, out_consumed, out_alert, in);
+ if (ret == ssl_open_record_error) {
+ ssl_set_read_error(ssl);
+ }
+ return ret;
+}
+
void ssl_cipher_preference_list_free(
struct ssl_cipher_preference_list_st *cipher_list) {
if (cipher_list == NULL) {
@@ -916,6 +969,11 @@
return -1;
}
+ // Replay post-handshake message errors.
+ if (!check_read_error(ssl)) {
+ return -1;
+ }
+
while (ssl->s3->pending_app_data.empty()) {
// Complete the current handshake, if any. False Start will cause
// |SSL_do_handshake| to return mid-handshake, so this may require multiple
@@ -936,6 +994,7 @@
if (ssl->method->get_message(ssl, &msg)) {
// Handle the post-handshake message and try again.
if (!ssl_do_post_handshake(ssl, msg)) {
+ ssl_set_read_error(ssl);
return -1;
}
ssl->method->next_message(ssl);
@@ -944,9 +1003,8 @@
uint8_t alert = SSL_AD_DECODE_ERROR;
size_t consumed = 0;
- auto ret =
- ssl->method->open_app_data(ssl, &ssl->s3->pending_app_data, &consumed,
- &alert, ssl_read_buffer(ssl));
+ auto ret = ssl_open_app_data(ssl, &ssl->s3->pending_app_data, &consumed,
+ &alert, ssl_read_buffer(ssl));
bool retry;
int bio_ret = ssl_handle_open_record(ssl, &retry, ret, consumed, alert);
if (bio_ret <= 0) {