Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/ssl/test
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@chromium.org>2014-11-16 03:06:08 +0300
committerAdam Langley <agl@google.com>2014-11-19 01:16:53 +0300
commitca6c82643ae885f94acff27ddd93bfb73fda3af5 (patch)
tree5a1940132175b6e6edf5de057af12078d2f00a60 /ssl/test
parentce5be4bd5ceaadb7bcebaf575e4dea74a4bff109 (diff)
Add DTLS-SRTP tests.
Just the negotiation portion as everything else is external. This feature is used in WebRTC. Change-Id: Iccc3983ea99e7d054b59010182f9a56a8099e116 Reviewed-on: https://boringssl-review.googlesource.com/2310 Reviewed-by: Adam Langley <agl@google.com>
Diffstat (limited to 'ssl/test')
-rw-r--r--ssl/test/bssl_shim.cc6
-rw-r--r--ssl/test/runner/common.go21
-rw-r--r--ssl/test/runner/conn.go3
-rw-r--r--ssl/test/runner/handshake_client.go51
-rw-r--r--ssl/test/runner/handshake_messages.go168
-rw-r--r--ssl/test/runner/handshake_server.go17
-rw-r--r--ssl/test/runner/runner.go85
-rw-r--r--ssl/test/test_config.cc1
-rw-r--r--ssl/test/test_config.h1
9 files changed, 297 insertions, 56 deletions
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 7adf0824..cdd62ff6 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -425,6 +425,12 @@ static int do_exchange(SSL_SESSION **out_session,
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;
+ }
+ }
BIO *bio = BIO_new_fd(fd, 1 /* take ownership */);
if (bio == NULL) {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 9f79778f..a4bdef80 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -77,6 +77,7 @@ const (
extensionSupportedCurves uint16 = 10
extensionSupportedPoints uint16 = 11
extensionSignatureAlgorithms uint16 = 13
+ extensionUseSRTP uint16 = 14
extensionALPN uint16 = 16
extensionExtendedMasterSecret uint16 = 23
extensionSessionTicket uint16 = 35
@@ -161,6 +162,12 @@ var supportedClientCertSignatureAlgorithms = []signatureAndHash{
{signatureECDSA, hashSHA256},
}
+// SRTP protection profiles (See RFC 5764, section 4.1.2)
+const (
+ SRTP_AES128_CM_HMAC_SHA1_80 uint16 = 0x0001
+ SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002
+)
+
// ConnectionState records basic TLS details about the connection.
type ConnectionState struct {
Version uint16 // TLS version used by the connection (e.g. VersionTLS12)
@@ -174,6 +181,7 @@ type ConnectionState struct {
PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
ChannelID *ecdsa.PublicKey // the channel ID for this connection
+ SRTPProtectionProfile uint16 // the negotiated DTLS-SRTP protection profile
}
// ClientAuthType declares the policy the server will follow for
@@ -334,6 +342,10 @@ type Config struct {
// with the PSK cipher suites.
PreSharedKeyIdentity string
+ // SRTPProtectionProfiles, if not nil, is the list of SRTP
+ // protection profiles to offer in DTLS-SRTP.
+ SRTPProtectionProfiles []uint16
+
// Bugs specifies optional misbehaviour to be used for testing other
// implementations.
Bugs ProtocolBugs
@@ -520,6 +532,15 @@ type ProtocolBugs struct {
// RSAServerKeyExchange, if true, causes the server to send a
// ServerKeyExchange message in the plain RSA key exchange.
RSAServerKeyExchange bool
+
+ // SRTPMasterKeyIdentifer, if not empty, is the SRTP MKI value that the
+ // client offers when negotiating SRTP. MKI support is still missing so
+ // the peer must still send none.
+ SRTPMasterKeyIdentifer string
+
+ // SendSRTPProtectionProfile, if non-zero, is the SRTP profile that the
+ // server sends in the ServerHello instead of the negotiated one.
+ SendSRTPProtectionProfile uint16
}
func (c *Config) serverInit() {
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index f4b4c361..94d7434d 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -56,6 +56,8 @@ type Conn struct {
channelID *ecdsa.PublicKey
+ srtpProtectionProfile uint16
+
// input/output
in, out halfConn // in.Mutex < out.Mutex
rawInput *block // raw input, right off the wire
@@ -1184,6 +1186,7 @@ func (c *Conn) ConnectionState() ConnectionState {
state.VerifiedChains = c.verifiedChains
state.ServerName = c.serverName
state.ChannelID = c.channelID
+ state.SRTPProtectionProfile = c.srtpProtectionProfile
}
return state
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 702797b2..71712a90 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -56,21 +56,23 @@ func (c *Conn) clientHandshake() error {
}
hello := &clientHelloMsg{
- isDTLS: c.isDTLS,
- vers: c.config.maxVersion(),
- compressionMethods: []uint8{compressionNone},
- random: make([]byte, 32),
- ocspStapling: true,
- serverName: c.config.ServerName,
- supportedCurves: c.config.curvePreferences(),
- supportedPoints: []uint8{pointFormatUncompressed},
- nextProtoNeg: len(c.config.NextProtos) > 0,
- secureRenegotiation: []byte{},
- alpnProtocols: c.config.NextProtos,
- duplicateExtension: c.config.Bugs.DuplicateExtension,
- channelIDSupported: c.config.ChannelID != nil,
- npnLast: c.config.Bugs.SwapNPNAndALPN,
- extendedMasterSecret: c.config.maxVersion() >= VersionTLS10,
+ isDTLS: c.isDTLS,
+ vers: c.config.maxVersion(),
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: c.config.curvePreferences(),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ nextProtoNeg: len(c.config.NextProtos) > 0,
+ secureRenegotiation: []byte{},
+ alpnProtocols: c.config.NextProtos,
+ duplicateExtension: c.config.Bugs.DuplicateExtension,
+ channelIDSupported: c.config.ChannelID != nil,
+ npnLast: c.config.Bugs.SwapNPNAndALPN,
+ extendedMasterSecret: c.config.maxVersion() >= VersionTLS10,
+ srtpProtectionProfiles: c.config.SRTPProtectionProfiles,
+ srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
}
if c.config.Bugs.SendClientVersion != 0 {
@@ -666,6 +668,25 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return false, errors.New("server advertised unrequested Channel ID extension")
}
+ if hs.serverHello.srtpProtectionProfile != 0 {
+ if hs.serverHello.srtpMasterKeyIdentifier != "" {
+ return false, errors.New("tls: server selected SRTP MKI value")
+ }
+
+ found := false
+ for _, p := range c.config.SRTPProtectionProfiles {
+ if p == hs.serverHello.srtpProtectionProfile {
+ found = true
+ break
+ }
+ }
+ if !found {
+ return false, errors.New("tls: server advertised unsupported SRTP profile")
+ }
+
+ c.srtpProtectionProfile = hs.serverHello.srtpProtectionProfile
+ }
+
if hs.serverResumedSession() {
// Restore masterSecret and peerCerts from previous state
hs.masterSecret = hs.session.masterSecret
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 12a9f3d5..cb3b5c42 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -7,28 +7,30 @@ package main
import "bytes"
type clientHelloMsg struct {
- raw []byte
- isDTLS bool
- vers uint16
- random []byte
- sessionId []byte
- cookie []byte
- cipherSuites []uint16
- compressionMethods []uint8
- nextProtoNeg bool
- serverName string
- ocspStapling bool
- supportedCurves []CurveID
- supportedPoints []uint8
- ticketSupported bool
- sessionTicket []uint8
- signatureAndHashes []signatureAndHash
- secureRenegotiation []byte
- alpnProtocols []string
- duplicateExtension bool
- channelIDSupported bool
- npnLast bool
- extendedMasterSecret bool
+ raw []byte
+ isDTLS bool
+ vers uint16
+ random []byte
+ sessionId []byte
+ cookie []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ nextProtoNeg bool
+ serverName string
+ ocspStapling bool
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ ticketSupported bool
+ sessionTicket []uint8
+ signatureAndHashes []signatureAndHash
+ secureRenegotiation []byte
+ alpnProtocols []string
+ duplicateExtension bool
+ channelIDSupported bool
+ npnLast bool
+ extendedMasterSecret bool
+ srtpProtectionProfiles []uint16
+ srtpMasterKeyIdentifier string
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -59,7 +61,9 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
m.duplicateExtension == m1.duplicateExtension &&
m.channelIDSupported == m1.channelIDSupported &&
m.npnLast == m1.npnLast &&
- m.extendedMasterSecret == m1.extendedMasterSecret
+ m.extendedMasterSecret == m1.extendedMasterSecret &&
+ eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) &&
+ m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier
}
func (m *clientHelloMsg) marshal() []byte {
@@ -124,6 +128,11 @@ func (m *clientHelloMsg) marshal() []byte {
if m.extendedMasterSecret {
numExtensions++
}
+ if len(m.srtpProtectionProfiles) > 0 {
+ extensionsLength += 2 + 2*len(m.srtpProtectionProfiles)
+ extensionsLength += 1 + len(m.srtpMasterKeyIdentifier)
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -334,6 +343,29 @@ func (m *clientHelloMsg) marshal() []byte {
z[1] = byte(extensionExtendedMasterSecret & 0xff)
z = z[4:]
}
+ if len(m.srtpProtectionProfiles) > 0 {
+ z[0] = byte(extensionUseSRTP >> 8)
+ z[1] = byte(extensionUseSRTP & 0xff)
+
+ profilesLen := 2 * len(m.srtpProtectionProfiles)
+ mkiLen := len(m.srtpMasterKeyIdentifier)
+ l := 2 + profilesLen + 1 + mkiLen
+ z[2] = byte(l >> 8)
+ z[3] = byte(l & 0xff)
+
+ z[4] = byte(profilesLen >> 8)
+ z[5] = byte(profilesLen & 0xff)
+ z = z[6:]
+ for _, p := range m.srtpProtectionProfiles {
+ z[0] = byte(p >> 8)
+ z[1] = byte(p & 0xff)
+ z = z[2:]
+ }
+
+ z[0] = byte(mkiLen)
+ copy(z[1:], []byte(m.srtpMasterKeyIdentifier))
+ z = z[1+mkiLen:]
+ }
m.raw = x
@@ -538,6 +570,25 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
m.extendedMasterSecret = true
+ case extensionUseSRTP:
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l > length-2 || l%2 != 0 {
+ return false
+ }
+ n := l / 2
+ m.srtpProtectionProfiles = make([]uint16, n)
+ d := data[2:length]
+ for i := 0; i < n; i++ {
+ m.srtpProtectionProfiles[i] = uint16(d[0])<<8 | uint16(d[1])
+ d = d[2:]
+ }
+ if len(d) < 1 || int(d[0]) != len(d)-1 {
+ return false
+ }
+ m.srtpMasterKeyIdentifier = string(d[1:])
}
data = data[length:]
}
@@ -546,22 +597,24 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
}
type serverHelloMsg struct {
- raw []byte
- isDTLS bool
- vers uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- compressionMethod uint8
- nextProtoNeg bool
- nextProtos []string
- ocspStapling bool
- ticketSupported bool
- secureRenegotiation []byte
- alpnProtocol string
- duplicateExtension bool
- channelIDRequested bool
- extendedMasterSecret bool
+ raw []byte
+ isDTLS bool
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ nextProtoNeg bool
+ nextProtos []string
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiation []byte
+ alpnProtocol string
+ duplicateExtension bool
+ channelIDRequested bool
+ extendedMasterSecret bool
+ srtpProtectionProfile uint16
+ srtpMasterKeyIdentifier string
}
func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -586,7 +639,9 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
m.alpnProtocol == m1.alpnProtocol &&
m.duplicateExtension == m1.duplicateExtension &&
m.channelIDRequested == m1.channelIDRequested &&
- m.extendedMasterSecret == m1.extendedMasterSecret
+ m.extendedMasterSecret == m1.extendedMasterSecret &&
+ m.srtpProtectionProfile == m1.srtpProtectionProfile &&
+ m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier
}
func (m *serverHelloMsg) marshal() []byte {
@@ -633,6 +688,10 @@ func (m *serverHelloMsg) marshal() []byte {
if m.extendedMasterSecret {
numExtensions++
}
+ if m.srtpProtectionProfile != 0 {
+ extensionsLength += 2 + 2 + 1 + len(m.srtpMasterKeyIdentifier)
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
@@ -734,6 +793,21 @@ func (m *serverHelloMsg) marshal() []byte {
z[1] = byte(extensionExtendedMasterSecret & 0xff)
z = z[4:]
}
+ if m.srtpProtectionProfile != 0 {
+ z[0] = byte(extensionUseSRTP >> 8)
+ z[1] = byte(extensionUseSRTP & 0xff)
+ l := 2 + 2 + 1 + len(m.srtpMasterKeyIdentifier)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l & 0xff)
+ z[4] = 0
+ z[5] = 2
+ z[6] = byte(m.srtpProtectionProfile >> 8)
+ z[7] = byte(m.srtpProtectionProfile & 0xff)
+ l = len(m.srtpMasterKeyIdentifier)
+ z[8] = byte(l)
+ copy(z[9:], []byte(m.srtpMasterKeyIdentifier))
+ z = z[9+l:]
+ }
m.raw = x
@@ -846,6 +920,20 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
return false
}
m.extendedMasterSecret = true
+ case extensionUseSRTP:
+ if length < 2+2+1 {
+ return false
+ }
+ if data[0] != 0 || data[1] != 2 {
+ return false
+ }
+ m.srtpProtectionProfile = uint16(data[2])<<8 | uint16(data[3])
+ d := data[4:length]
+ l := int(d[0])
+ if l != len(d)-1 {
+ return false
+ }
+ m.srtpMasterKeyIdentifier = string(d[1:])
}
data = data[length:]
}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 89c7b8d6..bd6f7022 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -270,6 +270,23 @@ Curves:
hs.hello.channelIDRequested = true
}
+ if hs.clientHello.srtpProtectionProfiles != nil {
+ SRTPLoop:
+ for _, p1 := range c.config.SRTPProtectionProfiles {
+ for _, p2 := range hs.clientHello.srtpProtectionProfiles {
+ if p1 == p2 {
+ hs.hello.srtpProtectionProfile = p1
+ c.srtpProtectionProfile = p1
+ break SRTPLoop
+ }
+ }
+ }
+ }
+
+ if c.config.Bugs.SendSRTPProtectionProfile != 0 {
+ hs.hello.srtpProtectionProfile = c.config.Bugs.SendSRTPProtectionProfile
+ }
+
_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
if hs.checkForResumption() {
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index a3026877..8c661a62 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -129,6 +129,9 @@ type testCase struct {
// expectedNextProtoType, if non-zero, is the expected next
// protocol negotiation mechanism.
expectedNextProtoType int
+ // expectedSRTPProtectionProfile is the DTLS-SRTP profile that
+ // should be negotiated. If zero, none should be negotiated.
+ expectedSRTPProtectionProfile uint16
// messageLen is the length, in bytes, of the test message that will be
// sent.
messageLen int
@@ -357,7 +360,7 @@ var testCases = []testCase{
name: "FragmentAlert",
config: Config{
Bugs: ProtocolBugs{
- FragmentAlert: true,
+ FragmentAlert: true,
SendSpuriousAlert: true,
},
},
@@ -589,6 +592,10 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
}
}
+ if p := tlsConn.ConnectionState().SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile {
+ return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile)
+ }
+
if test.shimWritesFirst {
var buf [5]byte
_, err := io.ReadFull(tlsConn, buf[:])
@@ -1741,6 +1748,82 @@ func addExtensionTests() {
shouldFail: true,
expectedError: ":DECODE_ERROR:",
})
+ // Basic DTLS-SRTP tests. Include fake profiles to ensure they
+ // are ignored.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "SRTP-Client",
+ config: Config{
+ SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
+ })
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SRTP-Server",
+ config: Config{
+ SRTPProtectionProfiles: []uint16{40, SRTP_AES128_CM_HMAC_SHA1_80, 42},
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
+ })
+ // Test that the MKI is ignored.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SRTP-Server-IgnoreMKI",
+ config: Config{
+ SRTPProtectionProfiles: []uint16{SRTP_AES128_CM_HMAC_SHA1_80},
+ Bugs: ProtocolBugs{
+ SRTPMasterKeyIdentifer: "bogus",
+ },
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_80,
+ })
+ // Test that SRTP isn't negotiated on the server if there were
+ // no matching profiles.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SRTP-Server-NoMatch",
+ config: Config{
+ SRTPProtectionProfiles: []uint16{100, 101, 102},
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32",
+ },
+ expectedSRTPProtectionProfile: 0,
+ })
+ // Test that the server returning an invalid SRTP profile is
+ // flagged as an error by the client.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ name: "SRTP-Client-NoMatch",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSRTPProtectionProfile: SRTP_AES128_CM_HMAC_SHA1_32,
+ },
+ },
+ flags: []string{
+ "-srtp-profiles",
+ "SRTP_AES128_CM_SHA1_80",
+ },
+ shouldFail: true,
+ expectedError: ":BAD_SRTP_PROTECTION_PROFILE_LIST:",
+ })
}
func addResumptionVersionTests() {
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index ebd5e4ee..5d0119d5 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -81,6 +81,7 @@ const StringFlag kStringFlags[] = {
{ "-select-alpn", &TestConfig::select_alpn },
{ "-psk", &TestConfig::psk },
{ "-psk-identity", &TestConfig::psk_identity },
+ { "-srtp-profiles", &TestConfig::srtp_profiles },
};
const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]);
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index 7de8b3fd..07f0897a 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -58,6 +58,7 @@ struct TestConfig {
std::string psk_identity;
bool renegotiate;
bool allow_unsafe_legacy_renegotiation;
+ std::string srtp_profiles;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);