mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
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 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
3812c7138b
commit
00dafac3ef
@ -1 +1 @@
|
||||
NSS_3_47_BETA3
|
||||
NSS_3_47_BETA4
|
@ -10,4 +10,3 @@
|
||||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
@ -9,6 +9,7 @@ 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 \
|
||||
|
415
security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
Normal file
415
security/nss/gtests/pk11_gtest/pk11_aeskeywrappad_unittest.cc
Normal file
@ -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 */
|
@ -41,6 +41,17 @@ class Pkcs11CbcPadTest : public ::testing::TestWithParam<CK_MECHANISM_TYPE> {
|
||||
}
|
||||
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));
|
||||
@ -340,6 +351,139 @@ TEST_P(Pkcs11CbcPadTest, ContextFailDecryptInvalidBlockSize) {
|
||||
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));
|
||||
|
@ -14,6 +14,7 @@
|
||||
'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',
|
||||
|
@ -48,6 +48,7 @@ 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,
|
||||
|
@ -77,6 +77,7 @@ class TlsAgent : public PollTarget {
|
||||
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();
|
||||
|
@ -16,7 +16,8 @@
|
||||
|
||||
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 */;
|
||||
@ -37,27 +38,27 @@ TEST_P(TlsConnectTls13, DCNotConfigured) {
|
||||
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,
|
||||
@ -74,7 +75,7 @@ TEST_P(TlsConnectTls13, DCConnectEcdsaP256) {
|
||||
|
||||
// Connected with ECDSA-P521.
|
||||
TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
|
||||
Reset(kDelegatorId);
|
||||
Reset(kEcdsaDelegatorId);
|
||||
client_->EnableDelegatedCredentials();
|
||||
server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
|
||||
ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
|
||||
@ -90,9 +91,9 @@ TEST_P(TlsConnectTls13, DCConnectEcdsaP521) {
|
||||
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());
|
||||
@ -106,9 +107,31 @@ TEST_P(TlsConnectTls13, DCConnectRsaPssRsae) {
|
||||
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,
|
||||
@ -172,7 +195,7 @@ static void GenerateWeakRsaKey(ScopedSECKEYPrivateKey& priv,
|
||||
|
||||
// Fail to connect with a weak RSA key.
|
||||
TEST_P(TlsConnectTls13, DCWeakKey) {
|
||||
Reset(kDelegatorId);
|
||||
Reset(kEcdsaDelegatorId);
|
||||
EnsureTlsSetup();
|
||||
|
||||
ScopedSECKEYPrivateKey dc_priv;
|
||||
@ -182,14 +205,14 @@ TEST_P(TlsConnectTls13, DCWeakKey) {
|
||||
|
||||
// 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();
|
||||
|
||||
@ -215,7 +238,7 @@ class ReplaceDCSigScheme : public TlsHandshakeFilter {
|
||||
|
||||
// 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,
|
||||
@ -229,7 +252,7 @@ TEST_P(TlsConnectTls13, DCAbortBadExpectedCertVerifyAlg) {
|
||||
|
||||
// Aborted because of invalid DC signature.
|
||||
TEST_P(TlsConnectTls13, DCAbortBadSignature) {
|
||||
Reset(kDelegatorId);
|
||||
Reset(kEcdsaDelegatorId);
|
||||
EnsureTlsSetup();
|
||||
client_->EnableDelegatedCredentials();
|
||||
|
||||
@ -238,8 +261,8 @@ TEST_P(TlsConnectTls13, DCAbortBadSignature) {
|
||||
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.
|
||||
@ -247,7 +270,7 @@ TEST_P(TlsConnectTls13, DCAbortBadSignature) {
|
||||
|
||||
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);
|
||||
@ -256,7 +279,7 @@ TEST_P(TlsConnectTls13, DCAbortBadSignature) {
|
||||
|
||||
// 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
|
||||
@ -278,7 +301,7 @@ TEST_P(TlsConnectTls13, DCAbortBadKeyUsage) {
|
||||
|
||||
// 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>(
|
||||
@ -291,7 +314,7 @@ TEST_P(TlsConnectTls13, DCConnectNoClientSupport) {
|
||||
|
||||
// Connected without DC because of no server DC.
|
||||
TEST_P(TlsConnectTls13, DCConnectNoServerSupport) {
|
||||
Reset(kDelegatorId);
|
||||
Reset(kEcdsaDelegatorId);
|
||||
client_->EnableDelegatedCredentials();
|
||||
|
||||
auto cfilter = MakeTlsFilter<TlsExtensionCapture>(
|
||||
@ -304,7 +327,7 @@ TEST_P(TlsConnectTls13, DCConnectNoServerSupport) {
|
||||
|
||||
// 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());
|
||||
|
||||
@ -324,7 +347,7 @@ TEST_P(TlsConnectTls13, DCConnectClientNoTls13) {
|
||||
|
||||
// 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());
|
||||
|
||||
@ -345,7 +368,7 @@ TEST_P(TlsConnectTls13, DCConnectServerNoTls13) {
|
||||
|
||||
// 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,
|
||||
@ -371,7 +394,7 @@ 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;
|
||||
|
@ -1605,6 +1605,68 @@ NSC_DecryptUpdate(CK_SESSION_HANDLE hSession,
|
||||
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,
|
||||
@ -1643,24 +1705,10 @@ NSC_DecryptFinal(CK_SESSION_HANDLE hSession,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1693,7 +1741,7 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
|
||||
return crv;
|
||||
|
||||
if (!pData) {
|
||||
outlen = ulEncryptedDataLen + context->blockSize;
|
||||
*pulDataLen = (CK_ULONG)(ulEncryptedDataLen + context->blockSize);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -1721,29 +1769,19 @@ NSC_Decrypt(CK_SESSION_HANDLE hSession,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -4255,7 +4255,7 @@ ssl_SignatureSchemeMatchesSpkiOid(SSLSignatureScheme scheme, SECOidTag spkiOid)
|
||||
}
|
||||
|
||||
/* Validate that the signature scheme works for the given key type. */
|
||||
static PRBool
|
||||
PRBool
|
||||
ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
|
||||
PRBool isTls13)
|
||||
{
|
||||
|
@ -1737,6 +1737,8 @@ 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"
|
||||
|
@ -703,6 +703,18 @@ SSLExp_DelegateCredential(const CERTCertificate *cert,
|
||||
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);
|
||||
|
@ -51,6 +51,11 @@ make_cert() {
|
||||
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
|
||||
|
@ -58,6 +58,7 @@ ssl_gtest_certs() {
|
||||
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 ##########################
|
||||
|
Loading…
Reference in New Issue
Block a user