summaryrefslogtreecommitdiffstats
path: root/src/ssl/test/runner
diff options
context:
space:
mode:
Diffstat (limited to 'src/ssl/test/runner')
-rw-r--r--src/ssl/test/runner/common.go34
-rw-r--r--src/ssl/test/runner/conn.go16
-rw-r--r--src/ssl/test/runner/dtls.go68
-rw-r--r--src/ssl/test/runner/handshake_client.go27
-rw-r--r--src/ssl/test/runner/handshake_server.go28
-rw-r--r--src/ssl/test/runner/key_agreement.go17
-rw-r--r--src/ssl/test/runner/runner.go700
7 files changed, 529 insertions, 361 deletions
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 4ac7250..edebba1 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -188,6 +188,7 @@ type ConnectionState struct {
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
+ TLSUnique []byte
}
// ClientAuthType declares the policy the server will follow for
@@ -478,7 +479,9 @@ type ProtocolBugs struct {
// MaxHandshakeRecordLength, if non-zero, is the maximum size of a
// handshake record. Handshake messages will be split into multiple
// records at the specified size, except that the client_version will
- // never be fragmented.
+ // never be fragmented. For DTLS, it is the maximum handshake fragment
+ // size, not record size; DTLS allows multiple handshake fragments in a
+ // single handshake record. See |PackHandshakeFragments|.
MaxHandshakeRecordLength int
// FragmentClientVersion will allow MaxHandshakeRecordLength to apply to
@@ -681,13 +684,14 @@ type ProtocolBugs struct {
// fragments in DTLS.
SendEmptyFragments bool
- // NeverResumeOnRenego, if true, causes renegotiations to always be full
- // handshakes.
- NeverResumeOnRenego bool
+ // SendSplitAlert, if true, causes an alert to be sent with the header
+ // and record body split across multiple packets. The peer should
+ // discard these packets rather than process it.
+ SendSplitAlert bool
- // NoSignatureAlgorithmsOnRenego, if true, causes renegotiations to omit
- // the signature_algorithms extension.
- NoSignatureAlgorithmsOnRenego bool
+ // FailIfResumeOnRenego, if true, causes renegotiations to fail if the
+ // client offers a resumption or the server accepts one.
+ FailIfResumeOnRenego bool
// IgnorePeerCipherPreferences, if true, causes the peer's cipher
// preferences to be ignored.
@@ -707,6 +711,22 @@ type ProtocolBugs struct {
// BadFinished, if true, causes the Finished hash to be broken.
BadFinished bool
+
+ // DHGroupPrime, if not nil, is used to define the (finite field)
+ // Diffie-Hellman group. The generator used is always two.
+ DHGroupPrime *big.Int
+
+ // PackHandshakeFragments, if true, causes handshake fragments to be
+ // packed into individual handshake records, up to the specified record
+ // size.
+ PackHandshakeFragments int
+
+ // PackHandshakeRecords, if true, causes handshake records to be packed
+ // into individual packets, up to the specified packet size.
+ PackHandshakeRecords int
+
+ // EnableAllCiphersInDTLS, if true, causes RC4 to be enabled in DTLS.
+ EnableAllCiphersInDTLS bool
}
func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index fd198ca..adbc1c3 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -44,7 +44,11 @@ type Conn struct {
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
// serverName contains the server name indicated by the client, if any.
- serverName string
+ serverName string
+ // firstFinished contains the first Finished hash sent during the
+ // handshake. This is the "tls-unique" channel binding value.
+ firstFinished [12]byte
+
clientRandom, serverRandom [32]byte
masterSecret [48]byte
@@ -1260,6 +1264,15 @@ func (c *Conn) Handshake() error {
return nil
}
+ if c.isDTLS && c.config.Bugs.SendSplitAlert {
+ c.conn.Write([]byte{
+ byte(recordTypeAlert), // type
+ 0xfe, 0xff, // version
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // sequence
+ 0x0, 0x2, // length
+ })
+ c.conn.Write([]byte{alertLevelError, byte(alertInternalError)})
+ }
if c.isClient {
c.handshakeErr = c.clientHandshake()
} else {
@@ -1290,6 +1303,7 @@ func (c *Conn) ConnectionState() ConnectionState {
state.ServerName = c.serverName
state.ChannelID = c.channelID
state.SRTPProtectionProfile = c.srtpProtectionProfile
+ state.TLSUnique = c.firstFinished[:]
}
return state
diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go
index 85c4247..50f7786 100644
--- a/src/ssl/test/runner/dtls.go
+++ b/src/ssl/test/runner/dtls.go
@@ -196,6 +196,8 @@ func (c *Conn) dtlsFlushHandshake() error {
return nil
}
+ // This is a test-only DTLS implementation, so there is no need to
+ // retain |c.pendingFragments| for a future retransmit.
var fragments [][]byte
fragments, c.pendingFragments = c.pendingFragments, fragments
@@ -208,38 +210,66 @@ func (c *Conn) dtlsFlushHandshake() error {
fragments = tmp
}
- // Send them all.
+ maxRecordLen := c.config.Bugs.PackHandshakeFragments
+ maxPacketLen := c.config.Bugs.PackHandshakeRecords
+
+ // Pack handshake fragments into records.
+ var records [][]byte
for _, fragment := range fragments {
if c.config.Bugs.SplitFragmentHeader {
- if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment[:2]); err != nil {
- return err
- }
- fragment = fragment[2:]
- } else if c.config.Bugs.SplitFragmentBody && len(fragment) > 12 {
- if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment[:13]); err != nil {
- return err
+ records = append(records, fragment[:2])
+ records = append(records, fragment[2:])
+ } else if c.config.Bugs.SplitFragmentBody {
+ if len(fragment) > 12 {
+ records = append(records, fragment[:13])
+ records = append(records, fragment[13:])
+ } else {
+ records = append(records, fragment)
}
- fragment = fragment[13:]
+ } else if i := len(records) - 1; len(records) > 0 && len(records[i])+len(fragment) <= maxRecordLen {
+ records[i] = append(records[i], fragment...)
+ } else {
+ // The fragment will be appended to, so copy it.
+ records = append(records, append([]byte{}, fragment...))
+ }
+ }
+
+ // Format them into packets.
+ var packets [][]byte
+ for _, record := range records {
+ b, err := c.dtlsSealRecord(recordTypeHandshake, record)
+ if err != nil {
+ return err
+ }
+
+ if i := len(packets) - 1; len(packets) > 0 && len(packets[i])+len(b.data) <= maxPacketLen {
+ packets[i] = append(packets[i], b.data...)
+ } else {
+ // The sealed record will be appended to and reused by
+ // |c.out|, so copy it.
+ packets = append(packets, append([]byte{}, b.data...))
}
+ c.out.freeBlock(b)
+ }
- // TODO(davidben): A real DTLS implementation needs to
- // retransmit handshake messages. For testing purposes, we don't
- // actually care.
- if _, err := c.dtlsWriteRawRecord(recordTypeHandshake, fragment); err != nil {
+ // Send all the packets.
+ for _, packet := range packets {
+ if _, err := c.conn.Write(packet); err != nil {
return err
}
}
return nil
}
-func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) {
+// dtlsSealRecord seals a record into a block from |c.out|'s pool.
+func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error) {
recordHeaderLen := dtlsRecordHeaderLen
maxLen := c.config.Bugs.MaxHandshakeRecordLength
if maxLen <= 0 {
maxLen = 1024
}
- b := c.out.newBlock()
+ b = c.out.newBlock()
explicitIVLen := 0
explicitIVIsSeq := false
@@ -286,6 +316,14 @@ func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error
}
copy(b.data[recordHeaderLen+explicitIVLen:], data)
c.out.encrypt(b, explicitIVLen)
+ return
+}
+
+func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) {
+ b, err := c.dtlsSealRecord(typ, data)
+ if err != nil {
+ return
+ }
_, err = c.conn.Write(b.data)
if err != nil {
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 0dac05d..a950313 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -115,7 +115,7 @@ NextCipherSuite:
continue
}
// Don't advertise non-DTLS cipher suites on DTLS.
- if c.isDTLS && suite.flags&suiteNoDTLS != 0 {
+ if c.isDTLS && suite.flags&suiteNoDTLS != 0 && !c.config.Bugs.EnableAllCiphersInDTLS {
continue
}
hello.cipherSuites = append(hello.cipherSuites, suiteId)
@@ -133,16 +133,13 @@ NextCipherSuite:
return errors.New("tls: short read from Rand: " + err.Error())
}
- if hello.vers >= VersionTLS12 && !c.config.Bugs.NoSignatureAndHashes && (c.cipherSuite == nil || !c.config.Bugs.NoSignatureAlgorithmsOnRenego) {
+ if hello.vers >= VersionTLS12 && !c.config.Bugs.NoSignatureAndHashes {
hello.signatureAndHashes = c.config.signatureAndHashesForClient()
}
var session *ClientSessionState
var cacheKey string
sessionCache := c.config.ClientSessionCache
- if c.config.Bugs.NeverResumeOnRenego && c.cipherSuite != nil {
- sessionCache = nil
- }
if sessionCache != nil {
hello.ticketSupported = !c.config.SessionTicketsDisabled
@@ -316,10 +313,10 @@ NextCipherSuite:
if err := hs.readSessionTicket(); err != nil {
return err
}
- if err := hs.readFinished(); err != nil {
+ if err := hs.readFinished(c.firstFinished[:]); err != nil {
return err
}
- if err := hs.sendFinished(isResume); err != nil {
+ if err := hs.sendFinished(nil, isResume); err != nil {
return err
}
} else {
@@ -329,7 +326,7 @@ NextCipherSuite:
if err := hs.establishKeys(); err != nil {
return err
}
- if err := hs.sendFinished(isResume); err != nil {
+ if err := hs.sendFinished(c.firstFinished[:], isResume); err != nil {
return err
}
// Most retransmits are triggered by a timeout, but the final
@@ -344,7 +341,7 @@ NextCipherSuite:
if err := hs.readSessionTicket(); err != nil {
return err
}
- if err := hs.readFinished(); err != nil {
+ if err := hs.readFinished(nil); err != nil {
return err
}
}
@@ -727,6 +724,12 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
}
if hs.serverResumedSession() {
+ // For test purposes, assert that the server never accepts the
+ // resumption offer on renegotiation.
+ if c.cipherSuite != nil && c.config.Bugs.FailIfResumeOnRenego {
+ return false, errors.New("tls: server resumed session on renegotiation")
+ }
+
// Restore masterSecret and peerCerts from previous state
hs.masterSecret = hs.session.masterSecret
c.peerCertificates = hs.session.serverCertificates
@@ -737,7 +740,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return false, nil
}
-func (hs *clientHandshakeState) readFinished() error {
+func (hs *clientHandshakeState) readFinished(out []byte) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
@@ -764,6 +767,7 @@ func (hs *clientHandshakeState) readFinished() error {
}
}
c.serverVerify = append(c.serverVerify[:0], serverFinished.verifyData...)
+ copy(out, serverFinished.verifyData)
hs.writeServerHash(serverFinished.marshal())
return nil
}
@@ -807,7 +811,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
return nil
}
-func (hs *clientHandshakeState) sendFinished(isResume bool) error {
+func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
c := hs.c
var postCCSBytes []byte
@@ -859,6 +863,7 @@ func (hs *clientHandshakeState) sendFinished(isResume bool) error {
} else {
finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
}
+ copy(out, finished.verifyData)
if c.config.Bugs.BadFinished {
finished.verifyData[0]++
}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 59ed9df..85cc0d2 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -69,7 +69,7 @@ func (c *Conn) serverHandshake() error {
return err
}
}
- if err := hs.sendFinished(); err != nil {
+ if err := hs.sendFinished(c.firstFinished[:]); err != nil {
return err
}
// Most retransmits are triggered by a timeout, but the final
@@ -81,7 +81,7 @@ func (c *Conn) serverHandshake() error {
}); err != nil {
return err
}
- if err := hs.readFinished(isResume); err != nil {
+ if err := hs.readFinished(nil, isResume); err != nil {
return err
}
c.didResume = true
@@ -94,7 +94,7 @@ func (c *Conn) serverHandshake() error {
if err := hs.establishKeys(); err != nil {
return err
}
- if err := hs.readFinished(isResume); err != nil {
+ if err := hs.readFinished(c.firstFinished[:], isResume); err != nil {
return err
}
if c.config.Bugs.AlertBeforeFalseStartTest != 0 {
@@ -108,7 +108,7 @@ func (c *Conn) serverHandshake() error {
if err := hs.sendSessionTicket(); err != nil {
return err
}
- if err := hs.sendFinished(); err != nil {
+ if err := hs.sendFinished(nil); err != nil {
return err
}
}
@@ -274,6 +274,10 @@ Curves:
hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
}
+ if c.config.Bugs.NoRenegotiationInfo {
+ hs.hello.secureRenegotiation = nil
+ }
+
hs.hello.compressionMethod = compressionNone
hs.hello.duplicateExtension = c.config.Bugs.DuplicateExtension
if len(hs.clientHello.serverName) > 0 {
@@ -333,6 +337,12 @@ Curves:
_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+ // For test purposes, check that the peer never offers a session when
+ // renegotiating.
+ if c.cipherSuite != nil && len(hs.clientHello.sessionId) > 0 && c.config.Bugs.FailIfResumeOnRenego {
+ return false, errors.New("tls: offered resumption on renegotiation")
+ }
+
if hs.checkForResumption() {
return true, nil
}
@@ -382,10 +392,6 @@ Curves:
func (hs *serverHandshakeState) checkForResumption() bool {
c := hs.c
- if c.config.Bugs.NeverResumeOnRenego && c.cipherSuite != nil {
- return false
- }
-
if len(hs.clientHello.sessionTicket) > 0 {
if c.config.SessionTicketsDisabled {
return false
@@ -748,7 +754,7 @@ func (hs *serverHandshakeState) establishKeys() error {
return nil
}
-func (hs *serverHandshakeState) readFinished(isResume bool) error {
+func (hs *serverHandshakeState) readFinished(out []byte, isResume bool) error {
c := hs.c
c.readRecord(recordTypeChangeCipherSpec)
@@ -817,6 +823,7 @@ func (hs *serverHandshakeState) readFinished(isResume bool) error {
return errors.New("tls: client's Finished message is incorrect")
}
c.clientVerify = append(c.clientVerify[:0], clientFinished.verifyData...)
+ copy(out, clientFinished.verifyData)
hs.writeClientHash(clientFinished.marshal())
return nil
@@ -853,11 +860,12 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
return nil
}
-func (hs *serverHandshakeState) sendFinished() error {
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
c := hs.c
finished := new(finishedMsg)
finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+ copy(out, finished.verifyData)
if c.config.Bugs.BadFinished {
finished.verifyData[0]++
}
diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go
index 5e44b54..2ee0087 100644
--- a/src/ssl/test/runner/key_agreement.go
+++ b/src/ssl/test/runner/key_agreement.go
@@ -561,11 +561,18 @@ type dheKeyAgreement struct {
}
func (ka *dheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
- // 2048-bit MODP Group with 256-bit Prime Order Subgroup (RFC
- // 5114, Section 2.3)
- ka.p, _ = new(big.Int).SetString("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", 16)
- ka.g, _ = new(big.Int).SetString("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", 16)
- q, _ := new(big.Int).SetString("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", 16)
+ var q *big.Int
+ if p := config.Bugs.DHGroupPrime; p != nil {
+ ka.p = p
+ ka.g = big.NewInt(2)
+ q = p
+ } else {
+ // 2048-bit MODP Group with 256-bit Prime Order Subgroup (RFC
+ // 5114, Section 2.3)
+ ka.p, _ = new(big.Int).SetString("87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", 16)
+ ka.g, _ = new(big.Int).SetString("3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", 16)
+ q, _ = new(big.Int).SetString("8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", 16)
+ }
var err error
ka.xOurs, err = rand.Int(config.rand(), q)
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index ec2fede..bd03cb1 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "math/big"
"net"
"os"
"os/exec"
@@ -160,6 +161,10 @@ type testCase struct {
// resumeSession controls whether a second connection should be tested
// which attempts to resume the first session.
resumeSession bool
+ // expectResumeRejected, if true, specifies that the attempted
+ // resumption must be rejected by the client. This is only valid for a
+ // serverTest.
+ expectResumeRejected bool
// resumeConfig, if not nil, points to a Config to be used on
// resumption. Unless newSessionsOnResume is set,
// SessionTicketKey, ServerSessionCache, and
@@ -196,6 +201,9 @@ type testCase struct {
// flags, if not empty, contains a list of command-line flags that will
// be passed to the shim program.
flags []string
+ // testTLSUnique, if true, causes the shim to send the tls-unique value
+ // which will be compared against the expected value.
+ testTLSUnique bool
}
var testCases = []testCase{
@@ -1085,6 +1093,49 @@ var testCases = []testCase{
},
expectedCipher: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
},
+ {
+ protocol: dtls,
+ name: "SendSplitAlert-Sync",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSplitAlert: true,
+ },
+ },
+ },
+ {
+ protocol: dtls,
+ name: "SendSplitAlert-Async",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSplitAlert: true,
+ },
+ },
+ flags: []string{"-async"},
+ },
+ {
+ protocol: dtls,
+ name: "PackDTLSHandshake",
+ config: Config{
+ Bugs: ProtocolBugs{
+ MaxHandshakeRecordLength: 2,
+ PackHandshakeFragments: 20,
+ PackHandshakeRecords: 200,
+ },
+ },
+ },
+ {
+ testType: serverTest,
+ protocol: dtls,
+ name: "NoRC4-DTLS",
+ config: Config{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Bugs: ProtocolBugs{
+ EnableAllCiphersInDTLS: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":NO_SHARED_CIPHER:",
+ },
}
func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
@@ -1144,16 +1195,20 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
if isResume && test.expectedResumeVersion != 0 {
expectedVersion = test.expectedResumeVersion
}
- if vers := tlsConn.ConnectionState().Version; expectedVersion != 0 && vers != expectedVersion {
+ connState := tlsConn.ConnectionState()
+ if vers := connState.Version; expectedVersion != 0 && vers != expectedVersion {
return fmt.Errorf("got version %x, expected %x", vers, expectedVersion)
}
- if cipher := tlsConn.ConnectionState().CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher {
+ if cipher := connState.CipherSuite; test.expectedCipher != 0 && cipher != test.expectedCipher {
return fmt.Errorf("got cipher %x, expected %x", cipher, test.expectedCipher)
}
+ if didResume := connState.DidResume; isResume && didResume == test.expectResumeRejected {
+ return fmt.Errorf("didResume is %t, but we expected the opposite", didResume)
+ }
if test.expectChannelID {
- channelID := tlsConn.ConnectionState().ChannelID
+ channelID := connState.ChannelID
if channelID == nil {
return fmt.Errorf("no channel ID negotiated")
}
@@ -1165,18 +1220,18 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
}
if expected := test.expectedNextProto; expected != "" {
- if actual := tlsConn.ConnectionState().NegotiatedProtocol; actual != expected {
+ if actual := connState.NegotiatedProtocol; actual != expected {
return fmt.Errorf("next proto mismatch: got %s, wanted %s", actual, expected)
}
}
if test.expectedNextProtoType != 0 {
- if (test.expectedNextProtoType == alpn) != tlsConn.ConnectionState().NegotiatedProtocolFromALPN {
+ if (test.expectedNextProtoType == alpn) != connState.NegotiatedProtocolFromALPN {
return fmt.Errorf("next proto type mismatch")
}
}
- if p := tlsConn.ConnectionState().SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile {
+ if p := connState.SRTPProtectionProfile; p != test.expectedSRTPProtectionProfile {
return fmt.Errorf("SRTP profile mismatch: got %d, wanted %d", p, test.expectedSRTPProtectionProfile)
}
@@ -1194,6 +1249,17 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i
}
}
+ if test.testTLSUnique {
+ var peersValue [12]byte
+ if _, err := io.ReadFull(tlsConn, peersValue[:]); err != nil {
+ return err
+ }
+ expected := tlsConn.ConnectionState().TLSUnique
+ if !bytes.Equal(peersValue[:], expected) {
+ return fmt.Errorf("tls-unique mismatch: peer sent %x, but %x was expected", peersValue[:], expected)
+ }
+ }
+
if test.shimWritesFirst {
var buf [5]byte
_, err := io.ReadFull(tlsConn, buf[:])
@@ -1321,6 +1387,10 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
panic("Error expected without shouldFail in " + test.name)
}
+ if test.expectResumeRejected && !test.resumeSession {
+ panic("expectResumeRejected without resumeSession in " + test.name)
+ }
+
listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}})
if err != nil {
panic(err)
@@ -1371,6 +1441,13 @@ func runTest(test *testCase, buildDir string, mallocNumToFail int64) error {
flags = append(flags, "-use-export-context")
}
}
+ if test.expectResumeRejected {
+ flags = append(flags, "-expect-session-miss")
+ }
+
+ if test.testTLSUnique {
+ flags = append(flags, "-tls-unique")
+ }
flags = append(flags, test.flags...)
@@ -1569,6 +1646,14 @@ func isDTLSCipher(suiteName string) bool {
return !hasComponent(suiteName, "RC4")
}
+func bigFromHex(hex string) *big.Int {
+ ret, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("failed to parse hex number 0x" + hex)
+ }
+ return ret
+}
+
func addCipherSuiteTests() {
for _, suite := range testCipherSuites {
const psk = "12345"
@@ -1667,6 +1752,21 @@ func addCipherSuiteTests() {
}
}
}
+
+ testCases = append(testCases, testCase{
+ name: "WeakDH",
+ config: Config{
+ CipherSuites: []uint16{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ // This is a 1023-bit prime number, generated
+ // with:
+ // openssl gendh 1023 | openssl asn1parse -i
+ DHGroupPrime: bigFromHex("518E9B7930CE61C6E445C8360584E5FC78D9137C0FFDC880B495D5338ADF7689951A6821C17A76B3ACB8E0156AEA607B7EC406EBEDBB84D8376EB8FE8F8BA1433488BEE0C3EDDFD3A32DBB9481980A7AF6C96BFCF490A094CFFB2B8192C1BB5510B77B658436E27C2D4D023FE3718222AB0CA1273995B51F6D625A4944D0DD4B"),
+ },
+ },
+ shouldFail: true,
+ expectedError: "BAD_DH_P_LENGTH",
+ })
}
func addBadECDSASignatureTests() {
@@ -1866,245 +1966,235 @@ func addExtendedMasterSecretTests() {
}
}
- // When a session is resumed, it should still be aware that its master
- // secret was generated via EMS and thus it's safe to use tls-unique.
- testCases = append(testCases, testCase{
- name: "ExtendedMasterSecret-Resume",
- config: Config{
- Bugs: ProtocolBugs{
- RequireExtendedMasterSecret: true,
- },
- },
- flags: []string{expectEMSFlag},
- resumeSession: true,
- })
+ for _, isClient := range []bool{false, true} {
+ for _, supportedInFirstConnection := range []bool{false, true} {
+ for _, supportedInResumeConnection := range []bool{false, true} {
+ boolToWord := func(b bool) string {
+ if b {
+ return "Yes"
+ }
+ return "No"
+ }
+ suffix := boolToWord(supportedInFirstConnection) + "To" + boolToWord(supportedInResumeConnection) + "-"
+ if isClient {
+ suffix += "Client"
+ } else {
+ suffix += "Server"
+ }
+
+ supportedConfig := Config{
+ Bugs: ProtocolBugs{
+ RequireExtendedMasterSecret: true,
+ },
+ }
+
+ noSupportConfig := Config{
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: true,
+ },
+ }
+
+ test := testCase{
+ name: "ExtendedMasterSecret-" + suffix,
+ resumeSession: true,
+ }
+
+ if !isClient {
+ test.testType = serverTest
+ }
+
+ if supportedInFirstConnection {
+ test.config = supportedConfig
+ } else {
+ test.config = noSupportConfig
+ }
+
+ if supportedInResumeConnection {
+ test.resumeConfig = &supportedConfig
+ } else {
+ test.resumeConfig = &noSupportConfig
+ }
+
+ switch suffix {
+ case "YesToYes-Client", "YesToYes-Server":
+ // When a session is resumed, it should
+ // still be aware that its master
+ // secret was generated via EMS and
+ // thus it's safe to use tls-unique.
+ test.flags = []string{expectEMSFlag}
+ case "NoToYes-Server":
+ // If an original connection did not
+ // contain EMS, but a resumption
+ // handshake does, then a server should
+ // not resume the session.
+ test.expectResumeRejected = true
+ case "YesToNo-Server":
+ // Resuming an EMS session without the
+ // EMS extension should cause the
+ // server to abort the connection.
+ test.shouldFail = true
+ test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:"
+ case "NoToYes-Client":
+ // A client should abort a connection
+ // where the server resumed a non-EMS
+ // session but echoed the EMS
+ // extension.
+ test.shouldFail = true
+ test.expectedError = ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:"
+ case "YesToNo-Client":
+ // A client should abort a connection
+ // where the server didn't echo EMS
+ // when the session used it.
+ test.shouldFail = true
+ test.expectedError = ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:"
+ }
+
+ testCases = append(testCases, test)
+ }
+ }
+ }
}
// Adds tests that try to cover the range of the handshake state machine, under
// various conditions. Some of these are redundant with other tests, but they
// only cover the synchronous case.
func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) {
- var suffix string
- var flags []string
- var maxHandshakeRecordLength int
- if protocol == dtls {
- suffix = "-DTLS"
- }
- if async {
- suffix += "-Async"
- flags = append(flags, "-async")
- } else {
- suffix += "-Sync"
- }
- if splitHandshake {
- suffix += "-SplitHandshakeRecords"
- maxHandshakeRecordLength = 1
- }
+ var tests []testCase
// Basic handshake, with resumption. Client and server,
// session ID and session ticket.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "Basic-Client" + suffix,
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
- },
- flags: flags,
+ tests = append(tests, testCase{
+ name: "Basic-Client",
resumeSession: true,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "Basic-Client-RenewTicket" + suffix,
+ tests = append(tests, testCase{
+ name: "Basic-Client-RenewTicket",
config: Config{
Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- RenewTicketOnResume: true,
+ RenewTicketOnResume: true,
},
},
- flags: flags,
resumeSession: true,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "Basic-Client-NoTicket" + suffix,
+ tests = append(tests, testCase{
+ name: "Basic-Client-NoTicket",
config: Config{
SessionTicketsDisabled: true,
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: flags,
resumeSession: true,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "Basic-Client-Implicit" + suffix,
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
- },
- flags: append(flags, "-implicit-handshake"),
+ tests = append(tests, testCase{
+ name: "Basic-Client-Implicit",
+ flags: []string{"-implicit-handshake"},
resumeSession: true,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
- testType: serverTest,
- name: "Basic-Server" + suffix,
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
- },
- flags: flags,
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server",
resumeSession: true,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: serverTest,
- name: "Basic-Server-NoTickets" + suffix,
+ name: "Basic-Server-NoTickets",
config: Config{
SessionTicketsDisabled: true,
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: flags,
resumeSession: true,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
- testType: serverTest,
- name: "Basic-Server-Implicit" + suffix,
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
- },
- flags: append(flags, "-implicit-handshake"),
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-Implicit",
+ flags: []string{"-implicit-handshake"},
resumeSession: true,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
- testType: serverTest,
- name: "Basic-Server-EarlyCallback" + suffix,
- config: Config{
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
- },
- flags: append(flags, "-use-early-callback"),
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "Basic-Server-EarlyCallback",
+ flags: []string{"-use-early-callback"},
resumeSession: true,
})
// TLS client auth.
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: clientTest,
- name: "ClientAuth-Client" + suffix,
+ name: "ClientAuth-Client",
config: Config{
ClientAuth: RequireAnyClientCert,
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags,
+ flags: []string{
"-cert-file", rsaCertificateFile,
- "-key-file", rsaKeyFile),
+ "-key-file", rsaKeyFile,
+ },
})
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: serverTest,
- name: "ClientAuth-Server" + suffix,
+ name: "ClientAuth-Server",
config: Config{
Certificates: []Certificate{rsaCertificate},
},
- flags: append(flags, "-require-any-client-certificate"),
+ flags: []string{"-require-any-client-certificate"},
})
// No session ticket support; server doesn't send NewSessionTicket.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "SessionTicketsDisabled-Client" + suffix,
+ tests = append(tests, testCase{
+ name: "SessionTicketsDisabled-Client",
config: Config{
SessionTicketsDisabled: true,
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: flags,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: serverTest,
- name: "SessionTicketsDisabled-Server" + suffix,
+ name: "SessionTicketsDisabled-Server",
config: Config{
SessionTicketsDisabled: true,
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: flags,
})
// Skip ServerKeyExchange in PSK key exchange if there's no
// identity hint.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "EmptyPSKHint-Client" + suffix,
+ tests = append(tests, testCase{
+ name: "EmptyPSKHint-Client",
config: Config{
CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
PreSharedKey: []byte("secret"),
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags, "-psk", "secret"),
+ flags: []string{"-psk", "secret"},
})
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: serverTest,
- name: "EmptyPSKHint-Server" + suffix,
+ name: "EmptyPSKHint-Server",
config: Config{
CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA},
PreSharedKey: []byte("secret"),
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags, "-psk", "secret"),
+ flags: []string{"-psk", "secret"},
})
if protocol == tls {
+ tests = append(tests, testCase{
+ name: "Renegotiate-Client",
+ renegotiate: true,
+ })
// NPN on client and server; results in post-handshake message.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "NPN-Client" + suffix,
+ tests = append(tests, testCase{
+ name: "NPN-Client",
config: Config{
NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags, "-select-next-proto", "foo"),
+ flags: []string{"-select-next-proto", "foo"},
expectedNextProto: "foo",
expectedNextProtoType: npn,
})
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: serverTest,
- name: "NPN-Server" + suffix,
+ name: "NPN-Server",
config: Config{
NextProtos: []string{"bar"},
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags,
+ flags: []string{
"-advertise-npn", "\x03foo\x03bar\x03baz",
- "-expect-next-proto", "bar"),
+ "-expect-next-proto", "bar",
+ },
expectedNextProto: "bar",
expectedNextProtoType: npn,
})
@@ -2112,146 +2202,148 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
// TODO(davidben): Add tests for when False Start doesn't trigger.
// Client does False Start and negotiates NPN.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "FalseStart" + suffix,
+ tests = append(tests, testCase{
+ name: "FalseStart",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ ExpectFalseStart: true,
},
},
- flags: append(flags,
+ flags: []string{
"-false-start",
- "-select-next-proto", "foo"),
+ "-select-next-proto", "foo",
+ },
shimWritesFirst: true,
resumeSession: true,
})
// Client does False Start and negotiates ALPN.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "FalseStart-ALPN" + suffix,
+ tests = append(tests, testCase{
+ name: "FalseStart-ALPN",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ ExpectFalseStart: true,
},
},
- flags: append(flags,
+ flags: []string{
"-false-start",
- "-advertise-alpn", "\x03foo"),
+ "-advertise-alpn", "\x03foo",
+ },
shimWritesFirst: true,
resumeSession: true,
})
// Client does False Start but doesn't explicitly call
// SSL_connect.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "FalseStart-Implicit" + suffix,
+ tests = append(tests, testCase{
+ name: "FalseStart-Implicit",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags,
+ flags: []string{
"-implicit-handshake",
"-false-start",
- "-advertise-alpn", "\x03foo"),
+ "-advertise-alpn", "\x03foo",
+ },
})
// False Start without session tickets.
- testCases = append(testCases, testCase{
- name: "FalseStart-SessionTicketsDisabled" + suffix,
+ tests = append(tests, testCase{
+ name: "FalseStart-SessionTicketsDisabled",
config: Config{
CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
NextProtos: []string{"foo"},
SessionTicketsDisabled: true,
Bugs: ProtocolBugs{
- ExpectFalseStart: true,
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
+ ExpectFalseStart: true,
},
},
- flags: append(flags,
+ flags: []string{
"-false-start",
"-select-next-proto", "foo",
- ),
+ },
shimWritesFirst: true,
})
// Server parses a V2ClientHello.
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: serverTest,
- name: "SendV2ClientHello" + suffix,
+ name: "SendV2ClientHello",
config: Config{
// Choose a cipher suite that does not involve
// elliptic curves, so no extensions are
// involved.
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- SendV2ClientHello: true,
+ SendV2ClientHello: true,
},
},
- flags: flags,
})
// Client sends a Channel ID.
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "ChannelID-Client" + suffix,
+ tests = append(tests, testCase{
+ name: "ChannelID-Client",
config: Config{
RequestChannelID: true,
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags,
- "-send-channel-id", channelIDKeyFile,
- ),
+ flags: []string{"-send-channel-id", channelIDKeyFile},
resumeSession: true,
expectChannelID: true,
})
// Server accepts a Channel ID.
- testCases = append(testCases, testCase{
- protocol: protocol,
+ tests = append(tests, testCase{
testType: serverTest,
- name: "ChannelID-Server" + suffix,
+ name: "ChannelID-Server",
config: Config{
ChannelID: channelIDKey,
- Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- },
},
- flags: append(flags,
+ flags: []string{
"-expect-channel-id",
base64.StdEncoding.EncodeToString(channelIDBytes),
- ),
+ },
resumeSession: true,
expectChannelID: true,
})
} else {
- testCases = append(testCases, testCase{
- protocol: protocol,
- name: "SkipHelloVerifyRequest" + suffix,
+ tests = append(tests, testCase{
+ name: "SkipHelloVerifyRequest",
config: Config{
Bugs: ProtocolBugs{
- MaxHandshakeRecordLength: maxHandshakeRecordLength,
- SkipHelloVerifyRequest: true,
+ SkipHelloVerifyRequest: true,
},
},
- flags: flags,
})
}
+
+ var suffix string
+ var flags []string
+ var maxHandshakeRecordLength int
+ if protocol == dtls {
+ suffix = "-DTLS"
+ }
+ if async {
+ suffix += "-Async"
+ flags = append(flags, "-async")
+ } else {
+ suffix += "-Sync"
+ }
+ if splitHandshake {
+ suffix += "-SplitHandshakeRecords"
+ maxHandshakeRecordLength = 1
+ }
+ for _, test := range tests {
+ test.protocol = protocol
+ test.name += suffix
+ test.config.Bugs.MaxHandshakeRecordLength = maxHandshakeRecordLength
+ test.flags = append(test.flags, flags...)
+ testCases = append(testCases, test)
+ }
}
func addDDoSCallbackTests() {
@@ -2637,8 +2729,8 @@ func addExtensionTests() {
CorruptTicket: true,
},
},
- resumeSession: true,
- flags: []string{"-expect-session-miss"},
+ resumeSession: true,
+ expectResumeRejected: true,
})
// Resume with an oversized session id.
testCases = append(testCases, testCase{
@@ -2799,7 +2891,6 @@ func addResumptionVersionTests() {
testCases = append(testCases, testCase{
protocol: protocol,
name: "Resume-Client-NoResume" + suffix,
- flags: []string{"-expect-session-miss"},
resumeSession: true,
config: Config{
MaxVersion: sessionVers.version,
@@ -2811,24 +2902,21 @@ func addResumptionVersionTests() {
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
},
newSessionsOnResume: true,
+ expectResumeRejected: true,
expectedResumeVersion: resumeVers.version,
})
- var flags []string
- if sessionVers.version != resumeVers.version {
- flags = append(flags, "-expect-session-miss")
- }
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
name: "Resume-Server" + suffix,
- flags: flags,
resumeSession: true,
config: Config{
MaxVersion: sessionVers.version,
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
},
- expectedVersion: sessionVers.version,
+ expectedVersion: sessionVers.version,
+ expectResumeRejected: sessionVers.version != resumeVers.version,
resumeConfig: &Config{
MaxVersion: resumeVers.version,
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
@@ -2857,57 +2945,50 @@ func addResumptionVersionTests() {
}
func addRenegotiationTests() {
+ // Servers cannot renegotiate.
testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server",
- flags: []string{"-renegotiate"},
- shimWritesFirst: true,
+ testType: serverTest,
+ name: "Renegotiate-Server-Forbidden",
+ renegotiate: true,
+ flags: []string{"-reject-peer-renegotiations"},
+ shouldFail: true,
+ expectedError: ":NO_RENEGOTIATION:",
+ expectedLocalError: "remote error: no renegotiation",
})
+ // TODO(agl): test the renegotiation info SCSV.
testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-Full",
+ name: "Renegotiate-Client",
config: Config{
Bugs: ProtocolBugs{
- NeverResumeOnRenego: true,
+ FailIfResumeOnRenego: true,
},
},
- flags: []string{"-renegotiate"},
- shimWritesFirst: true,
+ renegotiate: true,
})
testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-EmptyExt",
+ name: "Renegotiate-Client-EmptyExt",
+ renegotiate: true,
config: Config{
Bugs: ProtocolBugs{
EmptyRenegotiationInfo: true,
},
},
- flags: []string{"-renegotiate"},
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
})
testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-BadExt",
+ name: "Renegotiate-Client-BadExt",
+ renegotiate: true,
config: Config{
Bugs: ProtocolBugs{
BadRenegotiationInfo: true,
},
},
- flags: []string{"-renegotiate"},
- shimWritesFirst: true,
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
- })
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-ClientInitiated",
- renegotiate: true,
+ shouldFail: true,
+ expectedError: ":RENEGOTIATION_MISMATCH:",
})
testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-ClientInitiated-NoExt",
+ name: "Renegotiate-Client-NoExt",
renegotiate: true,
config: Config{
Bugs: ProtocolBugs{
@@ -2916,75 +2997,16 @@ func addRenegotiationTests() {
},
shouldFail: true,
expectedError: ":UNSAFE_LEGACY_RENEGOTIATION_DISABLED:",
+ flags: []string{"-no-legacy-server-connect"},
})
testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-ClientInitiated-NoExt-Allowed",
+ name: "Renegotiate-Client-NoExt-Allowed",
renegotiate: true,
config: Config{
Bugs: ProtocolBugs{
NoRenegotiationInfo: true,
},
},
- flags: []string{"-allow-unsafe-legacy-renegotiation"},
- })
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-ClientInitiated-Forbidden",
- renegotiate: true,
- flags: []string{"-reject-peer-renegotiations"},
- shouldFail: true,
- expectedError: ":NO_RENEGOTIATION:",
- expectedLocalError: "remote error: no renegotiation",
- })
- // Regression test for CVE-2015-0291.
- testCases = append(testCases, testCase{
- testType: serverTest,
- name: "Renegotiate-Server-NoSignatureAlgorithms",
- config: Config{
- Bugs: ProtocolBugs{
- NeverResumeOnRenego: true,
- NoSignatureAlgorithmsOnRenego: true,
- },
- },
- flags: []string{"-renegotiate"},
- shimWritesFirst: true,
- })
- // TODO(agl): test the renegotiation info SCSV.
- testCases = append(testCases, testCase{
- name: "Renegotiate-Client",
- renegotiate: true,
- })
- testCases = append(testCases, testCase{
- name: "Renegotiate-Client-Full",
- config: Config{
- Bugs: ProtocolBugs{
- NeverResumeOnRenego: true,
- },
- },
- renegotiate: true,
- })
- testCases = append(testCases, testCase{
- name: "Renegotiate-Client-EmptyExt",
- renegotiate: true,
- config: Config{
- Bugs: ProtocolBugs{
- EmptyRenegotiationInfo: true,
- },
- },
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
- })
- testCases = append(testCases, testCase{
- name: "Renegotiate-Client-BadExt",
- renegotiate: true,
- config: Config{
- Bugs: ProtocolBugs{
- BadRenegotiationInfo: true,
- },
- },
- shouldFail: true,
- expectedError: ":RENEGOTIATION_MISMATCH:",
})
testCases = append(testCases, testCase{
name: "Renegotiate-Client-SwitchCiphers",
@@ -3365,6 +3387,59 @@ func addExportKeyingMaterialTests() {
})
}
+func addTLSUniqueTests() {
+ for _, isClient := range []bool{false, true} {
+ for _, isResumption := range []bool{false, true} {
+ for _, hasEMS := range []bool{false, true} {
+ var suffix string
+ if isResumption {
+ suffix = "Resume-"
+ } else {
+ suffix = "Full-"
+ }
+
+ if hasEMS {
+ suffix += "EMS-"
+ } else {
+ suffix += "NoEMS-"
+ }
+
+ if isClient {
+ suffix += "Client"
+ } else {
+ suffix += "Server"
+ }
+
+ test := testCase{
+ name: "TLSUnique-" + suffix,
+ testTLSUnique: true,
+ config: Config{
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: !hasEMS,
+ },
+ },
+ }
+
+ if isResumption {
+ test.resumeSession = true
+ test.resumeConfig = &Config{
+ Bugs: ProtocolBugs{
+ NoExtendedMasterSecret: !hasEMS,
+ },
+ }
+ }
+
+ if isResumption && !hasEMS {
+ test.shouldFail = true
+ test.expectedError = "failed to get tls-unique"
+ }
+
+ testCases = append(testCases, test)
+ }
+ }
+ }
+}
+
func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) {
defer wg.Done()
@@ -3463,6 +3538,7 @@ func main() {
addFastRadioPaddingTests()
addDTLSRetransmitTests()
addExportKeyingMaterialTests()
+ addTLSUniqueTests()
for _, async := range []bool{false, true} {
for _, splitHandshake := range []bool{false, true} {
for _, protocol := range []protocol{tls, dtls} {