crypto/tls: add ECDHE support

(ECDHE is "Elliptic Curve Diffie Hellman Ephemeral")

R=rsc
CC=golang-dev
https://golang.org/cl/3668042
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index 29c8aad..955811a 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -34,12 +34,37 @@
 
 	hello := new(serverHelloMsg)
 
+	supportedCurve := false
+Curves:
+	for _, curve := range clientHello.supportedCurves {
+		switch curve {
+		case curveP256, curveP384, curveP521:
+			supportedCurve = true
+			break Curves
+		}
+	}
+
+	supportedPointFormat := false
+	for _, pointFormat := range clientHello.supportedPoints {
+		if pointFormat == pointFormatUncompressed {
+			supportedPointFormat = true
+			break
+		}
+	}
+
+	ellipticOk := supportedCurve && supportedPointFormat
+
 	var suite *cipherSuite
 	var suiteId uint16
 	for _, id := range clientHello.cipherSuites {
 		for _, supported := range config.cipherSuites() {
 			if id == supported {
 				suite = cipherSuites[id]
+				// Don't select a ciphersuite which we can't
+				// support for this client.
+				if suite.elliptic && !ellipticOk {
+					continue
+				}
 				suiteId = id
 				break
 			}
@@ -89,6 +114,18 @@
 	finishedHash.Write(certMsg.marshal())
 	c.writeRecord(recordTypeHandshake, certMsg.marshal())
 
+	keyAgreement := suite.ka()
+
+	skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	if skx != nil {
+		finishedHash.Write(skx.marshal())
+		c.writeRecord(recordTypeHandshake, skx.marshal())
+	}
+
 	if config.AuthenticateClient {
 		// Request a client certificate
 		certReq := new(certificateRequestMsg)
@@ -185,23 +222,12 @@
 		finishedHash.Write(certVerify.marshal())
 	}
 
-	preMasterSecret := make([]byte, 48)
-	_, err = io.ReadFull(config.rand(), preMasterSecret[2:])
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
 	if err != nil {
-		return c.sendAlert(alertInternalError)
+		c.sendAlert(alertHandshakeFailure)
+		return err
 	}
 
-	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret)
-	if err != nil {
-		return c.sendAlert(alertHandshakeFailure)
-	}
-	// We don't check the version number in the premaster secret. For one,
-	// by checking it, we would leak information about the validity of the
-	// encrypted pre-master secret. Secondly, it provides only a small
-	// benefit against a downgrade attack and some implementations send the
-	// wrong version anyway. See the discussion at the end of section
-	// 7.4.7.1 of RFC 4346.
-
 	masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
 		keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)