Lift BIO above SSL_PROTOCOL_METHOD. This gets us closer to exposing BIO-free APIs. The next step is probably to make the experimental bssl::OpenRecord function call a split out core of ssl_read_impl. Change-Id: I4acebb43f708df8c52eb4e328da8ae3551362fb9 Reviewed-on: https://boringssl-review.googlesource.com/21865 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 2f5374b..8e06c49 100644 --- a/ssl/ssl_lib.cc +++ b/ssl/ssl_lib.cc
@@ -907,7 +907,7 @@ return 0; } -static int ssl_read_impl(SSL *ssl, void *buf, int num, int peek) { +static int ssl_read_impl(SSL *ssl, void *buf, int num, bool peek) { ssl_reset_error_state(ssl); if (ssl->do_handshake == NULL) { @@ -941,25 +941,48 @@ continue; // Loop again. We may have begun a new handshake. } - bool got_handshake = false; - int ret = ssl->method->read_app_data(ssl, &got_handshake, (uint8_t *)buf, - num, peek); - if (got_handshake) { - continue; // Loop again to process the handshake data. - } - if (ret > 0) { + if (ssl->s3->pending_app_data.empty()) { + 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)); + bool retry; + int bio_ret = ssl_handle_open_record(ssl, &retry, ret, consumed, alert); + if (bio_ret <= 0) { + return bio_ret; + } + if (retry) { + continue; + } ssl->s3->key_update_count = 0; } - return ret; + + if (num <= 0) { + return num; + } + + size_t todo = + std::min(ssl->s3->pending_app_data.size(), static_cast<size_t>(num)); + OPENSSL_memcpy(buf, ssl->s3->pending_app_data.data(), todo); + if (!peek) { + // TODO(davidben): In DTLS, should the rest of the record be discarded? + // DTLS is not a stream. See https://crbug.com/boringssl/65. + ssl->s3->pending_app_data = ssl->s3->pending_app_data.subspan(todo); + if (ssl->s3->pending_app_data.empty()) { + ssl_read_buffer_discard(ssl); + } + } + return static_cast<int>(todo); } } int SSL_read(SSL *ssl, void *buf, int num) { - return ssl_read_impl(ssl, buf, num, 0 /* consume bytes */); + return ssl_read_impl(ssl, buf, num, false /* consume bytes */); } int SSL_peek(SSL *ssl, void *buf, int num) { - return ssl_read_impl(ssl, buf, num, 1 /* peek */); + return ssl_read_impl(ssl, buf, num, true /* peek */); } int SSL_write(SSL *ssl, const void *buf, int num) { @@ -1033,8 +1056,19 @@ return -1; } } else if (ssl->s3->read_shutdown != ssl_shutdown_close_notify) { - // Wait for the peer's close_notify. - ssl->method->read_close_notify(ssl); + ssl->s3->pending_app_data = Span<uint8_t>(); + for (;;) { + uint8_t alert = SSL_AD_DECODE_ERROR; + size_t consumed = 0; + auto ret = ssl->method->open_close_notify(ssl, &consumed, &alert, + ssl_read_buffer(ssl)); + bool retry; + int bio_ret = ssl_handle_open_record(ssl, &retry, ret, consumed, alert); + if (bio_ret <= 0) { + break; + } + assert(retry); // open_close_notify never reports success. + } if (ssl->s3->read_shutdown != ssl_shutdown_close_notify) { return -1; } @@ -1467,10 +1501,7 @@ void SSL_set_read_ahead(SSL *ssl, int yes) { } int SSL_pending(const SSL *ssl) { - if (ssl->s3->rrec.type != SSL3_RT_APPLICATION_DATA) { - return 0; - } - return ssl->s3->rrec.length; + return static_cast<int>(ssl->s3->pending_app_data.size()); } // Fix this so it checks all the valid key/cert options