Support generation of EC keys using P256 curve and support ECDSA certs.

This CL started life here: https://webrtc-codereview.appspot.com/51189004

BUG=webrtc:4685, webrtc:4686
R=hbos@webrtc.org, juberti@webrtc.org

Review URL: https://codereview.webrtc.org/1189583002 .

Cr-Commit-Position: refs/heads/master@{#9718}
diff --git a/webrtc/base/nssidentity.cc b/webrtc/base/nssidentity.cc
index bbcc73e..6511942 100644
--- a/webrtc/base/nssidentity.cc
+++ b/webrtc/base/nssidentity.cc
@@ -31,6 +31,7 @@
 #include "webrtc/base/helpers.h"
 #include "webrtc/base/nssstreamadapter.h"
 #include "webrtc/base/safe_conversions.h"
+#include "webrtc/base/stringutils.h"
 
 namespace rtc {
 
@@ -47,43 +48,69 @@
     SECKEY_DestroyPublicKey(pubkey_);
 }
 
-NSSKeyPair *NSSKeyPair::Generate() {
-  SECKEYPrivateKey *privkey = NULL;
-  SECKEYPublicKey *pubkey = NULL;
-  PK11RSAGenParams rsaparams;
-  rsaparams.keySizeInBits = 1024;
-  rsaparams.pe = 0x010001;  // 65537 -- a common RSA public exponent.
+NSSKeyPair* NSSKeyPair::Generate(KeyType key_type) {
+  SECKEYPrivateKey* privkey = nullptr;
+  SECKEYPublicKey* pubkey = nullptr;
+  SSLKEAType ssl_kea_type;
+  if (key_type == KT_RSA) {
+    PK11RSAGenParams rsa_params;
+    rsa_params.keySizeInBits = 1024;
+    rsa_params.pe = 0x010001;  // 65537 -- a common RSA public exponent.
 
-  privkey = PK11_GenerateKeyPair(NSSContext::GetSlot(),
-                                 CKM_RSA_PKCS_KEY_PAIR_GEN,
-                                 &rsaparams, &pubkey, PR_FALSE /*permanent*/,
-                                 PR_FALSE /*sensitive*/, NULL);
-  if (!privkey) {
-    LOG(LS_ERROR) << "Couldn't generate key pair";
-    return NULL;
+    privkey = PK11_GenerateKeyPair(
+        NSSContext::GetSlot(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsa_params, &pubkey,
+        PR_FALSE /*permanent*/, PR_FALSE /*sensitive*/, nullptr);
+
+    ssl_kea_type = ssl_kea_rsa;
+  } else if (key_type == KT_ECDSA) {
+    unsigned char param_buf[12];  // OIDs are small
+    SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)};
+    SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
+    if (!oid_data || oid_data->oid.len > sizeof(param_buf) - 2) {
+      LOG(LS_ERROR) << "oid_data incorrect: " << oid_data->oid.len;
+      return nullptr;
+    }
+    ecdsa_params.data[0] = SEC_ASN1_OBJECT_ID;
+    ecdsa_params.data[1] = oid_data->oid.len;
+    memcpy(ecdsa_params.data + 2, oid_data->oid.data, oid_data->oid.len);
+    ecdsa_params.len = oid_data->oid.len + 2;
+
+    privkey = PK11_GenerateKeyPair(
+        NSSContext::GetSlot(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params, &pubkey,
+        PR_FALSE /*permanent*/, PR_FALSE /*sensitive*/, nullptr);
+
+    ssl_kea_type = ssl_kea_ecdh;
+  } else {
+    LOG(LS_ERROR) << "Key type requested not understood";
+    return nullptr;
   }
 
-  return new NSSKeyPair(privkey, pubkey);
+  if (!privkey) {
+    LOG(LS_ERROR) << "Couldn't generate key pair: " << PORT_GetError();
+    return nullptr;
+  }
+
+  return new NSSKeyPair(privkey, pubkey, ssl_kea_type);
 }
 
 // Just make a copy.
-NSSKeyPair *NSSKeyPair::GetReference() {
-  SECKEYPrivateKey *privkey = SECKEY_CopyPrivateKey(privkey_);
+NSSKeyPair* NSSKeyPair::GetReference() {
+  SECKEYPrivateKey* privkey = SECKEY_CopyPrivateKey(privkey_);
   if (!privkey)
-    return NULL;
+    return nullptr;
 
-  SECKEYPublicKey *pubkey = SECKEY_CopyPublicKey(pubkey_);
+  SECKEYPublicKey* pubkey = SECKEY_CopyPublicKey(pubkey_);
   if (!pubkey) {
     SECKEY_DestroyPrivateKey(privkey);
-    return NULL;
+    return nullptr;
   }
 
-  return new NSSKeyPair(privkey, pubkey);
+  return new NSSKeyPair(privkey, pubkey, ssl_kea_type_);
 }
 
 NSSCertificate::NSSCertificate(CERTCertificate* cert)
     : certificate_(CERT_DupCertificate(cert)) {
-  ASSERT(certificate_ != NULL);
+  ASSERT(certificate_ != nullptr);
 }
 
 static void DeleteCert(SSLCertificate* cert) {
@@ -112,7 +139,7 @@
 
 NSSCertificate::NSSCertificate(CERTCertificate* cert, SSLCertChain* chain)
     : certificate_(CERT_DupCertificate(cert)) {
-  ASSERT(certificate_ != NULL);
+  ASSERT(certificate_ != nullptr);
   if (chain)
     chain_.reset(chain->Copy());
 }
@@ -122,27 +149,27 @@
     CERT_DestroyCertificate(certificate_);
 }
 
-NSSCertificate *NSSCertificate::FromPEMString(const std::string &pem_string) {
+NSSCertificate* NSSCertificate::FromPEMString(const std::string& pem_string) {
   std::string der;
   if (!SSLIdentity::PemToDer(kPemTypeCertificate, pem_string, &der))
-    return NULL;
+    return nullptr;
 
   SECItem der_cert;
   der_cert.data = reinterpret_cast<unsigned char *>(const_cast<char *>(
       der.data()));
   der_cert.len = checked_cast<unsigned int>(der.size());
-  CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
-      &der_cert, NULL, PR_FALSE, PR_TRUE);
+  CERTCertificate* cert = CERT_NewTempCertificate(
+      CERT_GetDefaultCertDB(), &der_cert, nullptr, PR_FALSE, PR_TRUE);
 
   if (!cert)
-    return NULL;
+    return nullptr;
 
   NSSCertificate* ret = new NSSCertificate(cert);
   CERT_DestroyCertificate(cert);
   return ret;
 }
 
-NSSCertificate *NSSCertificate::GetReference() const {
+NSSCertificate* NSSCertificate::GetReference() const {
   return new NSSCertificate(certificate_, chain_.get());
 }
 
@@ -180,8 +207,8 @@
 
   // Check that the parent's privkey was actually used to generate the child's
   // signature.
-  SECStatus verified = CERT_VerifySignedDataWithPublicKey(
-      &child->signatureWrap, parent_key, NULL);
+  SECStatus verified = CERT_VerifySignedDataWithPublicKey(&child->signatureWrap,
+                                                          parent_key, nullptr);
   SECKEY_DestroyPublicKey(parent_key);
   return verified == SECSuccess;
 }
@@ -199,7 +226,7 @@
 
 bool NSSCertificate::GetDigestLength(const std::string& algorithm,
                                      size_t* length) {
-  const SECHashObject *ho;
+  const SECHashObject* ho = nullptr;
 
   if (!GetDigestObject(algorithm, &ho))
     return false;
@@ -261,7 +288,7 @@
                                    unsigned char* digest,
                                    size_t size,
                                    size_t* length) const {
-  const SECHashObject *ho;
+  const SECHashObject* ho = nullptr;
 
   if (!GetDigestObject(algorithm, &ho))
     return false;
@@ -288,7 +315,7 @@
   return true;
 }
 
-bool NSSCertificate::Equals(const NSSCertificate *tocompare) const {
+bool NSSCertificate::Equals(const NSSCertificate* tocompare) const {
   if (!certificate_->derCert.len)
     return false;
   if (!tocompare->certificate_->derCert.len)
@@ -302,10 +329,9 @@
                 certificate_->derCert.len) == 0;
 }
 
-
-bool NSSCertificate::GetDigestObject(const std::string &algorithm,
-                                     const SECHashObject **hop) {
-  const SECHashObject *ho;
+bool NSSCertificate::GetDigestObject(const std::string& algorithm,
+                                     const SECHashObject** hop) {
+  const SECHashObject* ho;
   HASH_HashType hash_type;
 
   if (algorithm == DIGEST_SHA_1) {
@@ -339,14 +365,14 @@
 
 NSSIdentity* NSSIdentity::GenerateInternal(const SSLIdentityParams& params) {
   std::string subject_name_string = "CN=" + params.common_name;
-  CERTName *subject_name = CERT_AsciiToName(
-      const_cast<char *>(subject_name_string.c_str()));
-  NSSIdentity *identity = NULL;
-  CERTSubjectPublicKeyInfo *spki = NULL;
-  CERTCertificateRequest *certreq = NULL;
-  CERTValidity *validity = NULL;
-  CERTCertificate *certificate = NULL;
-  NSSKeyPair *keypair = NSSKeyPair::Generate();
+  CERTName* subject_name =
+      CERT_AsciiToName(const_cast<char*>(subject_name_string.c_str()));
+  NSSIdentity* identity = nullptr;
+  CERTSubjectPublicKeyInfo* spki = nullptr;
+  CERTCertificateRequest* certreq = nullptr;
+  CERTValidity* validity = nullptr;
+  CERTCertificate* certificate = nullptr;
+  NSSKeyPair* keypair = NSSKeyPair::Generate(params.key_type);
   SECItem inner_der;
   SECStatus rv;
   PLArenaPool* arena;
@@ -358,7 +384,7 @@
       now + static_cast<PRTime>(params.not_after) * PR_USEC_PER_SEC;
 
   inner_der.len = 0;
-  inner_der.data = NULL;
+  inner_der.data = nullptr;
 
   if (!keypair) {
     LOG(LS_ERROR) << "Couldn't generate key pair";
@@ -376,7 +402,7 @@
     goto fail;
   }
 
-  certreq = CERT_CreateCertificateRequest(subject_name, spki, NULL);
+  certreq = CERT_CreateCertificateRequest(subject_name, spki, nullptr);
   if (!certreq) {
     LOG(LS_ERROR) << "Couldn't create certificate signing request";
     goto fail;
@@ -405,22 +431,36 @@
 
   arena = certificate->arena;
 
-  rv = SECOID_SetAlgorithmID(arena, &certificate->signature,
-                             SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION, NULL);
-  if (rv != SECSuccess)
+  SECOidTag sec_oid;
+  if (params.key_type == KT_RSA) {
+    sec_oid = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
+  } else if (params.key_type == KT_ECDSA) {
+    sec_oid = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
+  } else {
+    // We should not arrive here since NSSKeyPair::Generate would have failed.
+    // Play it safe in order to accomodate code changes.
+    LOG(LS_ERROR) << "Key type requested not understood";
     goto fail;
+  }
+
+  rv = SECOID_SetAlgorithmID(arena, &certificate->signature, sec_oid, nullptr);
+  if (rv != SECSuccess) {
+    LOG(LS_ERROR) << "Couldn't set hashing algorithm";
+    goto fail;
+  }
 
   // Set version to X509v3.
   *(certificate->version.data) = 2;
   certificate->version.len = 1;
 
   if (!SEC_ASN1EncodeItem(arena, &inner_der, certificate,
-                          SEC_ASN1_GET(CERT_CertificateTemplate)))
+                          SEC_ASN1_GET(CERT_CertificateTemplate))) {
+    LOG(LS_ERROR) << "Couldn't encode certificate";
     goto fail;
+  }
 
   rv = SEC_DerSignData(arena, &signed_cert, inner_der.data, inner_der.len,
-                       keypair->privkey(),
-                       SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION);
+                       keypair->privkey(), sec_oid);
   if (rv != SECSuccess) {
     LOG(LS_ERROR) << "Couldn't sign certificate";
     goto fail;
@@ -443,11 +483,13 @@
   return identity;
 }
 
-NSSIdentity* NSSIdentity::Generate(const std::string &common_name) {
+NSSIdentity* NSSIdentity::Generate(const std::string& common_name,
+                                   KeyType key_type) {
   SSLIdentityParams params;
   params.common_name = common_name;
   params.not_before = CERTIFICATE_WINDOW;
   params.not_after = CERTIFICATE_LIFETIME;
+  params.key_type = key_type;
   return GenerateInternal(params);
 }
 
@@ -460,7 +502,7 @@
   std::string private_key_der;
   if (!SSLIdentity::PemToDer(
       kPemTypeRsaPrivateKey, private_key, &private_key_der))
-    return NULL;
+    return nullptr;
 
   SECItem private_key_item;
   private_key_item.data = reinterpret_cast<unsigned char *>(
@@ -470,35 +512,43 @@
   const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
       KU_DIGITAL_SIGNATURE;
 
-  SECKEYPrivateKey* privkey = NULL;
-  SECStatus rv =
-      PK11_ImportDERPrivateKeyInfoAndReturnKey(NSSContext::GetSlot(),
-                                               &private_key_item,
-                                               NULL, NULL, PR_FALSE, PR_FALSE,
-                                               key_usage, &privkey, NULL);
+  SECKEYPrivateKey* privkey = nullptr;
+  SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
+      NSSContext::GetSlot(), &private_key_item, nullptr, nullptr, PR_FALSE,
+      PR_FALSE, key_usage, &privkey, nullptr);
   if (rv != SECSuccess) {
     LOG(LS_ERROR) << "Couldn't import private key";
-    return NULL;
+    return nullptr;
   }
 
-  SECKEYPublicKey *pubkey = SECKEY_ConvertToPublicKey(privkey);
+  SECKEYPublicKey* pubkey = SECKEY_ConvertToPublicKey(privkey);
   if (rv != SECSuccess) {
     SECKEY_DestroyPrivateKey(privkey);
     LOG(LS_ERROR) << "Couldn't convert private key to public key";
-    return NULL;
+    return nullptr;
+  }
+
+  SSLKEAType ssl_kea_type;
+  if (rtc::starts_with(private_key.c_str(),
+                       "-----BEGIN RSA PRIVATE KEY-----")) {
+    ssl_kea_type = ssl_kea_rsa;
+  } else {
+    // We might want to check more key types here.  But since we're moving to
+    // Open/BoringSSL, don't bother.  Besides, this will likely be correct for
+    // any future key type, causing a test to do more harm than good.
+    ssl_kea_type = ssl_kea_ecdh;
   }
 
   // Assign to a scoped_ptr so we don't leak on error.
-  scoped_ptr<NSSKeyPair> keypair(new NSSKeyPair(privkey, pubkey));
+  scoped_ptr<NSSKeyPair> keypair(new NSSKeyPair(privkey, pubkey, ssl_kea_type));
 
   scoped_ptr<NSSCertificate> cert(NSSCertificate::FromPEMString(certificate));
   if (!cert) {
     LOG(LS_ERROR) << "Couldn't parse certificate";
-    return NULL;
+    return nullptr;
   }
 
   // TODO(ekr@rtfm.com): Check the public key against the certificate.
-
   return new NSSIdentity(keypair.release(), cert.release());
 }
 
@@ -506,15 +556,15 @@
   LOG(LS_INFO) << "Destroying NSS identity";
 }
 
-NSSIdentity *NSSIdentity::GetReference() const {
-  NSSKeyPair *keypair = keypair_->GetReference();
+NSSIdentity* NSSIdentity::GetReference() const {
+  NSSKeyPair* keypair = keypair_->GetReference();
   if (!keypair)
-    return NULL;
+    return nullptr;
 
-  NSSCertificate *certificate = certificate_->GetReference();
+  NSSCertificate* certificate = certificate_->GetReference();
   if (!certificate) {
     delete keypair;
-    return NULL;
+    return nullptr;
   }
 
   return new NSSIdentity(keypair, certificate);
@@ -529,4 +579,3 @@
 }  // rtc namespace
 
 #endif  // HAVE_NSS_SSL_H
-
diff --git a/webrtc/base/nssidentity.h b/webrtc/base/nssidentity.h
index 8a304e9..9ac76bf 100644
--- a/webrtc/base/nssidentity.h
+++ b/webrtc/base/nssidentity.h
@@ -24,6 +24,12 @@
 #include "hasht.h"
 #include "keythi.h"
 
+#ifdef NSS_SSL_RELATIVE_PATH
+#include "ssl.h"
+#else
+#include "net/third_party/nss/ssl/ssl.h"
+#endif
+
 #include "webrtc/base/common.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/scoped_ptr.h"
@@ -33,18 +39,24 @@
 
 class NSSKeyPair {
  public:
-  NSSKeyPair(SECKEYPrivateKey* privkey, SECKEYPublicKey* pubkey) :
-      privkey_(privkey), pubkey_(pubkey) {}
+  NSSKeyPair(SECKEYPrivateKey* privkey, SECKEYPublicKey* pubkey)
+      : privkey_(privkey), pubkey_(pubkey), ssl_kea_type_(ssl_kea_null) {}
+  NSSKeyPair(SECKEYPrivateKey* privkey,
+             SECKEYPublicKey* pubkey,
+             SSLKEAType ssl_kea_type)
+      : privkey_(privkey), pubkey_(pubkey), ssl_kea_type_(ssl_kea_type) {}
   ~NSSKeyPair();
 
   // Generate a 1024-bit RSA key pair.
-  static NSSKeyPair* Generate();
+  static NSSKeyPair* Generate(KeyType key_type);
   NSSKeyPair* GetReference();
 
   SECKEYPrivateKey* privkey() const { return privkey_; }
   SECKEYPublicKey * pubkey() const { return pubkey_; }
+  SSLKEAType ssl_kea_type() const { return ssl_kea_type_; }
 
  private:
+  SSLKEAType ssl_kea_type_;
   SECKEYPrivateKey* privkey_;
   SECKEYPublicKey* pubkey_;
 
@@ -103,7 +115,8 @@
 // Represents a SSL key pair and certificate for NSS.
 class NSSIdentity : public SSLIdentity {
  public:
-  static NSSIdentity* Generate(const std::string& common_name);
+  static NSSIdentity* Generate(const std::string& common_name,
+                               KeyType key_type);
   static NSSIdentity* GenerateForTest(const SSLIdentityParams& params);
   static SSLIdentity* FromPEMStrings(const std::string& private_key,
                                      const std::string& certificate);
diff --git a/webrtc/base/nssstreamadapter.cc b/webrtc/base/nssstreamadapter.cc
index 22f2a2e..2e78adf 100644
--- a/webrtc/base/nssstreamadapter.cc
+++ b/webrtc/base/nssstreamadapter.cc
@@ -68,9 +68,10 @@
 
 // Ciphers to enable to get ECDHE encryption with endpoints that support it.
 static const uint32_t kEnabledCiphers[] = {
-  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-};
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256};
 
 // Default cipher used between NSS stream adapters.
 // This needs to be updated when the default of the SSL library changes.
@@ -78,7 +79,10 @@
     "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
 static const char kDefaultSslCipher12[] =
     "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
-
+static const char kDefaultSslEcCipher10[] =
+    "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
+static const char kDefaultSslEcCipher12[] =
+    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
 
 // Implementation of NSPR methods
 static PRStatus StreamClose(PRFileDesc *socket) {
@@ -495,7 +499,7 @@
     }
     rv = SSL_ConfigSecureServer(ssl_fd_, identity->certificate().certificate(),
                                 identity->keypair()->privkey(),
-                                kt_rsa);
+                                identity->keypair()->ssl_kea_type());
     if (rv != SECSuccess) {
       Error("BeginSSL", -1, false);
       return -1;
@@ -1093,14 +1097,28 @@
   return true;
 }
 
-std::string NSSStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
-  switch (version) {
-    case SSL_PROTOCOL_TLS_10:
-    case SSL_PROTOCOL_TLS_11:
-      return kDefaultSslCipher10;
-    case SSL_PROTOCOL_TLS_12:
-    default:
-      return kDefaultSslCipher12;
+std::string NSSStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version,
+                                                  KeyType key_type) {
+  if (key_type == KT_RSA) {
+    switch (version) {
+      case SSL_PROTOCOL_TLS_10:
+      case SSL_PROTOCOL_TLS_11:
+        return kDefaultSslCipher10;
+      case SSL_PROTOCOL_TLS_12:
+      default:
+        return kDefaultSslCipher12;
+    }
+  } else if (key_type == KT_ECDSA) {
+    switch (version) {
+      case SSL_PROTOCOL_TLS_10:
+      case SSL_PROTOCOL_TLS_11:
+        return kDefaultSslEcCipher10;
+      case SSL_PROTOCOL_TLS_12:
+      default:
+        return kDefaultSslEcCipher12;
+    }
+  } else {
+    return std::string();
   }
 }
 
diff --git a/webrtc/base/nssstreamadapter.h b/webrtc/base/nssstreamadapter.h
index 65ac489..04c310e 100644
--- a/webrtc/base/nssstreamadapter.h
+++ b/webrtc/base/nssstreamadapter.h
@@ -91,7 +91,8 @@
   static bool HaveDtls();
   static bool HaveDtlsSrtp();
   static bool HaveExporter();
-  static std::string GetDefaultSslCipher(SSLProtocolVersion version);
+  static std::string GetDefaultSslCipher(SSLProtocolVersion version,
+                                         KeyType key_type);
 
  protected:
   // Override SSLStreamAdapter
diff --git a/webrtc/base/opensslidentity.cc b/webrtc/base/opensslidentity.cc
index dbb040e..de4e6a7 100644
--- a/webrtc/base/opensslidentity.cc
+++ b/webrtc/base/opensslidentity.cc
@@ -46,23 +46,40 @@
 static const int CERTIFICATE_WINDOW = -60*60*24;
 
 // Generate a key pair. Caller is responsible for freeing the returned object.
-static EVP_PKEY* MakeKey() {
+static EVP_PKEY* MakeKey(KeyType key_type) {
   LOG(LS_INFO) << "Making key pair";
   EVP_PKEY* pkey = EVP_PKEY_new();
-  // RSA_generate_key is deprecated. Use _ex version.
-  BIGNUM* exponent = BN_new();
-  RSA* rsa = RSA_new();
-  if (!pkey || !exponent || !rsa ||
-      !BN_set_word(exponent, 0x10001) ||  // 65537 RSA exponent
-      !RSA_generate_key_ex(rsa, KEY_LENGTH, exponent, NULL) ||
-      !EVP_PKEY_assign_RSA(pkey, rsa)) {
-    EVP_PKEY_free(pkey);
+  if (key_type == KT_RSA) {
+    BIGNUM* exponent = BN_new();
+    RSA* rsa = RSA_new();
+    if (!pkey || !exponent || !rsa ||
+        !BN_set_word(exponent, 0x10001) ||  // 65537 RSA exponent
+        !RSA_generate_key_ex(rsa, KEY_LENGTH, exponent, NULL) ||
+        !EVP_PKEY_assign_RSA(pkey, rsa)) {
+      EVP_PKEY_free(pkey);
+      BN_free(exponent);
+      RSA_free(rsa);
+      LOG(LS_ERROR) << "Failed to make RSA key pair";
+      return NULL;
+    }
+    // ownership of rsa struct was assigned, don't free it.
     BN_free(exponent);
-    RSA_free(rsa);
+  } else if (key_type == KT_ECDSA) {
+    EC_KEY* ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+    if (!pkey || !ec_key || !EC_KEY_generate_key(ec_key) ||
+        !EVP_PKEY_assign_EC_KEY(pkey, ec_key)) {
+      EVP_PKEY_free(pkey);
+      EC_KEY_free(ec_key);
+      LOG(LS_ERROR) << "Failed to make EC key pair";
+      return NULL;
+    }
+    // ownership of ec_key struct was assigned, don't free it.
+  } else {
+    EVP_PKEY_free(pkey);
+    LOG(LS_ERROR) << "Key type requested not understood";
     return NULL;
   }
-  // ownership of rsa struct was assigned, don't free it.
-  BN_free(exponent);
+
   LOG(LS_INFO) << "Returning key pair";
   return pkey;
 }
@@ -138,8 +155,8 @@
   }
 }
 
-OpenSSLKeyPair* OpenSSLKeyPair::Generate() {
-  EVP_PKEY* pkey = MakeKey();
+OpenSSLKeyPair* OpenSSLKeyPair::Generate(KeyType key_type) {
+  EVP_PKEY* pkey = MakeKey(key_type);
   if (!pkey) {
     LogSSLErrors("Generating key pair");
     return NULL;
@@ -207,8 +224,7 @@
   if (!bio)
     return NULL;
   BIO_set_mem_eof_return(bio, 0);
-  X509 *x509 = PEM_read_bio_X509(bio, NULL, NULL,
-                                 const_cast<char*>("\0"));
+  X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, const_cast<char*>("\0"));
   BIO_free(bio);  // Frees the BIO, but not the pointed-to string.
 
   if (!x509)
@@ -283,7 +299,7 @@
                                        unsigned char* digest,
                                        size_t size,
                                        size_t* length) {
-  const EVP_MD *md;
+  const EVP_MD* md;
   unsigned int n;
 
   if (!OpenSSLDigest::GetDigestEVP(algorithm, &md))
@@ -363,10 +379,10 @@
 
 OpenSSLIdentity* OpenSSLIdentity::GenerateInternal(
     const SSLIdentityParams& params) {
-  OpenSSLKeyPair *key_pair = OpenSSLKeyPair::Generate();
+  OpenSSLKeyPair* key_pair = OpenSSLKeyPair::Generate(params.key_type);
   if (key_pair) {
-    OpenSSLCertificate *certificate = OpenSSLCertificate::Generate(
-        key_pair, params);
+    OpenSSLCertificate* certificate =
+        OpenSSLCertificate::Generate(key_pair, params);
     if (certificate)
       return new OpenSSLIdentity(key_pair, certificate);
     delete key_pair;
@@ -375,11 +391,13 @@
   return NULL;
 }
 
-OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name) {
+OpenSSLIdentity* OpenSSLIdentity::Generate(const std::string& common_name,
+                                           KeyType key_type) {
   SSLIdentityParams params;
   params.common_name = common_name;
   params.not_before = CERTIFICATE_WINDOW;
   params.not_after = CERTIFICATE_LIFETIME;
+  params.key_type = key_type;
   return GenerateInternal(params);
 }
 
@@ -404,8 +422,8 @@
     return NULL;
   }
   BIO_set_mem_eof_return(bio, 0);
-  EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
-                                           const_cast<char*>("\0"));
+  EVP_PKEY* pkey =
+      PEM_read_bio_PrivateKey(bio, NULL, NULL, const_cast<char*>("\0"));
   BIO_free(bio);  // Frees the BIO, but not the pointed-to string.
 
   if (!pkey) {
diff --git a/webrtc/base/opensslidentity.h b/webrtc/base/opensslidentity.h
index ee7aabe..72de6c0 100644
--- a/webrtc/base/opensslidentity.h
+++ b/webrtc/base/opensslidentity.h
@@ -32,7 +32,7 @@
     ASSERT(pkey_ != NULL);
   }
 
-  static OpenSSLKeyPair* Generate();
+  static OpenSSLKeyPair* Generate(KeyType key_type);
 
   virtual ~OpenSSLKeyPair();
 
@@ -99,7 +99,8 @@
 // them consistently.
 class OpenSSLIdentity : public SSLIdentity {
  public:
-  static OpenSSLIdentity* Generate(const std::string& common_name);
+  static OpenSSLIdentity* Generate(const std::string& common_name,
+                                   KeyType key_type);
   static OpenSSLIdentity* GenerateForTest(const SSLIdentityParams& params);
   static SSLIdentity* FromPEMStrings(const std::string& private_key,
                                      const std::string& certificate);
diff --git a/webrtc/base/opensslstreamadapter.cc b/webrtc/base/opensslstreamadapter.cc
index 51921f1..3d17607 100644
--- a/webrtc/base/opensslstreamadapter.cc
+++ b/webrtc/base/opensslstreamadapter.cc
@@ -143,18 +143,26 @@
 // This needs to be updated when the default of the SSL library changes.
 static const char kDefaultSslCipher10[] =
     "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+static const char kDefaultSslEcCipher10[] =
+    "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
 
 #ifdef OPENSSL_IS_BORINGSSL
 static const char kDefaultSslCipher12[] =
     "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+static const char kDefaultSslEcCipher12[] =
+    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
 // Fallback cipher for DTLS 1.2 if hardware-accelerated AES-GCM is unavailable.
 static const char kDefaultSslCipher12NoAesGcm[] =
     "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256";
+static const char kDefaultSslEcCipher12NoAesGcm[] =
+    "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256";
 #else  // !OPENSSL_IS_BORINGSSL
 // OpenSSL sorts differently than BoringSSL, so the default cipher doesn't
 // change between TLS 1.0 and TLS 1.2 with the current setup.
 static const char kDefaultSslCipher12[] =
     "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+static const char kDefaultSslEcCipher12[] =
+    "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
 #endif
 
 //////////////////////////////////////////////////////////////////////
@@ -1118,22 +1126,44 @@
 }
 
 std::string OpenSSLStreamAdapter::GetDefaultSslCipher(
-    SSLProtocolVersion version) {
-  switch (version) {
-    case SSL_PROTOCOL_TLS_10:
-    case SSL_PROTOCOL_TLS_11:
-      return kDefaultSslCipher10;
-    case SSL_PROTOCOL_TLS_12:
-    default:
+    SSLProtocolVersion version,
+    KeyType key_type) {
+  if (key_type == KT_RSA) {
+    switch (version) {
+      case SSL_PROTOCOL_TLS_10:
+      case SSL_PROTOCOL_TLS_11:
+        return kDefaultSslCipher10;
+      case SSL_PROTOCOL_TLS_12:
+      default:
 #ifdef OPENSSL_IS_BORINGSSL
-      if (EVP_has_aes_hardware()) {
-        return kDefaultSslCipher12;
-      } else {
-        return kDefaultSslCipher12NoAesGcm;
-      }
+        if (EVP_has_aes_hardware()) {
+          return kDefaultSslCipher12;
+        } else {
+          return kDefaultSslCipher12NoAesGcm;
+        }
 #else  // !OPENSSL_IS_BORINGSSL
-      return kDefaultSslCipher12;
+        return kDefaultSslCipher12;
 #endif
+    }
+  } else if (key_type == KT_ECDSA) {
+    switch (version) {
+      case SSL_PROTOCOL_TLS_10:
+      case SSL_PROTOCOL_TLS_11:
+        return kDefaultSslEcCipher10;
+      case SSL_PROTOCOL_TLS_12:
+      default:
+#ifdef OPENSSL_IS_BORINGSSL
+        if (EVP_has_aes_hardware()) {
+          return kDefaultSslEcCipher12;
+        } else {
+          return kDefaultSslEcCipher12NoAesGcm;
+        }
+#else  // !OPENSSL_IS_BORINGSSL
+        return kDefaultSslEcCipher12;
+#endif
+    }
+  } else {
+    return std::string();
   }
 }
 
diff --git a/webrtc/base/opensslstreamadapter.h b/webrtc/base/opensslstreamadapter.h
index 5cad3a1..cf332b1 100644
--- a/webrtc/base/opensslstreamadapter.h
+++ b/webrtc/base/opensslstreamadapter.h
@@ -110,7 +110,8 @@
   static bool HaveDtls();
   static bool HaveDtlsSrtp();
   static bool HaveExporter();
-  static std::string GetDefaultSslCipher(SSLProtocolVersion version);
+  static std::string GetDefaultSslCipher(SSLProtocolVersion version,
+                                         KeyType key_type);
 
  protected:
   void OnEvent(StreamInterface* stream, int events, int err) override;
diff --git a/webrtc/base/ssladapter_unittest.cc b/webrtc/base/ssladapter_unittest.cc
index 9a05486..9b69451 100644
--- a/webrtc/base/ssladapter_unittest.cc
+++ b/webrtc/base/ssladapter_unittest.cc
@@ -15,6 +15,7 @@
 #include "webrtc/base/socketstream.h"
 #include "webrtc/base/ssladapter.h"
 #include "webrtc/base/sslstreamadapter.h"
+#include "webrtc/base/sslidentity.h"
 #include "webrtc/base/stream.h"
 #include "webrtc/base/virtualsocketserver.h"
 
@@ -129,10 +130,11 @@
 
 class SSLAdapterTestDummyServer : public sigslot::has_slots<> {
  public:
-  explicit SSLAdapterTestDummyServer(const rtc::SSLMode& ssl_mode)
+  explicit SSLAdapterTestDummyServer(const rtc::SSLMode& ssl_mode,
+                                     const rtc::KeyType key_type)
       : ssl_mode_(ssl_mode) {
     // Generate a key pair and a certificate for this host.
-    ssl_identity_.reset(rtc::SSLIdentity::Generate(GetHostname()));
+    ssl_identity_.reset(rtc::SSLIdentity::Generate(GetHostname(), key_type));
 
     server_socket_.reset(CreateSocket(ssl_mode_));
 
@@ -268,13 +270,13 @@
 class SSLAdapterTestBase : public testing::Test,
                            public sigslot::has_slots<> {
  public:
-  explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode)
+  explicit SSLAdapterTestBase(const rtc::SSLMode& ssl_mode,
+                              const rtc::KeyType key_type)
       : ssl_mode_(ssl_mode),
         ss_scope_(new rtc::VirtualSocketServer(NULL)),
-        server_(new SSLAdapterTestDummyServer(ssl_mode_)),
+        server_(new SSLAdapterTestDummyServer(ssl_mode_, key_type)),
         client_(new SSLAdapterTestDummyClient(ssl_mode_)),
-        handshake_wait_(kTimeout) {
-  }
+        handshake_wait_(kTimeout) {}
 
   void SetHandshakeWait(int wait) {
     handshake_wait_ = wait;
@@ -343,43 +345,78 @@
   int handshake_wait_;
 };
 
-class SSLAdapterTestTLS : public SSLAdapterTestBase {
+class SSLAdapterTestTLS_RSA : public SSLAdapterTestBase {
  public:
-  SSLAdapterTestTLS() : SSLAdapterTestBase(rtc::SSL_MODE_TLS) {}
+  SSLAdapterTestTLS_RSA()
+      : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KT_RSA) {}
 };
 
-class SSLAdapterTestDTLS : public SSLAdapterTestBase {
+class SSLAdapterTestTLS_ECDSA : public SSLAdapterTestBase {
  public:
-  SSLAdapterTestDTLS() : SSLAdapterTestBase(rtc::SSL_MODE_DTLS) {}
+  SSLAdapterTestTLS_ECDSA()
+      : SSLAdapterTestBase(rtc::SSL_MODE_TLS, rtc::KT_ECDSA) {}
+};
+
+class SSLAdapterTestDTLS_RSA : public SSLAdapterTestBase {
+ public:
+  SSLAdapterTestDTLS_RSA()
+      : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KT_RSA) {}
+};
+
+class SSLAdapterTestDTLS_ECDSA : public SSLAdapterTestBase {
+ public:
+  SSLAdapterTestDTLS_ECDSA()
+      : SSLAdapterTestBase(rtc::SSL_MODE_DTLS, rtc::KT_ECDSA) {}
 };
 
 #if SSL_USE_OPENSSL
 
 // Basic tests: TLS
 
-// Test that handshake works
-TEST_F(SSLAdapterTestTLS, TestTLSConnect) {
+// Test that handshake works, using RSA
+TEST_F(SSLAdapterTestTLS_RSA, TestTLSConnect) {
   TestHandshake(true);
 }
 
-// Test transfer between client and server
-TEST_F(SSLAdapterTestTLS, TestTLSTransfer) {
+// Test that handshake works, using ECDSA
+TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSConnect) {
+  TestHandshake(true);
+}
+
+// Test transfer between client and server, using RSA
+TEST_F(SSLAdapterTestTLS_RSA, TestTLSTransfer) {
+  TestHandshake(true);
+  TestTransfer("Hello, world!");
+}
+
+// Test transfer between client and server, using ECDSA
+TEST_F(SSLAdapterTestTLS_ECDSA, TestTLSTransfer) {
   TestHandshake(true);
   TestTransfer("Hello, world!");
 }
 
 // Basic tests: DTLS
 
-// Test that handshake works
-TEST_F(SSLAdapterTestDTLS, TestDTLSConnect) {
+// Test that handshake works, using RSA
+TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSConnect) {
   TestHandshake(true);
 }
 
-// Test transfer between client and server
-TEST_F(SSLAdapterTestDTLS, TestDTLSTransfer) {
+// Test that handshake works, using ECDSA
+TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSConnect) {
+  TestHandshake(true);
+}
+
+// Test transfer between client and server, using RSA
+TEST_F(SSLAdapterTestDTLS_RSA, TestDTLSTransfer) {
+  TestHandshake(true);
+  TestTransfer("Hello, world!");
+}
+
+// Test transfer between client and server, using ECDSA
+TEST_F(SSLAdapterTestDTLS_ECDSA, TestDTLSTransfer) {
   TestHandshake(true);
   TestTransfer("Hello, world!");
 }
 
 #endif  // SSL_USE_OPENSSL
-
diff --git a/webrtc/base/sslidentity.cc b/webrtc/base/sslidentity.cc
index ea9f547..33b7387 100644
--- a/webrtc/base/sslidentity.cc
+++ b/webrtc/base/sslidentity.cc
@@ -37,6 +37,7 @@
 
 const char kPemTypeCertificate[] = "CERTIFICATE";
 const char kPemTypeRsaPrivateKey[] = "RSA PRIVATE KEY";
+const char kPemTypeEcPrivateKey[] = "EC PRIVATE KEY";
 
 bool SSLIdentity::PemToDer(const std::string& pem_type,
                            const std::string& pem_string,
@@ -108,7 +109,8 @@
   return NULL;
 }
 
-SSLIdentity* SSLIdentity::Generate(const std::string& common_name) {
+SSLIdentity* SSLIdentity::Generate(const std::string& common_name,
+                                   KeyType key_type) {
   return NULL;
 }
 
@@ -127,8 +129,9 @@
   return OpenSSLCertificate::FromPEMString(pem_string);
 }
 
-SSLIdentity* SSLIdentity::Generate(const std::string& common_name) {
-  return OpenSSLIdentity::Generate(common_name);
+SSLIdentity* SSLIdentity::Generate(const std::string& common_name,
+                                   KeyType key_type) {
+  return OpenSSLIdentity::Generate(common_name, key_type);
 }
 
 SSLIdentity* SSLIdentity::GenerateForTest(const SSLIdentityParams& params) {
@@ -146,8 +149,9 @@
   return NSSCertificate::FromPEMString(pem_string);
 }
 
-SSLIdentity* SSLIdentity::Generate(const std::string& common_name) {
-  return NSSIdentity::Generate(common_name);
+SSLIdentity* SSLIdentity::Generate(const std::string& common_name,
+                                   KeyType key_type) {
+  return NSSIdentity::Generate(common_name, key_type);
 }
 
 SSLIdentity* SSLIdentity::GenerateForTest(const SSLIdentityParams& params) {
diff --git a/webrtc/base/sslidentity.h b/webrtc/base/sslidentity.h
index 59f87d0..15e23a3 100644
--- a/webrtc/base/sslidentity.h
+++ b/webrtc/base/sslidentity.h
@@ -117,6 +117,7 @@
   std::string common_name;
   int not_before;  // in seconds.
   int not_after;  // in seconds.
+  KeyType key_type;
 };
 
 // Our identity in an SSL negotiation: a keypair and certificate (both
@@ -129,7 +130,8 @@
   // subject and issuer name, otherwise a random string will be used.
   // Returns NULL on failure.
   // Caller is responsible for freeing the returned object.
-  static SSLIdentity* Generate(const std::string& common_name);
+  static SSLIdentity* Generate(const std::string& common_name,
+                               KeyType key_type);
 
   // Generates an identity with the specified validity period.
   static SSLIdentity* GenerateForTest(const SSLIdentityParams& params);
@@ -159,6 +161,7 @@
 
 extern const char kPemTypeCertificate[];
 extern const char kPemTypeRsaPrivateKey[];
+extern const char kPemTypeEcPrivateKey[];
 
 }  // namespace rtc
 
diff --git a/webrtc/base/sslidentity_unittest.cc b/webrtc/base/sslidentity_unittest.cc
index fd75411..b49d0d2 100644
--- a/webrtc/base/sslidentity_unittest.cc
+++ b/webrtc/base/sslidentity_unittest.cc
@@ -30,41 +30,75 @@
     "itAE+OjGF+PFKbwX8Q==\n"
     "-----END CERTIFICATE-----\n";
 
-const unsigned char kTestCertSha1[] = {0xA6, 0xC8, 0x59, 0xEA,
-                                       0xC3, 0x7E, 0x6D, 0x33,
-                                       0xCF, 0xE2, 0x69, 0x9D,
-                                       0x74, 0xE6, 0xF6, 0x8A,
-                                       0x9E, 0x47, 0xA7, 0xCA};
+const unsigned char kTestCertSha1[] = {
+    0xA6, 0xC8, 0x59, 0xEA, 0xC3, 0x7E, 0x6D, 0x33,
+    0xCF, 0xE2, 0x69, 0x9D, 0x74, 0xE6, 0xF6, 0x8A,
+    0x9E, 0x47, 0xA7, 0xCA};
+const unsigned char kTestCertSha224[] = {
+    0xd4, 0xce, 0xc6, 0xcf, 0x28, 0xcb, 0xe9, 0x77,
+    0x38, 0x36, 0xcf, 0xb1, 0x3b, 0x4a, 0xd7, 0xbd,
+    0xae, 0x24, 0x21, 0x08, 0xcf, 0x6a, 0x44, 0x0d,
+    0x3f, 0x94, 0x2a, 0x5b};
+const unsigned char kTestCertSha256[] = {
+    0x41, 0x6b, 0xb4, 0x93, 0x47, 0x79, 0x77, 0x24,
+    0x77, 0x0b, 0x8b, 0x2e, 0xa6, 0x2b, 0xe0, 0xf9,
+    0x0a, 0xed, 0x1f, 0x31, 0xa6, 0xf7, 0x5c, 0xa1,
+    0x5a, 0xc4, 0xb0, 0xa2, 0xa4, 0x78, 0xb9, 0x76};
+const unsigned char kTestCertSha384[] = {
+    0x42, 0x31, 0x9a, 0x79, 0x1d, 0xd6, 0x08, 0xbf,
+    0x3b, 0xba, 0x36, 0xd8, 0x37, 0x4a, 0x9a, 0x75,
+    0xd3, 0x25, 0x6e, 0x28, 0x92, 0xbe, 0x06, 0xb7,
+    0xc5, 0xa0, 0x83, 0xe3, 0x86, 0xb1, 0x03, 0xfc,
+    0x64, 0x47, 0xd6, 0xd8, 0xaa, 0xd9, 0x36, 0x60,
+    0x04, 0xcc, 0xbe, 0x7d, 0x6a, 0xe8, 0x34, 0x49};
+const unsigned char kTestCertSha512[] = {
+    0x51, 0x1d, 0xec, 0x02, 0x3d, 0x51, 0x45, 0xd3,
+    0xd8, 0x1d, 0xa4, 0x9d, 0x43, 0xc9, 0xee, 0x32,
+    0x6f, 0x4f, 0x37, 0xee, 0xab, 0x3f, 0x25, 0xdf,
+    0x72, 0xfc, 0x61, 0x1a, 0xd5, 0x92, 0xff, 0x6b,
+    0x28, 0x71, 0x58, 0xb3, 0xe1, 0x8a, 0x18, 0xcf,
+    0x61, 0x33, 0x0e, 0x14, 0xc3, 0x04, 0xaa, 0x07,
+    0xf6, 0xa5, 0xda, 0xdc, 0x42, 0x42, 0x22, 0x35,
+    0xce, 0x26, 0x58, 0x4a, 0x33, 0x6d, 0xbc, 0xb6};
 
 class SSLIdentityTest : public testing::Test {
  public:
-  SSLIdentityTest() :
-      identity1_(), identity2_() {
-  }
+  SSLIdentityTest() {}
 
   ~SSLIdentityTest() {
   }
 
   virtual void SetUp() {
-    identity1_.reset(SSLIdentity::Generate("test1"));
-    identity2_.reset(SSLIdentity::Generate("test2"));
+    identity_rsa1_.reset(SSLIdentity::Generate("test1", rtc::KT_RSA));
+    identity_rsa2_.reset(SSLIdentity::Generate("test2", rtc::KT_RSA));
+    identity_ecdsa1_.reset(SSLIdentity::Generate("test3", rtc::KT_ECDSA));
+    identity_ecdsa2_.reset(SSLIdentity::Generate("test4", rtc::KT_ECDSA));
 
-    ASSERT_TRUE(identity1_);
-    ASSERT_TRUE(identity2_);
+    ASSERT_TRUE(identity_rsa1_);
+    ASSERT_TRUE(identity_rsa2_);
+    ASSERT_TRUE(identity_ecdsa1_);
+    ASSERT_TRUE(identity_ecdsa2_);
 
-    test_cert_.reset(
-        rtc::SSLCertificate::FromPEMString(kTestCertificate));
+    test_cert_.reset(rtc::SSLCertificate::FromPEMString(kTestCertificate));
     ASSERT_TRUE(test_cert_);
   }
 
   void TestGetSignatureDigestAlgorithm() {
     std::string digest_algorithm;
-    // Both NSSIdentity::Generate and OpenSSLIdentity::Generate are
-    // hard-coded to generate RSA-SHA256 certificates.
-    ASSERT_TRUE(identity1_->certificate().GetSignatureDigestAlgorithm(
+
+    ASSERT_TRUE(identity_rsa1_->certificate().GetSignatureDigestAlgorithm(
         &digest_algorithm));
     ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
-    ASSERT_TRUE(identity2_->certificate().GetSignatureDigestAlgorithm(
+
+    ASSERT_TRUE(identity_rsa2_->certificate().GetSignatureDigestAlgorithm(
+        &digest_algorithm));
+    ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
+
+    ASSERT_TRUE(identity_ecdsa1_->certificate().GetSignatureDigestAlgorithm(
+        &digest_algorithm));
+    ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
+
+    ASSERT_TRUE(identity_ecdsa2_->certificate().GetSignatureDigestAlgorithm(
         &digest_algorithm));
     ASSERT_EQ(rtc::DIGEST_SHA_256, digest_algorithm);
 
@@ -73,58 +107,102 @@
     ASSERT_EQ(rtc::DIGEST_MD5, digest_algorithm);
   }
 
-  void TestDigest(const std::string &algorithm, size_t expected_len,
-                  const unsigned char *expected_digest = NULL) {
-    unsigned char digest1[64];
-    unsigned char digest1b[64];
-    unsigned char digest2[64];
-    size_t digest1_len;
-    size_t digest1b_len;
-    size_t digest2_len;
+  typedef unsigned char DigestType[rtc::MessageDigest::kMaxSize];
+
+  void TestDigestHelper(DigestType digest,
+                        const SSLIdentity* identity,
+                        const std::string& algorithm,
+                        size_t expected_len) {
+    DigestType digest1;
+    size_t digest_len;
     bool rv;
 
-    rv = identity1_->certificate().ComputeDigest(algorithm,
-                                                 digest1, sizeof(digest1),
-                                                 &digest1_len);
+    memset(digest, 0, expected_len);
+    rv = identity->certificate().ComputeDigest(algorithm, digest,
+                                               sizeof(DigestType), &digest_len);
     EXPECT_TRUE(rv);
-    EXPECT_EQ(expected_len, digest1_len);
+    EXPECT_EQ(expected_len, digest_len);
 
-    rv = identity1_->certificate().ComputeDigest(algorithm,
-                                                 digest1b, sizeof(digest1b),
-                                                 &digest1b_len);
+    // Repeat digest computation for the identity as a sanity check.
+    memset(digest1, 0xff, expected_len);
+    rv = identity->certificate().ComputeDigest(algorithm, digest1,
+                                               sizeof(DigestType), &digest_len);
     EXPECT_TRUE(rv);
-    EXPECT_EQ(expected_len, digest1b_len);
-    EXPECT_EQ(0, memcmp(digest1, digest1b, expected_len));
+    EXPECT_EQ(expected_len, digest_len);
 
+    EXPECT_EQ(0, memcmp(digest, digest1, expected_len));
+  }
 
-    rv = identity2_->certificate().ComputeDigest(algorithm,
-                                                 digest2, sizeof(digest2),
-                                                 &digest2_len);
-    EXPECT_TRUE(rv);
-    EXPECT_EQ(expected_len, digest2_len);
-    EXPECT_NE(0, memcmp(digest1, digest2, expected_len));
+  void TestDigestForGeneratedCert(const std::string& algorithm,
+                                  size_t expected_len) {
+    DigestType digest[4];
 
-    // If we have an expected hash for the test cert, check it.
-    if (expected_digest) {
-      unsigned char digest3[64];
-      size_t digest3_len;
+    ASSERT_TRUE(expected_len <= sizeof(DigestType));
 
-      rv = test_cert_->ComputeDigest(algorithm, digest3, sizeof(digest3),
-                                    &digest3_len);
-      EXPECT_TRUE(rv);
-      EXPECT_EQ(expected_len, digest3_len);
-      EXPECT_EQ(0, memcmp(digest3, expected_digest, expected_len));
+    TestDigestHelper(digest[0], identity_rsa1_.get(), algorithm, expected_len);
+    TestDigestHelper(digest[1], identity_rsa2_.get(), algorithm, expected_len);
+    TestDigestHelper(digest[2], identity_ecdsa1_.get(), algorithm,
+                     expected_len);
+    TestDigestHelper(digest[3], identity_ecdsa2_.get(), algorithm,
+                     expected_len);
+
+    // Sanity check that all four digests are unique.  This could theoretically
+    // fail, since cryptographic hash collisions have a non-zero probability.
+    for (int i = 0; i < 4; i++) {
+      for (int j = 0; j < 4; j++) {
+        if (i != j)
+          EXPECT_NE(0, memcmp(digest[i], digest[j], expected_len));
+      }
     }
   }
 
+  void TestDigestForFixedCert(const std::string& algorithm,
+                              size_t expected_len,
+                              const unsigned char* expected_digest) {
+    bool rv;
+    DigestType digest;
+    size_t digest_len;
+
+    ASSERT_TRUE(expected_len <= sizeof(DigestType));
+
+    rv = test_cert_->ComputeDigest(algorithm, digest, sizeof(digest),
+                                   &digest_len);
+    EXPECT_TRUE(rv);
+    EXPECT_EQ(expected_len, digest_len);
+    EXPECT_EQ(0, memcmp(digest, expected_digest, expected_len));
+  }
+
  private:
-  rtc::scoped_ptr<SSLIdentity> identity1_;
-  rtc::scoped_ptr<SSLIdentity> identity2_;
+  rtc::scoped_ptr<SSLIdentity> identity_rsa1_;
+  rtc::scoped_ptr<SSLIdentity> identity_rsa2_;
+  rtc::scoped_ptr<SSLIdentity> identity_ecdsa1_;
+  rtc::scoped_ptr<SSLIdentity> identity_ecdsa2_;
   rtc::scoped_ptr<rtc::SSLCertificate> test_cert_;
 };
 
-TEST_F(SSLIdentityTest, DigestSHA1) {
-  TestDigest(rtc::DIGEST_SHA_1, 20, kTestCertSha1);
+TEST_F(SSLIdentityTest, FixedDigestSHA1) {
+  TestDigestForFixedCert(rtc::DIGEST_SHA_1, 20, kTestCertSha1);
+}
+
+// HASH_AlgSHA224 is not supported in the chromium linux build.
+#if SSL_USE_NSS
+TEST_F(SSLIdentityTest, DISABLED_FixedDigestSHA224) {
+#else
+TEST_F(SSLIdentityTest, FixedDigestSHA224) {
+#endif
+  TestDigestForFixedCert(rtc::DIGEST_SHA_224, 28, kTestCertSha224);
+}
+
+TEST_F(SSLIdentityTest, FixedDigestSHA256) {
+  TestDigestForFixedCert(rtc::DIGEST_SHA_256, 32, kTestCertSha256);
+}
+
+TEST_F(SSLIdentityTest, FixedDigestSHA384) {
+  TestDigestForFixedCert(rtc::DIGEST_SHA_384, 48, kTestCertSha384);
+}
+
+TEST_F(SSLIdentityTest, FixedDigestSHA512) {
+  TestDigestForFixedCert(rtc::DIGEST_SHA_512, 64, kTestCertSha512);
 }
 
 // HASH_AlgSHA224 is not supported in the chromium linux build.
@@ -133,22 +211,22 @@
 #else
 TEST_F(SSLIdentityTest, DigestSHA224) {
 #endif
-  TestDigest(rtc::DIGEST_SHA_224, 28);
+  TestDigestForGeneratedCert(rtc::DIGEST_SHA_224, 28);
 }
 
 TEST_F(SSLIdentityTest, DigestSHA256) {
-  TestDigest(rtc::DIGEST_SHA_256, 32);
+  TestDigestForGeneratedCert(rtc::DIGEST_SHA_256, 32);
 }
 
 TEST_F(SSLIdentityTest, DigestSHA384) {
-  TestDigest(rtc::DIGEST_SHA_384, 48);
+  TestDigestForGeneratedCert(rtc::DIGEST_SHA_384, 48);
 }
 
 TEST_F(SSLIdentityTest, DigestSHA512) {
-  TestDigest(rtc::DIGEST_SHA_512, 64);
+  TestDigestForGeneratedCert(rtc::DIGEST_SHA_512, 64);
 }
 
-TEST_F(SSLIdentityTest, FromPEMStrings) {
+TEST_F(SSLIdentityTest, FromPEMStringsRSA) {
   static const char kRSA_PRIVATE_KEY_PEM[] =
       "-----BEGIN RSA PRIVATE KEY-----\n"
       "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMYRkbhmI7kVA/rM\n"
@@ -186,6 +264,39 @@
   EXPECT_EQ(kCERT_PEM, identity->certificate().ToPEMString());
 }
 
+#if SSL_USE_OPENSSL
+// This will not work on NSS as PK11_ImportDERPrivateKeyInfoAndReturnKey is not
+// ready for EC keys.  Furthermore, NSSIdentity::FromPEMStrings is currently
+// hardwired for RSA (the header matching via kPemTypeRsaPrivateKey needs
+// trivial generalization).
+TEST_F(SSLIdentityTest, FromPEMStringsEC) {
+  static const char kRSA_PRIVATE_KEY_PEM[] =
+      "-----BEGIN EC PRIVATE KEY-----\n"
+      "MHcCAQEEIKkIztWLPbs4Y2zWv7VW2Ov4is2ifleCuPgRB8fRv3IkoAoGCCqGSM49\n"
+      "AwEHoUQDQgAEDPV33NrhSdhg9cBRkUWUXnVMXc3h17i9ARbSmNgminKcBXb8/y8L\n"
+      "A76cMWQPPM0ybHO8OS7ZVg2U/m+TwE1M2g==\n"
+      "-----END EC PRIVATE KEY-----\n";
+  static const char kCERT_PEM[] =
+      "-----BEGIN CERTIFICATE-----\n"
+      "MIIB0jCCAXmgAwIBAgIJAMCjpFt9t6LMMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT\n"
+      "AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn\n"
+      "aXRzIFB0eSBMdGQwIBcNMTUwNjMwMTMwMTIyWhgPMjI4OTA0MTMxMzAxMjJaMEUx\n"
+      "CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl\n"
+      "cm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQM\n"
+      "9Xfc2uFJ2GD1wFGRRZRedUxdzeHXuL0BFtKY2CaKcpwFdvz/LwsDvpwxZA88zTJs\n"
+      "c7w5LtlWDZT+b5PATUzao1AwTjAdBgNVHQ4EFgQUYHq6nxNNIE832ZmaHc/noODO\n"
+      "rtAwHwYDVR0jBBgwFoAUYHq6nxNNIE832ZmaHc/noODOrtAwDAYDVR0TBAUwAwEB\n"
+      "/zAKBggqhkjOPQQDAgNHADBEAiAQRojsTyZG0BlKoU7gOt5h+yAMLl2cxmDtOIQr\n"
+      "GWP/PwIgJynB4AUDsPT0DWmethOXYijB5sY5UPd9DvgmiS/Mr6s=\n"
+      "-----END CERTIFICATE-----\n";
+
+  rtc::scoped_ptr<SSLIdentity> identity(
+      SSLIdentity::FromPEMStrings(kRSA_PRIVATE_KEY_PEM, kCERT_PEM));
+  EXPECT_TRUE(identity);
+  EXPECT_EQ(kCERT_PEM, identity->certificate().ToPEMString());
+}
+#endif
+
 TEST_F(SSLIdentityTest, PemDerConversion) {
   std::string der;
   EXPECT_TRUE(SSLIdentity::PemToDer("CERTIFICATE", kTestCertificate, &der));
diff --git a/webrtc/base/sslstreamadapter.cc b/webrtc/base/sslstreamadapter.cc
index 3c27b10..39426cd 100644
--- a/webrtc/base/sslstreamadapter.cc
+++ b/webrtc/base/sslstreamadapter.cc
@@ -72,7 +72,8 @@
 bool SSLStreamAdapter::HaveDtls() { return false; }
 bool SSLStreamAdapter::HaveDtlsSrtp() { return false; }
 bool SSLStreamAdapter::HaveExporter() { return false; }
-std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
+std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version,
+                                                  KeyType key_type) {
   return std::string();
 }
 #elif SSL_USE_OPENSSL
@@ -85,8 +86,9 @@
 bool SSLStreamAdapter::HaveExporter() {
   return OpenSSLStreamAdapter::HaveExporter();
 }
-std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
-  return OpenSSLStreamAdapter::GetDefaultSslCipher(version);
+std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version,
+                                                  KeyType key_type) {
+  return OpenSSLStreamAdapter::GetDefaultSslCipher(version, key_type);
 }
 #elif SSL_USE_NSS
 bool SSLStreamAdapter::HaveDtls() {
@@ -98,8 +100,9 @@
 bool SSLStreamAdapter::HaveExporter() {
   return NSSStreamAdapter::HaveExporter();
 }
-std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version) {
-  return NSSStreamAdapter::GetDefaultSslCipher(version);
+std::string SSLStreamAdapter::GetDefaultSslCipher(SSLProtocolVersion version,
+                                                  KeyType key_type) {
+  return NSSStreamAdapter::GetDefaultSslCipher(version, key_type);
 }
 #endif  // !SSL_USE_SCHANNEL && !SSL_USE_OPENSSL && !SSL_USE_NSS
 
diff --git a/webrtc/base/sslstreamadapter.h b/webrtc/base/sslstreamadapter.h
index dcb8029..4fb238a 100644
--- a/webrtc/base/sslstreamadapter.h
+++ b/webrtc/base/sslstreamadapter.h
@@ -167,7 +167,9 @@
 
   // Returns the default Ssl cipher used between streams of this class
   // for the given protocol version. This is used by the unit tests.
-  static std::string GetDefaultSslCipher(SSLProtocolVersion version);
+  // TODO(torbjorng@webrtc.org): Fix callers to avoid default parameter.
+  static std::string GetDefaultSslCipher(SSLProtocolVersion version,
+                                         KeyType key_type = KT_DEFAULT);
 
  private:
   // If true, the server certificate need not match the configured
diff --git a/webrtc/base/sslstreamadapter_unittest.cc b/webrtc/base/sslstreamadapter_unittest.cc
index 6abaaa3..67658ba 100644
--- a/webrtc/base/sslstreamadapter_unittest.cc
+++ b/webrtc/base/sslstreamadapter_unittest.cc
@@ -23,6 +23,11 @@
 #include "webrtc/base/stream.h"
 #include "webrtc/test/testsupport/gtest_disable.h"
 
+using ::testing::WithParamInterface;
+using ::testing::Values;
+using ::testing::Combine;
+using ::testing::tuple;
+
 static const int kBlockSize = 4096;
 static const char kAES_CM_HMAC_SHA1_80[] = "AES_CM_128_HMAC_SHA1_80";
 static const char kAES_CM_HMAC_SHA1_32[] = "AES_CM_128_HMAC_SHA1_32";
@@ -158,18 +163,27 @@
  public:
   SSLStreamAdapterTestBase(const std::string& client_cert_pem,
                            const std::string& client_private_key_pem,
-                           bool dtls) :
-      client_buffer_(kFifoBufferSize), server_buffer_(kFifoBufferSize),
-      client_stream_(
-          new SSLDummyStream(this, "c2s", &client_buffer_, &server_buffer_)),
-      server_stream_(
-          new SSLDummyStream(this, "s2c", &server_buffer_, &client_buffer_)),
-      client_ssl_(rtc::SSLStreamAdapter::Create(client_stream_)),
-      server_ssl_(rtc::SSLStreamAdapter::Create(server_stream_)),
-      client_identity_(NULL), server_identity_(NULL),
-      delay_(0), mtu_(1460), loss_(0), lose_first_packet_(false),
-      damage_(false), dtls_(dtls),
-      handshake_wait_(5000), identities_set_(false) {
+                           bool dtls,
+                           rtc::KeyType client_key_type = rtc::KT_DEFAULT,
+                           rtc::KeyType server_key_type = rtc::KT_DEFAULT)
+      : client_buffer_(kFifoBufferSize),
+        server_buffer_(kFifoBufferSize),
+        client_stream_(
+            new SSLDummyStream(this, "c2s", &client_buffer_, &server_buffer_)),
+        server_stream_(
+            new SSLDummyStream(this, "s2c", &server_buffer_, &client_buffer_)),
+        client_ssl_(rtc::SSLStreamAdapter::Create(client_stream_)),
+        server_ssl_(rtc::SSLStreamAdapter::Create(server_stream_)),
+        client_identity_(NULL),
+        server_identity_(NULL),
+        delay_(0),
+        mtu_(1460),
+        loss_(0),
+        lose_first_packet_(false),
+        damage_(false),
+        dtls_(dtls),
+        handshake_wait_(5000),
+        identities_set_(false) {
     // Set use of the test RNG to get predictable loss patterns.
     rtc::SetRandomTestMode(true);
 
@@ -181,9 +195,9 @@
       client_identity_ = rtc::SSLIdentity::FromPEMStrings(
           client_private_key_pem, client_cert_pem);
     } else {
-      client_identity_ = rtc::SSLIdentity::Generate("client");
+      client_identity_ = rtc::SSLIdentity::Generate("client", client_key_type);
     }
-    server_identity_ = rtc::SSLIdentity::Generate("server");
+    server_identity_ = rtc::SSLIdentity::Generate("server", server_key_type);
 
     client_ssl_->SetIdentity(client_identity_);
     server_ssl_->SetIdentity(server_identity_);
@@ -213,12 +227,14 @@
     client_params.common_name = "client";
     client_params.not_before = not_before;
     client_params.not_after = not_after;
+    client_params.key_type = rtc::KT_DEFAULT;
     client_identity_ = rtc::SSLIdentity::GenerateForTest(client_params);
 
     rtc::SSLIdentityParams server_params;
     server_params.common_name = "server";
     server_params.not_before = not_before;
     server_params.not_after = not_after;
+    server_params.key_type = rtc::KT_DEFAULT;
     server_identity_ = rtc::SSLIdentity::GenerateForTest(server_params);
 
     client_ssl_->SetIdentity(client_identity_);
@@ -444,11 +460,16 @@
   bool identities_set_;
 };
 
-class SSLStreamAdapterTestTLS : public SSLStreamAdapterTestBase {
+class SSLStreamAdapterTestTLS
+    : public SSLStreamAdapterTestBase,
+      public WithParamInterface<tuple<rtc::KeyType, rtc::KeyType>> {
  public:
-  SSLStreamAdapterTestTLS() :
-      SSLStreamAdapterTestBase("", "", false) {
-  };
+  SSLStreamAdapterTestTLS()
+      : SSLStreamAdapterTestBase("",
+                                 "",
+                                 false,
+                                 ::testing::get<0>(GetParam()),
+                                 ::testing::get<1>(GetParam())){};
 
   // Test data transfer for TLS
   virtual void TestTransfer(int size) {
@@ -547,12 +568,19 @@
   rtc::MemoryStream recv_stream_;
 };
 
-class SSLStreamAdapterTestDTLS : public SSLStreamAdapterTestBase {
+class SSLStreamAdapterTestDTLS
+    : public SSLStreamAdapterTestBase,
+      public WithParamInterface<tuple<rtc::KeyType, rtc::KeyType>> {
  public:
-  SSLStreamAdapterTestDTLS() :
-      SSLStreamAdapterTestBase("", "", true),
-      packet_size_(1000), count_(0), sent_(0) {
-  }
+  SSLStreamAdapterTestDTLS()
+      : SSLStreamAdapterTestBase("",
+                                 "",
+                                 true,
+                                 ::testing::get<0>(GetParam()),
+                                 ::testing::get<1>(GetParam())),
+        packet_size_(1000),
+        count_(0),
+        sent_(0) {}
 
   SSLStreamAdapterTestDTLS(const std::string& cert_pem,
                            const std::string& private_key_pem) :
@@ -677,7 +705,7 @@
 // This test only applies to NSS because OpenSSL has passthrough
 // semantics for I/O before the handshake is started.
 #if SSL_USE_NSS
-TEST_F(SSLStreamAdapterTestTLS, TestNoReadWriteBeforeConnect) {
+TEST_P(SSLStreamAdapterTestTLS, TestNoReadWriteBeforeConnect) {
   rtc::StreamResult rv;
   char block[kBlockSize];
   size_t dummy;
@@ -692,25 +720,25 @@
 
 
 // Test that we can make a handshake work
-TEST_F(SSLStreamAdapterTestTLS, TestTLSConnect) {
+TEST_P(SSLStreamAdapterTestTLS, TestTLSConnect) {
   TestHandshake();
 };
 
 // Test that closing the connection on one side updates the other side.
-TEST_F(SSLStreamAdapterTestTLS, TestTLSClose) {
+TEST_P(SSLStreamAdapterTestTLS, TestTLSClose) {
   TestHandshake();
   client_ssl_->Close();
   EXPECT_EQ_WAIT(rtc::SS_CLOSED, server_ssl_->GetState(), handshake_wait_);
 };
 
 // Test transfer -- trivial
-TEST_F(SSLStreamAdapterTestTLS, TestTLSTransfer) {
+TEST_P(SSLStreamAdapterTestTLS, TestTLSTransfer) {
   TestHandshake();
   TestTransfer(100000);
 };
 
 // Test read-write after close.
-TEST_F(SSLStreamAdapterTestTLS, ReadWriteAfterClose) {
+TEST_P(SSLStreamAdapterTestTLS, ReadWriteAfterClose) {
   TestHandshake();
   TestTransfer(100000);
   client_ssl_->Close();
@@ -729,7 +757,7 @@
 };
 
 // Test a handshake with a bogus peer digest
-TEST_F(SSLStreamAdapterTestTLS, TestTLSBogusDigest) {
+TEST_P(SSLStreamAdapterTestTLS, TestTLSBogusDigest) {
   SetPeerIdentitiesByDigest(false);
   TestHandshake(false);
 };
@@ -738,7 +766,7 @@
 
 // Basic tests: DTLS
 // Test that we can make a handshake work
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSConnect) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnect) {
   MAYBE_SKIP_TEST(HaveDtls);
   TestHandshake();
 };
@@ -746,15 +774,14 @@
 // Test that we can make a handshake work if the first packet in
 // each direction is lost. This gives us predictable loss
 // rather than having to tune random
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSConnectWithLostFirstPacket) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnectWithLostFirstPacket) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetLoseFirstPacket(true);
   TestHandshake();
 };
 
 // Test a handshake with loss and delay
-TEST_F(SSLStreamAdapterTestDTLS,
-       TestDTLSConnectWithLostFirstPacketDelay2s) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSConnectWithLostFirstPacketDelay2s) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetLoseFirstPacket(true);
   SetDelay(2000);
@@ -764,7 +791,7 @@
 
 // Test a handshake with small MTU
 // Disabled due to https://code.google.com/p/webrtc/issues/detail?id=3910
-TEST_F(SSLStreamAdapterTestDTLS, DISABLED_TestDTLSConnectWithSmallMtu) {
+TEST_P(SSLStreamAdapterTestDTLS, DISABLED_TestDTLSConnectWithSmallMtu) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetMtu(700);
   SetHandshakeWait(20000);
@@ -772,20 +799,20 @@
 };
 
 // Test transfer -- trivial
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSTransfer) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransfer) {
   MAYBE_SKIP_TEST(HaveDtls);
   TestHandshake();
   TestTransfer(100);
 };
 
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSTransferWithLoss) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithLoss) {
   MAYBE_SKIP_TEST(HaveDtls);
   TestHandshake();
   SetLoss(10);
   TestTransfer(100);
 };
 
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSTransferWithDamage) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSTransferWithDamage) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetDamage();  // Must be called first because first packet
                 // write happens at end of handshake.
@@ -794,7 +821,7 @@
 };
 
 // Test DTLS-SRTP with all high ciphers
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSSrtpHigh) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHigh) {
   MAYBE_SKIP_TEST(HaveDtlsSrtp);
   std::vector<std::string> high;
   high.push_back(kAES_CM_HMAC_SHA1_80);
@@ -812,7 +839,7 @@
 };
 
 // Test DTLS-SRTP with all low ciphers
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSSrtpLow) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpLow) {
   MAYBE_SKIP_TEST(HaveDtlsSrtp);
   std::vector<std::string> low;
   low.push_back(kAES_CM_HMAC_SHA1_32);
@@ -831,7 +858,7 @@
 
 
 // Test DTLS-SRTP with a mismatch -- should not converge
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSSrtpHighLow) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpHighLow) {
   MAYBE_SKIP_TEST(HaveDtlsSrtp);
   std::vector<std::string> high;
   high.push_back(kAES_CM_HMAC_SHA1_80);
@@ -848,7 +875,7 @@
 };
 
 // Test DTLS-SRTP with each side being mixed -- should select high
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSSrtpMixed) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSSrtpMixed) {
   MAYBE_SKIP_TEST(HaveDtlsSrtp);
   std::vector<std::string> mixed;
   mixed.push_back(kAES_CM_HMAC_SHA1_80);
@@ -867,7 +894,7 @@
 };
 
 // Test an exporter
-TEST_F(SSLStreamAdapterTestDTLS, TestDTLSExporter) {
+TEST_P(SSLStreamAdapterTestDTLS, TestDTLSExporter) {
   MAYBE_SKIP_TEST(HaveExporter);
   TestHandshake();
   unsigned char client_out[20];
@@ -890,7 +917,7 @@
 }
 
 // Test not yet valid certificates are not rejected.
-TEST_F(SSLStreamAdapterTestDTLS, TestCertNotYetValid) {
+TEST_P(SSLStreamAdapterTestDTLS, TestCertNotYetValid) {
   MAYBE_SKIP_TEST(HaveDtls);
   long one_day = 60 * 60 * 24;
   // Make the certificates not valid until one day later.
@@ -899,7 +926,7 @@
 }
 
 // Test expired certificates are not rejected.
-TEST_F(SSLStreamAdapterTestDTLS, TestCertExpired) {
+TEST_P(SSLStreamAdapterTestDTLS, TestCertExpired) {
   MAYBE_SKIP_TEST(HaveDtls);
   long one_day = 60 * 60 * 24;
   // Make the certificates already expired.
@@ -908,14 +935,14 @@
 }
 
 // Test data transfer using certs created from strings.
-TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestTransfer) {
+TEST_P(SSLStreamAdapterTestDTLSFromPEMStrings, TestTransfer) {
   MAYBE_SKIP_TEST(HaveDtls);
   TestHandshake();
   TestTransfer(100);
 }
 
 // Test getting the remote certificate.
-TEST_F(SSLStreamAdapterTestDTLSFromPEMStrings, TestDTLSGetPeerCertificate) {
+TEST_P(SSLStreamAdapterTestDTLSFromPEMStrings, TestDTLSGetPeerCertificate) {
   MAYBE_SKIP_TEST(HaveDtls);
 
   // Peer certificates haven't been received yet.
@@ -955,7 +982,7 @@
 
 // Test getting the used DTLS ciphers.
 // DTLS 1.2 enabled for neither client nor server -> DTLS 1.0 will be used.
-TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipher) {
+TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipher) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_10);
   TestHandshake();
@@ -966,14 +993,14 @@
   ASSERT_TRUE(GetSslCipher(false, &server_cipher));
 
   ASSERT_EQ(client_cipher, server_cipher);
-  ASSERT_EQ(
-      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
-      client_cipher);
+  ASSERT_EQ(rtc::SSLStreamAdapter::GetDefaultSslCipher(
+                rtc::SSL_PROTOCOL_DTLS_10, ::testing::get<1>(GetParam())),
+            server_cipher);
 }
 
 // Test getting the used DTLS 1.2 ciphers.
 // DTLS 1.2 enabled for client and server -> DTLS 1.2 will be used.
-TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Both) {
+TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Both) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_12);
   TestHandshake();
@@ -984,13 +1011,13 @@
   ASSERT_TRUE(GetSslCipher(false, &server_cipher));
 
   ASSERT_EQ(client_cipher, server_cipher);
-  ASSERT_EQ(
-      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_12),
-      client_cipher);
+  ASSERT_EQ(rtc::SSLStreamAdapter::GetDefaultSslCipher(
+                rtc::SSL_PROTOCOL_DTLS_12, ::testing::get<1>(GetParam())),
+            server_cipher);
 }
 
 // DTLS 1.2 enabled for client only -> DTLS 1.0 will be used.
-TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Client) {
+TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Client) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_10, rtc::SSL_PROTOCOL_DTLS_12);
   TestHandshake();
@@ -1001,13 +1028,13 @@
   ASSERT_TRUE(GetSslCipher(false, &server_cipher));
 
   ASSERT_EQ(client_cipher, server_cipher);
-  ASSERT_EQ(
-      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
-      client_cipher);
+  ASSERT_EQ(rtc::SSLStreamAdapter::GetDefaultSslCipher(
+                rtc::SSL_PROTOCOL_DTLS_10, ::testing::get<1>(GetParam())),
+            server_cipher);
 }
 
 // DTLS 1.2 enabled for server only -> DTLS 1.0 will be used.
-TEST_F(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Server) {
+TEST_P(SSLStreamAdapterTestDTLS, TestGetSslCipherDtls12Server) {
   MAYBE_SKIP_TEST(HaveDtls);
   SetupProtocolVersions(rtc::SSL_PROTOCOL_DTLS_12, rtc::SSL_PROTOCOL_DTLS_10);
   TestHandshake();
@@ -1018,7 +1045,16 @@
   ASSERT_TRUE(GetSslCipher(false, &server_cipher));
 
   ASSERT_EQ(client_cipher, server_cipher);
-  ASSERT_EQ(
-      rtc::SSLStreamAdapter::GetDefaultSslCipher(rtc::SSL_PROTOCOL_DTLS_10),
-      client_cipher);
+  ASSERT_EQ(rtc::SSLStreamAdapter::GetDefaultSslCipher(
+                rtc::SSL_PROTOCOL_DTLS_10, ::testing::get<1>(GetParam())),
+            server_cipher);
 }
+
+INSTANTIATE_TEST_CASE_P(SSLStreamAdapterTestsTLS,
+                        SSLStreamAdapterTestTLS,
+                        Combine(Values(rtc::KT_RSA, rtc::KT_ECDSA),
+                                Values(rtc::KT_RSA, rtc::KT_ECDSA)));
+INSTANTIATE_TEST_CASE_P(SSLStreamAdapterTestsDTLS,
+                        SSLStreamAdapterTestDTLS,
+                        Combine(Values(rtc::KT_RSA, rtc::KT_ECDSA),
+                                Values(rtc::KT_RSA, rtc::KT_ECDSA)));