зеркало из https://github.com/mozilla/gecko-dev.git
754 строки
28 KiB
C++
754 строки
28 KiB
C++
/* -*- 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 <functional>
|
|
#include <memory>
|
|
#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(TlsConnectGenericPre13, ConnectEcdh) {
|
|
SetExpectedVersion(std::get<1>(GetParam()));
|
|
Reset(TlsAgent::kServerEcdhEcdsa);
|
|
DisableAllCiphers();
|
|
EnableSomeEcdhCiphers();
|
|
|
|
Connect();
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_ecdh_ecdsa,
|
|
ssl_sig_none);
|
|
}
|
|
|
|
TEST_P(TlsConnectGenericPre13, ConnectEcdhWithoutDisablingSuites) {
|
|
SetExpectedVersion(std::get<1>(GetParam()));
|
|
Reset(TlsAgent::kServerEcdhEcdsa);
|
|
EnableSomeEcdhCiphers();
|
|
|
|
Connect();
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_ecdh_ecdsa,
|
|
ssl_sig_none);
|
|
}
|
|
|
|
TEST_P(TlsConnectGeneric, ConnectEcdhe) {
|
|
Connect();
|
|
CheckKeys();
|
|
}
|
|
|
|
// If we pick a 256-bit cipher suite and use a P-384 certificate, the server
|
|
// should choose P-384 for key exchange too. Only valid for TLS == 1.2 because
|
|
// we don't have 256-bit ciphers before then and 1.3 doesn't try to couple
|
|
// DHE size to symmetric size.
|
|
TEST_P(TlsConnectTls12, ConnectEcdheP384) {
|
|
Reset(TlsAgent::kServerEcdsa384);
|
|
ConnectWithCipherSuite(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_ecdsa,
|
|
ssl_sig_ecdsa_secp256r1_sha256);
|
|
}
|
|
|
|
TEST_P(TlsConnectGeneric, ConnectEcdheP384Client) {
|
|
EnsureTlsSetup();
|
|
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1,
|
|
ssl_grp_ffdhe_2048};
|
|
client_->ConfigNamedGroups(groups);
|
|
server_->ConfigNamedGroups(groups);
|
|
Connect();
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
}
|
|
|
|
// This causes a HelloRetryRequest in TLS 1.3. Earlier versions don't care.
|
|
TEST_P(TlsConnectGeneric, ConnectEcdheP384Server) {
|
|
EnsureTlsSetup();
|
|
auto hrr_capture = MakeTlsFilter<TlsHandshakeRecorder>(
|
|
server_, kTlsHandshakeHelloRetryRequest);
|
|
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp384r1};
|
|
server_->ConfigNamedGroups(groups);
|
|
Connect();
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
EXPECT_EQ(version_ == SSL_LIBRARY_VERSION_TLS_1_3,
|
|
hrr_capture->buffer().len() != 0);
|
|
}
|
|
|
|
// This enables only P-256 on the client and disables it on the server.
|
|
// This test will fail when we add other groups that identify as ECDHE.
|
|
TEST_P(TlsConnectGeneric, ConnectEcdheGroupMismatch) {
|
|
EnsureTlsSetup();
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1,
|
|
ssl_grp_ffdhe_2048};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ffdhe_2048};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
CheckKeys(ssl_kea_dh, ssl_auth_rsa_sign);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest, P384Priority) {
|
|
// P256, P384 and P521 are enabled. Both prefer P384.
|
|
const std::vector<SSLNamedGroup> groups = {
|
|
ssl_grp_ec_secp384r1, ssl_grp_ec_secp256r1, ssl_grp_ec_secp521r1};
|
|
EnsureKeyShareSetup();
|
|
ConfigNamedGroups(groups);
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
|
|
std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp384r1};
|
|
CheckKEXDetails(groups, shares);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest, DuplicateGroupConfig) {
|
|
const std::vector<SSLNamedGroup> groups = {
|
|
ssl_grp_ec_secp384r1, ssl_grp_ec_secp384r1, ssl_grp_ec_secp384r1,
|
|
ssl_grp_ec_secp256r1, ssl_grp_ec_secp256r1};
|
|
EnsureKeyShareSetup();
|
|
ConfigNamedGroups(groups);
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
|
|
std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp384r1};
|
|
std::vector<SSLNamedGroup> expectedGroups = {ssl_grp_ec_secp384r1,
|
|
ssl_grp_ec_secp256r1};
|
|
CheckKEXDetails(expectedGroups, shares);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest, P384PriorityDHEnabled) {
|
|
// P256, P384, P521, and FFDHE2048 are enabled. Both prefer P384.
|
|
const std::vector<SSLNamedGroup> groups = {
|
|
ssl_grp_ec_secp384r1, ssl_grp_ffdhe_2048, ssl_grp_ec_secp256r1,
|
|
ssl_grp_ec_secp521r1};
|
|
EnsureKeyShareSetup();
|
|
ConfigNamedGroups(groups);
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
|
|
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
|
|
std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp384r1};
|
|
CheckKEXDetails(groups, shares);
|
|
} else {
|
|
std::vector<SSLNamedGroup> oldtlsgroups = {
|
|
ssl_grp_ec_secp384r1, ssl_grp_ec_secp256r1, ssl_grp_ec_secp521r1};
|
|
CheckKEXDetails(oldtlsgroups, std::vector<SSLNamedGroup>());
|
|
}
|
|
}
|
|
|
|
TEST_P(TlsConnectGenericPre13, P384PriorityOnServer) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
// The server prefers P384. It has to win.
|
|
const std::vector<SSLNamedGroup> server_groups = {
|
|
ssl_grp_ec_secp384r1, ssl_grp_ec_secp256r1, ssl_grp_ec_secp521r1};
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
}
|
|
|
|
TEST_P(TlsConnectGenericPre13, P384PriorityFromModelSocket) {
|
|
EnsureModelSockets();
|
|
|
|
/* Both prefer P384, set on the model socket. */
|
|
const std::vector<SSLNamedGroup> groups = {
|
|
ssl_grp_ec_secp384r1, ssl_grp_ec_secp256r1, ssl_grp_ec_secp521r1,
|
|
ssl_grp_ffdhe_2048};
|
|
client_model_->ConfigNamedGroups(groups);
|
|
server_model_->ConfigNamedGroups(groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
}
|
|
|
|
class TlsKeyExchangeGroupCapture : public TlsHandshakeFilter {
|
|
public:
|
|
TlsKeyExchangeGroupCapture(const std::shared_ptr<TlsAgent> &a)
|
|
: TlsHandshakeFilter(a, {kTlsHandshakeServerKeyExchange}),
|
|
group_(ssl_grp_none) {}
|
|
|
|
SSLNamedGroup group() const { return group_; }
|
|
|
|
protected:
|
|
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
|
|
const DataBuffer &input,
|
|
DataBuffer *output) {
|
|
uint32_t value = 0;
|
|
EXPECT_TRUE(input.Read(0, 1, &value));
|
|
EXPECT_EQ(3U, value) << "curve type has to be 3";
|
|
|
|
EXPECT_TRUE(input.Read(1, 2, &value));
|
|
group_ = static_cast<SSLNamedGroup>(value);
|
|
|
|
return KEEP;
|
|
}
|
|
|
|
private:
|
|
SSLNamedGroup group_;
|
|
};
|
|
|
|
// If we strip the client's supported groups extension, the server should assume
|
|
// P-256 is supported by the client (<= 1.2 only).
|
|
TEST_P(TlsConnectGenericPre13, DropSupportedGroupExtensionP256) {
|
|
EnsureTlsSetup();
|
|
MakeTlsFilter<TlsExtensionDropper>(client_, ssl_supported_groups_xtn);
|
|
auto group_capture = MakeTlsFilter<TlsKeyExchangeGroupCapture>(server_);
|
|
|
|
ConnectExpectAlert(server_, kTlsAlertDecryptError);
|
|
client_->CheckErrorCode(SSL_ERROR_DECRYPT_ERROR_ALERT);
|
|
server_->CheckErrorCode(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
|
|
|
|
EXPECT_EQ(ssl_grp_ec_secp256r1, group_capture->group());
|
|
}
|
|
|
|
// Supported groups is mandatory in TLS 1.3.
|
|
TEST_P(TlsConnectTls13, DropSupportedGroupExtension) {
|
|
EnsureTlsSetup();
|
|
MakeTlsFilter<TlsExtensionDropper>(client_, ssl_supported_groups_xtn);
|
|
ConnectExpectAlert(server_, kTlsAlertMissingExtension);
|
|
client_->CheckErrorCode(SSL_ERROR_MISSING_EXTENSION_ALERT);
|
|
server_->CheckErrorCode(SSL_ERROR_MISSING_SUPPORTED_GROUPS_EXTENSION);
|
|
}
|
|
|
|
// If we only have a lame group, we fall back to static RSA.
|
|
TEST_P(TlsConnectGenericPre13, UseLameGroup) {
|
|
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_secp192r1};
|
|
client_->ConfigNamedGroups(groups);
|
|
server_->ConfigNamedGroups(groups);
|
|
Connect();
|
|
CheckKeys(ssl_kea_rsa, ssl_grp_none, ssl_auth_rsa_decrypt, ssl_sig_none);
|
|
}
|
|
|
|
// In TLS 1.3, we can't generate the ClientHello.
|
|
TEST_P(TlsConnectTls13, UseLameGroup) {
|
|
const std::vector<SSLNamedGroup> groups = {ssl_grp_ec_sect283k1};
|
|
client_->ConfigNamedGroups(groups);
|
|
server_->ConfigNamedGroups(groups);
|
|
client_->StartConnect();
|
|
client_->Handshake();
|
|
client_->CheckErrorCode(SSL_ERROR_NO_CIPHERS_SUPPORTED);
|
|
}
|
|
|
|
TEST_P(TlsConnectStreamPre13, ConfiguredGroupsRenegotiate) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_secp256r1,
|
|
ssl_grp_ec_secp256r1};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
CheckConnected();
|
|
|
|
// The renegotiation has to use the same preferences as the original session.
|
|
server_->PrepareForRenegotiate();
|
|
client_->StartRenegotiate();
|
|
Handshake();
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest, Curve25519) {
|
|
Reset(TlsAgent::kServerEcdsa256);
|
|
const std::vector<SSLNamedGroup> groups = {
|
|
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp521r1};
|
|
EnsureKeyShareSetup();
|
|
ConfigNamedGroups(groups);
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_ecdsa,
|
|
ssl_sig_ecdsa_secp256r1_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
|
|
CheckKEXDetails(groups, shares);
|
|
}
|
|
|
|
TEST_P(TlsConnectGenericPre13, GroupPreferenceServerPriority) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
// The client prefers P256 while the server prefers 25519.
|
|
// The server's preference has to win.
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1,
|
|
ssl_grp_ec_curve25519};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_curve25519,
|
|
ssl_grp_ec_secp256r1};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
}
|
|
|
|
#ifndef NSS_DISABLE_TLS_1_3
|
|
TEST_P(TlsKeyExchangeTest13, Curve25519P256EqualPriorityClient13) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// The client sends a P256 key share while the server prefers 25519.
|
|
// We have to accept P256 without retry.
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1,
|
|
ssl_grp_ec_curve25519};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_curve25519,
|
|
ssl_grp_ec_secp256r1};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp256r1};
|
|
CheckKEXDetails(client_groups, shares);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest13, Curve25519P256EqualPriorityServer13) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// The client sends a 25519 key share while the server prefers P256.
|
|
// We have to accept 25519 without retry.
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_curve25519,
|
|
ssl_grp_ec_secp256r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_secp256r1,
|
|
ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
|
|
CheckKEXDetails(client_groups, shares);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest13, EqualPriorityTestRetryECServer13) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// The client sends a 25519 key share while the server prefers P256.
|
|
// The server prefers P-384 over x25519, so it must not consider P-256 and
|
|
// x25519 to be equivalent. It will therefore request a P-256 share
|
|
// with a HelloRetryRequest.
|
|
const std::vector<SSLNamedGroup> client_groups = {
|
|
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {
|
|
ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
|
|
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest13, NotEqualPriorityWithIntermediateGroup13) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// The client sends a 25519 key share while the server prefers P256.
|
|
// The server prefers ffdhe_2048 over x25519, so it must not consider the
|
|
// P-256 and x25519 to be equivalent. It will therefore request a P-256 share
|
|
// with a HelloRetryRequest.
|
|
const std::vector<SSLNamedGroup> client_groups = {
|
|
ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ffdhe_2048};
|
|
const std::vector<SSLNamedGroup> server_groups = {
|
|
ssl_grp_ec_secp256r1, ssl_grp_ffdhe_2048, ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
|
|
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest13,
|
|
NotEqualPriorityWithUnsupportedFFIntermediateGroup13) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// As in the previous test, the server prefers ffdhe_2048. Thus, even though
|
|
// the client doesn't support this group, the server must not regard x25519 as
|
|
// equivalent to P-256.
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_curve25519,
|
|
ssl_grp_ec_secp256r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {
|
|
ssl_grp_ec_secp256r1, ssl_grp_ffdhe_2048, ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
|
|
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest13,
|
|
NotEqualPriorityWithUnsupportedECIntermediateGroup13) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// As in the previous test, the server prefers P-384. Thus, even though
|
|
// the client doesn't support this group, the server must not regard x25519 as
|
|
// equivalent to P-256. The server sends a HelloRetryRequest.
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_curve25519,
|
|
ssl_grp_ec_secp256r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {
|
|
ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1, ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
|
|
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest13, EqualPriority13) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// The client sends a 25519 key share while the server prefers P256.
|
|
// We have to accept 25519 without retry because it's considered equivalent to
|
|
// P256 by the server.
|
|
const std::vector<SSLNamedGroup> client_groups = {
|
|
ssl_grp_ec_curve25519, ssl_grp_ffdhe_2048, ssl_grp_ec_secp256r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_secp256r1,
|
|
ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
Connect();
|
|
|
|
CheckKeys();
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
|
|
CheckKEXDetails(client_groups, shares);
|
|
}
|
|
#endif
|
|
|
|
TEST_P(TlsConnectGeneric, P256ClientAndCurve25519Server) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
// The client sends a P256 key share while the server prefers 25519.
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_secp256r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_curve25519};
|
|
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
ConnectExpectAlert(server_, kTlsAlertHandshakeFailure);
|
|
client_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
|
server_->CheckErrorCode(SSL_ERROR_NO_CYPHER_OVERLAP);
|
|
}
|
|
|
|
TEST_P(TlsKeyExchangeTest13, MultipleClientShares) {
|
|
EnsureKeyShareSetup();
|
|
|
|
// The client sends 25519 and P256 key shares. The server prefers P256,
|
|
// which must be chosen here.
|
|
const std::vector<SSLNamedGroup> client_groups = {ssl_grp_ec_curve25519,
|
|
ssl_grp_ec_secp256r1};
|
|
const std::vector<SSLNamedGroup> server_groups = {ssl_grp_ec_secp256r1,
|
|
ssl_grp_ec_curve25519};
|
|
client_->ConfigNamedGroups(client_groups);
|
|
server_->ConfigNamedGroups(server_groups);
|
|
|
|
// Generate a key share on the client for both curves.
|
|
EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
|
|
|
|
Connect();
|
|
|
|
// The server would accept 25519 but its preferred group (P256) has to win.
|
|
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
|
|
ssl_sig_rsa_pss_rsae_sha256);
|
|
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519,
|
|
ssl_grp_ec_secp256r1};
|
|
CheckKEXDetails(client_groups, shares);
|
|
}
|
|
|
|
// Replace the point in the client key exchange message with an empty one
|
|
class ECCClientKEXFilter : public TlsHandshakeFilter {
|
|
public:
|
|
ECCClientKEXFilter(const std::shared_ptr<TlsAgent> &client)
|
|
: TlsHandshakeFilter(client, {kTlsHandshakeClientKeyExchange}) {}
|
|
|
|
protected:
|
|
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
|
|
const DataBuffer &input,
|
|
DataBuffer *output) {
|
|
// Replace the client key exchange message with an empty point
|
|
output->Allocate(1);
|
|
output->Write(0, 0U, 1); // set point length 0
|
|
return CHANGE;
|
|
}
|
|
};
|
|
|
|
// Replace the point in the server key exchange message with an empty one
|
|
class ECCServerKEXFilter : public TlsHandshakeFilter {
|
|
public:
|
|
ECCServerKEXFilter(const std::shared_ptr<TlsAgent> &server)
|
|
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}) {}
|
|
|
|
protected:
|
|
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
|
|
const DataBuffer &input,
|
|
DataBuffer *output) {
|
|
// Replace the server key exchange message with an empty point
|
|
output->Allocate(4);
|
|
output->Write(0, 3U, 1); // named curve
|
|
uint32_t curve = 0;
|
|
EXPECT_TRUE(input.Read(1, 2, &curve)); // get curve id
|
|
output->Write(1, curve, 2); // write curve id
|
|
output->Write(3, 0U, 1); // point length 0
|
|
return CHANGE;
|
|
}
|
|
};
|
|
|
|
TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyServerPoint) {
|
|
MakeTlsFilter<ECCServerKEXFilter>(server_);
|
|
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
|
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH);
|
|
}
|
|
|
|
TEST_P(TlsConnectGenericPre13, ConnectECDHEmptyClientPoint) {
|
|
MakeTlsFilter<ECCClientKEXFilter>(client_);
|
|
ConnectExpectAlert(server_, kTlsAlertIllegalParameter);
|
|
server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH);
|
|
}
|
|
|
|
// Damage ECParams/ECPoint of a SKE.
|
|
class ECCServerKEXDamager : public TlsHandshakeFilter {
|
|
public:
|
|
ECCServerKEXDamager(const std::shared_ptr<TlsAgent> &server, ECType ec_type,
|
|
SSLNamedGroup named_curve)
|
|
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
|
|
ec_type_(ec_type),
|
|
named_curve_(named_curve) {}
|
|
|
|
protected:
|
|
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
|
|
const DataBuffer &input,
|
|
DataBuffer *output) {
|
|
size_t offset = 0;
|
|
output->Allocate(5);
|
|
offset = output->Write(offset, ec_type_, 1);
|
|
offset = output->Write(offset, named_curve_, 2);
|
|
// Write a point with fmt != EC_POINT_FORM_UNCOMPRESSED.
|
|
offset = output->Write(offset, 1U, 1);
|
|
(void)output->Write(offset, 0x02, 1); // EC_POINT_FORM_COMPRESSED_Y0
|
|
return CHANGE;
|
|
}
|
|
|
|
private:
|
|
ECType ec_type_;
|
|
SSLNamedGroup named_curve_;
|
|
};
|
|
|
|
TEST_P(TlsConnectGenericPre13, ConnectUnsupportedCurveType) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_explicitPrime,
|
|
ssl_grp_none);
|
|
ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
|
|
client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
|
}
|
|
|
|
TEST_P(TlsConnectGenericPre13, ConnectUnsupportedCurve) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_named,
|
|
ssl_grp_ffdhe_2048);
|
|
ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
|
|
client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
|
}
|
|
|
|
TEST_P(TlsConnectGenericPre13, ConnectUnsupportedPointFormat) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
MakeTlsFilter<ECCServerKEXDamager>(server_, ec_type_named,
|
|
ssl_grp_ec_secp256r1);
|
|
ConnectExpectAlert(client_, kTlsAlertHandshakeFailure);
|
|
client_->CheckErrorCode(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
|
|
}
|
|
|
|
// Replace SignatureAndHashAlgorithm of a SKE.
|
|
class ECCServerKEXSigAlgReplacer : public TlsHandshakeFilter {
|
|
public:
|
|
ECCServerKEXSigAlgReplacer(const std::shared_ptr<TlsAgent> &server,
|
|
SSLSignatureScheme sig_scheme)
|
|
: TlsHandshakeFilter(server, {kTlsHandshakeServerKeyExchange}),
|
|
sig_scheme_(sig_scheme) {}
|
|
|
|
protected:
|
|
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader &header,
|
|
const DataBuffer &input,
|
|
DataBuffer *output) {
|
|
*output = input;
|
|
|
|
uint32_t point_len;
|
|
EXPECT_TRUE(output->Read(3, 1, &point_len));
|
|
output->Write(4 + point_len, sig_scheme_, 2);
|
|
|
|
return CHANGE;
|
|
}
|
|
|
|
private:
|
|
SSLSignatureScheme sig_scheme_;
|
|
};
|
|
|
|
TEST_P(TlsConnectTls12, ConnectUnsupportedSigAlg) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
MakeTlsFilter<ECCServerKEXSigAlgReplacer>(server_, ssl_sig_none);
|
|
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
|
client_->CheckErrorCode(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
}
|
|
|
|
TEST_P(TlsConnectTls12, ConnectIncorrectSigAlg) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
MakeTlsFilter<ECCServerKEXSigAlgReplacer>(server_,
|
|
ssl_sig_ecdsa_secp256r1_sha256);
|
|
ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
|
|
client_->CheckErrorCode(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
|
|
}
|
|
|
|
static void CheckSkeSigScheme(
|
|
std::shared_ptr<TlsHandshakeRecorder> &capture_ske,
|
|
uint16_t expected_scheme) {
|
|
TlsParser parser(capture_ske->buffer());
|
|
uint32_t tmp = 0;
|
|
EXPECT_TRUE(parser.Read(&tmp, 1)) << " read curve_type";
|
|
EXPECT_EQ(3U, tmp) << "curve type has to be 3";
|
|
EXPECT_TRUE(parser.Skip(2)) << " read namedcurve";
|
|
EXPECT_TRUE(parser.SkipVariable(1)) << " read public";
|
|
|
|
EXPECT_TRUE(parser.Read(&tmp, 2)) << " read sig_scheme";
|
|
EXPECT_EQ(expected_scheme, static_cast<uint16_t>(tmp));
|
|
}
|
|
|
|
TEST_P(TlsConnectTls12, ConnectSigAlgEnabledByPolicy) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
|
|
ssl_sig_rsa_pkcs1_sha384};
|
|
|
|
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
|
server_->SetSignatureSchemes(schemes.data(), schemes.size());
|
|
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
|
|
server_, kTlsHandshakeServerKeyExchange);
|
|
|
|
StartConnect();
|
|
client_->Handshake(); // Send ClientHello
|
|
|
|
// Enable SHA-1 by policy.
|
|
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, NSS_USE_ALG_IN_SSL_KX, 0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
|
0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
|
|
Handshake(); // Remainder of handshake
|
|
// The server should now report that it is connected
|
|
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
|
|
|
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha1);
|
|
}
|
|
|
|
TEST_P(TlsConnectTls12, ConnectSigAlgDisabledByPolicy) {
|
|
EnsureTlsSetup();
|
|
client_->DisableAllCiphers();
|
|
client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
|
|
|
|
const std::vector<SSLSignatureScheme> schemes = {ssl_sig_rsa_pkcs1_sha1,
|
|
ssl_sig_rsa_pkcs1_sha384};
|
|
|
|
client_->SetSignatureSchemes(schemes.data(), schemes.size());
|
|
server_->SetSignatureSchemes(schemes.data(), schemes.size());
|
|
auto capture_ske = MakeTlsFilter<TlsHandshakeRecorder>(
|
|
server_, kTlsHandshakeServerKeyExchange);
|
|
|
|
StartConnect();
|
|
client_->Handshake(); // Send ClientHello
|
|
|
|
// Disable SHA-1 by policy.
|
|
SECStatus rv = NSS_SetAlgorithmPolicy(SEC_OID_SHA1, 0, NSS_USE_ALG_IN_SSL_KX);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
rv = NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL,
|
|
0);
|
|
ASSERT_EQ(SECSuccess, rv);
|
|
|
|
Handshake(); // Remainder of handshake
|
|
// The server should now report that it is connected
|
|
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
|
|
|
|
CheckSkeSigScheme(capture_ske, ssl_sig_rsa_pkcs1_sha384);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
|
TlsConnectTestBase::kTlsV11Plus));
|
|
|
|
#ifndef NSS_DISABLE_TLS_1_3
|
|
INSTANTIATE_TEST_CASE_P(KeyExchangeTest, TlsKeyExchangeTest13,
|
|
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
|
|
TlsConnectTestBase::kTlsV13));
|
|
#endif
|
|
|
|
} // namespace nss_test
|