Bug 1577822 - land NSS NSS_3_47_BETA4 UPGRADE_NSS_RELEASE, r=kjacobs
authorJ.C. Jones <jc@mozilla.com>
Fri, 18 Oct 2019 17:05:24 +0000
changeset 559592 27bbc1fba01518ef3f0ef836fb4a0473d8f71915
parent 559591 c11aa23a063905003bdf0ebc16f78a36474f4b26
child 559593 80ffb5ef8efb71442034e56a093a4367ac06cdf6
push id12177
push usercsabou@mozilla.com
push dateMon, 21 Oct 2019 14:52:16 +0000
treeherdermozilla-beta@1918a9cd33bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskjacobs
bugs1577822, 1459141, 1589120, 1588244
milestone71.0a1
first release with
nightly linux32
27bbc1fba015 / 71.0a1 / 20191018214804 / files
nightly linux64
27bbc1fba015 / 71.0a1 / 20191018214804 / files
nightly mac
27bbc1fba015 / 71.0a1 / 20191018214804 / files
nightly win32
27bbc1fba015 / 71.0a1 / 20191018214804 / files
nightly win64
27bbc1fba015 / 71.0a1 / 20191018214804 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1577822 - land NSS NSS_3_47_BETA4 UPGRADE_NSS_RELEASE, r=kjacobs 2019-10-18 Deian Stefan <deian@cs.ucsd.edu> * lib/softoken/pkcs11c.c: Bug 1459141 - Rewrite softoken CBC pad check to be constant r=jcj,kjacobs [d3c8638f85cd] [NSS_3_47_BETA4] 2019-10-17 Kevin Jacobs <kjacobs@mozilla.com> * gtests/pk11_gtest/pk11_cbc_unittest.cc: Bug 1589120 - Additional test vectors for CBC padding. r=jcj This patch adds more test vectors for AES-CBC and 3DES-CBC padding. [7f17b911ac99] * gtests/pk11_gtest/manifest.mn, gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc, gtests/pk11_gtest/pk11_gtest.gyp: Bug 1589120 - Tests for padded AES key wrap r=jcj This patch adds test vectors for padded AES Key Wrap. AES-CBC and 3DES-CBC ports of the same vectors will be included in a separate revision. [fb4d9b6ea2c4] 2019-10-16 Kevin Jacobs <kjacobs@mozilla.com> * gtests/ssl_gtest/tls_agent.cc, gtests/ssl_gtest/tls_agent.h, gtests/ssl_gtest/tls_subcerts_unittest.cc, lib/ssl/ssl3con.c, lib/ssl/sslimpl.h, lib/ssl/tls13subcerts.c, tests/common/certsetup.sh, tests/ssl_gtests/ssl_gtests.sh: Bug 1588244 - SSLExp_DelegateCredential to support 'rsaEncryption' end-entity certs with default scheme override r=mt If an end-entity cert has an SPKI type of 'rsaEncryption', override the DC alg to be `ssl_sig_rsa_pss_rsae_sha256`. [93383e0fb833] 2019-10-16 J.C. Jones <jjones@mozilla.com> * .hgtags: Added tag NSS_3_47_BETA3 for changeset f10c3e0757b7 [fa8a67bee2dc] Differential Revision: https://phabricator.services.mozilla.com/D49774
security/nss/TAG-INFO
security/nss/coreconf/coreconf.dep
security/nss/gtests/pk11_gtest/manifest.mn
security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
security/nss/gtests/pk11_gtest/pk11_gtest.gyp
security/nss/gtests/ssl_gtest/tls_agent.cc
security/nss/gtests/ssl_gtest/tls_agent.h
security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/tls13subcerts.c
security/nss/tests/common/certsetup.sh
security/nss/tests/ssl_gtests/ssl_gtests.sh
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_47_BETA3
\ No newline at end of file
+NSS_3_47_BETA4
\ No newline at end of file
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/gtests/pk11_gtest/manifest.mn
+++ b/security/nss/gtests/pk11_gtest/manifest.mn
@@ -4,16 +4,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 CORE_DEPTH = ../..
 DEPTH      = ../..
 MODULE = nss
 
 CPPSRCS = \
       pk11_aes_gcm_unittest.cc \
       pk11_aeskeywrap_unittest.cc \
+      pk11_aeskeywrappad_unittest.cc \
       pk11_cbc_unittest.cc \
       pk11_chacha20poly1305_unittest.cc \
       pk11_curve25519_unittest.cc \
       pk11_der_private_key_import_unittest.cc \
       pk11_ecdsa_unittest.cc \
       pk11_encrypt_derive_unittest.cc \
       pk11_export_unittest.cc \
       pk11_find_certs_unittest.cc \
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
@@ -0,0 +1,415 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <memory>
+#include "gtest/gtest.h"
+#include "nss.h"
+#include "nss_scoped_ptrs.h"
+#include "pk11pub.h"
+
+namespace nss_test {
+
+class Pkcs11AESKeyWrapPadTest : public ::testing::Test {};
+
+// Encrypt an ephemeral EC key (U2F use case)
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapECKey) {
+  const uint32_t kwrappedBufLen = 256;
+  const uint32_t kPublicKeyLen = 65;
+  const uint32_t kOidLen = 65;
+  unsigned char param_buf[kOidLen];
+  unsigned char unwrap_buf[kPublicKeyLen];
+
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+
+  SECItem ecdsa_params = {siBuffer, param_buf, sizeof(param_buf)};
+  SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
+  ASSERT_NE(oid_data, 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;
+
+  SECKEYPublicKey* pub_tmp;
+  ScopedSECKEYPublicKey pub_key;
+  ScopedSECKEYPrivateKey priv_key(
+      PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsa_params,
+                           &pub_tmp, PR_FALSE, PR_TRUE, nullptr));
+  ASSERT_NE(nullptr, priv_key);
+  ASSERT_NE(nullptr, pub_tmp);
+  pub_key.reset(pub_tmp);
+
+  // Generate a KEK.
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
+  ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr));
+
+  SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(),
+                                  CKM_NSS_AES_KEY_WRAP_PAD, param.get(),
+                                  wrapped.get(), nullptr);
+  ASSERT_EQ(rv, SECSuccess);
+
+  SECItem pubKey = {siBuffer, unwrap_buf, kPublicKeyLen};
+  CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN};
+  int usageCount = 1;
+
+  ScopedSECKEYPrivateKey unwrapped(
+      PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD,
+                         param.get(), wrapped.get(), nullptr, &pubKey, false,
+                         true, CKK_EC, usages, usageCount, nullptr));
+  ASSERT_EQ(0, PORT_GetError());
+  ASSERT_TRUE(!!unwrapped);
+}
+
+// Encrypt an ephemeral RSA key
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRsaKey) {
+  const uint32_t kwrappedBufLen = 648;
+  unsigned char unwrap_buf[kwrappedBufLen];
+
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+
+  PK11RSAGenParams rsa_param;
+  rsa_param.keySizeInBits = 1024;
+  rsa_param.pe = 65537L;
+
+  SECKEYPublicKey* pub_tmp;
+  ScopedSECKEYPublicKey pub_key;
+  ScopedSECKEYPrivateKey priv_key(
+      PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsa_param,
+                           &pub_tmp, PR_FALSE, PR_FALSE, nullptr));
+  ASSERT_NE(nullptr, priv_key);
+  ASSERT_NE(nullptr, pub_tmp);
+  pub_key.reset(pub_tmp);
+
+  // Generate a KEK.
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  ScopedSECItem wrapped(::SECITEM_AllocItem(nullptr, nullptr, kwrappedBufLen));
+  ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, nullptr));
+
+  SECStatus rv = PK11_WrapPrivKey(slot.get(), kek.get(), priv_key.get(),
+                                  CKM_NSS_AES_KEY_WRAP_PAD, param.get(),
+                                  wrapped.get(), nullptr);
+  ASSERT_EQ(rv, SECSuccess);
+
+  SECItem pubKey = {siBuffer, unwrap_buf, kwrappedBufLen};
+  CK_ATTRIBUTE_TYPE usages[] = {CKA_SIGN};
+  int usageCount = 1;
+
+  ScopedSECKEYPrivateKey unwrapped(
+      PK11_UnwrapPrivKey(slot.get(), kek.get(), CKM_NSS_AES_KEY_WRAP_PAD,
+                         param.get(), wrapped.get(), nullptr, &pubKey, false,
+                         false, CKK_EC, usages, usageCount, nullptr));
+  ASSERT_EQ(0, PORT_GetError());
+  ASSERT_TRUE(!!unwrapped);
+
+  ScopedSECItem priv_key_data(
+      PK11_ExportDERPrivateKeyInfo(priv_key.get(), nullptr));
+  ScopedSECItem unwrapped_data(
+      PK11_ExportDERPrivateKeyInfo(unwrapped.get(), nullptr));
+  EXPECT_TRUE(!!priv_key_data);
+  EXPECT_TRUE(!!unwrapped_data);
+  ASSERT_EQ(priv_key_data->len, unwrapped_data->len);
+  ASSERT_EQ(
+      0, memcmp(priv_key_data->data, unwrapped_data->data, priv_key_data->len));
+}
+
+// Wrap a random that's a multiple of the block size, and compare the unwrap
+// result.
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_EvenBlock) {
+  const uint32_t kInputKeyLen = 128;
+  uint32_t out_len = 0;
+  std::vector<unsigned char> input_key(kInputKeyLen);
+  std::vector<unsigned char> wrapped_key(
+      kInputKeyLen + AES_BLOCK_SIZE);  // One block of padding
+  std::vector<unsigned char> unwrapped_key(
+      kInputKeyLen + AES_BLOCK_SIZE);  // One block of padding
+
+  // Generate input key material
+  SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
+  EXPECT_EQ(SECSuccess, rv);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    wrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(wrapped_key.size()),
+                    input_key.data(),
+                    static_cast<unsigned int>(input_key.size()));
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(input_key.size(), out_len);
+  ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
+}
+
+// Wrap a random that's NOT a multiple of the block size, and compare the unwrap
+// result.
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock1) {
+  const uint32_t kInputKeyLen = 65;
+  uint32_t out_len = 0;
+  std::vector<unsigned char> input_key(kInputKeyLen);
+  std::vector<unsigned char> wrapped_key(
+      kInputKeyLen + AES_BLOCK_SIZE);  // One block of padding
+  std::vector<unsigned char> unwrapped_key(
+      kInputKeyLen + AES_BLOCK_SIZE);  // One block of padding
+
+  // Generate input key material
+  SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
+  EXPECT_EQ(SECSuccess, rv);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    wrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(wrapped_key.size()),
+                    input_key.data(),
+                    static_cast<unsigned int>(input_key.size()));
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(input_key.size(), out_len);
+  ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
+}
+
+// Wrap a random that's NOT a multiple of the block size, and compare the unwrap
+// result.
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_OddBlock2) {
+  const uint32_t kInputKeyLen = 63;
+  uint32_t out_len = 0;
+  std::vector<unsigned char> input_key(kInputKeyLen);
+  std::vector<unsigned char> wrapped_key(
+      kInputKeyLen + AES_BLOCK_SIZE);  // One block of padding
+  std::vector<unsigned char> unwrapped_key(
+      kInputKeyLen + AES_BLOCK_SIZE);  // One block of padding
+
+  // Generate input key material
+  SECStatus rv = PK11_GenerateRandom(input_key.data(), input_key.size());
+  EXPECT_EQ(SECSuccess, rv);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  rv = PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    wrapped_key.data(), &out_len, wrapped_key.size(),
+                    input_key.data(), input_key.size());
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(input_key.size(), out_len);
+  ASSERT_EQ(0, memcmp(input_key.data(), unwrapped_key.data(), out_len));
+}
+
+// Invalid long padding (over the block size, but otherwise valid)
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_PaddingTooLong) {
+  const uint32_t kInputKeyLen = 32;
+  uint32_t out_len = 0;
+
+  // Apply our own padding
+  const unsigned char buf[32] = {
+      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
+  std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+  std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  SECStatus rv =
+      PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP,  // Don't apply more padding
+                   /* param */ nullptr, wrapped_key.data(), &out_len,
+                   wrapped_key.size(), buf, sizeof(buf));
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECFailure, rv);
+}
+
+// Invalid 0-length padding (there should be a full block if the message doesn't
+// need to be padded)
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_NoPadding) {
+  const uint32_t kInputKeyLen = 32;
+  uint32_t out_len = 0;
+
+  // Apply our own padding
+  const unsigned char buf[32] = {0};
+  std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+  std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  SECStatus rv =
+      PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP,  // Don't apply more padding
+                   /* param */ nullptr, wrapped_key.data(), &out_len,
+                   wrapped_key.size(), buf, sizeof(buf));
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECFailure, rv);
+}
+
+// Invalid padding
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding1) {
+  const uint32_t kInputKeyLen = 32;
+  uint32_t out_len = 0;
+
+  // Apply our own padding
+  const unsigned char buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08,
+                                 0x08, 0x08, 0x08, 0x08};  // Check all 8 bytes
+  std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+  std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  SECStatus rv =
+      PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP,  // Don't apply more padding
+                   /* param */ nullptr, wrapped_key.data(), &out_len,
+                   wrapped_key.size(), buf, sizeof(buf));
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECFailure, rv);
+}
+
+// Invalid padding
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_BadPadding2) {
+  const uint32_t kInputKeyLen = 32;
+  uint32_t out_len = 0;
+
+  // Apply our own padding
+  const unsigned char
+      buf[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                 0x00, 0x00, 0x00, 0x01, 0x02};  // Check first loop repeat
+  std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+  std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  SECStatus rv =
+      PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP,  // Don't apply more padding
+                   /* param */ nullptr, wrapped_key.data(), &out_len,
+                   wrapped_key.size(), buf, sizeof(buf));
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECFailure, rv);
+}
+
+// Minimum valid padding
+TEST_F(Pkcs11AESKeyWrapPadTest, WrapUnwrapRandom_ShortValidPadding) {
+  const uint32_t kInputKeyLen = 32;
+  uint32_t out_len = 0;
+
+  // Apply our own padding
+  const unsigned char buf[kInputKeyLen] = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};  // Minimum
+  std::vector<unsigned char> wrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+  std::vector<unsigned char> unwrapped_key(kInputKeyLen + AES_BLOCK_SIZE);
+
+  // Generate a KEK.
+  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+  ASSERT_NE(nullptr, slot);
+  ScopedPK11SymKey kek(
+      PK11_KeyGen(slot.get(), CKM_AES_CBC, nullptr, 16, nullptr));
+  ASSERT_NE(nullptr, kek);
+
+  // Wrap the key
+  SECStatus rv =
+      PK11_Encrypt(kek.get(), CKM_NSS_AES_KEY_WRAP,  // Don't apply more padding
+                   /* param */ nullptr, wrapped_key.data(), &out_len,
+                   wrapped_key.size(), buf, sizeof(buf));
+  ASSERT_EQ(SECSuccess, rv);
+
+  rv = PK11_Decrypt(kek.get(), CKM_NSS_AES_KEY_WRAP_PAD, /* param */ nullptr,
+                    unwrapped_key.data(), &out_len,
+                    static_cast<unsigned int>(unwrapped_key.size()),
+                    wrapped_key.data(), out_len);
+  ASSERT_EQ(SECSuccess, rv);
+  ASSERT_EQ(kInputKeyLen - 1, out_len);
+  ASSERT_EQ(0, memcmp(buf, unwrapped_key.data(), out_len));
+}
+
+} /* nss_test */
--- a/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
+++ b/security/nss/gtests/pk11_gtest/pk11_cbc_unittest.cc
@@ -36,16 +36,27 @@ class Pkcs11CbcPadTest : public ::testin
       case CKM_DES3_CBC:
         return false;
 
       default:
         ADD_FAILURE() << "Unknown mechanism " << GetParam();
     }
     return false;
   }
+  uint32_t GetUnpaddedParam() const {
+    switch (GetParam()) {
+      case CKM_AES_CBC_PAD:
+        return CKM_AES_CBC;
+      case CKM_DES3_CBC_PAD:
+        return CKM_DES3_CBC;
+      default:
+        ADD_FAILURE() << "Unknown padded mechanism " << GetParam();
+    }
+    return 0;
+  }
 
   size_t block_size() const {
     return static_cast<size_t>(PK11_GetBlockSize(GetParam(), nullptr));
   }
 
   size_t GetInputLen(CK_ATTRIBUTE_TYPE op) const {
     if (is_padded() && op == CKA_ENCRYPT) {
       // Anything goes for encryption when padded.
@@ -335,13 +346,146 @@ TEST_P(Pkcs11CbcPadTest, ContextFailDecr
   SECStatus rv = PK11_CipherOp(dctx.get(), output, &output_len, sizeof(output),
                                kInput, GetInputLen(CKA_DECRYPT) - 1);
   EXPECT_EQ(SECFailure, rv);
   // Because PK11_CipherOp is partial, it can return data on failure.
   // This means that it needs to reset its output length to 0 when it starts.
   EXPECT_EQ(0, output_len) << "output_len is reset";
 }
 
+TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_PaddingTooLong) {
+  if (!is_padded()) {
+    return;
+  }
+
+  // Padding that's over the block size
+  const std::vector<uint8_t> input = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+      0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
+  std::vector<uint8_t> encrypted(input.size());
+  uint32_t encrypted_len = 0;
+
+  ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
+  SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedParam(), GetIv(),
+                              encrypted.data(), &encrypted_len,
+                              encrypted.size(), input.data(), input.size());
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(input.size(), encrypted_len);
+
+  std::vector<uint8_t> decrypted(input.size());
+  uint32_t decrypted_len = 0;
+  ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
+  rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
+                    &decrypted_len, decrypted.size(), encrypted.data(),
+                    encrypted_len);
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(0U, decrypted_len);
+}
+
+TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_BadPadding1) {
+  if (!is_padded()) {
+    return;
+  }
+
+  // Padding that's one byte short
+  const std::vector<uint8_t> input = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08};
+  std::vector<uint8_t> encrypted(input.size());
+  uint32_t encrypted_len = 0;
+
+  ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
+  SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedParam(), GetIv(),
+                              encrypted.data(), &encrypted_len,
+                              encrypted.size(), input.data(), input.size());
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(input.size(), encrypted_len);
+
+  std::vector<uint8_t> decrypted(input.size());
+  uint32_t decrypted_len = 0;
+  ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
+  rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
+                    &decrypted_len, decrypted.size(), encrypted.data(),
+                    encrypted_len);
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(0U, decrypted_len);
+}
+
+TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_BadPadding2) {
+  if (!is_padded()) {
+    return;
+  }
+
+  // Padding that's one byte short
+  const std::vector<uint8_t> input = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02};
+  std::vector<uint8_t> encrypted(input.size());
+  uint32_t encrypted_len = 0;
+
+  ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
+  SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedParam(), GetIv(),
+                              encrypted.data(), &encrypted_len,
+                              encrypted.size(), input.data(), input.size());
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(input.size(), encrypted_len);
+
+  std::vector<uint8_t> decrypted(input.size());
+  uint32_t decrypted_len = 0;
+  ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
+  rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
+                    &decrypted_len, decrypted.size(), encrypted.data(),
+                    encrypted_len);
+  EXPECT_EQ(SECFailure, rv);
+  EXPECT_EQ(0U, decrypted_len);
+}
+
+TEST_P(Pkcs11CbcPadTest, EncryptDecrypt_ShortValidPadding) {
+  if (!is_padded()) {
+    return;
+  }
+
+  // Minimal valid padding
+  const std::vector<uint8_t> input = {
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+  std::vector<uint8_t> encrypted(input.size());
+  uint32_t encrypted_len = 0;
+
+  ScopedPK11SymKey ek = MakeKey(CKA_ENCRYPT);
+  SECStatus rv = PK11_Encrypt(ek.get(), GetUnpaddedParam(), GetIv(),
+                              encrypted.data(), &encrypted_len,
+                              encrypted.size(), input.data(), input.size());
+  ASSERT_EQ(SECSuccess, rv);
+  EXPECT_EQ(input.size(), encrypted_len);
+
+  std::vector<uint8_t> decrypted(input.size());
+  uint32_t decrypted_len = 0;
+  ScopedPK11SymKey dk = MakeKey(CKA_DECRYPT);
+  rv = PK11_Decrypt(dk.get(), GetParam(), GetIv(), decrypted.data(),
+                    &decrypted_len, decrypted.size(), encrypted.data(),
+                    encrypted_len);
+  EXPECT_EQ(SECSuccess, rv);
+  EXPECT_EQ(input.size() - 1, decrypted_len);
+  EXPECT_EQ(0, memcmp(decrypted.data(), input.data(), decrypted_len));
+}
+
 INSTANTIATE_TEST_CASE_P(EncryptDecrypt, Pkcs11CbcPadTest,
                         ::testing::Values(CKM_AES_CBC_PAD, CKM_AES_CBC,
                                           CKM_DES3_CBC_PAD, CKM_DES3_CBC));
 
 }  // namespace nss_test
--- a/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
+++ b/security/nss/gtests/pk11_gtest/pk11_gtest.gyp
@@ -9,16 +9,17 @@
   'targets': [
     {
       'target_name': 'pk11_gtest',
       'type': 'executable',
       'sources': [
         'pk11_aes_cmac_unittest.cc',
         'pk11_aes_gcm_unittest.cc',
         'pk11_aeskeywrap_unittest.cc',
+        'pk11_aeskeywrappad_unittest.cc',
         'pk11_cbc_unittest.cc',
         'pk11_chacha20poly1305_unittest.cc',
         'pk11_cipherop_unittest.cc',
         'pk11_curve25519_unittest.cc',
         'pk11_der_private_key_import_unittest.cc',
         'pk11_ecdsa_unittest.cc',
         'pk11_encrypt_derive_unittest.cc',
         'pk11_find_certs_unittest.cc',
--- a/security/nss/gtests/ssl_gtest/tls_agent.cc
+++ b/security/nss/gtests/ssl_gtest/tls_agent.cc
@@ -43,16 +43,17 @@ const std::string TlsAgent::kServerRsaPs
 const std::string TlsAgent::kServerRsaDecrypt = "rsa_decrypt";
 const std::string TlsAgent::kServerEcdsa256 = "ecdsa256";
 const std::string TlsAgent::kServerEcdsa384 = "ecdsa384";
 const std::string TlsAgent::kServerEcdsa521 = "ecdsa521";
 const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
 const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
 const std::string TlsAgent::kServerDsa = "dsa";
 const std::string TlsAgent::kDelegatorEcdsa256 = "delegator_ecdsa256";
+const std::string TlsAgent::kDelegatorRsae2048 = "delegator_rsae2048";
 
 static const uint8_t kCannedTls13ServerHello[] = {
     0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
     0xf0, 0x5c, 0x70, 0x7a, 0xe0, 0xd1, 0x9b, 0x3e, 0x5a, 0x44, 0x6b,
     0xdf, 0xe5, 0xc2, 0x28, 0x64, 0xf7, 0x00, 0xc1, 0x9c, 0x08, 0x76,
     0x08, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24,
     0x00, 0x1d, 0x00, 0x20, 0xc2, 0xcf, 0x23, 0x17, 0x64, 0x23, 0x03,
     0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65, 0x24, 0xa1, 0x6c, 0xa9,
--- a/security/nss/gtests/ssl_gtest/tls_agent.h
+++ b/security/nss/gtests/ssl_gtest/tls_agent.h
@@ -72,16 +72,17 @@ class TlsAgent : public PollTarget {
   static const std::string kServerRsaDecrypt;
   static const std::string kServerEcdsa256;
   static const std::string kServerEcdsa384;
   static const std::string kServerEcdsa521;
   static const std::string kServerEcdhEcdsa;
   static const std::string kServerEcdhRsa;
   static const std::string kServerDsa;
   static const std::string kDelegatorEcdsa256;  // draft-ietf-tls-subcerts
+  static const std::string kDelegatorRsae2048;  // draft-ietf-tls-subcerts
 
   TlsAgent(const std::string& name, Role role, SSLProtocolVariant variant);
   virtual ~TlsAgent();
 
   void SetPeer(std::shared_ptr<TlsAgent>& peer) {
     adapter_->SetPeer(peer->adapter_);
   }
 
--- a/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/tls_subcerts_unittest.cc
@@ -11,17 +11,18 @@
 #include "ssl.h"
 
 #include "gtest_utils.h"
 #include "tls_agent.h"
 #include "tls_connect.h"
 
 namespace nss_test {
 
-const std::string kDelegatorId = TlsAgent::kDelegatorEcdsa256;
+const std::string kEcdsaDelegatorId = TlsAgent::kDelegatorEcdsa256;
+const std::string kRsaeDelegatorId = TlsAgent::kDelegatorRsae2048;
 const std::string kDCId = TlsAgent::kServerEcdsa256;
 const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256;
 const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds */;
 
 static void CheckPeerDelegCred(const std::shared_ptr<TlsAgent>& client,
                                bool expected, PRUint32 key_bits = 0) {
   EXPECT_EQ(expected, client->info().peerDelegCred);
   if (expected) {
@@ -32,88 +33,110 @@ static void CheckPeerDelegCred(const std
 // Attempt to configure a DC when either the DC or DC private key is missing.
 TEST_P(TlsConnectTls13, DCNotConfigured) {
   // Load and delegate the credential.
   ScopedSECKEYPublicKey pub;
   ScopedSECKEYPrivateKey priv;
   EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
 
   StackSECItem dc;
-  TlsAgent::DelegateCredential(kDelegatorId, pub, kDCScheme, kDCValidFor, now(),
-                               &dc);
+  TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor,
+                               now(), &dc);
 
   // Attempt to install the certificate and DC with a missing DC private key.
   EnsureTlsSetup();
   SSLExtraServerCertData extra_data_missing_dc_priv_key = {
       ssl_auth_null, nullptr, nullptr, nullptr, &dc, nullptr};
-  EXPECT_FALSE(server_->ConfigServerCert(kDelegatorId, true,
+  EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true,
                                          &extra_data_missing_dc_priv_key));
 
   // Attempt to install the certificate and with only the DC private key.
   EnsureTlsSetup();
   SSLExtraServerCertData extra_data_missing_dc = {
       ssl_auth_null, nullptr, nullptr, nullptr, nullptr, priv.get()};
-  EXPECT_FALSE(
-      server_->ConfigServerCert(kDelegatorId, true, &extra_data_missing_dc));
+  EXPECT_FALSE(server_->ConfigServerCert(kEcdsaDelegatorId, true,
+                                         &extra_data_missing_dc));
 }
 
 // Connected with ECDSA-P256.
 TEST_P(TlsConnectTls13, DCConnectEcdsaP256) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
   server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
                                   ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
                                   now());
 
   auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
       client_, ssl_delegated_credentials_xtn);
   Connect();
 
   EXPECT_TRUE(cfilter->captured());
   CheckPeerDelegCred(client_, true, 256);
   EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme);
 }
 
 // Connected with ECDSA-P521.
 TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
   server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
                                   ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
                                   now());
   client_->EnableDelegatedCredentials();
 
   auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
       client_, ssl_delegated_credentials_xtn);
   Connect();
 
   EXPECT_TRUE(cfilter->captured());
   CheckPeerDelegCred(client_, true, 521);
   EXPECT_EQ(ssl_sig_ecdsa_secp521r1_sha512, client_->info().signatureScheme);
 }
 
-// Connected with RSA-PSS, using an RSAE SPKI.
+// Connected with RSA-PSS, using an RSAE DC SPKI.
 TEST_P(TlsConnectTls13, DCConnectRsaPssRsae) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
   server_->AddDelegatedCredential(
       TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now());
 
   auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
       client_, ssl_delegated_credentials_xtn);
   Connect();
 
   EXPECT_TRUE(cfilter->captured());
   CheckPeerDelegCred(client_, true, 1024);
   EXPECT_EQ(ssl_sig_rsa_pss_rsae_sha256, client_->info().signatureScheme);
 }
 
+// Connected with RSA-PSS, using a RSAE Delegator SPKI.
+TEST_P(TlsConnectTls13, DCConnectRsaeDelegator) {
+  Reset(kRsaeDelegatorId);
+
+  static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_rsae_sha256,
+                                                ssl_sig_rsa_pss_pss_sha256};
+  client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
+  server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
+
+  client_->EnableDelegatedCredentials();
+  server_->AddDelegatedCredential(
+      TlsAgent::kServerRsaPss, ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now());
+
+  auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
+      client_, ssl_delegated_credentials_xtn);
+  Connect();
+
+  EXPECT_TRUE(cfilter->captured());
+  CheckPeerDelegCred(client_, true, 1024);
+  EXPECT_EQ(ssl_sig_rsa_pss_pss_sha256, client_->info().signatureScheme);
+}
+
 // Connected with RSA-PSS, using a PSS SPKI.
 TEST_P(TlsConnectTls13, DCConnectRsaPssPss) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
 
   // Need to enable PSS-PSS, which is not on by default.
   static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256,
                                                 ssl_sig_rsa_pss_pss_sha256};
   client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
   server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
 
   client_->EnableDelegatedCredentials();
@@ -167,34 +190,34 @@ static void GenerateWeakRsaKey(ScopedSEC
     break;
   }
   ADD_FAILURE() << "Unable to generate an RSA key: "
                 << PORT_ErrorToName(PORT_GetError());
 }
 
 // Fail to connect with a weak RSA key.
 TEST_P(TlsConnectTls13, DCWeakKey) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   EnsureTlsSetup();
 
   ScopedSECKEYPrivateKey dc_priv;
   ScopedSECKEYPublicKey dc_pub;
   GenerateWeakRsaKey(dc_priv, dc_pub);
   ASSERT_TRUE(dc_priv);
 
   // Construct a DC.
   StackSECItem dc;
-  TlsAgent::DelegateCredential(kDelegatorId, dc_pub,
+  TlsAgent::DelegateCredential(kEcdsaDelegatorId, dc_pub,
                                ssl_sig_rsa_pss_rsae_sha256, kDCValidFor, now(),
                                &dc);
 
   // Configure the DC on the server.
   SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
                                        nullptr,       &dc,     dc_priv.get()};
-  EXPECT_TRUE(server_->ConfigServerCert(kDelegatorId, true, &extra_data));
+  EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data));
 
   client_->EnableDelegatedCredentials();
 
   auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
       client_, ssl_delegated_credentials_xtn);
   ConnectExpectAlert(client_, kTlsAlertInsufficientSecurity);
 }
 
@@ -210,58 +233,58 @@ class ReplaceDCSigScheme : public TlsHan
     *output = input;
     output->Write(0, ssl_sig_ecdsa_secp384r1_sha384, 2);
     return CHANGE;
   }
 };
 
 // Aborted because of incorrect DC signature algorithm indication.
 TEST_P(TlsConnectTls13, DCAbortBadExpectedCertVerifyAlg) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
   server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
                                   ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
                                   now());
   auto filter = MakeTlsFilter<ReplaceDCSigScheme>(server_);
   filter->EnableDecryption();
   ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
   client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 // Aborted because of invalid DC signature.
 TEST_P(TlsConnectTls13, DCAbortBadSignature) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   EnsureTlsSetup();
   client_->EnableDelegatedCredentials();
 
   ScopedSECKEYPublicKey pub;
   ScopedSECKEYPrivateKey priv;
   EXPECT_TRUE(TlsAgent::LoadKeyPairFromCert(kDCId, &pub, &priv));
 
   StackSECItem dc;
-  TlsAgent::DelegateCredential(kDelegatorId, pub, kDCScheme, kDCValidFor, now(),
-                               &dc);
+  TlsAgent::DelegateCredential(kEcdsaDelegatorId, pub, kDCScheme, kDCValidFor,
+                               now(), &dc);
   ASSERT_TRUE(dc.data != nullptr);
 
   // Flip the first bit of the DC so that the signature is invalid.
   dc.data[0] ^= 0x01;
 
   SSLExtraServerCertData extra_data = {ssl_auth_null, nullptr, nullptr,
                                        nullptr,       &dc,     priv.get()};
-  EXPECT_TRUE(server_->ConfigServerCert(kDelegatorId, true, &extra_data));
+  EXPECT_TRUE(server_->ConfigServerCert(kEcdsaDelegatorId, true, &extra_data));
 
   ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
   client_->CheckErrorCode(SSL_ERROR_DC_BAD_SIGNATURE);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
 }
 
 // Aborted because of expired DC.
 TEST_P(TlsConnectTls13, DCAbortExpired) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
   client_->EnableDelegatedCredentials();
   // When the client checks the time, it will be at least one second after the
   // DC expired.
   AdvanceTime((static_cast<PRTime>(kDCValidFor) + 1) * PR_USEC_PER_SEC);
   ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
   client_->CheckErrorCode(SSL_ERROR_DC_EXPIRED);
   server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
@@ -273,43 +296,43 @@ TEST_P(TlsConnectTls13, DCAbortBadKeyUsa
   Reset(TlsAgent::kServerEcdsa256);
   client_->EnableDelegatedCredentials();
   server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
   ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
 }
 
 // Connected without DC because of no client indication.
 TEST_P(TlsConnectTls13, DCConnectNoClientSupport) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
 
   auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
       client_, ssl_delegated_credentials_xtn);
   Connect();
 
   EXPECT_FALSE(cfilter->captured());
   CheckPeerDelegCred(client_, false);
 }
 
 // Connected without DC because of no server DC.
 TEST_P(TlsConnectTls13, DCConnectNoServerSupport) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
 
   auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
       client_, ssl_delegated_credentials_xtn);
   Connect();
 
   EXPECT_TRUE(cfilter->captured());
   CheckPeerDelegCred(client_, false);
 }
 
 // Connected without DC because client doesn't support TLS 1.3.
 TEST_P(TlsConnectTls13, DCConnectClientNoTls13) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
   server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
 
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
 
@@ -319,17 +342,17 @@ TEST_P(TlsConnectTls13, DCConnectClientN
 
   // Should fallback to TLS 1.2 and not negotiate a DC.
   EXPECT_FALSE(cfilter->captured());
   CheckPeerDelegCred(client_, false);
 }
 
 // Connected without DC because server doesn't support TLS 1.3.
 TEST_P(TlsConnectTls13, DCConnectServerNoTls13) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
   server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
 
   client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_3);
   server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
                            SSL_LIBRARY_VERSION_TLS_1_2);
 
@@ -340,17 +363,17 @@ TEST_P(TlsConnectTls13, DCConnectServerN
   // Should fallback to TLS 1.2 and not negotiate a DC. The client will still
   // send the indication because it supports 1.3.
   EXPECT_TRUE(cfilter->captured());
   CheckPeerDelegCred(client_, false);
 }
 
 // Connected without DC because client doesn't support the signature scheme.
 TEST_P(TlsConnectTls13, DCConnectExpectedCertVerifyAlgNotSupported) {
-  Reset(kDelegatorId);
+  Reset(kEcdsaDelegatorId);
   client_->EnableDelegatedCredentials();
   static const SSLSignatureScheme kClientSchemes[] = {
       ssl_sig_ecdsa_secp256r1_sha256,
   };
   client_->SetSignatureSchemes(kClientSchemes, PR_ARRAY_SIZE(kClientSchemes));
 
   server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
                                   ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
@@ -366,17 +389,17 @@ TEST_P(TlsConnectTls13, DCConnectExpecte
 }
 
 class DCDelegation : public ::testing::Test {};
 
 TEST_F(DCDelegation, DCDelegations) {
   PRTime now = PR_Now();
   ScopedCERTCertificate cert;
   ScopedSECKEYPrivateKey priv;
-  ASSERT_TRUE(TlsAgent::LoadCertificate(kDelegatorId, &cert, &priv));
+  ASSERT_TRUE(TlsAgent::LoadCertificate(kEcdsaDelegatorId, &cert, &priv));
 
   ScopedSECKEYPublicKey pub_rsa;
   ScopedSECKEYPrivateKey priv_rsa;
   ASSERT_TRUE(
       TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerRsa, &pub_rsa, &priv_rsa));
 
   StackSECItem dc;
   EXPECT_EQ(SECFailure,
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -1600,16 +1600,78 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSes
                             maxout, pEncryptedPart, ulEncryptedPartLen);
     if (rv != SECSuccess) {
         return sftk_MapDecryptError(PORT_GetError());
     }
     *pulPartLen = (CK_ULONG)(outlen + padoutlen);
     return CKR_OK;
 }
 
+/* From ssl3con.c: Constant-time helper macro that copies the MSB of x to all
+ * other bits. */
+#define DUPLICATE_MSB_TO_ALL(x) ((unsigned int)((int)(x) >> (sizeof(int) * 8 - 1)))
+/* CK_RVToMask returns, in constant time, a mask value of
+ * all ones if rv == CKR_OK.  Otherwise it returns zero. */
+static unsigned int
+CK_RVToMask(CK_RV rv)
+{
+    unsigned int good;
+    /* rv ^ CKR_OK is zero iff rv == CKR_OK. Subtracting one results
+     * in the MSB being set to one iff it was zero before. */
+    good = rv ^ CKR_OK;
+    good--;
+    return DUPLICATE_MSB_TO_ALL(good);
+}
+/* Constant-time helper macro that selects l or r depending on all-1 or all-0
+ * mask m */
+#define CT_SEL(m, l, r) (((m) & (l)) | (~(m) & (r)))
+/* Constant-time helper macro that returns all-1s if x is not 0; and all-0s
+ * otherwise. */
+#define CT_NOT_ZERO(x) (DUPLICATE_MSB_TO_ALL(((x) | (0 - x))))
+
+/* sftk_CheckCBCPadding checks, in constant time, the padding validity and
+ * accordingly sets the pad length. */
+static CK_RV
+sftk_CheckCBCPadding(CK_BYTE_PTR pLastPart,
+                     unsigned int blockSize, unsigned int *outPadSize)
+{
+    PORT_Assert(outPadSize);
+
+    unsigned int padSize = (unsigned int)pLastPart[blockSize - 1];
+
+    /* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/
+    unsigned int goodPad = DUPLICATE_MSB_TO_ALL(~(blockSize - padSize));
+    /* padSize should not be 0 */
+    goodPad &= CT_NOT_ZERO(padSize);
+
+    unsigned int i;
+    for (i = 0; i < blockSize; i++) {
+        /* If i < padSize, set loopMask to all-1s and all-0s otherwise.*/
+        unsigned int loopMask = DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i));
+        /* Get the padding value (should be padSize) from buffer */
+        unsigned int padVal = pLastPart[blockSize - 1 - i];
+        /* Update goodPad only if i < padSize */
+        goodPad &= CT_SEL(loopMask, ~(padVal ^ padSize), goodPad);
+    }
+
+    /* If any of the final padding bytes had the wrong value, one or more
+     * of the lower eight bits of |goodPad| will be cleared. We AND the
+     * bottom 8 bits together and duplicate the result to all the bits. */
+    goodPad &= goodPad >> 4;
+    goodPad &= goodPad >> 2;
+    goodPad &= goodPad >> 1;
+    goodPad <<= sizeof(goodPad) * 8 - 1;
+    goodPad = DUPLICATE_MSB_TO_ALL(goodPad);
+
+    /* Set outPadSize to padSize or 0 */
+    *outPadSize = CT_SEL(goodPad, padSize, 0);
+    /* Return OK if the pad is valid */
+    return CT_SEL(goodPad, CKR_OK, CKR_ENCRYPTED_DATA_INVALID);
+}
+
 /* NSC_DecryptFinal finishes a multiple-part decryption operation. */
 CK_RV
 NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
                  CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen)
 {
     SFTKSession *session;
     SFTKSessionContext *context;
     unsigned int outlen;
@@ -1638,34 +1700,20 @@ NSC_DecryptFinal(CK_SESSION_HANDLE hSess
         if (context->padDataLength != 0) {
             /* this assumes that pLastPart is big enough to hold the *whole*
              * buffer!!! */
             rv = (*context->update)(context->cipherInfo, pLastPart, &outlen,
                                     maxout, context->padBuf, context->blockSize);
             if (rv != SECSuccess) {
                 crv = sftk_MapDecryptError(PORT_GetError());
             } else {
-                unsigned int padSize =
-                    (unsigned int)pLastPart[context->blockSize - 1];
-                if ((padSize > context->blockSize) || (padSize == 0)) {
-                    crv = CKR_ENCRYPTED_DATA_INVALID;
-                } else {
-                    unsigned int i;
-                    unsigned int badPadding = 0; /* used as a boolean */
-                    for (i = 0; i < padSize; i++) {
-                        badPadding |=
-                            (unsigned int)pLastPart[context->blockSize - 1 - i] ^
-                            padSize;
-                    }
-                    if (badPadding) {
-                        crv = CKR_ENCRYPTED_DATA_INVALID;
-                    } else {
-                        *pulLastPartLen = outlen - padSize;
-                    }
-                }
+                unsigned int padSize = 0;
+                crv = sftk_CheckCBCPadding(&pLastPart[outlen - context->blockSize], context->blockSize, &padSize);
+                /* Update pulLastPartLen, in constant time, if crv is OK */
+                *pulLastPartLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulLastPartLen);
             }
         }
     }
 
     sftk_TerminateOp(session, SFTK_DECRYPT, context);
 finish:
     sftk_FreeSession(session);
     return crv;
@@ -1688,17 +1736,17 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
     CHECK_FORK();
 
     /* make sure we're legal */
     crv = sftk_GetContext(hSession, &context, SFTK_DECRYPT, PR_FALSE, &session);
     if (crv != CKR_OK)
         return crv;
 
     if (!pData) {
-        outlen = ulEncryptedDataLen + context->blockSize;
+        *pulDataLen = (CK_ULONG)(ulEncryptedDataLen + context->blockSize);
         goto done;
     }
 
     if (context->doPad && context->multi) {
         CK_ULONG updateLen = maxoutlen;
         CK_ULONG finalLen;
         /* padding is fairly complicated, have the update and final
          * code deal with it */
@@ -1716,39 +1764,29 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
         }
         return crv == CKR_OK ? crv2 : crv;
     }
 
     rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen,
                             pEncryptedData, ulEncryptedDataLen);
     /* XXX need to do MUCH better error mapping than this. */
     crv = (rv == SECSuccess) ? CKR_OK : sftk_MapDecryptError(PORT_GetError());
-    if (rv == SECSuccess && context->doPad) {
-        unsigned int padding = pData[outlen - 1];
-        if (padding > context->blockSize || !padding) {
-            crv = CKR_ENCRYPTED_DATA_INVALID;
+    if (rv == SECSuccess) {
+        if (context->doPad) {
+            unsigned int padSize = 0;
+            crv = sftk_CheckCBCPadding(&pData[outlen - context->blockSize], context->blockSize, &padSize);
+            /* Update pulDataLen, in constant time, if crv is OK */
+            *pulDataLen = CT_SEL(CK_RVToMask(crv), outlen - padSize, *pulDataLen);
         } else {
-            unsigned int i;
-            unsigned int badPadding = 0; /* used as a boolean */
-            for (i = 0; i < padding; i++) {
-                badPadding |= (unsigned int)pData[outlen - 1 - i] ^ padding;
-            }
-            if (badPadding) {
-                crv = CKR_ENCRYPTED_DATA_INVALID;
-            } else {
-                outlen -= padding;
-            }
+            *pulDataLen = (CK_ULONG)outlen;
         }
     }
     sftk_TerminateOp(session, SFTK_DECRYPT, context);
 done:
     sftk_FreeSession(session);
-    if (crv == CKR_OK) {
-        *pulDataLen = (CK_ULONG)outlen;
-    }
     return crv;
 }
 
 /*
  ************** Crypto Functions:     Digest (HASH)  ************************
  */
 
 /* NSC_DigestInit initializes a message-digesting operation. */
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -4250,17 +4250,17 @@ ssl_SignatureSchemeMatchesSpkiOid(SSLSig
         case ssl_sig_ed448:
             break;
     }
     PORT_Assert(0);
     return PR_FALSE;
 }
 
 /* Validate that the signature scheme works for the given key type. */
-static PRBool
+PRBool
 ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
                          PRBool isTls13)
 {
     if (!ssl_IsSupportedSignatureScheme(scheme)) {
         return PR_FALSE;
     }
     if (!ssl_SignatureSchemeMatchesSpkiOid(scheme, spkiOid)) {
         return PR_FALSE;
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -1732,16 +1732,18 @@ SECStatus ssl_PickSignatureScheme(sslSoc
 SECOidTag ssl3_HashTypeToOID(SSLHashType hashType);
 SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme);
 SSLAuthType ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme);
 
 SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes);
 SECStatus ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
                                  SSLContentType contentType, sslBuffer *wrBuf,
                                  PRBool *needsLength);
+PRBool ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
+                                PRBool isTls13);
 
 /* Pull in DTLS functions */
 #include "dtlscon.h"
 
 /* Pull in TLS 1.3 functions */
 #include "tls13con.h"
 #include "dtls13con.h"
 
--- a/security/nss/lib/ssl/tls13subcerts.c
+++ b/security/nss/lib/ssl/tls13subcerts.c
@@ -698,16 +698,28 @@ SSLExp_DelegateCredential(const CERTCert
         goto loser;
     }
 
     rv = ssl_SignatureSchemeFromSpki(&cert->subjectPublicKeyInfo,
                                      PR_TRUE /* isTls13 */, &dc->alg);
     if (rv != SECSuccess) {
         goto loser;
     }
+
+    if (dc->alg == ssl_sig_none) {
+        SECOidTag spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm);
+        /* If the Cert SPKI contained an AlgorithmIdentifier of "rsaEncryption", set a
+         * default rsa_pss_rsae_sha256 scheme. */
+        if (spkiOid == SEC_OID_PKCS1_RSA_ENCRYPTION) {
+            SSLSignatureScheme scheme = ssl_sig_rsa_pss_rsae_sha256;
+            if (ssl_SignatureSchemeValid(scheme, spkiOid, PR_TRUE /* isTls13 */)) {
+                dc->alg = scheme;
+            }
+        }
+    }
     PORT_Assert(dc->alg != ssl_sig_none);
 
     rv = tls13_AppendCredentialParams(&dcBuf, dc);
     if (rv != SECSuccess) {
         goto loser;
     }
 
     /* Hash signature message. */
--- a/security/nss/tests/common/certsetup.sh
+++ b/security/nss/tests/common/certsetup.sh
@@ -46,16 +46,21 @@ make_cert() {
     rsapss_chain) type_args=(-g 1024);sign=(-c rsa_pss_ca);type=rsa;;
     rsa_ca_rsapss_chain) type_args=(-g 1024 --pss-sign);sign=(-c rsa_ca);type=rsa;;
     ecdh_rsa) type_args=(-q nistp256);sign=(-c rsa_ca);type=ec ;;
     delegator_p256)
         touch empty.txt
         type_args=(-q nistp256 --extGeneric 1.3.6.1.4.1.44363.44:not-critical:empty.txt)
         type=ec
         ;;
+    delegator_rsae2048)
+        touch empty.txt
+        type_args=(-g 2048 --extGeneric 1.3.6.1.4.1.44363.44:not-critical:empty.txt)
+        type=rsa
+        ;;
   esac
   msg="create certificate: $@"
   shift 2
   counter=$(($counter + 1))
   cmd=(${BINDIR}/certutil -S \
     -z "$R_NOISE_FILE" -d "$PROFILEDIR" \
     -n $name -s "CN=$name" -t "$trust" "${sign[@]}" -m "$counter" \
     -w -2 -v 120 -k "$type" "${type_args[@]}" "${sighash[@]}" -1 -2)
--- a/security/nss/tests/ssl_gtests/ssl_gtests.sh
+++ b/security/nss/tests/ssl_gtests/ssl_gtests.sh
@@ -53,16 +53,17 @@ ssl_gtest_certs() {
   make_cert rsa_ca rsa_ca ca
   make_cert rsa_chain rsa_chain sign
   make_cert rsa_pss_ca rsapss_ca ca
   make_cert rsa_pss_chain rsapss_chain sign
   make_cert rsa_ca_rsa_pss_chain rsa_ca_rsapss_chain sign
   make_cert ecdh_rsa ecdh_rsa kex
   make_cert dsa dsa sign
   make_cert delegator_ecdsa256 delegator_p256 sign
+  make_cert delegator_rsae2048 delegator_rsae2048 sign
 }
 
 ############################## ssl_gtest_init ##########################
 # local shell function to initialize this script
 ########################################################################
 ssl_gtest_init()
 {
   SCRIPTNAME=ssl_gtest.sh      # sourced - $0 would point to all.sh