From 61f95277d40dc829fcc5cf09d0e208d247b2b50f Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 25 Nov 2014 01:55:35 -0500 Subject: [PATCH] Add tests for OCSP stapling and SCT lists. We forgot to add those when we implemented the features. (Also relevant because they will provide test coverage later for configuring features when using the generic method tables rather than *_client_method.) Change-Id: Ie08b27de893095e01a05a7084775676616459807 Reviewed-on: https://boringssl-review.googlesource.com/2410 Reviewed-by: Adam Langley --- ssl/test/bssl_shim.cc | 51 +++++++++++++++++++++------ ssl/test/runner/common.go | 29 ++++++++------- ssl/test/runner/handshake_messages.go | 43 ++++++++++++++++++++-- ssl/test/runner/handshake_server.go | 4 +++ ssl/test/runner/runner.go | 24 +++++++++++++ ssl/test/test_config.cc | 10 +++++- ssl/test/test_config.h | 4 +++ 7 files changed, 140 insertions(+), 25 deletions(-) diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 4239ee3e..a4dd06d7 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc @@ -423,17 +423,25 @@ static int do_exchange(SSL_SESSION **out_session, SSL_set_psk_client_callback(ssl, psk_client_callback); SSL_set_psk_server_callback(ssl, psk_server_callback); } - if (!config->psk_identity.empty()) { - if (!SSL_use_psk_identity_hint(ssl, config->psk_identity.c_str())) { - BIO_print_errors_fp(stdout); - return 1; - } + if (!config->psk_identity.empty() && + !SSL_use_psk_identity_hint(ssl, config->psk_identity.c_str())) { + BIO_print_errors_fp(stdout); + return 1; } - if (!config->srtp_profiles.empty()) { - if (!SSL_set_srtp_profiles(ssl, config->srtp_profiles.c_str())) { - BIO_print_errors_fp(stdout); - return 1; - } + if (!config->srtp_profiles.empty() && + !SSL_set_srtp_profiles(ssl, config->srtp_profiles.c_str())) { + BIO_print_errors_fp(stdout); + return 1; + } + if (config->enable_ocsp_stapling && + !SSL_enable_ocsp_stapling(ssl)) { + BIO_print_errors_fp(stdout); + return 1; + } + if (config->enable_signed_cert_timestamps && + !SSL_enable_signed_cert_timestamps(ssl)) { + BIO_print_errors_fp(stdout); + return 1; } BIO *bio = BIO_new_fd(fd, 1 /* take ownership */); @@ -555,6 +563,29 @@ static int do_exchange(SSL_SESSION **out_session, } } + if (!config->expected_ocsp_response.empty()) { + const uint8_t *data; + size_t len; + SSL_get0_ocsp_response(ssl, &data, &len); + if (config->expected_ocsp_response.size() != len || + memcmp(config->expected_ocsp_response.data(), data, len) != 0) { + fprintf(stderr, "OCSP response mismatch\n"); + return 2; + } + } + + if (!config->expected_signed_cert_timestamps.empty()) { + const uint8_t *data; + size_t len; + SSL_get0_signed_cert_timestamp_list(ssl, &data, &len); + if (config->expected_signed_cert_timestamps.size() != len || + memcmp(config->expected_signed_cert_timestamps.data(), + data, len) != 0) { + fprintf(stderr, "SCT list mismatch\n"); + return 2; + } + } + if (config->renegotiate) { if (config->async) { fprintf(stderr, "--renegotiate is not supported with --async.\n"); diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index 476a2a4f..02ee7e2e 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go @@ -72,18 +72,19 @@ const ( // TLS extension numbers const ( - extensionServerName uint16 = 0 - extensionStatusRequest uint16 = 5 - extensionSupportedCurves uint16 = 10 - extensionSupportedPoints uint16 = 11 - extensionSignatureAlgorithms uint16 = 13 - extensionUseSRTP uint16 = 14 - extensionALPN uint16 = 16 - extensionExtendedMasterSecret uint16 = 23 - extensionSessionTicket uint16 = 35 - extensionNextProtoNeg uint16 = 13172 // not IANA assigned - extensionRenegotiationInfo uint16 = 0xff01 - extensionChannelID uint16 = 30032 // not IANA assigned + extensionServerName uint16 = 0 + extensionStatusRequest uint16 = 5 + extensionSupportedCurves uint16 = 10 + extensionSupportedPoints uint16 = 11 + extensionSignatureAlgorithms uint16 = 13 + extensionUseSRTP uint16 = 14 + extensionALPN uint16 = 16 + extensionSignedCertificateTimestamp uint16 = 18 + extensionExtendedMasterSecret uint16 = 23 + extensionSessionTicket uint16 = 35 + extensionNextProtoNeg uint16 = 13172 // not IANA assigned + extensionRenegotiationInfo uint16 = 0xff01 + extensionChannelID uint16 = 30032 // not IANA assigned ) // TLS signaling cipher suite values @@ -731,6 +732,10 @@ type Certificate struct { // OCSPStaple contains an optional OCSP response which will be served // to clients that request it. OCSPStaple []byte + // SignedCertificateTimestampList contains an optional encoded + // SignedCertificateTimestampList structure which will be + // served to clients that request it. + SignedCertificateTimestampList []byte // Leaf is the parsed form of the leaf certificate, which may be // initialized using x509.ParseCertificate to reduce per-handshake // processing for TLS clients doing client authentication. If nil, the diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go index cb3b5c42..ce214fde 100644 --- a/ssl/test/runner/handshake_messages.go +++ b/ssl/test/runner/handshake_messages.go @@ -31,6 +31,7 @@ type clientHelloMsg struct { extendedMasterSecret bool srtpProtectionProfiles []uint16 srtpMasterKeyIdentifier string + sctListSupported bool } func (m *clientHelloMsg) equal(i interface{}) bool { @@ -63,7 +64,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.npnLast == m1.npnLast && m.extendedMasterSecret == m1.extendedMasterSecret && eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) && - m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier + m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier && + m.sctListSupported == m1.sctListSupported } func (m *clientHelloMsg) marshal() []byte { @@ -133,6 +135,9 @@ func (m *clientHelloMsg) marshal() []byte { extensionsLength += 1 + len(m.srtpMasterKeyIdentifier) numExtensions++ } + if m.sctListSupported { + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -366,6 +371,11 @@ func (m *clientHelloMsg) marshal() []byte { copy(z[1:], []byte(m.srtpMasterKeyIdentifier)) z = z[1+mkiLen:] } + if m.sctListSupported { + z[0] = byte(extensionSignedCertificateTimestamp >> 8) + z[1] = byte(extensionSignedCertificateTimestamp & 0xff) + z = z[4:] + } m.raw = x @@ -589,6 +599,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } m.srtpMasterKeyIdentifier = string(d[1:]) + case extensionSignedCertificateTimestamp: + if length != 0 { + return false + } + m.sctListSupported = true } data = data[length:] } @@ -615,6 +630,7 @@ type serverHelloMsg struct { extendedMasterSecret bool srtpProtectionProfile uint16 srtpMasterKeyIdentifier string + sctList []byte } func (m *serverHelloMsg) equal(i interface{}) bool { @@ -641,7 +657,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool { m.channelIDRequested == m1.channelIDRequested && m.extendedMasterSecret == m1.extendedMasterSecret && m.srtpProtectionProfile == m1.srtpProtectionProfile && - m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier + m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier && + bytes.Equal(m.sctList, m1.sctList) } func (m *serverHelloMsg) marshal() []byte { @@ -692,6 +709,10 @@ func (m *serverHelloMsg) marshal() []byte { extensionsLength += 2 + 2 + 1 + len(m.srtpMasterKeyIdentifier) numExtensions++ } + if m.sctList != nil { + extensionsLength += len(m.sctList) + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions @@ -808,6 +829,15 @@ func (m *serverHelloMsg) marshal() []byte { copy(z[9:], []byte(m.srtpMasterKeyIdentifier)) z = z[9+l:] } + if m.sctList != nil { + z[0] = byte(extensionSignedCertificateTimestamp >> 8) + z[1] = byte(extensionSignedCertificateTimestamp & 0xff) + l := len(m.sctList) + z[2] = byte(l >> 8) + z[3] = byte(l & 0xff) + copy(z[4:], m.sctList) + z = z[4+l:] + } m.raw = x @@ -934,6 +964,15 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return false } m.srtpMasterKeyIdentifier = string(d[1:]) + case extensionSignedCertificateTimestamp: + if length < 2 { + return false + } + l := int(data[0])<<8 | int(data[1]) + if l != len(data)-2 { + return false + } + m.sctList = data[2:length] } data = data[length:] } diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index b087b468..ec79b79f 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go @@ -428,6 +428,10 @@ func (hs *serverHandshakeState) doFullHandshake() error { hs.hello.ocspStapling = true } + if hs.clientHello.sctListSupported && len(hs.cert.SignedCertificateTimestampList) > 0 { + hs.hello.sctList = hs.cert.SignedCertificateTimestampList + } + hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled && c.vers > VersionSSL30 hs.hello.cipherSuite = hs.suite.id c.extendedMasterSecret = hs.hello.extendedMasterSecret diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 1ee63622..697437b6 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -45,17 +45,24 @@ var rsaCertificate, ecdsaCertificate Certificate var channelIDKey *ecdsa.PrivateKey var channelIDBytes []byte +var testOCSPResponse = []byte{1, 2, 3, 4} +var testSCTList = []byte{5, 6, 7, 8} + func initCertificates() { var err error rsaCertificate, err = LoadX509KeyPair(rsaCertificateFile, rsaKeyFile) if err != nil { panic(err) } + rsaCertificate.OCSPStaple = testOCSPResponse + rsaCertificate.SignedCertificateTimestampList = testSCTList ecdsaCertificate, err = LoadX509KeyPair(ecdsaCertificateFile, ecdsaKeyFile) if err != nil { panic(err) } + ecdsaCertificate.OCSPStaple = testOCSPResponse + ecdsaCertificate.SignedCertificateTimestampList = testSCTList channelIDPEMBlock, err := ioutil.ReadFile(channelIDKeyFile) if err != nil { @@ -1878,6 +1885,23 @@ func addExtensionTests() { shouldFail: true, expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:", }) + // Test OCSP stapling and SCT list. + testCases = append(testCases, testCase{ + name: "OCSPStapling", + flags: []string{ + "-enable-ocsp-stapling", + "-expect-ocsp-response", + base64.StdEncoding.EncodeToString(testOCSPResponse), + }, + }) + testCases = append(testCases, testCase{ + name: "SignedCertificateTimestampList", + flags: []string{ + "-enable-signed-cert-timestamps", + "-expect-signed-cert-timestamps", + base64.StdEncoding.EncodeToString(testSCTList), + }, + }) } func addResumptionVersionTests() { diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index 5d0119d5..e8034ce1 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc @@ -62,6 +62,9 @@ const BoolFlag kBoolFlags[] = { { "-renegotiate", &TestConfig::renegotiate }, { "-allow-unsafe-legacy-renegotiation", &TestConfig::allow_unsafe_legacy_renegotiation }, + { "-enable-ocsp-stapling", &TestConfig::enable_ocsp_stapling }, + { "-enable-signed-cert-timestamps", + &TestConfig::enable_signed_cert_timestamps }, }; const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]); @@ -89,6 +92,9 @@ const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]); const StringFlag kBase64Flags[] = { { "-expect-certificate-types", &TestConfig::expected_certificate_types }, { "-expect-channel-id", &TestConfig::expected_channel_id }, + { "-expect-ocsp-response", &TestConfig::expected_ocsp_response }, + { "-expect-signed-cert-timestamps", + &TestConfig::expected_signed_cert_timestamps }, }; const size_t kNumBase64Flags = sizeof(kBase64Flags) / sizeof(kBase64Flags[0]); @@ -116,7 +122,9 @@ TestConfig::TestConfig() expect_session_miss(false), expect_extended_master_secret(false), renegotiate(false), - allow_unsafe_legacy_renegotiation(false) { + allow_unsafe_legacy_renegotiation(false), + enable_ocsp_stapling(false), + enable_signed_cert_timestamps(false) { } bool ParseConfig(int argc, char **argv, TestConfig *out_config) { diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index 07f0897a..5f050a84 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h @@ -59,6 +59,10 @@ struct TestConfig { bool renegotiate; bool allow_unsafe_legacy_renegotiation; std::string srtp_profiles; + bool enable_ocsp_stapling; + std::string expected_ocsp_response; + bool enable_signed_cert_timestamps; + std::string expected_signed_cert_timestamps; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config);