summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Keeler <dkeeler@mozilla.com>2017-08-01 16:45:07 +0200
committerDavid Keeler <dkeeler@mozilla.com>2017-08-01 16:45:07 +0200
commitabe0fcdc657265eafe226c96c629bc716ac85b77 (patch)
tree7c038b73963c07b5c515da1e24e29d29dec2b575
parent36b1a750357ba5d8cf9eb2b887e92c880535790a (diff)
downloadnss-hg-abe0fcdc657265eafe226c96c629bc716ac85b77.tar.gz
Bug 1379273 - make softoken resettable via PK11_ResetToken r=franziskus,ttaubert
Summary: Two issues prevented PK11_ResetToken from working properly: 1. The backing DB tables would be dropped and never recreated, preventing future operations from working. 2. The needLogin property of the SFTKSlot would not be updated properly, preventing PK11_InitPin (and thus other operations) from succeeding. Reviewers: ttaubert, franziskus Reviewed By: ttaubert, franziskus Differential Revision: https://nss-review.dev.mozaws.net/D382
-rw-r--r--gtests/manifest.mn3
-rw-r--r--gtests/softoken_gtest/Makefile45
-rw-r--r--gtests/softoken_gtest/manifest.mn25
-rw-r--r--gtests/softoken_gtest/softoken_gtest.cc132
-rw-r--r--gtests/softoken_gtest/softoken_gtest.gyp51
-rw-r--r--lib/softoken/pkcs11.c14
-rw-r--r--lib/softoken/sdb.c24
-rw-r--r--nss.gyp1
-rwxr-xr-xtests/gtests/gtests.sh2
9 files changed, 275 insertions, 22 deletions
diff --git a/gtests/manifest.mn b/gtests/manifest.mn
index 1ae4cab77..3bc366432 100644
--- a/gtests/manifest.mn
+++ b/gtests/manifest.mn
@@ -23,8 +23,9 @@ NSS_SRCDIRS = \
certdb_gtest \
certhigh_gtest \
pk11_gtest \
+ softoken_gtest \
ssl_gtest \
- nss_bogo_shim \
+ nss_bogo_shim \
$(NULL)
endif
endif
diff --git a/gtests/softoken_gtest/Makefile b/gtests/softoken_gtest/Makefile
new file mode 100644
index 000000000..996669782
--- /dev/null
+++ b/gtests/softoken_gtest/Makefile
@@ -0,0 +1,45 @@
+#! gmake
+#
+# 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/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include ../common/gtest.mk
+
+CFLAGS += -I$(CORE_DEPTH)/lib/util
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
diff --git a/gtests/softoken_gtest/manifest.mn b/gtests/softoken_gtest/manifest.mn
new file mode 100644
index 000000000..4b34c099f
--- /dev/null
+++ b/gtests/softoken_gtest/manifest.mn
@@ -0,0 +1,25 @@
+# -*- makefile -*-
+# 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/.
+CORE_DEPTH = ../..
+DEPTH = ../..
+MODULE = nss
+
+CPPSRCS = \
+ softoken_gtest.cc \
+ $(NULL)
+
+INCLUDES += \
+ -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
+ -I$(CORE_DEPTH)/cpputil \
+ $(NULL)
+
+REQUIRES = nspr gtest
+
+PROGRAM = softoken_gtest
+
+EXTRA_LIBS = \
+ $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) \
+ $(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX) \
+ $(NULL)
diff --git a/gtests/softoken_gtest/softoken_gtest.cc b/gtests/softoken_gtest/softoken_gtest.cc
new file mode 100644
index 000000000..f0e4be9f9
--- /dev/null
+++ b/gtests/softoken_gtest/softoken_gtest.cc
@@ -0,0 +1,132 @@
+#include <cstdlib>
+
+#include "nspr.h"
+#include "nss.h"
+#include "pk11pub.h"
+
+#include "scoped_ptrs.h"
+
+#define GTEST_HAS_RTTI 0
+#include "gtest/gtest.h"
+
+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; }
+
+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;
+};
+
+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);
+}
+
+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-") { }
+
+ virtual void SetUp() {
+ std::string nssInitArg("sql:");
+ nssInitArg.append(mNSSDBDir.GetPath());
+ ASSERT_EQ(SECSuccess, NSS_Initialize(nssInitArg.c_str(), "", "", SECMOD_DB,
+ NSS_INIT_NOROOTINIT));
+ }
+
+ virtual void TearDown() {
+ ASSERT_EQ(SECSuccess, NSS_Shutdown());
+ const std::string& nssDBDirPath = mNSSDBDir.GetPath();
+ ASSERT_EQ(0, unlink((nssDBDirPath + "/cert9.db").c_str()));
+ ASSERT_EQ(0, unlink((nssDBDirPath + "/key4.db").c_str()));
+ ASSERT_EQ(0, unlink((nssDBDirPath + "/pkcs11.txt").c_str()));
+ }
+
+ ScopedUniqueDirectory mNSSDBDir;
+};
+
+TEST_F(SoftokenTest, ResetSoftokenEmptyPassword) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+ ASSERT_TRUE(slot);
+ EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
+ EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
+ EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, nullptr));
+}
+
+TEST_F(SoftokenTest, ResetSoftokenNonEmptyPassword) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot());
+ ASSERT_TRUE(slot);
+ EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password"));
+ EXPECT_EQ(SECSuccess, PK11_ResetToken(slot.get(), nullptr));
+ EXPECT_EQ(SECSuccess, PK11_InitPin(slot.get(), nullptr, "password2"));
+}
+
+} // namespace nss_test
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/gtests/softoken_gtest/softoken_gtest.gyp b/gtests/softoken_gtest/softoken_gtest.gyp
new file mode 100644
index 000000000..cff0ea414
--- /dev/null
+++ b/gtests/softoken_gtest/softoken_gtest.gyp
@@ -0,0 +1,51 @@
+# 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/.
+{
+ 'includes': [
+ '../../coreconf/config.gypi',
+ '../common/gtest.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'softoken_gtest',
+ 'type': 'executable',
+ 'sources': [
+ 'softoken_gtest.cc',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports',
+ '<(DEPTH)/lib/util/util.gyp:nssutil3',
+ '<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
+ ],
+ 'conditions': [
+ [ 'test_build==1', {
+ 'dependencies': [
+ '<(DEPTH)/lib/nss/nss.gyp:nss_static',
+ '<(DEPTH)/lib/pk11wrap/pk11wrap.gyp:pk11wrap_static',
+ '<(DEPTH)/lib/cryptohi/cryptohi.gyp:cryptohi',
+ '<(DEPTH)/lib/certhigh/certhigh.gyp:certhi',
+ '<(DEPTH)/lib/certdb/certdb.gyp:certdb',
+ '<(DEPTH)/lib/base/base.gyp:nssb',
+ '<(DEPTH)/lib/dev/dev.gyp:nssdev',
+ '<(DEPTH)/lib/pki/pki.gyp:nsspki',
+ '<(DEPTH)/lib/ssl/ssl.gyp:ssl',
+ ],
+ }, {
+ 'dependencies': [
+ '<(DEPTH)/lib/nss/nss.gyp:nss3',
+ '<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
+ ],
+ }],
+ ],
+ }
+ ],
+ 'target_defaults': {
+ 'include_dirs': [
+ '../../lib/util'
+ ]
+ },
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
index a594fd501..4e940990e 100644
--- a/lib/softoken/pkcs11.c
+++ b/lib/softoken/pkcs11.c
@@ -3566,7 +3566,6 @@ NSC_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin,
{
SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
SFTKDBHandle *handle;
- SFTKDBHandle *certHandle;
SECStatus rv;
unsigned int i;
SFTKObject *object;
@@ -3614,19 +3613,16 @@ NSC_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin,
}
rv = sftkdb_ResetKeyDB(handle);
+ /* clear the password */
+ sftkdb_ClearPassword(handle);
+ /* update slot->needLogin (should be true now since no password is set) */
+ sftk_checkNeedLogin(slot, handle);
sftk_freeDB(handle);
if (rv != SECSuccess) {
return CKR_DEVICE_ERROR;
}
- /* finally mark all the user certs as non-user certs */
- certHandle = sftk_getCertDB(slot);
- if (certHandle == NULL)
- return CKR_OK;
-
- sftk_freeDB(certHandle);
-
- return CKR_OK; /*is this the right function for not implemented*/
+ return CKR_OK;
}
/* NSC_InitPIN initializes the normal user's PIN. */
diff --git a/lib/softoken/sdb.c b/lib/softoken/sdb.c
index eb625b6cb..57337e334 100644
--- a/lib/softoken/sdb.c
+++ b/lib/softoken/sdb.c
@@ -1600,7 +1600,7 @@ loser:
return error;
}
-static const char RESET_CMD[] = "DROP TABLE IF EXISTS %s;";
+static const char RESET_CMD[] = "DELETE FROM %s;";
CK_RV
sdb_Reset(SDB *sdb)
{
@@ -1621,17 +1621,19 @@ sdb_Reset(SDB *sdb)
goto loser;
}
- /* delete the key table */
- newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table);
- if (newStr == NULL) {
- error = CKR_HOST_MEMORY;
- goto loser;
- }
- sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
- sqlite3_free(newStr);
+ if (tableExists(sqlDB, sdb_p->table)) {
+ /* delete the contents of the key table */
+ newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table);
+ if (newStr == NULL) {
+ error = CKR_HOST_MEMORY;
+ goto loser;
+ }
+ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
+ sqlite3_free(newStr);
- if (sqlerr != SQLITE_OK)
- goto loser;
+ if (sqlerr != SQLITE_OK)
+ goto loser;
+ }
/* delete the password entry table */
sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;",
diff --git a/nss.gyp b/nss.gyp
index e62d28449..1727dbe0b 100644
--- a/nss.gyp
+++ b/nss.gyp
@@ -168,6 +168,7 @@
'gtests/certdb_gtest/certdb_gtest.gyp:certdb_gtest',
'gtests/freebl_gtest/freebl_gtest.gyp:prng_gtest',
'gtests/pk11_gtest/pk11_gtest.gyp:pk11_gtest',
+ 'gtests/softoken_gtest/softoken_gtest.gyp:softoken_gtest',
'gtests/ssl_gtest/ssl_gtest.gyp:ssl_gtest',
'gtests/util_gtest/util_gtest.gyp:util_gtest',
'gtests/nss_bogo_shim/nss_bogo_shim.gyp:nss_bogo_shim',
diff --git a/tests/gtests/gtests.sh b/tests/gtests/gtests.sh
index c785241c4..6de1ee4b7 100755
--- a/tests/gtests/gtests.sh
+++ b/tests/gtests/gtests.sh
@@ -83,7 +83,7 @@ gtest_cleanup()
}
################## main #################################################
-GTESTS="prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest"
+GTESTS="prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest"
SOURCE_DIR="$PWD"/../..
gtest_init $0
gtest_start