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 <agl@google.com>kris/onging/CECPQ3_patch15
@@ -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"); | |||
@@ -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 | |||
@@ -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:] | |||
} | |||
@@ -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 | |||
@@ -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() { | |||
@@ -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) { | |||
@@ -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); | |||