summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Chernov <sergei.cv@ndivi.com>2015-12-08 17:11:24 -0500
committerSergei Chernov <sergei.cv@ndivi.com>2015-12-08 17:11:24 -0500
commit27b7eed22e67425da81ff78f81c5827707a94824 (patch)
tree2f644279c980f134b83535e50c17028385b368cd
parent7247d25bca20f12eac9248272d87e33c3f9b874e (diff)
downloadnss-hg-27b7eed22e67425da81ff78f81c5827707a94824.tar.gz
Bug 944175 - Implement Certificate Transparency [part 3, tests]. r=ekr
-rw-r--r--external_tests/ssl_gtest/databuffer.h20
-rw-r--r--external_tests/ssl_gtest/ssl_extension_unittest.cc104
-rw-r--r--external_tests/ssl_gtest/tls_agent.cc4
-rw-r--r--external_tests/ssl_gtest/tls_agent.h35
4 files changed, 160 insertions, 3 deletions
diff --git a/external_tests/ssl_gtest/databuffer.h b/external_tests/ssl_gtest/databuffer.h
index 832b8c382..ca59dd71a 100644
--- a/external_tests/ssl_gtest/databuffer.h
+++ b/external_tests/ssl_gtest/databuffer.h
@@ -51,9 +51,16 @@ class DataBuffer {
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);
+ if (data) {
+ Allocate(len);
+ memcpy(static_cast<void *>(data_), static_cast<const void *>(data), len);
+ } else {
+ assert(len == 0);
+ data_ = nullptr;
+ len_ = 0;
+ }
}
// Write will do a new allocation and expand the size of the buffer if needed.
@@ -166,6 +173,15 @@ inline std::ostream& operator<<(std::ostream& stream, const DataBuffer& buf) {
return stream;
}
+inline bool operator==(const DataBuffer& a, const DataBuffer& b) {
+ return (a.empty() && b.empty()) ||
+ (a.len() == b.len() && 0 == memcmp(a.data(), b.data(), a.len()));
+}
+
+inline bool operator!=(const DataBuffer& a, const DataBuffer& b) {
+ return !(a == b);
+}
+
} // namespace nss_test
#endif
diff --git a/external_tests/ssl_gtest/ssl_extension_unittest.cc b/external_tests/ssl_gtest/ssl_extension_unittest.cc
index b8e0adf74..751583510 100644
--- a/external_tests/ssl_gtest/ssl_extension_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_extension_unittest.cc
@@ -609,6 +609,110 @@ TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmConfiguration) {
}
}
+/*
+ * Tests for Certificate Transparency (RFC 6962)
+ */
+
+// Helper class - stores signed certificate timestamps as provided
+// by the relevant callbacks on the client.
+class SignedCertificateTimestampsExtractor {
+ public:
+ SignedCertificateTimestampsExtractor(TlsAgent& client) {
+ client.SetAuthCertificateCallback(
+ [&](TlsAgent& agent, PRBool checksig, PRBool isServer) {
+ const SECItem *scts = SSL_PeerSignedCertTimestamps(agent.ssl_fd());
+ ASSERT_TRUE(scts);
+ auth_timestamps_.reset(new DataBuffer(scts->data, scts->len));
+ }
+ );
+ client.SetHandshakeCallback(
+ [&](TlsAgent& agent) {
+ const SECItem *scts = SSL_PeerSignedCertTimestamps(agent.ssl_fd());
+ ASSERT_TRUE(scts);
+ handshake_timestamps_.reset(new DataBuffer(scts->data, scts->len));
+ }
+ );
+ }
+
+ void assertTimestamps(const DataBuffer& timestamps) {
+ ASSERT_TRUE(auth_timestamps_);
+ ASSERT_EQ(timestamps, *auth_timestamps_);
+
+ ASSERT_TRUE(handshake_timestamps_);
+ ASSERT_EQ(timestamps, *handshake_timestamps_);
+ }
+
+ private:
+ std::unique_ptr<DataBuffer> auth_timestamps_;
+ std::unique_ptr<DataBuffer> handshake_timestamps_;
+};
+
+// Test timestamps extraction during a successful handshake.
+TEST_P(TlsExtensionTestGeneric, SignedCertificateTimestampsHandshake) {
+ uint8_t val[] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
+ const SECItem si_timestamps = { siBuffer, val, sizeof(val) };
+ const DataBuffer timestamps(val, sizeof(val));
+
+ server_->StartConnect();
+ ASSERT_EQ(SECSuccess,
+ SSL_SetSignedCertTimestamps(server_->ssl_fd(),
+ &si_timestamps, server_->kea()));
+
+ client_->StartConnect();
+ ASSERT_EQ(SECSuccess,
+ SSL_OptionSet(client_->ssl_fd(),
+ SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, PR_TRUE));
+
+ SignedCertificateTimestampsExtractor timestamps_extractor(*client_);
+ Handshake();
+ CheckConnected();
+ timestamps_extractor.assertTimestamps(timestamps);
+}
+
+// Test SSL_PeerSignedCertTimestamps returning zero-length SECItem
+// when the client / the server / both have not enabled the feature.
+TEST_P(TlsExtensionTestGeneric, SignedCertificateTimestampsInactiveClient) {
+ uint8_t val[] = { 0x01, 0x23, 0x45, 0x67, 0x89 };
+ const SECItem si_timestamps = { siBuffer, val, sizeof(val) };
+
+ server_->StartConnect();
+ ASSERT_EQ(SECSuccess,
+ SSL_SetSignedCertTimestamps(server_->ssl_fd(),
+ &si_timestamps, server_->kea()));
+
+ client_->StartConnect();
+
+ SignedCertificateTimestampsExtractor timestamps_extractor(*client_);
+ Handshake();
+ CheckConnected();
+ timestamps_extractor.assertTimestamps(DataBuffer());
+}
+
+TEST_P(TlsExtensionTestGeneric, SignedCertificateTimestampsInactiveServer) {
+ server_->StartConnect();
+
+ client_->StartConnect();
+ ASSERT_EQ(SECSuccess,
+ SSL_OptionSet(client_->ssl_fd(),
+ SSL_ENABLE_SIGNED_CERT_TIMESTAMPS, PR_TRUE));
+
+ SignedCertificateTimestampsExtractor timestamps_extractor(*client_);
+ Handshake();
+ CheckConnected();
+ timestamps_extractor.assertTimestamps(DataBuffer());
+}
+
+TEST_P(TlsExtensionTestGeneric, SignedCertificateTimestampsInactiveBoth) {
+ server_->StartConnect();
+ client_->StartConnect();
+
+ SignedCertificateTimestampsExtractor timestamps_extractor(*client_);
+ Handshake();
+ CheckConnected();
+ timestamps_extractor.assertTimestamps(DataBuffer());
+}
+
+
INSTANTIATE_TEST_CASE_P(ExtensionTls10, TlsExtensionTestGeneric,
::testing::Combine(
TlsConnectTestBase::kTlsModesStream,
diff --git a/external_tests/ssl_gtest/tls_agent.cc b/external_tests/ssl_gtest/tls_agent.cc
index 2a41ecbc6..3758ea315 100644
--- a/external_tests/ssl_gtest/tls_agent.cc
+++ b/external_tests/ssl_gtest/tls_agent.cc
@@ -40,7 +40,9 @@ TlsAgent::TlsAgent(const std::string& name, Role role, Mode mode, SSLKEAType kea
error_code_(0),
send_ctr_(0),
recv_ctr_(0),
- expected_read_error_(false) {
+ expected_read_error_(false),
+ handshake_callback_(),
+ auth_certificate_callback_() {
memset(&info_, 0, sizeof(info_));
memset(&csinfo_, 0, sizeof(csinfo_));
diff --git a/external_tests/ssl_gtest/tls_agent.h b/external_tests/ssl_gtest/tls_agent.h
index f15de13aa..3a1ea6807 100644
--- a/external_tests/ssl_gtest/tls_agent.h
+++ b/external_tests/ssl_gtest/tls_agent.h
@@ -11,6 +11,7 @@
#include "ssl.h"
#include <iostream>
+#include <functional>
#include "test_io.h"
@@ -28,6 +29,16 @@ enum SessionResumptionMode {
RESUME_BOTH = RESUME_SESSIONID | RESUME_TICKET
};
+class TlsAgent;
+
+typedef
+ std::function<void(TlsAgent& agent, PRBool checksig, PRBool isServer)>
+ AuthCertificateCallbackFunction;
+
+typedef
+ std::function<void(TlsAgent& agent)>
+ HandshakeCallbackFunction;
+
class TlsAgent : public PollTarget {
public:
enum Role { CLIENT, SERVER };
@@ -94,8 +105,12 @@ class TlsAgent : public PollTarget {
void CheckExtendedMasterSecret(bool expected);
void DisableRollbackDetection();
+ Role role() const { return role_; }
+
State state() const { return state_; }
+ SSLKEAType kea() const { return kea_; }
+
const char* state_str() const { return state_str(state()); }
const char* state_str(State state) const { return states[state]; }
@@ -131,6 +146,15 @@ class TlsAgent : public PollTarget {
size_t received_bytes() const { return recv_ctr_; }
int32_t error_code() const { return error_code_; }
+ void SetHandshakeCallback(HandshakeCallbackFunction handshake_callback) {
+ handshake_callback_ = handshake_callback;
+ }
+
+ void SetAuthCertificateCallback(
+ AuthCertificateCallbackFunction auth_certificate_callback) {
+ auth_certificate_callback_ = auth_certificate_callback;
+ }
+
private:
const static char* states[];
@@ -148,6 +172,9 @@ class TlsAgent : public PollTarget {
TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
agent->CheckPreliminaryInfo();
agent->auth_certificate_hook_called_ = true;
+ if (agent->auth_certificate_callback_) {
+ agent->auth_certificate_callback_(*agent, checksig, isServer);
+ }
return SECSuccess;
}
@@ -157,6 +184,9 @@ class TlsAgent : public PollTarget {
TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
EXPECT_TRUE(agent->expect_client_auth_);
EXPECT_TRUE(isServer);
+ if (agent->auth_certificate_callback_) {
+ agent->auth_certificate_callback_(*agent, checksig, isServer);
+ }
return SECSuccess;
}
@@ -208,6 +238,9 @@ class TlsAgent : public PollTarget {
TlsAgent* agent = reinterpret_cast<TlsAgent*>(arg);
agent->CheckPreliminaryInfo();
agent->handshake_callback_called_ = true;
+ if (agent->handshake_callback_) {
+ agent->handshake_callback_(*agent);
+ }
}
void CheckCallbacks() const;
@@ -237,6 +270,8 @@ class TlsAgent : public PollTarget {
size_t send_ctr_;
size_t recv_ctr_;
bool expected_read_error_;
+ HandshakeCallbackFunction handshake_callback_;
+ AuthCertificateCallbackFunction auth_certificate_callback_;
};
class TlsAgentTestBase : public ::testing::Test {