summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/softoken_gtest
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
commitf4a12fc67689a830e9da1c87fd11afe5bc09deb3 (patch)
tree211ae0cd022a6c11b0026ecc7761a550c584583c /security/nss/gtests/softoken_gtest
parentf7d30133221896638f7bf4f66c504255c4b14f48 (diff)
downloadUXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.gz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.lz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.xz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.zip
Issue #1338 - Part 2: Update NSS to 3.48-RTM
Diffstat (limited to 'security/nss/gtests/softoken_gtest')
-rw-r--r--security/nss/gtests/softoken_gtest/manifest.mn10
-rw-r--r--security/nss/gtests/softoken_gtest/softoken_gtest.cc275
-rw-r--r--security/nss/gtests/softoken_gtest/softoken_gtest.gyp8
-rw-r--r--security/nss/gtests/softoken_gtest/softoken_nssckbi_testlib_gtest.cc124
4 files changed, 329 insertions, 88 deletions
diff --git a/security/nss/gtests/softoken_gtest/manifest.mn b/security/nss/gtests/softoken_gtest/manifest.mn
index 4b34c099f..8a533c56b 100644
--- a/security/nss/gtests/softoken_gtest/manifest.mn
+++ b/security/nss/gtests/softoken_gtest/manifest.mn
@@ -6,12 +6,22 @@ CORE_DEPTH = ../..
DEPTH = ../..
MODULE = nss
+DEFINES += -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" -DDLL_PREFIX=\"$(DLL_PREFIX)\"
+
+include $(CORE_DEPTH)/coreconf/arch.mk
+ifneq ($(OS_ARCH),WINNT)
+DB_TESTS = \
+ softoken_nssckbi_testlib_gtest.cc
+endif
+
CPPSRCS = \
softoken_gtest.cc \
+ $(DB_TESTS) \
$(NULL)
INCLUDES += \
-I$(CORE_DEPTH)/gtests/google_test/gtest/include \
+ -I$(CORE_DEPTH)/gtests/common \
-I$(CORE_DEPTH)/cpputil \
$(NULL)
diff --git a/security/nss/gtests/softoken_gtest/softoken_gtest.cc b/security/nss/gtests/softoken_gtest/softoken_gtest.cc
index 5e2a497b8..17949800a 100644
--- a/security/nss/gtests/softoken_gtest/softoken_gtest.cc
+++ b/security/nss/gtests/softoken_gtest/softoken_gtest.cc
@@ -1,104 +1,20 @@
-#include <cstdlib>
-#if defined(_WIN32)
-#include <windows.h>
-#include <codecvt>
-#endif
-
#include "cert.h"
#include "certdb.h"
#include "nspr.h"
#include "nss.h"
#include "pk11pub.h"
+#include "secmod.h"
#include "secerr.h"
#include "nss_scoped_ptrs.h"
+#include "util.h"
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
+#include <fstream>
namespace nss_test {
-// Given a prefix, attempts to create a unique directory that the user can do
-// work in without impacting other tests. For example, if given the prefix
-// "scratch", a directory like "scratch05c17b25" will be created in the current
-// working directory (or the location specified by NSS_GTEST_WORKDIR, if
-// defined).
-// Upon destruction, the implementation will attempt to delete the directory.
-// However, no attempt is made to first remove files in the directory - the
-// user is responsible for this. If the directory is not empty, deleting it will
-// fail.
-// Statistically, it is technically possible to fail to create a unique
-// directory name, but this is extremely unlikely given the expected workload of
-// this implementation.
-class ScopedUniqueDirectory {
- public:
- explicit ScopedUniqueDirectory(const std::string &prefix);
-
- // NB: the directory must be empty upon destruction
- ~ScopedUniqueDirectory() { assert(rmdir(mPath.c_str()) == 0); }
-
- const std::string &GetPath() { return mPath; }
- const std::string &GetUTF8Path() { return mUTF8Path; }
-
- private:
- static const int RETRY_LIMIT = 5;
- static void GenerateRandomName(/*in/out*/ std::string &prefix);
- static bool TryMakingDirectory(/*in/out*/ std::string &prefix);
-
- std::string mPath;
- std::string mUTF8Path;
-};
-
-ScopedUniqueDirectory::ScopedUniqueDirectory(const std::string &prefix) {
- std::string path;
- const char *workingDirectory = PR_GetEnvSecure("NSS_GTEST_WORKDIR");
- if (workingDirectory) {
- path.assign(workingDirectory);
- }
- path.append(prefix);
- for (int i = 0; i < RETRY_LIMIT; i++) {
- std::string pathCopy(path);
- // TryMakingDirectory will modify its input. If it fails, we want to throw
- // away the modified result.
- if (TryMakingDirectory(pathCopy)) {
- mPath.assign(pathCopy);
- break;
- }
- }
- assert(mPath.length() > 0);
-#if defined(_WIN32)
- // sqldb always uses UTF-8 regardless of the current system locale.
- DWORD len =
- MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), nullptr, 0);
- std::vector<wchar_t> buf(len, L'\0');
- MultiByteToWideChar(CP_ACP, 0, mPath.data(), mPath.size(), buf.data(),
- buf.size());
- std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
- mUTF8Path = converter.to_bytes(std::wstring(buf.begin(), buf.end()));
-#else
- mUTF8Path = mPath;
-#endif
-}
-
-void ScopedUniqueDirectory::GenerateRandomName(std::string &prefix) {
- std::stringstream ss;
- ss << prefix;
- // RAND_MAX is at least 32767.
- ss << std::setfill('0') << std::setw(4) << std::hex << rand() << rand();
- // This will overwrite the value of prefix. This is a little inefficient, but
- // at least it makes the code simple.
- ss >> prefix;
-}
-
-bool ScopedUniqueDirectory::TryMakingDirectory(std::string &prefix) {
- GenerateRandomName(prefix);
-#if defined(_WIN32)
- return _mkdir(prefix.c_str()) == 0;
-#else
- return mkdir(prefix.c_str(), 0777) == 0;
-#endif
-}
-
class SoftokenTest : public ::testing::Test {
protected:
SoftokenTest() : mNSSDBDir("SoftokenTest.d-") {}
@@ -205,6 +121,27 @@ TEST_F(SoftokenTest, CreateObjectChangePassword) {
EXPECT_EQ(nullptr, obj);
}
+// The size limit for a password is 500 characters as defined in pkcs11i.h
+TEST_F(SoftokenTest, CreateObjectChangeToBigPassword) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+ ASSERT_TRUE(slot);
+ EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
+ EXPECT_EQ(
+ SECSuccess,
+ PK11_ChangePW(slot.get(), "",
+ "rUIFIFr2bxKnbJbitsfkyqttpk6vCJzlYMNxcxXcaN37gSZKbLk763X7iR"
+ "yeVNWZHQ02lSF69HYjzTyPW3318ZD0DBFMMbALZ8ZPZP73CIo5uIQlaowV"
+ "IbP8eOhRYtGUqoLGlcIFNEYogV8Q3GN58VeBMs0KxrIOvPQ9s8SnYYkqvt"
+ "zzgntmAvCgvk64x6eQf0okHwegd5wi6m0WVJytEepWXkP9J629FSa5kNT8"
+ "FvL3jvslkiImzTNuTvl32fQDXXMSc8vVk5Q3mH7trMZM0VDdwHWYERjHbz"
+ "kGxFgp0VhediHx7p9kkz6H6ac4et9sW4UkTnN7xhYc1Zr17wRSk2heQtcX"
+ "oZJGwuzhiKm8A8wkuVxms6zO56P4JORIk8oaUW6lyNTLo2kWWnTA"));
+ EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
+ ScopedPK11GenericObject obj(PK11_CreateGenericObject(
+ slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
+ EXPECT_EQ(nullptr, obj);
+}
+
TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
ASSERT_TRUE(slot);
@@ -221,6 +158,76 @@ TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
EXPECT_NE(nullptr, obj);
}
+// We should be able to read CRLF, LF and CR.
+// During the Initialization of the NSS Database, is called a function to load
+// PKCS11 modules defined in pkcs11.txt. This file is read to get the
+// specifications, parse them and load the modules. Here we are ensuring that
+// the parsing will work correctly, independent of the breaking line format of
+// pkcs11.txt file, which could vary depending where it was created.
+// If the parsing is not well interpreted, the database cannot initialize.
+TEST_F(SoftokenTest, CreateObjectReadBreakLine) {
+ const std::string path = mNSSDBDir.GetPath();
+ const std::string dbname_in = path + "/pkcs11.txt";
+ const std::string dbname_out_cr = path + "/pkcs11_cr.txt";
+ const std::string dbname_out_crlf = path + "/pkcs11_crlf.txt";
+ const std::string dbname_out_lf = path + "/pkcs11_lf.txt";
+
+ std::ifstream in(dbname_in);
+ ASSERT_TRUE(in);
+ std::ofstream out_cr(dbname_out_cr);
+ ASSERT_TRUE(out_cr);
+ std::ofstream out_crlf(dbname_out_crlf);
+ ASSERT_TRUE(out_crlf);
+ std::ofstream out_lf(dbname_out_lf);
+ ASSERT_TRUE(out_lf);
+
+ // Database should be correctly initialized by Setup()
+ ASSERT_TRUE(NSS_IsInitialized());
+ ASSERT_EQ(SECSuccess, NSS_Shutdown());
+
+ // Prepare the file formats with CR, CRLF and LF
+ for (std::string line; getline(in, line);) {
+ out_cr << line << "\r";
+ out_crlf << line << "\r\n";
+ out_lf << line << "\n";
+ }
+ in.close();
+ out_cr.close();
+ out_crlf.close();
+ out_lf.close();
+
+ // Change the pkcs11.txt to CR format.
+ ASSERT_TRUE(!remove(dbname_in.c_str()));
+ ASSERT_TRUE(!rename(dbname_out_cr.c_str(), dbname_in.c_str()));
+
+ // Try to initialize with CR format.
+ std::string nssInitArg("sql:");
+ nssInitArg.append(mNSSDBDir.GetUTF8Path());
+ ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
+ NSS_INIT_NOROOTINIT));
+ ASSERT_TRUE(NSS_IsInitialized());
+ ASSERT_EQ(SECSuccess, NSS_Shutdown());
+
+ // Change the pkcs11.txt to CRLF format.
+ ASSERT_TRUE(!remove(dbname_in.c_str()));
+ ASSERT_TRUE(!rename(dbname_out_crlf.c_str(), dbname_in.c_str()));
+
+ // Try to initialize with CRLF format.
+ ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
+ NSS_INIT_NOROOTINIT));
+ ASSERT_TRUE(NSS_IsInitialized());
+ ASSERT_EQ(SECSuccess, NSS_Shutdown());
+
+ // Change the pkcs11.txt to LF format.
+ ASSERT_TRUE(!remove(dbname_in.c_str()));
+ ASSERT_TRUE(!rename(dbname_out_lf.c_str(), dbname_in.c_str()));
+
+ // Try to initialize with LF format.
+ ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
+ NSS_INIT_NOROOTINIT));
+ ASSERT_TRUE(NSS_IsInitialized());
+}
+
class SoftokenNonAsciiTest : public SoftokenTest {
protected:
SoftokenNonAsciiTest() : SoftokenTest("SoftokenTest.\xF7-") {}
@@ -351,6 +358,100 @@ TEST_F(SoftokenNoDBTest, NeedUserInitNoDB) {
ASSERT_EQ(SECSuccess, NSS_Shutdown());
}
+#ifndef NSS_FIPS_DISABLED
+
+class SoftokenFipsTest : public SoftokenTest {
+ protected:
+ SoftokenFipsTest() : SoftokenTest("SoftokenFipsTest.d-") {}
+
+ virtual void SetUp() {
+ SoftokenTest::SetUp();
+
+ // Turn on FIPS mode (code borrowed from FipsMode in modutil/pk11.c)
+ char *internal_name;
+ ASSERT_FALSE(PK11_IsFIPS());
+ internal_name = PR_smprintf("%s", SECMOD_GetInternalModule()->commonName);
+ ASSERT_EQ(SECSuccess, SECMOD_DeleteInternalModule(internal_name));
+ PR_smprintf_free(internal_name);
+ ASSERT_TRUE(PK11_IsFIPS());
+ }
+};
+
+const std::vector<std::string> kFipsPasswordCases[] = {
+ // FIPS level1 -> level1 -> level1
+ {"", "", ""},
+ // FIPS level1 -> level1 -> level2
+ {"", "", "strong-_123"},
+ // FIXME: this should work: FIPS level1 -> level2 -> level2
+ // {"", "strong-_123", "strong-_456"},
+ // FIPS level2 -> level2 -> level2
+ {"strong-_123", "strong-_456", "strong-_123"}};
+
+const std::vector<std::string> kFipsPasswordBadCases[] = {
+ // FIPS level1 -> level2 -> level1
+ {"", "strong-_123", ""},
+ // FIPS level2 -> level1 -> level1
+ {"strong-_123", ""},
+ // FIPS level2 -> level2 -> level1
+ {"strong-_123", "strong-_456", ""},
+ // initialize with a weak password
+ {"weak"},
+ // FIPS level1 -> weak password
+ {"", "weak"},
+ // FIPS level2 -> weak password
+ {"strong-_123", "weak"}};
+
+class SoftokenFipsPasswordTest
+ : public SoftokenFipsTest,
+ public ::testing::WithParamInterface<std::vector<std::string>> {};
+
+class SoftokenFipsBadPasswordTest
+ : public SoftokenFipsTest,
+ public ::testing::WithParamInterface<std::vector<std::string>> {};
+
+TEST_P(SoftokenFipsPasswordTest, SetPassword) {
+ const std::vector<std::string> &passwords = GetParam();
+ ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+ ASSERT_TRUE(slot);
+
+ auto it = passwords.begin();
+ auto prev_it = it;
+ EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, (*it).c_str()));
+ for (it++; it != passwords.end(); it++, prev_it++) {
+ EXPECT_EQ(SECSuccess,
+ PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str()));
+ }
+}
+
+TEST_P(SoftokenFipsBadPasswordTest, SetBadPassword) {
+ const std::vector<std::string> &passwords = GetParam();
+ ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+ ASSERT_TRUE(slot);
+
+ auto it = passwords.begin();
+ auto prev_it = it;
+ SECStatus rv = PK11_InitPin(slot.get(), nullptr, (*it).c_str());
+ if (it + 1 == passwords.end())
+ EXPECT_EQ(SECFailure, rv);
+ else
+ EXPECT_EQ(SECSuccess, rv);
+ for (it++; it != passwords.end(); it++, prev_it++) {
+ rv = PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str());
+ if (it + 1 == passwords.end())
+ EXPECT_EQ(SECFailure, rv);
+ else
+ EXPECT_EQ(SECSuccess, rv);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(FipsPasswordCases, SoftokenFipsPasswordTest,
+ ::testing::ValuesIn(kFipsPasswordCases));
+
+INSTANTIATE_TEST_CASE_P(BadFipsPasswordCases, SoftokenFipsBadPasswordTest,
+ ::testing::ValuesIn(kFipsPasswordBadCases));
+
+#endif
+
} // namespace nss_test
int main(int argc, char **argv) {
diff --git a/security/nss/gtests/softoken_gtest/softoken_gtest.gyp b/security/nss/gtests/softoken_gtest/softoken_gtest.gyp
index cff0ea414..3d9b8dba9 100644
--- a/security/nss/gtests/softoken_gtest/softoken_gtest.gyp
+++ b/security/nss/gtests/softoken_gtest/softoken_gtest.gyp
@@ -12,6 +12,7 @@
'type': 'executable',
'sources': [
'softoken_gtest.cc',
+ 'softoken_nssckbi_testlib_gtest.cc',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
@@ -19,7 +20,7 @@
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
],
'conditions': [
- [ 'test_build==1', {
+ [ 'static_libs==1', {
'dependencies': [
'<(DEPTH)/lib/nss/nss.gyp:nss_static',
'<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
@@ -30,6 +31,7 @@
'<(DEPTH)/lib/dev/dev.gyp:nssdev',
'<(DEPTH)/lib/pki/pki.gyp:nsspki',
'<(DEPTH)/lib/ssl/ssl.gyp:ssl',
+ '<(DEPTH)/lib/libpkix/libpkix.gyp:libpkix',
],
}, {
'dependencies': [
@@ -43,6 +45,10 @@
'target_defaults': {
'include_dirs': [
'../../lib/util'
+ ],
+ 'defines': [
+ 'DLL_PREFIX=\"<(dll_prefix)\"',
+ 'DLL_SUFFIX=\"<(dll_suffix)\"'
]
},
'variables': {
diff --git a/security/nss/gtests/softoken_gtest/softoken_nssckbi_testlib_gtest.cc b/security/nss/gtests/softoken_gtest/softoken_nssckbi_testlib_gtest.cc
new file mode 100644
index 000000000..e7d6bc28b
--- /dev/null
+++ b/security/nss/gtests/softoken_gtest/softoken_nssckbi_testlib_gtest.cc
@@ -0,0 +1,124 @@
+#include "cert.h"
+#include "certdb.h"
+#include "nspr.h"
+#include "nss.h"
+#include "pk11pub.h"
+#include "secerr.h"
+
+#include "nss_scoped_ptrs.h"
+#include "util.h"
+
+#define GTEST_HAS_RTTI 0
+#include "gtest/gtest.h"
+
+namespace nss_test {
+
+class SoftokenBuiltinsTest : public ::testing::Test {
+ protected:
+ SoftokenBuiltinsTest() : nss_db_dir_("SoftokenBuiltinsTest.d-") {}
+ SoftokenBuiltinsTest(const std::string &prefix) : nss_db_dir_(prefix) {}
+
+ virtual void SetUp() {
+ std::string nss_init_arg("sql:");
+ nss_init_arg.append(nss_db_dir_.GetUTF8Path());
+ ASSERT_EQ(SECSuccess, NSS_Initialize(nss_init_arg.c_str(), "", "",
+ SECMOD_DB, NSS_INIT_NOROOTINIT));
+ }
+
+ virtual void TearDown() {
+ ASSERT_EQ(SECSuccess, NSS_Shutdown());
+ const std::string &nss_db_dir_path = nss_db_dir_.GetPath();
+ ASSERT_EQ(0, unlink((nss_db_dir_path + "/cert9.db").c_str()));
+ ASSERT_EQ(0, unlink((nss_db_dir_path + "/key4.db").c_str()));
+ ASSERT_EQ(0, unlink((nss_db_dir_path + "/pkcs11.txt").c_str()));
+ }
+
+ virtual void LoadModule() {
+ ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+ ASSERT_TRUE(slot);
+ EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
+ SECStatus result = SECMOD_AddNewModule(
+ "Builtins-testlib", DLL_PREFIX "nssckbi-testlib." DLL_SUFFIX, 0, 0);
+ ASSERT_EQ(result, SECSuccess);
+ }
+
+ ScopedUniqueDirectory nss_db_dir_;
+};
+
+// The next tests in this class are used to test the Distrust Fields.
+// More details about these fields in lib/ckfw/builtins/README.
+TEST_F(SoftokenBuiltinsTest, CheckNoDistrustFields) {
+ const char *kCertNickname =
+ "Builtin Object Token:Distrust Fields Test - no_distrust";
+ LoadModule();
+
+ CERTCertDBHandle *cert_handle = CERT_GetDefaultCertDB();
+ ASSERT_TRUE(cert_handle);
+ ScopedCERTCertificate cert(
+ CERT_FindCertByNickname(cert_handle, kCertNickname));
+ ASSERT_TRUE(cert);
+
+ EXPECT_EQ(PR_FALSE,
+ PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
+ CKA_NSS_SERVER_DISTRUST_AFTER, PR_FALSE));
+ EXPECT_EQ(PR_FALSE,
+ PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
+ CKA_NSS_EMAIL_DISTRUST_AFTER, PR_FALSE));
+ ASSERT_FALSE(cert->distrust);
+}
+
+TEST_F(SoftokenBuiltinsTest, CheckOkDistrustFields) {
+ const char *kCertNickname =
+ "Builtin Object Token:Distrust Fields Test - ok_distrust";
+ LoadModule();
+
+ CERTCertDBHandle *cert_handle = CERT_GetDefaultCertDB();
+ ASSERT_TRUE(cert_handle);
+ ScopedCERTCertificate cert(
+ CERT_FindCertByNickname(cert_handle, kCertNickname));
+ ASSERT_TRUE(cert);
+
+ const char *kExpectedDERValueServer = "200617000000Z";
+ const char *kExpectedDERValueEmail = "071014085320Z";
+ // When a valid timestamp is encoded, the result length is exactly 13.
+ const unsigned int kDistrustFieldSize = 13;
+
+ ASSERT_TRUE(cert->distrust);
+ ASSERT_EQ(kDistrustFieldSize, cert->distrust->serverDistrustAfter.len);
+ ASSERT_NE(nullptr, cert->distrust->serverDistrustAfter.data);
+ EXPECT_TRUE(!memcmp(kExpectedDERValueServer,
+ cert->distrust->serverDistrustAfter.data,
+ kDistrustFieldSize));
+
+ ASSERT_EQ(kDistrustFieldSize, cert->distrust->emailDistrustAfter.len);
+ ASSERT_NE(nullptr, cert->distrust->emailDistrustAfter.data);
+ EXPECT_TRUE(!memcmp(kExpectedDERValueEmail,
+ cert->distrust->emailDistrustAfter.data,
+ kDistrustFieldSize));
+}
+
+TEST_F(SoftokenBuiltinsTest, CheckInvalidDistrustFields) {
+ const char *kCertNickname =
+ "Builtin Object Token:Distrust Fields Test - err_distrust";
+ LoadModule();
+
+ CERTCertDBHandle *cert_handle = CERT_GetDefaultCertDB();
+ ASSERT_TRUE(cert_handle);
+ ScopedCERTCertificate cert(
+ CERT_FindCertByNickname(cert_handle, kCertNickname));
+ ASSERT_TRUE(cert);
+
+ // The field should never be set to TRUE in production, we are just
+ // testing if this field is readable, even if set to TRUE.
+ EXPECT_EQ(PR_TRUE,
+ PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
+ CKA_NSS_SERVER_DISTRUST_AFTER, PR_FALSE));
+ // If something other than CK_BBOOL CK_TRUE, it will be considered FALSE
+ // Here, there is an OCTAL value, but with unexpected content (1 digit less).
+ EXPECT_EQ(PR_FALSE,
+ PK11_HasAttributeSet(cert->slot, cert->pkcs11ID,
+ CKA_NSS_EMAIL_DISTRUST_AFTER, PR_FALSE));
+ ASSERT_FALSE(cert->distrust);
+}
+
+} // namespace nss_test