diff options
Diffstat (limited to 'ssl/ssl_test.cc')
-rw-r--r-- | ssl/ssl_test.cc | 265 |
1 files changed, 243 insertions, 22 deletions
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index ed1d3c7d..3e9cd1ed 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc @@ -254,6 +254,31 @@ static const char *kMustNotIncludeNull[] = { "TLSv1.2", }; +static const char *kMustNotIncludeCECPQ1[] = { + "ALL", + "DEFAULT", + "MEDIUM", + "HIGH", + "FIPS", + "SHA", + "SHA1", + "SHA256", + "SHA384", + "RSA", + "SSLv3", + "TLSv1", + "TLSv1.2", + "aRSA", + "RSA", + "aECDSA", + "ECDSA", + "AES", + "AES128", + "AES256", + "AESGCM", + "CHACHA20", +}; + static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) { bool in_group = false; for (size_t i = 0; i < sk_SSL_CIPHER_num(list->ciphers); i++) { @@ -324,6 +349,24 @@ static bool TestRuleDoesNotIncludeNull(const char *rule) { return true; } +static bool TestRuleDoesNotIncludeCECPQ1(const char *rule) { + ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method())); + if (!ctx) { + return false; + } + if (!SSL_CTX_set_cipher_list(ctx.get(), rule)) { + fprintf(stderr, "Error: cipher rule '%s' failed\n", rule); + return false; + } + for (size_t i = 0; i < sk_SSL_CIPHER_num(ctx->cipher_list->ciphers); i++) { + if (SSL_CIPHER_is_CECPQ1(sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, i))) { + fprintf(stderr, "Error: cipher rule '%s' includes CECPQ1\n",rule); + return false; + } + } + return true; +} + static bool TestCipherRules() { for (const CipherTest &test : kCipherTests) { if (!TestCipherRule(test)) { @@ -349,6 +392,12 @@ static bool TestCipherRules() { } } + for (const char *rule : kMustNotIncludeCECPQ1) { + if (!TestRuleDoesNotIncludeCECPQ1(rule)) { + return false; + } + } + return true; } @@ -646,7 +695,10 @@ static bool TestDefaultVersion(uint16_t version, if (!ctx) { return false; } - return ctx->min_version == version && ctx->max_version == version; + // TODO(svaldez): Remove TLS1_2_VERSION fallback upon implementing TLS 1.3. + return ctx->min_version == version && + (ctx->max_version == version || + (version == 0 && ctx->max_version == TLS1_2_VERSION)); } static bool CipherGetRFCName(std::string *out, uint16_t value) { @@ -1001,8 +1053,7 @@ static ScopedX509 GetTestCertificate() { "T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f\n" "j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg==\n" "-----END CERTIFICATE-----\n"; - ScopedBIO bio( - BIO_new_mem_buf(const_cast<char *>(kCertPEM), strlen(kCertPEM))); + ScopedBIO bio(BIO_new_mem_buf(kCertPEM, strlen(kCertPEM))); return ScopedX509(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); } @@ -1023,28 +1074,14 @@ static ScopedEVP_PKEY GetTestKey() { "tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n" "moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n" "-----END RSA PRIVATE KEY-----\n"; - ScopedBIO bio(BIO_new_mem_buf(const_cast<char *>(kKeyPEM), strlen(kKeyPEM))); + ScopedBIO bio(BIO_new_mem_buf(kKeyPEM, strlen(kKeyPEM))); return ScopedEVP_PKEY( PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr)); } -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; - } - - // Create a client and server connected to each other. - ScopedSSL client(SSL_new(client_ctx.get())), server(SSL_new(server_ctx.get())); +static bool ConnectClientAndServer(ScopedSSL *out_client, ScopedSSL *out_server, + SSL_CTX *client_ctx, SSL_CTX *server_ctx) { + ScopedSSL client(SSL_new(client_ctx)), server(SSL_new(server_ctx)); if (!client || !server) { return false; } @@ -1084,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_write_seq = SSL_get_write_sequence(client.get()); uint64_t server_read_seq = SSL_get_read_sequence(server.get()); @@ -1132,6 +1195,162 @@ static bool TestSequenceNumber(bool dtls) { 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; +} + +static bool ExpectFDs(const SSL *ssl, int rfd, int wfd) { + if (SSL_get_rfd(ssl) != rfd || SSL_get_wfd(ssl) != wfd) { + fprintf(stderr, "Got fds %d and %d, wanted %d and %d.\n", SSL_get_rfd(ssl), + SSL_get_wfd(ssl), rfd, wfd); + return false; + } + + // The wrapper BIOs are always equal when fds are equal, even if set + // individually. + if (rfd == wfd && SSL_get_rbio(ssl) != SSL_get_wbio(ssl)) { + fprintf(stderr, "rbio and wbio did not match.\n"); + return false; + } + + return true; +} + +static bool TestSetFD() { + ScopedSSL_CTX ctx(SSL_CTX_new(TLS_method())); + if (!ctx) { + return false; + } + + // Test setting different read and write FDs. + ScopedSSL ssl(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_rfd(ssl.get(), 1) || + !SSL_set_wfd(ssl.get(), 2) || + !ExpectFDs(ssl.get(), 1, 2)) { + return false; + } + + // Test setting the same FD. + ssl.reset(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_fd(ssl.get(), 1) || + !ExpectFDs(ssl.get(), 1, 1)) { + return false; + } + + // Test setting the same FD one side at a time. + ssl.reset(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_rfd(ssl.get(), 1) || + !SSL_set_wfd(ssl.get(), 1) || + !ExpectFDs(ssl.get(), 1, 1)) { + return false; + } + + // Test setting the same FD in the other order. + ssl.reset(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_wfd(ssl.get(), 1) || + !SSL_set_rfd(ssl.get(), 1) || + !ExpectFDs(ssl.get(), 1, 1)) { + return false; + } + + // Test changing the read FD partway through. + ssl.reset(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_fd(ssl.get(), 1) || + !SSL_set_rfd(ssl.get(), 2) || + !ExpectFDs(ssl.get(), 2, 1)) { + return false; + } + + // Test changing the write FD partway through. + ssl.reset(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_fd(ssl.get(), 1) || + !SSL_set_wfd(ssl.get(), 2) || + !ExpectFDs(ssl.get(), 1, 2)) { + return false; + } + + // Test a no-op change to the read FD partway through. + ssl.reset(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_fd(ssl.get(), 1) || + !SSL_set_rfd(ssl.get(), 1) || + !ExpectFDs(ssl.get(), 1, 1)) { + return false; + } + + // Test a no-op change to the write FD partway through. + ssl.reset(SSL_new(ctx.get())); + if (!ssl || + !SSL_set_fd(ssl.get(), 1) || + !SSL_set_wfd(ssl.get(), 1) || + !ExpectFDs(ssl.get(), 1, 1)) { + return false; + } + + // ASan builds will implicitly test that the internal |BIO| reference-counting + // is correct. + + return true; +} + int main() { CRYPTO_library_init(); @@ -1155,7 +1374,9 @@ int main() { !TestClientCAList() || !TestInternalSessionCache() || !TestSequenceNumber(false /* TLS */) || - !TestSequenceNumber(true /* DTLS */)) { + !TestSequenceNumber(true /* DTLS */) || + !TestOneSidedShutdown() || + !TestSetFD()) { ERR_print_errors_fp(stderr); return 1; } |