blob: adb4424c1b7754ed36aaa39aae98fdea298ad89b [file] [log] [blame]
/* -*- 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 "nss_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("rsa_chain");
Connect();
CheckKeys();
size_t chain_length;
EXPECT_TRUE(client_->GetPeerChainLength(&chain_length));
EXPECT_EQ(2UL, chain_length);
}
TEST_P(TlsConnectTls12Plus, ServerAuthRsaPss) {
static const SSLSignatureScheme kSignatureSchemePss[] = {
ssl_sig_rsa_pss_pss_sha256};
Reset(TlsAgent::kServerRsaPss);
client_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
server_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_pss,
ssl_sig_rsa_pss_pss_sha256);
}
// PSS doesn't work with TLS 1.0 or 1.1 because we can't signal it.
TEST_P(TlsConnectPre12, ServerAuthRsaPssFails) {
static const SSLSignatureScheme kSignatureSchemePss[] = {
ssl_sig_rsa_pss_pss_sha256};
Reset(TlsAgent::kServerRsaPss);
client_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
server_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
// Check that a PSS certificate with no parameters works.
TEST_P(TlsConnectTls12Plus, ServerAuthRsaPssNoParameters) {
static const SSLSignatureScheme kSignatureSchemePss[] = {
ssl_sig_rsa_pss_pss_sha256};
Reset("rsa_pss_noparam");
client_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
server_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_pss,
ssl_sig_rsa_pss_pss_sha256);
}
TEST_P(TlsConnectGeneric, ServerAuthRsaPssChain) {
Reset("rsa_pss_chain");
Connect();
CheckKeys();
size_t chain_length;
EXPECT_TRUE(client_->GetPeerChainLength(&chain_length));
EXPECT_EQ(2UL, chain_length);
}
TEST_P(TlsConnectGeneric, ServerAuthRsaCARsaPssChain) {
Reset("rsa_ca_rsa_pss_chain");
Connect();
CheckKeys();
size_t chain_length;
EXPECT_TRUE(client_->GetPeerChainLength(&chain_length));
EXPECT_EQ(2UL, chain_length);
}
TEST_P(TlsConnectGeneric, ServerAuthRejected) {
EnsureTlsSetup();
client_->SetAuthCertificateCallback(
[](TlsAgent*, PRBool, PRBool) -> SECStatus { return SECFailure; });
ConnectExpectAlert(client_, kTlsAlertBadCertificate);
client_->CheckErrorCode(SSL_ERROR_BAD_CERTIFICATE);
server_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
}
struct AuthCompleteArgs : public PollTarget {
AuthCompleteArgs(const std::shared_ptr<TlsAgent>& a, PRErrorCode c)
: agent(a), code(c) {}
std::shared_ptr<TlsAgent> agent;
PRErrorCode code;
};
static void CallAuthComplete(PollTarget* target, Event event) {
EXPECT_EQ(TIMER_EVENT, event);
auto args = reinterpret_cast<AuthCompleteArgs*>(target);
std::cerr << args->agent->role_str() << ": call SSL_AuthCertificateComplete "
<< (args->code ? PR_ErrorToName(args->code) : "no error")
<< std::endl;
EXPECT_EQ(SECSuccess,
SSL_AuthCertificateComplete(args->agent->ssl_fd(), args->code));
args->agent->Handshake(); // Make the TlsAgent aware of the error.
delete args;
}
// Install an AuthCertificateCallback that blocks when called. Then
// SSL_AuthCertificateComplete is called on a very short timer. This allows any
// processing that might follow the callback to complete.
static void SetDeferredAuthCertificateCallback(std::shared_ptr<TlsAgent> agent,
PRErrorCode code) {
auto args = new AuthCompleteArgs(agent, code);
agent->SetAuthCertificateCallback(
[args](TlsAgent*, PRBool, PRBool) -> SECStatus {
// This can't be 0 or we race the message from the client to the server,
// and tests assume that we lose that race.
std::shared_ptr<Poller::Timer> timer_handle;
Poller::Instance()->SetTimer(1U, args, CallAuthComplete, &timer_handle);
return SECWouldBlock;
});
}
TEST_P(TlsConnectTls13, ServerAuthRejectAsync) {
SetDeferredAuthCertificateCallback(client_, SEC_ERROR_REVOKED_CERTIFICATE);
ConnectExpectAlert(client_, kTlsAlertCertificateRevoked);
// We only detect the error here when we attempt to handshake, so all the
// client learns is that the handshake has already failed.
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILED);
server_->CheckErrorCode(SSL_ERROR_REVOKED_CERT_ALERT);
}
// In TLS 1.2 and earlier, this will result in the client sending its Finished
// before learning that the server certificate is bad. That means that the
// server will believe that the handshake is complete.
TEST_P(TlsConnectGenericPre13, ServerAuthRejectAsync) {
SetDeferredAuthCertificateCallback(client_, SEC_ERROR_EXPIRED_CERTIFICATE);
client_->ExpectSendAlert(kTlsAlertCertificateExpired);
server_->ExpectReceiveAlert(kTlsAlertCertificateExpired);
ConnectExpectFailOneSide(TlsAgent::CLIENT);
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILED);
// The server might not receive the alert that the client sends, which would
// cause the test to fail when it cleans up. Reset expectations.
server_->ExpectReceiveAlert(kTlsAlertCloseNotify, kTlsAlertWarning);
}
TEST_P(TlsConnectGeneric, ClientAuth) {
client_->SetupClientAuth();
server_->RequestClientAuth(true);
Connect();
CheckKeys();
}
class TlsCertificateRequestContextRecorder : public TlsHandshakeFilter {
public:
TlsCertificateRequestContextRecorder(const std::shared_ptr<TlsAgent>& a,
uint8_t handshake_type)
: TlsHandshakeFilter(a, {handshake_type}), buffer_(), filtered_(false) {
EnableDecryption();
}
bool filtered() const { return filtered_; }
const DataBuffer& buffer() const { return buffer_; }
protected:
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) {
assert(1 < input.len());
size_t len = input.data()[0];
assert(len + 1 < input.len());
buffer_.Assign(input.data() + 1, len);
filtered_ = true;
return KEEP;
}
private:
DataBuffer buffer_;
bool filtered_;
};
// All stream only tests; DTLS isn't supported yet.
TEST_F(TlsConnectStreamTls13, PostHandshakeAuth) {
EnsureTlsSetup();
auto capture_cert_req = MakeTlsFilter<TlsCertificateRequestContextRecorder>(
server_, kTlsHandshakeCertificateRequest);
auto capture_certificate =
MakeTlsFilter<TlsCertificateRequestContextRecorder>(
client_, kTlsHandshakeCertificate);
client_->SetupClientAuth();
client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
called++;
return SECSuccess;
});
Connect();
EXPECT_EQ(0U, called);
EXPECT_FALSE(capture_cert_req->filtered());
EXPECT_FALSE(capture_certificate->filtered());
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
// Need to do a round-trip so that the post-handshake message is
// handled on both client and server.
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
EXPECT_TRUE(capture_cert_req->filtered());
EXPECT_TRUE(capture_certificate->filtered());
// Check if a non-empty request context is generated and it is
// properly sent back.
EXPECT_LT(0U, capture_cert_req->buffer().len());
EXPECT_EQ(capture_cert_req->buffer().len(),
capture_certificate->buffer().len());
EXPECT_EQ(0, memcmp(capture_cert_req->buffer().data(),
capture_certificate->buffer().data(),
capture_cert_req->buffer().len()));
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterResumption) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
Connect();
SendReceive(); // Need to read so that we absorb the session tickets.
CheckKeys();
// Resume the connection.
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
ExpectResumption(RESUME_TICKET);
client_->SetupClientAuth();
client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
Connect();
SendReceive();
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
called++;
return SECSuccess;
});
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
static SECStatus GetClientAuthDataHook(void* self, PRFileDesc* fd,
CERTDistNames* caNames,
CERTCertificate** clientCert,
SECKEYPrivateKey** clientKey) {
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey priv;
// use a different certificate than TlsAgent::kClient
if (!TlsAgent::LoadCertificate(TlsAgent::kRsa2048, &cert, &priv)) {
return SECFailure;
}
*clientCert = cert.release();
*clientKey = priv.release();
return SECSuccess;
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMultiple) {
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
called++;
return SECSuccess;
});
Connect();
EXPECT_EQ(0U, called);
EXPECT_EQ(nullptr, SSL_PeerCertificate(server_->ssl_fd()));
// Send 1st CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
// Send 2nd CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
client_->ssl_fd(), GetClientAuthDataHook, nullptr));
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
EXPECT_EQ(2U, called);
ScopedCERTCertificate cert3(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert3.get());
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert4.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert4->derCert));
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert1->derCert));
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthConcurrent) {
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
Connect();
// Send 1st CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
// Send 2nd CertificateRequest.
EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthBeforeKeyUpdate) {
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
Connect();
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
// Send KeyUpdate.
EXPECT_EQ(SECFailure, SSL_KeyUpdate(server_->ssl_fd(), PR_TRUE));
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDuringClientKeyUpdate) {
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
Connect();
CheckEpochs(3, 3);
// Send CertificateRequest from server.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
// Send KeyUpdate from client.
EXPECT_EQ(SECSuccess, SSL_KeyUpdate(client_->ssl_fd(), PR_TRUE));
server_->SendData(50); // server sends CertificateRequest
client_->SendData(50); // client sends KeyUpdate
server_->ReadBytes(50); // server receives KeyUpdate and defers response
CheckEpochs(4, 3);
client_->ReadBytes(50); // client receives CertificateRequest
client_->SendData(
50); // client sends Certificate, CertificateVerify, Finished
server_->ReadBytes(
50); // server receives Certificate, CertificateVerify, Finished
client_->CheckEpochs(3, 4);
server_->CheckEpochs(4, 4);
server_->SendData(50); // server sends KeyUpdate
client_->ReadBytes(50); // client receives KeyUpdate
client_->CheckEpochs(4, 4);
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMissingExtension) {
client_->SetupClientAuth();
Connect();
// Send CertificateRequest, should fail due to missing
// post_handshake_auth extension.
EXPECT_EQ(SECFailure, SSL_SendCertificateRequest(server_->ssl_fd()));
EXPECT_EQ(SSL_ERROR_MISSING_POST_HANDSHAKE_AUTH_EXTENSION, PORT_GetError());
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthAfterClientAuth) {
client_->SetupClientAuth();
server_->RequestClientAuth(true);
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
called++;
return SECSuccess;
});
Connect();
EXPECT_EQ(1U, called);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
client_->ssl_fd(), GetClientAuthDataHook, nullptr));
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
EXPECT_EQ(2U, called);
ScopedCERTCertificate cert3(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert3.get());
ScopedCERTCertificate cert4(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert4.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert4->derCert));
EXPECT_FALSE(SECITEM_ItemsAreEqual(&cert3->derCert, &cert1->derCert));
}
// Damages the request context in a CertificateRequest message.
// We don't modify a Certificate message instead, so that the client
// can compute CertificateVerify correctly.
class TlsDamageCertificateRequestContextFilter : public TlsHandshakeFilter {
public:
TlsDamageCertificateRequestContextFilter(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}) {
EnableDecryption();
}
protected:
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) {
*output = input;
assert(1 < output->len());
// The request context has a 1 octet length.
output->data()[1] ^= 73;
return CHANGE;
}
};
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthContextMismatch) {
EnsureTlsSetup();
MakeTlsFilter<TlsDamageCertificateRequestContextFilter>(server_);
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
Connect();
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ExpectSendAlert(kTlsAlertIllegalParameter);
server_->ReadBytes(50);
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CERTIFICATE, PORT_GetError());
server_->ExpectReadWriteError();
server_->SendData(50);
client_->ExpectReceiveAlert(kTlsAlertIllegalParameter);
client_->ReadBytes(50);
EXPECT_EQ(SSL_ERROR_ILLEGAL_PARAMETER_ALERT, PORT_GetError());
}
// Replaces signature in a CertificateVerify message.
class TlsDamageSignatureFilter : public TlsHandshakeFilter {
public:
TlsDamageSignatureFilter(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateVerify}) {
EnableDecryption();
}
protected:
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) {
*output = input;
assert(2 < output->len());
// The signature follows a 2-octet signature scheme.
output->data()[2] ^= 73;
return CHANGE;
}
};
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthBadSignature) {
EnsureTlsSetup();
MakeTlsFilter<TlsDamageSignatureFilter>(client_);
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
Connect();
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ExpectSendAlert(kTlsAlertDecodeError);
server_->ReadBytes(50);
EXPECT_EQ(SSL_ERROR_RX_MALFORMED_CERT_VERIFY, PORT_GetError());
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDecline) {
EnsureTlsSetup();
auto capture_cert_req = MakeTlsFilter<TlsCertificateRequestContextRecorder>(
server_, kTlsHandshakeCertificateRequest);
auto capture_certificate =
MakeTlsFilter<TlsCertificateRequestContextRecorder>(
client_, kTlsHandshakeCertificate);
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
EXPECT_EQ(SECSuccess,
SSL_OptionSet(server_->ssl_fd(), SSL_REQUIRE_CERTIFICATE,
SSL_REQUIRE_ALWAYS));
// Client to decline the certificate request.
EXPECT_EQ(SECSuccess,
SSL_GetClientAuthDataHook(
client_->ssl_fd(),
[](void*, PRFileDesc*, CERTDistNames*, CERTCertificate**,
SECKEYPrivateKey**) -> SECStatus { return SECFailure; },
nullptr));
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
called++;
return SECSuccess;
});
Connect();
EXPECT_EQ(0U, called);
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50); // send Certificate Request
client_->ReadBytes(50); // read Certificate Request
client_->SendData(50); // send empty Certificate+Finished
server_->ExpectSendAlert(kTlsAlertCertificateRequired);
server_->ReadBytes(50); // read empty Certificate+Finished
server_->ExpectReadWriteError();
server_->SendData(50); // send alert
// AuthCertificateCallback is not called, because the client sends
// an empty certificate_list.
EXPECT_EQ(0U, called);
EXPECT_TRUE(capture_cert_req->filtered());
EXPECT_TRUE(capture_certificate->filtered());
// Check if a non-empty request context is generated and it is
// properly sent back.
EXPECT_LT(0U, capture_cert_req->buffer().len());
EXPECT_EQ(capture_cert_req->buffer().len(),
capture_certificate->buffer().len());
EXPECT_EQ(0, memcmp(capture_cert_req->buffer().data(),
capture_certificate->buffer().data(),
capture_cert_req->buffer().len()));
}
// Check if post-handshake auth still works when session tickets are enabled:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1553443
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthWithSessionTicketsEnabled) {
EnsureTlsSetup();
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE));
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),
SSL_ENABLE_SESSION_TICKETS, PR_TRUE));
EXPECT_EQ(SECSuccess, SSL_OptionSet(server_->ssl_fd(),
SSL_ENABLE_SESSION_TICKETS, PR_TRUE));
size_t called = 0;
server_->SetAuthCertificateCallback(
[&called](TlsAgent*, PRBool, PRBool) -> SECStatus {
called++;
return SECSuccess;
});
Connect();
EXPECT_EQ(0U, called);
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_GetClientAuthDataHook(
client_->ssl_fd(), GetClientAuthDataHook, nullptr));
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_NE(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_NE(nullptr, cert2.get());
EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
}
TEST_P(TlsConnectGenericPre13, ClientAuthRequiredRejected) {
server_->RequestClientAuth(true);
ConnectExpectAlert(server_, kTlsAlertBadCertificate);
client_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
}
// In TLS 1.3, the client will claim that the connection is done and then
// receive the alert afterwards. So drive the handshake manually.
TEST_P(TlsConnectTls13, ClientAuthRequiredRejected) {
server_->RequestClientAuth(true);
StartConnect();
client_->Handshake(); // CH
server_->Handshake(); // SH.. (no resumption)
client_->Handshake(); // Next message
ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
ExpectAlert(server_, kTlsAlertCertificateRequired);
server_->Handshake(); // Alert
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
client_->Handshake(); // Receive Alert
client_->CheckErrorCode(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT);
}
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, ClientAuthWithEch) {
Reset(TlsAgent::kServerEcdsa256);
EnsureTlsSetup();
SetupEch(client_, server_);
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(std::shared_ptr<TlsHandshakeRecorder>& capture,
size_t offset, std::shared_ptr<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()));
ASSERT_NE(nullptr, remote_cert.get());
ScopedSECKEYPublicKey remote_key(CERT_ExtractPublicKey(remote_cert.get()));
ASSERT_NE(nullptr, remote_key.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 = MakeTlsFilter<TlsHandshakeRecorder>(
server_, kTlsHandshakeServerKeyExchange);
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_rsae_sha256,
1024);
}
TEST_P(TlsConnectTls12, ClientAuthCheckSigAlg) {
EnsureTlsSetup();
auto capture_cert_verify = MakeTlsFilter<TlsHandshakeRecorder>(
client_, kTlsHandshakeCertificateVerify);
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 = MakeTlsFilter<TlsHandshakeRecorder>(
client_, kTlsHandshakeCertificateVerify);
client_->SetupClientAuth();
server_->RequestClientAuth(true);
Connect();
CheckKeys();
CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_rsae_sha256,
2048);
}
// Replaces the signature scheme in a CertificateVerify message.
class TlsReplaceSignatureSchemeFilter : public TlsHandshakeFilter {
public:
TlsReplaceSignatureSchemeFilter(const std::shared_ptr<TlsAgent>& a,
SSLSignatureScheme scheme)
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateVerify}),
scheme_(scheme) {}
protected:
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) {
*output = input;
output->Write(0, scheme_, 2);
return CHANGE;
}
private:
SSLSignatureScheme scheme_;
};
// Check if CertificateVerify signed with rsa_pss_rsae_* is properly
// rejected when the certificate is RSA-PSS.
//
// This only works under TLS 1.2, because PSS doesn't work with TLS
// 1.0 or TLS 1.1 and the TLS 1.3 1-RTT handshake is partially
// successful at the client side.
TEST_P(TlsConnectTls12, ClientAuthInconsistentRsaeSignatureScheme) {
static const SSLSignatureScheme kSignatureSchemePss[] = {
ssl_sig_rsa_pss_pss_sha256, ssl_sig_rsa_pss_rsae_sha256};
Reset(TlsAgent::kServerRsa, "rsa_pss");
client_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
server_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
client_->SetupClientAuth();
server_->RequestClientAuth(true);
EnsureTlsSetup();
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(client_,
ssl_sig_rsa_pss_rsae_sha256);
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
}
// Check if CertificateVerify signed with rsa_pss_pss_* is properly
// rejected when the certificate is RSA.
//
// This only works under TLS 1.2, because PSS doesn't work with TLS
// 1.0 or TLS 1.1 and the TLS 1.3 1-RTT handshake is partially
// successful at the client side.
TEST_P(TlsConnectTls12, ClientAuthInconsistentPssSignatureScheme) {
static const SSLSignatureScheme kSignatureSchemePss[] = {
ssl_sig_rsa_pss_rsae_sha256, ssl_sig_rsa_pss_pss_sha256};
Reset(TlsAgent::kServerRsa, "rsa");
client_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
server_->SetSignatureSchemes(kSignatureSchemePss,
PR_ARRAY_SIZE(kSignatureSchemePss));
client_->SetupClientAuth();
server_->RequestClientAuth(true);
EnsureTlsSetup();
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(client_,
ssl_sig_rsa_pss_pss_sha256);
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
}
TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureScheme) {
static const SSLSignatureScheme kSignatureScheme[] = {
ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pss_rsae_sha256};
Reset(TlsAgent::kServerRsa, "rsa");
client_->SetSignatureSchemes(kSignatureScheme,
PR_ARRAY_SIZE(kSignatureScheme));
server_->SetSignatureSchemes(kSignatureScheme,
PR_ARRAY_SIZE(kSignatureScheme));
client_->SetupClientAuth();
server_->RequestClientAuth(true);
auto capture_cert_verify = MakeTlsFilter<TlsHandshakeRecorder>(
client_, kTlsHandshakeCertificateVerify);
capture_cert_verify->EnableDecryption();
Connect();
CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_rsae_sha256,
1024);
}
// Client should refuse to connect without a usable signature scheme.
TEST_P(TlsConnectTls13, ClientAuthPkcs1SignatureSchemeOnly) {
static const SSLSignatureScheme kSignatureScheme[] = {
ssl_sig_rsa_pkcs1_sha256};
Reset(TlsAgent::kServerRsa, "rsa");
client_->SetSignatureSchemes(kSignatureScheme,
PR_ARRAY_SIZE(kSignatureScheme));
client_->SetupClientAuth();
client_->StartConnect();
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
// Though the client has a usable signature scheme, when a certificate is
// requested, it can't produce one.
TEST_P(TlsConnectTls13, ClientAuthPkcs1AndEcdsaScheme) {
static const SSLSignatureScheme kSignatureScheme[] = {
ssl_sig_rsa_pkcs1_sha256, ssl_sig_ecdsa_secp256r1_sha256};
Reset(TlsAgent::kServerRsa, "rsa");
client_->SetSignatureSchemes(kSignatureScheme,
PR_ARRAY_SIZE(kSignatureScheme));
client_->SetupClientAuth();
server_->RequestClientAuth(true);
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
class TlsZeroCertificateRequestSigAlgsFilter : public TlsHandshakeFilter {
public:
TlsZeroCertificateRequestSigAlgsFilter(const std::shared_ptr<TlsAgent>& a)
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}) {}
virtual PacketFilter::Action FilterHandshake(
const TlsHandshakeFilter::HandshakeHeader& header,
const DataBuffer& input, DataBuffer* output) {
TlsParser parser(input);
std::cerr << "Zeroing CertReq.supported_signature_algorithms" << std::endl;
DataBuffer cert_types;
if (!parser.ReadVariable(&cert_types, 1)) {
ADD_FAILURE();
return KEEP;
}
if (!parser.SkipVariable(2)) {
ADD_FAILURE();
return KEEP;
}
DataBuffer cas;
if (!parser.ReadVariable(&cas, 2)) {
ADD_FAILURE();
return KEEP;
}
size_t idx = 0;
// Write certificate types.
idx = output->Write(idx, cert_types.len(), 1);
idx = output->Write(idx, cert_types);
// Write zero signature algorithms.
idx = output->Write(idx, 0U, 2);
// Write certificate authorities.
idx = output->Write(idx, cas.len(), 2);
idx = output->Write(idx, cas);
return CHANGE;
}
};
// Check that we send an alert when the server doesn't provide any
// supported_signature_algorithms in the CertificateRequest message.
TEST_P(TlsConnectTls12, ClientAuthNoSigAlgs) {
EnsureTlsSetup();
MakeTlsFilter<TlsZeroCertificateRequestSigAlgsFilter>(server_);
auto capture_cert_verify = MakeTlsFilter<TlsHandshakeRecorder>(
client_, kTlsHandshakeCertificateVerify);
client_->SetupClientAuth();
server_->RequestClientAuth(true);
ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
}
static SECStatus GetEcClientAuthDataHook(void* self, PRFileDesc* fd,
CERTDistNames* caNames,
CERTCertificate** clientCert,
SECKEYPrivateKey** clientKey) {
ScopedCERTCertificate cert;
ScopedSECKEYPrivateKey priv;
// use a different certificate than TlsAgent::kClient
if (!TlsAgent::LoadCertificate(TlsAgent::kServerEcdsa256, &cert, &priv)) {
return SECFailure;
}
*clientCert = cert.release();
*clientKey = priv.release();
return SECSuccess;
}
TEST_P(TlsConnectTls12Plus, ClientAuthDisjointSchemes) {
EnsureTlsSetup();
client_->SetupClientAuth();
server_->RequestClientAuth(true);
SSLSignatureScheme server_scheme = ssl_sig_rsa_pss_rsae_sha256;
std::vector<SSLSignatureScheme> client_schemes{
ssl_sig_rsa_pss_rsae_sha256, ssl_sig_ecdsa_secp256r1_sha256};
SECStatus rv =
SSL_SignatureSchemePrefSet(server_->ssl_fd(), &server_scheme, 1);
EXPECT_EQ(SECSuccess, rv);
rv = SSL_SignatureSchemePrefSet(
client_->ssl_fd(), client_schemes.data(),
static_cast<unsigned int>(client_schemes.size()));
EXPECT_EQ(SECSuccess, rv);
// Select an EC cert that's incompatible with server schemes.
EXPECT_EQ(SECSuccess,
SSL_GetClientAuthDataHook(client_->ssl_fd(),
GetEcClientAuthDataHook, nullptr));
StartConnect();
client_->Handshake(); // CH
server_->Handshake(); // SH
client_->Handshake();
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
ASSERT_EQ(TlsAgent::STATE_CONNECTED, client_->state());
ExpectAlert(server_, kTlsAlertCertificateRequired);
server_->Handshake(); // Alert
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
client_->Handshake(); // Receive Alert
client_->CheckErrorCode(SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT);
} else {
ASSERT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
ExpectAlert(server_, kTlsAlertBadCertificate);
server_->Handshake(); // Alert
server_->CheckErrorCode(SSL_ERROR_NO_CERTIFICATE);
client_->Handshake(); // Receive Alert
client_->CheckErrorCode(SSL_ERROR_BAD_CERT_ALERT);
}
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthDisjointSchemes) {
EnsureTlsSetup();
SSLSignatureScheme server_scheme = ssl_sig_rsa_pss_rsae_sha256;
std::vector<SSLSignatureScheme> client_schemes{
ssl_sig_rsa_pss_rsae_sha256, ssl_sig_ecdsa_secp256r1_sha256};
SECStatus rv =
SSL_SignatureSchemePrefSet(server_->ssl_fd(), &server_scheme, 1);
EXPECT_EQ(SECSuccess, rv);
rv = SSL_SignatureSchemePrefSet(
client_->ssl_fd(), client_schemes.data(),
static_cast<unsigned int>(client_schemes.size()));
EXPECT_EQ(SECSuccess, rv);
client_->SetupClientAuth();
client_->SetOption(SSL_ENABLE_POST_HANDSHAKE_AUTH, PR_TRUE);
// Select an EC cert that's incompatible with server schemes.
EXPECT_EQ(SECSuccess,
SSL_GetClientAuthDataHook(client_->ssl_fd(),
GetEcClientAuthDataHook, nullptr));
Connect();
// Send CertificateRequest.
EXPECT_EQ(SECSuccess, SSL_SendCertificateRequest(server_->ssl_fd()))
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
// Need to do a round-trip so that the post-handshake message is
// handled on both client and server.
server_->SendData(50);
client_->ReadBytes(50);
client_->SendData(50);
server_->ReadBytes(50);
ScopedCERTCertificate cert1(SSL_PeerCertificate(server_->ssl_fd()));
ASSERT_EQ(nullptr, cert1.get());
ScopedCERTCertificate cert2(SSL_LocalCertificate(client_->ssl_fd()));
ASSERT_EQ(nullptr, cert2.get());
}
static const SSLSignatureScheme kSignatureSchemeEcdsaSha384[] = {
ssl_sig_ecdsa_secp384r1_sha384};
static const SSLSignatureScheme kSignatureSchemeEcdsaSha256[] = {
ssl_sig_ecdsa_secp256r1_sha256};
static const SSLSignatureScheme kSignatureSchemeRsaSha384[] = {
ssl_sig_rsa_pkcs1_sha384};
static const SSLSignatureScheme kSignatureSchemeRsaSha256[] = {
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(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
server_->SetSignatureSchemes(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
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(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
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(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
Connect();
}
// In TLS 1.3, curve and hash are coupled.
TEST_P(TlsConnectTls13, SignatureSchemeCurveMismatch) {
Reset(TlsAgent::kServerEcdsa256);
client_->SetSignatureSchemes(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
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(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
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(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
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(kSignatureSchemeRsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeRsaSha384));
server_->SetSignatureSchemes(kSignatureSchemeRsaSha256,
PR_ARRAY_SIZE(kSignatureSchemeRsaSha256));
EnableOnlyStaticRsaCiphers();
Connect();
CheckKeys(ssl_kea_rsa, ssl_auth_rsa_decrypt);
}
TEST_P(TlsConnectTls12Plus, SignatureAlgorithmNoOverlapEcdsa) {
Reset(TlsAgent::kServerEcdsa256);
client_->SetSignatureSchemes(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
server_->SetSignatureSchemes(kSignatureSchemeEcdsaSha256,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha256));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
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(kSignatureSchemeEcdsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
server_->SetSignatureSchemes(kSignatureSchemeEcdsaSha256,
PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha256));
Connect();
}
// The signature_algorithms extension is mandatory in TLS 1.3.
TEST_P(TlsConnectTls13, SignatureAlgorithmDrop) {
MakeTlsFilter<TlsExtensionDropper>(client_, ssl_signature_algorithms_xtn);
ConnectExpectAlert(server_, kTlsAlertMissingExtension);
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) {
MakeTlsFilter<TlsExtensionDropper>(client_, ssl_signature_algorithms_xtn);
ConnectExpectAlert(server_, kTlsAlertDecryptError);
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
TEST_P(TlsConnectTls13, UnsupportedSignatureSchemeAlert) {
EnsureTlsSetup();
auto filter =
MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(server_, ssl_sig_none);
filter->EnableDecryption();
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
}
TEST_P(TlsConnectTls13, InconsistentSignatureSchemeAlert) {
EnsureTlsSetup();
// This won't work because we use an RSA cert by default.
auto filter = MakeTlsFilter<TlsReplaceSignatureSchemeFilter>(
server_, ssl_sig_ecdsa_secp256r1_sha256);
filter->EnableDecryption();
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
}
TEST_P(TlsConnectTls12, RequestClientAuthWithSha384) {
server_->SetSignatureSchemes(kSignatureSchemeRsaSha384,
PR_ARRAY_SIZE(kSignatureSchemeRsaSha384));
server_->RequestClientAuth(false);
Connect();
}
class BeforeFinished : public TlsRecordFilter {
private:
enum HandshakeState { BEFORE_CCS, AFTER_CCS, DONE };
public:
BeforeFinished(const std::shared_ptr<TlsAgent>& server,
const std::shared_ptr<TlsAgent>& client,
VoidFunction before_ccs, VoidFunction before_finished)
: TlsRecordFilter(server),
client_(client),
before_ccs_(before_ccs),
before_finished_(before_finished),
state_(BEFORE_CCS) {}
protected:
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& body,
DataBuffer* out) {
switch (state_) {
case BEFORE_CCS:
// Awaken when we see the CCS.
if (header.content_type() == ssl_ct_change_cipher_spec) {
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);
agent()->SendDirect(ccs);
client_.lock()->Handshake();
state_ = AFTER_CCS;
// Request that the original record be dropped by the filter.
return DROP;
}
break;
case AFTER_CCS:
EXPECT_EQ(ssl_ct_handshake, 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:
std::weak_ptr<TlsAgent> client_;
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(const std::shared_ptr<TlsAgent>& server,
const std::shared_ptr<TlsAgent>& client,
VoidFunction before_finished)
: server_(server),
client_(client),
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_.lock()->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_.lock()->Handshake();
before_finished_();
break;
default:
break;
}
return KEEP;
}
private:
std::weak_ptr<TlsAgent> server_;
std::weak_ptr<TlsAgent> client_;
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);
MakeTlsFilter<BeforeFinished13>(server_, client_, [this]() {
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
});
Connect();
}
// 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_P(TlsConnectTls13, AuthCompleteAfterFinished) {
SetDeferredAuthCertificateCallback(client_, 0); // 0 = success.
Connect();
}
TEST_P(TlsConnectGenericPre13, ClientWriteBetweenCCSAndFinishedWithFalseStart) {
client_->EnableFalseStart();
MakeTlsFilter<BeforeFinished>(
server_, client_,
[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);
MakeTlsFilter<BeforeFinished>(
server_, client_,
[]() {
// 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);
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_->SetFilter(std::make_shared<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 filter before closing or the close_notify alert will trigger it.
client_->ClearFilter();
}
TEST_P(TlsConnectGenericPre13, AuthCompleteFailDelayed) {
client_->SetAuthCertificateCallback(AuthCompleteBlock);
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_->SetFilter(std::make_shared<EnforceNoActivity>());
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
// Report failure.
client_->ClearFilter();
client_->ExpectSendAlert(kTlsAlertBadCertificate);
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(),
SSL_ERROR_BAD_CERTIFICATE));
client_->Handshake(); // Fail
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
}
// TLS 1.3 handles a delayed AuthComplete callback differently since the
// shape of the handshake is different.
TEST_P(TlsConnectTls13, AuthCompleteDelayed) {
client_->SetAuthCertificateCallback(AuthCompleteBlock);
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_->SetFilter(std::make_shared<EnforceNoActivity>());
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
// This should allow the handshake to complete now.
client_->ClearFilter();
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());
}
TEST_P(TlsConnectTls13, AuthCompleteFailDelayed) {
client_->SetAuthCertificateCallback(AuthCompleteBlock);
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_->SetFilter(std::make_shared<EnforceNoActivity>());
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
// Report failure.
client_->ClearFilter();
ExpectAlert(client_, kTlsAlertBadCertificate);
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(),
SSL_ERROR_BAD_CERTIFICATE));
client_->Handshake(); // This should now fail.
server_->Handshake(); // Get the error.
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
}
static SECStatus AuthCompleteFail(TlsAgent*, PRBool, PRBool) {
PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
return SECFailure;
}
TEST_P(TlsConnectGeneric, AuthFailImmediate) {
client_->SetAuthCertificateCallback(AuthCompleteFail);
StartConnect();
ConnectExpectAlert(client_, kTlsAlertBadCertificate);
client_->CheckErrorCode(SSL_ERROR_BAD_CERTIFICATE);
}
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Decrypt = {
ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr, nullptr, nullptr};
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Sign = {
ssl_auth_rsa_sign, nullptr, nullptr, nullptr, nullptr, nullptr};
static const SSLExtraServerCertData ServerCertDataRsaPss = {
ssl_auth_rsa_pss, nullptr, nullptr, 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_FALSE(SSLInt_HasCertWithAuthType(ssl_fd, ssl_auth_rsa_pss));
// Configuring for only rsa_sign or rsa_decrypt should work.
EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsa, false,
&ServerCertDataRsaPkcs1Decrypt));
EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsa, false,
&ServerCertDataRsaPkcs1Sign));
EXPECT_FALSE(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_FALSE(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 should work.
EXPECT_TRUE(agent_->ConfigServerCert(TlsAgent::kServerRsaSign, false,
&ServerCertDataRsaPkcs1Sign));
EXPECT_FALSE(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));
}
// A server should refuse to even start a handshake with
// misconfigured certificate and signature scheme.
TEST_P(TlsConnectTls12Plus, MisconfiguredCertScheme) {
Reset(TlsAgent::kServerDsa);
static const SSLSignatureScheme kScheme[] = {ssl_sig_ecdsa_secp256r1_sha256};
server_->SetSignatureSchemes(kScheme, PR_ARRAY_SIZE(kScheme));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
if (version_ < SSL_LIBRARY_VERSION_TLS_1_3) {
// TLS 1.2 disables cipher suites, which leads to a different error.
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
} else {
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
// In TLS 1.2, disabling an EC group causes ECDSA to be invalid.
TEST_P(TlsConnectTls12, Tls12CertDisabledGroup) {
Reset(TlsAgent::kServerEcdsa256);
static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
server_->ConfigNamedGroups(k25519);
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
// In TLS 1.3, ECDSA configuration only depends on the signature scheme.
TEST_P(TlsConnectTls13, Tls13CertDisabledGroup) {
Reset(TlsAgent::kServerEcdsa256);
static const std::vector<SSLNamedGroup> k25519 = {ssl_grp_ec_curve25519};
server_->ConfigNamedGroups(k25519);
Connect();
}
// A client should refuse to even start a handshake with only DSA.
TEST_P(TlsConnectTls13, Tls13DsaOnlyClient) {
static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
client_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
client_->StartConnect();
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
TEST_P(TlsConnectTls13, Tls13DsaOnlyServer) {
Reset(TlsAgent::kServerDsa);
static const SSLSignatureScheme kDsa[] = {ssl_sig_dsa_sha256};
server_->SetSignatureSchemes(kDsa, PR_ARRAY_SIZE(kDsa));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyClient) {
static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
client_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
client_->StartConnect();
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
}
TEST_P(TlsConnectTls13, Tls13Pkcs1OnlyServer) {
static const SSLSignatureScheme kPkcs1[] = {ssl_sig_rsa_pkcs1_sha256};
server_->SetSignatureSchemes(kPkcs1, PR_ARRAY_SIZE(kPkcs1));
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
server_->CheckErrorCode(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
}
TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedClient) {
EnsureTlsSetup();
static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
ssl_sig_rsa_pss_rsae_sha256};
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
auto capture =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
Connect();
// We should only have the one signature algorithm advertised.
static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
ssl_sig_rsa_pss_rsae_sha256 & 0xff};
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
capture->extension());
}
TEST_P(TlsConnectTls13, Tls13DsaIsNotAdvertisedServer) {
EnsureTlsSetup();
static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256,
ssl_sig_rsa_pss_rsae_sha256};
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
auto capture = MakeTlsFilter<TlsExtensionCapture>(
server_, ssl_signature_algorithms_xtn, true);
capture->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
capture->EnableDecryption();
server_->RequestClientAuth(false); // So we get a CertificateRequest.
Connect();
// We should only have the one signature algorithm advertised.
static const uint8_t kExpectedExt[] = {0, 2, ssl_sig_rsa_pss_rsae_sha256 >> 8,
ssl_sig_rsa_pss_rsae_sha256 & 0xff};
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
capture->extension());
}
TEST_P(TlsConnectTls13, Tls13RsaPkcs1IsAdvertisedClient) {
EnsureTlsSetup();
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pkcs1_sha256,
ssl_sig_rsa_pss_rsae_sha256};
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
auto capture =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
Connect();
// We should only have the one signature algorithm advertised.
static const uint8_t kExpectedExt[] = {0,
4,
ssl_sig_rsa_pss_rsae_sha256 >> 8,
ssl_sig_rsa_pss_rsae_sha256 & 0xff,
ssl_sig_rsa_pkcs1_sha256 >> 8,
ssl_sig_rsa_pkcs1_sha256 & 0xff};
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
capture->extension());
}
TEST_P(TlsConnectTls13, Tls13RsaPkcs1IsAdvertisedServer) {
EnsureTlsSetup();
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pkcs1_sha256,
ssl_sig_rsa_pss_rsae_sha256};
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
auto capture = MakeTlsFilter<TlsExtensionCapture>(
server_, ssl_signature_algorithms_xtn, true);
capture->SetHandshakeTypes({kTlsHandshakeCertificateRequest});
capture->EnableDecryption();
server_->RequestClientAuth(false); // So we get a CertificateRequest.
Connect();
// We should only have the one signature algorithm advertised.
static const uint8_t kExpectedExt[] = {0,
4,
ssl_sig_rsa_pss_rsae_sha256 >> 8,
ssl_sig_rsa_pss_rsae_sha256 & 0xff,
ssl_sig_rsa_pkcs1_sha256 >> 8,
ssl_sig_rsa_pkcs1_sha256 & 0xff};
ASSERT_EQ(DataBuffer(kExpectedExt, sizeof(kExpectedExt)),
capture->extension());
}
// variant, version, certificate, auth type, signature scheme
typedef std::tuple<SSLProtocolVariant, 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(std::shared_ptr<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_);
auto capture =
MakeTlsFilter<TlsExtensionCapture>(client_, ssl_signature_algorithms_xtn);
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_);
}
class Tls12CertificateRequestReplacer : public TlsHandshakeFilter {
public:
Tls12CertificateRequestReplacer(const std::shared_ptr<TlsAgent>& a,
SSLSignatureScheme scheme)
: TlsHandshakeFilter(a, {kTlsHandshakeCertificateRequest}),
scheme_(scheme) {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output) {
uint32_t offset = 0;
if (header.handshake_type() != ssl_hs_certificate_request) {
return KEEP;
}
*output = input;
uint32_t types_len = 0;
if (!output->Read(offset, 1, &types_len)) {
ADD_FAILURE();
return KEEP;
}
offset += 1 + types_len;
uint32_t scheme_len = 0;
if (!output->Read(offset, 2, &scheme_len)) {
ADD_FAILURE();
return KEEP;
}
DataBuffer schemes;
schemes.Write(0, 2, 2);
schemes.Write(2, scheme_, 2);
output->Write(offset, 2, schemes.len());
output->Splice(schemes, offset + 2, scheme_len);
return CHANGE;
}
private:
SSLSignatureScheme scheme_;
};
//
// Test how policy interacts with client auth connections
//
// TLS/DTLS version algorithm policy
typedef std::tuple<SSLProtocolVariant, uint16_t, SECOidTag, PRUint32>
PolicySignatureSchemeProfile;
// Only TLS 1.2 handles client auth schemes inside
// the certificate request packet, so our failure tests for
// those kinds of connections only occur here.
class TlsConnectAuthWithPolicyTls12
: public TlsConnectTestBase,
public ::testing::WithParamInterface<PolicySignatureSchemeProfile> {
public:
TlsConnectAuthWithPolicyTls12()
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
alg_ = std::get<2>(GetParam());
policy_ = std::get<3>(GetParam());
// use the algorithm to select which single scheme to deploy
// We use these schemes to force servers sending schemes the client
// didn't advertise to make sure the client will still filter these
// by policy and detect that no valid schemes were presented, rather
// than sending an empty client auth message.
switch (alg_) {
case SEC_OID_SHA256:
case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
scheme_ = ssl_sig_rsa_pss_pss_sha256;
break;
case SEC_OID_PKCS1_RSA_ENCRYPTION:
scheme_ = ssl_sig_rsa_pkcs1_sha256;
break;
case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
scheme_ = ssl_sig_ecdsa_secp256r1_sha256;
break;
default:
ADD_FAILURE() << "need to update algorithm table in "
"TlsConnectAuthWithPolicyTls12";
scheme_ = ssl_sig_none;
break;
}
}
protected:
SECOidTag alg_;
PRUint32 policy_;
SSLSignatureScheme scheme_;
};
// Only TLS 1.2 and greater looks at schemes extensions on client auth
class TlsConnectAuthWithPolicyTls12Plus
: public TlsConnectTestBase,
public ::testing::WithParamInterface<PolicySignatureSchemeProfile> {
public:
TlsConnectAuthWithPolicyTls12Plus()
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {
alg_ = std::get<2>(GetParam());
policy_ = std::get<3>(GetParam());
}
protected:
SECOidTag alg_;
PRUint32 policy_;
};
// make sure we can turn single algorithms off by policy an still connect
// this is basically testing that we are properly filtering our schemes
// by policy before communicating them to the server, and that the
// server is respecting our choices
TEST_P(TlsConnectAuthWithPolicyTls12Plus, PolicySuccessTest) {
// in TLS 1.3, RSA PKCS1 is restricted. If we are also
// restricting RSA PSS by policy, we can't use the default
// RSA certificate as the server cert, switch to ECDSA
if ((version_ >= SSL_LIBRARY_VERSION_TLS_1_3) &&
(alg_ == SEC_OID_PKCS1_RSA_PSS_SIGNATURE)) {
Reset(TlsAgent::kServerEcdsa256);
}
client_->SetPolicy(alg_, 0, policy_); // Disable policy for client
client_->SetupClientAuth();
server_->RequestClientAuth(false);
Connect();
}
// make sure we fail if the server ignores our policy preference and
// requests client auth with a scheme we don't support
TEST_P(TlsConnectAuthWithPolicyTls12, PolicyFailureTest) {
client_->SetPolicy(alg_, 0, policy_);
client_->SetupClientAuth();
server_->RequestClientAuth(false);
MakeTlsFilter<Tls12CertificateRequestReplacer>(server_, scheme_);
ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
server_->CheckErrorCode(SSL_ERROR_HANDSHAKE_FAILURE_ALERT);
}
INSTANTIATE_TEST_SUITE_P(
SignaturesWithPolicyFail, TlsConnectAuthWithPolicyTls12,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12,
::testing::Values(SEC_OID_SHA256,
SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
SEC_OID_PKCS1_RSA_ENCRYPTION,
SEC_OID_ANSIX962_EC_PUBLIC_KEY),
::testing::Values(NSS_USE_ALG_IN_SSL_KX,
NSS_USE_ALG_IN_ANY_SIGNATURE)));
INSTANTIATE_TEST_SUITE_P(
SignaturesWithPolicySuccess, TlsConnectAuthWithPolicyTls12Plus,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(SEC_OID_SHA256,
SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
SEC_OID_PKCS1_RSA_ENCRYPTION,
SEC_OID_ANSIX962_EC_PUBLIC_KEY),
::testing::Values(NSS_USE_ALG_IN_SSL_KX,
NSS_USE_ALG_IN_ANY_SIGNATURE)));
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeRsa, TlsSignatureSchemeConfiguration,
::testing::Combine(
TlsConnectTestBase::kTlsVariantsAll, TlsConnectTestBase::kTlsV12,
::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_rsae_sha256,
ssl_sig_rsa_pss_rsae_sha384)));
// RSASSA-PKCS1-v1_5 is not allowed to be used in TLS 1.3
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeRsaTls13, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV13,
::testing::Values(TlsAgent::kServerRsaSign),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pss_rsae_sha256,
ssl_sig_rsa_pss_rsae_sha384)));
// PSS with SHA-512 needs a bigger key to work.
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeBigRsa, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kRsa2048),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pss_rsae_sha512)));
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeRsaSha1, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12,
::testing::Values(TlsAgent::kServerRsa),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pkcs1_sha1)));
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeEcdsaP256, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kServerEcdsa256),
::testing::Values(ssl_auth_ecdsa),
::testing::Values(ssl_sig_ecdsa_secp256r1_sha256)));
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeEcdsaP384, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kServerEcdsa384),
::testing::Values(ssl_auth_ecdsa),
::testing::Values(ssl_sig_ecdsa_secp384r1_sha384)));
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeEcdsaP521, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kServerEcdsa521),
::testing::Values(ssl_auth_ecdsa),
::testing::Values(ssl_sig_ecdsa_secp521r1_sha512)));
INSTANTIATE_TEST_SUITE_P(
SignatureSchemeEcdsaSha1, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12,
::testing::Values(TlsAgent::kServerEcdsa256,
TlsAgent::kServerEcdsa384),
::testing::Values(ssl_auth_ecdsa),
::testing::Values(ssl_sig_ecdsa_sha1)));
} // namespace nss_test