runner: Implement DHE-RSA.

Use it to test DHE-RSA in BoringSSL.

Change-Id: I88f7bfa76507a6f60234d61d494c9f94b7df4e0a
Reviewed-on: https://boringssl-review.googlesource.com/1377
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 1cfe080..40bd533 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -112,6 +112,7 @@
   }
 
   SSL_CTX *ssl_ctx = NULL;
+  DH *dh = NULL;
 
   ssl_ctx = SSL_CTX_new(
       is_server ? SSLv23_server_method() : SSLv23_client_method());
@@ -127,6 +128,11 @@
     goto err;
   }
 
+  dh = DH_get_2048_256(NULL);
+  if (!SSL_CTX_set_tmp_dh(ssl_ctx, dh)) {
+    goto err;
+  }
+
   SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_BOTH);
 
   ssl_ctx->select_certificate_cb = select_certificate_callback;
@@ -136,9 +142,13 @@
   SSL_CTX_set_next_proto_select_cb(
       ssl_ctx, next_proto_select_callback, NULL);
 
+  DH_free(dh);
   return ssl_ctx;
 
  err:
+  if (dh != NULL) {
+    DH_free(dh);
+  }
   if (ssl_ctx != NULL) {
     SSL_CTX_free(ssl_ctx);
   }
diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go
index bf1a755..8a9df4c 100644
--- a/ssl/test/runner/cipher_suites.go
+++ b/ssl/test/runner/cipher_suites.go
@@ -82,11 +82,18 @@
 	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
+	{TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, dheRSAKA, suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, dheRSAKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, dheRSAKA, 0, cipherAES, macSHA1, nil},
+	{TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, dheRSAKA, 0, cipherAES, macSHA1, nil},
+	{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
+	{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
 	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
 	{TLS_RSA_WITH_RC4_128_MD5, 16, 16, 0, rsaKA, 0, cipherRC4, macMD5, nil},
 	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
+	{TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil},
 	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
 }
 
@@ -241,15 +248,28 @@
 
 func ecdheECDSAKA(version uint16) keyAgreement {
 	return &ecdheKeyAgreement{
-		sigType: signatureECDSA,
-		version: version,
+		signedKeyAgreement: signedKeyAgreement{
+			sigType: signatureECDSA,
+			version: version,
+		},
 	}
 }
 
 func ecdheRSAKA(version uint16) keyAgreement {
 	return &ecdheKeyAgreement{
-		sigType: signatureRSA,
-		version: version,
+		signedKeyAgreement: signedKeyAgreement{
+			sigType: signatureRSA,
+			version: version,
+		},
+	}
+}
+
+func dheRSAKA(version uint16) keyAgreement {
+	return &dheKeyAgreement{
+		signedKeyAgreement: signedKeyAgreement{
+			sigType: signatureRSA,
+			version: version,
+		},
 	}
 }
 
@@ -275,8 +295,15 @@
 	TLS_RSA_WITH_RC4_128_MD5                uint16 = 0x0004
 	TLS_RSA_WITH_RC4_128_SHA                uint16 = 0x0005
 	TLS_RSA_WITH_3DES_EDE_CBC_SHA           uint16 = 0x000a
+	TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA       uint16 = 0x0016
 	TLS_RSA_WITH_AES_128_CBC_SHA            uint16 = 0x002f
+	TLS_DHE_RSA_WITH_AES_128_CBC_SHA        uint16 = 0x0033
 	TLS_RSA_WITH_AES_256_CBC_SHA            uint16 = 0x0035
+	TLS_DHE_RSA_WITH_AES_256_CBC_SHA        uint16 = 0x0039
+	TLS_RSA_WITH_AES_128_GCM_SHA256         uint16 = 0x009c
+	TLS_RSA_WITH_AES_256_GCM_SHA384         uint16 = 0x009d
+	TLS_DHE_RSA_WITH_AES_128_GCM_SHA256     uint16 = 0x009e
+	TLS_DHE_RSA_WITH_AES_256_GCM_SHA384     uint16 = 0x009f
 	TLS_ECDHE_ECDSA_WITH_RC4_128_SHA        uint16 = 0xc007
 	TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA    uint16 = 0xc009
 	TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA    uint16 = 0xc00a
diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go
index 8681475..0e29d63 100644
--- a/ssl/test/runner/key_agreement.go
+++ b/ssl/test/runner/key_agreement.go
@@ -9,6 +9,7 @@
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/md5"
+	"crypto/rand"
 	"crypto/rsa"
 	"crypto/sha1"
 	"crypto/sha256"
@@ -177,13 +178,148 @@
 
 }
 
+// signedKeyAgreement implements helper functions for key agreement
+// methods that involve signed parameters in the ServerKeyExchange.
+type signedKeyAgreement struct {
+	version uint16
+	sigType uint8
+}
+
+func (ka *signedKeyAgreement) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) {
+	var tls12HashId uint8
+	var err error
+	if ka.version >= VersionTLS12 {
+		if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
+			return nil, err
+		}
+	}
+
+	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, params)
+	if err != nil {
+		return nil, err
+	}
+
+	if config.Bugs.InvalidSKXSignature {
+		digest[0] ^= 0x80
+	}
+
+	var sig []byte
+	switch ka.sigType {
+	case signatureECDSA:
+		privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key")
+		}
+		r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
+		if err != nil {
+			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+		}
+		order := privKey.Curve.Params().N
+		r = maybeCorruptECDSAValue(r, config.Bugs.BadECDSAR, order)
+		s = maybeCorruptECDSAValue(s, config.Bugs.BadECDSAS, order)
+		sig, err = asn1.Marshal(ecdsaSignature{r, s})
+	case signatureRSA:
+		privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
+		if !ok {
+			return nil, errors.New("ECDHE 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 ECDHE parameters: " + err.Error())
+		}
+	default:
+		return nil, errors.New("unknown ECDHE signature algorithm")
+	}
+
+	skx := new(serverKeyExchangeMsg)
+	if config.Bugs.UnauthenticatedECDH {
+		skx.key = params
+	} else {
+		sigAndHashLen := 0
+		if ka.version >= VersionTLS12 {
+			sigAndHashLen = 2
+		}
+		skx.key = make([]byte, len(params)+sigAndHashLen+2+len(sig))
+		copy(skx.key, params)
+		k := skx.key[len(params):]
+		if ka.version >= VersionTLS12 {
+			k[0] = tls12HashId
+			k[1] = ka.sigType
+			k = k[2:]
+		}
+		k[0] = byte(len(sig) >> 8)
+		k[1] = byte(len(sig))
+		copy(k[2:], sig)
+	}
+
+	return skx, nil
+}
+
+func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error {
+	if len(sig) < 2 {
+		return errServerKeyExchange
+	}
+
+	var tls12HashId uint8
+	if ka.version >= VersionTLS12 {
+		// handle SignatureAndHashAlgorithm
+		var sigAndHash []uint8
+		sigAndHash, sig = sig[:2], sig[2:]
+		if sigAndHash[1] != ka.sigType {
+			return errServerKeyExchange
+		}
+		tls12HashId = sigAndHash[0]
+		if len(sig) < 2 {
+			return errServerKeyExchange
+		}
+	}
+	sigLen := int(sig[0])<<8 | int(sig[1])
+	if sigLen+2 != len(sig) {
+		return errServerKeyExchange
+	}
+	sig = sig[2:]
+
+	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, params)
+	if err != nil {
+		return err
+	}
+	switch ka.sigType {
+	case signatureECDSA:
+		pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
+		if !ok {
+			return errors.New("ECDHE ECDSA requires a ECDSA server public key")
+		}
+		ecdsaSig := new(ecdsaSignature)
+		if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
+			return err
+		}
+		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+			return errors.New("ECDSA signature contained zero or negative values")
+		}
+		if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
+			return errors.New("ECDSA verification failure")
+		}
+	case signatureRSA:
+		pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
+		if !ok {
+			return errors.New("ECDHE RSA requires a RSA server public key")
+		}
+		if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
+			return err
+		}
+	default:
+		return errors.New("unknown ECDHE signature algorithm")
+	}
+
+	return nil
+}
+
 // ecdheRSAKeyAgreement implements a TLS key agreement where the server
 // generates a ephemeral EC public/private key pair and signs it. The
 // pre-master secret is then calculated using ECDH. The signature may
 // either be ECDSA or RSA.
 type ecdheKeyAgreement struct {
-	version    uint16
-	sigType    uint8
+	signedKeyAgreement
 	privateKey []byte
 	curve      elliptic.Curve
 	x, y       *big.Int
@@ -249,72 +385,7 @@
 	serverECDHParams[3] = byte(len(ecdhePublic))
 	copy(serverECDHParams[4:], ecdhePublic)
 
-	var tls12HashId uint8
-	if ka.version >= VersionTLS12 {
-		if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
-			return nil, err
-		}
-	}
-
-	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, serverECDHParams)
-	if err != nil {
-		return nil, err
-	}
-
-	if config.Bugs.InvalidSKXSignature {
-		digest[0] ^= 0x80
-	}
-
-	var sig []byte
-	switch ka.sigType {
-	case signatureECDSA:
-		privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
-		if !ok {
-			return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key")
-		}
-		r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
-		if err != nil {
-			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
-		}
-		order := privKey.Curve.Params().N
-		r = maybeCorruptECDSAValue(r, config.Bugs.BadECDSAR, order)
-		s = maybeCorruptECDSAValue(s, config.Bugs.BadECDSAS, order)
-		sig, err = asn1.Marshal(ecdsaSignature{r, s})
-	case signatureRSA:
-		privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
-		if !ok {
-			return nil, errors.New("ECDHE 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 ECDHE parameters: " + err.Error())
-		}
-	default:
-		return nil, errors.New("unknown ECDHE signature algorithm")
-	}
-
-	skx := new(serverKeyExchangeMsg)
-	if config.Bugs.UnauthenticatedECDH {
-		skx.key = serverECDHParams
-	} else {
-		sigAndHashLen := 0
-		if ka.version >= VersionTLS12 {
-			sigAndHashLen = 2
-		}
-		skx.key = make([]byte, len(serverECDHParams)+sigAndHashLen+2+len(sig))
-		copy(skx.key, serverECDHParams)
-		k := skx.key[len(serverECDHParams):]
-		if ka.version >= VersionTLS12 {
-			k[0] = tls12HashId
-			k[1] = ka.sigType
-			k = k[2:]
-		}
-		k[0] = byte(len(sig) >> 8)
-		k[1] = byte(len(sig))
-		copy(k[2:], sig)
-	}
-
-	return skx, nil
+	return ka.signParameters(config, cert, clientHello, hello, serverECDHParams)
 }
 
 func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
@@ -356,64 +427,9 @@
 		return errServerKeyExchange
 	}
 	serverECDHParams := skx.key[:4+publicLen]
-
 	sig := skx.key[4+publicLen:]
-	if len(sig) < 2 {
-		return errServerKeyExchange
-	}
 
-	var tls12HashId uint8
-	if ka.version >= VersionTLS12 {
-		// handle SignatureAndHashAlgorithm
-		var sigAndHash []uint8
-		sigAndHash, sig = sig[:2], sig[2:]
-		if sigAndHash[1] != ka.sigType {
-			return errServerKeyExchange
-		}
-		tls12HashId = sigAndHash[0]
-		if len(sig) < 2 {
-			return errServerKeyExchange
-		}
-	}
-	sigLen := int(sig[0])<<8 | int(sig[1])
-	if sigLen+2 != len(sig) {
-		return errServerKeyExchange
-	}
-	sig = sig[2:]
-
-	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, serverECDHParams)
-	if err != nil {
-		return err
-	}
-	switch ka.sigType {
-	case signatureECDSA:
-		pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
-		if !ok {
-			return errors.New("ECDHE ECDSA requires a ECDSA server public key")
-		}
-		ecdsaSig := new(ecdsaSignature)
-		if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
-			return err
-		}
-		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
-			return errors.New("ECDSA signature contained zero or negative values")
-		}
-		if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
-			return errors.New("ECDSA verification failure")
-		}
-	case signatureRSA:
-		pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
-		if !ok {
-			return errors.New("ECDHE RSA requires a RSA server public key")
-		}
-		if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
-			return err
-		}
-	default:
-		return errors.New("unknown ECDHE signature algorithm")
-	}
-
-	return nil
+	return ka.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
 }
 
 func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
@@ -438,3 +454,126 @@
 
 	return preMasterSecret, ckx, nil
 }
+
+// dheRSAKeyAgreement implements a TLS key agreement where the server generates
+// an ephemeral Diffie-Hellman public/private key pair and signs it. The
+// pre-master secret is then calculated using Diffie-Hellman.
+type dheKeyAgreement struct {
+	signedKeyAgreement
+	p, g    *big.Int
+	yTheirs *big.Int
+	xOurs   *big.Int
+}
+
+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 err error
+	ka.xOurs, err = rand.Int(config.rand(), q)
+	if err != nil {
+		return nil, err
+	}
+	yOurs := new(big.Int).Exp(ka.g, ka.xOurs, ka.p)
+
+	// http://tools.ietf.org/html/rfc5246#section-7.4.3
+	pBytes := ka.p.Bytes()
+	gBytes := ka.g.Bytes()
+	yBytes := yOurs.Bytes()
+	serverDHParams := make([]byte, 0, 2+len(pBytes)+2+len(gBytes)+2+len(yBytes))
+	serverDHParams = append(serverDHParams, byte(len(pBytes)>>8), byte(len(pBytes)))
+	serverDHParams = append(serverDHParams, pBytes...)
+	serverDHParams = append(serverDHParams, byte(len(gBytes)>>8), byte(len(gBytes)))
+	serverDHParams = append(serverDHParams, gBytes...)
+	serverDHParams = append(serverDHParams, byte(len(yBytes)>>8), byte(len(yBytes)))
+	serverDHParams = append(serverDHParams, yBytes...)
+
+	return ka.signParameters(config, cert, clientHello, hello, serverDHParams)
+}
+
+func (ka *dheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	if len(ckx.ciphertext) < 2 {
+		return nil, errClientKeyExchange
+	}
+	yLen := (int(ckx.ciphertext[0]) << 8) | int(ckx.ciphertext[1])
+	if yLen != len(ckx.ciphertext)-2 {
+		return nil, errClientKeyExchange
+	}
+	yTheirs := new(big.Int).SetBytes(ckx.ciphertext[2:])
+	if yTheirs.Sign() <= 0 || yTheirs.Cmp(ka.p) >= 0 {
+		return nil, errClientKeyExchange
+	}
+	return new(big.Int).Exp(yTheirs, ka.xOurs, ka.p).Bytes(), nil
+}
+
+func (ka *dheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+	// Read dh_p
+	k := skx.key
+	if len(k) < 2 {
+		return errServerKeyExchange
+	}
+	pLen := (int(k[0]) << 8) | int(k[1])
+	k = k[2:]
+	if len(k) < pLen {
+		return errServerKeyExchange
+	}
+	ka.p = new(big.Int).SetBytes(k[:pLen])
+	k = k[pLen:]
+
+	// Read dh_g
+	if len(k) < 2 {
+		return errServerKeyExchange
+	}
+	gLen := (int(k[0]) << 8) | int(k[1])
+	k = k[2:]
+	if len(k) < gLen {
+		return errServerKeyExchange
+	}
+	ka.g = new(big.Int).SetBytes(k[:gLen])
+	k = k[gLen:]
+
+	// Read dh_Ys
+	if len(k) < 2 {
+		return errServerKeyExchange
+	}
+	yLen := (int(k[0]) << 8) | int(k[1])
+	k = k[2:]
+	if len(k) < yLen {
+		return errServerKeyExchange
+	}
+	ka.yTheirs = new(big.Int).SetBytes(k[:yLen])
+	k = k[yLen:]
+	if ka.yTheirs.Sign() <= 0 || ka.yTheirs.Cmp(ka.p) >= 0 {
+		return errServerKeyExchange
+	}
+
+	sig := k
+	serverDHParams := skx.key[:len(skx.key)-len(sig)]
+
+	return ka.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig)
+}
+
+func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+	if ka.p == nil || ka.g == nil || ka.yTheirs == nil {
+		return nil, nil, errors.New("missing ServerKeyExchange message")
+	}
+
+	xOurs, err := rand.Int(config.rand(), ka.p)
+	if err != nil {
+		return nil, nil, err
+	}
+	preMasterSecret := new(big.Int).Exp(ka.yTheirs, xOurs, ka.p).Bytes()
+
+	yOurs := new(big.Int).Exp(ka.g, xOurs, ka.p)
+	yBytes := yOurs.Bytes()
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = make([]byte, 2+len(yBytes))
+	ckx.ciphertext[0] = byte(len(yBytes) >> 8)
+	ckx.ciphertext[1] = byte(len(yBytes))
+	copy(ckx.ciphertext[2:], yBytes)
+
+	return preMasterSecret, ckx, nil
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 109fdbf..cf9e44c 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -607,20 +607,27 @@
 	id   uint16
 }{
 	{"3DES-SHA", TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+	{"AES128-GCM", TLS_RSA_WITH_AES_128_GCM_SHA256},
 	{"AES128-SHA", TLS_RSA_WITH_AES_128_CBC_SHA},
+	{"AES256-GCM", TLS_RSA_WITH_AES_256_GCM_SHA384},
 	{"AES256-SHA", TLS_RSA_WITH_AES_256_CBC_SHA},
+	{"DHE-RSA-3DES-SHA", TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
+	{"DHE-RSA-AES128-GCM", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+	{"DHE-RSA-AES128-SHA", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
+	{"DHE-RSA-AES256-GCM", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
+	{"DHE-RSA-AES256-SHA", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
 	{"ECDHE-ECDSA-AES128-GCM", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
 	{"ECDHE-ECDSA-AES128-SHA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
 	{"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
 	{"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
 	{"ECDHE-RSA-3DES-SHA", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
 	{"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
-	{"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
 	{"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+	{"ECDHE-RSA-AES256-GCM", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
 	{"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
 	{"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
-	{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
 	{"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5},
+	{"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA},
 }
 
 func addCipherSuiteTests() {