Tighten SSL_OP_LEGACY_SERVER_CONNECT to align with RFC 5746.

RFC 5746 forbids a server from downgrading or upgrading
renegotiation_info support. Even with SSL_OP_LEGACY_SERVER_CONNECT set
(the default), we can still enforce a few things.

I do not believe this has practical consequences. The attack variant
where the server half is prefixed does not involve a renegotiation on
the client. The converse where the client sees the renegotiation and
prefix does, but we only support renego for the mid-stream HTTP/1.1
client auth hack, which doesn't do this. (And with triple-handshake,
HTTPS clients should be requiring the certificate be unchanged across
renego which makes this moot.)

Ultimately, an application which makes the mistake of using
renegotiation needs to be aware of what exactly that means and how to
handle connection state changing mid-stream. We make renego opt-in now,
so this is a tenable requirement.

(Also the legacy -> secure direction would have been caught by the
server anyway since we send a non-empty RI extension.)

Change-Id: I915965c342f8a9cf3a4b6b32f0a87a00c3df3559
Reviewed-on: https://boringssl-review.googlesource.com/6559
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 4ac2341..143b0e0 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -579,10 +579,18 @@
 	// renegotiation handshake to be incorrect.
 	BadRenegotiationInfo bool
 
-	// NoRenegotiationInfo causes the client to behave as if it
-	// didn't support the renegotiation info extension.
+	// NoRenegotiationInfo disables renegotiation info support in all
+	// handshakes.
 	NoRenegotiationInfo bool
 
+	// NoRenegotiationInfoInInitial disables renegotiation info support in
+	// the initial handshake.
+	NoRenegotiationInfoInInitial bool
+
+	// NoRenegotiationInfoAfterInitial disables renegotiation info support
+	// in renegotiation handshakes.
+	NoRenegotiationInfoAfterInitial bool
+
 	// RequireRenegotiationInfo, if true, causes the client to return an
 	// error if the server doesn't reply with the renegotiation extension.
 	RequireRenegotiationInfo bool
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index ab9e233..7178d20 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -1414,3 +1414,18 @@
 	prfForVersion(c.vers, c.cipherSuite)(result, c.masterSecret[:], label, seed)
 	return result, nil
 }
+
+// noRenegotiationInfo returns true if the renegotiation info extension
+// should be supported in the current handshake.
+func (c *Conn) noRenegotiationInfo() bool {
+	if c.config.Bugs.NoRenegotiationInfo {
+		return true
+	}
+	if c.cipherSuite == nil && c.config.Bugs.NoRenegotiationInfoInInitial {
+		return true
+	}
+	if c.cipherSuite != nil && c.config.Bugs.NoRenegotiationInfoAfterInitial {
+		return true
+	}
+	return false
+}
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 9d8ffee..512d23f 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -98,7 +98,7 @@
 		}
 	}
 
-	if c.config.Bugs.NoRenegotiationInfo {
+	if c.noRenegotiationInfo() {
 		hello.secureRenegotiation = nil
 	}
 
@@ -282,7 +282,7 @@
 		return errors.New("tls: renegotiation extension missing")
 	}
 
-	if len(c.clientVerify) > 0 && !c.config.Bugs.NoRenegotiationInfo {
+	if len(c.clientVerify) > 0 && !c.noRenegotiationInfo() {
 		var expectedRenegInfo []byte
 		expectedRenegInfo = append(expectedRenegInfo, c.clientVerify...)
 		expectedRenegInfo = append(expectedRenegInfo, c.serverVerify...)
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 568f836..61c6cbe 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -286,7 +286,7 @@
 		hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
 	}
 
-	if c.config.Bugs.NoRenegotiationInfo {
+	if c.noRenegotiationInfo() {
 		hs.hello.secureRenegotiation = nil
 	}
 
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 5a8f56b..3c4e2ea 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -3804,6 +3804,30 @@
 		flags:         []string{"-no-legacy-server-connect"},
 	})
 	testCases = append(testCases, testCase{
+		name:        "Renegotiate-Client-Downgrade",
+		renegotiate: 1,
+		config: Config{
+			Bugs: ProtocolBugs{
+				NoRenegotiationInfoAfterInitial: true,
+			},
+		},
+		flags:         []string{"-renegotiate-freely"},
+		shouldFail:    true,
+		expectedError: ":RENEGOTIATION_MISMATCH:",
+	})
+	testCases = append(testCases, testCase{
+		name:        "Renegotiate-Client-Upgrade",
+		renegotiate: 1,
+		config: Config{
+			Bugs: ProtocolBugs{
+				NoRenegotiationInfoInInitial: true,
+			},
+		},
+		flags:         []string{"-renegotiate-freely"},
+		shouldFail:    true,
+		expectedError: ":RENEGOTIATION_MISMATCH:",
+	})
+	testCases = append(testCases, testCase{
 		name:        "Renegotiate-Client-NoExt-Allowed",
 		renegotiate: 1,
 		config: Config{