Add a unit test for one-sided shutdown.

OpenSSL was actually super-buggy here (though known bugs on our end have been
fixed), but pyOpenSSL was confused and incorrectly documented that callers call
SSL_read after SSL_shutdown to do bidi shutdown, so we should probably support
this. Add a test that it works.

Change-Id: I2b6d012161330aeb4cf894bae3a0b6a55d53c70d
Reviewed-on: https://boringssl-review.googlesource.com/8093
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2016-05-10 15:15:41 -04:00 committed by Adam Langley
parent bbd43b5e90
commit 686bb19ba1

View File

@ -1079,23 +1079,9 @@ static ScopedEVP_PKEY GetTestKey() {
PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr)); PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
} }
static bool TestSequenceNumber(bool dtls) { static bool ConnectClientAndServer(ScopedSSL *out_client, ScopedSSL *out_server,
ScopedSSL_CTX client_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method())); SSL_CTX *client_ctx, SSL_CTX *server_ctx) {
ScopedSSL_CTX server_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method())); ScopedSSL client(SSL_new(client_ctx)), server(SSL_new(server_ctx));
if (!client_ctx || !server_ctx) {
return false;
}
ScopedX509 cert = GetTestCertificate();
ScopedEVP_PKEY key = GetTestKey();
if (!cert || !key ||
!SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
!SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
return false;
}
// Create a client and server connected to each other.
ScopedSSL client(SSL_new(client_ctx.get())), server(SSL_new(server_ctx.get()));
if (!client || !server) { if (!client || !server) {
return false; return false;
} }
@ -1135,6 +1121,32 @@ static bool TestSequenceNumber(bool dtls) {
} }
} }
*out_client = std::move(client);
*out_server = std::move(server);
return true;
}
static bool TestSequenceNumber(bool dtls) {
ScopedSSL_CTX client_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
ScopedSSL_CTX server_ctx(SSL_CTX_new(dtls ? DTLS_method() : TLS_method()));
if (!client_ctx || !server_ctx) {
return false;
}
ScopedX509 cert = GetTestCertificate();
ScopedEVP_PKEY key = GetTestKey();
if (!cert || !key ||
!SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
!SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
return false;
}
ScopedSSL client, server;
if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
server_ctx.get())) {
return false;
}
uint64_t client_read_seq = SSL_get_read_sequence(client.get()); uint64_t client_read_seq = SSL_get_read_sequence(client.get());
uint64_t client_write_seq = SSL_get_write_sequence(client.get()); uint64_t client_write_seq = SSL_get_write_sequence(client.get());
uint64_t server_read_seq = SSL_get_read_sequence(server.get()); uint64_t server_read_seq = SSL_get_read_sequence(server.get());
@ -1183,6 +1195,62 @@ static bool TestSequenceNumber(bool dtls) {
return true; return true;
} }
static bool TestOneSidedShutdown() {
ScopedSSL_CTX client_ctx(SSL_CTX_new(TLS_method()));
ScopedSSL_CTX server_ctx(SSL_CTX_new(TLS_method()));
if (!client_ctx || !server_ctx) {
return false;
}
ScopedX509 cert = GetTestCertificate();
ScopedEVP_PKEY key = GetTestKey();
if (!cert || !key ||
!SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
!SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
return false;
}
ScopedSSL client, server;
if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
server_ctx.get())) {
return false;
}
// Shut down half the connection. SSL_shutdown will return 0 to signal only
// one side has shut down.
if (SSL_shutdown(client.get()) != 0) {
fprintf(stderr, "Could not shutdown.\n");
return false;
}
// Reading from the server should consume the EOF.
uint8_t byte;
if (SSL_read(server.get(), &byte, 1) != 0 ||
SSL_get_error(server.get(), 0) != SSL_ERROR_ZERO_RETURN) {
fprintf(stderr, "Connection was not shut down cleanly.\n");
return false;
}
// However, the server may continue to write data and then shut down the
// connection.
byte = 42;
if (SSL_write(server.get(), &byte, 1) != 1 ||
SSL_read(client.get(), &byte, 1) != 1 ||
byte != 42) {
fprintf(stderr, "Could not send byte.\n");
return false;
}
// The server may then shutdown the connection.
if (SSL_shutdown(server.get()) != 1 ||
SSL_shutdown(client.get()) != 1) {
fprintf(stderr, "Could not complete shutdown.\n");
return false;
}
return true;
}
int main() { int main() {
CRYPTO_library_init(); CRYPTO_library_init();
@ -1206,7 +1274,8 @@ int main() {
!TestClientCAList() || !TestClientCAList() ||
!TestInternalSessionCache() || !TestInternalSessionCache() ||
!TestSequenceNumber(false /* TLS */) || !TestSequenceNumber(false /* TLS */) ||
!TestSequenceNumber(true /* DTLS */)) { !TestSequenceNumber(true /* DTLS */) ||
!TestOneSidedShutdown()) {
ERR_print_errors_fp(stderr); ERR_print_errors_fp(stderr);
return 1; return 1;
} }