Skip to content

Commit

Permalink
Bug 1158489 - Enable signature algorithm configuration, r=wtc,ekr
Browse files Browse the repository at this point in the history
  • Loading branch information
martinthomson committed Aug 17, 2015
1 parent 718ebbc commit 7a9173a
Show file tree
Hide file tree
Showing 21 changed files with 876 additions and 345 deletions.
22 changes: 20 additions & 2 deletions external_tests/ssl_gtest/databuffer.h
Expand Up @@ -27,13 +27,13 @@ class DataBuffer {
Assign(data, len);
}
explicit DataBuffer(const DataBuffer& other) : data_(nullptr), len_(0) {
Assign(other.data(), other.len());
Assign(other);
}
~DataBuffer() { delete[] data_; }

DataBuffer& operator=(const DataBuffer& other) {
if (&other != this) {
Assign(other.data(), other.len());
Assign(other);
}
return *this;
}
Expand All @@ -48,6 +48,9 @@ class DataBuffer {
len_ = std::min(len_, len);
}

void Assign(const DataBuffer& other) {
Assign(other.data(), other.len());
}
void Assign(const uint8_t* data, size_t len) {
Allocate(len);
memcpy(static_cast<void *>(data_), static_cast<const void *>(data), len);
Expand Down Expand Up @@ -83,6 +86,21 @@ class DataBuffer {
Write(index, addr + sizeof(uint32_t) - count, count);
}

// This can't use the same trick as Write(), since we might be reading from a
// smaller data source.
bool Read(size_t index, size_t count, uint32_t* val) const {
assert(count < sizeof(uint32_t));
assert(val);
if ((index > len()) || (count > (len() - index))) {
return false;
}
*val = 0;
for (size_t i = 0; i < count; ++i) {
*val = (*val << 8) | data()[index + i];
}
return true;
}

// Starting at |index|, remove |remove| bytes and replace them with the
// contents of |buf|.
void Splice(const DataBuffer& buf, size_t index, size_t remove = 0) {
Expand Down
52 changes: 49 additions & 3 deletions external_tests/ssl_gtest/ssl_extension_unittest.cc
Expand Up @@ -196,8 +196,8 @@ class TlsExtensionReplacer : public TlsExtensionFilter {
return true;
}
private:
uint16_t extension_;
DataBuffer data_;
const uint16_t extension_;
const DataBuffer data_;
};

class TlsExtensionInjector : public TlsHandshakeFilter {
Expand Down Expand Up @@ -251,7 +251,27 @@ class TlsExtensionInjector : public TlsHandshakeFilter {
}

private:
uint16_t extension_;
const uint16_t extension_;
const DataBuffer data_;
};

class TlsExtensionCapture : public TlsExtensionFilter {
public:
TlsExtensionCapture(uint16_t ext)
: extension_(ext), data_() {}

virtual bool FilterExtension(uint16_t extension_type,
const DataBuffer& input, DataBuffer* output) {
if (extension_type == extension_) {
data_.Assign(input);
}
return false;
}

const DataBuffer& extension() const { return data_; }

private:
const uint16_t extension_;
DataBuffer data_;
};

Expand Down Expand Up @@ -562,6 +582,32 @@ TEST_P(TlsExtensionTestGeneric, RenegotiationInfoExtensionEmpty) {
extension));
}

TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmConfiguration) {
const SSLSignatureAndHashAlg algorithms[] = {
{ssl_hash_sha512, ssl_sign_rsa},
{ssl_hash_sha384, ssl_sign_ecdsa}
};

TlsExtensionCapture *capture =
new TlsExtensionCapture(ssl_signature_algorithms_xtn);
client_->SetSignatureAlgorithms(algorithms, PR_ARRAY_SIZE(algorithms));
client_->SetPacketFilter(capture);
DisableDheCiphers();
Connect();

const DataBuffer& ext = capture->extension();
EXPECT_EQ(2 + PR_ARRAY_SIZE(algorithms) * 2, ext.len());
for (size_t i = 0, cursor = 2;
i < PR_ARRAY_SIZE(algorithms) && cursor < ext.len();
++i) {
uint32_t v;
EXPECT_TRUE(ext.Read(cursor++, 1, &v));
EXPECT_EQ(algorithms[i].hashAlg, static_cast<SSLHashType>(v));
EXPECT_TRUE(ext.Read(cursor++, 1, &v));
EXPECT_EQ(algorithms[i].sigAlg, static_cast<SSLSignType>(v));
}
}

INSTANTIATE_TEST_CASE_P(ExtensionTls10, TlsExtensionTestGeneric,
::testing::Combine(
TlsConnectTestBase::kTlsModesStream,
Expand Down
119 changes: 117 additions & 2 deletions external_tests/ssl_gtest/ssl_loopback_unittest.cc
Expand Up @@ -182,6 +182,112 @@ TEST_P(TlsConnectGeneric, ResumeWithHigherVersion) {
Connect();
}

TEST_P(TlsConnectGeneric, ClientAuth) {
client_->SetupClientAuth();
server_->RequestClientAuth(true);
Connect();
server_->CheckAuthType(ssl_auth_rsa);
}

TEST_P(TlsConnectGeneric, ClientAuthEcdsa) {
ResetEcdsa();
client_->SetupClientAuth();
server_->RequestClientAuth(true);
Connect();
server_->CheckAuthType(ssl_auth_ecdsa);
}

static const SSLSignatureAndHashAlg SignatureEcdsaSha384[] = {
{ssl_hash_sha384, ssl_sign_ecdsa}
};
static const SSLSignatureAndHashAlg SignatureEcdsaSha256[] = {
{ssl_hash_sha256, ssl_sign_ecdsa}
};
static const SSLSignatureAndHashAlg SignatureRsaSha384[] = {
{ssl_hash_sha384, ssl_sign_rsa}
};
static const SSLSignatureAndHashAlg SignatureRsaSha256[] = {
{ssl_hash_sha256, ssl_sign_rsa}
};

// 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) {
client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
PR_ARRAY_SIZE(SignatureEcdsaSha384));
server_->SetSignatureAlgorithms(SignatureEcdsaSha384,
PR_ARRAY_SIZE(SignatureEcdsaSha384));
ResetEcdsa();
Connect();
}

// 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
};
client_->SetSignatureAlgorithms(clientAlgorithms,
PR_ARRAY_SIZE(clientAlgorithms));
ResetEcdsa();
Connect();
}

// 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) {
server_->SetSignatureAlgorithms(SignatureEcdsaSha384,
PR_ARRAY_SIZE(SignatureEcdsaSha384));
ResetEcdsa();
Connect();
}

// There is no need for overlap on signatures; since we don't actually use the
// signatures for static RSA, this should still connect successfully.
// This should also work in TLS 1.0 and 1.1 where the algorithms aren't used.
TEST_P(TlsConnectGeneric, SignatureAlgorithmNoOverlapStaticRsa) {
client_->SetSignatureAlgorithms(SignatureRsaSha384,
PR_ARRAY_SIZE(SignatureRsaSha384));
server_->SetSignatureAlgorithms(SignatureRsaSha256,
PR_ARRAY_SIZE(SignatureRsaSha256));
DisableDheCiphers();
Connect();
client_->CheckKEAType(ssl_kea_rsa);
client_->CheckAuthType(ssl_auth_rsa);
}

// Signature algorithms governs both verification and generation of signatures.
// With ECDSA, we need to at least have a common signature algorithm configured.
TEST_P(TlsConnectTls12, SignatureAlgorithmNoOverlapEcdsa) {
ResetEcdsa();
client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
PR_ARRAY_SIZE(SignatureEcdsaSha384));
server_->SetSignatureAlgorithms(SignatureEcdsaSha256,
PR_ARRAY_SIZE(SignatureEcdsaSha256));
ConnectExpectFail();
}

// Pre 1.2, a mismatch on signature algorithms shouldn't affect anything.
TEST_P(TlsConnectPre12, SignatureAlgorithmNoOverlapEcdsa) {
ResetEcdsa();
client_->SetSignatureAlgorithms(SignatureEcdsaSha384,
PR_ARRAY_SIZE(SignatureEcdsaSha384));
server_->SetSignatureAlgorithms(SignatureEcdsaSha256,
PR_ARRAY_SIZE(SignatureEcdsaSha256));
Connect();
}

// The server requests client auth but doesn't offer a SHA-256 option.
// This fails because NSS only uses SHA-256 for handshake transcript hashes.
TEST_P(TlsConnectTls12, RequestClientAuthWithoutSha256) {
server_->SetSignatureAlgorithms(SignatureRsaSha384,
PR_ARRAY_SIZE(SignatureRsaSha384));
server_->RequestClientAuth(false);
ConnectExpectFail();
}

TEST_P(TlsConnectGeneric, ConnectAlpn) {
EnableAlpn();
Connect();
Expand Down Expand Up @@ -295,8 +401,7 @@ TEST_P(TlsConnectDatagram, ShortRead) {
Connect();
client_->SetExpectedReadError(true);
server_->SendData(1200, 1200);
WAIT_(client_->error_code() == SSL_ERROR_RX_SHORT_DTLS_READ,
2000);
WAIT_(client_->error_code() == SSL_ERROR_RX_SHORT_DTLS_READ, 2000);
// Don't call CheckErrorCode() because it requires us to being
// in state ERROR.
ASSERT_EQ(SSL_ERROR_RX_SHORT_DTLS_READ, client_->error_code());
Expand Down Expand Up @@ -334,6 +439,16 @@ INSTANTIATE_TEST_CASE_P(VariantsAll, TlsConnectGeneric,
TlsConnectTestBase::kTlsV11V12));
INSTANTIATE_TEST_CASE_P(VersionsDatagram, TlsConnectDatagram,
TlsConnectTestBase::kTlsV11V12);
INSTANTIATE_TEST_CASE_P(Variants12, TlsConnectTls12,
TlsConnectTestBase::kTlsModesAll);
INSTANTIATE_TEST_CASE_P(Pre12Stream, TlsConnectPre12,
::testing::Combine(
TlsConnectTestBase::kTlsModesStream,
TlsConnectTestBase::kTlsV10));
INSTANTIATE_TEST_CASE_P(Pre12All, TlsConnectPre12,
::testing::Combine(
TlsConnectTestBase::kTlsModesAll,
TlsConnectTestBase::kTlsV11));
INSTANTIATE_TEST_CASE_P(VersionsStream10, TlsConnectStream,
TlsConnectTestBase::kTlsV10);
INSTANTIATE_TEST_CASE_P(VersionsStream, TlsConnectStream,
Expand Down
10 changes: 8 additions & 2 deletions external_tests/ssl_gtest/test_io.cc
Expand Up @@ -125,8 +125,9 @@ static PRStatus DummyListen(PRFileDesc *f, int32_t depth) {
}

static PRStatus DummyShutdown(PRFileDesc *f, int32_t how) {
UNIMPLEMENTED();
return PR_FAILURE;
DummyPrSocket *io = reinterpret_cast<DummyPrSocket *>(f->secret);
io->Reset();
return PR_SUCCESS;
}

// This function does not support peek.
Expand Down Expand Up @@ -250,7 +251,12 @@ static int32_t DummyReserved(PRFileDesc *f) {
}

DummyPrSocket::~DummyPrSocket() {
Reset();
}

void DummyPrSocket::Reset() {
delete filter_;
peer_ = nullptr;
while (!input_.empty())
{
Packet* front = input_.front();
Expand Down
3 changes: 2 additions & 1 deletion external_tests/ssl_gtest/test_io.h
Expand Up @@ -50,8 +50,9 @@ class DummyPrSocket {
static DummyPrSocket* GetAdapter(PRFileDesc* fd);

void SetPeer(DummyPrSocket* peer) { peer_ = peer; }

void SetPacketFilter(PacketFilter* filter) { filter_ = filter; }
// Drops peer, packet filter and any outstanding packets.
void Reset();

void PacketReceived(const DataBuffer& data);
int32_t Read(void* data, int32_t len);
Expand Down

0 comments on commit 7a9173a

Please sign in to comment.