Bug 1227905 - Support ChaCha20+Poly1305 cipher suites r=mt,wtc,ekr
authorTim Taubert <ttaubert@mozilla.com>
Thu, 11 Feb 2016 08:42:47 +0100
changeset 11886 b6c9ec057991a8a7cab3b82dba148afefc16bf83
parent 11885 b7b1d793bc64e27b70c038ca59257027252b7ede
child 11887 ac1ad4ae73c78853f5c0994f2b5e9d6077c28df1
push id986
push userttaubert@mozilla.com
push dateThu, 11 Feb 2016 07:44:05 +0000
reviewersmt, wtc, ekr
bugs1227905
Bug 1227905 - Support ChaCha20+Poly1305 cipher suites r=mt,wtc,ekr
cmd/ssltap/ssltap.c
external_tests/ssl_gtest/ssl_loopback_unittest.cc
lib/pk11wrap/pk11pars.c
lib/ssl/ssl3con.c
lib/ssl/ssl3ecc.c
lib/ssl/sslenum.c
lib/ssl/sslimpl.h
lib/ssl/sslinfo.c
lib/ssl/sslproto.h
lib/ssl/sslt.h
lib/util/secoid.c
lib/util/secoidt.h
tests/ssl/ssl.sh
tests/ssl/sslcov.txt
--- a/cmd/ssltap/ssltap.c
+++ b/cmd/ssltap/ssltap.c
@@ -438,16 +438,20 @@ const char * V2CipherString(int cs_int)
   case 0x00C027:    cs_str = "TLS/ECDHE-RSA/AES128-CBC/SHA256"; break;
   case 0x00C028:    cs_str = "TLS/ECDHE-RSA/AES256-CBC/SHA384"; break;
   case 0x00C029:    cs_str = "TLS/ECDH-RSA/AES128-CBC/SHA256"; break;
   case 0x00C02A:    cs_str = "TLS/ECDH-RSA/AES256-CBC/SHA384"; break;
   case 0x00C02B:    cs_str = "TLS/ECDHE-ECDSA/AES128-GCM/SHA256"; break;
   case 0x00C02C:    cs_str = "TLS/ECDHE-ECDSA/AES256-GCM/SHA384"; break;
   case 0x00C02F:    cs_str = "TLS/ECDHE-RSA/AES128-GCM/SHA256"; break;
 
+  case 0x00CCA8:    cs_str = "TLS/ECDHE-RSA/CHACHA20-POLY1305/SHA256"; break;
+  case 0x00CCA9:    cs_str = "TLS/ECDHE-ECDSA/CHACHA20-POLY1305/SHA256"; break;
+  case 0x00CCAA:    cs_str = "TLS/DHE-RSA/CHACHA20-POLY1305/SHA256"; break;
+
   case 0x00FEFF:    cs_str = "SSL3/RSA-FIPS/3DESEDE-CBC/SHA";	break;
   case 0x00FEFE:    cs_str = "SSL3/RSA-FIPS/DES-CBC/SHA";	break;
   case 0x00FFE1:    cs_str = "SSL3/RSA-FIPS/DES56-CBC/SHA";     break;
   case 0x00FFE0:    cs_str = "SSL3/RSA-FIPS/3DES192EDE-CBC/SHA";break;
 
   /* the string literal is broken up to avoid trigraphs */
   default:          cs_str = "????" "/????????" "/?????????" "/???"; break;
   }
--- a/external_tests/ssl_gtest/ssl_loopback_unittest.cc
+++ b/external_tests/ssl_gtest/ssl_loopback_unittest.cc
@@ -103,16 +103,39 @@ class TlsServerKeyExchangeEcdhe {
     }
 
     return parser.ReadVariable(&public_key_, 1);
   }
 
   DataBuffer public_key_;
 };
 
+class TlsChaCha20Poly1305Test : public TlsConnectTls12 {
+ public:
+  void ConnectSendReceive(PRUint32 cipher_suite)
+  {
+    // Disable all ciphers.
+    client_->DisableCiphersByKeyExchange(ssl_kea_rsa);
+    client_->DisableCiphersByKeyExchange(ssl_kea_dh);
+    client_->DisableCiphersByKeyExchange(ssl_kea_ecdh);
+
+    // Re-enable ChaCha20/Poly1305.
+    SECStatus rv = SSL_CipherPrefSet(client_->ssl_fd(), cipher_suite, PR_TRUE);
+    EXPECT_EQ(SECSuccess, rv);
+
+    Connect();
+    SendReceive();
+
+    // Check that we used the right cipher suite.
+    int16_t actual, expected = static_cast<int16_t>(cipher_suite);
+    EXPECT_TRUE(client_->cipher_suite(&actual) && actual == expected);
+    EXPECT_TRUE(server_->cipher_suite(&actual) && actual == expected);
+  }
+};
+
 TEST_P(TlsConnectGeneric, SetupOnly) {}
 
 TEST_P(TlsConnectGeneric, Connect) {
   SetExpectedVersion(std::get<1>(GetParam()));
   Connect();
   CheckKeys(ssl_kea_ecdh, ssl_auth_rsa);
 }
 
@@ -537,16 +560,29 @@ TEST_P(TlsConnectStreamPre13, ConnectEcd
                         dhe1.public_key_.len())));
 }
 
 TEST_P(TlsConnectGeneric, ConnectSendReceive) {
   Connect();
   SendReceive();
 }
 
+TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305DheRsa) {
+  ConnectSendReceive(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
+}
+
+TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheRsa) {
+  ConnectSendReceive(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256);
+}
+
+TEST_P(TlsChaCha20Poly1305Test, SendReceiveChaCha20Poly1305EcdheEcdsa) {
+  ResetEcdsa();
+  ConnectSendReceive(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256);
+}
+
 // The next two tests takes advantage of the fact that we
 // automatically read the first 1024 bytes, so if
 // we provide 1200 bytes, they overrun the read buffer
 // provided by the calling test.
 
 // DTLS should return an error.
 TEST_P(TlsConnectDatagram, ShortRead) {
   Connect();
--- a/lib/pk11wrap/pk11pars.c
+++ b/lib/pk11wrap/pk11pars.c
@@ -349,16 +349,17 @@ static const oidValDef algOptList[] = {
     {CIPHER_NAME("AES192-CBC"), SEC_OID_AES_192_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("AES256-CBC"), SEC_OID_AES_256_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("AES128-GCM"), SEC_OID_AES_128_GCM, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("AES192-GCM"), SEC_OID_AES_192_GCM, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("AES256-GCM"), SEC_OID_AES_256_GCM, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("CAMELLIA128-CBC"), SEC_OID_CAMELLIA_128_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("CAMELLIA192-CBC"), SEC_OID_CAMELLIA_192_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("CAMELLIA256-CBC"), SEC_OID_CAMELLIA_256_CBC, NSS_USE_ALG_IN_SSL},
+    {CIPHER_NAME("CHACHA20-POLY1305"), SEC_OID_CHACHA20_POLY1305, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("SEED-CBC"), SEC_OID_SEED_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("DES-EDE3-CBC"), SEC_OID_DES_EDE3_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("DES-40-CBC"), SEC_OID_DES_40_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("DES-CBC"), SEC_OID_DES_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("NULL-CIPHER"), SEC_OID_NULL_CIPHER, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("RC2"), SEC_OID_RC2_CBC, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("RC4"), SEC_OID_RC4, NSS_USE_ALG_IN_SSL},
     {CIPHER_NAME("IDEA"), SEC_OID_IDEA_CBC, NSS_USE_ALG_IN_SSL},
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -89,32 +89,35 @@ static SECStatus ssl3_AESGCMBypass(ssl3K
  * suites to this list.
  */
 static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
    /*      cipher_suite                     policy       enabled   isPresent */
 
 #ifndef NSS_DISABLE_ECC
  { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
+ { TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
+ { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
    /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around
     * bug 946147.
     */
  { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,    SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,    SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,      SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,   SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,      SSL_ALLOWED, PR_TRUE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,        SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_ECDHE_RSA_WITH_RC4_128_SHA,          SSL_ALLOWED, PR_FALSE, PR_FALSE},
 #endif /* NSS_DISABLE_ECC */
 
  { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,     SSL_ALLOWED, PR_TRUE,  PR_FALSE},
+ { TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,SSL_ALLOWED,PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_AES_128_CBC_SHA,        SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_128_CBC_SHA,        SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,     SSL_ALLOWED, PR_TRUE,  PR_FALSE},
  { TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,     SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,   SSL_ALLOWED, PR_FALSE, PR_FALSE},
  { TLS_DHE_RSA_WITH_AES_256_CBC_SHA,        SSL_ALLOWED, PR_TRUE,  PR_FALSE},
@@ -284,16 +287,17 @@ static const ssl3BulkCipherDef bulk_ciph
     {cipher_des40,        calg_des,          8, 5, type_block,  8, 8, 0, 0, SEC_OID_DES_40_CBC},
     {cipher_idea,         calg_idea,        16,16, type_block,  8, 8, 0, 0, SEC_OID_IDEA_CBC},
     {cipher_aes_128,      calg_aes,         16,16, type_block, 16,16, 0, 0, SEC_OID_AES_128_CBC},
     {cipher_aes_256,      calg_aes,         32,32, type_block, 16,16, 0, 0, SEC_OID_AES_256_CBC},
     {cipher_camellia_128, calg_camellia,    16,16, type_block, 16,16, 0, 0, SEC_OID_CAMELLIA_128_CBC},
     {cipher_camellia_256, calg_camellia,    32,32, type_block, 16,16, 0, 0, SEC_OID_CAMELLIA_256_CBC},
     {cipher_seed,         calg_seed,        16,16, type_block, 16,16, 0, 0, SEC_OID_SEED_CBC},
     {cipher_aes_128_gcm,  calg_aes_gcm,     16,16, type_aead,   4, 0,16, 8, SEC_OID_AES_128_GCM},
+    {cipher_chacha20,     calg_chacha20,    32,32, type_aead,  12, 0,16, 0, SEC_OID_CHACHA20_POLY1305},
     {cipher_missing,      calg_null,         0, 0, type_stream, 0, 0, 0, 0, 0},
 };
 
 static const ssl3KEADef kea_defs[] =
 { /* indexed by SSL3KeyExchangeAlgorithm */
     /* kea            exchKeyType signKeyType is_limited limit tls_keygen ephemeral  oid */
     {kea_null,           kt_null, ssl_sign_null,  PR_FALSE,   0, PR_FALSE, PR_FALSE, 0},
     {kea_rsa,            kt_rsa,  ssl_sign_rsa,   PR_FALSE,   0, PR_FALSE, PR_FALSE, SEC_OID_TLS_RSA},
@@ -415,16 +419,20 @@ static const ssl3CipherSuiteDef cipher_s
     {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_rsa},
     {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_rsa},
     {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_ecdhe_ecdsa},
 
     {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss},
     {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss},
     {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss},
 
+    {TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_dhe_rsa},
+    {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_rsa},
+    {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, mac_aead, kea_ecdhe_ecdsa},
+
 #ifndef NSS_DISABLE_ECC
     {TLS_ECDH_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdh_ecdsa},
     {TLS_ECDH_ECDSA_WITH_RC4_128_SHA,      cipher_rc4, mac_sha, kea_ecdh_ecdsa},
     {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa},
     {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa},
     {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa},
 
     {TLS_ECDHE_ECDSA_WITH_NULL_SHA,        cipher_null, mac_sha, kea_ecdhe_ecdsa},
@@ -479,16 +487,17 @@ static const SSLCipher2Mech alg2Mech[] =
     { calg_des      , CKM_DES_CBC			},
     { calg_3des     , CKM_DES3_CBC			},
     { calg_idea     , CKM_IDEA_CBC			},
     { calg_fortezza , CKM_SKIPJACK_CBC64                },
     { calg_aes      , CKM_AES_CBC			},
     { calg_camellia , CKM_CAMELLIA_CBC			},
     { calg_seed     , CKM_SEED_CBC			},
     { calg_aes_gcm  , CKM_AES_GCM			},
+    { calg_chacha20 , CKM_NSS_CHACHA20_POLY1305         },
 /*  { calg_init     , (CK_MECHANISM_TYPE)0x7fffffffL    }  */
 };
 
 #define mmech_invalid  (CK_MECHANISM_TYPE)0x80000000L
 #define mmech_md5      CKM_SSL3_MD5_MAC
 #define mmech_sha      CKM_SSL3_SHA1_MAC
 #define mmech_md5_hmac CKM_MD5_HMAC
 #define mmech_sha_hmac CKM_SHA_1_HMAC
@@ -1790,16 +1799,17 @@ ssl3_InitPendingContextsBypass(sslSocket
         break;
     /* kill warnings. */
     case ssl_calg_null:
     case ssl_calg_rc4:
     case ssl_calg_rc2:
     case ssl_calg_idea:
     case ssl_calg_fortezza:
     case ssl_calg_aes_gcm:
+    case ssl_calg_chacha20:
         break;
     }
 
     rv = (*initFn)(clientContext,
 		   pwSpec->client.write_key_item.data,
 		   pwSpec->client.write_key_item.len,
 		   pwSpec->client.write_iv_item.data,
 		   mode, optArg1, optArg2);
@@ -1910,18 +1920,19 @@ ssl3_AESGCM(ssl3KeyMaterial *keys,
 	    int additionalDataLen)
 {
     SECItem            param;
     SECStatus          rv = SECFailure;
     unsigned char      nonce[12];
     unsigned int       uOutLen;
     CK_GCM_PARAMS      gcmParams;
 
-    static const int   tagSize = 16;
-    static const int   explicitNonceLen = 8;
+    const int tagSize = bulk_cipher_defs[cipher_aes_128_gcm].tag_size;
+    const int explicitNonceLen =
+        bulk_cipher_defs[cipher_aes_128_gcm].explicit_nonce_size;
 
     /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
      * nonce is formed. */
     memcpy(nonce, keys->write_iv, 4);
     if (doDecrypt) {
 	memcpy(nonce + 4, in, explicitNonceLen);
 	in += explicitNonceLen;
 	inlen -= explicitNonceLen;
@@ -1973,18 +1984,19 @@ ssl3_AESGCMBypass(ssl3KeyMaterial *keys,
 		  int additionalDataLen)
 {
     SECStatus          rv = SECFailure;
     unsigned char      nonce[12];
     unsigned int       uOutLen;
     AESContext        *cx;
     CK_GCM_PARAMS      gcmParams;
 
-    static const int   tagSize = 16;
-    static const int   explicitNonceLen = 8;
+    const int tagSize = bulk_cipher_defs[cipher_aes_128_gcm].tag_size;
+    const int explicitNonceLen =
+        bulk_cipher_defs[cipher_aes_128_gcm].explicit_nonce_size;
 
     /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the
      * nonce is formed. */
     PORT_Assert(keys->write_iv_item.len == 4);
     if (keys->write_iv_item.len != 4) {
 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 	return SECFailure;
     }
@@ -2028,16 +2040,65 @@ ssl3_AESGCMBypass(ssl3KeyMaterial *keys,
     }
     AES_DestroyContext(cx, PR_FALSE);
     *outlen += (int) uOutLen;
 
     return rv;
 }
 #endif
 
+static SECStatus
+ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
+                      unsigned char *out, int *outlen, int maxout,
+                      const unsigned char *in, int inlen,
+                      const unsigned char *additionalData,
+                      int additionalDataLen)
+{
+    size_t i;
+    SECItem param;
+    SECStatus rv = SECFailure;
+    unsigned int uOutLen;
+    unsigned char nonce[12];
+    CK_NSS_AEAD_PARAMS aeadParams;
+
+    const int tagSize = bulk_cipher_defs[cipher_chacha20].tag_size;
+
+    /* See
+     * https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2
+     * for details of how the nonce is formed. */
+    PORT_Memcpy(nonce, keys->write_iv, 12);
+
+    /* XOR the last 8 bytes of the IV with the sequence number. */
+    PORT_Assert(additionalDataLen >= 8);
+    for (i = 0; i < 8; ++i) {
+        nonce[4 + i] ^= additionalData[i];
+    }
+
+    param.type = siBuffer;
+    param.len = sizeof(aeadParams);
+    param.data = (unsigned char *)&aeadParams;
+    memset(&aeadParams, 0, sizeof(aeadParams));
+    aeadParams.pNonce = nonce;
+    aeadParams.ulNonceLen = sizeof(nonce);
+    aeadParams.pAAD = (unsigned char *)additionalData;
+    aeadParams.ulAADLen = additionalDataLen;
+    aeadParams.ulTagLen = tagSize;
+
+    if (doDecrypt) {
+        rv = PK11_Decrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, &param,
+                          out, &uOutLen, maxout, in, inlen);
+    } else {
+        rv = PK11_Encrypt(keys->write_key, CKM_NSS_CHACHA20_POLY1305, &param,
+                          out, &uOutLen, maxout, in, inlen);
+    }
+    *outlen = (int)uOutLen;
+
+    return rv;
+}
+
 /* Initialize encryption and MAC contexts for pending spec.
  * Master Secret already is derived.
  * Caller holds Spec write lock.
  */
 static SECStatus
 ssl3_InitPendingContextsPKCS11(sslSocket *ss)
 {
       ssl3CipherSpec  *  pwSpec;
@@ -2061,23 +2122,33 @@ ssl3_InitPendingContextsPKCS11(sslSocket
     cipher_def    = pwSpec->cipher_def;
     macLength     = pwSpec->mac_size;
     calg          = cipher_def->calg;
     PORT_Assert(alg2Mech[calg].calg == calg);
 
     pwSpec->client.write_mac_context = NULL;
     pwSpec->server.write_mac_context = NULL;
 
-    if (calg == calg_aes_gcm) {
+    if (cipher_def->type == type_aead) {
 	pwSpec->encode = NULL;
 	pwSpec->decode = NULL;
 	pwSpec->destroy = NULL;
 	pwSpec->encodeContext = NULL;
 	pwSpec->decodeContext = NULL;
-	pwSpec->aead = ssl3_AESGCM;
+        switch (calg) {
+        case calg_aes_gcm:
+            pwSpec->aead = ssl3_AESGCM;
+            break;
+        case calg_chacha20:
+            pwSpec->aead = ssl3_ChaCha20Poly1305;
+            break;
+        default:
+            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+            return SECFailure;
+        }
 	return SECSuccess;
     }
 
     /* 
     ** Now setup the MAC contexts, 
     **   crypto contexts are setup below.
     */
 
@@ -2180,16 +2251,31 @@ fail:
     if (pwSpec->server.write_mac_context != NULL) {
     	PK11_DestroyContext(pwSpec->server.write_mac_context,PR_TRUE);
 	pwSpec->server.write_mac_context = NULL;
     }
 
     return SECFailure;
 }
 
+/* Returns whether we can bypass PKCS#11 for a given cipher algorithm.
+ *
+ * We do not support PKCS#11 bypass for ChaCha20/Poly1305.
+ */
+static PRBool
+ssl3_CanBypassCipher(SSLCipherAlgorithm calg)
+{
+    switch (calg) {
+      case calg_chacha20:
+        return PR_FALSE;
+      default:
+        return PR_TRUE;
+    }
+}
+
 /* Complete the initialization of all keys, ciphers, MACs and their contexts
  * for the pending Cipher Spec.
  * Called from: ssl3_SendClientKeyExchange 	(for Full handshake)
  *              ssl3_HandleRSAClientKeyExchange	(for Full handshake)
  *              ssl3_HandleServerHello		(for session restart)
  *              ssl3_HandleClientHello		(for session restart)
  * Sets error code, but caller probably should override to disambiguate.
  * NULL pms means re-use old master_secret.
@@ -2219,17 +2305,18 @@ ssl3_InitPendingCipherSpec(sslSocket *ss
 
     if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) {
 	rv = ssl3_DeriveMasterSecret(ss, pms);
 	if (rv != SECSuccess) {
 	    goto done;  /* err code set by ssl3_DeriveMasterSecret */
 	}
     }
 #ifndef NO_PKCS11_BYPASS
-    if (ss->opt.bypassPKCS11 && pwSpec->msItem.len && pwSpec->msItem.data) {
+    if (ss->opt.bypassPKCS11 && pwSpec->msItem.len && pwSpec->msItem.data &&
+        ssl3_CanBypassCipher(ss->ssl3.pwSpec->cipher_def->calg)) {
 	/* Double Bypass succeeded in extracting the master_secret */
 	const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
 	PRBool             isTLS   = (PRBool)(kea_def->tls_keygen ||
                                 (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
 	pwSpec->bypassCiphers = PR_TRUE;
 	rv = ssl3_KeyAndMacDeriveBypass( pwSpec, 
 			     (const unsigned char *)&ss->ssl3.hs.client_random,
 			     (const unsigned char *)&ss->ssl3.hs.server_random,
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -1056,46 +1056,50 @@ static const ssl3CipherSuite ecdh_rsa_su
 };
 
 static const ssl3CipherSuite ecdhe_ecdsa_suites[] = {
     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_ECDHE_ECDSA_WITH_NULL_SHA,
     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
     0 /* end of list marker */
 };
 
 static const ssl3CipherSuite ecdhe_rsa_suites[] = {
     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
     TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_ECDHE_RSA_WITH_NULL_SHA,
     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
     0 /* end of list marker */
 };
 
 /* List of all ECC cipher suites */
 static const ssl3CipherSuite ecSuites[] = {
     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_ECDHE_ECDSA_WITH_NULL_SHA,
     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
     TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_ECDHE_RSA_WITH_NULL_SHA,
     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
     TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
     TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
     TLS_ECDH_ECDSA_WITH_NULL_SHA,
     TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
     TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
--- a/lib/ssl/sslenum.c
+++ b/lib/ssl/sslenum.c
@@ -45,32 +45,35 @@
  *      TLS_RSA_WITH_DES_CBC_SHA { 0x00,0x09 }
  * The broken server only supports the third and fourth ones and will select
  * the third one.
  */
 const PRUint16 SSL_ImplementedCiphers[] = {
 #ifndef NSS_DISABLE_ECC
     TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
     TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
     /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA must appear before
      * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA to work around bug 946147.
      */
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
     TLS_ECDHE_RSA_WITH_RC4_128_SHA,
 #endif /* NSS_DISABLE_ECC */
 
     TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+    TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
     TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
     TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
     TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
     TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
     TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
     TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
     TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
     TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -45,16 +45,17 @@ typedef SSLMACAlgorithm SSL3MACAlgorithm
 #define calg_des	ssl_calg_des
 #define calg_3des	ssl_calg_3des
 #define calg_idea	ssl_calg_idea
 #define calg_fortezza	ssl_calg_fortezza /* deprecated, must preserve */
 #define calg_aes	ssl_calg_aes
 #define calg_camellia	ssl_calg_camellia
 #define calg_seed	ssl_calg_seed
 #define calg_aes_gcm    ssl_calg_aes_gcm
+#define calg_chacha20   ssl_calg_chacha20
 
 #define mac_null	ssl_mac_null
 #define mac_md5 	ssl_mac_md5
 #define mac_sha 	ssl_mac_sha
 #define hmac_md5	ssl_hmac_md5
 #define hmac_sha	ssl_hmac_sha
 #define hmac_sha256	ssl_hmac_sha256
 #define mac_aead	ssl_mac_aead
@@ -280,19 +281,19 @@ typedef struct {
     ssl3CipherSuite cipher_suite;
     PRUint8         policy;
     unsigned char   enabled   : 1;
     unsigned char   isPresent : 1;
 #endif
 } ssl3CipherSuiteCfg;
 
 #ifndef NSS_DISABLE_ECC
-#define ssl_V3_SUITES_IMPLEMENTED 64
+#define ssl_V3_SUITES_IMPLEMENTED 67
 #else
-#define ssl_V3_SUITES_IMPLEMENTED 40
+#define ssl_V3_SUITES_IMPLEMENTED 41
 #endif /* NSS_DISABLE_ECC */
 
 #define MAX_DTLS_SRTP_CIPHER_SUITES 4
 
 /* MAX_SIGNATURE_ALGORITHMS allows for a large number of combinations of
  * SSLSignType and SSLHashType, but not all combinations (specifically, this
  * doesn't allow space for combinations with MD5). */
 #define MAX_SIGNATURE_ALGORITHMS 15
@@ -467,16 +468,17 @@ typedef enum {
     cipher_des40,
     cipher_idea, 
     cipher_aes_128,
     cipher_aes_256,
     cipher_camellia_128,
     cipher_camellia_256,
     cipher_seed,
     cipher_aes_128_gcm,
+    cipher_chacha20,
     cipher_missing              /* reserved for no such supported cipher */
     /* This enum must match ssl3_cipherName[] in ssl3con.c.  */
 } SSL3BulkCipher;
 
 typedef enum { type_stream, type_block, type_aead } CipherType;
 
 #define MAX_IV_LENGTH 24
 
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -146,16 +146,17 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc
 #define C_AES	"AES", calg_aes
 #define C_RC4	"RC4", calg_rc4
 #define C_RC2	"RC2", calg_rc2
 #define C_DES	"DES", calg_des
 #define C_3DES	"3DES", calg_3des
 #define C_NULL  "NULL", calg_null
 #define C_SJ 	"SKIPJACK", calg_sj
 #define C_AESGCM "AES-GCM", calg_aes_gcm
+#define C_CHACHA20 "CHACHA20POLY1305", calg_chacha20
 
 #define B_256	256, 256, 256
 #define B_128	128, 128, 128
 #define B_3DES  192, 156, 112
 #define B_SJ     96,  80,  80
 #define B_DES    64,  56,  56
 #define B_56    128,  56,  56
 #define B_40    128,  40,  40
@@ -165,16 +166,17 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc
 #define M_SHA256 "SHA256", ssl_hmac_sha256, 256
 #define M_SHA	"SHA1", ssl_mac_sha, 160
 #define M_MD5	"MD5",  ssl_mac_md5, 128
 #define M_NULL	"NULL", ssl_mac_null,  0
 
 static const SSLCipherSuiteInfo suiteInfo[] = {
 /* <------ Cipher suite --------------------> <auth> <KEA>  <bulk cipher> <MAC> <FIPS> */
 {0,CS(TLS_RSA_WITH_AES_128_GCM_SHA256),       S_RSA, K_RSA, C_AESGCM, B_128, M_AEAD_128, 1, 0, 0 },
+{0,CS(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_DHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 },
 
 {0,CS(TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA), S_RSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 },
 {0,CS(TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA), S_DSA, K_DHE, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 },
 {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256),   S_RSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0 },
 {0,CS(TLS_DHE_RSA_WITH_AES_256_CBC_SHA),      S_RSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0 },
 {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA),      S_DSA, K_DHE, C_AES, B_256, M_SHA, 1, 0, 0 },
 {0,CS(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256),   S_DSA, K_DHE, C_AES, B_256, M_SHA256, 1, 0, 0 },
 {0,CS(TLS_RSA_WITH_CAMELLIA_256_CBC_SHA),     S_RSA, K_RSA, C_CAMELLIA, B_256, M_SHA, 0, 0, 0 },
@@ -227,29 +229,31 @@ static const SSLCipherSuiteInfo suiteInf
 {0,CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA),   S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0 },
 
 {0,CS(TLS_ECDHE_ECDSA_WITH_NULL_SHA),         S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0 },
 {0,CS(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA),      S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0 },
 {0,CS(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0 },
 {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA),  S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0 },
 {0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0 },
 {0,CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA),  S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0 },
+{0,CS(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256), S_ECDSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 },
 
 {0,CS(TLS_ECDH_RSA_WITH_NULL_SHA),            S_RSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0 },
 {0,CS(TLS_ECDH_RSA_WITH_RC4_128_SHA),         S_RSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0 },
 {0,CS(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA),    S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, 1, 0, 0 },
 {0,CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA),     S_RSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0 },
 {0,CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA),     S_RSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0 },
 
 {0,CS(TLS_ECDHE_RSA_WITH_NULL_SHA),           S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0 },
 {0,CS(TLS_ECDHE_RSA_WITH_RC4_128_SHA),        S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0 },
 {0,CS(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA),   S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0 },
 {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA),    S_RSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0 },
 {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256), S_RSA, K_ECDHE, C_AES, B_128, M_SHA256, 1, 0, 0 },
 {0,CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA),    S_RSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0 },
+{0,CS(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256), S_RSA, K_ECDHE, C_CHACHA20, B_256, M_AEAD_128, 0, 0, 0 },
 #endif /* NSS_DISABLE_ECC */
 
 /* SSL 2 table */
 {0,CK(SSL_CK_RC4_128_WITH_MD5),               S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0 },
 {0,CK(SSL_CK_RC2_128_CBC_WITH_MD5),           S_RSA, K_RSA, C_RC2, B_128, M_MD5, 0, 0, 0 },
 {0,CK(SSL_CK_DES_192_EDE3_CBC_WITH_MD5),      S_RSA, K_RSA, C_3DES,B_3DES,M_MD5, 0, 0, 0 },
 {0,CK(SSL_CK_DES_64_CBC_WITH_MD5),            S_RSA, K_RSA, C_DES, B_DES, M_MD5, 0, 0, 0 },
 {0,CK(SSL_CK_RC4_128_EXPORT40_WITH_MD5),      S_RSA, K_RSA, C_RC4, B_40,  M_MD5, 0, 1, 0 },
--- a/lib/ssl/sslproto.h
+++ b/lib/ssl/sslproto.h
@@ -255,16 +255,20 @@
 #define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
 #define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256   0xC027
 
 #define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
 #define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256  0xC02D
 #define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   0xC02F
 #define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256    0xC031
 
+#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256   0xCCA8
+#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9
+#define TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256     0xCCAA
+
 /* Netscape "experimental" cipher suites. */
 #define SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA   0xffe0
 #define SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA        0xffe1
 
 /* New non-experimental openly spec'ed versions of those cipher suites. */
 #define SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA      0xfeff
 #define SSL_RSA_FIPS_WITH_DES_CBC_SHA           0xfefe
 
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -99,17 +99,18 @@ typedef enum {
     ssl_calg_rc2      = 2,
     ssl_calg_des      = 3,
     ssl_calg_3des     = 4,
     ssl_calg_idea     = 5,
     ssl_calg_fortezza = 6,      /* deprecated, now unused */
     ssl_calg_aes      = 7,
     ssl_calg_camellia = 8,
     ssl_calg_seed     = 9,
-    ssl_calg_aes_gcm  = 10
+    ssl_calg_aes_gcm  = 10,
+    ssl_calg_chacha20 = 11
 } SSLCipherAlgorithm;
 
 typedef enum { 
     ssl_mac_null      = 0, 
     ssl_mac_md5       = 1, 
     ssl_mac_sha       = 2, 
     ssl_hmac_md5      = 3, 	/* TLS HMAC version of mac_md5 */
     ssl_hmac_sha      = 4, 	/* TLS HMAC version of mac_sha */
--- a/lib/util/secoid.c
+++ b/lib/util/secoid.c
@@ -1647,17 +1647,16 @@ const static SECOidData oids[SEC_OID_TOT
 	CKM_INVALID_MECHANISM /* not yet defined */, INVALID_CERT_EXTENSION),
     OD( msExtendedKeyUsageTrustListSigning, 
         SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING,
         "Microsoft Trust List Signing",
 	CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
     OD( x520Name, SEC_OID_AVA_NAME,
     	"X520 Name",    CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
 
-
     OD( aes128_GCM, SEC_OID_AES_128_GCM,
 	"AES-128-GCM", CKM_AES_GCM, INVALID_CERT_EXTENSION ),
     OD( aes192_GCM, SEC_OID_AES_192_GCM,
 	"AES-192-GCM", CKM_AES_GCM, INVALID_CERT_EXTENSION ),
     OD( aes256_GCM, SEC_OID_AES_256_GCM,
 	"AES-256-GCM", CKM_AES_GCM, INVALID_CERT_EXTENSION ),
     OD( idea_CBC, SEC_OID_IDEA_CBC,
 	"IDEA_CBC", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
@@ -1705,16 +1704,18 @@ const static SECOidData oids[SEC_OID_TOT
     ODE( SEC_OID_TLS_DH_RSA_EXPORT,
 	"TLS DH-RSA-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
     ODE( SEC_OID_TLS_DH_DSS_EXPORT,
 	"TLS DH-DSS-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
     ODE( SEC_OID_TLS_DH_ANON_EXPORT,
 	"TLS DH-ANON-EXPORT key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
     ODE( SEC_OID_APPLY_SSL_POLICY,
 	"Apply SSL policy (pseudo-OID)", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+    ODE( SEC_OID_CHACHA20_POLY1305,
+	"ChaCha20-Poly1305", CKM_NSS_CHACHA20_POLY1305, INVALID_CERT_EXTENSION ),
 
 };
 
 /* PRIVATE EXTENDED SECOID Table
  * This table is private. Its structure is opaque to the outside.
  * It is indexed by the same SECOidTag as the oids table above.
  * Every member of this struct must have accessor functions (set, get)
  * and those functions must operate by value, not by reference.
--- a/lib/util/secoidt.h
+++ b/lib/util/secoidt.h
@@ -474,16 +474,18 @@ typedef enum {
 
     SEC_OID_TLS_DHE_RSA_EXPORT         = 340,
     SEC_OID_TLS_DHE_DSS_EXPORT         = 341,
     SEC_OID_TLS_DH_RSA_EXPORT          = 342,
     SEC_OID_TLS_DH_DSS_EXPORT          = 343,
     SEC_OID_TLS_DH_ANON_EXPORT         = 344,
     SEC_OID_APPLY_SSL_POLICY           = 345,
 
+    SEC_OID_CHACHA20_POLY1305          = 346,
+
     SEC_OID_TOTAL
 } SECOidTag;
 
 #define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1
 #define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1
 #define SEC_OID_PKCS12_KEY_USAGE  SEC_OID_X509_KEY_USAGE
 
 /* fake OID for DSS sign/verify */
--- a/tests/ssl/ssl.sh
+++ b/tests/ssl/ssl.sh
@@ -80,22 +80,24 @@ ssl_init()
   #fileout=1
   #verbose="-v" #FIXME - see where this is usefull
 
   USER_NICKNAME=TestUser
   NORM_EXT=""
 
   if [ -z "$NSS_DISABLE_ECC" ] ; then
       ECC_STRING=" - with ECC"
+      # List of cipher suites to test, including ECC cipher suites.
+      CIPHER_SUITES="-c ABCDEF:C001:C002:C003:C004:C005:C006:C007:C008:C009:C00A:C00B:C00C:C00D:C00E:C00F:C010:C011:C012:C013:C014:C023:C027:C02B:C02F:CCA8:CCA9:CCAA:0016:0032:0033:0038:0039:003B:003C:003D:0040:0041:0067:006A:006B:0084:009C:009E:00A2cdefgijklmnvyz"
   else
       ECC_STRING=""
+      # List of cipher suites to test, excluding ECC cipher suites.
+      CIPHER_SUITES="-c ABCDEF:0016:0032:0033:0038:0039:003B:003C:003D:0040:0041:0067:006A:006B:0084:009C:009E:00A2:CCAAcdefgijklmnvyz"
   fi
 
-  CSHORT="-c ABCDEF:0016:0032:0033:0038:0039:003B:003C:003D:0040:0041:0067:006A:006B:0084:009C:009E:00A2cdefgijklmnvyz"
-  CLONG="-c ABCDEF:C001:C002:C003:C004:C005:C006:C007:C008:C009:C00A:C00B:C00C:C00D:C00E:C00F:C010:C011:C012:C013:C014:C023:C027:C02B:C02F:0016:0032:0033:0038:0039:003B:003C:003D:0040:0041:0067:006A:006B:0084:009C:009E:00A2cdefgijklmnvyz"
 
   if [ "${OS_ARCH}" != "WINNT" ]; then
       ulimit -n 1000 # make sure we have enough file descriptors
   fi
 
   cd ${CLIENTDIR}
 }
 
@@ -255,21 +257,17 @@ start_selfserv()
 ############################## ssl_cov #################################
 # local shell function to perform SSL Cipher Coverage tests
 ########################################################################
 ssl_cov()
 {
   html_head "SSL Cipher Coverage $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE $ECC_STRING"
 
   testname=""
-  if [ -z "$NSS_DISABLE_ECC" ] ; then
-      sparam="$CLONG"
-  else
-      sparam="$CSHORT"
-  fi
+  sparam="$CIPHER_SUITES"
 
   mixed=0
   start_selfserv # Launch the server
 
   VMIN="ssl2"
   VMAX="tls1.1"
                
   exec < ${SSLCOV}
@@ -726,21 +724,17 @@ ssl_crl_ssl()
 ############################## ssl_cov #################################
 # local shell function to perform SSL Policy tests
 ########################################################################
 ssl_policy()
 {
   html_head "SSL POLICY $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE $ECC_STRING"
 
   testname=""
-  if [ -z "$NSS_DISABLE_ECC" ] ; then
-      sparam="$CLONG"
-  else
-      sparam="$CSHORT"
-  fi
+  sparam="$CIPHER_SUITES"
 
   if [ ! -f "${P_R_CLIENTDIR}/pkcs11.txt" ] ; then
       return;
   fi
 
   echo "Saving pkcs11.txt"
   cp ${P_R_CLIENTDIR}/pkcs11.txt ${P_R_CLIENTDIR}/pkcs11.txt.sav
 
--- a/tests/ssl/sslcov.txt
+++ b/tests/ssl/sslcov.txt
@@ -96,16 +96,17 @@
   noECC  TLS12 :003D  TLS12_RSA_WITH_AES_256_CBC_SHA256
   noECC  TLS12 :0040  TLS12_DHE_DSS_WITH_AES_128_CBC_SHA256
   noECC  TLS12 :0067  TLS12_DHE_RSA_WITH_AES_128_CBC_SHA256
   noECC  TLS12 :006A  TLS12_DHE_DSS_WITH_AES_256_CBC_SHA256
   noECC  TLS12 :006B  TLS12_DHE_RSA_WITH_AES_256_CBC_SHA256
   noECC  TLS12 :009C  TLS12_RSA_WITH_AES_128_GCM_SHA256
   noECC  TLS12 :009E  TLS12_DHE_RSA_WITH_AES_128_GCM_SHA256
   noECC  TLS12 :00A2  TLS12_DHE_DSS_WITH_AES_128_GCM_SHA256
+  noECC  TLS12 :CCAA  TLS12_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
 #
 # ECC ciphers (TLS)
 #
    ECC   TLS10  :C001 TLS_ECDH_ECDSA_WITH_NULL_SHA
    ECC   TLS10  :C002 TLS_ECDH_ECDSA_WITH_RC4_128_SHA
    ECC   TLS10  :C003 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
    ECC   TLS10  :C004 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
    ECC   TLS10  :C005 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
@@ -165,8 +166,10 @@
    ECC   TLS12  :C011 TLS12_ECDHE_RSA_WITH_RC4_128_SHA
    ECC   TLS12  :C012 TLS12_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
    ECC   TLS12  :C013 TLS12_ECDHE_RSA_WITH_AES_128_CBC_SHA
    ECC   TLS12  :C014 TLS12_ECDHE_RSA_WITH_AES_256_CBC_SHA
    ECC   TLS12  :C023 TLS12_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    ECC   TLS12  :C027 TLS12_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    ECC   TLS12  :C02B TLS12_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    ECC   TLS12  :C02F TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+   ECC   TLS12  :CCA8 TLS12_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+   ECC   TLS12  :CCA9 TLS12_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256