Import RSAEphemeralKey tests from master.

This is a cherry-pick of https://boringssl-review.googlesource.com/#/c/2232/
and https://boringssl-review.googlesource.com/#/c/3650/ from master.

Change-Id: Ia488e629f20a92121beefcf7e106292030b41f67
Reviewed-on: https://boringssl-review.googlesource.com/3660
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
index 5a3ac80..62b8100 100644
--- a/ssl/test/runner/cipher_suites.go
+++ b/ssl/test/runner/cipher_suites.go
@@ -289,7 +289,7 @@
 }
 
 func rsaKA(version uint16) keyAgreement {
-	return rsaKeyAgreement{}
+	return &rsaKeyAgreement{version: version}
 }
 
 func ecdheECDSAKA(version uint16) keyAgreement {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 6f146af..1f7e392 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -499,6 +499,11 @@
 	// BadRenegotiationInfo causes the renegotiation extension value in a
 	// renegotiation handshake to be incorrect.
 	BadRenegotiationInfo bool
+
+	// RSAEphemeralKey, if true, causes the server to send a
+	// ServerKeyExchange message containing an ephemeral key (as in
+	// RSA_EXPORT) in the plain RSA key exchange.
+	RSAEphemeralKey bool
 }
 
 func (c *Config) serverInit() {
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index af54a8f..86202ae 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -25,10 +25,71 @@
 
 // rsaKeyAgreement implements the standard TLS key agreement where the client
 // encrypts the pre-master secret to the server's public key.
-type rsaKeyAgreement struct{}
+type rsaKeyAgreement struct {
+	version       uint16
+	exportKey     *rsa.PrivateKey
+}
 
-func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
-	return nil, nil
+func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	if !config.Bugs.RSAEphemeralKey {
+		return nil, nil
+	}
+
+	// Generate an ephemeral RSA key to use instead of the real
+	// one, as in RSA_EXPORT.
+	key, err := rsa.GenerateKey(config.rand(), 512)
+	if err != nil {
+		return nil, err
+	}
+	ka.exportKey = key
+
+	modulus := key.N.Bytes()
+	exponent := big.NewInt(int64(key.E)).Bytes()
+	serverRSAParams := make([]byte, 0, 2+len(modulus)+2+len(exponent))
+	serverRSAParams = append(serverRSAParams, byte(len(modulus)>>8), byte(len(modulus)))
+	serverRSAParams = append(serverRSAParams, modulus...)
+	serverRSAParams = append(serverRSAParams, byte(len(exponent)>>8), byte(len(exponent)))
+	serverRSAParams = append(serverRSAParams, exponent...)
+
+	var tls12HashId uint8
+	if ka.version >= VersionTLS12 {
+		if tls12HashId, err = pickTLS12HashForSignature(signatureRSA, clientHello.signatureAndHashes); err != nil {
+			return nil, err
+		}
+	}
+
+	digest, hashFunc, err := hashForServerKeyExchange(signatureRSA, tls12HashId, ka.version, clientHello.random, hello.random, serverRSAParams)
+	if err != nil {
+		return nil, err
+	}
+	var sig []byte
+	privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
+	if !ok {
+		return nil, errors.New("RSA requires a RSA server private key")
+	}
+	sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest)
+	if err != nil {
+		return nil, errors.New("failed to sign RSA parameters: " + err.Error())
+	}
+
+	skx := new(serverKeyExchangeMsg)
+	sigAndHashLen := 0
+	if ka.version >= VersionTLS12 {
+		sigAndHashLen = 2
+	}
+	skx.key = make([]byte, len(serverRSAParams)+sigAndHashLen+2+len(sig))
+	copy(skx.key, serverRSAParams)
+	k := skx.key[len(serverRSAParams):]
+	if ka.version >= VersionTLS12 {
+		k[0] = tls12HashId
+		k[1] = signatureRSA
+		k = k[2:]
+	}
+	k[0] = byte(len(sig) >> 8)
+	k[1] = byte(len(sig))
+	copy(k[2:], sig)
+
+	return skx, nil
 }
 
 func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
@@ -51,7 +112,11 @@
 		ciphertext = ckx.ciphertext[2:]
 	}
 
-	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
+	key := cert.PrivateKey.(*rsa.PrivateKey)
+	if ka.exportKey != nil {
+		key = ka.exportKey
+	}
+	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), key, ciphertext, preMasterSecret)
 	if err != nil {
 		return nil, err
 	}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 4b43481..57213bb 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -492,6 +492,17 @@
 		shouldFail:    true,
 		expectedError: ":WRONG_CIPHER_RETURNED:",
 	},
+	{
+		name: "RSAEphemeralKey",
+		config: Config{
+			CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+			Bugs: ProtocolBugs{
+				RSAEphemeralKey: true,
+			},
+		},
+		shouldFail:    true,
+		expectedError: ":UNEXPECTED_MESSAGE:",
+	},
 }
 
 func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {