aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@google.com>2021-11-12 14:43:21 -0500
committerBoringssl LUCI CQ <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>2021-11-18 21:08:27 +0000
commitb3ed071ecc4efb77afd0a025ea1078da19578bfd (patch)
treebb3f097f6dc76593ce2200bbaa86e7ce95ef9ed6
parentea57bcbd66ffc13b5ebad2767412e35931aa17ff (diff)
downloadboringssl-b3ed071ecc4efb77afd0a025ea1078da19578bfd.zip
boringssl-b3ed071ecc4efb77afd0a025ea1078da19578bfd.tar.gz
boringssl-b3ed071ecc4efb77afd0a025ea1078da19578bfd.tar.bz2
Add SSL_has_pending.
This was added in OpenSSL 1.1.x. It is slightly different from SSL_pending in that it also reports buffered transport data. Change-Id: I81e217aad1ceb6f4c31c36634a546e12b6dc8dfc Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/50445 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com>
-rw-r--r--include/openssl/ssl.h25
-rw-r--r--ssl/ssl_lib.cc4
-rw-r--r--ssl/ssl_test.cc20
3 files changed, 47 insertions, 2 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 057fbc0..ca7ae14 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -362,10 +362,31 @@ OPENSSL_EXPORT int SSL_read(SSL *ssl, void *buf, int num);
// SSL_peek behaves like |SSL_read| but does not consume any bytes returned.
OPENSSL_EXPORT int SSL_peek(SSL *ssl, void *buf, int num);
-// SSL_pending returns the number of bytes available in |ssl|. It does not read
-// from the transport.
+// SSL_pending returns the number of buffered, decrypted bytes available for
+// read in |ssl|. It does not read from the transport.
+//
+// In DTLS, it is possible for this function to return zero while there is
+// buffered, undecrypted data from the transport in |ssl|. For example,
+// |SSL_read| may read a datagram with two records, decrypt the first, and leave
+// the second buffered for a subsequent call to |SSL_read|. Callers that wish to
+// detect this case can use |SSL_has_pending|.
OPENSSL_EXPORT int SSL_pending(const SSL *ssl);
+// SSL_has_pending returns one if |ssl| has buffered, decrypted bytes available
+// for read, or if |ssl| has buffered data from the transport that has not yet
+// been decrypted. If |ssl| has neither, this function returns zero.
+//
+// In TLS, BoringSSL does not implement read-ahead, so this function returns one
+// if and only if |SSL_pending| would return a non-zero value. In DTLS, it is
+// possible for this function to return one while |SSL_pending| returns zero.
+// For example, |SSL_read| may read a datagram with two records, decrypt the
+// first, and leave the second buffered for a subsequent call to |SSL_read|.
+//
+// As a result, if this function returns one, the next call to |SSL_read| may
+// still fail, read from the transport, or both. The buffered, undecrypted data
+// may be invalid or incomplete.
+OPENSSL_EXPORT int SSL_has_pending(const SSL *ssl);
+
// SSL_write writes up to |num| bytes from |buf| into |ssl|. It implicitly runs
// any pending handshakes, including renegotiations when enabled. On success, it
// returns the number of bytes written. Otherwise, it returns <= 0. The caller
diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
index 03864e1..e2e2436 100644
--- a/ssl/ssl_lib.cc
+++ b/ssl/ssl_lib.cc
@@ -1697,6 +1697,10 @@ int SSL_pending(const SSL *ssl) {
return static_cast<int>(ssl->s3->pending_app_data.size());
}
+int SSL_has_pending(const SSL *ssl) {
+ return SSL_pending(ssl) != 0 || !ssl->s3->read_buffer.empty();
+}
+
int SSL_CTX_check_private_key(const SSL_CTX *ctx) {
return ssl_cert_check_private_key(ctx->cert.get(),
ctx->cert->privatekey.get());
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
index a2ca07a..4169671 100644
--- a/ssl/ssl_test.cc
+++ b/ssl/ssl_test.cc
@@ -4966,23 +4966,43 @@ TEST_P(SSLVersionTest, SSLPending) {
ASSERT_TRUE(Connect());
EXPECT_EQ(0, SSL_pending(client_.get()));
+ EXPECT_EQ(0, SSL_has_pending(client_.get()));
ASSERT_EQ(5, SSL_write(server_.get(), "hello", 5));
ASSERT_EQ(5, SSL_write(server_.get(), "world", 5));
EXPECT_EQ(0, SSL_pending(client_.get()));
+ EXPECT_EQ(0, SSL_has_pending(client_.get()));
char buf[10];
ASSERT_EQ(1, SSL_peek(client_.get(), buf, 1));
EXPECT_EQ(5, SSL_pending(client_.get()));
+ EXPECT_EQ(1, SSL_has_pending(client_.get()));
ASSERT_EQ(1, SSL_read(client_.get(), buf, 1));
EXPECT_EQ(4, SSL_pending(client_.get()));
+ EXPECT_EQ(1, SSL_has_pending(client_.get()));
ASSERT_EQ(4, SSL_read(client_.get(), buf, 10));
EXPECT_EQ(0, SSL_pending(client_.get()));
+ if (is_dtls()) {
+ // In DTLS, the two records would have been read as a single datagram and
+ // buffered inside |client_|. Thus, |SSL_has_pending| should return true.
+ //
+ // This test is slightly unrealistic. It relies on |ConnectClientAndServer|
+ // using a |BIO| pair, which does not preserve datagram boundaries. Reading
+ // 1 byte, then 4 bytes, from the first record also relies on
+ // https://crbug.com/boringssl/65. But it does test the codepaths. When
+ // fixing either of these bugs, this test may need to be redone.
+ EXPECT_EQ(1, SSL_has_pending(client_.get()));
+ } else {
+ // In TLS, we do not overread, so |SSL_has_pending| should report no data is
+ // buffered.
+ EXPECT_EQ(0, SSL_has_pending(client_.get()));
+ }
ASSERT_EQ(2, SSL_read(client_.get(), buf, 2));
EXPECT_EQ(3, SSL_pending(client_.get()));
+ EXPECT_EQ(1, SSL_has_pending(client_.get()));
}
// Test that post-handshake tickets consumed by |SSL_shutdown| are ignored.