diff --git a/.gitignore b/.gitignore index b0ffa84..4befa78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -SOURCES/PayPalEE.cert SOURCES/blank-cert8.db SOURCES/blank-cert9.db SOURCES/blank-key3.db SOURCES/blank-key4.db SOURCES/blank-secmod.db -SOURCES/nss-3.67.tar.gz +SOURCES/nss-3.79.tar.gz diff --git a/.nss.metadata b/.nss.metadata index 46cc0d2..b374a5a 100644 --- a/.nss.metadata +++ b/.nss.metadata @@ -1,7 +1,6 @@ -bc5c03643bfa1a5ea8519b8e7e2d7d5e30abea30 SOURCES/PayPalEE.cert d272a7b58364862613d44261c5744f7a336bf177 SOURCES/blank-cert8.db b5570125fbf6bfb410705706af48217a0817c03a SOURCES/blank-cert9.db 7f78b5bcecdb5005e7b803604b2ec9d1a9df2fb5 SOURCES/blank-key3.db f9c9568442386da370193474de1b25c3f68cdaf6 SOURCES/blank-key4.db bd748cf6e1465a1bbe6e751b72ffc0076aff0b50 SOURCES/blank-secmod.db -9cccf98f0476905c0d863a6b2cb08a1955482241 SOURCES/nss-3.67.tar.gz +3719dd97c8ec9cb04aa61e6aca41b129b4adc004 SOURCES/nss-3.79.tar.gz diff --git a/SOURCES/nss-3.44-kbkdf-coverity.patch b/SOURCES/nss-3.44-kbkdf-coverity.patch deleted file mode 100644 index 1ef1d8d..0000000 --- a/SOURCES/nss-3.44-kbkdf-coverity.patch +++ /dev/null @@ -1,39 +0,0 @@ -diff -up ./lib/softoken/kbkdf.c.coverity ./lib/softoken/kbkdf.c ---- ./lib/softoken/kbkdf.c.coverity 2019-12-03 15:33:43.047732312 -0800 -+++ ./lib/softoken/kbkdf.c 2019-12-03 15:39:40.982578357 -0800 -@@ -534,6 +534,10 @@ CK_RV kbkdf_CreateKey(CK_SESSION_HANDLE - PR_ASSERT(derived_key != NULL); - PR_ASSERT(derived_key->phKey != NULL); - -+ if (slot == NULL) { -+ return CKR_SESSION_HANDLE_INVALID; -+ } -+ - /* Create the new key object for this additional derived key. */ - key = sftk_NewObject(slot); - if (key == NULL) { -@@ -589,7 +593,9 @@ done: - sftk_FreeObject(key); - - /* Doesn't do anything. */ -- sftk_FreeSession(session); -+ if (session) { -+ sftk_FreeSession(session); -+ } - - return ret; - } -diff -up ./lib/softoken/sftkhmac.c.coverity ./lib/softoken/sftkhmac.c ---- ./lib/softoken/sftkhmac.c.coverity 2019-12-03 15:40:06.108848341 -0800 -+++ ./lib/softoken/sftkhmac.c 2019-12-03 15:41:04.919480267 -0800 -@@ -232,7 +232,9 @@ sftk_MAC_Init(sftk_MACCtx *ctx, CK_MECHA - keyval->attrib.ulValueLen, isFIPS); - - done: -- sftk_FreeAttribute(keyval); -+ if (keyval) { -+ sftk_FreeAttribute(keyval); -+ } - return ret; - } - diff --git a/SOURCES/nss-3.53.1-measure-fix.patch b/SOURCES/nss-3.53.1-measure-fix.patch deleted file mode 100644 index a312936..0000000 --- a/SOURCES/nss-3.53.1-measure-fix.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -up ./coreconf/config.gypi.orig ./coreconf/config.gypi ---- ./coreconf/config.gypi.orig 2020-06-16 15:50:59.000000000 -0700 -+++ ./coreconf/config.gypi 2020-10-15 16:05:37.542761192 -0700 -@@ -363,7 +363,7 @@ - '_DEFAULT_SOURCE', # for functions, strdup, realpath, and getentropy - '_BSD_SOURCE', # for the above in glibc <= 2.19 - '_POSIX_SOURCE', # for -- 'SQL_MEASURE_USE_TEMP_DIR', # use tmpdir for the access calls -+ 'SDB_MEASURE_USE_TEMP_DIR', # use tmpdir for the access calls - ], - }], - [ 'OS=="dragonfly" or OS=="freebsd"', { -diff -up ./coreconf/Linux.mk.orig ./coreconf/Linux.mk ---- ./coreconf/Linux.mk.orig 2020-10-15 16:05:04.794591674 -0700 -+++ ./coreconf/Linux.mk 2020-10-15 16:05:37.543761197 -0700 -@@ -21,7 +21,7 @@ ifeq ($(USE_PTHREADS),1) - endif - - DEFAULT_COMPILER = gcc --DEFINES += -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_SOURCE -DSQL_MEASURE_USE_TEMP_DIR -+DEFINES += -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_SOURCE -DSDB_MEASURE_USE_TEMP_DIR - - ifeq ($(OS_TARGET),Android) - ifndef ANDROID_NDK diff --git a/SOURCES/nss-3.66-fix-gtest-parsing.patch b/SOURCES/nss-3.66-fix-gtest-parsing.patch deleted file mode 100644 index 7e5ff4b..0000000 --- a/SOURCES/nss-3.66-fix-gtest-parsing.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff -up ./tests/common/parsegtestreport.sed.new_gtest ./tests/common/parsegtestreport.sed ---- ./tests/common/parsegtestreport.sed.new_gtest 2021-06-17 16:26:49.361035662 -0700 -+++ ./tests/common/parsegtestreport.sed 2021-06-17 16:49:08.512261136 -0700 -@@ -1,8 +1,11 @@ - /\len) { - case 1536 / PR_BITS_PER_BYTE: -+ /* don't accept 1536 bit primes in FIPS mode */ -+ if (isFIPS) { -+ break; -+ } - if (PORT_Memcmp(dhPrime->data, prime_ike_1536, - sizeof(prime_ike_1536)) == 0) { - return &subprime_ike_1536; diff --git a/SOURCES/nss-3.67-cve-2021-43527-test.patch b/SOURCES/nss-3.67-cve-2021-43527-test.patch deleted file mode 100644 index 51cb8e0..0000000 --- a/SOURCES/nss-3.67-cve-2021-43527-test.patch +++ /dev/null @@ -1,325 +0,0 @@ -diff --git a/tests/cert/Leaf-bogus-dsa.crt b/tests/cert/Leaf-bogus-dsa.crt -new file mode 100644 ---- /dev/null -+++ b/tests/cert/Leaf-bogus-dsa.crt -@@ -0,0 +1,143 @@ -+-----BEGIN CERTIFICATE----- -+MIIaZzCCCkWgAwIBAgIBATALBgcqhkjOOAQDBQAwMTEvMC0GA1UEAxMmZGVjb2Rl -+RUNvckRTQVNpZ25hdHVyZS10ZXN0Q2FzZS90YXZpc28wHhcNMjEwMTAxMDAwMDAw -+WhcNNDEwMTAxMDAwMDAwWjAxMS8wLQYDVQQDEyZkZWNvZGVFQ29yRFNBU2lnbmF0 -+dXJlLXRlc3RDYXNlL3RhdmlzbzCCCaYwggkaBgcqhkjOOAQBMIIJDQKBgQCqqqqq -+qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq -+qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq -+qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqgKCCAEAu7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7 -+u7u7u7u7u7u7u7u7u7u7u7sCgYEAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM -+zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM -+zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM -+zMzMzMwDgYUAAoGB3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d -+3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d -+3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3dMAkG -+ByqGSM44BAMDghAPADCCEAoCgggBAO7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u -+7u7u7u7uAoIIAQD///////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////// -+/////////////////////////////////////////////////////////w== -+-----END CERTIFICATE----- -diff --git a/tests/cert/Leaf-bogus-rsa-pss.crt b/tests/cert/Leaf-bogus-rsa-pss.crt -new file mode 100644 ---- /dev/null -+++ b/tests/cert/Leaf-bogus-rsa-pss.crt -@@ -0,0 +1,126 @@ -+-----BEGIN CERTIFICATE----- -+MIIXODCCC/WgAwIBAgIBAjApBgkqhkiG9w0BAQowHKACMAChETAPBQAwCwYJYIZI -+AWUDBAIBogMCASAwNzEgMB4GCSqGSIb3DQEJARYRdGF2aXNvQGdvb2dsZS5jb20x -+EzARBgNVBAMTCmJ1ZzE3Mzc0NzAwHhcNMjAwMTAxMDAwMDAwWhcNNDAwMTAxMDAw -+MDAwWjA3MSAwHgYJKoZIhvcNAQkBFhF0YXZpc29AZ29vZ2xlLmNvbTETMBEGA1UE -+AxMKYnVnMTczNzQ3MDCCCywwDQYJKoZIhvcNAQEBBQADggsZADCCCxQCggsLAMRE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERE -+RERERERERERERERERERERERERERERERERERERERERERERERERERERQIDAQABMC4G -+CSqGSIb3DQEBCjAhoRowGAYJKoZIhvcNAQEIMAsGCSqGSIb3DQEBCqIDAgEgA4IL -+CwAAxVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV -+VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVU= -+-----END CERTIFICATE----- -diff --git a/tests/cert/cert.sh b/tests/cert/cert.sh ---- a/tests/cert/cert.sh -+++ b/tests/cert/cert.sh -@@ -114,16 +114,28 @@ certu() - cert_log "ERROR: ${CU_ACTION} failed $RET" - else - html_passed "${CU_ACTION}" - fi - - return $RET - } - -+cert_test_vfy() -+{ -+ echo "$SCRIPTNAME: Verify large rsa pss signature --------------" -+ echo " vfychain -a Leaf-bogus-dsa.crt" -+ vfychain -a ${QADIR}/cert/Leaf-bogus-dsa.crt -+ html_msg $? 1 "Verify large dsa signature" -+ echo "$SCRIPTNAME: Verify large rsa pss signature --------------" -+ echo " vfychain -a Leaf-bogus-rsa-pss.crt" -+ vfychain -a ${QADIR}/cert/Leaf-bogus-rsa-pss.crt -+ html_msg $? 1 "Verify large rsa pss signature" -+} -+ - ################################ crlu ################################# - # local shell function to call crlutil, also: writes action and options to - # stdout, sets variable RET and writes results to the html file results - ######################################################################## - crlu() - { - echo "$SCRIPTNAME: ${CU_ACTION} --------------------------" - -@@ -2640,11 +2652,13 @@ if [ -z "$NSS_TEST_DISABLE_CRL" ] ; then - else - echo "$SCRIPTNAME: Skipping CRL Tests" - fi - - if [ -n "$DO_DIST_ST" -a "$DO_DIST_ST" = "TRUE" ] ; then - cert_stresscerts - fi - -+cert_test_vfy -+ - cert_iopr_setup - - cert_cleanup diff --git a/SOURCES/nss-3.67-cve-2021-43527.patch b/SOURCES/nss-3.67-cve-2021-43527.patch deleted file mode 100644 index 8fc81d3..0000000 --- a/SOURCES/nss-3.67-cve-2021-43527.patch +++ /dev/null @@ -1,279 +0,0 @@ -diff --git a/lib/cryptohi/secvfy.c b/lib/cryptohi/secvfy.c ---- a/lib/cryptohi/secvfy.c -+++ b/lib/cryptohi/secvfy.c -@@ -164,6 +164,37 @@ - PR_FALSE /*XXX: unsafeAllowMissingParameters*/); - } - -+static unsigned int -+checkedSignatureLen(const SECKEYPublicKey *pubk) -+{ -+ unsigned int sigLen = SECKEY_SignatureLen(pubk); -+ if (sigLen == 0) { -+ /* Error set by SECKEY_SignatureLen */ -+ return sigLen; -+ } -+ unsigned int maxSigLen; -+ switch (pubk->keyType) { -+ case rsaKey: -+ case rsaPssKey: -+ maxSigLen = (RSA_MAX_MODULUS_BITS + 7) / 8; -+ break; -+ case dsaKey: -+ maxSigLen = DSA_MAX_SIGNATURE_LEN; -+ break; -+ case ecKey: -+ maxSigLen = 2 * MAX_ECKEY_LEN; -+ break; -+ default: -+ PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); -+ return 0; -+ } -+ if (sigLen > maxSigLen) { -+ PORT_SetError(SEC_ERROR_INVALID_KEY); -+ return 0; -+ } -+ return sigLen; -+} -+ - /* - * decode the ECDSA or DSA signature from it's DER wrapping. - * The unwrapped/raw signature is placed in the buffer pointed -@@ -174,38 +205,38 @@ - unsigned int len) - { - SECItem *dsasig = NULL; /* also used for ECDSA */ -- SECStatus rv = SECSuccess; - -- if ((algid != SEC_OID_ANSIX9_DSA_SIGNATURE) && -- (algid != SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { -- if (sig->len != len) { -- PORT_SetError(SEC_ERROR_BAD_DER); -- return SECFailure; -+ /* Safety: Ensure algId is as expected and that signature size is within maxmimums */ -+ if (algid == SEC_OID_ANSIX9_DSA_SIGNATURE) { -+ if (len > DSA_MAX_SIGNATURE_LEN) { -+ goto loser; - } -- -- PORT_Memcpy(dsig, sig->data, sig->len); -- return SECSuccess; -+ } else if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { -+ if (len > MAX_ECKEY_LEN * 2) { -+ goto loser; -+ } -+ } else { -+ goto loser; - } - -- if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { -- if (len > MAX_ECKEY_LEN * 2) { -- PORT_SetError(SEC_ERROR_BAD_DER); -- return SECFailure; -- } -+ /* Decode and pad to length */ -+ dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); -+ if (dsasig == NULL) { -+ goto loser; - } -- dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); -- -- if ((dsasig == NULL) || (dsasig->len != len)) { -- rv = SECFailure; -- } else { -- PORT_Memcpy(dsig, dsasig->data, dsasig->len); -+ if (dsasig->len != len) { -+ SECITEM_FreeItem(dsasig, PR_TRUE); -+ goto loser; - } - -- if (dsasig != NULL) -- SECITEM_FreeItem(dsasig, PR_TRUE); -- if (rv == SECFailure) -- PORT_SetError(SEC_ERROR_BAD_DER); -- return rv; -+ PORT_Memcpy(dsig, dsasig->data, len); -+ SECITEM_FreeItem(dsasig, PR_TRUE); -+ -+ return SECSuccess; -+ -+loser: -+ PORT_SetError(SEC_ERROR_BAD_DER); -+ return SECFailure; - } - - const SEC_ASN1Template hashParameterTemplate[] = -@@ -281,7 +312,7 @@ - sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, - const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg) - { -- int len; -+ unsigned int len; - PLArenaPool *arena; - SECStatus rv; - SECItem oid; -@@ -466,48 +497,52 @@ - cx->pkcs1RSADigestInfo = NULL; - rv = SECSuccess; - if (sig) { -- switch (type) { -- case rsaKey: -- rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, -- &cx->pkcs1RSADigestInfo, -- &cx->pkcs1RSADigestInfoLen, -- cx->key, -- sig, wincx); -- break; -- case rsaPssKey: -- sigLen = SECKEY_SignatureLen(key); -- if (sigLen == 0) { -- /* error set by SECKEY_SignatureLen */ -- rv = SECFailure; -+ rv = SECFailure; -+ if (type == rsaKey) { -+ rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, -+ &cx->pkcs1RSADigestInfo, -+ &cx->pkcs1RSADigestInfoLen, -+ cx->key, -+ sig, wincx); -+ } else { -+ sigLen = checkedSignatureLen(key); -+ /* Check signature length is within limits */ -+ if (sigLen == 0) { -+ /* error set by checkedSignatureLen */ -+ rv = SECFailure; -+ goto loser; -+ } -+ if (sigLen > sizeof(cx->u)) { -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); -+ rv = SECFailure; -+ goto loser; -+ } -+ switch (type) { -+ case rsaPssKey: -+ if (sig->len != sigLen) { -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); -+ rv = SECFailure; -+ goto loser; -+ } -+ PORT_Memcpy(cx->u.buffer, sig->data, sigLen); -+ rv = SECSuccess; - break; -- } -- if (sig->len != sigLen) { -- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); -+ case ecKey: -+ case dsaKey: -+ /* decodeECorDSASignature will check sigLen == sig->len after padding */ -+ rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); -+ break; -+ default: -+ /* Unreachable */ - rv = SECFailure; -- break; -- } -- PORT_Memcpy(cx->u.buffer, sig->data, sigLen); -- break; -- case dsaKey: -- case ecKey: -- sigLen = SECKEY_SignatureLen(key); -- if (sigLen == 0) { -- /* error set by SECKEY_SignatureLen */ -- rv = SECFailure; -- break; -- } -- rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen); -- break; -- default: -- rv = SECFailure; -- PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); -- break; -+ goto loser; -+ } -+ } -+ if (rv != SECSuccess) { -+ goto loser; - } - } - -- if (rv) -- goto loser; -- - /* check hash alg again, RSA may have changed it.*/ - if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { - /* error set by HASH_GetHashTypeByOidTag */ -@@ -650,11 +685,16 @@ - switch (cx->key->keyType) { - case ecKey: - case dsaKey: -- dsasig.data = cx->u.buffer; -- dsasig.len = SECKEY_SignatureLen(cx->key); -+ dsasig.len = checkedSignatureLen(cx->key); - if (dsasig.len == 0) { - return SECFailure; - } -+ if (dsasig.len > sizeof(cx->u)) { -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); -+ return SECFailure; -+ } -+ dsasig.data = cx->u.buffer; -+ - if (sig) { - rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data, - dsasig.len); -@@ -686,8 +726,13 @@ - } - - rsasig.data = cx->u.buffer; -- rsasig.len = SECKEY_SignatureLen(cx->key); -+ rsasig.len = checkedSignatureLen(cx->key); - if (rsasig.len == 0) { -+ /* Error set by checkedSignatureLen */ -+ return SECFailure; -+ } -+ if (rsasig.len > sizeof(cx->u)) { -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - return SECFailure; - } - if (sig) { -@@ -749,7 +794,6 @@ - SECStatus rv; - VFYContext *cx; - SECItem dsasig; /* also used for ECDSA */ -- - rv = SECFailure; - - cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); -@@ -757,19 +801,25 @@ - switch (key->keyType) { - case rsaKey: - rv = verifyPKCS1DigestInfo(cx, digest); -+ /* Error (if any) set by verifyPKCS1DigestInfo */ - break; -- case dsaKey: - case ecKey: -+ case dsaKey: - dsasig.data = cx->u.buffer; -- dsasig.len = SECKEY_SignatureLen(cx->key); -+ dsasig.len = checkedSignatureLen(cx->key); - if (dsasig.len == 0) { -+ /* Error set by checkedSignatureLen */ -+ rv = SECFailure; - break; - } -- if (PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx) != -- SECSuccess) { -+ if (dsasig.len > sizeof(cx->u)) { - PORT_SetError(SEC_ERROR_BAD_SIGNATURE); -- } else { -- rv = SECSuccess; -+ rv = SECFailure; -+ break; -+ } -+ rv = PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx); -+ if (rv != SECSuccess) { -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); - } - break; - default: - diff --git a/SOURCES/nss-3.67-fix-coverity-issues.patch b/SOURCES/nss-3.67-fix-coverity-issues.patch deleted file mode 100644 index a68fa57..0000000 --- a/SOURCES/nss-3.67-fix-coverity-issues.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -up ./lib/pk11wrap/pk11cxt.c.coverity ./lib/pk11wrap/pk11cxt.c ---- ./lib/pk11wrap/pk11cxt.c.coverity 2021-06-18 09:36:19.499203028 -0700 -+++ ./lib/pk11wrap/pk11cxt.c 2021-06-18 09:37:57.993765299 -0700 -@@ -382,7 +382,7 @@ pk11_CreateNewContextInSlot(CK_MECHANISM - * of the connection.*/ - context->fortezzaHack = PR_FALSE; - if (type == CKM_SKIPJACK_CBC64) { -- if (symKey->origin == PK11_OriginFortezzaHack) { -+ if (symKey && (symKey->origin == PK11_OriginFortezzaHack)) { - context->fortezzaHack = PR_TRUE; - } - } -diff -up ./lib/pk11wrap/pk11hpke.c.coverity ./lib/pk11wrap/pk11hpke.c ---- ./lib/pk11wrap/pk11hpke.c.coverity 2021-06-18 13:40:05.410644464 -0700 -+++ ./lib/pk11wrap/pk11hpke.c 2021-06-18 13:42:40.627606469 -0700 -@@ -1164,8 +1164,6 @@ PK11_HPKE_Seal(HpkeContext *cx, const SE - unsigned char tagBuf[HASH_LENGTH_MAX]; - size_t tagLen; - unsigned int fixedBits; -- PORT_Assert(cx->baseNonce->len == sizeof(ivOut)); -- PORT_Memcpy(ivOut, cx->baseNonce->data, cx->baseNonce->len); - - /* aad may be NULL, PT may be zero-length but not NULL. */ - if (!cx || !cx->aeadContext || -@@ -1176,6 +1174,9 @@ PK11_HPKE_Seal(HpkeContext *cx, const SE - return SECFailure; - } - -+ PORT_Assert(cx->baseNonce->len == sizeof(ivOut)); -+ PORT_Memcpy(ivOut, cx->baseNonce->data, cx->baseNonce->len); -+ - tagLen = cx->aeadParams->tagLen; - maxOut = pt->len + tagLen; - fixedBits = (cx->baseNonce->len - 8) * 8; -diff -up ./lib/softoken/sftkike.c.coverity ./lib/softoken/sftkike.c ---- ./lib/softoken/sftkike.c.coverity 2021-06-18 09:33:59.633405513 -0700 -+++ ./lib/softoken/sftkike.c 2021-06-18 09:34:20.305523382 -0700 -@@ -1411,7 +1411,6 @@ sftk_fips_IKE_PowerUpSelfTests(void) - (outKeySize != sizeof(ike_known_sha256_prf_plus)) || - (PORT_Memcmp(outKeyData, ike_known_sha256_prf_plus, - sizeof(ike_known_sha256_prf_plus)) != 0)) { -- PORT_ZFree(outKeyData, outKeySize); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } diff --git a/SOURCES/nss-3.67-fix-private-key-mac.patch b/SOURCES/nss-3.67-fix-private-key-mac.patch deleted file mode 100644 index d211940..0000000 --- a/SOURCES/nss-3.67-fix-private-key-mac.patch +++ /dev/null @@ -1,81 +0,0 @@ -diff -up ./lib/softoken/sftkpwd.c.orig ./lib/softoken/sftkpwd.c ---- ./lib/softoken/sftkpwd.c.orig 2021-06-10 05:33:12.000000000 -0700 -+++ ./lib/softoken/sftkpwd.c 2021-07-01 14:04:34.068596942 -0700 -@@ -287,9 +287,12 @@ sftkdb_DecryptAttribute(SFTKDBHandle *ha - } - - /* If we are using aes 256, we need to check authentication as well.*/ -- if ((type != CKT_INVALID_TYPE) && (cipherValue.alg == SEC_OID_AES_256_CBC)) { -+ if ((type != CKT_INVALID_TYPE) && -+ (cipherValue.alg == SEC_OID_PKCS5_PBES2) && -+ (cipherValue.param->encAlg == SEC_OID_AES_256_CBC)) { - SECItem signature; - unsigned char signData[SDB_MAX_META_DATA_LEN]; -+ CK_RV crv; - - /* if we get here from the old legacy db, there is clearly an - * error, don't return the plaintext */ -@@ -301,15 +304,28 @@ sftkdb_DecryptAttribute(SFTKDBHandle *ha - - signature.data = signData; - signature.len = sizeof(signData); -- rv = sftkdb_GetAttributeSignature(handle, handle, id, type, -+ rv = SECFailure; -+ /* sign sftkdb_GetAttriibuteSignature returns a crv, not an rv */ -+ crv = sftkdb_GetAttributeSignature(handle, handle, id, type, - &signature); -- if (rv != SECSuccess) { -- goto loser; -+ if (crv == CKR_OK) { -+ rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE, -+ type, *plain, &signature); - } -- rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE, type, -- *plain, &signature); - if (rv != SECSuccess) { -- goto loser; -+ /* handle a bug where old versions of NSS misfiled the signature -+ * attribute on password update */ -+ id |= SFTK_KEYDB_TYPE|SFTK_TOKEN_TYPE; -+ signature.len = sizeof(signData); -+ crv = sftkdb_GetAttributeSignature(handle, handle, id, type, -+ &signature); -+ if (crv != CKR_OK) { -+ rv = SECFailure; -+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); -+ goto loser; -+ } -+ rv = sftkdb_VerifyAttribute(handle, passKey, CK_INVALID_HANDLE, -+ type, *plain, &signature); - } - } - -@@ -1198,6 +1214,7 @@ sftk_updateEncrypted(PLArenaPool *arena, - unsigned int i; - for (i = 0; i < privAttrCount; i++) { - // Read the old attribute in the clear. -+ CK_OBJECT_HANDLE sdbId = id & SFTK_OBJ_ID_MASK; - CK_ATTRIBUTE privAttr = { privAttrTypes[i], NULL, 0 }; - CK_RV crv = sftkdb_GetAttributeValue(keydb, id, &privAttr, 1); - if (crv != CKR_OK) { -@@ -1222,7 +1239,7 @@ sftk_updateEncrypted(PLArenaPool *arena, - plainText.data = privAttr.pValue; - plainText.len = privAttr.ulValueLen; - if (sftkdb_EncryptAttribute(arena, keydb, keydb->db, newKey, -- iterationCount, id, privAttr.type, -+ iterationCount, sdbId, privAttr.type, - &plainText, &result) != SECSuccess) { - return CKR_GENERAL_ERROR; - } -@@ -1232,10 +1249,9 @@ sftk_updateEncrypted(PLArenaPool *arena, - PORT_Memset(plainText.data, 0, plainText.len); - - // Write the newly encrypted attributes out directly. -- CK_OBJECT_HANDLE newId = id & SFTK_OBJ_ID_MASK; - keydb->newKey = newKey; - keydb->newDefaultIterationCount = iterationCount; -- crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, newId, &privAttr, 1); -+ crv = (*keydb->db->sdb_SetAttributeValue)(keydb->db, sdbId, &privAttr, 1); - keydb->newKey = NULL; - if (crv != CKR_OK) { - return crv; diff --git a/SOURCES/nss-3.67-fix-sdb-timeout.patch b/SOURCES/nss-3.67-fix-sdb-timeout.patch deleted file mode 100644 index 120cb5b..0000000 --- a/SOURCES/nss-3.67-fix-sdb-timeout.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff --git a/lib/softoken/sdb.c b/lib/softoken/sdb.c ---- a/lib/softoken/sdb.c -+++ b/lib/softoken/sdb.c -@@ -1519,16 +1519,18 @@ sdb_Begin(SDB *sdb) - - sqlerr = sqlite3_prepare_v2(sqlDB, BEGIN_CMD, -1, &stmt, NULL); - - do { - sqlerr = sqlite3_step(stmt); - if (sqlerr == SQLITE_BUSY) { - PR_Sleep(SDB_BUSY_RETRY_TIME); - } -+ /* don't retry BEGIN transaction*/ -+ retry = 0; - } while (!sdb_done(sqlerr, &retry)); - - if (stmt) { - sqlite3_reset(stmt); - sqlite3_finalize(stmt); - } - - loser: -diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c ---- a/lib/softoken/sftkdb.c -+++ b/lib/softoken/sftkdb.c -@@ -1521,17 +1521,17 @@ sftkdb_DestroyObject(SFTKDBHandle *handl - if (handle == NULL) { - return CKR_TOKEN_WRITE_PROTECTED; - } - db = SFTK_GET_SDB(handle); - objectID &= SFTK_OBJ_ID_MASK; - - crv = (*db->sdb_Begin)(db); - if (crv != CKR_OK) { -- goto loser; -+ return crv; - } - crv = (*db->sdb_DestroyObject)(db, objectID); - if (crv != CKR_OK) { - goto loser; - } - /* if the database supports meta data, delete any old signatures - * that we may have added */ - if ((db->sdb_flags & SDB_HAS_META) == SDB_HAS_META) { -@@ -2456,17 +2456,17 @@ sftkdb_Update(SFTKDBHandle *handle, SECI - return CKR_OK; - } - /* - * put the whole update under a transaction. This allows us to handle - * any possible race conditions between with the updateID check. - */ - crv = (*handle->db->sdb_Begin)(handle->db); - if (crv != CKR_OK) { -- goto loser; -+ return crv; - } - inTransaction = PR_TRUE; - - /* some one else has already updated this db */ - if (sftkdb_hasUpdate(sftkdb_TypeString(handle), - handle->db, handle->updateID)) { - crv = CKR_OK; - goto done; diff --git a/SOURCES/nss-3.67-fix-ssl-alerts.patch b/SOURCES/nss-3.67-fix-ssl-alerts.patch deleted file mode 100644 index 10cdaf5..0000000 --- a/SOURCES/nss-3.67-fix-ssl-alerts.patch +++ /dev/null @@ -1,122 +0,0 @@ -diff -up ./lib/ssl/ssl3con.c.alert-fix ./lib/ssl/ssl3con.c ---- ./lib/ssl/ssl3con.c.alert-fix 2021-06-10 05:33:12.000000000 -0700 -+++ ./lib/ssl/ssl3con.c 2021-07-06 17:08:25.894018521 -0700 -@@ -4319,7 +4319,11 @@ ssl_SignatureSchemeValid(SSLSignatureSch - if (!ssl_IsSupportedSignatureScheme(scheme)) { - return PR_FALSE; - } -- if (!ssl_SignatureSchemeMatchesSpkiOid(scheme, spkiOid)) { -+ /* if we are purposefully passed SEC_OID_UNKOWN, it means -+ * we not checking the scheme against a potential key, so skip -+ * the call */ -+ if ((spkiOid != SEC_OID_UNKNOWN) && -+ !ssl_SignatureSchemeMatchesSpkiOid(scheme, spkiOid)) { - return PR_FALSE; - } - if (isTls13) { -@@ -4517,7 +4521,8 @@ ssl_CheckSignatureSchemeConsistency(sslS - } - - /* Verify that the signature scheme matches the signing key. */ -- if (!ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13)) { -+ if ((spkiOid == SEC_OID_UNKNOWN) || -+ !ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13)) { - PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM); - return SECFailure; - } -@@ -4533,6 +4538,7 @@ ssl_CheckSignatureSchemeConsistency(sslS - PRBool - ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme) - { -+ PRBool isSupported = PR_FALSE; - switch (scheme) { - case ssl_sig_rsa_pkcs1_sha1: - case ssl_sig_rsa_pkcs1_sha256: -@@ -4552,7 +4558,8 @@ ssl_IsSupportedSignatureScheme(SSLSignat - case ssl_sig_dsa_sha384: - case ssl_sig_dsa_sha512: - case ssl_sig_ecdsa_sha1: -- return PR_TRUE; -+ isSupported = PR_TRUE; -+ break; - - case ssl_sig_rsa_pkcs1_sha1md5: - case ssl_sig_none: -@@ -4560,7 +4567,19 @@ ssl_IsSupportedSignatureScheme(SSLSignat - case ssl_sig_ed448: - return PR_FALSE; - } -- return PR_FALSE; -+ if (isSupported) { -+ SECOidTag hashOID = ssl3_HashTypeToOID(ssl_SignatureSchemeToHashType(scheme)); -+ PRUint32 policy; -+ const PRUint32 sigSchemePolicy= -+ NSS_USE_ALG_IN_SSL_KX|NSS_USE_ALG_IN_SIGNATURE; -+ /* check hash policy */ -+ if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) && -+ ((policy & sigSchemePolicy) != sigSchemePolicy)) { -+ return PR_FALSE; -+ } -+ /* check algorithm policy */ -+ } -+ return isSupported; - } - - PRBool -@@ -6533,6 +6552,9 @@ ssl_PickSignatureScheme(sslSocket *ss, - } - - spkiOid = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); -+ if (spkiOid == SEC_OID_UNKNOWN) { -+ goto loser; -+ } - - /* Now we have to search based on the key type. Go through our preferred - * schemes in order and find the first that can be used. */ -@@ -6547,6 +6569,7 @@ ssl_PickSignatureScheme(sslSocket *ss, - } - } - -+loser: - PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM); - return SECFailure; - } -@@ -7700,7 +7723,8 @@ ssl_ParseSignatureSchemes(const sslSocke - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } -- if (ssl_IsSupportedSignatureScheme((SSLSignatureScheme)tmp)) { -+ if (ssl_SignatureSchemeValid((SSLSignatureScheme)tmp, SEC_OID_UNKNOWN, -+ (PRBool)ss->version >= SSL_LIBRARY_VERSION_TLS_1_3)) {; - schemes[numSupported++] = (SSLSignatureScheme)tmp; - } - } -@@ -10286,7 +10310,12 @@ ssl3_HandleCertificateVerify(sslSocket * - PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_record); - rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); - if (rv != SECSuccess) { -- goto loser; /* malformed or unsupported. */ -+ errCode = PORT_GetError(); -+ /* unsupported == illegal_parameter, others == handshake_failure. */ -+ if (errCode == SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM) { -+ desc = illegal_parameter; -+ } -+ goto alert_loser; - } - rv = ssl_CheckSignatureSchemeConsistency( - ss, sigScheme, &ss->sec.peerCert->subjectPublicKeyInfo); -diff -up ./gtests/ssl_gtest/ssl_extension_unittest.cc.alert-fix ./gtests/ssl_gtest/ssl_extension_unittest.cc ---- ./gtests/ssl_gtest/ssl_extension_unittest.cc.alert-fix 2021-07-07 11:32:11.634376932 -0700 -+++ ./gtests/ssl_gtest/ssl_extension_unittest.cc 2021-07-07 11:33:30.595841110 -0700 -@@ -428,7 +428,10 @@ TEST_P(TlsExtensionTest12Plus, Signature - } - - TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsTrailingData) { -- const uint8_t val[] = {0x00, 0x02, 0x04, 0x01, 0x00}; // sha-256, rsa -+ // make sure the test uses an algorithm that is legal for -+ // tls 1.3 (or tls 1.3 will through and illegalParameter -+ // instead of a decode error) -+ const uint8_t val[] = {0x00, 0x02, 0x08, 0x09, 0x00}; // sha-256, rsa-pss-pss - DataBuffer extension(val, sizeof(val)); - ClientHelloErrorTest(std::make_shared( - client_, ssl_signature_algorithms_xtn, extension)); diff --git a/SOURCES/nss-3.79-dbtool.patch b/SOURCES/nss-3.79-dbtool.patch new file mode 100644 index 0000000..b61942b --- /dev/null +++ b/SOURCES/nss-3.79-dbtool.patch @@ -0,0 +1,3411 @@ +diff --git a/cmd/dbtool/Makefile b/cmd/dbtool/Makefile +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/Makefile +@@ -0,0 +1,46 @@ ++#! 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 ../platlibs.mk ++ ++####################################################################### ++# (5) Execute "global" rules. (OPTIONAL) # ++####################################################################### ++ ++include $(CORE_DEPTH)/coreconf/rules.mk ++ ++####################################################################### ++# (6) Execute "component" rules. (OPTIONAL) # ++####################################################################### ++ ++#include ../platlibs.mk ++ ++####################################################################### ++# (7) Execute "local" rules. (OPTIONAL). # ++####################################################################### ++ ++include ../platrules.mk ++ +diff --git a/cmd/dbtool/dbtool.c b/cmd/dbtool/dbtool.c +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/dbtool.c +@@ -0,0 +1,806 @@ ++/* 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/. */ ++ ++/* ++** dbtool.c ++** ++** tool to dump the underlying encoding of a database. This tool duplicates ++** some private functions in softoken. It uses libsec and libutil, but no ++** other portions of NSS. It currently only works on sqlite databases. For ++** an even more primitive dump, use sqlite3 on the individual files. ++** ++** TODO: dump the meta data for the databases. ++** optionally dump more PKCS5 information (KDF/salt/iterations) ++** take a password and decode encrypted attributes/verify signed ++** attributes. ++*/ ++#include ++#include ++ ++#if defined(WIN32) ++#include "fcntl.h" ++#include "io.h" ++#endif ++ ++#include "secutil.h" ++#include "pk11pub.h" ++ ++#if defined(XP_UNIX) ++#include ++#endif ++ ++#include "nspr.h" ++#include "prtypes.h" ++#include "certdb.h" ++#include "nss.h" ++#include "../modutil/modutil.h" ++#include "pk11table.h" ++#include "sftkdbt.h" ++#include "sdb.h" ++#include "secoid.h" ++ ++#include "plgetopt.h" ++ ++static char *progName; ++ ++char *dbDir = NULL; ++ ++static void ++Usage() ++{ ++ printf("Usage: %s [-c certprefix] [-k keyprefix] " ++ "[-V certversion] [-v keyversion]\n" ++ " [-d dbdir]\n", ++ progName); ++ printf("%-20s Directory with cert database (default is .)\n", ++ "-d certdir"); ++ printf("%-20s prefix for the cert database (default is \"\")\n", ++ "-c certprefix"); ++ printf("%-20s prefix for the key database (default is \"\")\n", ++ "-k keyprefix"); ++ printf("%-20s version of the cert database (default is 9)\n", ++ "-V certversion"); ++ printf("%-20s version of the key database (default is 4)\n", ++ "-v keyversion"); ++ exit(1); ++} ++#define SFTK_KEYDB_TYPE 0x40000000 ++#define SFTK_TOKEN_TYPE 0x80000000 ++ ++/* ++ * known attributes ++ */ ++static const CK_ATTRIBUTE_TYPE known_attributes[] = { ++ CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, ++ CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, ++ CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, ++ CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, ++ CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, ++ CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, ++ CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, ++ CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, ++ CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, ++ CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, ++ CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, ++ CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, ++ CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, ++ CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, ++ CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, ++ CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, ++ CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, ++ CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, ++ CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, ++ CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, ++ CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, ++ CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL, ++ CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, ++ CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, ++ CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, ++ CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, ++ CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, ++ CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, ++ CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, ++ CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, ++ CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, ++ CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, ++ CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, ++ CKA_NSS_DB, CKA_NSS_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS, ++ CKA_PUBLIC_KEY_INFO ++}; ++ ++static unsigned int known_attributes_size = sizeof(known_attributes) / ++ sizeof(known_attributes[0]); ++ ++PRBool ++isULONGAttribute(CK_ATTRIBUTE_TYPE type) ++{ ++ switch (type) { ++ case CKA_CERTIFICATE_CATEGORY: ++ case CKA_CERTIFICATE_TYPE: ++ case CKA_CLASS: ++ case CKA_JAVA_MIDP_SECURITY_DOMAIN: ++ case CKA_KEY_GEN_MECHANISM: ++ case CKA_KEY_TYPE: ++ case CKA_MECHANISM_TYPE: ++ case CKA_MODULUS_BITS: ++ case CKA_PRIME_BITS: ++ case CKA_SUBPRIME_BITS: ++ case CKA_VALUE_BITS: ++ case CKA_VALUE_LEN: ++ ++ case CKA_TRUST_DIGITAL_SIGNATURE: ++ case CKA_TRUST_NON_REPUDIATION: ++ case CKA_TRUST_KEY_ENCIPHERMENT: ++ case CKA_TRUST_DATA_ENCIPHERMENT: ++ case CKA_TRUST_KEY_AGREEMENT: ++ case CKA_TRUST_KEY_CERT_SIGN: ++ case CKA_TRUST_CRL_SIGN: ++ ++ case CKA_TRUST_SERVER_AUTH: ++ case CKA_TRUST_CLIENT_AUTH: ++ case CKA_TRUST_CODE_SIGNING: ++ case CKA_TRUST_EMAIL_PROTECTION: ++ case CKA_TRUST_IPSEC_END_SYSTEM: ++ case CKA_TRUST_IPSEC_TUNNEL: ++ case CKA_TRUST_IPSEC_USER: ++ case CKA_TRUST_TIME_STAMPING: ++ case CKA_TRUST_STEP_UP_APPROVED: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++/* are the attributes private? */ ++static PRBool ++isPrivateAttribute(CK_ATTRIBUTE_TYPE type) ++{ ++ switch (type) { ++ case CKA_VALUE: ++ case CKA_PRIVATE_EXPONENT: ++ case CKA_PRIME_1: ++ case CKA_PRIME_2: ++ case CKA_EXPONENT_1: ++ case CKA_EXPONENT_2: ++ case CKA_COEFFICIENT: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++/* These attributes must be authenticated with an hmac. */ ++static PRBool ++isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) ++{ ++ switch (type) { ++ case CKA_MODULUS: ++ case CKA_PUBLIC_EXPONENT: ++ case CKA_CERT_SHA1_HASH: ++ case CKA_CERT_MD5_HASH: ++ case CKA_TRUST_SERVER_AUTH: ++ case CKA_TRUST_CLIENT_AUTH: ++ case CKA_TRUST_EMAIL_PROTECTION: ++ case CKA_TRUST_CODE_SIGNING: ++ case CKA_TRUST_STEP_UP_APPROVED: ++ case CKA_NSS_OVERRIDE_EXTENSIONS: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++/* ++ * convert a database ulong back to a native ULONG. (reverse of the above ++ * function. ++ */ ++static CK_ULONG ++sdbULong2ULong(unsigned char *data) ++{ ++ int i; ++ CK_ULONG value = 0; ++ ++ for (i = 0; i < SDB_ULONG_SIZE; i++) { ++ value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) ++ * PR_BITS_PER_BYTE); ++ } ++ return value; ++} ++ ++/* PBE defines and functions */ ++ ++typedef struct EncryptedDataInfoStr { ++ SECAlgorithmID algorithm; ++ SECItem encryptedData; ++} EncryptedDataInfo; ++ ++static const SEC_ASN1Template encryptedDataInfoTemplate[] = { ++ { SEC_ASN1_SEQUENCE, ++ 0, NULL, sizeof(EncryptedDataInfo) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(EncryptedDataInfo, algorithm), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { SEC_ASN1_OCTET_STRING, ++ offsetof(EncryptedDataInfo, encryptedData) }, ++ { 0 } ++}; ++ ++typedef struct PBEParameterStr { ++ SECAlgorithmID prfAlg; ++ SECItem salt; ++ SECItem iteration; ++ SECItem keyLength; ++} PBEParameter; ++ ++static const SEC_ASN1Template pkcs5V1PBEParameterTemplate[] = ++ { ++ { SEC_ASN1_SEQUENCE, ++ 0, NULL, sizeof(PBEParameter) }, ++ { SEC_ASN1_OCTET_STRING, ++ offsetof(PBEParameter, salt) }, ++ { SEC_ASN1_INTEGER, ++ offsetof(PBEParameter, iteration) }, ++ { 0 } ++ }; ++ ++static const SEC_ASN1Template pkcs12V2PBEParameterTemplate[] = ++ { ++ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, ++ { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, ++ { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, ++ { 0 } ++ }; ++ ++ ++static const SEC_ASN1Template pkcs5V2PBEParameterTemplate[] = ++ { ++ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, ++ /* this is really a choice, but since we don't understand any other ++ * choice, just inline it. */ ++ { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, ++ { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, ++ { SEC_ASN1_INTEGER, offsetof(PBEParameter, keyLength) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(PBEParameter, prfAlg), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { 0 } ++ }; ++ ++typedef struct Pkcs5v2PBEParameterStr { ++ SECAlgorithmID keyParams; /* parameters of the key generation */ ++ SECAlgorithmID algParams; /* parameters for the encryption or mac op */ ++} Pkcs5v2PBEParameter; ++ ++static const SEC_ASN1Template pkcs5v2PBES2ParameterTemplate[] = { ++ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(Pkcs5v2PBEParameter) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(Pkcs5v2PBEParameter, keyParams), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(Pkcs5v2PBEParameter, algParams), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { 0 } ++}; ++ ++static inline PRBool ++isPKCS12PBE(SECOidTag alg) { ++ switch (alg) { ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++ ++/* helper functions */ ++ ++/* output an NSS specific attribute or name that wasn't found in our ++ * pkcs #11 table */ ++const char * ++makeNSSVendorName(CK_ATTRIBUTE_TYPE attribute, const char *nameType) ++{ ++ static char nss_name[256]; ++ const char *name = NULL; ++ if ((attribute >= CKA_NSS) && (attribute <= 0xffffffff)) { ++ sprintf(nss_name,"%s+%d", nameType, (int)(attribute-CKA_NSS)); ++ name = nss_name; ++ } ++ return name; ++} ++ ++/* turn and attribute into a name */ ++const char * ++AttributeName(CK_ATTRIBUTE_TYPE attribute) ++{ ++ const char *name = getNameFromAttribute(attribute); ++ if (!name) { ++ name = makeNSSVendorName(attribute, "CKA_NSS"); ++ } ++ ++ return name ? name : "UNKNOWN_ATTRIBUTE_TYPE"; ++} ++ ++/* turn and error code into a name */ ++const char * ++ErrorName(CK_RV crv) ++{ ++ const char *error = getName(crv, ConstResult); ++ if (!error) { ++ error = makeNSSVendorName(crv, "CKR_NSS"); ++ } ++ return error ? error : "UNKNOWN_ERROR"; ++} ++ ++/* turn an oud tag into a string */ ++const char * ++oid2string(SECOidTag alg) ++{ ++ const char *oidstring = SECOID_FindOIDTagDescription(alg); ++ const char *def="Invalid oid tag"; /* future build a dotted oid string value here */ ++ return oidstring ? oidstring : def; ++} ++ ++/* dump an arbitary data blob. Dump it has hex with ascii on the side */ ++#define ASCCHAR(val) ((val) >= ' ' && (val) <= 0x7e ? (val) : '.') ++#define LINE_LENGTH 16 ++void ++dumpValue(const unsigned char *v, int len) ++{ ++ int i, next = 0; ++ char string[LINE_LENGTH+1]; ++ char space[LINE_LENGTH*2+1]; ++ char *nl = ""; ++ char *sp = ""; ++ PORT_Memset(string, 0, sizeof(string)); ++ ++ for (i=0; i < len; i++) { ++ if ((i % LINE_LENGTH) == 0) { ++ printf("%s%s%s ", sp, string, nl); ++ PORT_Memset(string, 0, sizeof(string)); ++ next = 0; ++ nl = "\n"; ++ sp = " "; ++ } ++ printf("%02x", v[i]); ++ string[next++] = ASCCHAR(v[i]); ++ } ++ PORT_Memset(space, 0, sizeof(space)); ++ i = LINE_LENGTH - (len % LINE_LENGTH); ++ if (i != LINE_LENGTH) { ++ int j; ++ for (j=0 ; j < i; j++) { ++ space[j*2] = ' '; ++ space[j*2+1] = ' '; ++ } ++ } ++ printf("%s%s%s%s", space, sp, string, nl); ++} ++ ++/* dump a PKCS5/12 PBE blob */ ++void ++dumpPKCS(unsigned char *val, CK_ULONG len, PRBool *hasSig) ++{ ++ EncryptedDataInfo edi; ++ SECStatus rv; ++ SECItem data; ++ PLArenaPool *arena; ++ SECOidTag alg, prfAlg; ++ PBEParameter pbeParam; ++ unsigned char zero = 0; ++ const SEC_ASN1Template *template = pkcs5V1PBEParameterTemplate; ++ int iter, keyLen, i; ++ ++ if (hasSig) { *hasSig = PR_FALSE; } ++ ++ ++ data.data = val; ++ data.len = len; ++ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); ++ if (arena == NULL) { ++ printf("Couldn't allocate arena\n"); ++ return; ++ } ++ ++ /* initialize default values */ ++ PORT_Memset(&pbeParam, 0, sizeof(pbeParam)); ++ pbeParam.keyLength.data = &zero; ++ pbeParam.keyLength.len = sizeof(zero); ++ SECOID_SetAlgorithmID(arena, &pbeParam.prfAlg, SEC_OID_SHA1, NULL); ++ ++ /* first crack the encrypted data from the PBE algorithm ID */ ++ rv = SEC_QuickDERDecodeItem(arena, &edi, encryptedDataInfoTemplate, &data); ++ if (rv != SECSuccess) { ++ printf("Encrypted Data, failed to decode\n"); ++ dumpValue(val,len); ++ PORT_FreeArena(arena, PR_FALSE); ++ return; ++ } ++ /* now use the pbe secalg to dump info on the pbe */ ++ alg = SECOID_GetAlgorithmTag(&edi.algorithm); ++ if ((alg == SEC_OID_PKCS5_PBES2) || (alg == SEC_OID_PKCS5_PBMAC1)){ ++ Pkcs5v2PBEParameter param; ++ SECOidTag palg; ++ const char *typeName = (alg == SEC_OID_PKCS5_PBES2) ? ++ "Encrypted Data PBES2" : ++ "Mac Data PBMAC1"; ++ ++ rv = SEC_QuickDERDecodeItem(arena, ¶m, ++ pkcs5v2PBES2ParameterTemplate, ++ &edi.algorithm.parameters); ++ if (rv != SECSuccess) { ++ printf("%s, failed to decode\n", typeName); ++ dumpValue(val,len); ++ PORT_FreeArena(arena, PR_FALSE); ++ return; ++ } ++ palg = SECOID_GetAlgorithmTag(¶m.algParams); ++ printf("%s alg=%s ", typeName, oid2string(palg)); ++ if (hasSig && palg == SEC_OID_AES_256_CBC) { ++ *hasSig = PR_TRUE; ++ } ++ template = pkcs5V2PBEParameterTemplate; ++ edi.algorithm.parameters = param.keyParams.parameters; ++ } else { ++ printf("Encrypted Data alg=%s ", oid2string(alg)); ++ if (alg == SEC_OID_PKCS5_PBKDF2) { ++ template = pkcs5V2PBEParameterTemplate; ++ } else if (isPKCS12PBE(alg)) { ++ template = pkcs12V2PBEParameterTemplate; ++ } else { ++ template = pkcs5V1PBEParameterTemplate; ++ } ++ } ++ rv = SEC_QuickDERDecodeItem(arena, &pbeParam, ++ template, ++ &edi.algorithm.parameters); ++ if (rv != SECSuccess) { ++ printf("( failed to decode params)\n"); ++ PORT_FreeArena(arena, PR_FALSE); ++ return; ++ } ++ /* dump the pbe parmeters */ ++ iter = DER_GetInteger(&pbeParam.iteration); ++ keyLen = DER_GetInteger(&pbeParam.keyLength); ++ prfAlg = SECOID_GetAlgorithmTag(&pbeParam.prfAlg); ++ printf("(prf=%s iter=%d keyLen=%d salt=0x", ++ oid2string(prfAlg), iter, keyLen); ++ for(i=0;i < pbeParam.salt.len; i++) printf("%02x",pbeParam.salt.data[i]); ++ printf(")\n"); ++ /* finally dump the raw encrypted data */ ++ dumpValue(edi.encryptedData.data, edi.encryptedData.len); ++ PORT_FreeArena(arena, PR_FALSE); ++} ++ ++/* dump a long attribute, convert to an unsigned long. PKCS #11 Longs are ++ * limited to 32 bits by the spec, even if the CK_ULONG is longer */ ++void ++dumpLongAttribute(CK_ATTRIBUTE_TYPE type, CK_ULONG value) ++{ ++ const char *nameType = "CK_NSS"; ++ ConstType constType = ConstNone; ++ const char *valueName = NULL; ++ ++ switch (type) { ++ case CKA_CLASS: ++ nameType = "CKO_NSS"; ++ constType = ConstObject; ++ break; ++ case CKA_CERTIFICATE_TYPE: ++ nameType = "CKC_NSS"; ++ constType = ConstCertType; ++ break; ++ case CKA_KEY_TYPE: ++ nameType = "CKK_NSS"; ++ constType = ConstKeyType; ++ break; ++ case CKA_MECHANISM_TYPE: ++ nameType = "CKM_NSS"; ++ constType = ConstMechanism; ++ break; ++ case CKA_TRUST_SERVER_AUTH: ++ case CKA_TRUST_CLIENT_AUTH: ++ case CKA_TRUST_CODE_SIGNING: ++ case CKA_TRUST_EMAIL_PROTECTION: ++ case CKA_TRUST_IPSEC_END_SYSTEM: ++ case CKA_TRUST_IPSEC_TUNNEL: ++ case CKA_TRUST_IPSEC_USER: ++ case CKA_TRUST_TIME_STAMPING: ++ nameType = "CKT_NSS"; ++ constType = ConstTrust; ++ break; ++ default: ++ break; ++ } ++ /* if value has a symbolic name, use it */ ++ if (constType != ConstNone) { ++ valueName = getName(value, constType); ++ } ++ if (!valueName) { ++ valueName = makeNSSVendorName(value, nameType); ++ } ++ if (!valueName) { ++ printf("%d (0x%08x)\n", (int) value, (int)value); ++ } else { ++ printf("%s (0x%08x)\n", valueName, (int)value); ++ } ++} ++ ++/* dump a signature for an object */ ++static const char META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; ++void ++dumpSignature(CK_ATTRIBUTE_TYPE attribute, SDB *keydb, PRBool isKey, ++ CK_OBJECT_HANDLE objectID, PRBool force) ++{ ++ char id[30]; ++ CK_RV crv; ++ SECItem signText; ++ unsigned char signData[SDB_MAX_META_DATA_LEN]; ++ ++ if (!force && !isAuthenticatedAttribute(attribute)) { ++ return; ++ } ++ sprintf(id, META_SIG_TEMPLATE, ++ isKey ? "key" : "cert", ++ (unsigned int)objectID, (unsigned int)attribute); ++ printf(" Signature %s:",id); ++ signText.data = signData; ++ signText.len = sizeof(signData); ++ ++ ++ crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); ++ if ((crv != CKR_OK) && isKey) { ++ sprintf(id, META_SIG_TEMPLATE, ++ isKey ? "key" : "cert", (unsigned int) ++ (objectID | SFTK_KEYDB_TYPE | SFTK_TOKEN_TYPE), ++ (unsigned int)attribute); ++ crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); ++ } ++ if (crv != CKR_OK) { ++ printf(" FAILED %s with %s (0x%08x)\n", id, ErrorName(crv), (int) crv); ++ return; ++ } ++ dumpPKCS(signText.data, signText.len, NULL); ++ return; ++} ++ ++/* dump an attribute. use the helper functions above */ ++void ++dumpAttribute(CK_ATTRIBUTE *template, SDB *keydb, PRBool isKey, ++ CK_OBJECT_HANDLE id) ++{ ++ CK_ATTRIBUTE_TYPE attribute = template->type; ++ printf(" %s(0x%08x): ", AttributeName(attribute), (int)attribute); ++ if (template->pValue == NULL) { ++ printf("NULL (%d)\n", (int)template->ulValueLen); ++ return; ++ } ++ if (template->ulValueLen == SDB_ULONG_SIZE ++ && isULONGAttribute(attribute)) { ++ CK_ULONG value=sdbULong2ULong(template->pValue); ++ dumpLongAttribute(attribute, value); ++ return; ++ } ++ if (template->ulValueLen == 1) { ++ unsigned char val = *(unsigned char *)template->pValue; ++ switch (val) { ++ case 0: ++ printf("CK_FALSE\n"); ++ break; ++ case 1: ++ printf("CK_TRUE\n"); ++ break; ++ default: ++ printf("%d 0x%02x %c\n", val, val, ASCCHAR(val)); ++ break; ++ } ++ return; ++ } ++ if (isKey && isPrivateAttribute(attribute)) { ++ PRBool hasSig = PR_FALSE; ++ dumpPKCS(template->pValue, template->ulValueLen, &hasSig); ++ if (hasSig) { ++ dumpSignature(attribute, keydb, isKey, id, PR_TRUE); ++ } ++ return; ++ } ++ if (template->ulValueLen == 0) { printf("empty"); } ++ printf("\n"); ++ dumpValue(template->pValue, template->ulValueLen); ++} ++ ++/* dump all the attributes in an object */ ++void ++dumpObject(CK_OBJECT_HANDLE id, SDB *db, SDB *keydb, PRBool isKey) ++{ ++ CK_RV crv; ++ int i; ++ CK_ATTRIBUTE template; ++ char buffer[2048]; ++ char * alloc = NULL; ++ ++ printf(" Object 0x%08x:\n", (int)id); ++ for (i = 0; i < known_attributes_size; i++) { ++ CK_ATTRIBUTE_TYPE attribute = known_attributes[i]; ++ template.type = attribute; ++ template.pValue = NULL; ++ template.ulValueLen = 0; ++ crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); ++ ++ if (crv != CKR_OK) { ++ if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { ++ PR_fprintf(PR_STDERR, " " ++ "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", ++ AttributeName(attribute), (int)attribute, ++ ErrorName(crv), (int)crv); ++ } ++ continue; ++ } ++ ++ if (template.ulValueLen < sizeof(buffer)) { ++ template.pValue = buffer; ++ } else { ++ alloc = PORT_Alloc(template.ulValueLen); ++ template.pValue = alloc; ++ } ++ if (template.pValue == NULL) { ++ PR_fprintf(PR_STDERR, " " ++ "Could allocate %d bytes for Attribute %s (0x%08x)\n", ++ (int) template.ulValueLen, ++ AttributeName(attribute), (int)attribute); ++ continue; ++ } ++ crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); ++ ++ if (crv != CKR_OK) { ++ if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { ++ PR_fprintf(PR_STDERR, " " ++ "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", ++ AttributeName(attribute), (int)attribute, ++ ErrorName(crv), (int)crv); ++ } ++ if (alloc) { ++ PORT_Free(alloc); ++ alloc = NULL; ++ } ++ continue; ++ } ++ ++ dumpAttribute(&template, keydb, isKey, id); ++ dumpSignature(template.type, keydb, isKey, id, PR_FALSE); ++ if (alloc) { ++ PORT_Free(alloc); ++ alloc = NULL; ++ } ++ } ++} ++ ++/* dump all the objects in a database */ ++void ++dumpDB(SDB *db, const char *name, SDB *keydb, PRBool isKey) ++{ ++ SDBFind *findHandle= NULL; ++ CK_BBOOL isTrue = 1; ++ CK_ATTRIBUTE allObjectTemplate = {CKA_TOKEN, NULL, 1 }; ++ CK_ULONG allObjectTemplateCount = 1; ++ PRBool recordFound = PR_FALSE; ++ CK_RV crv = CKR_OK; ++ CK_ULONG objectCount = 0; ++ printf("%s:\n",name); ++ ++ allObjectTemplate.pValue = &isTrue; ++ crv = (*db->sdb_FindObjectsInit)(db, &allObjectTemplate, ++ allObjectTemplateCount, &findHandle); ++ do { ++ CK_OBJECT_HANDLE id; ++ recordFound = PR_FALSE; ++ crv =(*db->sdb_FindObjects)(db, findHandle, &id, 1, &objectCount); ++ if ((crv == CKR_OK) && (objectCount == 1)) { ++ recordFound = PR_TRUE; ++ dumpObject(id, db, keydb, isKey); ++ } ++ } while (recordFound); ++ if (crv != CKR_OK) { ++ PR_fprintf(PR_STDERR, ++ "Last record return PKCS #11 error = %s (0x%08x)\n", ++ ErrorName(crv), (int)crv); ++ } ++ (*db->sdb_FindObjectsFinal)(db,findHandle); ++} ++ ++int ++main(int argc, char **argv) ++{ ++ PLOptState *optstate; ++ PLOptStatus optstatus; ++ char *certPrefix="", *keyPrefix=""; ++ int cert_version = 9; ++ int key_version = 4; ++ SDB *certdb = NULL; ++ SDB *keydb = NULL; ++ PRBool isNew = PR_FALSE; ++ ++ CK_RV crv; ++ ++ progName = strrchr(argv[0], '/'); ++ if (!progName) ++ progName = strrchr(argv[0], '\\'); ++ progName = progName ? progName + 1 : argv[0]; ++ ++ optstate = PL_CreateOptState(argc, argv, "d:c:k:v:V:h"); ++ ++ while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { ++ switch (optstate->option) { ++ case 'h': ++ default: ++ Usage(); ++ break; ++ ++ case 'd': ++ dbDir = PORT_Strdup(optstate->value); ++ break; ++ ++ case 'c': ++ certPrefix = PORT_Strdup(optstate->value); ++ break; ++ ++ case 'k': ++ keyPrefix = PORT_Strdup(optstate->value); ++ break; ++ ++ case 'v': ++ key_version = atoi(optstate->value); ++ break; ++ ++ case 'V': ++ cert_version = atoi(optstate->value); ++ break; ++ ++ } ++ } ++ PL_DestroyOptState(optstate); ++ if (optstatus == PL_OPT_BAD) ++ Usage(); ++ ++ if (dbDir) { ++ char *tmp = dbDir; ++ dbDir = SECU_ConfigDirectory(tmp); ++ PORT_Free(tmp); ++ } else { ++ /* Look in $SSL_DIR */ ++ dbDir = SECU_ConfigDirectory(SECU_DefaultSSLDir()); ++ } ++ PR_fprintf(PR_STDERR, "dbdir selected is %s\n\n", dbDir); ++ ++ if (dbDir[0] == '\0') { ++ PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir); ++ return 1; ++ } ++ ++ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); ++ SECOID_Init(); ++ ++ crv = s_open(dbDir, certPrefix, keyPrefix, cert_version, key_version, ++ SDB_RDONLY, &certdb, &keydb, &isNew); ++ if (crv != CKR_OK) { ++ PR_fprintf(PR_STDERR, ++ "Couldn't open databased in %s, error=%s (0x%08x)\n", ++ dbDir, ErrorName(crv), (int)crv); ++ return 1; ++ } ++ ++ /* now dump the objects in the cert database */ ++ dumpDB(certdb, "CertDB", keydb, PR_FALSE); ++ dumpDB(keydb, "KeyDB", keydb, PR_TRUE); ++ return 0; ++} +diff --git a/cmd/dbtool/dbtool.gyp b/cmd/dbtool/dbtool.gyp +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/dbtool.gyp +@@ -0,0 +1,25 @@ ++# 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', ++ '../../cmd/platlibs.gypi' ++ ], ++ 'targets': [ ++ { ++ 'target_name': 'dbtest', ++ 'type': 'executable', ++ 'sources': [ ++ 'dbtest.c' ++ ], ++ 'dependencies': [ ++ '<(DEPTH)/exports.gyp:dbm_exports', ++ '<(DEPTH)/exports.gyp:nss_exports' ++ ] ++ } ++ ], ++ 'variables': { ++ 'module': 'nss' ++ } ++} +\ No newline at end of file +diff --git a/cmd/dbtool/manifest.mn b/cmd/dbtool/manifest.mn +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/manifest.mn +@@ -0,0 +1,18 @@ ++# ++# 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 = ../.. ++ ++# MODULE public and private header directories are implicitly REQUIRED. ++MODULE = nss ++ ++USE_STATIC_LIBS = 1 ++ ++# DIRS = ++ ++CSRCS = dbtool.c sdb.c ++ ++PROGRAM = dbtool ++ +diff --git a/cmd/dbtool/sdb.c b/cmd/dbtool/sdb.c +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/sdb.c +@@ -0,0 +1,2469 @@ ++/* 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/. */ ++/* ++ * This file implements PKCS 11 on top of our existing security modules ++ * ++ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. ++ * This implementation has two slots: ++ * slot 1 is our generic crypto support. It does not require login. ++ * It supports Public Key ops, and all they bulk ciphers and hashes. ++ * It can also support Private Key ops for imported Private keys. It does ++ * not have any token storage. ++ * slot 2 is our private key support. It requires a login before use. It ++ * can store Private Keys and Certs as token objects. Currently only private ++ * keys and their associated Certificates are saved on the token. ++ * ++ * In this implementation, session objects are only visible to the session ++ * that created or generated them. ++ */ ++ ++#include "sdb.h" ++#include "pkcs11t.h" ++#include "seccomon.h" ++#include ++#include "prthread.h" ++#include "prio.h" ++#include ++#include "secport.h" ++#include "prmon.h" ++#include "prenv.h" ++#include "prprf.h" ++#include "prsystem.h" /* for PR_GetDirectorySeparator() */ ++#include ++#if defined(_WIN32) ++#include ++#include ++#elif defined(XP_UNIX) ++#include ++#endif ++#if defined(LINUX) && !defined(ANDROID) ++#include ++#include ++#endif ++#include "utilpars.h" ++ ++#ifdef SQLITE_UNSAFE_THREADS ++#include "prlock.h" ++/* ++ * SQLite can be compiled to be thread safe or not. ++ * turn on SQLITE_UNSAFE_THREADS if the OS does not support ++ * a thread safe version of sqlite. ++ */ ++static PRLock *sqlite_lock = NULL; ++ ++#define LOCK_SQLITE() PR_Lock(sqlite_lock); ++#define UNLOCK_SQLITE() PR_Unlock(sqlite_lock); ++#else ++#define LOCK_SQLITE() ++#define UNLOCK_SQLITE() ++#endif ++ ++typedef enum { ++ SDB_CERT = 1, ++ SDB_KEY = 2 ++} sdbDataType; ++ ++/* ++ * defines controlling how long we wait to acquire locks. ++ * ++ * SDB_SQLITE_BUSY_TIMEOUT specifies how long (in milliseconds) ++ * sqlite will wait on lock. If that timeout expires, sqlite will ++ * return SQLITE_BUSY. ++ * SDB_BUSY_RETRY_TIME specifies how many seconds the sdb_ code waits ++ * after receiving a busy before retrying. ++ * SDB_MAX_BUSY_RETRIES specifies how many times the sdb_ will retry on ++ * a busy condition. ++ * ++ * SDB_SQLITE_BUSY_TIMEOUT affects all opertions, both manual ++ * (prepare/step/reset/finalize) and automatic (sqlite3_exec()). ++ * SDB_BUSY_RETRY_TIME and SDB_MAX_BUSY_RETRIES only affect manual operations ++ * ++ * total wait time for automatic operations: ++ * 1 second (SDB_SQLITE_BUSY_TIMEOUT/1000). ++ * total wait time for manual operations: ++ * (1 second + SDB_BUSY_RETRY_TIME) * 30 = 30 seconds. ++ * (SDB_SQLITE_BUSY_TIMEOUT/1000 + SDB_BUSY_RETRY_TIME)*SDB_MAX_BUSY_RETRIES ++ */ ++#define SDB_SQLITE_BUSY_TIMEOUT 1000 /* milliseconds */ ++#define SDB_BUSY_RETRY_TIME 5 /* 'ticks', varies by platforms */ ++#define SDB_MAX_BUSY_RETRIES 30 ++ ++/* ++ * known attributes ++ */ ++static const CK_ATTRIBUTE_TYPE known_attributes[] = { ++ CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, ++ CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, ++ CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, ++ CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, ++ CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, ++ CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, ++ CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, ++ CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, ++ CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, ++ CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, ++ CKA_PUBLIC_KEY_INFO, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, ++ CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, ++ CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, ++ CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, ++ CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, ++ CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_HW_FEATURE_TYPE, ++ CKA_RESET_ON_INIT, CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, ++ CKA_RESOLUTION, CKA_CHAR_ROWS, CKA_CHAR_COLUMNS, CKA_COLOR, ++ CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, CKA_ENCODING_METHODS, CKA_MIME_TYPES, ++ CKA_MECHANISM_TYPE, CKA_REQUIRED_CMS_ATTRIBUTES, ++ CKA_DEFAULT_CMS_ATTRIBUTES, CKA_SUPPORTED_CMS_ATTRIBUTES, ++ CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE, CKA_NSS_TRUST, CKA_NSS_URL, ++ CKA_NSS_EMAIL, CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, ++ CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, ++ CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, ++ CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, ++ CKA_NSS_OVERRIDE_EXTENSIONS, CKA_NSS_SERVER_DISTRUST_AFTER, ++ CKA_NSS_EMAIL_DISTRUST_AFTER, CKA_TRUST_DIGITAL_SIGNATURE, ++ CKA_TRUST_NON_REPUDIATION, CKA_TRUST_KEY_ENCIPHERMENT, ++ CKA_TRUST_DATA_ENCIPHERMENT, CKA_TRUST_KEY_AGREEMENT, ++ CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, CKA_TRUST_SERVER_AUTH, ++ CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, ++ CKA_TRUST_IPSEC_END_SYSTEM, CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, ++ CKA_TRUST_TIME_STAMPING, CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, ++ CKA_CERT_MD5_HASH, CKA_NSS_DB ++}; ++ ++static const int known_attributes_size = PR_ARRAY_SIZE(known_attributes); ++ ++/* ++ * Note on use of sqlReadDB: Only one thread at a time may have an actual ++ * operation going on given sqlite3 * database. An operation is defined as ++ * the time from a sqlite3_prepare() until the sqlite3_finalize(). ++ * Multiple sqlite3 * databases can be open and have simultaneous operations ++ * going. We use the sqlXactDB for all write operations. This database ++ * is only opened when we first create a transaction and closed when the ++ * transaction is complete. sqlReadDB is open when we first opened the database ++ * and is used for all read operation. It's use is protected by a monitor. This ++ * is because an operation can span the use of FindObjectsInit() through the ++ * call to FindObjectsFinal(). In the intermediate time it is possible to call ++ * other operations like NSC_GetAttributeValue */ ++ ++struct SDBPrivateStr { ++ char *sqlDBName; /* invariant, path to this database */ ++ sqlite3 *sqlXactDB; /* access protected by dbMon, use protected ++ * by the transaction. Current transaction db*/ ++ PRThread *sqlXactThread; /* protected by dbMon, ++ * current transaction thread */ ++ sqlite3 *sqlReadDB; /* use protected by dbMon, value invariant */ ++ PRIntervalTime lastUpdateTime; /* last time the cache was updated */ ++ PRIntervalTime updateInterval; /* how long the cache can go before it ++ * must be updated again */ ++ sdbDataType type; /* invariant, database type */ ++ char *table; /* invariant, SQL table which contains the db */ ++ char *cacheTable; /* invariant, SQL table cache of db */ ++ PRMonitor *dbMon; /* invariant, monitor to protect ++ * sqlXact* fields, and use of the sqlReadDB */ ++ CK_ATTRIBUTE_TYPE *schemaAttrs; /* Attribute columns that exist in the table. */ ++ unsigned int numSchemaAttrs; ++}; ++ ++typedef struct SDBPrivateStr SDBPrivate; ++ ++/* Magic for an explicit NULL. NOTE: ideally this should be ++ * out of band data. Since it's not completely out of band, pick ++ * a value that has no meaning to any existing PKCS #11 attributes. ++ * This value is 1) not a valid string (imbedded '\0'). 2) not a U_LONG ++ * or a normal key (too short). 3) not a bool (too long). 4) not an RSA ++ * public exponent (too many bits). ++ */ ++const unsigned char SQLITE_EXPLICIT_NULL[] = { 0xa5, 0x0, 0x5a }; ++#define SQLITE_EXPLICIT_NULL_LEN 3 ++ ++/* ++ * determine when we've completed our tasks ++ */ ++static int ++sdb_done(int err, int *count) ++{ ++ /* allow as many rows as the database wants to give */ ++ if (err == SQLITE_ROW) { ++ *count = 0; ++ return 0; ++ } ++ if (err != SQLITE_BUSY) { ++ return 1; ++ } ++ /* err == SQLITE_BUSY, Dont' retry forever in this case */ ++ if (++(*count) >= SDB_MAX_BUSY_RETRIES) { ++ return 1; ++ } ++ return 0; ++} ++ ++#if defined(_WIN32) ++/* ++ * NSPR functions and narrow CRT functions do not handle UTF-8 file paths that ++ * sqlite3 expects. ++ */ ++ ++static int ++sdb_chmod(const char *filename, int pmode) ++{ ++ int result; ++ ++ if (!filename) { ++ return -1; ++ } ++ ++ wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename); ++ if (!filenameWide) { ++ return -1; ++ } ++ result = _wchmod(filenameWide, pmode); ++ PORT_Free(filenameWide); ++ ++ return result; ++} ++#else ++#define sdb_chmod(filename, pmode) chmod((filename), (pmode)) ++#endif ++ ++/* ++ * find out where sqlite stores the temp tables. We do this by replicating ++ * the logic from sqlite. ++ */ ++#if defined(_WIN32) ++static char * ++sdb_getFallbackTempDir(void) ++{ ++ /* sqlite uses sqlite3_temp_directory if it is not NULL. We don't have ++ * access to sqlite3_temp_directory because it is not exported from ++ * sqlite3.dll. Assume sqlite3_win32_set_directory isn't called and ++ * sqlite3_temp_directory is NULL. ++ */ ++ char path[MAX_PATH]; ++ DWORD rv; ++ size_t len; ++ ++ rv = GetTempPathA(MAX_PATH, path); ++ if (rv > MAX_PATH || rv == 0) ++ return NULL; ++ len = strlen(path); ++ if (len == 0) ++ return NULL; ++ /* The returned string ends with a backslash, for example, "C:\TEMP\". */ ++ if (path[len - 1] == '\\') ++ path[len - 1] = '\0'; ++ return PORT_Strdup(path); ++} ++#elif defined(XP_UNIX) ++static char * ++sdb_getFallbackTempDir(void) ++{ ++ const char *azDirs[] = { ++ NULL, ++ NULL, ++ "/var/tmp", ++ "/usr/tmp", ++ "/tmp", ++ NULL /* List terminator */ ++ }; ++ unsigned int i; ++ struct stat buf; ++ const char *zDir = NULL; ++ ++ azDirs[0] = sqlite3_temp_directory; ++ azDirs[1] = PR_GetEnvSecure("TMPDIR"); ++ ++ for (i = 0; i < PR_ARRAY_SIZE(azDirs); i++) { ++ zDir = azDirs[i]; ++ if (zDir == NULL) ++ continue; ++ if (stat(zDir, &buf)) ++ continue; ++ if (!S_ISDIR(buf.st_mode)) ++ continue; ++ if (access(zDir, 07)) ++ continue; ++ break; ++ } ++ ++ if (zDir == NULL) ++ return NULL; ++ return PORT_Strdup(zDir); ++} ++#else ++#error "sdb_getFallbackTempDir not implemented" ++#endif ++ ++#ifndef SQLITE_FCNTL_TEMPFILENAME ++/* SQLITE_FCNTL_TEMPFILENAME was added in SQLite 3.7.15 */ ++#define SQLITE_FCNTL_TEMPFILENAME 16 ++#endif ++ ++static char * ++sdb_getTempDir(sqlite3 *sqlDB) ++{ ++ int sqlrv; ++ char *result = NULL; ++ char *tempName = NULL; ++ char *foundSeparator = NULL; ++ ++ /* Obtain temporary filename in sqlite's directory for temporary tables */ ++ sqlrv = sqlite3_file_control(sqlDB, 0, SQLITE_FCNTL_TEMPFILENAME, ++ (void *)&tempName); ++ if (sqlrv == SQLITE_NOTFOUND) { ++ /* SQLITE_FCNTL_TEMPFILENAME not implemented because we are using ++ * an older SQLite. */ ++ return sdb_getFallbackTempDir(); ++ } ++ if (sqlrv != SQLITE_OK) { ++ return NULL; ++ } ++ ++ /* We'll extract the temporary directory from tempName */ ++ foundSeparator = PORT_Strrchr(tempName, PR_GetDirectorySeparator()); ++ if (foundSeparator) { ++ /* We shorten the temp filename string to contain only ++ * the directory name (including the trailing separator). ++ * We know the byte after the foundSeparator position is ++ * safe to use, in the shortest scenario it contains the ++ * end-of-string byte. ++ * By keeping the separator at the found position, it will ++ * even work if tempDir consists of the separator, only. ++ * (In this case the toplevel directory will be used for ++ * access speed testing). */ ++ ++foundSeparator; ++ *foundSeparator = 0; ++ ++ /* Now we copy the directory name for our caller */ ++ result = PORT_Strdup(tempName); ++ } ++ ++ sqlite3_free(tempName); ++ return result; ++} ++ ++/* ++ * Map SQL_LITE errors to PKCS #11 errors as best we can. ++ */ ++static CK_RV ++sdb_mapSQLError(sdbDataType type, int sqlerr) ++{ ++ switch (sqlerr) { ++ /* good matches */ ++ case SQLITE_OK: ++ case SQLITE_DONE: ++ return CKR_OK; ++ case SQLITE_NOMEM: ++ return CKR_HOST_MEMORY; ++ case SQLITE_READONLY: ++ return CKR_TOKEN_WRITE_PROTECTED; ++ /* close matches */ ++ case SQLITE_AUTH: ++ case SQLITE_PERM: ++ /*return CKR_USER_NOT_LOGGED_IN; */ ++ case SQLITE_CANTOPEN: ++ case SQLITE_NOTFOUND: ++ /* NSS distiguishes between failure to open the cert and the key db */ ++ return type == SDB_CERT ? CKR_NSS_CERTDB_FAILED : CKR_NSS_KEYDB_FAILED; ++ case SQLITE_IOERR: ++ return CKR_DEVICE_ERROR; ++ default: ++ break; ++ } ++ return CKR_GENERAL_ERROR; ++} ++ ++/* ++ * build up database name from a directory, prefix, name, version and flags. ++ */ ++static char * ++sdb_BuildFileName(const char *directory, ++ const char *prefix, const char *type, ++ int version) ++{ ++ char *dbname = NULL; ++ /* build the full dbname */ ++ dbname = sqlite3_mprintf("%s%c%s%s%d.db", directory, ++ (int)(unsigned char)PR_GetDirectorySeparator(), ++ prefix, type, version); ++ return dbname; ++} ++ ++/* ++ * find out how expensive the access system call is for non-existant files ++ * in the given directory. Return the number of operations done in 33 ms. ++ */ ++static PRUint32 ++sdb_measureAccess(const char *directory) ++{ ++ PRUint32 i; ++ PRIntervalTime time; ++ PRIntervalTime delta; ++ PRIntervalTime duration = PR_MillisecondsToInterval(33); ++ const char *doesntExistName = "_dOeSnotExist_.db"; ++ char *temp, *tempStartOfFilename; ++ size_t maxTempLen, maxFileNameLen, directoryLength, tmpdirLength = 0; ++#ifdef SDB_MEASURE_USE_TEMP_DIR ++ /* ++ * on some OS's and Filesystems, creating a bunch of files and deleting ++ * them messes up the systems's caching, but if we create the files in ++ * a temp directory which we later delete, then the cache gets cleared ++ * up. This code uses several OS dependent calls, and it's not clear ++ * that temp directory use won't mess up other filesystems and OS caching, ++ * so if you need this for your OS, you can turn on the ++ * 'SDB_MEASURE_USE_TEMP_DIR' define in coreconf ++ */ ++ const char template[] = "dbTemp.XXXXXX"; ++ tmpdirLength = sizeof(template); ++#endif ++ /* no directory, just return one */ ++ if (directory == NULL) { ++ return 1; ++ } ++ ++ /* our calculation assumes time is a 4 bytes == 32 bit integer */ ++ PORT_Assert(sizeof(time) == 4); ++ ++ directoryLength = strlen(directory); ++ ++ maxTempLen = directoryLength + 1 /* dirname + / */ ++ + tmpdirLength /* tmpdirname includes / */ ++ + strlen(doesntExistName) /* filename base */ ++ + 11 /* max chars for 32 bit int plus potential sign */ ++ + 1; /* zero terminator */ ++ ++ temp = PORT_ZAlloc(maxTempLen); ++ if (!temp) { ++ return 1; ++ } ++ ++ /* We'll copy directory into temp just once, then ensure it ends ++ * with the directory separator. */ ++ ++ strcpy(temp, directory); ++ if (directory[directoryLength - 1] != PR_GetDirectorySeparator()) { ++ temp[directoryLength++] = PR_GetDirectorySeparator(); ++ } ++ ++#ifdef SDB_MEASURE_USE_TEMP_DIR ++ /* add the template for a temporary subdir, and create it */ ++ strcat(temp, template); ++ if (!mkdtemp(temp)) { ++ PORT_Free(temp); ++ return 1; ++ } ++ /* and terminate that tmp subdir with a / */ ++ strcat(temp, "/"); ++#endif ++ ++ /* Remember the position after the last separator, and calculate the ++ * number of remaining bytes. */ ++ tempStartOfFilename = temp + directoryLength + tmpdirLength; ++ maxFileNameLen = maxTempLen - directoryLength; ++ ++ /* measure number of Access operations that can be done in 33 milliseconds ++ * (1/30'th of a second), or 10000 operations, which ever comes first. ++ */ ++ time = PR_IntervalNow(); ++ for (i = 0; i < 10000u; i++) { ++ PRIntervalTime next; ++ ++ /* We'll use the variable part first in the filename string, just in ++ * case it's longer than assumed, so if anything gets cut off, it ++ * will be cut off from the constant part. ++ * This code assumes the directory name at the beginning of ++ * temp remains unchanged during our loop. */ ++ PR_snprintf(tempStartOfFilename, maxFileNameLen, ++ ".%lu%s", (PRUint32)(time + i), doesntExistName); ++ PR_Access(temp, PR_ACCESS_EXISTS); ++ next = PR_IntervalNow(); ++ delta = next - time; ++ if (delta >= duration) ++ break; ++ } ++ ++#ifdef SDB_MEASURE_USE_TEMP_DIR ++ /* turn temp back into our tmpdir path by removing doesntExistName, and ++ * remove the tmp dir */ ++ *tempStartOfFilename = '\0'; ++ (void)rmdir(temp); ++#endif ++ PORT_Free(temp); ++ ++ /* always return 1 or greater */ ++ return i ? i : 1u; ++} ++ ++/* ++ * some file sytems are very slow to run sqlite3 on, particularly if the ++ * access count is pretty high. On these filesystems is faster to create ++ * a temporary database on the local filesystem and access that. This ++ * code uses a temporary table to create that cache. Temp tables are ++ * automatically cleared when the database handle it was created on ++ * Is freed. ++ */ ++static const char DROP_CACHE_CMD[] = "DROP TABLE %s"; ++static const char CREATE_CACHE_CMD[] = ++ "CREATE TEMPORARY TABLE %s AS SELECT * FROM %s"; ++static const char CREATE_ISSUER_INDEX_CMD[] = ++ "CREATE INDEX issuer ON %s (a81)"; ++static const char CREATE_SUBJECT_INDEX_CMD[] = ++ "CREATE INDEX subject ON %s (a101)"; ++static const char CREATE_LABEL_INDEX_CMD[] = "CREATE INDEX label ON %s (a3)"; ++static const char CREATE_ID_INDEX_CMD[] = "CREATE INDEX ckaid ON %s (a102)"; ++ ++static CK_RV ++sdb_buildCache(sqlite3 *sqlDB, sdbDataType type, ++ const char *cacheTable, const char *table) ++{ ++ char *newStr; ++ int sqlerr = SQLITE_OK; ++ ++ newStr = sqlite3_mprintf(CREATE_CACHE_CMD, cacheTable, table); ++ if (newStr == NULL) { ++ return CKR_HOST_MEMORY; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ return sdb_mapSQLError(type, sqlerr); ++ } ++ /* failure to create the indexes is not an issue */ ++ newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ return CKR_OK; ++} ++ ++/* ++ * update the cache and the data records describing it. ++ * The cache is updated by dropping the temp database and recreating it. ++ */ ++static CK_RV ++sdb_updateCache(SDBPrivate *sdb_p) ++{ ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ char *newStr; ++ ++ /* drop the old table */ ++ newStr = sqlite3_mprintf(DROP_CACHE_CMD, sdb_p->cacheTable); ++ if (newStr == NULL) { ++ return CKR_HOST_MEMORY; ++ } ++ sqlerr = sqlite3_exec(sdb_p->sqlReadDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if ((sqlerr != SQLITE_OK) && (sqlerr != SQLITE_ERROR)) { ++ /* something went wrong with the drop, don't try to refresh... ++ * NOTE: SQLITE_ERROR is returned if the table doesn't exist. In ++ * that case, we just continue on and try to reload it */ ++ return sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ /* set up the new table */ ++ error = sdb_buildCache(sdb_p->sqlReadDB, sdb_p->type, ++ sdb_p->cacheTable, sdb_p->table); ++ if (error == CKR_OK) { ++ /* we have a new cache! */ ++ sdb_p->lastUpdateTime = PR_IntervalNow(); ++ } ++ return error; ++} ++ ++/* ++ * The sharing of sqlite3 handles across threads is tricky. Older versions ++ * couldn't at all, but newer ones can under strict conditions. Basically ++ * no 2 threads can use the same handle while another thread has an open ++ * stmt running. Once the sqlite3_stmt is finalized, another thread can then ++ * use the database handle. ++ * ++ * We use monitors to protect against trying to use a database before ++ * it's sqlite3_stmt is finalized. This is preferable to the opening and ++ * closing the database each operation because there is significant overhead ++ * in the open and close. Also continually opening and closing the database ++ * defeats the cache code as the cache table is lost on close (thus ++ * requiring us to have to reinitialize the cache every operation). ++ * ++ * An execption to the shared handle is transations. All writes happen ++ * through a transaction. When we are in a transaction, we must use the ++ * same database pointer for that entire transation. In this case we save ++ * the transaction database and use it for all accesses on the transaction ++ * thread. Other threads use the common database. ++ * ++ * There can only be once active transaction on the database at a time. ++ * ++ * sdb_openDBLocal() provides us with a valid database handle for whatever ++ * state we are in (reading or in a transaction), and acquires any locks ++ * appropriate to that state. It also decides when it's time to refresh ++ * the cache before we start an operation. Any database handle returned ++ * just eventually be closed with sdb_closeDBLocal(). ++ * ++ * The table returned either points to the database's physical table, or ++ * to the cached shadow. Tranactions always return the physical table ++ * and read operations return either the physical table or the cache ++ * depending on whether or not the cache exists. ++ */ ++static CK_RV ++sdb_openDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB, const char **table) ++{ ++ *sqlDB = NULL; ++ ++ PR_EnterMonitor(sdb_p->dbMon); ++ ++ if (table) { ++ *table = sdb_p->table; ++ } ++ ++ /* We're in a transaction, use the transaction DB */ ++ if ((sdb_p->sqlXactDB) && (sdb_p->sqlXactThread == PR_GetCurrentThread())) { ++ *sqlDB = sdb_p->sqlXactDB; ++ /* only one thread can get here, safe to unlock */ ++ PR_ExitMonitor(sdb_p->dbMon); ++ return CKR_OK; ++ } ++ ++ /* ++ * if we are just reading from the table, we may have the table ++ * cached in a temporary table (especially if it's on a shared FS). ++ * In that case we want to see updates to the table, the the granularity ++ * is on order of human scale, not computer scale. ++ */ ++ if (table && sdb_p->cacheTable) { ++ PRIntervalTime now = PR_IntervalNow(); ++ if ((now - sdb_p->lastUpdateTime) > sdb_p->updateInterval) { ++ sdb_updateCache(sdb_p); ++ } ++ *table = sdb_p->cacheTable; ++ } ++ ++ *sqlDB = sdb_p->sqlReadDB; ++ ++ /* leave holding the lock. only one thread can actually use a given ++ * database connection at once */ ++ ++ return CKR_OK; ++} ++ ++/* closing the local database currenly means unlocking the monitor */ ++static CK_RV ++sdb_closeDBLocal(SDBPrivate *sdb_p, sqlite3 *sqlDB) ++{ ++ if (sdb_p->sqlXactDB != sqlDB) { ++ /* if we weren't in a transaction, we got a lock */ ++ PR_ExitMonitor(sdb_p->dbMon); ++ } ++ return CKR_OK; ++} ++ ++/* ++ * wrapper to sqlite3_open which also sets the busy_timeout ++ */ ++static int ++sdb_openDB(const char *name, sqlite3 **sqlDB, int flags) ++{ ++ int sqlerr; ++ int openFlags; ++ ++ *sqlDB = NULL; ++ ++ if (flags & SDB_RDONLY) { ++ openFlags = SQLITE_OPEN_READONLY; ++ } else { ++ openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; ++ /* sqlite 3.34 seem to incorrectly open readwrite. ++ * when the file is readonly. Explicitly reject that issue here */ ++ if ((_NSSUTIL_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) && (_NSSUTIL_Access(name, PR_ACCESS_WRITE_OK) != PR_SUCCESS)) { ++ return SQLITE_READONLY; ++ } ++ } ++ ++ /* Requires SQLite 3.5.0 or newer. */ ++ sqlerr = sqlite3_open_v2(name, sqlDB, openFlags, NULL); ++ if (sqlerr != SQLITE_OK) { ++ return sqlerr; ++ } ++ ++ sqlerr = sqlite3_busy_timeout(*sqlDB, SDB_SQLITE_BUSY_TIMEOUT); ++ if (sqlerr != SQLITE_OK) { ++ sqlite3_close(*sqlDB); ++ *sqlDB = NULL; ++ return sqlerr; ++ } ++ return SQLITE_OK; ++} ++ ++/* Sigh, if we created a new table since we opened the database, ++ * the database handle will not see the new table, we need to close this ++ * database and reopen it. Caller must be in a transaction or holding ++ * the dbMon. sqlDB is changed on success. */ ++static int ++sdb_reopenDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB) ++{ ++ sqlite3 *newDB; ++ int sqlerr; ++ ++ /* open a new database */ ++ sqlerr = sdb_openDB(sdb_p->sqlDBName, &newDB, SDB_RDONLY); ++ if (sqlerr != SQLITE_OK) { ++ return sqlerr; ++ } ++ ++ /* if we are in a transaction, we may not be holding the monitor. ++ * grab it before we update the transaction database. This is ++ * safe since are using monitors. */ ++ PR_EnterMonitor(sdb_p->dbMon); ++ /* update our view of the database */ ++ if (sdb_p->sqlReadDB == *sqlDB) { ++ sdb_p->sqlReadDB = newDB; ++ } else if (sdb_p->sqlXactDB == *sqlDB) { ++ sdb_p->sqlXactDB = newDB; ++ } ++ PR_ExitMonitor(sdb_p->dbMon); ++ ++ /* close the old one */ ++ sqlite3_close(*sqlDB); ++ ++ *sqlDB = newDB; ++ return SQLITE_OK; ++} ++ ++struct SDBFindStr { ++ sqlite3 *sqlDB; ++ sqlite3_stmt *findstmt; ++}; ++ ++static const char FIND_OBJECTS_CMD[] = "SELECT ALL id FROM %s WHERE %s;"; ++static const char FIND_OBJECTS_ALL_CMD[] = "SELECT ALL id FROM %s;"; ++CK_RV ++sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count, ++ SDBFind **find) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ const char *table; ++ char *newStr, *findStr = NULL; ++ sqlite3_stmt *findstmt = NULL; ++ char *join = ""; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ unsigned int i; ++ ++ LOCK_SQLITE() ++ *find = NULL; ++ error = sdb_openDBLocal(sdb_p, &sqlDB, &table); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ findStr = sqlite3_mprintf(""); ++ for (i = 0; findStr && i < count; i++) { ++ newStr = sqlite3_mprintf("%s%sa%x=$DATA%d", findStr, join, ++ template[i].type, i); ++ join = " AND "; ++ sqlite3_free(findStr); ++ findStr = newStr; ++ } ++ ++ if (findStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ if (count == 0) { ++ newStr = sqlite3_mprintf(FIND_OBJECTS_ALL_CMD, table); ++ } else { ++ newStr = sqlite3_mprintf(FIND_OBJECTS_CMD, table, findStr); ++ } ++ sqlite3_free(findStr); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &findstmt, NULL); ++ sqlite3_free(newStr); ++ for (i = 0; sqlerr == SQLITE_OK && i < count; i++) { ++ const void *blobData = template[i].pValue; ++ unsigned int blobSize = template[i].ulValueLen; ++ if (blobSize == 0) { ++ blobSize = SQLITE_EXPLICIT_NULL_LEN; ++ blobData = SQLITE_EXPLICIT_NULL; ++ } ++ sqlerr = sqlite3_bind_blob(findstmt, i + 1, blobData, blobSize, ++ SQLITE_TRANSIENT); ++ } ++ if (sqlerr == SQLITE_OK) { ++ *find = PORT_New(SDBFind); ++ if (*find == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ (*find)->findstmt = findstmt; ++ (*find)->sqlDB = sqlDB; ++ UNLOCK_SQLITE() ++ return CKR_OK; ++ } ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ ++loser: ++ if (findstmt) { ++ sqlite3_reset(findstmt); ++ sqlite3_finalize(findstmt); ++ } ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++CK_RV ++sdb_FindObjects(SDB *sdb, SDBFind *sdbFind, CK_OBJECT_HANDLE *object, ++ CK_ULONG arraySize, CK_ULONG *count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3_stmt *stmt = sdbFind->findstmt; ++ int sqlerr = SQLITE_OK; ++ int retry = 0; ++ ++ *count = 0; ++ ++ if (arraySize == 0) { ++ return CKR_OK; ++ } ++ LOCK_SQLITE() ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ /* only care about the id */ ++ *object++ = sqlite3_column_int(stmt, 0); ++ arraySize--; ++ (*count)++; ++ } ++ } while (!sdb_done(sqlerr, &retry) && (arraySize > 0)); ++ ++ /* we only have some of the objects, there is probably more, ++ * set the sqlerr to an OK value so we return CKR_OK */ ++ if (sqlerr == SQLITE_ROW && arraySize == 0) { ++ sqlerr = SQLITE_DONE; ++ } ++ UNLOCK_SQLITE() ++ ++ return sdb_mapSQLError(sdb_p->type, sqlerr); ++} ++ ++CK_RV ++sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3_stmt *stmt = sdbFind->findstmt; ++ sqlite3 *sqlDB = sdbFind->sqlDB; ++ int sqlerr = SQLITE_OK; ++ ++ LOCK_SQLITE() ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlerr = sqlite3_finalize(stmt); ++ } ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ PORT_Free(sdbFind); ++ ++ UNLOCK_SQLITE() ++ return sdb_mapSQLError(sdb_p->type, sqlerr); ++} ++ ++static CK_RV ++sdb_GetValidAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id, ++ CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ const char *table = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int found = 0; ++ int retry = 0; ++ unsigned int i; ++ ++ if (count == 0) { ++ error = CKR_OBJECT_HANDLE_INVALID; ++ goto loser; ++ } ++ ++ /* open a new db if necessary */ ++ error = sdb_openDBLocal(sdb_p, &sqlDB, &table); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ char *columns = NULL; ++ for (i = 0; i < count; i++) { ++ char *newColumns; ++ if (columns) { ++ newColumns = sqlite3_mprintf("%s, a%x", columns, template[i].type); ++ sqlite3_free(columns); ++ columns = NULL; ++ } else { ++ newColumns = sqlite3_mprintf("a%x", template[i].type); ++ } ++ if (!newColumns) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ columns = newColumns; ++ } ++ ++ PORT_Assert(columns); ++ ++ char *statement = sqlite3_mprintf("SELECT DISTINCT %s FROM %s where id=$ID LIMIT 1;", ++ columns, table); ++ sqlite3_free(columns); ++ columns = NULL; ++ if (!statement) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ sqlerr = sqlite3_prepare_v2(sqlDB, statement, -1, &stmt, NULL); ++ sqlite3_free(statement); ++ statement = NULL; ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ // NB: indices in sqlite3_bind_int are 1-indexed ++ sqlerr = sqlite3_bind_int(stmt, 1, object_id); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ PORT_Assert(!found); ++ for (i = 0; i < count; i++) { ++ unsigned int blobSize; ++ const char *blobData; ++ ++ // NB: indices in sqlite_column_{bytes,blob} are 0-indexed ++ blobSize = sqlite3_column_bytes(stmt, i); ++ blobData = sqlite3_column_blob(stmt, i); ++ if (blobData == NULL) { ++ /* PKCS 11 requires that get attributes process all the ++ * attributes in the template, marking the attributes with ++ * issues with -1. Mark the error but continue */ ++ template[i].ulValueLen = -1; ++ error = CKR_ATTRIBUTE_TYPE_INVALID; ++ continue; ++ } ++ /* If the blob equals our explicit NULL value, then the ++ * attribute is a NULL. */ ++ if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) && ++ (PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL, ++ SQLITE_EXPLICIT_NULL_LEN) == 0)) { ++ blobSize = 0; ++ } ++ if (template[i].pValue) { ++ if (template[i].ulValueLen < blobSize) { ++ /* like CKR_ATTRIBUTE_TYPE_INVALID, continue processing */ ++ template[i].ulValueLen = -1; ++ error = CKR_BUFFER_TOO_SMALL; ++ continue; ++ } ++ PORT_Memcpy(template[i].pValue, blobData, blobSize); ++ } ++ template[i].ulValueLen = blobSize; ++ } ++ found = 1; ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ stmt = NULL; ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ if (!found && error == CKR_OK) { ++ error = CKR_OBJECT_HANDLE_INVALID; ++ } ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ /* if we had to open a new database, free it now */ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ return error; ++} ++ ++/* NOTE: requires sdb_p->schemaAttrs to be sorted asc. */ ++inline static PRBool ++sdb_attributeExists(SDB *sdb, CK_ATTRIBUTE_TYPE attr) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ int first = 0; ++ int last = (int)sdb_p->numSchemaAttrs - 1; ++ while (last >= first) { ++ int mid = first + (last - first) / 2; ++ if (sdb_p->schemaAttrs[mid] == attr) { ++ return PR_TRUE; ++ } ++ if (attr > sdb_p->schemaAttrs[mid]) { ++ first = mid + 1; ++ } else { ++ last = mid - 1; ++ } ++ } ++ ++ return PR_FALSE; ++} ++ ++CK_RV ++sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, ++ CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ CK_RV crv = CKR_OK; ++ unsigned int tmplIdx; ++ unsigned int resIdx = 0; ++ unsigned int validCount = 0; ++ unsigned int i; ++ ++ if (count == 0) { ++ return crv; ++ } ++ ++ CK_ATTRIBUTE *validTemplate; ++ PRBool invalidExists = PR_FALSE; ++ for (tmplIdx = 0; tmplIdx < count; tmplIdx++) { ++ if (!sdb_attributeExists(sdb, template[tmplIdx].type)) { ++ template[tmplIdx].ulValueLen = -1; ++ crv = CKR_ATTRIBUTE_TYPE_INVALID; ++ invalidExists = PR_TRUE; ++ break; ++ } ++ } ++ ++ if (!invalidExists) { ++ validTemplate = template; ++ validCount = count; ++ } else { ++ /* Create a new template containing only the valid subset of ++ * input |template|, and query with that. */ ++ validCount = tmplIdx; ++ validTemplate = malloc(sizeof(CK_ATTRIBUTE) * count); ++ if (!validTemplate) { ++ return CKR_HOST_MEMORY; ++ } ++ /* Copy in what we already know is valid. */ ++ for (i = 0; i < validCount; i++) { ++ validTemplate[i] = template[i]; ++ } ++ ++ /* tmplIdx was left at the index of the first invalid ++ * attribute, which has been handled. We only need to ++ * deal with the remainder. */ ++ tmplIdx++; ++ for (; tmplIdx < count; tmplIdx++) { ++ if (sdb_attributeExists(sdb, template[tmplIdx].type)) { ++ validTemplate[validCount++] = template[tmplIdx]; ++ } else { ++ template[tmplIdx].ulValueLen = -1; ++ } ++ } ++ } ++ ++ if (validCount) { ++ LOCK_SQLITE() ++ CK_RV crv2 = sdb_GetValidAttributeValueNoLock(sdb, object_id, validTemplate, validCount); ++ UNLOCK_SQLITE() ++ ++ /* If an invalid attribute was removed above, let ++ * the caller know. Any other error from the actual ++ * query should propogate. */ ++ crv = (crv2 == CKR_OK) ? crv : crv2; ++ } ++ ++ if (invalidExists) { ++ /* Copy out valid lengths. */ ++ tmplIdx = 0; ++ for (resIdx = 0; resIdx < validCount; resIdx++) { ++ for (; tmplIdx < count; tmplIdx++) { ++ if (template[tmplIdx].type != validTemplate[resIdx].type) { ++ continue; ++ } ++ template[tmplIdx].ulValueLen = validTemplate[resIdx].ulValueLen; ++ tmplIdx++; ++ break; ++ } ++ } ++ free(validTemplate); ++ } ++ ++ return crv; ++} ++ ++static const char SET_ATTRIBUTE_CMD[] = "UPDATE %s SET %s WHERE id=$ID;"; ++CK_RV ++sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, ++ const CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ char *setStr = NULL; ++ char *newStr = NULL; ++ int sqlerr = SQLITE_OK; ++ int retry = 0; ++ CK_RV error = CKR_OK; ++ unsigned int i; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ if (count == 0) { ++ return CKR_OK; ++ } ++ ++ LOCK_SQLITE() ++ setStr = sqlite3_mprintf(""); ++ for (i = 0; setStr && i < count; i++) { ++ if (i == 0) { ++ sqlite3_free(setStr); ++ setStr = sqlite3_mprintf("a%x=$VALUE%d", ++ template[i].type, i); ++ continue; ++ } ++ newStr = sqlite3_mprintf("%s,a%x=$VALUE%d", setStr, ++ template[i].type, i); ++ sqlite3_free(setStr); ++ setStr = newStr; ++ } ++ newStr = NULL; ++ ++ if (setStr == NULL) { ++ return CKR_HOST_MEMORY; ++ } ++ newStr = sqlite3_mprintf(SET_ATTRIBUTE_CMD, sdb_p->table, setStr); ++ sqlite3_free(setStr); ++ if (newStr == NULL) { ++ UNLOCK_SQLITE() ++ return CKR_HOST_MEMORY; ++ } ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ for (i = 0; i < count; i++) { ++ if (template[i].ulValueLen != 0) { ++ sqlerr = sqlite3_bind_blob(stmt, i + 1, template[i].pValue, ++ template[i].ulValueLen, SQLITE_STATIC); ++ } else { ++ sqlerr = sqlite3_bind_blob(stmt, i + 1, SQLITE_EXPLICIT_NULL, ++ SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ sqlerr = sqlite3_bind_int(stmt, i + 1, object_id); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ if (newStr) { ++ sqlite3_free(newStr); ++ } ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++/* ++ * check to see if a candidate object handle already exists. ++ */ ++static PRBool ++sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate) ++{ ++ CK_RV crv; ++ CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 }; ++ ++ crv = sdb_GetValidAttributeValueNoLock(sdb, candidate, &template, 1); ++ if (crv == CKR_OBJECT_HANDLE_INVALID) { ++ return PR_FALSE; ++ } ++ return PR_TRUE; ++} ++ ++/* ++ * if we're here, we are in a transaction, so it's safe ++ * to examine the current state of the database ++ */ ++static CK_OBJECT_HANDLE ++sdb_getObjectId(SDB *sdb) ++{ ++ CK_OBJECT_HANDLE candidate; ++ static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE; ++ int count; ++ /* ++ * get an initial object handle to use ++ */ ++ if (next_obj == CK_INVALID_HANDLE) { ++ PRTime time; ++ time = PR_Now(); ++ ++ next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL); ++ } ++ candidate = next_obj++; ++ /* detect that we've looped through all the handles... */ ++ for (count = 0; count < 0x40000000; count++, candidate = next_obj++) { ++ /* mask off excess bits */ ++ candidate &= 0x3fffffff; ++ /* if we hit zero, go to the next entry */ ++ if (candidate == CK_INVALID_HANDLE) { ++ continue; ++ } ++ /* make sure we aren't already using */ ++ if (!sdb_objectExists(sdb, candidate)) { ++ /* this one is free */ ++ return candidate; ++ } ++ } ++ ++ /* no handle is free, fail */ ++ return CK_INVALID_HANDLE; ++} ++ ++CK_RV ++sdb_GetNewObjectID(SDB *sdb, CK_OBJECT_HANDLE *object) ++{ ++ CK_OBJECT_HANDLE id; ++ ++ id = sdb_getObjectId(sdb); ++ if (id == CK_INVALID_HANDLE) { ++ return CKR_DEVICE_MEMORY; /* basically we ran out of resources */ ++ } ++ *object = id; ++ return CKR_OK; ++} ++ ++static const char CREATE_CMD[] = "INSERT INTO %s (id%s) VALUES($ID%s);"; ++CK_RV ++sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, ++ const CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ char *columnStr = NULL; ++ char *valueStr = NULL; ++ char *newStr = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ CK_OBJECT_HANDLE this_object = CK_INVALID_HANDLE; ++ int retry = 0; ++ unsigned int i; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ if ((*object_id != CK_INVALID_HANDLE) && ++ !sdb_objectExists(sdb, *object_id)) { ++ this_object = *object_id; ++ } else { ++ this_object = sdb_getObjectId(sdb); ++ } ++ if (this_object == CK_INVALID_HANDLE) { ++ UNLOCK_SQLITE(); ++ return CKR_HOST_MEMORY; ++ } ++ columnStr = sqlite3_mprintf(""); ++ valueStr = sqlite3_mprintf(""); ++ *object_id = this_object; ++ for (i = 0; columnStr && valueStr && i < count; i++) { ++ newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type); ++ sqlite3_free(columnStr); ++ columnStr = newStr; ++ newStr = sqlite3_mprintf("%s,$VALUE%d", valueStr, i); ++ sqlite3_free(valueStr); ++ valueStr = newStr; ++ } ++ newStr = NULL; ++ if ((columnStr == NULL) || (valueStr == NULL)) { ++ if (columnStr) { ++ sqlite3_free(columnStr); ++ } ++ if (valueStr) { ++ sqlite3_free(valueStr); ++ } ++ UNLOCK_SQLITE() ++ return CKR_HOST_MEMORY; ++ } ++ newStr = sqlite3_mprintf(CREATE_CMD, sdb_p->table, columnStr, valueStr); ++ sqlite3_free(columnStr); ++ sqlite3_free(valueStr); ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_int(stmt, 1, *object_id); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ for (i = 0; i < count; i++) { ++ if (template[i].ulValueLen) { ++ sqlerr = sqlite3_bind_blob(stmt, i + 2, template[i].pValue, ++ template[i].ulValueLen, SQLITE_STATIC); ++ } else { ++ sqlerr = sqlite3_bind_blob(stmt, i + 2, SQLITE_EXPLICIT_NULL, ++ SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ if (newStr) { ++ sqlite3_free(newStr); ++ } ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ ++ return error; ++} ++ ++/* ++ * Generic destroy that can destroy metadata or objects ++ */ ++static const char DESTROY_CMD[] = "DELETE FROM %s WHERE (id=$ID);"; ++CK_RV ++sdb_destroyAnyObject(SDB *sdb, const char *table, ++ CK_OBJECT_HANDLE object_id, const char *string_id) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ char *newStr = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ newStr = sqlite3_mprintf(DESTROY_CMD, table); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ if (string_id == NULL) { ++ sqlerr = sqlite3_bind_int(stmt, 1, object_id); ++ } else { ++ sqlerr = sqlite3_bind_text(stmt, 1, string_id, ++ PORT_Strlen(string_id), SQLITE_STATIC); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++CK_RV ++sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ return sdb_destroyAnyObject(sdb, sdb_p->table, object_id, NULL); ++} ++ ++CK_RV ++sdb_DestroyMetaData(SDB *sdb, const char *id) ++{ ++ return sdb_destroyAnyObject(sdb, "metaData", 0, id); ++} ++ ++static const char BEGIN_CMD[] = "BEGIN IMMEDIATE TRANSACTION;"; ++ ++/* ++ * start a transaction. ++ * ++ * We need to open a new database, then store that new database into ++ * the private data structure. We open the database first, then use locks ++ * to protect storing the data to prevent deadlocks. ++ */ ++CK_RV ++sdb_Begin(SDB *sdb) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ ++ /* get a new version that we will use for the entire transaction */ ++ sqlerr = sdb_openDB(sdb_p->sqlDBName, &sqlDB, SDB_RDWR); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ sqlerr = sqlite3_prepare_v2(sqlDB, BEGIN_CMD, -1, &stmt, NULL); ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ /* don't retry BEGIN transaction*/ ++ retry = 0; ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++loser: ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ ++ /* we are starting a new transaction, ++ * and if we succeeded, then save this database for the rest of ++ * our transaction */ ++ if (error == CKR_OK) { ++ /* we hold a 'BEGIN TRANSACTION' and a sdb_p->lock. At this point ++ * sdb_p->sqlXactDB MUST be null */ ++ PR_EnterMonitor(sdb_p->dbMon); ++ PORT_Assert(sdb_p->sqlXactDB == NULL); ++ sdb_p->sqlXactDB = sqlDB; ++ sdb_p->sqlXactThread = PR_GetCurrentThread(); ++ PR_ExitMonitor(sdb_p->dbMon); ++ } else { ++ /* we failed to start our transaction, ++ * free any databases we opened. */ ++ if (sqlDB) { ++ sqlite3_close(sqlDB); ++ } ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++/* ++ * Complete a transaction. Basically undo everything we did in begin. ++ * There are 2 flavors Abort and Commit. Basically the only differerence between ++ * these 2 are what the database will show. (no change in to former, change in ++ * the latter). ++ */ ++static CK_RV ++sdb_complete(SDB *sdb, const char *cmd) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ /* We must have a transation database, or we shouldn't have arrived here */ ++ PR_EnterMonitor(sdb_p->dbMon); ++ PORT_Assert(sdb_p->sqlXactDB); ++ if (sdb_p->sqlXactDB == NULL) { ++ PR_ExitMonitor(sdb_p->dbMon); ++ return CKR_GENERAL_ERROR; /* shouldn't happen */ ++ } ++ PORT_Assert(sdb_p->sqlXactThread == PR_GetCurrentThread()); ++ if (sdb_p->sqlXactThread != PR_GetCurrentThread()) { ++ PR_ExitMonitor(sdb_p->dbMon); ++ return CKR_GENERAL_ERROR; /* shouldn't happen */ ++ } ++ sqlDB = sdb_p->sqlXactDB; ++ sdb_p->sqlXactDB = NULL; /* no one else can get to this DB, ++ * safe to unlock */ ++ sdb_p->sqlXactThread = NULL; ++ PR_ExitMonitor(sdb_p->dbMon); ++ ++ sqlerr = sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ /* Pending BEGIN TRANSACTIONS Can move forward at this point. */ ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ /* we we have a cached DB image, update it as well */ ++ if (sdb_p->cacheTable) { ++ PR_EnterMonitor(sdb_p->dbMon); ++ sdb_updateCache(sdb_p); ++ PR_ExitMonitor(sdb_p->dbMon); ++ } ++ ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ ++ /* We just finished a transaction. ++ * Free the database, and remove it from the list */ ++ sqlite3_close(sqlDB); ++ ++ return error; ++} ++ ++static const char COMMIT_CMD[] = "COMMIT TRANSACTION;"; ++CK_RV ++sdb_Commit(SDB *sdb) ++{ ++ CK_RV crv; ++ LOCK_SQLITE() ++ crv = sdb_complete(sdb, COMMIT_CMD); ++ UNLOCK_SQLITE() ++ return crv; ++} ++ ++static const char ROLLBACK_CMD[] = "ROLLBACK TRANSACTION;"; ++CK_RV ++sdb_Abort(SDB *sdb) ++{ ++ CK_RV crv; ++ LOCK_SQLITE() ++ crv = sdb_complete(sdb, ROLLBACK_CMD); ++ UNLOCK_SQLITE() ++ return crv; ++} ++ ++static int tableExists(sqlite3 *sqlDB, const char *tableName); ++ ++static const char GET_PW_CMD[] = "SELECT ALL * FROM metaData WHERE id=$ID;"; ++CK_RV ++sdb_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = sdb_p->sqlXactDB; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int found = 0; ++ int retry = 0; ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ /* handle 'test' versions of the sqlite db */ ++ sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); ++ /* Sigh, if we created a new table since we opened the database, ++ * the database handle will not see the new table, we need to close this ++ * database and reopen it. This is safe because we are holding the lock ++ * still. */ ++ if (sqlerr == SQLITE_SCHEMA) { ++ sqlerr = sdb_reopenDBLocal(sdb_p, &sqlDB); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ const char *blobData; ++ unsigned int len = item1->len; ++ item1->len = sqlite3_column_bytes(stmt, 1); ++ if (item1->len > len) { ++ error = CKR_BUFFER_TOO_SMALL; ++ continue; ++ } ++ blobData = sqlite3_column_blob(stmt, 1); ++ PORT_Memcpy(item1->data, blobData, item1->len); ++ if (item2) { ++ len = item2->len; ++ item2->len = sqlite3_column_bytes(stmt, 2); ++ if (item2->len > len) { ++ error = CKR_BUFFER_TOO_SMALL; ++ continue; ++ } ++ blobData = sqlite3_column_blob(stmt, 2); ++ PORT_Memcpy(item2->data, blobData, item2->len); ++ } ++ found = 1; ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ if (!found && error == CKR_OK) { ++ error = CKR_OBJECT_HANDLE_INVALID; ++ } ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ ++ return error; ++} ++ ++static const char PW_CREATE_TABLE_CMD[] = ++ "CREATE TABLE metaData (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, item1, item2);"; ++static const char PW_CREATE_CMD[] = ++ "INSERT INTO metaData (id,item1,item2) VALUES($ID,$ITEM1,$ITEM2);"; ++static const char MD_CREATE_CMD[] = ++ "INSERT INTO metaData (id,item1) VALUES($ID,$ITEM1);"; ++ ++CK_RV ++sdb_PutMetaData(SDB *sdb, const char *id, const SECItem *item1, ++ const SECItem *item2) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = sdb_p->sqlXactDB; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ const char *cmd = PW_CREATE_CMD; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ if (!tableExists(sqlDB, "metaData")) { ++ sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ if (item2 == NULL) { ++ cmd = MD_CREATE_CMD; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_blob(stmt, 2, item1->data, item1->len, SQLITE_STATIC); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ if (item2) { ++ sqlerr = sqlite3_bind_blob(stmt, 3, item2->data, ++ item2->len, SQLITE_STATIC); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ ++ return error; ++} ++ ++static const char RESET_CMD[] = "DELETE FROM %s;"; ++CK_RV ++sdb_Reset(SDB *sdb) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ char *newStr; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ ++ /* only Key databases can be reset */ ++ if (sdb_p->type != SDB_KEY) { ++ return CKR_OBJECT_HANDLE_INVALID; ++ } ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ 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; ++ } ++ ++ /* delete the password entry table */ ++ sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;", ++ NULL, 0, NULL); ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++CK_RV ++sdb_Close(SDB *sdb) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ int sqlerr = SQLITE_OK; ++ sdbDataType type = sdb_p->type; ++ ++ sqlerr = sqlite3_close(sdb_p->sqlReadDB); ++ PORT_Free(sdb_p->sqlDBName); ++ if (sdb_p->cacheTable) { ++ sqlite3_free(sdb_p->cacheTable); ++ } ++ if (sdb_p->dbMon) { ++ PR_DestroyMonitor(sdb_p->dbMon); ++ } ++ free(sdb_p->schemaAttrs); ++ free(sdb_p); ++ free(sdb); ++ return sdb_mapSQLError(type, sqlerr); ++} ++ ++/* ++ * functions to support open ++ */ ++ ++static const char CHECK_TABLE_CMD[] = "SELECT ALL * FROM %s LIMIT 0;"; ++ ++/* return 1 if sqlDB contains table 'tableName */ ++static int ++tableExists(sqlite3 *sqlDB, const char *tableName) ++{ ++ char *cmd = sqlite3_mprintf(CHECK_TABLE_CMD, tableName); ++ int sqlerr = SQLITE_OK; ++ ++ if (cmd == NULL) { ++ return 0; ++ } ++ ++ sqlerr = sqlite3_exec(sqlDB, cmd, NULL, 0, 0); ++ sqlite3_free(cmd); ++ ++ return (sqlerr == SQLITE_OK) ? 1 : 0; ++} ++ ++void ++sdb_SetForkState(PRBool forked) ++{ ++ /* XXXright now this is a no-op. The global fork state in the softokn3 ++ * shared library is already taken care of at the PKCS#11 level. ++ * If and when we add fork state to the sqlite shared library and extern ++ * interface, we will need to set it and reset it from here */ ++} ++ ++static int ++sdb_attributeComparator(const void *a, const void *b) ++{ ++ if (*(CK_ATTRIBUTE_TYPE *)a < *(CK_ATTRIBUTE_TYPE *)b) { ++ return -1; ++ } ++ if (*(CK_ATTRIBUTE_TYPE *)a > *(CK_ATTRIBUTE_TYPE *)b) { ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * initialize a single database ++ */ ++static const char INIT_CMD[] = ++ "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)"; ++ ++CK_RV ++sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, ++ int *newInit, int inFlags, PRUint32 accessOps, SDB **pSdb) ++{ ++ int i; ++ char *initStr = NULL; ++ char *newStr; ++ char *queryStr = NULL; ++ int inTransaction = 0; ++ SDB *sdb = NULL; ++ SDBPrivate *sdb_p = NULL; ++ sqlite3 *sqlDB = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ char *cacheTable = NULL; ++ PRIntervalTime now = 0; ++ char *env; ++ PRBool enableCache = PR_FALSE; ++ PRBool checkFSType = PR_FALSE; ++ PRBool measureSpeed = PR_FALSE; ++ PRBool create; ++ int flags = inFlags & 0x7; ++ ++ *pSdb = NULL; ++ *inUpdate = 0; ++ ++ /* sqlite3 doesn't have a flag to specify that we want to ++ * open the database read only. If the db doesn't exist, ++ * sqlite3 will always create it. ++ */ ++ LOCK_SQLITE(); ++ create = (_NSSUTIL_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS); ++ if ((flags == SDB_RDONLY) && create) { ++ error = sdb_mapSQLError(type, SQLITE_CANTOPEN); ++ goto loser; ++ } ++ sqlerr = sdb_openDB(dbname, &sqlDB, flags); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ /* ++ * SQL created the file, but it doesn't set appropriate modes for ++ * a database. ++ * ++ * NO NSPR call for chmod? :( ++ */ ++ if (create && sdb_chmod(dbname, 0600) != 0) { ++ error = sdb_mapSQLError(type, SQLITE_CANTOPEN); ++ goto loser; ++ } ++ ++ if (flags != SDB_RDONLY) { ++ sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ inTransaction = 1; ++ } ++ if (!tableExists(sqlDB, table)) { ++ *newInit = 1; ++ if (flags != SDB_CREATE) { ++ error = sdb_mapSQLError(type, SQLITE_CANTOPEN); ++ goto loser; ++ } ++ initStr = sqlite3_mprintf(""); ++ for (i = 0; initStr && i < known_attributes_size; i++) { ++ newStr = sqlite3_mprintf("%s, a%x", initStr, known_attributes[i]); ++ sqlite3_free(initStr); ++ initStr = newStr; ++ } ++ if (initStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(INIT_CMD, table, initStr); ++ sqlite3_free(initStr); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, 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) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, 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) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, 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) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, 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) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ } ++ /* ++ * detect the case where we have created the database, but have ++ * not yet updated it. ++ * ++ * We only check the Key database because only the key database has ++ * a metaData table. The metaData table is created when a password ++ * is set, or in the case of update, when a password is supplied. ++ * If no key database exists, then the update would have happened immediately ++ * on noticing that the cert database didn't exist (see newInit set above). ++ */ ++ if (type == SDB_KEY && !tableExists(sqlDB, "metaData")) { ++ *newInit = 1; ++ } ++ ++ /* access to network filesystems are significantly slower than local ones ++ * for database operations. In those cases we need to create a cached copy ++ * of the database in a temporary location on the local disk. SQLITE ++ * already provides a way to create a temporary table and initialize it, ++ * so we use it for the cache (see sdb_buildCache for how it's done).*/ ++ ++ /* ++ * we decide whether or not to use the cache based on the following input. ++ * ++ * NSS_SDB_USE_CACHE environment variable is set to anything other than ++ * "yes" or "no" (for instance, "auto"): NSS will measure the performance ++ * of access to the temp database versus the access to the user's ++ * passed-in database location. If the temp database location is ++ * "significantly" faster we will use the cache. ++ * ++ * NSS_SDB_USE_CACHE environment variable is nonexistent or set to "no": ++ * cache will not be used. ++ * ++ * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will ++ * always be used. ++ * ++ * It is expected that most applications will not need this feature, and ++ * thus it is disabled by default. ++ */ ++ ++ env = PR_GetEnvSecure("NSS_SDB_USE_CACHE"); ++ ++ /* Variables enableCache, checkFSType, measureSpeed are PR_FALSE by default, ++ * which is the expected behavior for NSS_SDB_USE_CACHE="no". ++ * We don't need to check for "no" here. */ ++ if (!env) { ++ /* By default, with no variable set, we avoid expensive measuring for ++ * most FS types. We start with inexpensive FS type checking, and ++ * might perform measuring for some types. */ ++ checkFSType = PR_TRUE; ++ } else if (PORT_Strcasecmp(env, "yes") == 0) { ++ enableCache = PR_TRUE; ++ } else if (PORT_Strcasecmp(env, "no") != 0) { /* not "no" => "auto" */ ++ measureSpeed = PR_TRUE; ++ } ++ ++ if (checkFSType) { ++#if defined(LINUX) && !defined(ANDROID) ++ struct statfs statfs_s; ++ if (statfs(dbname, &statfs_s) == 0) { ++ switch (statfs_s.f_type) { ++ case SMB_SUPER_MAGIC: ++ case 0xff534d42: /* CIFS_MAGIC_NUMBER */ ++ case NFS_SUPER_MAGIC: ++ /* We assume these are slow. */ ++ enableCache = PR_TRUE; ++ break; ++ case CODA_SUPER_MAGIC: ++ case 0x65735546: /* FUSE_SUPER_MAGIC */ ++ case NCP_SUPER_MAGIC: ++ /* It's uncertain if this FS is fast or slow. ++ * It seems reasonable to perform slow measuring for users ++ * with questionable FS speed. */ ++ measureSpeed = PR_TRUE; ++ break; ++ case AFS_SUPER_MAGIC: /* Already implements caching. */ ++ default: ++ break; ++ } ++ } ++#endif ++ } ++ ++ if (measureSpeed) { ++ char *tempDir = NULL; ++ PRUint32 tempOps = 0; ++ /* ++ * Use PR_Access to determine how expensive it ++ * is to check for the existance of a local file compared to the same ++ * check in the temp directory. If the temp directory is faster, cache ++ * the database there. */ ++ tempDir = sdb_getTempDir(sqlDB); ++ if (tempDir) { ++ tempOps = sdb_measureAccess(tempDir); ++ PORT_Free(tempDir); ++ ++ /* There is a cost to continually copying the database. ++ * Account for that cost with the arbitrary factor of 10 */ ++ enableCache = (PRBool)(tempOps > accessOps * 10); ++ } ++ } ++ ++ if (enableCache) { ++ /* try to set the temp store to memory.*/ ++ sqlite3_exec(sqlDB, "PRAGMA temp_store=MEMORY", NULL, 0, NULL); ++ /* Failure to set the temp store to memory is not fatal, ++ * ignore the error */ ++ ++ cacheTable = sqlite3_mprintf("%sCache", table); ++ if (cacheTable == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ /* build the cache table */ ++ error = sdb_buildCache(sqlDB, type, cacheTable, table); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ /* initialize the last cache build time */ ++ now = PR_IntervalNow(); ++ } ++ ++ sdb = (SDB *)malloc(sizeof(SDB)); ++ if (!sdb) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sdb_p = (SDBPrivate *)malloc(sizeof(SDBPrivate)); ++ if (!sdb_p) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ /* Cache the attributes that are held in the table, so we can later check ++ * that queried attributes actually exist. We don't assume the schema ++ * to be exactly |known_attributes|, as it may change over time. */ ++ sdb_p->schemaAttrs = NULL; ++ if (!PORT_Strcmp("nssPublic", table) || ++ !PORT_Strcmp("nssPrivate", table)) { ++ sqlite3_stmt *stmt = NULL; ++ int retry = 0; ++ unsigned int backedAttrs = 0; ++ ++ /* Can't bind parameters to a PRAGMA. */ ++ queryStr = sqlite3_mprintf("PRAGMA table_info(%s);", table); ++ if (queryStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, queryStr, -1, &stmt, NULL); ++ sqlite3_free(queryStr); ++ queryStr = NULL; ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ unsigned int schemaAttrsCapacity = known_attributes_size; ++ sdb_p->schemaAttrs = malloc(schemaAttrsCapacity * sizeof(CK_ATTRIBUTE_TYPE)); ++ if (!sdb_p->schemaAttrs) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ if (backedAttrs == schemaAttrsCapacity) { ++ schemaAttrsCapacity += known_attributes_size; ++ sdb_p->schemaAttrs = realloc(sdb_p->schemaAttrs, ++ schemaAttrsCapacity * sizeof(CK_ATTRIBUTE_TYPE)); ++ if (!sdb_p->schemaAttrs) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ } ++ /* Record the ULONG attribute value. */ ++ char *val = (char *)sqlite3_column_text(stmt, 1); ++ if (val && val[0] == 'a') { ++ CK_ATTRIBUTE_TYPE attr = strtoul(&val[1], NULL, 16); ++ sdb_p->schemaAttrs[backedAttrs++] = attr; ++ } ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ if (sqlerr != SQLITE_DONE) { ++ goto loser; ++ } ++ sqlerr = sqlite3_reset(stmt); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_finalize(stmt); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ sdb_p->numSchemaAttrs = backedAttrs; ++ ++ /* Sort these once so we can shortcut invalid attribute searches. */ ++ qsort(sdb_p->schemaAttrs, sdb_p->numSchemaAttrs, ++ sizeof(CK_ATTRIBUTE_TYPE), sdb_attributeComparator); ++ } ++ ++ /* invariant fields */ ++ sdb_p->sqlDBName = PORT_Strdup(dbname); ++ sdb_p->type = type; ++ sdb_p->table = table; ++ sdb_p->cacheTable = cacheTable; ++ sdb_p->lastUpdateTime = now; ++ /* set the cache delay time. This is how long we will wait before we ++ * decide the existing cache is stale. Currently set to 10 sec */ ++ sdb_p->updateInterval = PR_SecondsToInterval(10); ++ sdb_p->dbMon = PR_NewMonitor(); ++ /* these fields are protected by the lock */ ++ sdb_p->sqlXactDB = NULL; ++ sdb_p->sqlXactThread = NULL; ++ sdb->private = sdb_p; ++ sdb->version = 1; ++ sdb->sdb_flags = inFlags | SDB_HAS_META; ++ sdb->app_private = NULL; ++ sdb->sdb_FindObjectsInit = sdb_FindObjectsInit; ++ sdb->sdb_FindObjects = sdb_FindObjects; ++ sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal; ++ sdb->sdb_GetAttributeValue = sdb_GetAttributeValue; ++ sdb->sdb_SetAttributeValue = sdb_SetAttributeValue; ++ sdb->sdb_CreateObject = sdb_CreateObject; ++ sdb->sdb_DestroyObject = sdb_DestroyObject; ++ sdb->sdb_GetMetaData = sdb_GetMetaData; ++ sdb->sdb_PutMetaData = sdb_PutMetaData; ++ sdb->sdb_DestroyMetaData = sdb_DestroyMetaData; ++ sdb->sdb_Begin = sdb_Begin; ++ sdb->sdb_Commit = sdb_Commit; ++ sdb->sdb_Abort = sdb_Abort; ++ sdb->sdb_Reset = sdb_Reset; ++ sdb->sdb_Close = sdb_Close; ++ sdb->sdb_SetForkState = sdb_SetForkState; ++ sdb->sdb_GetNewObjectID = sdb_GetNewObjectID; ++ ++ if (inTransaction) { ++ sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ goto loser; ++ } ++ inTransaction = 0; ++ } ++ ++ sdb_p->sqlReadDB = sqlDB; ++ ++ *pSdb = sdb; ++ UNLOCK_SQLITE(); ++ return CKR_OK; ++ ++loser: ++ /* lots of stuff to do */ ++ if (inTransaction) { ++ sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL); ++ } ++ if (sdb) { ++ free(sdb); ++ } ++ if (sdb_p) { ++ if (sdb_p->schemaAttrs) { ++ free(sdb_p->schemaAttrs); ++ } ++ free(sdb_p); ++ } ++ if (sqlDB) { ++ sqlite3_close(sqlDB); ++ } ++ UNLOCK_SQLITE(); ++ return error; ++} ++ ++/* sdbopen */ ++CK_RV ++s_open(const char *directory, const char *certPrefix, const char *keyPrefix, ++ int cert_version, int key_version, int flags, ++ SDB **certdb, SDB **keydb, int *newInit) ++{ ++ char *cert = sdb_BuildFileName(directory, certPrefix, ++ "cert", cert_version); ++ char *key = sdb_BuildFileName(directory, keyPrefix, ++ "key", key_version); ++ CK_RV error = CKR_OK; ++ int inUpdate; ++ PRUint32 accessOps; ++ ++ if (certdb) ++ *certdb = NULL; ++ if (keydb) ++ *keydb = NULL; ++ *newInit = 0; ++ ++#ifdef SQLITE_UNSAFE_THREADS ++ if (sqlite_lock == NULL) { ++ sqlite_lock = PR_NewLock(); ++ if (sqlite_lock == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ } ++#endif ++ ++ /* how long does it take to test for a non-existant file in our working ++ * directory? Allows us to test if we may be on a network file system */ ++ accessOps = 1; ++ { ++ char *env; ++ env = PR_GetEnvSecure("NSS_SDB_USE_CACHE"); ++ /* If the environment variable is undefined or set to yes or no, ++ * sdb_init() will ignore the value of accessOps, and we can skip the ++ * measuring.*/ ++ if (env && PORT_Strcasecmp(env, "no") != 0 && ++ PORT_Strcasecmp(env, "yes") != 0) { ++ accessOps = sdb_measureAccess(directory); ++ } ++ } ++ ++ /* ++ * open the cert data base ++ */ ++ if (certdb) { ++ /* initialize Certificate database */ ++ error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate, ++ newInit, flags, accessOps, certdb); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ } ++ ++ /* ++ * open the key data base: ++ * NOTE:if we want to implement a single database, we open ++ * the same database file as the certificate here. ++ * ++ * cert an key db's have different tables, so they will not ++ * conflict. ++ */ ++ if (keydb) { ++ /* initialize the Key database */ ++ error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, ++ newInit, flags, accessOps, keydb); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ } ++ ++loser: ++ if (cert) { ++ sqlite3_free(cert); ++ } ++ if (key) { ++ sqlite3_free(key); ++ } ++ ++ if (error != CKR_OK) { ++ /* currently redundant, but could be necessary if more code is added ++ * just before loser */ ++ if (keydb && *keydb) { ++ sdb_Close(*keydb); ++ } ++ if (certdb && *certdb) { ++ sdb_Close(*certdb); ++ } ++ } ++ ++ return error; ++} ++ ++CK_RV ++s_shutdown() ++{ ++#ifdef SQLITE_UNSAFE_THREADS ++ if (sqlite_lock) { ++ PR_DestroyLock(sqlite_lock); ++ sqlite_lock = NULL; ++ } ++#endif ++ return CKR_OK; ++} +diff --git a/cmd/manifest.mn b/cmd/manifest.mn +--- a/cmd/manifest.mn ++++ b/cmd/manifest.mn +@@ -36,16 +36,17 @@ NSS_SRCDIRS = \ + addbuiltin \ + atob \ + btoa \ + certutil \ + chktest \ + crlutil \ + crmftest \ + dbtest \ ++ dbtool \ + derdump \ + digest \ + httpserv \ + listsuites \ + makepqg \ + multinit \ + nss-policy-check \ + ocspclnt \ diff --git a/SOURCES/nss-3.79-distrusted-certs.patch b/SOURCES/nss-3.79-distrusted-certs.patch new file mode 100644 index 0000000..14a5b0c --- /dev/null +++ b/SOURCES/nss-3.79-distrusted-certs.patch @@ -0,0 +1,375 @@ +# HG changeset patch +# User John M. Schanck +# Date 1648094761 0 +# Thu Mar 24 04:06:01 2022 +0000 +# Node ID b722e523d66297fe4bc1fac0ebb06203138eccbb +# Parent 853b64626b19a46f41f4ba9c684490dc15923c94 +Bug 1751305 - Remove expired explicitly distrusted certificates from certdata.txt. r=KathleenWilson + +Differential Revision: https://phabricator.services.mozilla.com/D141919 + +diff --git a/lib/ckfw/builtins/certdata.txt b/lib/ckfw/builtins/certdata.txt +--- a/lib/ckfw/builtins/certdata.txt ++++ b/lib/ckfw/builtins/certdata.txt +@@ -7663,197 +7663,16 @@ CKA_SERIAL_NUMBER MULTILINE_OCTAL + \377\377 + END + CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED + CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED + CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED + CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + + # +-# Certificate "Explicitly Distrusted DigiNotar PKIoverheid G2" +-# +-# Issuer: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Serial Number: 268435455 (0xfffffff) +-# Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Not Valid Before: Wed May 12 08:51:39 2010 +-# Not Valid After : Mon Mar 23 09:50:05 2020 +-# Fingerprint (MD5): 2E:61:A2:D1:78:CE:EE:BF:59:33:B0:23:14:0F:94:1C +-# Fingerprint (SHA1): D5:F2:57:A9:BF:2D:D0:3F:8B:46:57:F9:2B:C9:A4:C6:92:E1:42:42 +-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "Explicitly Distrusted DigiNotar PKIoverheid G2" +-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +-CKA_SUBJECT MULTILINE_OCTAL +-\060\132\061\013\060\011\006\003\125\004\006\023\002\116\114\061 +-\027\060\025\006\003\125\004\012\014\016\104\151\147\151\116\157 +-\164\141\162\040\102\056\126\056\061\062\060\060\006\003\125\004 +-\003\014\051\104\151\147\151\116\157\164\141\162\040\120\113\111 +-\157\166\145\162\150\145\151\144\040\103\101\040\117\162\147\141 +-\156\151\163\141\164\151\145\040\055\040\107\062 +-END +-CKA_ID UTF8 "0" +-CKA_ISSUER MULTILINE_OCTAL +-\060\132\061\013\060\011\006\003\125\004\006\023\002\116\114\061 +-\027\060\025\006\003\125\004\012\014\016\104\151\147\151\116\157 +-\164\141\162\040\102\056\126\056\061\062\060\060\006\003\125\004 +-\003\014\051\104\151\147\151\116\157\164\141\162\040\120\113\111 +-\157\166\145\162\150\145\151\144\040\103\101\040\117\162\147\141 +-\156\151\163\141\164\151\145\040\055\040\107\062 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\017\377\377\377 +-END +-CKA_VALUE MULTILINE_OCTAL +-\060\202\006\225\060\202\004\175\240\003\002\001\002\002\004\017 +-\377\377\377\060\015\006\011\052\206\110\206\367\015\001\001\013 +-\005\000\060\132\061\013\060\011\006\003\125\004\006\023\002\116 +-\114\061\027\060\025\006\003\125\004\012\014\016\104\151\147\151 +-\116\157\164\141\162\040\102\056\126\056\061\062\060\060\006\003 +-\125\004\003\014\051\104\151\147\151\116\157\164\141\162\040\120 +-\113\111\157\166\145\162\150\145\151\144\040\103\101\040\117\162 +-\147\141\156\151\163\141\164\151\145\040\055\040\107\062\060\036 +-\027\015\061\060\060\065\061\062\060\070\065\061\063\071\132\027 +-\015\062\060\060\063\062\063\060\071\065\060\060\065\132\060\132 +-\061\013\060\011\006\003\125\004\006\023\002\116\114\061\027\060 +-\025\006\003\125\004\012\014\016\104\151\147\151\116\157\164\141 +-\162\040\102\056\126\056\061\062\060\060\006\003\125\004\003\014 +-\051\104\151\147\151\116\157\164\141\162\040\120\113\111\157\166 +-\145\162\150\145\151\144\040\103\101\040\117\162\147\141\156\151 +-\163\141\164\151\145\040\055\040\107\062\060\202\002\042\060\015 +-\006\011\052\206\110\206\367\015\001\001\001\005\000\003\202\002 +-\017\000\060\202\002\012\002\202\002\001\000\261\023\031\017\047 +-\346\154\324\125\206\113\320\354\211\212\105\221\170\254\107\275 +-\107\053\344\374\105\353\117\264\046\163\133\067\323\303\177\366 +-\343\336\327\243\370\055\150\305\010\076\113\224\326\344\207\045 +-\066\153\204\265\030\164\363\050\130\163\057\233\152\317\274\004 +-\036\366\336\335\257\374\113\252\365\333\146\142\045\001\045\202 +-\336\362\227\132\020\156\335\135\251\042\261\004\251\043\163\072 +-\370\161\255\035\317\204\104\353\107\321\257\155\310\174\050\253 +-\307\362\067\172\164\137\137\305\002\024\212\243\132\343\033\154 +-\001\343\135\216\331\150\326\364\011\033\062\334\221\265\054\365 +-\040\353\214\003\155\046\111\270\223\304\205\135\330\322\233\257 +-\126\152\314\005\063\314\240\102\236\064\125\104\234\153\240\324 +-\022\320\053\124\315\267\211\015\345\366\353\350\373\205\001\063 +-\117\172\153\361\235\162\063\226\016\367\262\204\245\245\047\304 +-\047\361\121\163\051\167\272\147\156\376\114\334\264\342\241\241 +-\201\057\071\111\215\103\070\023\316\320\245\134\302\207\072\000 +-\147\145\102\043\361\066\131\012\035\243\121\310\274\243\224\052 +-\061\337\343\074\362\235\032\074\004\260\357\261\012\060\023\163 +-\266\327\363\243\114\001\165\024\205\170\300\327\212\071\130\205 +-\120\372\056\346\305\276\317\213\077\257\217\066\324\045\011\055 +-\322\017\254\162\223\362\277\213\324\120\263\371\025\120\233\231 +-\365\024\331\373\213\221\243\062\046\046\240\370\337\073\140\201 +-\206\203\171\133\053\353\023\075\051\072\301\155\335\275\236\216 +-\207\326\112\256\064\227\005\356\024\246\366\334\070\176\112\351 +-\044\124\007\075\227\150\067\106\153\015\307\250\041\257\023\124 +-\344\011\152\361\115\106\012\311\135\373\233\117\275\336\373\267 +-\124\313\270\070\234\247\071\373\152\055\300\173\215\253\245\247 +-\127\354\112\222\212\063\305\341\040\134\163\330\220\222\053\200 +-\325\017\206\030\151\174\071\117\204\206\274\367\114\133\363\325 +-\264\312\240\302\360\067\042\312\171\122\037\123\346\252\363\220 +-\260\073\335\362\050\375\254\353\305\006\044\240\311\324\057\017 +-\130\375\265\236\354\017\317\262\131\320\242\004\172\070\152\256 +-\162\373\275\360\045\142\224\011\247\005\013\002\003\001\000\001 +-\243\202\001\141\060\202\001\135\060\110\006\003\125\035\040\004 +-\101\060\077\060\075\006\004\125\035\040\000\060\065\060\063\006 +-\010\053\006\001\005\005\007\002\001\026\047\150\164\164\160\072 +-\057\057\167\167\167\056\144\151\147\151\156\157\164\141\162\056 +-\156\154\057\143\160\163\057\160\153\151\157\166\145\162\150\145 +-\151\144\060\017\006\003\125\035\023\001\001\377\004\005\060\003 +-\001\001\377\060\016\006\003\125\035\017\001\001\377\004\004\003 +-\002\001\006\060\201\205\006\003\125\035\043\004\176\060\174\200 +-\024\071\020\213\111\222\134\333\141\022\040\315\111\235\032\216 +-\332\234\147\100\271\241\136\244\134\060\132\061\013\060\011\006 +-\003\125\004\006\023\002\116\114\061\036\060\034\006\003\125\004 +-\012\014\025\123\164\141\141\164\040\144\145\162\040\116\145\144 +-\145\162\154\141\156\144\145\156\061\053\060\051\006\003\125\004 +-\003\014\042\123\164\141\141\164\040\144\145\162\040\116\145\144 +-\145\162\154\141\156\144\145\156\040\122\157\157\164\040\103\101 +-\040\055\040\107\062\202\004\000\230\226\364\060\111\006\003\125 +-\035\037\004\102\060\100\060\076\240\074\240\072\206\070\150\164 +-\164\160\072\057\057\143\162\154\056\160\153\151\157\166\145\162 +-\150\145\151\144\056\156\154\057\104\157\155\117\162\147\141\156 +-\151\163\141\164\151\145\114\141\164\145\163\164\103\122\114\055 +-\107\062\056\143\162\154\060\035\006\003\125\035\016\004\026\004 +-\024\274\135\224\073\331\253\173\003\045\163\141\302\333\055\356 +-\374\253\217\145\241\060\015\006\011\052\206\110\206\367\015\001 +-\001\013\005\000\003\202\002\001\000\217\374\055\114\267\331\055 +-\325\037\275\357\313\364\267\150\027\165\235\116\325\367\335\234 +-\361\052\046\355\237\242\266\034\003\325\123\263\354\010\317\064 +-\342\343\303\364\265\026\057\310\303\276\327\323\163\253\000\066 +-\371\032\112\176\326\143\351\136\106\272\245\266\216\025\267\243 +-\052\330\103\035\357\135\310\037\201\205\263\213\367\377\074\364 +-\331\364\106\010\077\234\274\035\240\331\250\114\315\045\122\116 +-\012\261\040\367\037\351\103\331\124\106\201\023\232\300\136\164 +-\154\052\230\062\352\374\167\273\015\245\242\061\230\042\176\174 +-\174\347\332\244\255\354\267\056\032\031\161\370\110\120\332\103 +-\217\054\204\335\301\100\047\343\265\360\025\116\226\324\370\134 +-\343\206\051\106\053\327\073\007\353\070\177\310\206\127\227\323 +-\357\052\063\304\027\120\325\144\151\153\053\153\105\136\135\057 +-\027\312\132\116\317\303\327\071\074\365\073\237\106\271\233\347 +-\016\111\227\235\326\325\343\033\017\352\217\001\116\232\023\224 +-\131\012\002\007\110\113\032\140\253\177\117\355\013\330\125\015 +-\150\157\125\234\151\145\025\102\354\300\334\335\154\254\303\026 +-\316\013\035\126\233\244\304\304\322\056\340\017\342\104\047\053 +-\120\151\244\334\142\350\212\041\051\102\154\314\000\072\226\166 +-\233\357\100\300\244\136\167\204\062\154\046\052\071\146\256\135 +-\343\271\271\262\054\150\037\036\232\220\003\071\360\252\263\244 +-\314\111\213\030\064\351\067\311\173\051\307\204\174\157\104\025 +-\057\354\141\131\004\311\105\313\242\326\122\242\174\177\051\222 +-\326\112\305\213\102\250\324\376\352\330\307\207\043\030\344\235 +-\172\175\163\100\122\230\240\256\156\343\005\077\005\017\340\245 +-\306\155\115\355\203\067\210\234\307\363\334\102\232\152\266\327 +-\041\111\066\167\362\357\030\117\305\160\331\236\351\336\267\053 +-\213\364\274\176\050\337\015\100\311\205\134\256\235\305\061\377 +-\320\134\016\265\250\176\360\351\057\272\257\210\256\345\265\321 +-\130\245\257\234\161\247\051\001\220\203\151\067\202\005\272\374 +-\011\301\010\156\214\170\073\303\063\002\200\077\104\205\010\035 +-\337\125\126\010\255\054\205\055\135\261\003\341\256\252\164\305 +-\244\363\116\272\067\230\173\202\271 +-END +- +-# Trust for Certificate "Explicitly Distrusted DigiNotar PKIoverheid G2" +-# Issuer: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Serial Number: 268435455 (0xfffffff) +-# Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Not Valid Before: Wed May 12 08:51:39 2010 +-# Not Valid After : Mon Mar 23 09:50:05 2020 +-# Fingerprint (MD5): 2E:61:A2:D1:78:CE:EE:BF:59:33:B0:23:14:0F:94:1C +-# Fingerprint (SHA1): D5:F2:57:A9:BF:2D:D0:3F:8B:46:57:F9:2B:C9:A4:C6:92:E1:42:42 +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "Explicitly Distrusted DigiNotar PKIoverheid G2" +-CKA_CERT_SHA1_HASH MULTILINE_OCTAL +-\325\362\127\251\277\055\320\077\213\106\127\371\053\311\244\306 +-\222\341\102\102 +-END +-CKA_CERT_MD5_HASH MULTILINE_OCTAL +-\056\141\242\321\170\316\356\277\131\063\260\043\024\017\224\034 +-END +-CKA_ISSUER MULTILINE_OCTAL +-\060\132\061\013\060\011\006\003\125\004\006\023\002\116\114\061 +-\027\060\025\006\003\125\004\012\014\016\104\151\147\151\116\157 +-\164\141\162\040\102\056\126\056\061\062\060\060\006\003\125\004 +-\003\014\051\104\151\147\151\116\157\164\141\162\040\120\113\111 +-\157\166\145\162\150\145\151\144\040\103\101\040\117\162\147\141 +-\156\151\163\141\164\151\145\040\055\040\107\062 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\017\377\377\377 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- +-# + # Certificate "Security Communication RootCA2" + # + # Issuer: OU=Security Communication RootCA2,O="SECOM Trust Systems CO.,LTD.",C=JP + # Serial Number: 0 (0x0) + # Subject: OU=Security Communication RootCA2,O="SECOM Trust Systems CO.,LTD.",C=JP + # Not Valid Before: Fri May 29 05:00:39 2009 + # Not Valid After : Tue May 29 05:00:39 2029 + # Fingerprint (SHA-256): 51:3B:2C:EC:B8:10:D4:CD:E5:DD:85:39:1A:DF:C6:C2:DD:60:D8:7B:B7:36:D2:B5:21:48:4A:A4:7A:0E:BE:F6 +@@ -8337,78 +8156,16 @@ END + CKA_SERIAL_NUMBER MULTILINE_OCTAL + \002\001\000 + END + CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR + CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR + CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST + CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +-# Explicitly Distrust "MITM subCA 1 issued by Trustwave", Bug 724929 +-# Issuer: E=ca@trustwave.com,CN="Trustwave Organization Issuing CA, Level 2",O="Trustwave Holdings, Inc.",L=Chicago,ST=Illinois,C=US +-# Serial Number: 1800000005 (0x6b49d205) +-# Not Before: Apr 7 15:37:15 2011 GMT +-# Not After : Apr 4 15:37:15 2021 GMT +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "MITM subCA 1 issued by Trustwave" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\253\061\013\060\011\006\003\125\004\006\023\002\125\123 +-\061\021\060\017\006\003\125\004\010\023\010\111\154\154\151\156 +-\157\151\163\061\020\060\016\006\003\125\004\007\023\007\103\150 +-\151\143\141\147\157\061\041\060\037\006\003\125\004\012\023\030 +-\124\162\165\163\164\167\141\166\145\040\110\157\154\144\151\156 +-\147\163\054\040\111\156\143\056\061\063\060\061\006\003\125\004 +-\003\023\052\124\162\165\163\164\167\141\166\145\040\117\162\147 +-\141\156\151\172\141\164\151\157\156\040\111\163\163\165\151\156 +-\147\040\103\101\054\040\114\145\166\145\154\040\062\061\037\060 +-\035\006\011\052\206\110\206\367\015\001\011\001\026\020\143\141 +-\100\164\162\165\163\164\167\141\166\145\056\143\157\155 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\153\111\322\005 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- +-# Explicitly Distrust "MITM subCA 2 issued by Trustwave", Bug 724929 +-# Issuer: E=ca@trustwave.com,CN="Trustwave Organization Issuing CA, Level 2",O="Trustwave Holdings, Inc.",L=Chicago,ST=Illinois,C=US +-# Serial Number: 1800000006 (0x6b49d206) +-# Not Before: Apr 18 21:09:30 2011 GMT +-# Not After : Apr 15 21:09:30 2021 GMT +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "MITM subCA 2 issued by Trustwave" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\253\061\013\060\011\006\003\125\004\006\023\002\125\123 +-\061\021\060\017\006\003\125\004\010\023\010\111\154\154\151\156 +-\157\151\163\061\020\060\016\006\003\125\004\007\023\007\103\150 +-\151\143\141\147\157\061\041\060\037\006\003\125\004\012\023\030 +-\124\162\165\163\164\167\141\166\145\040\110\157\154\144\151\156 +-\147\163\054\040\111\156\143\056\061\063\060\061\006\003\125\004 +-\003\023\052\124\162\165\163\164\167\141\166\145\040\117\162\147 +-\141\156\151\172\141\164\151\157\156\040\111\163\163\165\151\156 +-\147\040\103\101\054\040\114\145\166\145\154\040\062\061\037\060 +-\035\006\011\052\206\110\206\367\015\001\011\001\026\020\143\141 +-\100\164\162\165\163\164\167\141\166\145\056\143\157\155 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\153\111\322\006 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- + # + # Certificate "Actalis Authentication Root CA" + # + # Issuer: CN=Actalis Authentication Root CA,O=Actalis S.p.A./03358520967,L=Milan,C=IT + # Serial Number:57:0a:11:97:42:c4:e3:cc + # Subject: CN=Actalis Authentication Root CA,O=Actalis S.p.A./03358520967,L=Milan,C=IT + # Not Valid Before: Thu Sep 22 11:22:02 2011 + # Not Valid After : Sun Sep 22 11:22:02 2030 +@@ -9042,84 +8799,16 @@ END + CKA_SERIAL_NUMBER MULTILINE_OCTAL + \002\001\001 + END + CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR + CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST + CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST + CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +-# Explicitly Distrust "TURKTRUST Mis-issued Intermediate CA 1", Bug 825022 +-# Issuer: O=T..RKTRUST Bilgi ..leti..im ve Bili..im G..venli..i Hizmetleri A...,C=TR,CN=T..RKTRUST Elektronik Sunucu Sertifikas.. Hizmetleri +-# Serial Number: 2087 (0x827) +-# Subject: CN=*.EGO.GOV.TR,OU=EGO BILGI ISLEM,O=EGO,L=ANKARA,ST=ANKARA,C=TR +-# Not Valid Before: Mon Aug 08 07:07:51 2011 +-# Not Valid After : Tue Jul 06 07:07:51 2021 +-# Fingerprint (MD5): F8:F5:25:FF:0C:31:CF:85:E1:0C:86:17:C1:CE:1F:8E +-# Fingerprint (SHA1): C6:9F:28:C8:25:13:9E:65:A6:46:C4:34:AC:A5:A1:D2:00:29:5D:B1 +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "TURKTRUST Mis-issued Intermediate CA 1" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\254\061\075\060\073\006\003\125\004\003\014\064\124\303 +-\234\122\113\124\122\125\123\124\040\105\154\145\153\164\162\157 +-\156\151\153\040\123\165\156\165\143\165\040\123\145\162\164\151 +-\146\151\153\141\163\304\261\040\110\151\172\155\145\164\154\145 +-\162\151\061\013\060\011\006\003\125\004\006\023\002\124\122\061 +-\136\060\134\006\003\125\004\012\014\125\124\303\234\122\113\124 +-\122\125\123\124\040\102\151\154\147\151\040\304\260\154\145\164 +-\151\305\237\151\155\040\166\145\040\102\151\154\151\305\237\151 +-\155\040\107\303\274\166\145\156\154\151\304\237\151\040\110\151 +-\172\155\145\164\154\145\162\151\040\101\056\305\236\056\040\050 +-\143\051\040\113\141\163\304\261\155\040\040\062\060\060\065 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\002\010\047 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- +-# Explicitly Distrust "TURKTRUST Mis-issued Intermediate CA 2", Bug 825022 +-# Issuer: O=T..RKTRUST Bilgi ..leti..im ve Bili..im G..venli..i Hizmetleri A...,C=TR,CN=T..RKTRUST Elektronik Sunucu Sertifikas.. Hizmetleri +-# Serial Number: 2148 (0x864) +-# Subject: E=ileti@kktcmerkezbankasi.org,CN=e-islem.kktcmerkezbankasi.org,O=KKTC Merkez Bankasi,L=Lefkosa,ST=Lefkosa,C=TR +-# Not Valid Before: Mon Aug 08 07:07:51 2011 +-# Not Valid After : Thu Aug 05 07:07:51 2021 +-# Fingerprint (MD5): BF:C3:EC:AD:0F:42:4F:B4:B5:38:DB:35:BF:AD:84:A2 +-# Fingerprint (SHA1): F9:2B:E5:26:6C:C0:5D:B2:DC:0D:C3:F2:DC:74:E0:2D:EF:D9:49:CB +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "TURKTRUST Mis-issued Intermediate CA 2" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\254\061\075\060\073\006\003\125\004\003\014\064\124\303 +-\234\122\113\124\122\125\123\124\040\105\154\145\153\164\162\157 +-\156\151\153\040\123\165\156\165\143\165\040\123\145\162\164\151 +-\146\151\153\141\163\304\261\040\110\151\172\155\145\164\154\145 +-\162\151\061\013\060\011\006\003\125\004\006\023\002\124\122\061 +-\136\060\134\006\003\125\004\012\014\125\124\303\234\122\113\124 +-\122\125\123\124\040\102\151\154\147\151\040\304\260\154\145\164 +-\151\305\237\151\155\040\166\145\040\102\151\154\151\305\237\151 +-\155\040\107\303\274\166\145\156\154\151\304\237\151\040\110\151 +-\172\155\145\164\154\145\162\151\040\101\056\305\236\056\040\050 +-\143\051\040\113\141\163\304\261\155\040\040\062\060\060\065 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\002\010\144 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- + # + # Certificate "D-TRUST Root Class 3 CA 2 2009" + # + # Issuer: CN=D-TRUST Root Class 3 CA 2 2009,O=D-Trust GmbH,C=DE + # Serial Number: 623603 (0x983f3) + # Subject: CN=D-TRUST Root Class 3 CA 2 2009,O=D-Trust GmbH,C=DE + # Not Valid Before: Thu Nov 05 08:35:58 2009 + # Not Valid After : Mon Nov 05 08:35:58 2029 diff --git a/SOURCES/nss-3.79-dont-verify-default.patch b/SOURCES/nss-3.79-dont-verify-default.patch new file mode 100644 index 0000000..aa20713 --- /dev/null +++ b/SOURCES/nss-3.79-dont-verify-default.patch @@ -0,0 +1,170 @@ +diff --git a/lib/softoken/legacydb/pcertdb.c b/lib/softoken/legacydb/pcertdb.c +--- a/lib/softoken/legacydb/pcertdb.c ++++ b/lib/softoken/legacydb/pcertdb.c +@@ -4272,16 +4272,17 @@ CreateTrust(void) + { + NSSLOWCERTTrust *trust = NULL; + + nsslowcert_LockFreeList(); + trust = trustListHead; + if (trust) { + trustListCount--; + trustListHead = trust->next; ++ trust->next = NULL; + } + PORT_Assert(trustListCount >= 0); + nsslowcert_UnlockFreeList(); + if (trust) { + return trust; + } + + return PORT_ZNew(NSSLOWCERTTrust); +@@ -5155,19 +5156,21 @@ done: + } + + PRBool + nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust) + { + if (trust == NULL) { + return PR_FALSE; + } +- return !((trust->sslFlags & CERTDB_TRUSTED_UNKNOWN) && +- (trust->emailFlags & CERTDB_TRUSTED_UNKNOWN) && +- (trust->objectSigningFlags & CERTDB_TRUSTED_UNKNOWN)); ++ /* if we only have CERTDB__USER and CERTDB_TRUSTED_UNKNOWN bits, then ++ * we don't have a trust record. */ ++ return !(((trust->sslFlags & ~(CERTDB_USER|CERTDB_TRUSTED_UNKNOWN)) == 0) && ++ ((trust->emailFlags & ~(CERTDB_USER|CERTDB_TRUSTED_UNKNOWN)) == 0) && ++ ((trust->objectSigningFlags & ~(CERTDB_USER|CERTDB_TRUSTED_UNKNOWN)) == 0)); + } + + /* + * This function has the logic that decides if another person's cert and + * email profile from an S/MIME message should be saved. It can deal with + * the case when there is no profile. + */ + static SECStatus +diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c +--- a/lib/softoken/sftkdb.c ++++ b/lib/softoken/sftkdb.c +@@ -119,47 +119,79 @@ sftkdb_isAuthenticatedAttribute(CK_ATTRI + case CKA_TRUST_STEP_UP_APPROVED: + case CKA_NSS_OVERRIDE_EXTENSIONS: + return PR_TRUE; + default: + break; + } + return PR_FALSE; + } +- + /* + * convert a native ULONG to a database ulong. Database ulong's + * are all 4 byte big endian values. + */ + void + sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value) + { + int i; + + for (i = 0; i < SDB_ULONG_SIZE; i++) { + data[i] = (value >> (SDB_ULONG_SIZE - 1 - i) * BBP) & 0xff; + } + } + + /* + * convert a database ulong back to a native ULONG. (reverse of the above +- * function. ++ * function). + */ + static CK_ULONG + sftk_SDBULong2ULong(unsigned char *data) + { + int i; + CK_ULONG value = 0; + + for (i = 0; i < SDB_ULONG_SIZE; i++) { + value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * BBP); + } + return value; + } + ++/* certain trust records are default values, which are the values ++ * returned if the signature check fails anyway. ++ * In those cases, we can skip the signature check. */ ++PRBool ++sftkdb_isNullTrust(const CK_ATTRIBUTE *template) ++{ ++ switch (template->type) { ++ case CKA_TRUST_SERVER_AUTH: ++ case CKA_TRUST_CLIENT_AUTH: ++ case CKA_TRUST_EMAIL_PROTECTION: ++ case CKA_TRUST_CODE_SIGNING: ++ if (template->ulValueLen != SDB_ULONG_SIZE) { ++ break; ++ } ++ if (sftk_SDBULong2ULong(template->pValue) == ++ CKT_NSS_TRUST_UNKNOWN) { ++ return PR_TRUE; ++ } ++ break; ++ case CKA_TRUST_STEP_UP_APPROVED: ++ if (template->ulValueLen != 1) { ++ break; ++ } ++ if (*((unsigned char *)(template->pValue)) == 0) { ++ return PR_TRUE; ++ } ++ break; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ + /* + * fix up the input templates. Our fixed up ints are stored in data and must + * be freed by the caller. The new template must also be freed. If there are no + * CK_ULONG attributes, the orignal template is passed in as is. + */ + static CK_ATTRIBUTE * + sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, + unsigned char **dataOut, int *dataOutSize) +@@ -410,17 +442,18 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te + } + + /* copy the plain text back into the template */ + PORT_Memcpy(template[i].pValue, plainText->data, plainText->len); + template[i].ulValueLen = plainText->len; + SECITEM_ZfreeItem(plainText, PR_TRUE); + } + /* make sure signed attributes are valid */ +- if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) { ++ if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type) ++ && !sftkdb_isNullTrust(&ntemplate[i])) { + SECStatus rv; + CK_RV local_crv; + SECItem signText; + SECItem plainText; + unsigned char signData[SDB_MAX_META_DATA_LEN]; + + signText.data = signData; + signText.len = sizeof(signData); +@@ -2387,16 +2420,18 @@ sftkdb_mergeObject(SFTKDBHandle *handle, + crv = (*source->sdb_GetAttributeValue)(source, id, + ptemplate, max_attributes); + if (crv != CKR_OK) { + goto loser; + } + + objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate, + max_attributes); ++printf(" - merging object Type 0x%08lx id=0x%08lx updateID=%s\n", objectType, id, ++ handle->updateID?handle->updateID: ""); + + /* + * Update Object updates the object template if necessary then returns + * whether or not we need to actually write the object out to our target + * database. + */ + if (!handle->updateID) { + crv = sftkdb_CreateObject(arena, handle, target, &newID, diff --git a/SOURCES/nss-3.79-fix-client-cert-crash.patch b/SOURCES/nss-3.79-fix-client-cert-crash.patch new file mode 100644 index 0000000..5f80fdc --- /dev/null +++ b/SOURCES/nss-3.79-fix-client-cert-crash.patch @@ -0,0 +1,23 @@ +diff --git a/lib/ssl/authcert.c b/lib/ssl/authcert.c +--- a/lib/ssl/authcert.c ++++ b/lib/ssl/authcert.c +@@ -212,17 +212,17 @@ NSS_GetClientAuthData(void *arg, + pw_arg); + } else { + int nnames = 0; + char **names = ssl_DistNamesToStrings(caNames, &nnames); + rv = CERT_FilterCertListByCANames(certList, nnames, names, + certUsageSSLClient); + ssl_FreeDistNamesStrings(names, nnames); + } +- if ((rv != SECSuccess) || CERT_LIST_EMPTY(certList)) { ++ if ((rv != SECSuccess) || (certList && CERT_LIST_EMPTY(certList))) { + CERT_DestroyCertList(certList); + certList = NULL; + } + } + if (certList == NULL) { + /* no user certs meeting the nickname/usage requirements found */ + return SECFailure; + } + diff --git a/SOURCES/nss-539183.patch b/SOURCES/nss-539183.patch deleted file mode 100644 index 267e71e..0000000 --- a/SOURCES/nss-539183.patch +++ /dev/null @@ -1,62 +0,0 @@ ---- nss/cmd/httpserv/httpserv.c.539183 2016-05-21 18:31:39.879585420 -0700 -+++ nss/cmd/httpserv/httpserv.c 2016-05-21 18:37:22.374464057 -0700 -@@ -953,23 +953,23 @@ - getBoundListenSocket(unsigned short port) - { - PRFileDesc *listen_sock; - int listenQueueDepth = 5 + (2 * maxThreads); - PRStatus prStatus; - PRNetAddr addr; - PRSocketOptionData opt; - -- addr.inet.family = PR_AF_INET; -- addr.inet.ip = PR_INADDR_ANY; -- addr.inet.port = PR_htons(port); -+ if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, port, &addr) != PR_SUCCESS) { -+ errExit("PR_SetNetAddr"); -+ } - -- listen_sock = PR_NewTCPSocket(); -+ listen_sock = PR_OpenTCPSocket(PR_AF_INET6); - if (listen_sock == NULL) { -- errExit("PR_NewTCPSocket"); -+ errExit("PR_OpenTCPSockett"); - } - - opt.option = PR_SockOpt_Nonblocking; - opt.value.non_blocking = PR_FALSE; - prStatus = PR_SetSocketOption(listen_sock, &opt); - if (prStatus < 0) { - PR_Close(listen_sock); - errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)"); ---- nss/cmd/selfserv/selfserv.c.539183 2016-05-21 18:31:39.882585367 -0700 -+++ nss/cmd/selfserv/selfserv.c 2016-05-21 18:41:43.092801174 -0700 -@@ -1711,23 +1711,23 @@ - getBoundListenSocket(unsigned short port) - { - PRFileDesc *listen_sock; - int listenQueueDepth = 5 + (2 * maxThreads); - PRStatus prStatus; - PRNetAddr addr; - PRSocketOptionData opt; - -- addr.inet.family = PR_AF_INET; -- addr.inet.ip = PR_INADDR_ANY; -- addr.inet.port = PR_htons(port); -+ if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, port, &addr) != PR_SUCCESS) { -+ errExit("PR_SetNetAddr"); -+ } - -- listen_sock = PR_NewTCPSocket(); -+ listen_sock = PR_OpenTCPSocket(PR_AF_INET6); - if (listen_sock == NULL) { -- errExit("PR_NewTCPSocket"); -+ errExit("PR_OpenTCPSocket error"); - } - - opt.option = PR_SockOpt_Nonblocking; - opt.value.non_blocking = PR_FALSE; - prStatus = PR_SetSocketOption(listen_sock, &opt); - if (prStatus < 0) { - PR_Close(listen_sock); - errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)"); diff --git a/SPECS/nss.spec b/SPECS/nss.spec index 3f000bc..303cd9b 100644 --- a/SPECS/nss.spec +++ b/SPECS/nss.spec @@ -1,6 +1,7 @@ -%global nspr_build_version 4.25.0 -%global nspr_version 4.25.0 -%global nss_version 3.67.0 +%global nspr_build_version 4.34.0-3 +%global nspr_release -3 +%global nspr_version 4.34.0 +%global nss_version 3.79.0 %global unsupported_tools_directory %{_libdir}/nss/unsupported-tools %global saved_files_dir %{_libdir}/nss/saved %global dracutlibdir %{_prefix}/lib/dracut @@ -44,13 +45,28 @@ rpm.define(string.format("nss_release_tag NSS_%s_RTM", string.gsub(rpm.expand("%nss_archive_version"), "%.", "_"))) } +# This is taken from gnutls.spec +%define srpmhash() %{lua: +local files = rpm.expand("%_specdir/nss.spec") +for i, p in ipairs(patches) do + files = files.." "..p +end +for i, p in ipairs(sources) do + files = files.." "..p +end +local sha256sum = assert(io.popen("cat "..files.."| sha256sum")) +local hash = sha256sum:read("*a") +sha256sum:close() +print(string.sub(hash, 0, 16)) +} + Summary: Network Security Services Name: nss Version: %{nss_version} -Release: 7%{?dist} +Release: 4%{?dist} License: MPLv2.0 URL: http://www.mozilla.org/projects/security/pki/nss/ -Requires: nspr >= %{nspr_version} +Requires: nspr >= %{nspr_version}%{nspr_release} Requires: nss-util >= %{nss_version} # TODO: revert to same version as nss once we are done with the merge Requires: nss-softokn%{_isa} >= %{nss_version} @@ -93,12 +109,10 @@ Source25: key3.db.xml Source26: key4.db.xml Source27: secmod.db.xml Source28: nss-p11-kit.config -Source30: PayPalEE.cert +#Source30: PayPalEE.cert # To inject hardening flags for DSO Patch1: nss-dso-ldflags.patch -# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=617723 -Patch2: nss-539183.patch # This patch uses the GCC -iquote option documented at # http://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html#Directory-Options # to give the in-tree headers a higher priority over the system headers, @@ -139,27 +153,13 @@ Patch45: nss-3.66-disable-external-host-test.patch # Local patch: restore old pkcs 12 defaults on old version of rhel Patch50: nss-3.66-restore-old-pkcs12-default.patch -# Patches that should be upstreamed, and (hopefully) will disappear next -# rebase -# Need upstream bug -Patch219: nss-3.44-kbkdf-coverity.patch -# no upsteam bug yet -Patch225: nss-3.67-fix-private-key-mac.patch -# no upstream bug yet -Patch229: nss-3.53.1-measure-fix.patch -# no upstream bug yet -Patch230: nss-3.66-no-small-primes.patch -# no upstream bug yet -Patch232: nss-3.66-fix-gtest-parsing.patch -# no upstream bug yet -Patch233: nss-3.67-fix-coverity-issues.patch -# no upstream bug yet -Patch234: nss-3.67-fix-sdb-timeout.patch -# no upstream bug yet -Patch235: nss-3.67-fix-ssl-alerts.patch -Patch300: nss-3.67-cve-2021-43527.patch -Patch301: nss-3.67-cve-2021-43527-test.patch +# post upstream release patches (need to be upstreamed) +Patch60: nss-3.79-dbtool.patch +Patch61: nss-3.79-dont-verify-default.patch +Patch63: nss-3.79-fix-client-cert-crash.patch +# restore expired distrusted certs for now +Patch300: nss-3.79-distrusted-certs.patch %description @@ -203,7 +203,7 @@ Provides: nss-static = %{version}-%{release} Requires: nss%{?_isa} = %{version}-%{release} Requires: nss-util-devel Requires: nss-softokn-devel -Requires: nspr-devel >= %{nspr_version} +Requires: nspr-devel >= %{nspr_version}%{nspr_release} Requires: pkgconfig BuildRequires: xmlto @@ -224,7 +224,7 @@ low level services. %package util Summary: Network Security Services Utilities Library -Requires: nspr >= %{nspr_version} +Requires: nspr >= %{nspr_version}%{nspr_release} %description util Utilities for Network Security Services and the Softoken module @@ -232,7 +232,7 @@ Utilities for Network Security Services and the Softoken module %package util-devel Summary: Development libraries for Network Security Services Utilities Requires: nss-util%{?_isa} = %{version}-%{release} -Requires: nspr-devel >= %{nspr_version} +Requires: nspr-devel >= %{nspr_version}%{nspr_release} Requires: pkgconfig %description util-devel @@ -241,7 +241,7 @@ Header and library files for doing development with Network Security Services. %package softokn Summary: Network Security Services Softoken Module -Requires: nspr >= %{nspr_version} +Requires: nspr >= %{nspr_version}%{nspr_release} Requires: nss-util >= %{version}-%{release} Requires: nss-softokn-freebl%{_isa} >= %{version}-%{release} @@ -278,7 +278,7 @@ Developers should rely only on the officially supported NSS public API. Summary: Development libraries for Network Security Services Requires: nss-softokn%{?_isa} = %{version}-%{release} Requires: nss-softokn-freebl-devel%{?_isa} = %{version}-%{release} -Requires: nspr-devel >= %{nspr_version} +Requires: nspr-devel >= %{nspr_version}%{nspr_release} Requires: nss-util-devel >= %{version}-%{release} Requires: pkgconfig BuildRequires: nspr-devel >= %{nspr_build_version} @@ -290,14 +290,15 @@ Header and library files for doing development with Network Security Services. %prep %autosetup -N -n %{name}-%{nss_archive_version} pushd nss -%autopatch -p1 +%autopatch -p1 -M 299 +%patch300 -R -p1 popd # https://bugzilla.redhat.com/show_bug.cgi?id=1247353 find nss/lib/libpkix -perm /u+x -type f -exec chmod -x {} \; #update paypal cert (git binary patches don't work with autopatch) -cp %{SOURCE30} nss/tests/libpkix/certs/ +#cp %{SOURCE30} nss/tests/libpkix/certs/ %build @@ -312,7 +313,13 @@ export FREEBL_LOWHASH=1 # uncomment if the iquote patch is activated export IN_TREE_FREEBL_HEADERS_FIRST=1 +# FIPS related defines export NSS_FORCE_FIPS=1 +export NSS_FIPS_VERSION="%{name}\ %{version}-%{srpmhash}" +eval $(sed -n 's/^\(\(NAME\|VERSION_ID\)=.*\)/OS_\1/p' /etc/os-release | sed -e 's/ /\\ /g') +export FIPS_MODULE_OS="$OS_NAME\ ${OS_VERSION_ID%%.*}" +export NSS_FIPS_MODULE_ID="${FIPS_MODULE_OS}\ ${NSS_FIPS_VERSION}" + # Enable compiler optimizations and disable debugging code export BUILD_OPT=1 @@ -603,7 +610,7 @@ do done # Copy the binaries we ship as unsupported -for file in bltest ecperf fbectest fipstest shlibsign atob btoa derdump listsuites ocspclnt pp selfserv signtool strsclnt symkeyutil tstclnt vfyserv vfychain +for file in bltest dbtool ecperf fbectest fipstest shlibsign atob btoa derdump listsuites ocspclnt pp selfserv signtool strsclnt symkeyutil tstclnt validation vfyserv vfychain do install -p -m 755 dist/*.OBJ/bin/$file $RPM_BUILD_ROOT/%{unsupported_tools_directory} done @@ -728,6 +735,7 @@ update-crypto-policies --no-reload &> /dev/null || : %{unsupported_tools_directory}/strsclnt %{unsupported_tools_directory}/symkeyutil %{unsupported_tools_directory}/tstclnt +%{unsupported_tools_directory}/validation %{unsupported_tools_directory}/vfyserv %{unsupported_tools_directory}/vfychain # instead of %%{_mandir}/man*/* let's list them explicitly @@ -885,6 +893,7 @@ update-crypto-policies --no-reload &> /dev/null || : %dir %{saved_files_dir} %dir %{unsupported_tools_directory} %{unsupported_tools_directory}/bltest +%{unsupported_tools_directory}/dbtool %{unsupported_tools_directory}/ecperf %{unsupported_tools_directory}/fbectest %{unsupported_tools_directory}/fipstest @@ -932,6 +941,22 @@ update-crypto-policies --no-reload &> /dev/null || : %changelog +* Fri Jun 17 2022 Bob Relyea - 3.79.0-4 +- Fix pkgconfig output + +* Wed Jun 15 2022 Bob Relyea - 3.79.0-3 +- NSR Coverity fix changed selfserv from passive to active, change it back + +* Sat Jun 11 2022 Bob Relyea - 3.79.0-2 +- Fix regressions found in test suites. + +* Thu Jun 2 2022 Bob Relyea - 3.79.0-1 +- Rebase to NSS 3.79 +- Set FIPS Module ID +- skip attribute verification on attributes with default values +- don't export trust objects if they are default trust objects from dbm +- add dbtool to nss-tools + * Thu Nov 18 2021 Bob Relyea - 3.67.0-7 - Fix CVE 2021 43527