mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-28 03:17:31 +09:00
414 lines
16 KiB
C++
414 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 */
|