diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc')
-rw-r--r-- | security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc | 754 |
1 files changed, 754 insertions, 0 deletions
diff --git a/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc new file mode 100644 index 000000000..d663d81e0 --- /dev/null +++ b/security/nss/gtests/ssl_gtest/ssl_auth_unittest.cc @@ -0,0 +1,754 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "secerr.h" +#include "ssl.h" +#include "sslerr.h" +#include "sslproto.h" + +extern "C" { +// This is not something that should make you happy. +#include "libssl_internals.h" +} + +#include "gtest_utils.h" +#include "scoped_ptrs.h" +#include "tls_connect.h" +#include "tls_filter.h" +#include "tls_parser.h" + +namespace nss_test { + +TEST_P(TlsConnectGeneric, ServerAuthBigRsa) { + Reset(TlsAgent::kRsa2048); + Connect(); + CheckKeys(); +} + +TEST_P(TlsConnectGeneric, ServerAuthRsaChain) { + Reset(TlsAgent::kServerRsaChain); + Connect(); + CheckKeys(); + size_t chain_length; + EXPECT_TRUE(client_->GetPeerChainLength(&chain_length)); + EXPECT_EQ(2UL, chain_length); +} + +TEST_P(TlsConnectGeneric, ClientAuth) { + client_->SetupClientAuth(); + server_->RequestClientAuth(true); + Connect(); + CheckKeys(); +} + +// In TLS 1.3, the client sends its cert rejection on the +// second flight, and since it has already received the +// server's Finished, it transitions to complete and +// then gets an alert from the server. The test harness +// doesn't handle this right yet. +TEST_P(TlsConnectStream, DISABLED_ClientAuthRequiredRejected) { + server_->RequestClientAuth(true); + ConnectExpectFail(); +} + +TEST_P(TlsConnectGeneric, ClientAuthRequestedRejected) { + server_->RequestClientAuth(false); + Connect(); + CheckKeys(); +} + +TEST_P(TlsConnectGeneric, ClientAuthEcdsa) { + Reset(TlsAgent::kServerEcdsa256); + client_->SetupClientAuth(); + server_->RequestClientAuth(true); + Connect(); + CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa); +} + +TEST_P(TlsConnectGeneric, ClientAuthBigRsa) { + Reset(TlsAgent::kServerRsa, TlsAgent::kRsa2048); + client_->SetupClientAuth(); + server_->RequestClientAuth(true); + Connect(); + CheckKeys(); +} + +// Offset is the position in the captured buffer where the signature sits. +static void CheckSigScheme(TlsInspectorRecordHandshakeMessage* capture, + size_t offset, TlsAgent* peer, + uint16_t expected_scheme, size_t expected_size) { + EXPECT_LT(offset + 2U, capture->buffer().len()); + + uint32_t scheme = 0; + capture->buffer().Read(offset, 2, &scheme); + EXPECT_EQ(expected_scheme, static_cast<uint16_t>(scheme)); + + ScopedCERTCertificate remote_cert(SSL_PeerCertificate(peer->ssl_fd())); + ScopedSECKEYPublicKey remote_key(CERT_ExtractPublicKey(remote_cert.get())); + EXPECT_EQ(expected_size, SECKEY_PublicKeyStrengthInBits(remote_key.get())); +} + +// The server should prefer SHA-256 by default, even for the small key size used +// in the default certificate. +TEST_P(TlsConnectTls12, ServerAuthCheckSigAlg) { + EnsureTlsSetup(); + auto capture_ske = + new TlsInspectorRecordHandshakeMessage(kTlsHandshakeServerKeyExchange); + server_->SetPacketFilter(capture_ske); + Connect(); + CheckKeys(); + + const DataBuffer& buffer = capture_ske->buffer(); + EXPECT_LT(3U, buffer.len()); + EXPECT_EQ(3U, buffer.data()[0]) << "curve_type == named_curve"; + uint32_t tmp; + EXPECT_TRUE(buffer.Read(1, 2, &tmp)) << "read NamedCurve"; + EXPECT_EQ(ssl_grp_ec_curve25519, tmp); + EXPECT_TRUE(buffer.Read(3, 1, &tmp)) << " read ECPoint"; + CheckSigScheme(capture_ske, 4 + tmp, client_, ssl_sig_rsa_pss_sha256, 1024); +} + +TEST_P(TlsConnectTls12, ClientAuthCheckSigAlg) { + EnsureTlsSetup(); + auto capture_cert_verify = + new TlsInspectorRecordHandshakeMessage(kTlsHandshakeCertificateVerify); + client_->SetPacketFilter(capture_cert_verify); + client_->SetupClientAuth(); + server_->RequestClientAuth(true); + Connect(); + CheckKeys(); + + CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pkcs1_sha1, 1024); +} + +TEST_P(TlsConnectTls12, ClientAuthBigRsaCheckSigAlg) { + Reset(TlsAgent::kServerRsa, TlsAgent::kRsa2048); + auto capture_cert_verify = + new TlsInspectorRecordHandshakeMessage(kTlsHandshakeCertificateVerify); + client_->SetPacketFilter(capture_cert_verify); + client_->SetupClientAuth(); + server_->RequestClientAuth(true); + Connect(); + CheckKeys(); + CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_sha256, 2048); +} + +static const SSLSignatureScheme SignatureSchemeEcdsaSha384[] = { + ssl_sig_ecdsa_secp384r1_sha384}; +static const SSLSignatureScheme SignatureSchemeEcdsaSha256[] = { + ssl_sig_ecdsa_secp256r1_sha256}; +static const SSLSignatureScheme SignatureSchemeRsaSha384[] = { + ssl_sig_rsa_pkcs1_sha384}; +static const SSLSignatureScheme SignatureSchemeRsaSha256[] = { + ssl_sig_rsa_pkcs1_sha256}; + +static SSLNamedGroup NamedGroupForEcdsa384(uint16_t version) { + // NSS tries to match the group size to the symmetric cipher. In TLS 1.1 and + // 1.0, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is the highest priority suite, so + // we use P-384. With TLS 1.2 on we pick AES-128 GCM so use x25519. + if (version <= SSL_LIBRARY_VERSION_TLS_1_1) { + return ssl_grp_ec_secp384r1; + } + return ssl_grp_ec_curve25519; +} + +// When signature algorithms match up, this should connect successfully; even +// for TLS 1.1 and 1.0, where they should be ignored. +TEST_P(TlsConnectGeneric, SignatureAlgorithmServerAuth) { + Reset(TlsAgent::kServerEcdsa384); + client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + server_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + Connect(); + CheckKeys(ssl_kea_ecdh, NamedGroupForEcdsa384(version_), ssl_auth_ecdsa, + ssl_sig_ecdsa_secp384r1_sha384); +} + +// Here the client picks a single option, which should work in all versions. +// Defaults on the server include the first option. +TEST_P(TlsConnectGeneric, SignatureAlgorithmClientOnly) { + const SSLSignatureAndHashAlg clientAlgorithms[] = { + {ssl_hash_sha384, ssl_sign_ecdsa}, + {ssl_hash_sha384, ssl_sign_rsa}, // supported but unusable + {ssl_hash_md5, ssl_sign_ecdsa} // unsupported and ignored + }; + Reset(TlsAgent::kServerEcdsa384); + EnsureTlsSetup(); + // Use the old API for this function. + EXPECT_EQ(SECSuccess, + SSL_SignaturePrefSet(client_->ssl_fd(), clientAlgorithms, + PR_ARRAY_SIZE(clientAlgorithms))); + Connect(); + CheckKeys(ssl_kea_ecdh, NamedGroupForEcdsa384(version_), ssl_auth_ecdsa, + ssl_sig_ecdsa_secp384r1_sha384); +} + +// Here the server picks a single option, which should work in all versions. +// Defaults on the client include the provided option. +TEST_P(TlsConnectGeneric, SignatureAlgorithmServerOnly) { + Reset(TlsAgent::kServerEcdsa384); + server_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + Connect(); + CheckKeys(ssl_kea_ecdh, NamedGroupForEcdsa384(version_), ssl_auth_ecdsa, + ssl_sig_ecdsa_secp384r1_sha384); +} + +// In TLS 1.2, curve and hash aren't bound together. +TEST_P(TlsConnectTls12, SignatureSchemeCurveMismatch) { + Reset(TlsAgent::kServerEcdsa256); + client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + Connect(); +} + +// In TLS 1.3, curve and hash are coupled. +TEST_P(TlsConnectTls13, SignatureSchemeCurveMismatch) { + Reset(TlsAgent::kServerEcdsa256); + client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + ConnectExpectFail(); + server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); + client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); +} + +// Configuring a P-256 cert with only SHA-384 signatures is OK in TLS 1.2. +TEST_P(TlsConnectTls12, SignatureSchemeBadConfig) { + Reset(TlsAgent::kServerEcdsa256); // P-256 cert can't be used. + server_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + Connect(); +} + +// A P-256 certificate in TLS 1.3 needs a SHA-256 signature scheme. +TEST_P(TlsConnectTls13, SignatureSchemeBadConfig) { + Reset(TlsAgent::kServerEcdsa256); // P-256 cert can't be used. + server_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + ConnectExpectFail(); + server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); + client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); +} + +// Where there is no overlap on signature schemes, we still connect successfully +// if we aren't going to use a signature. +TEST_P(TlsConnectGenericPre13, SignatureAlgorithmNoOverlapStaticRsa) { + client_->SetSignatureSchemes(SignatureSchemeRsaSha384, + PR_ARRAY_SIZE(SignatureSchemeRsaSha384)); + server_->SetSignatureSchemes(SignatureSchemeRsaSha256, + PR_ARRAY_SIZE(SignatureSchemeRsaSha256)); + EnableOnlyStaticRsaCiphers(); + Connect(); + CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt); +} + +TEST_P(TlsConnectTls12Plus, SignatureAlgorithmNoOverlapEcdsa) { + Reset(TlsAgent::kServerEcdsa256); + client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + server_->SetSignatureSchemes(SignatureSchemeEcdsaSha256, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha256)); + ConnectExpectFail(); + client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP); + server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); +} + +// Pre 1.2, a mismatch on signature algorithms shouldn't affect anything. +TEST_P(TlsConnectPre12, SignatureAlgorithmNoOverlapEcdsa) { + Reset(TlsAgent::kServerEcdsa256); + client_->SetSignatureSchemes(SignatureSchemeEcdsaSha384, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha384)); + server_->SetSignatureSchemes(SignatureSchemeEcdsaSha256, + PR_ARRAY_SIZE(SignatureSchemeEcdsaSha256)); + Connect(); +} + +// The signature_algorithms extension is mandatory in TLS 1.3. +TEST_P(TlsConnectTls13, SignatureAlgorithmDrop) { + client_->SetPacketFilter( + new TlsExtensionDropper(ssl_signature_algorithms_xtn)); + ConnectExpectFail(); + client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT); + server_->CheckErrorCode(SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION); +} + +// TLS 1.2 has trouble detecting this sort of modification: it uses SHA1 and +// only fails when the Finished is checked. +TEST_P(TlsConnectTls12, SignatureAlgorithmDrop) { + client_->SetPacketFilter( + new TlsExtensionDropper(ssl_signature_algorithms_xtn)); + ConnectExpectFail(); + client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT); + server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); +} + +TEST_P(TlsConnectTls12Plus, RequestClientAuthWithSha384) { + server_->SetSignatureSchemes(SignatureSchemeRsaSha384, + PR_ARRAY_SIZE(SignatureSchemeRsaSha384)); + server_->RequestClientAuth(false); + Connect(); +} + +class BeforeFinished : public TlsRecordFilter { + private: + enum HandshakeState { BEFORE_CCS, AFTER_CCS, DONE }; + + public: + BeforeFinished(TlsAgent* client, TlsAgent* server, VoidFunction before_ccs, + VoidFunction before_finished) + : client_(client), + server_(server), + before_ccs_(before_ccs), + before_finished_(before_finished), + state_(BEFORE_CCS) {} + + protected: + virtual PacketFilter::Action FilterRecord(const RecordHeader& header, + const DataBuffer& body, + DataBuffer* out) { + switch (state_) { + case BEFORE_CCS: + // Awaken when we see the CCS. + if (header.content_type() == kTlsChangeCipherSpecType) { + before_ccs_(); + + // Write the CCS out as a separate write, so that we can make + // progress. Ordinarily, libssl sends the CCS and Finished together, + // but that means that they both get processed together. + DataBuffer ccs; + header.Write(&ccs, 0, body); + server_->SendDirect(ccs); + client_->Handshake(); + state_ = AFTER_CCS; + // Request that the original record be dropped by the filter. + return DROP; + } + break; + + case AFTER_CCS: + EXPECT_EQ(kTlsHandshakeType, header.content_type()); + // This could check that data contains a Finished message, but it's + // encrypted, so that's too much extra work. + + before_finished_(); + state_ = DONE; + break; + + case DONE: + break; + } + return KEEP; + } + + private: + TlsAgent* client_; + TlsAgent* server_; + VoidFunction before_ccs_; + VoidFunction before_finished_; + HandshakeState state_; +}; + +// Running code after the client has started processing the encrypted part of +// the server's first flight, but before the Finished is processed is very hard +// in TLS 1.3. These encrypted messages are sent in a single encrypted blob. +// The following test uses DTLS to make it possible to force the client to +// process the handshake in pieces. +// +// The first encrypted message from the server is dropped, and the MTU is +// reduced to just below the original message size so that the server sends two +// messages. The Finished message is then processed separately. +class BeforeFinished13 : public PacketFilter { + private: + enum HandshakeState { + INIT, + BEFORE_FIRST_FRAGMENT, + BEFORE_SECOND_FRAGMENT, + DONE + }; + + public: + BeforeFinished13(TlsAgent* client, TlsAgent* server, + VoidFunction before_finished) + : client_(client), + server_(server), + before_finished_(before_finished), + records_(0) {} + + protected: + virtual PacketFilter::Action Filter(const DataBuffer& input, + DataBuffer* output) { + switch (++records_) { + case 1: + // Packet 1 is the server's entire first flight. Drop it. + EXPECT_EQ(SECSuccess, + SSLInt_SetMTU(server_->ssl_fd(), input.len() - 1)); + return DROP; + + // Packet 2 is the first part of the server's retransmitted first + // flight. Keep that. + + case 3: + // Packet 3 is the second part of the server's retransmitted first + // flight. Before passing that on, make sure that the client processes + // packet 2, then call the before_finished_() callback. + client_->Handshake(); + before_finished_(); + break; + + default: + break; + } + return KEEP; + } + + private: + TlsAgent* client_; + TlsAgent* server_; + VoidFunction before_finished_; + size_t records_; +}; + +static SECStatus AuthCompleteBlock(TlsAgent*, PRBool, PRBool) { + return SECWouldBlock; +} + +// This test uses an AuthCertificateCallback that blocks. A filter is used to +// split the server's first flight into two pieces. Before the second piece is +// processed by the client, SSL_AuthCertificateComplete() is called. +TEST_F(TlsConnectDatagram13, AuthCompleteBeforeFinished) { + client_->SetAuthCertificateCallback(AuthCompleteBlock); + server_->SetPacketFilter(new BeforeFinished13(client_, server_, [this]() { + EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0)); + })); + Connect(); +} + +static void TriggerAuthComplete(PollTarget* target, Event event) { + std::cerr << "client: call SSL_AuthCertificateComplete" << std::endl; + EXPECT_EQ(TIMER_EVENT, event); + TlsAgent* client = static_cast<TlsAgent*>(target); + EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client->ssl_fd(), 0)); +} + +// This test uses a simple AuthCertificateCallback. Due to the way that the +// entire server flight is processed, the call to SSL_AuthCertificateComplete +// will trigger after the Finished message is processed. +TEST_F(TlsConnectDatagram13, AuthCompleteAfterFinished) { + client_->SetAuthCertificateCallback( + [this](TlsAgent*, PRBool, PRBool) -> SECStatus { + Poller::Timer* timer_handle; + // This is really just to unroll the stack. + Poller::Instance()->SetTimer(1U, client_, TriggerAuthComplete, + &timer_handle); + return SECWouldBlock; + }); + Connect(); +} + +TEST_P(TlsConnectGenericPre13, ClientWriteBetweenCCSAndFinishedWithFalseStart) { + client_->EnableFalseStart(); + server_->SetPacketFilter(new BeforeFinished( + client_, server_, + [this]() { EXPECT_TRUE(client_->can_falsestart_hook_called()); }, + [this]() { + // Write something, which used to fail: bug 1235366. + client_->SendData(10); + })); + + Connect(); + server_->SendData(10); + Receive(10); +} + +TEST_P(TlsConnectGenericPre13, AuthCompleteBeforeFinishedWithFalseStart) { + client_->EnableFalseStart(); + client_->SetAuthCertificateCallback(AuthCompleteBlock); + server_->SetPacketFilter(new BeforeFinished( + client_, server_, + []() { + // Do nothing before CCS + }, + [this]() { + EXPECT_FALSE(client_->can_falsestart_hook_called()); + // AuthComplete before Finished still enables false start. + EXPECT_EQ(SECSuccess, + SSL_AuthCertificateComplete(client_->ssl_fd(), 0)); + EXPECT_TRUE(client_->can_falsestart_hook_called()); + client_->SendData(10); + })); + + Connect(); + server_->SendData(10); + Receive(10); +} + +class EnforceNoActivity : public PacketFilter { + protected: + PacketFilter::Action Filter(const DataBuffer& input, + DataBuffer* output) override { + std::cerr << "Unexpected packet: " << input << std::endl; + EXPECT_TRUE(false) << "should not send anything"; + return KEEP; + } +}; + +// In this test, we want to make sure that the server completes its handshake, +// but the client does not. Because the AuthCertificate callback blocks and we +// never call SSL_AuthCertificateComplete(), the client should never report that +// it has completed the handshake. Manually call Handshake(), alternating sides +// between client and server, until the desired state is reached. +TEST_P(TlsConnectGenericPre13, AuthCompleteDelayed) { + client_->SetAuthCertificateCallback(AuthCompleteBlock); + + server_->StartConnect(); + client_->StartConnect(); + client_->Handshake(); // Send ClientHello + server_->Handshake(); // Send ServerHello + client_->Handshake(); // Send ClientKeyExchange and Finished + server_->Handshake(); // Send Finished + // The server should now report that it is connected + EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state()); + + // The client should send nothing from here on. + client_->SetPacketFilter(new EnforceNoActivity()); + client_->Handshake(); + EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state()); + + // This should allow the handshake to complete now. + EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0)); + client_->Handshake(); // Transition to connected + EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state()); + EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state()); + + // Remove this before closing or the close_notify alert will trigger it. + client_->SetPacketFilter(nullptr); +} + +// TLS 1.3 handles a delayed AuthComplete callback differently since the +// shape of the handshake is different. +TEST_P(TlsConnectTls13, AuthCompleteDelayed) { + client_->SetAuthCertificateCallback(AuthCompleteBlock); + + server_->StartConnect(); + client_->StartConnect(); + client_->Handshake(); // Send ClientHello + server_->Handshake(); // Send ServerHello + EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state()); + EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state()); + + // The client will send nothing until AuthCertificateComplete is called. + client_->SetPacketFilter(new EnforceNoActivity()); + client_->Handshake(); + EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state()); + + // This should allow the handshake to complete now. + client_->SetPacketFilter(nullptr); + EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0)); + client_->Handshake(); // Send Finished + server_->Handshake(); // Transition to connected and send NewSessionTicket + EXPECT_EQ(TlsAgent::STATE_CONNECTED, client_->state()); + EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state()); +} + +static const SSLExtraServerCertData ServerCertDataRsaPkcs1Decrypt = { + ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr}; +static const SSLExtraServerCertData ServerCertDataRsaPkcs1Sign = { + ssl_auth_rsa_sign, nullptr, nullptr, nullptr}; +static const SSLExtraServerCertData ServerCertDataRsaPss = { + ssl_auth_rsa_pss, nullptr, nullptr, nullptr}; + +// Test RSA cert with usage=[signature, encipherment]. +TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPkcs1SignAndKEX) { + Reset(TlsAgent::kServerRsa); + + PRFileDesc* ssl_fd = agent_->ssl_fd(); + EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_decrypt)); + EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_sign)); + EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_pss)); + + // Configuring for only rsa_sign, rsa_pss, or rsa_decrypt should work. + EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsa, false, + &ServerCertDataRsaPkcs1Decrypt)); + EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsa, false, + &ServerCertDataRsaPkcs1Sign)); + EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsa, false, + &ServerCertDataRsaPss)); +} + +// Test RSA cert with usage=[signature]. +TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPkcs1Sign) { + Reset(TlsAgent::kServerRsaSign); + + PRFileDesc* ssl_fd = agent_->ssl_fd(); + EXPECT_FALSE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_decrypt)); + EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_sign)); + EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_pss)); + + // Configuring for only rsa_decrypt should fail. + EXPECT_FALSE(agent_->ConfigServerCert(TlsAgent::kServerRsaSign, false, + &ServerCertDataRsaPkcs1Decrypt)); + + // Configuring for only rsa_sign or rsa_pss should work. + EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsaSign, false, + &ServerCertDataRsaPkcs1Sign)); + EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsaSign, false, + &ServerCertDataRsaPss)); +} + +// Test RSA cert with usage=[encipherment]. +TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPkcs1KEX) { + Reset(TlsAgent::kServerRsaDecrypt); + + PRFileDesc* ssl_fd = agent_->ssl_fd(); + EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_decrypt)); + EXPECT_FALSE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_sign)); + EXPECT_FALSE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_pss)); + + // Configuring for only rsa_sign or rsa_pss should fail. + EXPECT_FALSE(agent_->ConfigServerCert(TlsAgent::kServerRsaDecrypt, false, + &ServerCertDataRsaPkcs1Sign)); + EXPECT_FALSE(agent_->ConfigServerCert(TlsAgent::kServerRsaDecrypt, false, + &ServerCertDataRsaPss)); + + // Configuring for only rsa_decrypt should work. + EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsaDecrypt, false, + &ServerCertDataRsaPkcs1Decrypt)); +} + +// Test configuring an RSA-PSS cert. +TEST_F(TlsAgentStreamTestServer, ConfigureCertRsaPss) { + Reset(TlsAgent::kServerRsaPss); + + PRFileDesc* ssl_fd = agent_->ssl_fd(); + EXPECT_FALSE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_decrypt)); + EXPECT_FALSE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_sign)); + EXPECT_TRUE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_pss)); + + // Configuring for only rsa_sign or rsa_decrypt should fail. + EXPECT_FALSE(agent_->ConfigServerCert(TlsAgent::kServerRsaPss, false, + &ServerCertDataRsaPkcs1Sign)); + EXPECT_FALSE(agent_->ConfigServerCert(TlsAgent::kServerRsaPss, false, + &ServerCertDataRsaPkcs1Decrypt)); + + // Configuring for only rsa_pss should work. + EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsaPss, false, + &ServerCertDataRsaPss)); +} + +// mode, version, certificate, auth type, signature scheme +typedef std::tuple<std::string, uint16_t, std::string, SSLAuthType, + SSLSignatureScheme> + SignatureSchemeProfile; + +class TlsSignatureSchemeConfiguration + : public TlsConnectTestBase, + public ::testing::WithParamInterface<SignatureSchemeProfile> { + public: + TlsSignatureSchemeConfiguration() + : TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())), + certificate_(std::get<2>(GetParam())), + auth_type_(std::get<3>(GetParam())), + signature_scheme_(std::get<4>(GetParam())) {} + + protected: + void TestSignatureSchemeConfig(TlsAgent* configPeer) { + EnsureTlsSetup(); + configPeer->SetSignatureSchemes(&signature_scheme_, 1); + Connect(); + CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, auth_type_, + signature_scheme_); + } + + std::string certificate_; + SSLAuthType auth_type_; + SSLSignatureScheme signature_scheme_; +}; + +TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigServer) { + Reset(certificate_); + TestSignatureSchemeConfig(server_); +} + +TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigClient) { + Reset(certificate_); + TlsExtensionCapture* capture = + new TlsExtensionCapture(ssl_signature_algorithms_xtn); + client_->SetPacketFilter(capture); + TestSignatureSchemeConfig(client_); + + const DataBuffer& ext = capture->extension(); + ASSERT_EQ(2U + 2U, ext.len()); + uint32_t v = 0; + ASSERT_TRUE(ext.Read(0, 2, &v)); + EXPECT_EQ(2U, v); + ASSERT_TRUE(ext.Read(2, 2, &v)); + EXPECT_EQ(signature_scheme_, static_cast<SSLSignatureScheme>(v)); +} + +TEST_P(TlsSignatureSchemeConfiguration, SignatureSchemeConfigBoth) { + Reset(certificate_); + EnsureTlsSetup(); + client_->SetSignatureSchemes(&signature_scheme_, 1); + server_->SetSignatureSchemes(&signature_scheme_, 1); + Connect(); + CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, auth_type_, signature_scheme_); +} + +INSTANTIATE_TEST_CASE_P( + SignatureSchemeRsa, TlsSignatureSchemeConfiguration, + ::testing::Combine( + TlsConnectTestBase::kTlsModesAll, TlsConnectTestBase::kTlsV12Plus, + ::testing::Values(TlsAgent::kServerRsaSign), + ::testing::Values(ssl_auth_rsa_sign), + ::testing::Values(ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pkcs1_sha384, + ssl_sig_rsa_pkcs1_sha512, ssl_sig_rsa_pss_sha256, + ssl_sig_rsa_pss_sha384))); +// PSS with SHA-512 needs a bigger key to work. +INSTANTIATE_TEST_CASE_P( + SignatureSchemeBigRsa, TlsSignatureSchemeConfiguration, + ::testing::Combine(TlsConnectTestBase::kTlsModesAll, + TlsConnectTestBase::kTlsV12Plus, + ::testing::Values(TlsAgent::kRsa2048), + ::testing::Values(ssl_auth_rsa_sign), + ::testing::Values(ssl_sig_rsa_pss_sha512))); +INSTANTIATE_TEST_CASE_P( + SignatureSchemeRsaSha1, TlsSignatureSchemeConfiguration, + ::testing::Combine(TlsConnectTestBase::kTlsModesAll, + TlsConnectTestBase::kTlsV12, + ::testing::Values(TlsAgent::kServerRsa), + ::testing::Values(ssl_auth_rsa_sign), + ::testing::Values(ssl_sig_rsa_pkcs1_sha1))); +INSTANTIATE_TEST_CASE_P( + SignatureSchemeEcdsaP256, TlsSignatureSchemeConfiguration, + ::testing::Combine(TlsConnectTestBase::kTlsModesAll, + TlsConnectTestBase::kTlsV12Plus, + ::testing::Values(TlsAgent::kServerEcdsa256), + ::testing::Values(ssl_auth_ecdsa), + ::testing::Values(ssl_sig_ecdsa_secp256r1_sha256))); +INSTANTIATE_TEST_CASE_P( + SignatureSchemeEcdsaP384, TlsSignatureSchemeConfiguration, + ::testing::Combine(TlsConnectTestBase::kTlsModesAll, + TlsConnectTestBase::kTlsV12Plus, + ::testing::Values(TlsAgent::kServerEcdsa384), + ::testing::Values(ssl_auth_ecdsa), + ::testing::Values(ssl_sig_ecdsa_secp384r1_sha384))); +INSTANTIATE_TEST_CASE_P( + SignatureSchemeEcdsaP521, TlsSignatureSchemeConfiguration, + ::testing::Combine(TlsConnectTestBase::kTlsModesAll, + TlsConnectTestBase::kTlsV12Plus, + ::testing::Values(TlsAgent::kServerEcdsa521), + ::testing::Values(ssl_auth_ecdsa), + ::testing::Values(ssl_sig_ecdsa_secp521r1_sha512))); +INSTANTIATE_TEST_CASE_P( + SignatureSchemeEcdsaSha1, TlsSignatureSchemeConfiguration, + ::testing::Combine(TlsConnectTestBase::kTlsModesAll, + TlsConnectTestBase::kTlsV12, + ::testing::Values(TlsAgent::kServerEcdsa256, + TlsAgent::kServerEcdsa384), + ::testing::Values(ssl_auth_ecdsa), + ::testing::Values(ssl_sig_ecdsa_sha1))); +} |