Pull Go TLS server extension logic into its own function.

As with the client, the logic around extensions in 1.3 will want to be
tweaked. readClientHello will probably shrink a bit. (We could probably
stuff 1.3 into the existing parameter negotiation logic, but I expect
it'll get a bit unwieldy once HelloRetryRequest, PSK resumption, and
0-RTT get in there, so I think it's best we leave them separate.)

Change-Id: Id8c323a06a1def6857a59accd9f87fb0b088385a
Reviewed-on: https://boringssl-review.googlesource.com/8596
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 771beea..8dd533e 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -218,12 +218,10 @@
 	}
 	c.haveVers = true
 
-	hs.hello = &serverHelloMsg{
-		isDTLS: c.isDTLS,
-		extensions: serverExtensions{
-			customExtension: config.Bugs.CustomExtension,
-			npnLast:         config.Bugs.SwapNPNAndALPN,
-		},
+	hs.hello = &serverHelloMsg{isDTLS: c.isDTLS}
+
+	if err := hs.processClientExtensions(&hs.hello.extensions); err != nil {
+		return false, err
 	}
 
 	supportedCurve := false
@@ -272,93 +270,7 @@
 		return false, err
 	}
 
-	if !bytes.Equal(c.clientVerify, hs.clientHello.secureRenegotiation) {
-		c.sendAlert(alertHandshakeFailure)
-		return false, errors.New("tls: renegotiation mismatch")
-	}
-
-	if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo {
-		hs.hello.extensions.secureRenegotiation = append(hs.hello.extensions.secureRenegotiation, c.clientVerify...)
-		hs.hello.extensions.secureRenegotiation = append(hs.hello.extensions.secureRenegotiation, c.serverVerify...)
-		if c.config.Bugs.BadRenegotiationInfo {
-			hs.hello.extensions.secureRenegotiation[0] ^= 0x80
-		}
-	} else {
-		hs.hello.extensions.secureRenegotiation = hs.clientHello.secureRenegotiation
-	}
-
-	if c.noRenegotiationInfo() {
-		hs.hello.extensions.secureRenegotiation = nil
-	}
-
 	hs.hello.compressionMethod = compressionNone
-	hs.hello.extensions.duplicateExtension = c.config.Bugs.DuplicateExtension
-	if len(hs.clientHello.serverName) > 0 {
-		c.serverName = hs.clientHello.serverName
-	}
-
-	if len(hs.clientHello.alpnProtocols) > 0 {
-		if proto := c.config.Bugs.ALPNProtocol; proto != nil {
-			hs.hello.extensions.alpnProtocol = *proto
-			hs.hello.extensions.alpnProtocolEmpty = len(*proto) == 0
-			c.clientProtocol = *proto
-			c.usedALPN = true
-		} else if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
-			hs.hello.extensions.alpnProtocol = selectedProto
-			c.clientProtocol = selectedProto
-			c.usedALPN = true
-		}
-	}
-	if len(hs.clientHello.alpnProtocols) == 0 || c.config.Bugs.NegotiateALPNAndNPN {
-		// Although sending an empty NPN extension is reasonable, Firefox has
-		// had a bug around this. Best to send nothing at all if
-		// config.NextProtos is empty. See
-		// https://code.google.com/p/go/issues/detail?id=5445.
-		if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
-			hs.hello.extensions.nextProtoNeg = true
-			hs.hello.extensions.nextProtos = config.NextProtos
-		}
-	}
-	hs.hello.extensions.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !c.config.Bugs.NoExtendedMasterSecret
-
-	if len(config.Certificates) == 0 {
-		c.sendAlert(alertInternalError)
-		return false, errors.New("tls: no certificates configured")
-	}
-	hs.cert = &config.Certificates[0]
-	if len(hs.clientHello.serverName) > 0 {
-		hs.cert = config.getCertificateForName(hs.clientHello.serverName)
-	}
-	if expected := c.config.Bugs.ExpectServerName; expected != "" && expected != hs.clientHello.serverName {
-		return false, errors.New("tls: unexpected server name")
-	}
-
-	if hs.clientHello.channelIDSupported && config.RequestChannelID {
-		hs.hello.extensions.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.extensions.srtpProtectionProfile = p1
-					c.srtpProtectionProfile = p1
-					break SRTPLoop
-				}
-			}
-		}
-	}
-
-	if c.config.Bugs.SendSRTPProtectionProfile != 0 {
-		hs.hello.extensions.srtpProtectionProfile = c.config.Bugs.SendSRTPProtectionProfile
-	}
-
-	if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil {
-		if hs.clientHello.customExtension != *expected {
-			return false, fmt.Errorf("tls: bad custom extension contents %q", hs.clientHello.customExtension)
-		}
-	}
 
 	_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
 
@@ -417,6 +329,105 @@
 	return false, nil
 }
 
+// processClientExtensions processes all ClientHello extensions not directly
+// related to cipher suite negotiation and writes responses in serverExtensions.
+func (hs *serverHandshakeState) processClientExtensions(serverExtensions *serverExtensions) error {
+	config := hs.c.config
+	c := hs.c
+
+	if !bytes.Equal(c.clientVerify, hs.clientHello.secureRenegotiation) {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: renegotiation mismatch")
+	}
+
+	if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo {
+		serverExtensions.secureRenegotiation = append(serverExtensions.secureRenegotiation, c.clientVerify...)
+		serverExtensions.secureRenegotiation = append(serverExtensions.secureRenegotiation, c.serverVerify...)
+		if c.config.Bugs.BadRenegotiationInfo {
+			serverExtensions.secureRenegotiation[0] ^= 0x80
+		}
+	} else {
+		serverExtensions.secureRenegotiation = hs.clientHello.secureRenegotiation
+	}
+
+	if c.noRenegotiationInfo() {
+		serverExtensions.secureRenegotiation = nil
+	}
+
+	serverExtensions.duplicateExtension = c.config.Bugs.DuplicateExtension
+
+	if len(hs.clientHello.serverName) > 0 {
+		c.serverName = hs.clientHello.serverName
+	}
+	if len(config.Certificates) == 0 {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: no certificates configured")
+	}
+	hs.cert = &config.Certificates[0]
+	if len(hs.clientHello.serverName) > 0 {
+		hs.cert = config.getCertificateForName(hs.clientHello.serverName)
+	}
+	if expected := c.config.Bugs.ExpectServerName; expected != "" && expected != hs.clientHello.serverName {
+		return errors.New("tls: unexpected server name")
+	}
+
+	if len(hs.clientHello.alpnProtocols) > 0 {
+		if proto := c.config.Bugs.ALPNProtocol; proto != nil {
+			serverExtensions.alpnProtocol = *proto
+			serverExtensions.alpnProtocolEmpty = len(*proto) == 0
+			c.clientProtocol = *proto
+			c.usedALPN = true
+		} else if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
+			serverExtensions.alpnProtocol = selectedProto
+			c.clientProtocol = selectedProto
+			c.usedALPN = true
+		}
+	}
+	if len(hs.clientHello.alpnProtocols) == 0 || c.config.Bugs.NegotiateALPNAndNPN {
+		// Although sending an empty NPN extension is reasonable, Firefox has
+		// had a bug around this. Best to send nothing at all if
+		// config.NextProtos is empty. See
+		// https://code.google.com/p/go/issues/detail?id=5445.
+		if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+			serverExtensions.nextProtoNeg = true
+			serverExtensions.nextProtos = config.NextProtos
+			serverExtensions.npnLast = config.Bugs.SwapNPNAndALPN
+		}
+	}
+
+	serverExtensions.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !c.config.Bugs.NoExtendedMasterSecret
+
+	if hs.clientHello.channelIDSupported && config.RequestChannelID {
+		serverExtensions.channelIDRequested = true
+	}
+
+	if hs.clientHello.srtpProtectionProfiles != nil {
+	SRTPLoop:
+		for _, p1 := range c.config.SRTPProtectionProfiles {
+			for _, p2 := range hs.clientHello.srtpProtectionProfiles {
+				if p1 == p2 {
+					serverExtensions.srtpProtectionProfile = p1
+					c.srtpProtectionProfile = p1
+					break SRTPLoop
+				}
+			}
+		}
+	}
+
+	if c.config.Bugs.SendSRTPProtectionProfile != 0 {
+		serverExtensions.srtpProtectionProfile = c.config.Bugs.SendSRTPProtectionProfile
+	}
+
+	if expected := c.config.Bugs.ExpectedCustomExtension; expected != nil {
+		if hs.clientHello.customExtension != *expected {
+			return fmt.Errorf("tls: bad custom extension contents %q", hs.clientHello.customExtension)
+		}
+	}
+	serverExtensions.customExtension = config.Bugs.CustomExtension
+
+	return nil
+}
+
 // checkForResumption returns true if we should perform resumption on this connection.
 func (hs *serverHandshakeState) checkForResumption() bool {
 	c := hs.c