tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

softoken_gtest.cc (41943B)


      1 #include "cert.h"
      2 #include "certdb.h"
      3 #include "nspr.h"
      4 #include "nss.h"
      5 #include "pk11pub.h"
      6 #include "secmod.h"
      7 #include "secerr.h"
      8 
      9 #include "nss_scoped_ptrs.h"
     10 #include "secmodt.h"
     11 #include "secmodti.h"
     12 #include "util.h"
     13 
     14 #define GTEST_HAS_RTTI 0
     15 #include "gtest/gtest.h"
     16 #include "databuffer.h"
     17 #include <fstream>
     18 #include <chrono>
     19 #include <sqlite3.h>
     20 using namespace std::chrono;
     21 
     22 #include "softoken_dh_vectors.h"
     23 
     24 namespace nss_test {
     25 class SoftokenTest : public ::testing::Test {
     26 protected:
     27  SoftokenTest() : mNSSDBDir("SoftokenTest.d-") {}
     28  SoftokenTest(const std::string &prefix) : mNSSDBDir(prefix) {}
     29 
     30  virtual void SetUp() {
     31    std::string nssInitArg("sql:");
     32    nssInitArg.append(mNSSDBDir.GetUTF8Path());
     33    ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
     34                                         NSS_INIT_NOROOTINIT));
     35  }
     36 
     37  virtual void TearDown() {
     38    ASSERT_EQ(SECSuccess, NSS_Shutdown());
     39    const std::string &nssDBDirPath = mNSSDBDir.GetPath();
     40    ASSERT_EQ(0, unlink((nssDBDirPath + "/cert9.db").c_str()));
     41    ASSERT_EQ(0, unlink((nssDBDirPath + "/key4.db").c_str()));
     42    ASSERT_EQ(0, unlink((nssDBDirPath + "/pkcs11.txt").c_str()));
     43  }
     44 
     45  ScopedUniqueDirectory mNSSDBDir;
     46 };
     47 
     48 TEST_F(SoftokenTest, CheckDefaultPbkdf2Iterations) {
     49  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
     50  ASSERT_TRUE(slot);
     51  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
     52 
     53  // Open key4.db and check encoded PBE algorithm and iteration count.
     54  // Compare bytes against the expected values to avoid ASN.1 here.
     55  std::string key_db = mNSSDBDir.GetPath() + "/key4.db";
     56 
     57  sqlite3 *sql_db = NULL;
     58  ASSERT_EQ(SQLITE_OK, sqlite3_open(key_db.c_str(), &sql_db));
     59 
     60  char *query_str = sqlite3_mprintf("SELECT item2 FROM metaData;");
     61  ASSERT_NE(nullptr, query_str);
     62 
     63  sqlite3_stmt *statement = NULL;
     64  ASSERT_EQ(SQLITE_OK,
     65            sqlite3_prepare_v2(sql_db, query_str, -1, &statement, NULL));
     66  ASSERT_EQ(SQLITE_ROW, sqlite3_step(statement));
     67  unsigned int len = sqlite3_column_bytes(statement, 0);
     68  const unsigned char *reader = sqlite3_column_text(statement, 0);
     69 
     70  ASSERT_NE(nullptr, reader);
     71  ASSERT_EQ(133U, len);
     72 
     73  // pkcs5PBES2, pkcs5PBKDF2
     74  const uint8_t pkcs5_with_pbkdf2[] = {
     75      0x30, 0x81, 0x82, 0x30, 0x6E, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
     76      0xF7, 0x0D, 0x01, 0x05, 0x0D, 0x30, 0x61, 0x30, 0x42, 0x06, 0x09,
     77      0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C, 0x30, 0x35};
     78  EXPECT_EQ(0, memcmp(reader, pkcs5_with_pbkdf2, sizeof(pkcs5_with_pbkdf2)));
     79  reader += sizeof(pkcs5_with_pbkdf2);
     80 
     81  // Skip over the 32B random salt
     82  const uint8_t salt_prefix[] = {0x04, 0x20};
     83  EXPECT_EQ(0, memcmp(reader, salt_prefix, sizeof(salt_prefix)));
     84  reader += sizeof(salt_prefix) + 0x20;
     85 
     86  // Expect 10000 iterations
     87  const uint8_t iterations[] = {0x02, 0x02, 0x27, 0x10};
     88  EXPECT_EQ(0, memcmp(reader, iterations, sizeof(iterations)));
     89  reader += sizeof(iterations);
     90 
     91  // hmacWithSHA256, aes256-CBC
     92  const uint8_t oids[] = {0x02, 0x01, 0x20, 0x30, 0x0A, 0x06, 0x08,
     93                          0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02,
     94                          0x09, 0x30, 0x1B, 0x06, 0x09, 0x60, 0x86,
     95                          0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2A};
     96  EXPECT_EQ(0, memcmp(reader, oids, sizeof(oids)));
     97 
     98  EXPECT_EQ(SQLITE_OK, sqlite3_finalize(statement));
     99  sqlite3_free(query_str);
    100  sqlite3_close(sql_db);
    101 }
    102 
    103 TEST_F(SoftokenTest, ResetSoftokenEmptyPassword) {
    104  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    105  ASSERT_TRUE(slot);
    106  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
    107  EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
    108  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
    109 }
    110 
    111 TEST_F(SoftokenTest, ResetSoftokenNonEmptyPassword) {
    112  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    113  ASSERT_TRUE(slot);
    114  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    115  EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
    116  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password2"));
    117 }
    118 
    119 // Test certificate to use in the CreateObject tests.
    120 static const CK_OBJECT_CLASS cko_nss_trust = CKO_NSS_TRUST;
    121 static const CK_BBOOL ck_false = CK_FALSE;
    122 static const CK_BBOOL ck_true = CK_TRUE;
    123 static const CK_TRUST ckt_nss_must_verify_trust = CKT_NSS_MUST_VERIFY_TRUST;
    124 static const CK_TRUST ckt_nss_trusted_delegator = CKT_NSS_TRUSTED_DELEGATOR;
    125 static const CK_ATTRIBUTE attributes[] = {
    126    {CKA_CLASS, (void *)&cko_nss_trust, (PRUint32)sizeof(CK_OBJECT_CLASS)},
    127    {CKA_TOKEN, (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL)},
    128    {CKA_PRIVATE, (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL)},
    129    {CKA_MODIFIABLE, (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL)},
    130    {CKA_LABEL,
    131     (void *)"Symantec Class 2 Public Primary Certification Authority - G4",
    132     (PRUint32)61},
    133    {CKA_CERT_SHA1_HASH,
    134     (void *)"\147\044\220\056\110\001\260\042\226\100\020\106\264\261\147\054"
    135             "\251\165\375\053",
    136     (PRUint32)20},
    137    {CKA_CERT_MD5_HASH,
    138     (void *)"\160\325\060\361\332\224\227\324\327\164\337\276\355\150\336\226",
    139     (PRUint32)16},
    140    {CKA_ISSUER,
    141     (void *)"\060\201\224\061\013\060\011\006\003\125\004\006\023\002\125\123"
    142             "\061\035\060\033\006\003\125\004\012\023\024\123\171\155\141\156"
    143             "\164\145\143\040\103\157\162\160\157\162\141\164\151\157\156\061"
    144             "\037\060\035\006\003\125\004\013\023\026\123\171\155\141\156\164"
    145             "\145\143\040\124\162\165\163\164\040\116\145\164\167\157\162\153"
    146             "\061\105\060\103\006\003\125\004\003\023\074\123\171\155\141\156"
    147             "\164\145\143\040\103\154\141\163\163\040\062\040\120\165\142\154"
    148             "\151\143\040\120\162\151\155\141\162\171\040\103\145\162\164\151"
    149             "\146\151\143\141\164\151\157\156\040\101\165\164\150\157\162\151"
    150             "\164\171\040\055\040\107\064",
    151     (PRUint32)151},
    152    {CKA_SERIAL_NUMBER,
    153     (void *)"\002\020\064\027\145\022\100\073\267\126\200\055\200\313\171\125"
    154             "\246\036",
    155     (PRUint32)18},
    156    {CKA_TRUST_SERVER_AUTH, (void *)&ckt_nss_must_verify_trust,
    157     (PRUint32)sizeof(CK_TRUST)},
    158    {CKA_TRUST_EMAIL_PROTECTION, (void *)&ckt_nss_trusted_delegator,
    159     (PRUint32)sizeof(CK_TRUST)},
    160    {CKA_TRUST_CODE_SIGNING, (void *)&ckt_nss_must_verify_trust,
    161     (PRUint32)sizeof(CK_TRUST)},
    162    {CKA_TRUST_STEP_UP_APPROVED, (void *)&ck_false,
    163     (PRUint32)sizeof(CK_BBOOL)}};
    164 
    165 TEST_F(SoftokenTest, GetInvalidAttribute) {
    166  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    167  ASSERT_TRUE(slot);
    168  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    169  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    170      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    171  ASSERT_NE(nullptr, obj);
    172  SECItem out = {siBuffer, nullptr, 0};
    173  SECStatus rv = PK11_ReadRawAttribute(PK11_TypeGeneric, obj.get(),
    174                                       CKA_ALLOWED_MECHANISMS, &out);
    175  EXPECT_EQ(SECFailure, rv);
    176  // CKR_ATTRIBUTE_TYPE_INVALID maps to SEC_ERROR_BAD_DATA.
    177  EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
    178 }
    179 
    180 TEST_F(SoftokenTest, GetValidAttributes) {
    181  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    182  ASSERT_TRUE(slot);
    183  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    184  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    185      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    186  ASSERT_NE(nullptr, obj);
    187 
    188  CK_ATTRIBUTE template_attrs[] = {
    189      {CKA_LABEL, NULL, 0},
    190      {CKA_CERT_SHA1_HASH, NULL, 0},
    191      {CKA_ISSUER, NULL, 0},
    192  };
    193  SECStatus rv =
    194      PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
    195                             template_attrs, PR_ARRAY_SIZE(template_attrs));
    196  EXPECT_EQ(SECSuccess, rv);
    197  ASSERT_EQ(attributes[4].ulValueLen, template_attrs[0].ulValueLen);
    198  EXPECT_EQ(0, memcmp(attributes[4].pValue, template_attrs[0].pValue,
    199                      template_attrs[0].ulValueLen));
    200  ASSERT_EQ(attributes[5].ulValueLen, template_attrs[1].ulValueLen);
    201  EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[1].pValue,
    202                      template_attrs[1].ulValueLen));
    203  ASSERT_EQ(attributes[7].ulValueLen, template_attrs[2].ulValueLen);
    204  EXPECT_EQ(0, memcmp(attributes[7].pValue, template_attrs[2].pValue,
    205                      template_attrs[2].ulValueLen));
    206  for (unsigned int i = 0; i < PR_ARRAY_SIZE(template_attrs); i++) {
    207    PORT_Free(template_attrs[i].pValue);
    208  }
    209 }
    210 
    211 TEST_F(SoftokenTest, GetOnlyInvalidAttributes) {
    212  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    213  ASSERT_TRUE(slot);
    214  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    215  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    216      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    217  ASSERT_NE(nullptr, obj);
    218 
    219  // Provide buffers of sufficient size, so that token
    220  // will write the data. This is annoying, but PK11_GetAttributes
    221  // won't allocate in the cases below when a single attribute
    222  // is missing. So, just put them all on the stack.
    223  unsigned char buf1[100];
    224  unsigned char buf2[100];
    225  CK_ATTRIBUTE template_attrs[] = {{0xffffffffUL, buf1, sizeof(buf1)},
    226                                   {0xfffffffeUL, buf2, sizeof(buf2)}};
    227  SECStatus rv =
    228      PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
    229                             template_attrs, PR_ARRAY_SIZE(template_attrs));
    230  EXPECT_EQ(SECFailure, rv);
    231  EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
    232 
    233  // MSVC rewards -1UL with a C4146 warning...
    234  ASSERT_EQ(0UL, template_attrs[0].ulValueLen + 1);
    235  ASSERT_EQ(0UL, template_attrs[1].ulValueLen + 1);
    236 }
    237 
    238 TEST_F(SoftokenTest, GetAttributesInvalidInterspersed1) {
    239  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    240  ASSERT_TRUE(slot);
    241  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    242  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    243      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    244  ASSERT_NE(nullptr, obj);
    245 
    246  unsigned char buf1[100];
    247  unsigned char buf2[100];
    248  unsigned char buf3[200];
    249  CK_ATTRIBUTE template_attrs[] = {{0xffffffff, buf1, sizeof(buf1)},
    250                                   {CKA_CERT_SHA1_HASH, buf2, sizeof(buf2)},
    251                                   {CKA_ISSUER, buf3, sizeof(buf3)}};
    252  SECStatus rv =
    253      PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
    254                             template_attrs, PR_ARRAY_SIZE(template_attrs));
    255  EXPECT_EQ(SECFailure, rv);
    256  EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
    257  ASSERT_EQ(0UL, template_attrs[0].ulValueLen + 1);
    258  ASSERT_EQ(attributes[5].ulValueLen, template_attrs[1].ulValueLen);
    259  EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[1].pValue,
    260                      template_attrs[1].ulValueLen));
    261  ASSERT_EQ(attributes[7].ulValueLen, template_attrs[2].ulValueLen);
    262  EXPECT_EQ(0, memcmp(attributes[7].pValue, template_attrs[2].pValue,
    263                      template_attrs[2].ulValueLen));
    264 }
    265 
    266 TEST_F(SoftokenTest, GetAttributesInvalidInterspersed2) {
    267  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    268  ASSERT_TRUE(slot);
    269  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    270  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    271      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    272  ASSERT_NE(nullptr, obj);
    273 
    274  unsigned char buf1[100];
    275  unsigned char buf2[100];
    276  unsigned char buf3[100];
    277  CK_ATTRIBUTE template_attrs[] = {{CKA_LABEL, buf1, sizeof(buf1)},
    278                                   {CKA_CERT_SHA1_HASH, buf2, sizeof(buf2)},
    279                                   {0xffffffffUL, buf3, sizeof(buf3)}};
    280  SECStatus rv =
    281      PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
    282                             template_attrs, PR_ARRAY_SIZE(template_attrs));
    283  EXPECT_EQ(SECFailure, rv);
    284  EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
    285  ASSERT_EQ(attributes[4].ulValueLen, template_attrs[0].ulValueLen);
    286  EXPECT_EQ(0, memcmp(attributes[4].pValue, template_attrs[0].pValue,
    287                      template_attrs[0].ulValueLen));
    288  ASSERT_EQ(attributes[5].ulValueLen, template_attrs[1].ulValueLen);
    289  EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[1].pValue,
    290                      template_attrs[1].ulValueLen));
    291  ASSERT_EQ(0UL, template_attrs[2].ulValueLen + 1);
    292 }
    293 
    294 TEST_F(SoftokenTest, GetAttributesInvalidInterspersed3) {
    295  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    296  ASSERT_TRUE(slot);
    297  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    298  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    299      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    300  ASSERT_NE(nullptr, obj);
    301 
    302  unsigned char buf1[100];
    303  unsigned char buf2[100];
    304  unsigned char buf3[100];
    305  unsigned char buf4[100];
    306  unsigned char buf5[100];
    307  unsigned char buf6[200];
    308  CK_ATTRIBUTE template_attrs[6] = {{CKA_LABEL, buf1, sizeof(buf1)},
    309                                    {0xffffffffUL, buf2, sizeof(buf2)},
    310                                    {0xfffffffeUL, buf3, sizeof(buf3)},
    311                                    {CKA_CERT_SHA1_HASH, buf4, sizeof(buf4)},
    312                                    {0xfffffffdUL, buf5, sizeof(buf5)},
    313                                    {CKA_ISSUER, buf6, sizeof(buf6)}};
    314  SECStatus rv =
    315      PK11_ReadRawAttributes(nullptr, PK11_TypeGeneric, obj.get(),
    316                             template_attrs, PR_ARRAY_SIZE(template_attrs));
    317  EXPECT_EQ(SECFailure, rv);
    318  EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
    319 
    320  ASSERT_EQ(attributes[4].ulValueLen, template_attrs[0].ulValueLen);
    321  EXPECT_EQ(0, memcmp(attributes[4].pValue, template_attrs[0].pValue,
    322                      template_attrs[0].ulValueLen));
    323  ASSERT_EQ(0UL, template_attrs[1].ulValueLen + 1);
    324  ASSERT_EQ(0UL, template_attrs[2].ulValueLen + 1);
    325  ASSERT_EQ(attributes[5].ulValueLen, template_attrs[3].ulValueLen);
    326  EXPECT_EQ(0, memcmp(attributes[5].pValue, template_attrs[3].pValue,
    327                      template_attrs[3].ulValueLen));
    328  ASSERT_EQ(0UL, template_attrs[4].ulValueLen + 1);
    329  ASSERT_EQ(attributes[7].ulValueLen, template_attrs[5].ulValueLen);
    330  EXPECT_EQ(0, memcmp(attributes[7].pValue, template_attrs[5].pValue,
    331                      template_attrs[5].ulValueLen));
    332 }
    333 
    334 TEST_F(SoftokenTest, CreateObjectNonEmptyPassword) {
    335  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    336  ASSERT_TRUE(slot);
    337  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    338  EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
    339  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    340      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    341  EXPECT_EQ(nullptr, obj);
    342 }
    343 
    344 TEST_F(SoftokenTest, CreateObjectChangePassword) {
    345  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    346  ASSERT_TRUE(slot);
    347  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
    348  EXPECT_EQ(SECSuccess, PK11_ChangePW(slot.get(), "", "password"));
    349  EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
    350  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    351      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    352  EXPECT_EQ(nullptr, obj);
    353 }
    354 
    355 // The size limit for a password is 500 characters as defined in pkcs11i.h
    356 TEST_F(SoftokenTest, CreateObjectChangeToBigPassword) {
    357  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    358  ASSERT_TRUE(slot);
    359  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
    360  EXPECT_EQ(
    361      SECSuccess,
    362      PK11_ChangePW(slot.get(), "",
    363                    "rUIFIFr2bxKnbJbitsfkyqttpk6vCJzlYMNxcxXcaN37gSZKbLk763X7iR"
    364                    "yeVNWZHQ02lSF69HYjzTyPW3318ZD0DBFMMbALZ8ZPZP73CIo5uIQlaowV"
    365                    "IbP8eOhRYtGUqoLGlcIFNEYogV8Q3GN58VeBMs0KxrIOvPQ9s8SnYYkqvt"
    366                    "zzgntmAvCgvk64x6eQf0okHwegd5wi6m0WVJytEepWXkP9J629FSa5kNT8"
    367                    "FvL3jvslkiImzTNuTvl32fQDXXMSc8vVk5Q3mH7trMZM0VDdwHWYERjHbz"
    368                    "kGxFgp0VhediHx7p9kkz6H6ac4et9sW4UkTnN7xhYc1Zr17wRSk2heQtcX"
    369                    "oZJGwuzhiKm8A8wkuVxms6zO56P4JORIk8oaUW6lyNTLo2kWWnTA"));
    370  EXPECT_EQ(SECSuccess, PK11_Logout(slot.get()));
    371  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    372      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    373  EXPECT_EQ(nullptr, obj);
    374 }
    375 
    376 TEST_F(SoftokenTest, CreateObjectChangeToEmptyPassword) {
    377  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    378  ASSERT_TRUE(slot);
    379  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    380  EXPECT_EQ(SECSuccess, PK11_ChangePW(slot.get(), "password", ""));
    381  // PK11_Logout returnes an error and SEC_ERROR_TOKEN_NOT_LOGGED_IN if the user
    382  // is not "logged in".
    383  EXPECT_EQ(SECFailure, PK11_Logout(slot.get()));
    384  EXPECT_EQ(SEC_ERROR_TOKEN_NOT_LOGGED_IN, PORT_GetError());
    385  ScopedPK11GenericObject obj(PK11_CreateGenericObject(
    386      slot.get(), attributes, PR_ARRAY_SIZE(attributes), true));
    387  // Because there's no password we can't logout and the operation should have
    388  // succeeded.
    389  EXPECT_NE(nullptr, obj);
    390 }
    391 
    392 // We should be able to read CRLF, LF and CR.
    393 // During the Initialization of the NSS Database, is called a function to load
    394 // PKCS11 modules defined in pkcs11.txt. This file is read to get the
    395 // specifications, parse them and load the modules. Here we are ensuring that
    396 // the parsing will work correctly, independent of the breaking line format of
    397 // pkcs11.txt file, which could vary depending where it was created.
    398 // If the parsing is not well interpreted, the database cannot initialize.
    399 TEST_F(SoftokenTest, CreateObjectReadBreakLine) {
    400  const std::string path = mNSSDBDir.GetPath();
    401  const std::string dbname_in = path + "/pkcs11.txt";
    402  const std::string dbname_out_cr = path + "/pkcs11_cr.txt";
    403  const std::string dbname_out_crlf = path + "/pkcs11_crlf.txt";
    404  const std::string dbname_out_lf = path + "/pkcs11_lf.txt";
    405 
    406  std::ifstream in(dbname_in);
    407  ASSERT_TRUE(in);
    408  std::ofstream out_cr(dbname_out_cr);
    409  ASSERT_TRUE(out_cr);
    410  std::ofstream out_crlf(dbname_out_crlf);
    411  ASSERT_TRUE(out_crlf);
    412  std::ofstream out_lf(dbname_out_lf);
    413  ASSERT_TRUE(out_lf);
    414 
    415  // Database should be correctly initialized by Setup()
    416  ASSERT_TRUE(NSS_IsInitialized());
    417  ASSERT_EQ(SECSuccess, NSS_Shutdown());
    418 
    419  // Prepare the file formats with CR, CRLF and LF
    420  for (std::string line; getline(in, line);) {
    421    out_cr << line << "\r";
    422    out_crlf << line << "\r\n";
    423    out_lf << line << "\n";
    424  }
    425  in.close();
    426  out_cr.close();
    427  out_crlf.close();
    428  out_lf.close();
    429 
    430  // Change the pkcs11.txt to CR format.
    431  ASSERT_TRUE(!remove(dbname_in.c_str()));
    432  ASSERT_TRUE(!rename(dbname_out_cr.c_str(), dbname_in.c_str()));
    433 
    434  // Try to initialize with CR format.
    435  std::string nssInitArg("sql:");
    436  nssInitArg.append(mNSSDBDir.GetUTF8Path());
    437  ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
    438                                       NSS_INIT_NOROOTINIT));
    439  ASSERT_TRUE(NSS_IsInitialized());
    440  ASSERT_EQ(SECSuccess, NSS_Shutdown());
    441 
    442  // Change the pkcs11.txt to CRLF format.
    443  ASSERT_TRUE(!remove(dbname_in.c_str()));
    444  ASSERT_TRUE(!rename(dbname_out_crlf.c_str(), dbname_in.c_str()));
    445 
    446  // Try to initialize with CRLF format.
    447  ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
    448                                       NSS_INIT_NOROOTINIT));
    449  ASSERT_TRUE(NSS_IsInitialized());
    450  ASSERT_EQ(SECSuccess, NSS_Shutdown());
    451 
    452  // Change the pkcs11.txt to LF format.
    453  ASSERT_TRUE(!remove(dbname_in.c_str()));
    454  ASSERT_TRUE(!rename(dbname_out_lf.c_str(), dbname_in.c_str()));
    455 
    456  // Try to initialize with LF format.
    457  ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
    458                                       NSS_INIT_NOROOTINIT));
    459  ASSERT_TRUE(NSS_IsInitialized());
    460 }
    461 
    462 // Key IDs used for CreateKeyUnique test below
    463 static unsigned char keyID1[16] = {0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
    464                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    465                                   0x00, 0x00, 0x00, 0x01};
    466 static SECItem keyID1Item = {SECItemType::siBuffer, keyID1, sizeof(keyID1)};
    467 static unsigned char keyID2[16] = {0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
    468                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    469                                   0x00, 0x00, 0x00, 0x02};
    470 static SECItem keyID2Item = {SECItemType::siBuffer, keyID2, sizeof(keyID2)};
    471 
    472 // Test that new keys added to the database are checked for uniqueness
    473 // correctly. Any attempt to create a new key with the same ID and type of an
    474 // existing key should just overwrite the existing key instead of creating a new
    475 // key.
    476 TEST_F(SoftokenTest, CreateKeyUnique) {
    477  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    478  ASSERT_TRUE(slot);
    479  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
    480 
    481  int aesKeySize = PK11_GetBestKeyLength(slot.get(), CKM_AES_CBC);
    482  int des3KeySize = PK11_GetBestKeyLength(slot.get(), CKM_DES3_CBC);
    483 
    484  ScopedPK11SymKey key1(PK11_TokenKeyGen(slot.get(), CKM_AES_CBC, 0, aesKeySize,
    485                                         &keyID1Item, true, nullptr));
    486 
    487  // No new key should be generated here, as the ID and the type match.
    488  ScopedPK11SymKey key2(PK11_TokenKeyGen(slot.get(), CKM_AES_CBC, 0, aesKeySize,
    489                                         &keyID1Item, true, nullptr));
    490  EXPECT_EQ(key1->objectID, key2->objectID);
    491 
    492  // This should generate a new key, as the type differs.
    493  ScopedPK11SymKey key3(PK11_TokenKeyGen(
    494      slot.get(), CKM_DES3_CBC, 0, des3KeySize, &keyID1Item, true, nullptr));
    495  EXPECT_NE(key1->objectID, key3->objectID);
    496 
    497  // This should generate a new key, as the ID differs.
    498  ScopedPK11SymKey key4(PK11_TokenKeyGen(slot.get(), CKM_AES_CBC, 0, aesKeySize,
    499                                         &keyID2Item, true, nullptr));
    500  EXPECT_NE(key1->objectID, key4->objectID);
    501 
    502  // This should generate a new key, as no ID is specified.
    503  ScopedPK11SymKey key5(PK11_TokenKeyGen(slot.get(), CKM_AES_CBC, 0, aesKeySize,
    504                                         NULL, true, nullptr));
    505  EXPECT_NE(key1->objectID, key5->objectID);
    506 
    507  // The ID is not specified again. This should create a new key different from
    508  // the previous one.
    509  ScopedPK11SymKey key6(PK11_TokenKeyGen(slot.get(), CKM_AES_CBC, 0, aesKeySize,
    510                                         NULL, true, nullptr));
    511  EXPECT_NE(key5->objectID, key6->objectID);
    512 }
    513 
    514 // Disabled on MacOS because of Bug 1962505
    515 // (Skip test is insufficient because the error happens during
    516 // test class construction)
    517 #if !GTEST_OS_MAC
    518 
    519 class SoftokenNonAsciiTest : public SoftokenTest {
    520 protected:
    521  SoftokenNonAsciiTest() : SoftokenTest("SoftokenTest.\xF7-") {}
    522 };
    523 
    524 TEST_F(SoftokenNonAsciiTest, NonAsciiPathWorking) {
    525  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    526  ASSERT_TRUE(slot);
    527  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
    528  EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
    529  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
    530 }
    531 #endif
    532 
    533 // This is just any X509 certificate. Its contents don't matter.
    534 static unsigned char certDER[] = {
    535    0x30, 0x82, 0x01, 0xEF, 0x30, 0x82, 0x01, 0x94, 0xA0, 0x03, 0x02, 0x01,
    536    0x02, 0x02, 0x14, 0x49, 0xC4, 0xC4, 0x4A, 0xB6, 0x86, 0x07, 0xA3, 0x06,
    537    0xDC, 0x4D, 0xC8, 0xC3, 0xFE, 0xC7, 0x21, 0x3A, 0x2D, 0xE4, 0xDA, 0x30,
    538    0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
    539    0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C,
    540    0x04, 0x74, 0x65, 0x73, 0x74, 0x30, 0x22, 0x18, 0x0F, 0x32, 0x30, 0x31,
    541    0x35, 0x31, 0x31, 0x32, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
    542    0x18, 0x0F, 0x32, 0x30, 0x31, 0x38, 0x30, 0x32, 0x30, 0x35, 0x30, 0x30,
    543    0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x0F, 0x31, 0x0D, 0x30, 0x0B, 0x06,
    544    0x03, 0x55, 0x04, 0x03, 0x0C, 0x04, 0x74, 0x65, 0x73, 0x74, 0x30, 0x82,
    545    0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
    546    0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, 0x30, 0x82,
    547    0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xBA, 0x88, 0x51, 0xA8, 0x44,
    548    0x8E, 0x16, 0xD6, 0x41, 0xFD, 0x6E, 0xB6, 0x88, 0x06, 0x36, 0x10, 0x3D,
    549    0x3C, 0x13, 0xD9, 0xEA, 0xE4, 0x35, 0x4A, 0xB4, 0xEC, 0xF5, 0x68, 0x57,
    550    0x6C, 0x24, 0x7B, 0xC1, 0xC7, 0x25, 0xA8, 0xE0, 0xD8, 0x1F, 0xBD, 0xB1,
    551    0x9C, 0x06, 0x9B, 0x6E, 0x1A, 0x86, 0xF2, 0x6B, 0xE2, 0xAF, 0x5A, 0x75,
    552    0x6B, 0x6A, 0x64, 0x71, 0x08, 0x7A, 0xA5, 0x5A, 0xA7, 0x45, 0x87, 0xF7,
    553    0x1C, 0xD5, 0x24, 0x9C, 0x02, 0x7E, 0xCD, 0x43, 0xFC, 0x1E, 0x69, 0xD0,
    554    0x38, 0x20, 0x29, 0x93, 0xAB, 0x20, 0xC3, 0x49, 0xE4, 0xDB, 0xB9, 0x4C,
    555    0xC2, 0x6B, 0x6C, 0x0E, 0xED, 0x15, 0x82, 0x0F, 0xF1, 0x7E, 0xAD, 0x69,
    556    0x1A, 0xB1, 0xD3, 0x02, 0x3A, 0x8B, 0x2A, 0x41, 0xEE, 0xA7, 0x70, 0xE0,
    557    0x0F, 0x0D, 0x8D, 0xFD, 0x66, 0x0B, 0x2B, 0xB0, 0x24, 0x92, 0xA4, 0x7D,
    558    0xB9, 0x88, 0x61, 0x79, 0x90, 0xB1, 0x57, 0x90, 0x3D, 0xD2, 0x3B, 0xC5,
    559    0xE0, 0xB8, 0x48, 0x1F, 0xA8, 0x37, 0xD3, 0x88, 0x43, 0xEF, 0x27, 0x16,
    560    0xD8, 0x55, 0xB7, 0x66, 0x5A, 0xAA, 0x7E, 0x02, 0x90, 0x2F, 0x3A, 0x7B,
    561    0x10, 0x80, 0x06, 0x24, 0xCC, 0x1C, 0x6C, 0x97, 0xAD, 0x96, 0x61, 0x5B,
    562    0xB7, 0xE2, 0x96, 0x12, 0xC0, 0x75, 0x31, 0xA3, 0x0C, 0x91, 0xDD, 0xB4,
    563    0xCA, 0xF7, 0xFC, 0xAD, 0x1D, 0x25, 0xD3, 0x09, 0xEF, 0xB9, 0x17, 0x0E,
    564    0xA7, 0x68, 0xE1, 0xB3, 0x7B, 0x2F, 0x22, 0x6F, 0x69, 0xE3, 0xB4, 0x8A,
    565    0x95, 0x61, 0x1D, 0xEE, 0x26, 0xD6, 0x25, 0x9D, 0xAB, 0x91, 0x08, 0x4E,
    566    0x36, 0xCB, 0x1C, 0x24, 0x04, 0x2C, 0xBF, 0x16, 0x8B, 0x2F, 0xE5, 0xF1,
    567    0x8F, 0x99, 0x17, 0x31, 0xB8, 0xB3, 0xFE, 0x49, 0x23, 0xFA, 0x72, 0x51,
    568    0xC4, 0x31, 0xD5, 0x03, 0xAC, 0xDA, 0x18, 0x0A, 0x35, 0xED, 0x8D, 0x02,
    569    0x03, 0x01, 0x00, 0x01, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
    570    0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x20,
    571    0x5C, 0x75, 0x51, 0x9F, 0x13, 0x11, 0x50, 0xCD, 0x5D, 0x8A, 0xDE, 0x20,
    572    0xA3, 0xBC, 0x06, 0x30, 0x91, 0xFF, 0xB2, 0x73, 0x75, 0x5F, 0x31, 0x64,
    573    0xEC, 0xFD, 0xCB, 0x42, 0x80, 0x0A, 0x70, 0xE6, 0x02, 0x21, 0x00, 0x82,
    574    0x12, 0xF7, 0xE5, 0xEA, 0x40, 0x27, 0xFD, 0xF7, 0xC0, 0x0E, 0x25, 0xF3,
    575    0x3E, 0x34, 0x95, 0x80, 0xB9, 0xA3, 0x38, 0xE0, 0x56, 0x68, 0xDA, 0xE5,
    576    0xC1, 0xF5, 0x37, 0xC7, 0xB5, 0xCE, 0x0D};
    577 
    578 struct PasswordPair {
    579  const char *mInitialPassword;
    580  const char *mSecondPassword;
    581 };
    582 
    583 class SoftokenPasswordChangeTest
    584    : public SoftokenTest,
    585      public ::testing::WithParamInterface<PasswordPair> {};
    586 
    587 TEST_P(SoftokenPasswordChangeTest, KeepTrustAfterPasswordChange) {
    588  const PasswordPair &passwords = GetParam();
    589  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    590  ASSERT_TRUE(slot);
    591  // Set a password.
    592  EXPECT_EQ(SECSuccess,
    593            PK11_InitPin(slot.get(), nullptr, passwords.mInitialPassword));
    594  SECItem certDERItem = {siBuffer, certDER, sizeof(certDER)};
    595  // Import a certificate.
    596  ScopedCERTCertificate cert(CERT_NewTempCertificate(
    597      CERT_GetDefaultCertDB(), &certDERItem, nullptr, true, true));
    598  EXPECT_TRUE(cert);
    599  SECStatus result =
    600      PK11_ImportCert(slot.get(), cert.get(), CK_INVALID_HANDLE, "test", false);
    601  EXPECT_EQ(SECSuccess, result);
    602  // Set a trust value.
    603  CERTCertTrust trust = {CERTDB_TRUSTED_CLIENT_CA | CERTDB_NS_TRUSTED_CA |
    604                             CERTDB_TRUSTED_CA | CERTDB_VALID_CA,
    605                         0, 0};
    606  result = CERT_ChangeCertTrust(nullptr, cert.get(), &trust);
    607  EXPECT_EQ(SECSuccess, result);
    608  // Release the certificate to ensure we get it from the DB rather than an
    609  // in-memory cache, below.
    610  cert = nullptr;
    611  // Change the password.
    612  result = PK11_ChangePW(slot.get(), passwords.mInitialPassword,
    613                         passwords.mSecondPassword);
    614  EXPECT_EQ(SECSuccess, result);
    615  // Look up the certificate again.
    616  ScopedCERTCertificate newCert(
    617      PK11_FindCertFromDERCertItem(slot.get(), &certDERItem, nullptr));
    618  EXPECT_TRUE(newCert.get());
    619  // The trust should be the same as before.
    620  CERTCertTrust newTrust = {0, 0, 0};
    621  result = CERT_GetCertTrust(newCert.get(), &newTrust);
    622  EXPECT_EQ(SECSuccess, result);
    623  EXPECT_EQ(trust.sslFlags, newTrust.sslFlags);
    624  EXPECT_EQ(trust.emailFlags, newTrust.emailFlags);
    625  EXPECT_EQ(trust.objectSigningFlags, newTrust.objectSigningFlags);
    626 }
    627 
    628 static const PasswordPair PASSWORD_CHANGE_TESTS[] = {
    629    {"password", ""},           // non-empty to empty password
    630    {"", "password"},           // empty to non-empty password
    631    {"password", "password2"},  // non-empty to non-empty password
    632 };
    633 
    634 INSTANTIATE_TEST_SUITE_P(SoftokenPasswordChangeTests,
    635                         SoftokenPasswordChangeTest,
    636                         ::testing::ValuesIn(PASSWORD_CHANGE_TESTS));
    637 
    638 class SoftokenNoDBTest : public ::testing::Test {};
    639 
    640 TEST_F(SoftokenNoDBTest, NeedUserInitNoDB) {
    641  ASSERT_EQ(SECSuccess, NSS_NoDB_Init("."));
    642  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    643  ASSERT_TRUE(slot);
    644  EXPECT_EQ(PR_FALSE, PK11_NeedUserInit(slot.get()));
    645 
    646  // When shutting down in here we have to release the slot first.
    647  slot = nullptr;
    648  ASSERT_EQ(SECSuccess, NSS_Shutdown());
    649 }
    650 
    651 SECStatus test_dh_value(const PQGParams *params, const SECItem *pub_key_value,
    652                        PRBool genFailOK, time_t *time) {
    653  SECKEYDHParams dh_params;
    654  dh_params.base = params->base;
    655  dh_params.prime = params->prime;
    656 
    657  ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    658  EXPECT_TRUE(slot);
    659  if (!slot) return SECFailure;
    660 
    661  /* create a private/public key pair in with the given params */
    662  SECKEYPublicKey *pub_tmp = nullptr;
    663  ScopedSECKEYPrivateKey priv_key(
    664      PK11_GenerateKeyPair(slot.get(), CKM_DH_PKCS_KEY_PAIR_GEN, &dh_params,
    665                           &pub_tmp, PR_FALSE, PR_TRUE, nullptr));
    666  if ((genFailOK) && ((priv_key.get() == nullptr) || (pub_tmp == nullptr))) {
    667    return SECFailure;
    668  }
    669  EXPECT_NE(nullptr, priv_key.get())
    670      << "PK11_GenerateKeyPair failed: " << PORT_ErrorToName(PORT_GetError());
    671  EXPECT_NE(nullptr, pub_tmp);
    672  if ((priv_key.get() == nullptr) || (pub_tmp == nullptr)) return SECFailure;
    673  ScopedSECKEYPublicKey pub_key(pub_tmp);
    674  ScopedSECKEYPublicKey peer_pub_key_manager(nullptr);
    675  SECKEYPublicKey *peer_pub_key = pub_key.get();
    676 
    677  /* if a subprime has been given set it on the PKCS #11 key */
    678  if (params->subPrime.data != nullptr) {
    679    SECStatus rv;
    680    EXPECT_EQ(SECSuccess, rv = PK11_WriteRawAttribute(
    681                              PK11_TypePrivKey, priv_key.get(), CKA_SUBPRIME,
    682                              (SECItem *)&params->subPrime))
    683        << "PK11_WriteRawAttribute failed: "
    684        << PORT_ErrorToString(PORT_GetError());
    685    if (rv != SECSuccess) {
    686      return rv;
    687    }
    688  }
    689 
    690  /* find if we weren't passed a public value in, use the
    691   * one we just generated */
    692  if (pub_key_value && pub_key_value->data) {
    693    peer_pub_key = SECKEY_CopyPublicKey(pub_key.get());
    694    EXPECT_NE(nullptr, peer_pub_key);
    695    if (peer_pub_key == nullptr) {
    696      return SECFailure;
    697    }
    698    peer_pub_key->u.dh.publicValue = *pub_key_value;
    699    peer_pub_key_manager.reset(peer_pub_key);
    700  }
    701 
    702  /* now do the derive. time it and return the time if
    703   * the caller requested it. */
    704  auto start = high_resolution_clock::now();
    705  ScopedPK11SymKey derivedKey(PK11_PubDerive(
    706      priv_key.get(), peer_pub_key, PR_FALSE, nullptr, nullptr,
    707      CKM_DH_PKCS_DERIVE, CKM_HKDF_DERIVE, CKA_DERIVE, 32, nullptr));
    708  auto stop = high_resolution_clock::now();
    709  if (!derivedKey) {
    710    std::cerr << "PK11_PubDerive failed: "
    711              << PORT_ErrorToString(PORT_GetError()) << std::endl;
    712  }
    713 
    714  if (time) {
    715    auto duration = duration_cast<microseconds>(stop - start);
    716    *time = duration.count();
    717  }
    718  return derivedKey ? SECSuccess : SECFailure;
    719 }
    720 
    721 class SoftokenDhTest : public SoftokenTest {
    722 protected:
    723  SoftokenDhTest() : SoftokenTest("SoftokenDhTest.d-") {}
    724 #ifdef NSS_USE_TIMING_CODE
    725  time_t reference_time[CLASS_LAST] = {0};
    726 #endif
    727 
    728  virtual void SetUp() {
    729    SoftokenTest::SetUp();
    730 
    731 #ifdef NSS_USE_TIMING_CODE
    732    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    733    ASSERT_TRUE(slot);
    734 
    735    time_t time;
    736    for (int i = CLASS_FIRST; i < CLASS_LAST; i++) {
    737      PQGParams params;
    738      params.prime.data = (unsigned char *)reference_prime[i];
    739      params.prime.len = reference_prime_len[i];
    740      params.base.data = (unsigned char *)g2;
    741      params.base.len = sizeof(g2);
    742      params.subPrime.data = nullptr;
    743      params.subPrime.len = 0;
    744      ASSERT_EQ(SECSuccess, test_dh_value(&params, nullptr, PR_FALSE, &time));
    745      reference_time[i] = time / 2 + 3 * time;
    746    }
    747 #endif
    748  };
    749 };
    750 
    751 const char *param_value(DhParamType param_type) {
    752  switch (param_type) {
    753    case TLS_APPROVED:
    754      return "TLS_APPROVED";
    755    case IKE_APPROVED:
    756      return "IKE_APPROVED";
    757    case SAFE_PRIME:
    758      return "SAFE_PRIME";
    759    case SAFE_PRIME_WITH_SUBPRIME:
    760      return "SAFE_PRIME_WITH_SUBPRIME";
    761    case KNOWN_SUBPRIME:
    762      return "KNOWN_SUBPRIME";
    763    case UNKNOWN_SUBPRIME:
    764      return "UNKNOWN_SUBPRIME";
    765    case WRONG_SUBPRIME:
    766      return "WRONG_SUBPRIME";
    767    case BAD_PUB_KEY:
    768      return "BAD_PUB_KEY";
    769  }
    770  return "**Invalid**";
    771 }
    772 
    773 const char *key_value(DhKeyClass key_class) {
    774  switch (key_class) {
    775    case CLASS_1536:
    776      return "CLASS_1536";
    777    case CLASS_2048:
    778      return "CLASS_2048";
    779    case CLASS_3072:
    780      return "CLASS_3072";
    781    case CLASS_4096:
    782      return "CLASS_4096";
    783    case CLASS_6144:
    784      return "CLASS_6144";
    785    case CLASS_8192:
    786      return "CLASS_8192";
    787    case CLASS_LAST:
    788      break;
    789  }
    790  return "**Invalid**";
    791 }
    792 
    793 class SoftokenDhValidate : public SoftokenDhTest,
    794                           public ::testing::WithParamInterface<DhTestVector> {
    795 };
    796 
    797 /* test the DH validation process. In non-fips mode, only BAD_PUB_KEY tests
    798 * should fail */
    799 TEST_P(SoftokenDhValidate, DhVectors) {
    800  const DhTestVector dhTestValues = GetParam();
    801  std::string testId = (char *)(dhTestValues.id);
    802  std::string err = "Test(" + testId + ") failed";
    803  SECStatus rv;
    804  time_t time;
    805 
    806  PQGParams params;
    807  params.prime = dhTestValues.p;
    808  params.base = dhTestValues.g;
    809  params.subPrime = dhTestValues.q;
    810 
    811  std::cerr << "Test: " + testId << std::endl
    812            << "param_type: " << param_value(dhTestValues.param_type)
    813            << ", key_class: " << key_value(dhTestValues.key_class) << std::endl
    814            << "p: " << DataBuffer(dhTestValues.p.data, dhTestValues.p.len)
    815            << std::endl
    816            << "g: " << DataBuffer(dhTestValues.g.data, dhTestValues.g.len)
    817            << std::endl
    818            << "q: " << DataBuffer(dhTestValues.q.data, dhTestValues.q.len)
    819            << std::endl
    820            << "pub_key: "
    821            << DataBuffer(dhTestValues.pub_key.data, dhTestValues.pub_key.len)
    822            << std::endl;
    823  rv = test_dh_value(&params, &dhTestValues.pub_key, PR_FALSE, &time);
    824 
    825  switch (dhTestValues.param_type) {
    826    case TLS_APPROVED:
    827    case IKE_APPROVED:
    828    case SAFE_PRIME:
    829    case UNKNOWN_SUBPRIME:
    830      EXPECT_EQ(SECSuccess, rv) << err;
    831 #ifdef NSS_USE_TIMING_CODE
    832      EXPECT_LE(time, reference_time[dhTestValues.key_class]) << err;
    833 #endif
    834      break;
    835    case KNOWN_SUBPRIME:
    836    case SAFE_PRIME_WITH_SUBPRIME:
    837      EXPECT_EQ(SECSuccess, rv) << err;
    838 #ifdef NSS_USE_TIMING_CODE
    839      EXPECT_GT(time, reference_time[dhTestValues.key_class]) << err;
    840 #endif
    841      break;
    842    case WRONG_SUBPRIME:
    843    case BAD_PUB_KEY:
    844      EXPECT_EQ(SECFailure, rv) << err;
    845      break;
    846  }
    847 }
    848 
    849 INSTANTIATE_TEST_SUITE_P(DhValidateCases, SoftokenDhValidate,
    850                         ::testing::ValuesIn(DH_TEST_VECTORS));
    851 
    852 #ifndef NSS_FIPS_DISABLED
    853 
    854 class SoftokenFipsTest : public SoftokenTest {
    855 protected:
    856  SoftokenFipsTest() : SoftokenTest("SoftokenFipsTest.d-") {}
    857  SoftokenFipsTest(const std::string &prefix) : SoftokenTest(prefix) {}
    858 
    859  virtual void SetUp() {
    860    SoftokenTest::SetUp();
    861 
    862    // Turn on FIPS mode (code borrowed from FipsMode in modutil/pk11.c)
    863    char *internal_name;
    864    ASSERT_FALSE(PK11_IsFIPS());
    865    internal_name = PR_smprintf("%s", SECMOD_GetInternalModule()->commonName);
    866    ASSERT_EQ(SECSuccess, SECMOD_DeleteInternalModule(internal_name))
    867        << PORT_ErrorToName(PORT_GetError());
    868    PR_smprintf_free(internal_name);
    869    ASSERT_TRUE(PK11_IsFIPS());
    870  }
    871 };
    872 
    873 class SoftokenFipsDhTest : public SoftokenFipsTest {
    874 protected:
    875  SoftokenFipsDhTest() : SoftokenFipsTest("SoftokenFipsDhTest.d-") {}
    876 #ifdef NSS_USE_TIMING_CODE
    877  time_t reference_time[CLASS_LAST] = {0};
    878 #endif
    879 
    880  virtual void SetUp() {
    881    SoftokenFipsTest::SetUp();
    882 
    883    ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
    884    ASSERT_TRUE(slot);
    885 
    886    ASSERT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, ""));
    887    ASSERT_EQ(SECSuccess, PK11_Authenticate(slot.get(), PR_FALSE, nullptr));
    888 
    889 #ifdef NSS_USE_TIMING_CODE
    890    time_t time;
    891    for (int i = CLASS_FIRST; i < CLASS_LAST; i++) {
    892      PQGParams params;
    893      params.prime.data = (unsigned char *)reference_prime[i];
    894      params.prime.len = reference_prime_len[i];
    895      params.base.data = (unsigned char *)g2;
    896      params.base.len = sizeof(g2);
    897      params.subPrime.data = nullptr;
    898      params.subPrime.len = 0;
    899      ASSERT_EQ(SECSuccess, test_dh_value(&params, nullptr, PR_FALSE, &time));
    900      reference_time[i] = time / 2 + 3 * time;
    901    }
    902 #endif
    903  };
    904 };
    905 
    906 const std::vector<std::string> kFipsPasswordCases[] = {
    907    // FIPS level1 -> level1 -> level1
    908    {"", "", ""},
    909    // FIPS level1 -> level1 -> level2
    910    {"", "", "strong-_123"},
    911    // FIXME: this should work: FIPS level1 -> level2 -> level2
    912    // {"", "strong-_123", "strong-_456"},
    913    // FIPS level2 -> level2 -> level2
    914    {"strong-_123", "strong-_456", "strong-_123"}};
    915 
    916 const std::vector<std::string> kFipsPasswordBadCases[] = {
    917    // FIPS level1 -> level2 -> level1
    918    {"", "strong-_123", ""},
    919    // FIPS level2 -> level1 -> level1
    920    {"strong-_123", ""},
    921    // FIPS level2 -> level2 -> level1
    922    {"strong-_123", "strong-_456", ""},
    923    // initialize with a weak password
    924    {"weak"},
    925    // FIPS level1 -> weak password
    926    {"", "weak"},
    927    // FIPS level2 -> weak password
    928    {"strong-_123", "weak"}};
    929 
    930 class SoftokenFipsPasswordTest
    931    : public SoftokenFipsTest,
    932      public ::testing::WithParamInterface<std::vector<std::string>> {};
    933 
    934 class SoftokenFipsBadPasswordTest
    935    : public SoftokenFipsTest,
    936      public ::testing::WithParamInterface<std::vector<std::string>> {};
    937 
    938 TEST_P(SoftokenFipsPasswordTest, SetPassword) {
    939  const std::vector<std::string> &passwords = GetParam();
    940  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    941  ASSERT_TRUE(slot);
    942 
    943  auto it = passwords.begin();
    944  auto prev_it = it;
    945  EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, (*it).c_str()));
    946  for (it++; it != passwords.end(); it++, prev_it++) {
    947    EXPECT_EQ(SECSuccess,
    948              PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str()));
    949  }
    950 }
    951 
    952 TEST_P(SoftokenFipsBadPasswordTest, SetBadPassword) {
    953  const std::vector<std::string> &passwords = GetParam();
    954  ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
    955  ASSERT_TRUE(slot);
    956 
    957  auto it = passwords.begin();
    958  auto prev_it = it;
    959  SECStatus rv = PK11_InitPin(slot.get(), nullptr, (*it).c_str());
    960  if (it + 1 == passwords.end())
    961    EXPECT_EQ(SECFailure, rv);
    962  else
    963    EXPECT_EQ(SECSuccess, rv);
    964  for (it++; it != passwords.end(); it++, prev_it++) {
    965    rv = PK11_ChangePW(slot.get(), (*prev_it).c_str(), (*it).c_str());
    966    if (it + 1 == passwords.end())
    967      EXPECT_EQ(SECFailure, rv);
    968    else
    969      EXPECT_EQ(SECSuccess, rv);
    970  }
    971 }
    972 
    973 class SoftokenFipsDhValidate
    974    : public SoftokenFipsDhTest,
    975      public ::testing::WithParamInterface<DhTestVector> {};
    976 
    977 /* test the DH validation process. In fips mode, primes with unknown
    978 * subprimes, and all sorts of bad public keys should fail */
    979 TEST_P(SoftokenFipsDhValidate, DhVectors) {
    980  const DhTestVector dhTestValues = GetParam();
    981  std::string testId = (char *)(dhTestValues.id);
    982  std::string err = "Test(" + testId + ") failed";
    983  time_t time;
    984  PRBool genFailOK = PR_FALSE;
    985  SECStatus rv;
    986 
    987  PQGParams params;
    988  params.prime = dhTestValues.p;
    989  params.base = dhTestValues.g;
    990  params.subPrime = dhTestValues.q;
    991  std::cerr << "Test:" + testId << std::endl
    992            << "param_type: " << param_value(dhTestValues.param_type)
    993            << ", key_class: " << key_value(dhTestValues.key_class) << std::endl
    994            << "p: " << DataBuffer(dhTestValues.p.data, dhTestValues.p.len)
    995            << std::endl
    996            << "g: " << DataBuffer(dhTestValues.g.data, dhTestValues.g.len)
    997            << std::endl
    998            << "q: " << DataBuffer(dhTestValues.q.data, dhTestValues.q.len)
    999            << std::endl
   1000            << "pub_key: "
   1001            << DataBuffer(dhTestValues.pub_key.data, dhTestValues.pub_key.len)
   1002            << std::endl;
   1003 
   1004  if ((dhTestValues.param_type != TLS_APPROVED) &&
   1005      (dhTestValues.param_type != IKE_APPROVED)) {
   1006    genFailOK = PR_TRUE;
   1007  }
   1008  rv = test_dh_value(&params, &dhTestValues.pub_key, genFailOK, &time);
   1009 
   1010  switch (dhTestValues.param_type) {
   1011    case TLS_APPROVED:
   1012    case IKE_APPROVED:
   1013      EXPECT_EQ(SECSuccess, rv) << err;
   1014 #ifdef NSS_USE_TIMING_CODE
   1015      EXPECT_LE(time, reference_time[dhTestValues.key_class]) << err;
   1016 #endif
   1017      break;
   1018    case SAFE_PRIME:
   1019    case SAFE_PRIME_WITH_SUBPRIME:
   1020    case KNOWN_SUBPRIME:
   1021    case UNKNOWN_SUBPRIME:
   1022    case WRONG_SUBPRIME:
   1023    case BAD_PUB_KEY:
   1024      EXPECT_EQ(SECFailure, rv) << err;
   1025      break;
   1026  }
   1027 }
   1028 
   1029 INSTANTIATE_TEST_SUITE_P(FipsPasswordCases, SoftokenFipsPasswordTest,
   1030                         ::testing::ValuesIn(kFipsPasswordCases));
   1031 
   1032 INSTANTIATE_TEST_SUITE_P(BadFipsPasswordCases, SoftokenFipsBadPasswordTest,
   1033                         ::testing::ValuesIn(kFipsPasswordBadCases));
   1034 
   1035 INSTANTIATE_TEST_SUITE_P(FipsDhCases, SoftokenFipsDhValidate,
   1036                         ::testing::ValuesIn(DH_TEST_VECTORS));
   1037 #endif
   1038 
   1039 }  // namespace nss_test
   1040 
   1041 int main(int argc, char **argv) {
   1042  ::testing::InitGoogleTest(&argc, argv);
   1043 
   1044  return RUN_ALL_TESTS();
   1045 }