From 12155fa416fc6f997119b1b5543168bd4b4a3dbd Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 13 Sep 2022 03:38:18 -0400 Subject: [PATCH] import nss-3.79.0-10.el8_6 --- .gitignore | 3 +- .nss.metadata | 3 +- SOURCES/nss-3.44-kbkdf-coverity.patch | 39 - SOURCES/nss-3.53.1-measure-fix.patch | 24 - SOURCES/nss-3.66-fix-gtest-parsing.patch | 16 - SOURCES/nss-3.66-no-small-primes.patch | 86 - SOURCES/nss-3.67-cve-2021-43527-test.patch | 325 -- SOURCES/nss-3.67-cve-2021-43527.patch | 279 -- SOURCES/nss-3.67-fix-coverity-issues.patch | 45 - SOURCES/nss-3.67-fix-private-key-mac.patch | 81 - SOURCES/nss-3.67-fix-sdb-timeout.patch | 63 - SOURCES/nss-3.67-fix-ssl-alerts.patch | 122 - SOURCES/nss-3.79-dbtool.patch | 3411 +++++++++++++++++ SOURCES/nss-3.79-dont-verify-default.patch | 170 + SOURCES/nss-3.79-enable-POST-rerun.patch | 522 +++ SOURCES/nss-3.79-fips.patch | 742 ++++ SOURCES/nss-3.79-fix-client-cert-crash.patch | 23 + SOURCES/nss-3.79-increase-pbe-cache.patch | 22 + SOURCES/nss-3.79-pkcs12-fips-defaults.patch | 25 + .../nss-3.79-pkcs12-fix-null-password.patch | 21 + .../nss-3.79-revert-distrusted-certs.patch | 335 ++ ...ss-3.79-rhel-8-fips-signature-policy.patch | 685 ++++ SOURCES/nss-539183.patch | 62 - SPECS/nss.spec | 132 +- 24 files changed, 6050 insertions(+), 1186 deletions(-) delete mode 100644 SOURCES/nss-3.44-kbkdf-coverity.patch delete mode 100644 SOURCES/nss-3.53.1-measure-fix.patch delete mode 100644 SOURCES/nss-3.66-fix-gtest-parsing.patch delete mode 100644 SOURCES/nss-3.66-no-small-primes.patch delete mode 100644 SOURCES/nss-3.67-cve-2021-43527-test.patch delete mode 100644 SOURCES/nss-3.67-cve-2021-43527.patch delete mode 100644 SOURCES/nss-3.67-fix-coverity-issues.patch delete mode 100644 SOURCES/nss-3.67-fix-private-key-mac.patch delete mode 100644 SOURCES/nss-3.67-fix-sdb-timeout.patch delete mode 100644 SOURCES/nss-3.67-fix-ssl-alerts.patch create mode 100644 SOURCES/nss-3.79-dbtool.patch create mode 100644 SOURCES/nss-3.79-dont-verify-default.patch create mode 100644 SOURCES/nss-3.79-enable-POST-rerun.patch create mode 100644 SOURCES/nss-3.79-fips.patch create mode 100644 SOURCES/nss-3.79-fix-client-cert-crash.patch create mode 100644 SOURCES/nss-3.79-increase-pbe-cache.patch create mode 100644 SOURCES/nss-3.79-pkcs12-fips-defaults.patch create mode 100644 SOURCES/nss-3.79-pkcs12-fix-null-password.patch create mode 100644 SOURCES/nss-3.79-revert-distrusted-certs.patch create mode 100644 SOURCES/nss-3.79-rhel-8-fips-signature-policy.patch delete mode 100644 SOURCES/nss-539183.patch 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-dont-verify-default.patch b/SOURCES/nss-3.79-dont-verify-default.patch new file mode 100644 index 0000000..6c747b6 --- /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-enable-POST-rerun.patch b/SOURCES/nss-3.79-enable-POST-rerun.patch new file mode 100644 index 0000000..47c1ff8 --- /dev/null +++ b/SOURCES/nss-3.79-enable-POST-rerun.patch @@ -0,0 +1,522 @@ +diff --git a/cmd/bltest/blapitest.c b/cmd/bltest/blapitest.c +--- a/cmd/bltest/blapitest.c ++++ b/cmd/bltest/blapitest.c +@@ -3870,17 +3870,17 @@ main(int argc, char **argv) + rv = blapi_selftest(modesToTest, numModesToTest, inoff, outoff, + encrypt, decrypt); + PORT_Free(cipherInfo); + return rv == SECSuccess ? 0 : 1; + } + + /* Do FIPS self-test */ + if (bltest.commands[cmd_FIPS].activated) { +- CK_RV ckrv = sftk_FIPSEntryOK(); ++ CK_RV ckrv = sftk_FIPSEntryOK(PR_FALSE); + fprintf(stdout, "CK_RV: %ld.\n", ckrv); + PORT_Free(cipherInfo); + if (ckrv == CKR_OK) + return SECSuccess; + return SECFailure; + } + + /* +diff --git a/cmd/pk11mode/pk11mode.c b/cmd/pk11mode/pk11mode.c +--- a/cmd/pk11mode/pk11mode.c ++++ b/cmd/pk11mode/pk11mode.c +@@ -318,23 +318,25 @@ static PRBool verbose = PR_FALSE; + + int + main(int argc, char **argv) + { + CK_C_GetFunctionList pC_GetFunctionList; + CK_FUNCTION_LIST_PTR pFunctionList; + CK_RV crv = CKR_OK; + CK_C_INITIALIZE_ARGS_NSS initArgs; ++ CK_C_INITIALIZE_ARGS_NSS initArgsRerun; /* rerun selftests */ + CK_SLOT_ID *pSlotList = NULL; + CK_TOKEN_INFO tokenInfo; + CK_ULONG slotID = 0; /* slotID == 0 for FIPSMODE */ + + CK_UTF8CHAR *pwd = NULL; + CK_ULONG pwdLen = 0; + char *moduleSpec = NULL; ++ char *moduleSpecRerun = NULL; + char *configDir = NULL; + char *dbPrefix = NULL; + char *disableUnload = NULL; + PRBool doForkTests = PR_TRUE; + + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "nvhf:Fd:p:"); + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { +@@ -458,18 +460,23 @@ main(int argc, char **argv) + initArgs.CreateMutex = NULL; + initArgs.DestroyMutex = NULL; + initArgs.LockMutex = NULL; + initArgs.UnlockMutex = NULL; + initArgs.flags = CKF_OS_LOCKING_OK; + moduleSpec = PR_smprintf("configdir='%s' certPrefix='%s' " + "keyPrefix='%s' secmod='secmod.db' flags= ", + configDir, dbPrefix, dbPrefix); ++ moduleSpecRerun = PR_smprintf("configdir='%s' certPrefix='%s' " ++ "keyPrefix='%s' secmod='secmod.db' flags=forcePOST ", ++ configDir, dbPrefix, dbPrefix); + initArgs.LibraryParameters = (CK_CHAR_PTR *)moduleSpec; + initArgs.pReserved = NULL; ++ initArgsRerun = initArgs; ++ initArgsRerun.LibraryParameters = (CK_CHAR_PTR *)moduleSpecRerun; + + /*DebugBreak();*/ + /* FIPSMODE invokes FC_Initialize as pFunctionList->C_Initialize */ + /* NSS cryptographic module library initialization for the FIPS */ + /* Approved mode when FC_Initialize is envoked will perfom */ + /* software integrity test, and power-up self-tests before */ + /* FC_Initialize returns */ + crv = pFunctionList->C_Initialize(&initArgs); +@@ -705,17 +712,17 @@ main(int argc, char **argv) + PKM_Error("PKM_HybridMode failed with 0x%08X, %-26s\n", crv, + PKM_CK_RVtoStr(crv)); + goto cleanup; + } + + if (doForkTests) { + /* testing one more C_Initialize / C_Finalize to exercise getpid() + * fork check code */ +- crv = pFunctionList->C_Initialize(&initArgs); ++ crv = pFunctionList->C_Initialize(&initArgsRerun); + if (crv == CKR_OK) { + PKM_LogIt("C_Initialize succeeded\n"); + } else { + PKM_Error("C_Initialize failed with 0x%08X, %-26s\n", crv, + PKM_CK_RVtoStr(crv)); + goto cleanup; + } + crv = pFunctionList->C_Finalize(NULL); +@@ -741,16 +748,19 @@ cleanup: + free(configDir); + } + if (dbPrefix) { + free(dbPrefix); + } + if (moduleSpec) { + PR_smprintf_free(moduleSpec); + } ++ if (moduleSpecRerun) { ++ PR_smprintf_free(moduleSpecRerun); ++ } + + #ifdef _WIN32 + FreeLibrary(hModule); + #else + disableUnload = PR_GetEnvSecure("NSS_DISABLE_UNLOAD"); + if (!disableUnload) { + PR_UnloadLibrary(lib); + } +diff --git a/lib/freebl/blapii.h b/lib/freebl/blapii.h +--- a/lib/freebl/blapii.h ++++ b/lib/freebl/blapii.h +@@ -24,17 +24,17 @@ typedef SECStatus (*freeblAeadFunc)(void + void *params, unsigned int paramsLen, + const unsigned char *aad, unsigned int aadLen, + unsigned int blocksize); + typedef void (*freeblDestroyFunc)(void *cx, PRBool freeit); + + SEC_BEGIN_PROTOS + + #ifndef NSS_FIPS_DISABLED +-SECStatus BL_FIPSEntryOK(PRBool freeblOnly); ++SECStatus BL_FIPSEntryOK(PRBool freeblOnly, PRBool rerun); + PRBool BL_POSTRan(PRBool freeblOnly); + #endif + + #if defined(XP_UNIX) && !defined(NO_FORK_CHECK) + + extern PRBool bl_parentForkedAfterC_Initialize; + + #define SKIP_AFTER_FORK(x) \ +diff --git a/lib/freebl/blapit.h b/lib/freebl/blapit.h +--- a/lib/freebl/blapit.h ++++ b/lib/freebl/blapit.h +@@ -223,16 +223,21 @@ typedef int __BLAPI_DEPRECATED __attribu + * + * If we arbitrarily set p = 10^-18 (1 chance in trillion trillion operation) + * we get GCMIV_RANDOM_BIRTHDAY_BITS = -(-18)/.301 -1 = 59 (.301 = log10 2) + * GCMIV_RANDOM_BIRTHDAY_BITS should be at least 59, call it a round 64. NOTE: + * the variable IV size for TLS is 64 bits, which explains why it's not safe + * to use a random value for the nonce in TLS. */ + #define GCMIV_RANDOM_BIRTHDAY_BITS 64 + ++/* flag to tell BLAPI_Verify* to rerun the post and integrity tests */ ++#define BLAPI_FIPS_RERUN_FLAG '\377' /* 0xff, 255 invalide code for UFT8/ASCII */ ++#define BLAPI_FIPS_RERUN_FLAG_STRING "\377" /* The above as a C string */ ++ ++ + /*************************************************************************** + ** Opaque objects + */ + + struct DESContextStr; + struct RC2ContextStr; + struct RC4ContextStr; + struct RC5ContextStr; +diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c +--- a/lib/freebl/fipsfreebl.c ++++ b/lib/freebl/fipsfreebl.c +@@ -2211,29 +2211,37 @@ bl_startup_tests(void) + } + + /* + * this is called from the freebl init entry points that controll access to + * all other freebl functions. This prevents freebl from operating if our + * power on selftest failed. + */ + SECStatus +-BL_FIPSEntryOK(PRBool freebl_only) ++BL_FIPSEntryOK(PRBool freebl_only, PRBool rerun) + { + #ifdef NSS_NO_INIT_SUPPORT + /* this should only be set on platforms that can't handle one of the INIT + * schemes. This code allows those platforms to continue to function, + * though they don't meet the strict NIST requirements. If NSS_NO_INIT_SUPPORT + * is not set, and init support has not been properly enabled, freebl + * will always fail because of the test below + */ + if (!self_tests_freebl_ran) { + bl_startup_tests(); + } + #endif ++ if (rerun) { ++ /* reset the flags */ ++ self_tests_freebl_ran = PR_FALSE; ++ self_tests_success = PR_FALSE; ++ self_tests_success = PR_FALSE; ++ self_tests_freebl_success = PR_FALSE; ++ bl_startup_tests(); ++ } + /* if the general self tests succeeded, we're done */ + if (self_tests_success) { + return SECSuccess; + } + /* standalone freebl can initialize */ + if (freebl_only && self_tests_freebl_success) { + return SECSuccess; + } +diff --git a/lib/freebl/nsslowhash.c b/lib/freebl/nsslowhash.c +--- a/lib/freebl/nsslowhash.c ++++ b/lib/freebl/nsslowhash.c +@@ -55,17 +55,17 @@ NSSLOW_Init(void) + #ifdef FREEBL_NO_DEPEND + (void)FREEBL_InitStubs(); + #endif + + #ifndef NSS_FIPS_DISABLED + /* make sure the FIPS product is installed if we are trying to + * go into FIPS mode */ + if (nsslow_GetFIPSEnabled()) { +- if (BL_FIPSEntryOK(PR_TRUE) != SECSuccess) { ++ if (BL_FIPSEntryOK(PR_TRUE, PR_FALSE) != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + post_failed = PR_TRUE; + return NULL; + } + } + #endif + post_failed = PR_FALSE; + +diff --git a/lib/freebl/shvfy.c b/lib/freebl/shvfy.c +--- a/lib/freebl/shvfy.c ++++ b/lib/freebl/shvfy.c +@@ -282,52 +282,62 @@ readItem(PRFileDesc *fd, SECItem *item) + PORT_Free(item->data); + item->data = NULL; + item->len = 0; + return SECFailure; + } + return SECSuccess; + } + +-static PRBool blapi_SHVerifyFile(const char *shName, PRBool self); ++static PRBool blapi_SHVerifyFile(const char *shName, PRBool self, PRBool rerun); + + static PRBool +-blapi_SHVerify(const char *name, PRFuncPtr addr, PRBool self) ++blapi_SHVerify(const char *name, PRFuncPtr addr, PRBool self, PRBool rerun) + { + PRBool result = PR_FALSE; /* if anything goes wrong, + * the signature does not verify */ + /* find our shared library name */ + char *shName = PR_GetLibraryFilePathname(name, addr); + if (!shName) { + goto loser; + } +- result = blapi_SHVerifyFile(shName, self); ++ result = blapi_SHVerifyFile(shName, self, rerun); + + loser: + if (shName != NULL) { + PR_Free(shName); + } + + return result; + } + + PRBool + BLAPI_SHVerify(const char *name, PRFuncPtr addr) + { +- return blapi_SHVerify(name, addr, PR_FALSE); ++ PRBool rerun = PR_FALSE; ++ if (name && *name == BLAPI_FIPS_RERUN_FLAG) { ++ name++; ++ rerun = PR_TRUE; ++ } ++ return blapi_SHVerify(name, addr, PR_FALSE, rerun); + } + + PRBool + BLAPI_SHVerifyFile(const char *shName) + { +- return blapi_SHVerifyFile(shName, PR_FALSE); ++ PRBool rerun = PR_FALSE; ++ if (shName && *shName == BLAPI_FIPS_RERUN_FLAG) { ++ shName++; ++ rerun = PR_TRUE; ++ } ++ return blapi_SHVerifyFile(shName, PR_FALSE, rerun); + } + + static PRBool +-blapi_SHVerifyFile(const char *shName, PRBool self) ++blapi_SHVerifyFile(const char *shName, PRBool self, PRBool rerun) + { + char *checkName = NULL; + PRFileDesc *checkFD = NULL; + PRFileDesc *shFD = NULL; + void *hashcx = NULL; + const SECHashObject *hashObj = NULL; + SECItem signature = { 0, NULL, 0 }; + SECItem hash; +@@ -346,17 +356,17 @@ blapi_SHVerifyFile(const char *shName, P + unsigned char hashBuf[HASH_LENGTH_MAX]; + + PORT_Memset(&key, 0, sizeof(key)); + hash.data = hashBuf; + hash.len = sizeof(hashBuf); + + /* If our integrity check was never ran or failed, fail any other + * integrity checks to prevent any token going into FIPS mode. */ +- if (!self && (BL_FIPSEntryOK(PR_FALSE) != SECSuccess)) { ++ if (!self && (BL_FIPSEntryOK(PR_FALSE, rerun) != SECSuccess)) { + return PR_FALSE; + } + + if (!shName) { + goto loser; + } + + /* figure out the name of our check file */ +@@ -536,17 +546,17 @@ BLAPI_VerifySelf(const char *name) + { + if (name == NULL) { + /* + * If name is NULL, freebl is statically linked into softoken. + * softoken will call BLAPI_SHVerify next to verify itself. + */ + return PR_TRUE; + } +- return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE); ++ return blapi_SHVerify(name, (PRFuncPtr)decodeInt, PR_TRUE, PR_FALSE); + } + + #else /* NSS_FIPS_DISABLED */ + + PRBool + BLAPI_SHVerifyFile(const char *shName) + { + return PR_FALSE; +diff --git a/lib/softoken/fipstest.c b/lib/softoken/fipstest.c +--- a/lib/softoken/fipstest.c ++++ b/lib/softoken/fipstest.c +@@ -684,22 +684,25 @@ sftk_fips_HKDF_PowerUpSelfTest(void) + + static PRBool sftk_self_tests_ran = PR_FALSE; + static PRBool sftk_self_tests_success = PR_FALSE; + + /* + * This function is called at dll load time, the code tha makes this + * happen is platform specific on defined above. + */ +-static void +-sftk_startup_tests(void) ++void sftk_startup_tests_with_rerun(PRBool rerun) + { + SECStatus rv; +- const char *libraryName = SOFTOKEN_LIB_NAME; +- ++ /*const char *nlibraryName = SOFTOKEN_LIB_NAME; ++ const char *rlibraryName = BLAPI_FIPS_RERUN_FLAG_STRING SOFTOKEN_LIB_NAME; */ ++ const char *libraryName = rerun ? ++ BLAPI_FIPS_RERUN_FLAG_STRING SOFTOKEN_LIB_NAME : ++ SOFTOKEN_LIB_NAME; ++ + PORT_Assert(!sftk_self_tests_ran); + PORT_Assert(!sftk_self_tests_success); + sftk_self_tests_ran = PR_TRUE; + sftk_self_tests_success = PR_FALSE; /* just in case */ + + /* need to initiallize the oid library before the RSA tests */ + rv = SECOID_Init(); + if (rv != SECSuccess) { +@@ -746,35 +749,46 @@ sftk_startup_tests(void) + rv = sftk_fips_pbkdf_PowerUpSelfTests(); + if (rv != SECSuccess) { + return; + } + + sftk_self_tests_success = PR_TRUE; + } + ++static void ++sftk_startup_tests(void) ++{ ++ sftk_startup_tests_with_rerun(PR_FALSE); ++} ++ + /* + * this is called from nsc_Common_Initizialize entry points that gates access + * to * all other pkcs11 functions. This prevents softoken operation if our + * power on selftest failed. + */ + CK_RV +-sftk_FIPSEntryOK() ++sftk_FIPSEntryOK(PRBool rerun) + { + #ifdef NSS_NO_INIT_SUPPORT + /* this should only be set on platforms that can't handle one of the INIT + * schemes. This code allows those platforms to continue to function, + * though they don't meet the strict NIST requirements. If NSS_NO_INIT_SUPPORT + * is not set, and init support has not been properly enabled, softken + * will always fail because of the test below + */ + if (!sftk_self_tests_ran) { + sftk_startup_tests(); + } + #endif ++ if (rerun) { ++ sftk_self_tests_ran = PR_FALSE; ++ sftk_self_tests_success = PR_FALSE; ++ sftk_startup_tests_with_rerun(PR_TRUE); ++ } + if (!sftk_self_tests_success) { + return CKR_DEVICE_ERROR; + } + return CKR_OK; + } + #else + #include "pkcs11t.h" + CK_RV +diff --git a/lib/softoken/fipstokn.c b/lib/softoken/fipstokn.c +--- a/lib/softoken/fipstokn.c ++++ b/lib/softoken/fipstokn.c +@@ -524,25 +524,32 @@ fc_log_init_error(CK_RV crv) + } + + /* FC_Initialize initializes the PKCS #11 library. */ + CK_RV + FC_Initialize(CK_VOID_PTR pReserved) + { + const char *envp; + CK_RV crv; ++ PRBool rerun; + + if ((envp = PR_GetEnv("NSS_ENABLE_AUDIT")) != NULL) { + sftk_audit_enabled = (atoi(envp) == 1); + } + ++ /* if we have the forcePOST flag on, rerun the integrity checks */ ++ /* we need to know this before we fully parse the arguments in ++ * nsc_CommonInitialize, so read it now */ ++ rerun = sftk_RawArgHasFlag("flags", "forcePost", pReserved); ++ + /* At this point we should have already done post and integrity checks. + * if we haven't, it probably means the FIPS product has not been installed +- * or the tests failed. Don't let an application try to enter FIPS mode */ +- crv = sftk_FIPSEntryOK(); ++ * or the tests failed. Don't let an application try to enter FIPS mode. This ++ * also forces the tests to be rerun if forcePOST is set. */ ++ crv = sftk_FIPSEntryOK(rerun); + if (crv != CKR_OK) { + sftk_fatalError = PR_TRUE; + fc_log_init_error(crv); + return crv; + } + + sftk_ForkReset(pReserved, &crv); + +diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h +--- a/lib/softoken/pkcs11i.h ++++ b/lib/softoken/pkcs11i.h +@@ -869,16 +869,17 @@ extern CK_RV sftk_MechAllowsOperation(CK + * acquiring a reference to the keydb from the slot */ + NSSLOWKEYPrivateKey *sftk_FindKeyByPublicKey(SFTKSlot *slot, SECItem *dbKey); + + /* + * parameter parsing functions + */ + CK_RV sftk_parseParameters(char *param, sftk_parameters *parsed, PRBool isFIPS); + void sftk_freeParams(sftk_parameters *params); ++PRBool sftk_RawArgHasFlag(const char *entry, const char *flag, const void *pReserved); + + /* + * narrow objects + */ + SFTKSessionObject *sftk_narrowToSessionObject(SFTKObject *); + SFTKTokenObject *sftk_narrowToTokenObject(SFTKObject *); + + /* +diff --git a/lib/softoken/sftkpars.c b/lib/softoken/sftkpars.c +--- a/lib/softoken/sftkpars.c ++++ b/lib/softoken/sftkpars.c +@@ -244,8 +244,21 @@ sftk_freeParams(sftk_parameters *params) + FREE_CLEAR(params->configdir); + FREE_CLEAR(params->secmodName); + FREE_CLEAR(params->man); + FREE_CLEAR(params->libdes); + FREE_CLEAR(params->tokens); + FREE_CLEAR(params->updatedir); + FREE_CLEAR(params->updateID); + } ++ ++PRBool ++sftk_RawArgHasFlag(const char *entry, const char *flag, const void *pReserved) ++{ ++ CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *)pReserved; ++ ++ /* if we don't have any params, the flag isn't set */ ++ if ((!init_args || !init_args->LibraryParameters)) { ++ return PR_FALSE; ++ } ++ ++ return NSSUTIL_ArgHasFlag(entry, flag, (const char *)init_args->LibraryParameters); ++} +diff --git a/lib/softoken/softoken.h b/lib/softoken/softoken.h +--- a/lib/softoken/softoken.h ++++ b/lib/softoken/softoken.h +@@ -52,17 +52,17 @@ extern unsigned char *CBC_PadBuffer(PLAr + unsigned int inlen, unsigned int *outlen, + int blockSize); + + /****************************************/ + /* + ** Power-Up selftests are required for FIPS. + */ + /* make sure Power-up selftests have been run. */ +-extern CK_RV sftk_FIPSEntryOK(void); ++extern CK_RV sftk_FIPSEntryOK(PRBool rerun); + + /* + ** make known fixed PKCS #11 key types to their sizes in bytes + */ + unsigned long sftk_MapKeySize(CK_KEY_TYPE keyType); + + /* + ** FIPS 140-2 auditing diff --git a/SOURCES/nss-3.79-fips.patch b/SOURCES/nss-3.79-fips.patch new file mode 100644 index 0000000..eadcb26 --- /dev/null +++ b/SOURCES/nss-3.79-fips.patch @@ -0,0 +1,742 @@ +diff --git a/lib/freebl/config.mk b/lib/freebl/config.mk +--- a/lib/freebl/config.mk ++++ b/lib/freebl/config.mk +@@ -85,9 +85,13 @@ EXTRA_SHARED_LIBS += \ + $(NULL) + endif + endif + + ifeq ($(OS_ARCH), Darwin) + EXTRA_SHARED_LIBS += -dylib_file @executable_path/libplc4.dylib:$(DIST)/lib/libplc4.dylib -dylib_file @executable_path/libplds4.dylib:$(DIST)/lib/libplds4.dylib + endif + ++ifdef NSS_FIPS_140_3 ++DEFINES += -DNSS_FIPS_140_3 + endif ++ ++endif +diff --git a/lib/freebl/unix_urandom.c b/lib/freebl/unix_urandom.c +--- a/lib/freebl/unix_urandom.c ++++ b/lib/freebl/unix_urandom.c +@@ -20,53 +20,110 @@ RNG_SystemInfoForRNG(void) + if (!numBytes) { + /* error is set */ + return; + } + RNG_RandomUpdate(bytes, numBytes); + PORT_Memset(bytes, 0, sizeof bytes); + } + ++#ifdef NSS_FIPS_140_3 ++#include ++#include "prinit.h" ++ ++static int rng_grndFlags= 0; ++static PRCallOnceType rng_KernelFips; ++ ++static PRStatus ++rng_getKernelFips() ++{ ++#ifdef LINUX ++ FILE *f; ++ char d; ++ size_t size; ++ ++ f = fopen("/proc/sys/crypto/fips_enabled", "r"); ++ if (!f) ++ return PR_FAILURE; ++ ++ size = fread(&d, 1, 1, f); ++ fclose(f); ++ if (size != 1) ++ return PR_SUCCESS; ++ if (d != '1') ++ return PR_SUCCESS; ++ /* if the kernel is in FIPS mode, set the GRND_RANDOM flag */ ++ rng_grndFlags = GRND_RANDOM; ++#endif /* LINUX */ ++ return PR_SUCCESS; ++} ++#endif ++ + size_t + RNG_SystemRNG(void *dest, size_t maxLen) + { ++ size_t fileBytes = 0; ++ unsigned char *buffer = dest; ++#ifndef NSS_FIPS_140_3 + int fd; + int bytes; +- size_t fileBytes = 0; +- unsigned char *buffer = dest; ++#else ++ PR_CallOnce(&rng_KernelFips, rng_getKernelFips); ++#endif + + #if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(LINUX) && defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 25)))) + int result; +- + while (fileBytes < maxLen) { + size_t getBytes = maxLen - fileBytes; + if (getBytes > GETENTROPY_MAX_BYTES) { + getBytes = GETENTROPY_MAX_BYTES; + } ++#ifdef NSS_FIPS_140_3 ++ /* FIP 140-3 requires full kernel reseeding for chained entropy sources ++ * so we need to use getrandom with GRND_RANDOM. ++ * getrandom returns -1 on failure, otherwise returns ++ * the number of bytes, which can be less than getBytes */ ++ result = getrandom(buffer, getBytes, rng_grndFlags); ++ if (result < 0) { ++ break; ++ } ++ fileBytes += result; ++ buffer += result; ++#else ++ /* get entropy returns 0 on success and always return ++ * getBytes on success */ + result = getentropy(buffer, getBytes); + if (result == 0) { /* success */ + fileBytes += getBytes; + buffer += getBytes; + } else { + break; + } ++#endif + } + if (fileBytes == maxLen) { /* success */ + return maxLen; + } ++#ifdef NSS_FIPS_140_3 ++ /* in FIPS 104-3 we don't fallback, just fail */ ++ PORT_SetError(SEC_ERROR_NEED_RANDOM); ++ return 0; ++#else + /* If we failed with an error other than ENOSYS, it means the destination + * buffer is not writeable. We don't need to try writing to it again. */ + if (errno != ENOSYS) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + return 0; + } ++#endif /*!NSS_FIPS_140_3 */ ++#endif /* platorm has getentropy */ ++#ifndef NSS_FIPS_140_3 + /* ENOSYS means the kernel doesn't support getentropy()/getrandom(). + * Reset the number of bytes to get and fall back to /dev/urandom. */ + fileBytes = 0; +-#endif + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + return 0; + } + while (fileBytes < maxLen) { + bytes = read(fd, buffer, maxLen - fileBytes); + if (bytes <= 0) { +@@ -76,9 +133,10 @@ RNG_SystemRNG(void *dest, size_t maxLen) + buffer += bytes; + } + (void)close(fd); + if (fileBytes != maxLen) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + return 0; + } + return fileBytes; ++#endif + } +diff --git a/lib/softoken/config.mk b/lib/softoken/config.mk +--- a/lib/softoken/config.mk ++++ b/lib/softoken/config.mk +@@ -58,8 +58,12 @@ endif + ifdef NSS_ENABLE_FIPS_INDICATORS + DEFINES += -DNSS_ENABLE_FIPS_INDICATORS + endif + + ifdef NSS_FIPS_MODULE_ID + DEFINES += -DNSS_FIPS_MODULE_ID=\"${NSS_FIPS_MODULE_ID}\" + endif + ++ifdef NSS_FIPS_140_3 ++DEFINES += -DNSS_FIPS_140_3 ++endif ++ +diff --git a/lib/softoken/fips_algorithms.h b/lib/softoken/fips_algorithms.h +--- a/lib/softoken/fips_algorithms.h ++++ b/lib/softoken/fips_algorithms.h +@@ -49,33 +49,46 @@ SFTKFIPSAlgorithmList sftk_fips_mechs[] + #define CKF_KEK (CKF_WRAP | CKF_UNWRAP) + #define CKF_KEA CKF_DERIVE + #define CKF_KDF CKF_DERIVE + #define CKF_HSH CKF_DIGEST + #define CK_MAX 0xffffffffUL + /* mechanisms using the same key types share the same key type + * limits */ + #define RSA_FB_KEY 2048, 4096 /* min, max */ +-#define RSA_FB_STEP 1024 ++#define RSA_FB_STEP 1 ++#define RSA_LEGACY_FB_KEY 1024, 1792 /* min, max */ ++#define RSA_LEGACY_FB_STEP 256 ++ + #define DSA_FB_KEY 2048, 4096 /* min, max */ + #define DSA_FB_STEP 1024 + #define DH_FB_KEY 2048, 4096 /* min, max */ + #define DH_FB_STEP 1024 + #define EC_FB_KEY 256, 521 /* min, max */ + #define EC_FB_STEP 1 /* key limits handled by special operation */ + #define AES_FB_KEY 128, 256 + #define AES_FB_STEP 64 + { CKM_RSA_PKCS_KEY_PAIR_GEN, { RSA_FB_KEY, CKF_KPG }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_RSA_PKCS_OAEP, { RSA_FB_KEY, CKF_ENC }, RSA_FB_STEP, SFTKFIPSNone }, ++ { CKM_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ + /* -------------- RSA Multipart Signing Operations -------------------- */ + { CKM_SHA224_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_SHA256_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_SHA384_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_SHA512_RSA_PKCS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA224_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA256_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA384_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA512_RSA_PKCS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA224_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA256_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA384_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, ++ { CKM_SHA512_RSA_PKCS_PSS, { RSA_LEGACY_FB_KEY, CKF_VERIFY }, RSA_LEGACY_FB_STEP, SFTKFIPSNone }, + { CKM_SHA224_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_SHA256_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_SHA384_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + { CKM_SHA512_RSA_PKCS_PSS, { RSA_FB_KEY, CKF_SGN }, RSA_FB_STEP, SFTKFIPSNone }, + /* ------------------------- DSA Operations --------------------------- */ + { CKM_DSA_KEY_PAIR_GEN, { DSA_FB_KEY, CKF_KPG }, DSA_FB_STEP, SFTKFIPSNone }, + { CKM_DSA, { DSA_FB_KEY, CKF_SGN }, DSA_FB_STEP, SFTKFIPSNone }, + { CKM_DSA_PARAMETER_GEN, { DSA_FB_KEY, CKF_KPG }, DSA_FB_STEP, SFTKFIPSNone }, +@@ -95,76 +108,73 @@ SFTKFIPSAlgorithmList sftk_fips_mechs[] + { CKM_ECDSA_SHA256, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC }, + { CKM_ECDSA_SHA384, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC }, + { CKM_ECDSA_SHA512, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC }, + /* ------------------------- RC2 Operations --------------------------- */ + /* ------------------------- AES Operations --------------------------- */ + { CKM_AES_KEY_GEN, { AES_FB_KEY, CKF_GEN }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_ECB, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_CBC, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, +- { CKM_AES_MAC, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone }, +- { CKM_AES_MAC_GENERAL, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_CMAC, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_CMAC_GENERAL, { AES_FB_KEY, CKF_SGN }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_CBC_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_CTS, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_CTR, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_GCM, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSAEAD }, + { CKM_AES_KEY_WRAP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_KEY_WRAP_PAD, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, + { CKM_AES_KEY_WRAP_KWP, { AES_FB_KEY, CKF_ENC }, AES_FB_STEP, SFTKFIPSNone }, +- { CKM_AES_XCBC_MAC_96, { 96, 96, CKF_SGN }, 1, SFTKFIPSNone }, +- { CKM_AES_XCBC_MAC, { 128, 128, CKF_SGN }, 1, SFTKFIPSNone }, + /* ------------------------- Hashing Operations ----------------------- */ + { CKM_SHA224, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone }, + { CKM_SHA224_HMAC, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone }, + { CKM_SHA224_HMAC_GENERAL, { 112, 224, CKF_SGN }, 1, SFTKFIPSNone }, + { CKM_SHA256, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone }, +- { CKM_SHA256_HMAC, { 128, 256, CKF_SGN }, 1, SFTKFIPSNone }, +- { CKM_SHA256_HMAC_GENERAL, { 128, 256, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_SHA256_HMAC, { 112, 256, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_SHA256_HMAC_GENERAL, { 112, 256, CKF_SGN }, 1, SFTKFIPSNone }, + { CKM_SHA384, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone }, +- { CKM_SHA384_HMAC, { 192, 384, CKF_SGN }, 1, SFTKFIPSNone }, +- { CKM_SHA384_HMAC_GENERAL, { 192, 384, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_SHA384_HMAC, { 112, 384, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_SHA384_HMAC_GENERAL, { 112, 384, CKF_SGN }, 1, SFTKFIPSNone }, + { CKM_SHA512, { 0, 0, CKF_HSH }, 1, SFTKFIPSNone }, +- { CKM_SHA512_HMAC, { 256, 512, CKF_SGN }, 1, SFTKFIPSNone }, +- { CKM_SHA512_HMAC_GENERAL, { 256, 512, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_SHA512_HMAC, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_SHA512_HMAC_GENERAL, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone }, + /* --------------------- Secret Key Operations ------------------------ */ +- { CKM_GENERIC_SECRET_KEY_GEN, { 8, 256, CKF_GEN }, 1, SFTKFIPSNone }, ++ { CKM_GENERIC_SECRET_KEY_GEN, { 112, 256, CKF_GEN }, 1, SFTKFIPSNone }, + /* ---------------------- SSL/TLS operations ------------------------- */ + { CKM_SHA224_KEY_DERIVATION, { 112, 224, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_SHA256_KEY_DERIVATION, { 128, 256, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_SHA384_KEY_DERIVATION, { 192, 284, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_SHA512_KEY_DERIVATION, { 256, 512, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_SHA256_KEY_DERIVATION, { 112, 256, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_SHA384_KEY_DERIVATION, { 112, 284, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_SHA512_KEY_DERIVATION, { 112, 512, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_SSL3_PRE_MASTER_KEY_GEN, { 384, 384, CKF_GEN }, 1, SFTKFIPSNone }, + { CKM_TLS12_MASTER_KEY_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone }, + { CKM_TLS12_MASTER_KEY_DERIVE_DH, { DH_FB_KEY, CKF_KDF }, 1, SFTKFIPSNone }, + { CKM_TLS12_KEY_AND_MAC_DERIVE, { 384, 384, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_TLS_PRF_GENERAL, { 8, 512, CKF_SGN }, 1, SFTKFIPSNone }, +- { CKM_TLS_MAC, { 8, 512, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_TLS_PRF_GENERAL, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone }, ++ { CKM_TLS_MAC, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone }, + /* sigh, is this algorithm really tested. ssl doesn't seem to have a + * way of turning the extension off */ + { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE, { 192, 1024, CKF_KDF }, 1, SFTKFIPSNone }, + { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH, { 192, 1024, CKF_DERIVE }, 1, SFTKFIPSNone }, + + /* ------------------------- HKDF Operations -------------------------- */ +- { CKM_HKDF_DERIVE, { 8, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_HKDF_DATA, { 8, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_HKDF_DERIVE, { 112, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_HKDF_DATA, { 112, 255 * 64 * 8, CKF_KDF }, 1, SFTKFIPSNone }, + { CKM_HKDF_KEY_GEN, { 160, 224, CKF_GEN }, 1, SFTKFIPSNone }, + { CKM_HKDF_KEY_GEN, { 256, 512, CKF_GEN }, 128, SFTKFIPSNone }, + /* ------------------ NIST 800-108 Key Derivations ------------------- */ +- { CKM_SP800_108_COUNTER_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_SP800_108_FEEDBACK_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA, { 0, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_SP800_108_COUNTER_KDF, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_SP800_108_FEEDBACK_KDF, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_SP800_108_DOUBLE_PIPELINE_KDF, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_NSS_SP800_108_COUNTER_KDF_DERIVE_DATA, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_NSS_SP800_108_FEEDBACK_KDF_DERIVE_DATA, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_NSS_SP800_108_DOUBLE_PIPELINE_KDF_DERIVE_DATA, { 112, CK_MAX, CKF_KDF }, 1, SFTKFIPSNone }, + /* --------------------IPSEC ----------------------- */ +- { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 8, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_NSS_IKE_PRF_DERIVE, { 8, 64, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_KDF }, 1, SFTKFIPSNone }, +- { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_NSS_IKE_PRF_PLUS_DERIVE, { 112, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_NSS_IKE_PRF_DERIVE, { 112, 64, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_NSS_IKE1_PRF_DERIVE, { 112, 64, CKF_KDF }, 1, SFTKFIPSNone }, ++ { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 112, 255 * 64, CKF_KDF }, 1, SFTKFIPSNone }, + /* ------------------ PBE Key Derivations ------------------- */ +- { CKM_PKCS5_PBKD2, { 1, 256, CKF_GEN }, 1, SFTKFIPSNone }, ++ { CKM_PKCS5_PBKD2, { 112, 256, CKF_GEN }, 1, SFTKFIPSNone }, + { CKM_NSS_PKCS12_PBE_SHA224_HMAC_KEY_GEN, { 224, 224, CKF_GEN }, 1, SFTKFIPSNone }, + { CKM_NSS_PKCS12_PBE_SHA256_HMAC_KEY_GEN, { 256, 256, CKF_GEN }, 1, SFTKFIPSNone }, + { CKM_NSS_PKCS12_PBE_SHA384_HMAC_KEY_GEN, { 384, 384, CKF_GEN }, 1, SFTKFIPSNone }, + { CKM_NSS_PKCS12_PBE_SHA512_HMAC_KEY_GEN, { 512, 512, CKF_GEN }, 1, SFTKFIPSNone } + }; + const int SFTK_NUMBER_FIPS_ALGORITHMS = PR_ARRAY_SIZE(sftk_fips_mechs); +diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c +--- a/lib/softoken/lowpbe.c ++++ b/lib/softoken/lowpbe.c +@@ -1765,27 +1765,29 @@ SECStatus + sftk_fips_pbkdf_PowerUpSelfTests(void) + { + SECItem *result; + SECItem inKey; + NSSPKCS5PBEParameter pbe_params; + unsigned char iteration_count = 5; + unsigned char keyLen = 64; + char *inKeyData = TEST_KEY; +- static const unsigned char saltData[] = +- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; ++ static const unsigned char saltData[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, ++ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ++ }; + static const unsigned char pbkdf_known_answer[] = { +- 0x31, 0xf0, 0xe5, 0x39, 0x9f, 0x39, 0xb9, 0x29, +- 0x68, 0xac, 0xf2, 0xe9, 0x53, 0x9b, 0xb4, 0x9c, +- 0x28, 0x59, 0x8b, 0x5c, 0xd8, 0xd4, 0x02, 0x37, +- 0x18, 0x22, 0xc1, 0x92, 0xd0, 0xfa, 0x72, 0x90, +- 0x2c, 0x8d, 0x19, 0xd4, 0x56, 0xfb, 0x16, 0xfa, +- 0x8d, 0x5c, 0x06, 0x33, 0xd1, 0x5f, 0x17, 0xb1, +- 0x22, 0xd9, 0x9c, 0xaf, 0x5e, 0x3f, 0xf3, 0x66, +- 0xc6, 0x14, 0xfe, 0x83, 0xfa, 0x1a, 0x2a, 0xc5 ++ 0x73, 0x8c, 0xfa, 0x02, 0xe8, 0xdb, 0x43, 0xe4, ++ 0x99, 0xc5, 0xfd, 0xd9, 0x4d, 0x8e, 0x3e, 0x7b, ++ 0xc4, 0xda, 0x22, 0x1b, 0xe1, 0xae, 0x23, 0x7a, ++ 0x21, 0x27, 0xbd, 0xcc, 0x78, 0xc4, 0xe6, 0xc5, ++ 0x33, 0x38, 0x35, 0xe0, 0x68, 0x1a, 0x1e, 0x06, ++ 0xad, 0xaf, 0x7f, 0xd7, 0x3f, 0x0e, 0xc0, 0x90, ++ 0x17, 0x97, 0x73, 0x75, 0x7b, 0x88, 0x49, 0xd8, ++ 0x6f, 0x78, 0x5a, 0xde, 0x50, 0x20, 0x55, 0x33 + }; + + sftk_PBELockInit(); + + inKey.data = (unsigned char *)inKeyData; + inKey.len = sizeof(TEST_KEY) - 1; + + pbe_params.salt.data = (unsigned char *)saltData; +diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c +--- a/lib/softoken/pkcs11c.c ++++ b/lib/softoken/pkcs11c.c +@@ -4609,16 +4609,17 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi + goto loser; + } + + /* make sure we don't have any class, key_type, or value fields */ + sftk_DeleteAttributeType(key, CKA_CLASS); + sftk_DeleteAttributeType(key, CKA_KEY_TYPE); + sftk_DeleteAttributeType(key, CKA_VALUE); + ++ + /* Now Set up the parameters to generate the key (based on mechanism) */ + key_gen_type = nsc_bulk; /* bulk key by default */ + switch (pMechanism->mechanism) { + case CKM_CDMF_KEY_GEN: + case CKM_DES_KEY_GEN: + case CKM_DES2_KEY_GEN: + case CKM_DES3_KEY_GEN: + checkWeak = PR_TRUE; +@@ -4812,16 +4813,19 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi + crv = sftk_handleObject(key, session); + sftk_FreeSession(session); + if (crv == CKR_OK && sftk_isTrue(key, CKA_SENSITIVE)) { + crv = sftk_forceAttribute(key, CKA_ALWAYS_SENSITIVE, &cktrue, sizeof(CK_BBOOL)); + } + if (crv == CKR_OK && !sftk_isTrue(key, CKA_EXTRACTABLE)) { + crv = sftk_forceAttribute(key, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL)); + } ++ /* we need to do this check at the end, so we can check the generated key length against ++ * fips requirements */ ++ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key); + if (crv == CKR_OK) { + *phKey = key->handle; + } + loser: + PORT_Memset(buf, 0, sizeof buf); + sftk_FreeObject(key); + return crv; + } +@@ -5780,16 +5784,19 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS + + if (crv != CKR_OK) { + NSC_DestroyObject(hSession, publicKey->handle); + sftk_FreeObject(publicKey); + NSC_DestroyObject(hSession, privateKey->handle); + sftk_FreeObject(privateKey); + return crv; + } ++ /* we need to do this check at the end to make sure the generated key meets the key length requirements */ ++ privateKey->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE_KEY_PAIR, privateKey); ++ publicKey->isFIPS = privateKey->isFIPS; + + *phPrivateKey = privateKey->handle; + *phPublicKey = publicKey->handle; + sftk_FreeObject(publicKey); + sftk_FreeObject(privateKey); + + return CKR_OK; + } +@@ -6990,16 +6997,17 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_ + } + + /* HKDF-Extract(salt, base key value) */ + if (params->bExtract) { + CK_BYTE *salt; + CK_ULONG saltLen; + HMACContext *hmac; + unsigned int bufLen; ++ SFTKSource saltKeySource = SFTK_SOURCE_DEFAULT; + + switch (params->ulSaltType) { + case CKF_HKDF_SALT_NULL: + saltLen = hashLen; + salt = hashbuf; + memset(salt, 0, saltLen); + break; + case CKF_HKDF_SALT_DATA: +@@ -7026,29 +7034,54 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_ + if (isFIPS && (key->isFIPS == 0) && (saltKey->isFIPS == 1)) { + CK_MECHANISM mech; + mech.mechanism = CKM_HKDF_DERIVE; + mech.pParameter = params; + mech.ulParameterLen = sizeof(*params); + key->isFIPS = sftk_operationIsFIPS(saltKey->slot, &mech, + CKA_DERIVE, saltKey); + } ++ saltKeySource = saltKey->source; + saltKey_att = sftk_FindAttribute(saltKey, CKA_VALUE); + if (saltKey_att == NULL) { + sftk_FreeObject(saltKey); + return CKR_KEY_HANDLE_INVALID; + } + /* save the resulting salt */ + salt = saltKey_att->attrib.pValue; + saltLen = saltKey_att->attrib.ulValueLen; + break; + default: + return CKR_MECHANISM_PARAM_INVALID; + break; + } ++ /* only TLS style usage is FIPS approved, ++ * turn off the FIPS indicator for other usages */ ++ if (isFIPS && key && sourceKey) { ++ PRBool fipsOK = PR_FALSE; ++ /* case one: mix the kea with a previous or default ++ * salt */ ++ if ((sourceKey->source == SFTK_SOURCE_KEA) && ++ (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) && ++ (saltLen == rawHash->length)) { ++ fipsOK = PR_TRUE; ++ } ++ /* case two: restart, remix the previous secret as a salt */ ++ if ((sourceKey->objclass == CKO_DATA) && ++ (NSS_SecureMemcmpZero(sourceKeyBytes, sourceKeyLen) == 0) && ++ (sourceKeyLen == rawHash->length) && ++ (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) && ++ (saltLen == rawHash->length)) { ++ fipsOK = PR_TRUE; ++ } ++ if (!fipsOK) { ++ key->isFIPS = PR_FALSE; ++ } ++ } ++ if (key) key->source = SFTK_SOURCE_HKDF_EXTRACT; + + hmac = HMAC_Create(rawHash, salt, saltLen, isFIPS); + if (saltKey_att) { + sftk_FreeAttribute(saltKey_att); + } + if (saltKey) { + sftk_FreeObject(saltKey); + } +@@ -7076,16 +7109,40 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_ + /* T(1) = HMAC-Hash(prk, "" | info | 0x01) + * T(n) = HMAC-Hash(prk, T(n-1) | info | n + * key material = T(1) | ... | T(n) + */ + HMACContext *hmac; + CK_BYTE bi; + unsigned iterations; + ++ /* only TLS style usage is FIPS approved, ++ * turn off the FIPS indicator for other usages */ ++ if (isFIPS && key && key->isFIPS && sourceKey) { ++ unsigned char *info=¶ms->pInfo[3]; ++ /* only one case, ++ * 1) Expand only ++ * 2) with a key whose source was ++ * SFTK_SOURCE_HKDF_EXPAND or SFTK_SOURCE_HKDF_EXTRACT ++ * 3) source key length == rawHash->length ++ * 4) Info has tls or dtls ++ * If any of those conditions aren't met, then we turn ++ * off the fips indicator */ ++ if (params->bExtract || ++ ((sourceKey->source != SFTK_SOURCE_HKDF_EXTRACT) && ++ (sourceKey->source != SFTK_SOURCE_HKDF_EXPAND)) || ++ (sourceKeyLen != rawHash->length) || ++ (params->ulInfoLen < 7) || ++ ((PORT_Memcmp(info,"tls",3) != 0) && ++ (PORT_Memcmp(info,"dtls",4) != 0))) { ++ key->isFIPS = PR_FALSE; ++ } ++ } ++ if (key) key->source = SFTK_SOURCE_HKDF_EXPAND; ++ + genLen = PR_ROUNDUP(keySize, hashLen); + iterations = genLen / hashLen; + + if (genLen > sizeof(keyBlock)) { + keyBlockAlloc = PORT_Alloc(genLen); + if (keyBlockAlloc == NULL) { + return CKR_HOST_MEMORY; + } +@@ -8434,16 +8491,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession + + /* calculate private value - oct */ + rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize); + + SECITEM_ZfreeItem(&dhPrime, PR_FALSE); + SECITEM_ZfreeItem(&dhValue, PR_FALSE); + + if (rv == SECSuccess) { ++ key->source = SFTK_SOURCE_KEA; + sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len); + SECITEM_ZfreeItem(&derived, PR_FALSE); + crv = CKR_OK; + } else + crv = CKR_HOST_MEMORY; + + break; + } +@@ -8564,16 +8622,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession + } + PORT_Memcpy(&keyData[keySize - secretlen], secret, secretlen); + secret = keyData; + } else { + secret += (secretlen - keySize); + } + secretlen = keySize; + } ++ key->source = SFTK_SOURCE_KEA; + + sftk_forceAttribute(key, CKA_VALUE, secret, secretlen); + PORT_ZFree(tmp.data, tmp.len); + if (keyData) { + PORT_ZFree(keyData, keySize); + } + break; + +diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h +--- a/lib/softoken/pkcs11i.h ++++ b/lib/softoken/pkcs11i.h +@@ -147,16 +147,26 @@ typedef enum { + */ + typedef enum { + SFTK_DestroyFailure, + SFTK_Destroyed, + SFTK_Busy + } SFTKFreeStatus; + + /* ++ * Source of various objects ++ */ ++typedef enum { ++ SFTK_SOURCE_DEFAULT=0, ++ SFTK_SOURCE_KEA, ++ SFTK_SOURCE_HKDF_EXPAND, ++ SFTK_SOURCE_HKDF_EXTRACT ++} SFTKSource; ++ ++/* + * attribute values of an object. + */ + struct SFTKAttributeStr { + SFTKAttribute *next; + SFTKAttribute *prev; + PRBool freeAttr; + PRBool freeData; + /*must be called handle to make sftkqueue_find work */ +@@ -189,16 +199,17 @@ struct SFTKObjectStr { + CK_OBJECT_CLASS objclass; + CK_OBJECT_HANDLE handle; + int refCount; + PZLock *refLock; + SFTKSlot *slot; + void *objectInfo; + SFTKFree infoFree; + PRBool isFIPS; ++ SFTKSource source; + }; + + struct SFTKTokenObjectStr { + SFTKObject obj; + SECItem dbKey; + }; + + struct SFTKSessionObjectStr { +diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c +--- a/lib/softoken/pkcs11u.c ++++ b/lib/softoken/pkcs11u.c +@@ -1090,16 +1090,17 @@ sftk_NewObject(SFTKSlot *slot) + sessObject->attrList[i].freeData = PR_FALSE; + } + sessObject->optimizeSpace = slot->optimizeSpace; + + object->handle = 0; + object->next = object->prev = NULL; + object->slot = slot; + object->isFIPS = sftk_isFIPS(slot->slotID); ++ object->source = SFTK_SOURCE_DEFAULT; + + object->refCount = 1; + sessObject->sessionList.next = NULL; + sessObject->sessionList.prev = NULL; + sessObject->sessionList.parent = object; + sessObject->session = NULL; + sessObject->wasDerived = PR_FALSE; + if (!hasLocks) +@@ -1674,16 +1675,17 @@ fail: + CK_RV + sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject) + { + SFTKAttribute *attribute; + SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject); + unsigned int i; + + destObject->isFIPS = srcObject->isFIPS; ++ destObject->source = srcObject->source; + if (src_so == NULL) { + return sftk_CopyTokenObject(destObject, srcObject); + } + + PZ_Lock(src_so->attributeLock); + for (i = 0; i < src_so->hashSize; i++) { + attribute = src_so->head[i]; + do { +@@ -2059,16 +2061,17 @@ sftk_NewTokenObject(SFTKSlot *slot, SECI + /* every object must have a class, if we can't get it, the object + * doesn't exist */ + crv = handleToClass(slot, handle, &object->objclass); + if (crv != CKR_OK) { + goto loser; + } + object->slot = slot; + object->isFIPS = sftk_isFIPS(slot->slotID); ++ object->source = SFTK_SOURCE_DEFAULT; + object->objectInfo = NULL; + object->infoFree = NULL; + if (!hasLocks) { + object->refLock = PZ_NewLock(nssILockRefLock); + } + if (object->refLock == NULL) { + goto loser; + } +@@ -2225,16 +2228,25 @@ sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE + break; + case CKA_DERIVE: + flags = CKF_DERIVE; + break; + /* fake attribute to select digesting */ + case CKA_DIGEST: + flags = CKF_DIGEST; + break; ++ /* fake attribute to select key gen */ ++ case CKA_NSS_GENERATE: ++ flags = CKF_GENERATE; ++ break; ++ /* fake attribute to select key pair gen */ ++ case CKA_NSS_GENERATE_KEY_PAIR: ++ flags = CKF_GENERATE_KEY_PAIR; ++ break; ++ /* fake attributes to to handle MESSAGE* flags */ + case CKA_NSS_MESSAGE | CKA_ENCRYPT: + flags = CKF_MESSAGE_ENCRYPT; + break; + case CKA_NSS_MESSAGE | CKA_DECRYPT: + flags = CKF_MESSAGE_DECRYPT; + break; + case CKA_NSS_MESSAGE | CKA_SIGN: + flags = CKF_MESSAGE_SIGN; +@@ -2278,17 +2290,17 @@ sftk_quickGetECCCurveOid(SFTKObject *sou + } + + /* This function currently only returns valid lengths for + * FIPS approved ECC curves. If we want to make this generic + * in the future, that Curve determination can be done in + * the sftk_handleSpecial. Since it's currently only used + * in FIPS indicators, it's currently only compiled with + * the FIPS indicator code */ +-static int ++static CK_ULONG + sftk_getKeyLength(SFTKObject *source) + { + CK_KEY_TYPE keyType = CK_INVALID_HANDLE; + CK_ATTRIBUTE_TYPE keyAttribute; + CK_ULONG keyLength = 0; + SFTKAttribute *attribute; + CK_RV crv; + +diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h +--- a/lib/util/pkcs11n.h ++++ b/lib/util/pkcs11n.h +@@ -58,16 +58,18 @@ + /* + * NSS-defined certificate types + * + */ + #define CKC_NSS (CKC_VENDOR_DEFINED | NSSCK_VENDOR_NSS) + + /* FAKE PKCS #11 defines */ + #define CKA_DIGEST 0x81000000L ++#define CKA_NSS_GENERATE 0x81000001L ++#define CKA_NSS_GENERATE_KEY_PAIR 0x81000002L + #define CKA_NSS_MESSAGE 0x82000000L + #define CKA_NSS_MESSAGE_MASK 0xff000000L + #define CKA_FLAGS_ONLY 0 /* CKA_CLASS */ + + /* + * NSS-defined object attributes + * + */ 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..2d752e4 --- /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 +@@ -201,16 +201,19 @@ NSS_GetClientAuthData(void *arg, + + /* otherwise look through the cache based on usage + * if chosenNickname is set, we ignore the expiration date */ + if (certList == NULL) { + certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), + certUsageSSLClient, + PR_FALSE, chosenNickName == NULL, + pw_arg); ++ if (certList == NULL) { ++ return SECFailure; ++ } + /* filter only the certs that meet the nickname requirements */ + if (chosenNickName) { + rv = CERT_FilterCertListByNickname(certList, chosenNickName, + pw_arg); + } else { + int nnames = 0; + char **names = ssl_DistNamesToStrings(caNames, &nnames); + rv = CERT_FilterCertListByCANames(certList, nnames, names, diff --git a/SOURCES/nss-3.79-increase-pbe-cache.patch b/SOURCES/nss-3.79-increase-pbe-cache.patch new file mode 100644 index 0000000..e175766 --- /dev/null +++ b/SOURCES/nss-3.79-increase-pbe-cache.patch @@ -0,0 +1,22 @@ +diff --git a/lib/softoken/lowpbe.c b/lib/softoken/lowpbe.c +--- a/lib/softoken/lowpbe.c ++++ b/lib/softoken/lowpbe.c +@@ -565,17 +565,17 @@ struct KDFCacheItemStr { + int iterations; + int keyLen; + }; + typedef struct KDFCacheItemStr KDFCacheItem; + + /* Bug 1606992 - Cache the hash result for the common case that we're + * asked to repeatedly compute the key for the same password item, + * hash, iterations and salt. */ +-#define KDF2_CACHE_COUNT 3 ++#define KDF2_CACHE_COUNT 150 + static struct { + PZLock *lock; + struct { + KDFCacheItem common; + int ivLen; + PRBool faulty3DES; + } cacheKDF1; + struct { diff --git a/SOURCES/nss-3.79-pkcs12-fips-defaults.patch b/SOURCES/nss-3.79-pkcs12-fips-defaults.patch new file mode 100644 index 0000000..fd8cb4d --- /dev/null +++ b/SOURCES/nss-3.79-pkcs12-fips-defaults.patch @@ -0,0 +1,25 @@ +diff -up ./cmd/pk12util/pk12util.c.pkcs12_fips_defaults ./cmd/pk12util/pk12util.c +--- ./cmd/pk12util/pk12util.c.pkcs12_fips_defaults 2022-07-20 13:40:24.152212683 -0700 ++++ ./cmd/pk12util/pk12util.c 2022-07-20 13:42:40.031094190 -0700 +@@ -1146,6 +1146,11 @@ main(int argc, char **argv) + goto done; + } + ++ if (PK11_IsFIPS()) { ++ cipher = SEC_OID_AES_256_CBC; ++ certCipher = SEC_OID_AES_128_CBC; ++ } ++ + if (pk12util.options[opt_Cipher].activated) { + char *cipherString = pk12util.options[opt_Cipher].arg; + +@@ -1160,9 +1165,6 @@ main(int argc, char **argv) + } + } + +- if (PK11_IsFIPS()) { +- certCipher = SEC_OID_UNKNOWN; +- } + if (pk12util.options[opt_CertCipher].activated) { + char *cipherString = pk12util.options[opt_CertCipher].arg; + diff --git a/SOURCES/nss-3.79-pkcs12-fix-null-password.patch b/SOURCES/nss-3.79-pkcs12-fix-null-password.patch new file mode 100644 index 0000000..1195e5c --- /dev/null +++ b/SOURCES/nss-3.79-pkcs12-fix-null-password.patch @@ -0,0 +1,21 @@ +diff -up ./lib/pkcs12/p12local.c.fix_null_password ./lib/pkcs12/p12local.c +--- ./lib/pkcs12/p12local.c.fix_null_password 2022-07-20 14:15:45.081009438 -0700 ++++ ./lib/pkcs12/p12local.c 2022-07-20 14:19:40.856546963 -0700 +@@ -968,15 +968,14 @@ sec_pkcs12_convert_item_to_unicode(PLAre + if (zeroTerm) { + /* unicode adds two nulls at the end */ + if (toUnicode) { +- if ((dest->len >= 2) && +- (dest->data[dest->len - 1] || dest->data[dest->len - 2])) { ++ if ((dest->len < 2) || dest->data[dest->len - 1] || dest->data[dest->len - 2]) { + /* we've already allocated space for these new NULLs */ + PORT_Assert(dest->len + 2 <= bufferSize); + dest->len += 2; + dest->data[dest->len - 1] = dest->data[dest->len - 2] = 0; + } + /* ascii/utf-8 adds just 1 */ +- } else if ((dest->len >= 1) && dest->data[dest->len - 1]) { ++ } else if (!dest->len || dest->data[dest->len - 1]) { + PORT_Assert(dest->len + 1 <= bufferSize); + dest->len++; + dest->data[dest->len - 1] = 0; diff --git a/SOURCES/nss-3.79-revert-distrusted-certs.patch b/SOURCES/nss-3.79-revert-distrusted-certs.patch new file mode 100644 index 0000000..8a607a3 --- /dev/null +++ b/SOURCES/nss-3.79-revert-distrusted-certs.patch @@ -0,0 +1,335 @@ +diff -up ./lib/ckfw/builtins/certdata.txt.revert-distrusted ./lib/ckfw/builtins/certdata.txt +--- ./lib/ckfw/builtins/certdata.txt.revert-distrusted 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/ckfw/builtins/certdata.txt 2022-06-24 10:51:32.035207662 -0700 +@@ -7668,6 +7668,187 @@ CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_ + 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 +@@ -8161,6 +8342,68 @@ CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_ + 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" + # +@@ -8804,6 +9047,74 @@ CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_ + 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" + # diff --git a/SOURCES/nss-3.79-rhel-8-fips-signature-policy.patch b/SOURCES/nss-3.79-rhel-8-fips-signature-policy.patch new file mode 100644 index 0000000..f2692c0 --- /dev/null +++ b/SOURCES/nss-3.79-rhel-8-fips-signature-policy.patch @@ -0,0 +1,685 @@ +diff -up ./cmd/crmftest/testcrmf.c.sign_policy ./cmd/crmftest/testcrmf.c +--- ./cmd/crmftest/testcrmf.c.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./cmd/crmftest/testcrmf.c 2022-06-20 16:47:35.023785628 -0700 +@@ -85,7 +85,7 @@ + #include "sechash.h" + #endif + +-#define MAX_KEY_LEN 512 ++#define MAX_KEY_LEN 1024 + #define PATH_LEN 150 + #define BUFF_SIZE 150 + #define UID_BITS 800 +diff -up ./gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc.sign_policy ./gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc +--- ./gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc 2022-06-20 16:47:35.024785635 -0700 +@@ -16,6 +16,7 @@ + #include "secerr.h" + #include "sechash.h" + #include "pk11_signature_test.h" ++#include "blapit.h" + + #include "testvectors/rsa_signature_2048_sha224-vectors.h" + #include "testvectors/rsa_signature_2048_sha256-vectors.h" +@@ -109,7 +110,11 @@ class Pkcs11RsaPkcs1WycheproofTest + * Use 6 as the invalid value since modLen % 16 must be zero. + */ + TEST(RsaPkcs1Test, Pkcs1MinimumPadding) { +- const size_t kRsaShortKeyBits = 736; ++#define RSA_SHORT_KEY_LENGTH 736 ++/* if our minimum supported key length is big enough to handle ++ * our largest Hash function, we can't test a short length */ ++#if RSA_MIN_MODULUS_BITS < RSA_SHORT_KEY_LENGTH ++ const size_t kRsaShortKeyBits = RSA_SHORT_KEY_LENGTH; + const size_t kRsaKeyBits = 752; + static const std::vector kMsg{'T', 'E', 'S', 'T'}; + static const std::vector kSha512DigestInfo{ +@@ -209,6 +214,9 @@ TEST(RsaPkcs1Test, Pkcs1MinimumPadding) + SEC_OID_PKCS1_RSA_ENCRYPTION, SEC_OID_SHA512, + nullptr); + EXPECT_EQ(SECSuccess, rv); ++#else ++ GTEST_SKIP(); ++#endif + } + + TEST(RsaPkcs1Test, RequireNullParameter) { +diff -up ./gtests/ssl_gtest/tls_subcerts_unittest.cc.sign_policy ./gtests/ssl_gtest/tls_subcerts_unittest.cc +--- ./gtests/ssl_gtest/tls_subcerts_unittest.cc.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./gtests/ssl_gtest/tls_subcerts_unittest.cc 2022-06-20 16:47:35.024785635 -0700 +@@ -9,6 +9,8 @@ + #include "prtime.h" + #include "secerr.h" + #include "ssl.h" ++#include "nss.h" ++#include "blapit.h" + + #include "gtest_utils.h" + #include "tls_agent.h" +@@ -348,9 +350,14 @@ static void GenerateWeakRsaKey(ScopedSEC + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + ASSERT_TRUE(slot); + PK11RSAGenParams rsaparams; +- // The absolute minimum size of RSA key that we can use with SHA-256 is +- // 256bit (hash) + 256bit (salt) + 8 (start byte) + 8 (end byte) = 528. ++// The absolute minimum size of RSA key that we can use with SHA-256 is ++// 256bit (hash) + 256bit (salt) + 8 (start byte) + 8 (end byte) = 528. ++#define RSA_WEAK_KEY 528 ++#if RSA_MIN_MODULUS_BITS < RSA_WEAK_KEY + rsaparams.keySizeInBits = 528; ++#else ++ rsaparams.keySizeInBits = RSA_MIN_MODULUS_BITS + 1; ++#endif + rsaparams.pe = 65537; + + // Bug 1012786: PK11_GenerateKeyPair can fail if there is insufficient +@@ -390,6 +397,18 @@ TEST_P(TlsConnectTls13, DCWeakKey) { + ssl_sig_rsa_pss_pss_sha256}; + client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); + server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes)); ++#if RSA_MIN_MODULUS_BITS > RSA_WEAK_KEY ++ // save the MIN POLICY length. ++ PRInt32 minRsa; ++ ++ ASSERT_EQ(SECSuccess, NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minRsa)); ++#if RSA_MIN_MODULUS_BITS >= 2048 ++ ASSERT_EQ(SECSuccess, ++ NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, RSA_MIN_MODULUS_BITS + 1024)); ++#else ++ ASSERT_EQ(SECSuccess, NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, 2048)); ++#endif ++#endif + + ScopedSECKEYPrivateKey dc_priv; + ScopedSECKEYPublicKey dc_pub; +@@ -412,6 +431,9 @@ TEST_P(TlsConnectTls13, DCWeakKey) { + auto cfilter = MakeTlsFilter( + client_, ssl_delegated_credentials_xtn); + ConnectExpectAlert(client_, kTlsAlertInsufficientSecurity); ++#if RSA_MIN_MODULUS_BITS > RSA_WEAK_KEY ++ ASSERT_EQ(SECSuccess, NSS_OptionSet(NSS_RSA_MIN_KEY_SIZE, minRsa)); ++#endif + } + + class ReplaceDCSigScheme : public TlsHandshakeFilter { +diff -up ./lib/cryptohi/keyhi.h.sign_policy ./lib/cryptohi/keyhi.h +--- ./lib/cryptohi/keyhi.h.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/keyhi.h 2022-06-20 16:47:35.024785635 -0700 +@@ -53,6 +53,11 @@ extern unsigned SECKEY_PublicKeyStrength + extern unsigned SECKEY_PublicKeyStrengthInBits(const SECKEYPublicKey *pubk); + + /* ++** Return the strength of the private key in bits ++*/ ++extern unsigned SECKEY_PrivateKeyStrengthInBits(const SECKEYPrivateKey *privk); ++ ++/* + ** Return the length of the signature in bytes + */ + extern unsigned SECKEY_SignatureLen(const SECKEYPublicKey *pubk); +diff -up ./lib/cryptohi/keyi.h.sign_policy ./lib/cryptohi/keyi.h +--- ./lib/cryptohi/keyi.h.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/keyi.h 2022-06-20 16:47:35.024785635 -0700 +@@ -4,6 +4,7 @@ + + #ifndef _KEYI_H_ + #define _KEYI_H_ ++#include "secerr.h" + + SEC_BEGIN_PROTOS + /* NSS private functions */ +@@ -36,6 +37,9 @@ SECStatus sec_DecodeRSAPSSParamsToMechan + const SECItem *params, + CK_RSA_PKCS_PSS_PARAMS *mech); + ++/* make sure the key length matches the policy for keyType */ ++SECStatus seckey_EnforceKeySize(KeyType keyType, unsigned keyLength, ++ SECErrorCodes error); + SEC_END_PROTOS + + #endif /* _KEYHI_H_ */ +diff -up ./lib/cryptohi/seckey.c.sign_policy ./lib/cryptohi/seckey.c +--- ./lib/cryptohi/seckey.c.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/seckey.c 2022-06-20 16:47:35.025785641 -0700 +@@ -14,6 +14,7 @@ + #include "secdig.h" + #include "prtime.h" + #include "keyi.h" ++#include "nss.h" + + SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) + SEC_ASN1_MKSUB(SEC_IntegerTemplate) +@@ -1042,6 +1043,62 @@ SECKEY_PublicKeyStrengthInBits(const SEC + return bitSize; + } + ++unsigned ++SECKEY_PrivateKeyStrengthInBits(const SECKEYPrivateKey *privk) ++{ ++ unsigned bitSize = 0; ++ CK_ATTRIBUTE_TYPE attribute = CKT_INVALID_TYPE; ++ SECItem params; ++ SECStatus rv; ++ ++ if (!privk) { ++ PORT_SetError(SEC_ERROR_INVALID_KEY); ++ return 0; ++ } ++ ++ /* interpret modulus length as key strength */ ++ switch (privk->keyType) { ++ case rsaKey: ++ case rsaPssKey: ++ case rsaOaepKey: ++ /* some tokens don't export CKA_MODULUS on the private key, ++ * PK11_SignatureLen works around this if necessary */ ++ bitSize = PK11_SignatureLen((SECKEYPrivateKey *)privk) * PR_BITS_PER_BYTE; ++ if (bitSize == -1) { ++ bitSize = 0; ++ } ++ return bitSize; ++ case dsaKey: ++ case fortezzaKey: ++ case dhKey: ++ case keaKey: ++ attribute = CKA_PRIME; ++ break; ++ case ecKey: ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, ++ CKA_EC_PARAMS, NULL, ¶ms); ++ if ((rv != SECSuccess) || (params.data == NULL)) { ++ return 0; ++ } ++ bitSize = SECKEY_ECParamsToKeySize(¶ms); ++ PORT_Free(params.data); ++ return bitSize; ++ default: ++ PORT_SetError(SEC_ERROR_INVALID_KEY); ++ return 0; ++ } ++ PORT_Assert(attribute != CKT_INVALID_TYPE); ++ rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID, ++ attribute, NULL, ¶ms); ++ if ((rv != SECSuccess) || (params.data == NULL)) { ++ PORT_SetError(SEC_ERROR_INVALID_KEY); ++ return 0; ++ } ++ bitSize = SECKEY_BigIntegerBitLength(¶ms); ++ PORT_Free(params.data); ++ return bitSize; ++} ++ + /* returns signature length in bytes (not bits) */ + unsigned + SECKEY_SignatureLen(const SECKEYPublicKey *pubk) +@@ -1212,6 +1269,51 @@ SECKEY_CopyPublicKey(const SECKEYPublicK + } + + /* ++ * Check that a given key meets the policy limits for the given key ++ * size. ++ */ ++SECStatus ++seckey_EnforceKeySize(KeyType keyType, unsigned keyLength, SECErrorCodes error) ++{ ++ PRInt32 opt = -1; ++ PRInt32 optVal; ++ SECStatus rv; ++ ++ switch (keyType) { ++ case rsaKey: ++ case rsaPssKey: ++ case rsaOaepKey: ++ opt = NSS_RSA_MIN_KEY_SIZE; ++ break; ++ case dsaKey: ++ case fortezzaKey: ++ opt = NSS_DSA_MIN_KEY_SIZE; ++ break; ++ case dhKey: ++ case keaKey: ++ opt = NSS_DH_MIN_KEY_SIZE; ++ break; ++ case ecKey: ++ opt = NSS_ECC_MIN_KEY_SIZE; ++ break; ++ case nullKey: ++ default: ++ PORT_SetError(SEC_ERROR_INVALID_KEY); ++ return SECFailure; ++ } ++ PORT_Assert(opt != -1); ++ rv = NSS_OptionGet(opt, &optVal); ++ if (rv != SECSuccess) { ++ return rv; ++ } ++ if (optVal < keyLength) { ++ PORT_SetError(error); ++ return SECFailure; ++ } ++ return SECSuccess; ++} ++ ++/* + * Use the private key to find a public key handle. The handle will be on + * the same slot as the private key. + */ +diff -up ./lib/cryptohi/secsign.c.sign_policy ./lib/cryptohi/secsign.c +--- ./lib/cryptohi/secsign.c.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/secsign.c 2022-06-20 16:47:35.025785641 -0700 +@@ -15,6 +15,7 @@ + #include "pk11func.h" + #include "secerr.h" + #include "keyi.h" ++#include "nss.h" + + struct SGNContextStr { + SECOidTag signalg; +@@ -32,6 +33,7 @@ sgn_NewContext(SECOidTag alg, SECItem *p + SECOidTag hashalg, signalg; + KeyType keyType; + PRUint32 policyFlags; ++ PRInt32 optFlags; + SECStatus rv; + + /* OK, map a PKCS #7 hash and encrypt algorithm into +@@ -56,6 +58,16 @@ sgn_NewContext(SECOidTag alg, SECItem *p + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return NULL; + } ++ if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) { ++ if (optFlags & NSS_KEY_SIZE_POLICY_SIGN_FLAG) { ++ rv = seckey_EnforceKeySize(key->keyType, ++ SECKEY_PrivateKeyStrengthInBits(key), ++ SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); ++ if (rv != SECSuccess) { ++ return NULL; ++ } ++ } ++ } + /* check the policy on the hash algorithm */ + if ((NSS_GetAlgorithmPolicy(hashalg, &policyFlags) == SECFailure) || + !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { +@@ -467,9 +479,20 @@ SGN_Digest(SECKEYPrivateKey *privKey, + SGNDigestInfo *di = 0; + SECOidTag enctag; + PRUint32 policyFlags; ++ PRInt32 optFlags; + + result->data = 0; + ++ if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) { ++ if (optFlags & NSS_KEY_SIZE_POLICY_SIGN_FLAG) { ++ rv = seckey_EnforceKeySize(privKey->keyType, ++ SECKEY_PrivateKeyStrengthInBits(privKey), ++ SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); ++ if (rv != SECSuccess) { ++ return SECFailure; ++ } ++ } ++ } + /* check the policy on the hash algorithm */ + if ((NSS_GetAlgorithmPolicy(algtag, &policyFlags) == SECFailure) || + !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { +diff -up ./lib/cryptohi/secvfy.c.sign_policy ./lib/cryptohi/secvfy.c +--- ./lib/cryptohi/secvfy.c.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/secvfy.c 2022-06-20 16:47:35.025785641 -0700 +@@ -16,6 +16,7 @@ + #include "secdig.h" + #include "secerr.h" + #include "keyi.h" ++#include "nss.h" + + /* + ** Recover the DigestInfo from an RSA PKCS#1 signature. +@@ -467,6 +468,7 @@ vfy_CreateContext(const SECKEYPublicKey + unsigned int sigLen; + KeyType type; + PRUint32 policyFlags; ++ PRInt32 optFlags; + + /* make sure the encryption algorithm matches the key type */ + /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */ +@@ -476,7 +478,16 @@ vfy_CreateContext(const SECKEYPublicKey + PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH); + return NULL; + } +- ++ if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) { ++ if (optFlags & NSS_KEY_SIZE_POLICY_VERIFY_FLAG) { ++ rv = seckey_EnforceKeySize(key->keyType, ++ SECKEY_PublicKeyStrengthInBits(key), ++ SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); ++ if (rv != SECSuccess) { ++ return NULL; ++ } ++ } ++ } + /* check the policy on the encryption algorithm */ + if ((NSS_GetAlgorithmPolicy(encAlg, &policyFlags) == SECFailure) || + !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { +diff -up ./lib/freebl/blapit.h.sign_policy ./lib/freebl/blapit.h +--- ./lib/freebl/blapit.h.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/freebl/blapit.h 2022-06-20 16:47:35.025785641 -0700 +@@ -135,7 +135,7 @@ typedef int __BLAPI_DEPRECATED __attribu + * These values come from the initial key size limits from the PKCS #11 + * module. They may be arbitrarily adjusted to any value freebl supports. + */ +-#define RSA_MIN_MODULUS_BITS 128 ++#define RSA_MIN_MODULUS_BITS 1023 /* 128 */ + #define RSA_MAX_MODULUS_BITS 16384 + #define RSA_MAX_EXPONENT_BITS 64 + #define DH_MIN_P_BITS 128 +diff -up ./lib/nss/nss.h.sign_policy ./lib/nss/nss.h +--- ./lib/nss/nss.h.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/nss/nss.h 2022-06-20 16:47:35.026785647 -0700 +@@ -302,6 +302,28 @@ SECStatus NSS_UnregisterShutdown(NSS_Shu + #define NSS_DEFAULT_LOCKS 0x00d /* lock default values */ + #define NSS_DEFAULT_SSL_LOCK 1 /* lock the ssl default values */ + ++/* NSS_KEY_SIZE_POLICY controls what kinds of operations are subject to ++ * the NSS_XXX_MIN_KEY_SIZE values. ++ * NSS_KEY_SIZE_POLICY_FLAGS sets and clears all the flags to the input ++ * value ++ * On get it returns all the flags ++ * NSS_KEY_SIZE_POLICY_SET_FLAGS sets only the flags=1 in theinput value and ++ * does not affect the other flags ++ * On get it returns all the flags ++ * NSS_KEY_SIZE_POLICY_CLEAR_FLAGS clears only the flags=1 in the input ++ * value and does not affect the other flags ++ * On get it returns all the compliment of all the flags ++ * (cleared flags == 1) */ ++#define NSS_KEY_SIZE_POLICY_FLAGS 0x00e ++#define NSS_KEY_SIZE_POLICY_SET_FLAGS 0x00f ++#define NSS_KEY_SIZE_POLICY_CLEAR_FLAGS 0x010 ++/* currently defined flags */ ++#define NSS_KEY_SIZE_POLICY_SSL_FLAG 1 ++#define NSS_KEY_SIZE_POLICY_VERIFY_FLAG 2 ++#define NSS_KEY_SIZE_POLICY_SIGN_FLAG 4 ++ ++#define NSS_ECC_MIN_KEY_SIZE 0x011 ++ + /* + * Set and get global options for the NSS library. + */ +diff -up ./lib/nss/nssoptions.c.sign_policy ./lib/nss/nssoptions.c +--- ./lib/nss/nssoptions.c.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/nss/nssoptions.c 2022-06-20 16:47:35.026785647 -0700 +@@ -26,6 +26,8 @@ struct nssOps { + PRInt32 dtlsVersionMaxPolicy; + PRInt32 pkcs12DecodeForceUnicode; + PRInt32 defaultLocks; ++ PRInt32 keySizePolicyFlags; ++ PRInt32 eccMinKeySize; + }; + + static struct nssOps nss_ops = { +@@ -37,7 +39,9 @@ static struct nssOps nss_ops = { + 1, + 0xffff, + PR_FALSE, +- 0 ++ 0, ++ NSS_KEY_SIZE_POLICY_SSL_FLAG, ++ SSL_ECC_MIN_CURVE_BITS + }; + + SECStatus +@@ -78,6 +82,18 @@ NSS_OptionSet(PRInt32 which, PRInt32 val + case NSS_DEFAULT_LOCKS: + nss_ops.defaultLocks = value; + break; ++ case NSS_KEY_SIZE_POLICY_FLAGS: ++ nss_ops.keySizePolicyFlags = value; ++ break; ++ case NSS_KEY_SIZE_POLICY_SET_FLAGS: ++ nss_ops.keySizePolicyFlags |= value; ++ break; ++ case NSS_KEY_SIZE_POLICY_CLEAR_FLAGS: ++ nss_ops.keySizePolicyFlags &= ~value; ++ break; ++ case NSS_ECC_MIN_KEY_SIZE: ++ nss_ops.eccMinKeySize = value; ++ break; + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; +@@ -119,6 +135,16 @@ NSS_OptionGet(PRInt32 which, PRInt32 *va + case NSS_DEFAULT_LOCKS: + *value = nss_ops.defaultLocks; + break; ++ case NSS_KEY_SIZE_POLICY_FLAGS: ++ case NSS_KEY_SIZE_POLICY_SET_FLAGS: ++ *value = nss_ops.keySizePolicyFlags; ++ break; ++ case NSS_KEY_SIZE_POLICY_CLEAR_FLAGS: ++ *value = ~nss_ops.keySizePolicyFlags; ++ break; ++ case NSS_ECC_MIN_KEY_SIZE: ++ *value = nss_ops.eccMinKeySize; ++ break; + default: + rv = SECFailure; + } +diff -up ./lib/nss/nssoptions.h.sign_policy ./lib/nss/nssoptions.h +--- ./lib/nss/nssoptions.h.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/nss/nssoptions.h 2022-06-20 16:47:35.026785647 -0700 +@@ -18,3 +18,5 @@ + * happens because NSS used to count bit lengths incorrectly. */ + #define SSL_DH_MIN_P_BITS 1023 + #define SSL_DSA_MIN_P_BITS 1023 ++/* not really used by SSL, but define it here for consistency */ ++#define SSL_ECC_MIN_CURVE_BITS 256 +diff -up ./lib/pk11wrap/pk11kea.c.sign_policy ./lib/pk11wrap/pk11kea.c +--- ./lib/pk11wrap/pk11kea.c.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/pk11wrap/pk11kea.c 2022-06-20 16:47:35.026785647 -0700 +@@ -78,15 +78,14 @@ pk11_KeyExchange(PK11SlotInfo *slot, CK_ + if (privKeyHandle == CK_INVALID_HANDLE) { + PK11RSAGenParams rsaParams; + +- if (symKeyLength > 53) /* bytes */ { +- /* we'd have to generate an RSA key pair > 512 bits long, ++ if (symKeyLength > 120) /* bytes */ { ++ /* we'd have to generate an RSA key pair > 1024 bits long, + ** and that's too costly. Don't even try. + */ + PORT_SetError(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY); + goto rsa_failed; + } +- rsaParams.keySizeInBits = +- (symKeyLength > 21 || symKeyLength == 0) ? 512 : 256; ++ rsaParams.keySizeInBits = 1024; + rsaParams.pe = 0x10001; + privKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, + &rsaParams, &pubKey, PR_FALSE, PR_TRUE, symKey->cx); +diff -up ./lib/pk11wrap/pk11pars.c.sign_policy ./lib/pk11wrap/pk11pars.c +--- ./lib/pk11wrap/pk11pars.c.sign_policy 2022-06-20 16:47:35.004785510 -0700 ++++ ./lib/pk11wrap/pk11pars.c 2022-06-20 16:47:35.026785647 -0700 +@@ -427,12 +427,21 @@ static const optionFreeDef sslOptList[] + { CIPHER_NAME("DTLS1.3"), 0x304 }, + }; + ++static const optionFreeDef keySizeFlagsList[] = { ++ { CIPHER_NAME("KEY-SIZE-SSL"), NSS_KEY_SIZE_POLICY_SSL_FLAG }, ++ { CIPHER_NAME("KEY-SIZE-SIGN"), NSS_KEY_SIZE_POLICY_SIGN_FLAG }, ++ { CIPHER_NAME("KEY-SIZE-VERIFY"), NSS_KEY_SIZE_POLICY_VERIFY_FLAG }, ++}; ++ + static const optionFreeDef freeOptList[] = { + + /* Restrictions for asymetric keys */ + { CIPHER_NAME("RSA-MIN"), NSS_RSA_MIN_KEY_SIZE }, + { CIPHER_NAME("DH-MIN"), NSS_DH_MIN_KEY_SIZE }, + { CIPHER_NAME("DSA-MIN"), NSS_DSA_MIN_KEY_SIZE }, ++ { CIPHER_NAME("ECC-MIN"), NSS_ECC_MIN_KEY_SIZE }, ++ /* what operations doe the key size apply to */ ++ { CIPHER_NAME("KEY-SIZE-FLAGS"), NSS_KEY_SIZE_POLICY_FLAGS }, + /* constraints on SSL Protocols */ + { CIPHER_NAME("TLS-VERSION-MIN"), NSS_TLS_VERSION_MIN_POLICY }, + { CIPHER_NAME("TLS-VERSION-MAX"), NSS_TLS_VERSION_MAX_POLICY }, +@@ -540,6 +549,7 @@ secmod_getPolicyOptValue(const char *pol + *result = val; + return SECSuccess; + } ++ /* handle any ssl strings */ + for (i = 0; i < PR_ARRAY_SIZE(sslOptList); i++) { + if (policyValueLength == sslOptList[i].name_size && + PORT_Strncasecmp(sslOptList[i].name, policyValue, +@@ -548,7 +558,29 @@ secmod_getPolicyOptValue(const char *pol + return SECSuccess; + } + } +- return SECFailure; ++ /* handle key_size flags. Each flag represents a bit, which ++ * gets or'd together. They can be separated by , | or + */ ++ val = 0; ++ while (*policyValue) { ++ PRBool found = PR_FALSE; ++ for (i = 0; i < PR_ARRAY_SIZE(keySizeFlagsList); i++) { ++ if (PORT_Strncasecmp(keySizeFlagsList[i].name, policyValue, ++ keySizeFlagsList[i].name_size) == 0) { ++ val |= keySizeFlagsList[i].option; ++ found = PR_TRUE; ++ policyValue += keySizeFlagsList[i].name_size; ++ break; ++ } ++ } ++ if (!found) { ++ return SECFailure; ++ } ++ if (*policyValue == ',' || *policyValue == '|' || *policyValue == '+') { ++ policyValue++; ++ } ++ } ++ *result = val; ++ return SECSuccess; + } + + /* Policy operations: +diff -up ./lib/ssl/ssl3con.c.sign_policy ./lib/ssl/ssl3con.c +--- ./lib/ssl/ssl3con.c.sign_policy 2022-06-20 16:47:34.998785473 -0700 ++++ ./lib/ssl/ssl3con.c 2022-06-20 16:47:35.028785660 -0700 +@@ -7409,6 +7409,8 @@ ssl_HandleDHServerKeyExchange(sslSocket + unsigned dh_p_bits; + unsigned dh_g_bits; + PRInt32 minDH; ++ PRInt32 optval; ++ PRBool usePolicyLength = PR_FALSE; + + SSL3Hashes hashes; + SECItem signature = { siBuffer, NULL, 0 }; +@@ -7419,8 +7421,13 @@ ssl_HandleDHServerKeyExchange(sslSocket + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } ++ rv = NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optval); ++ if (rv == SECSuccess) { ++ usePolicyLength = (PRBool)((optval & NSS_KEY_SIZE_POLICY_SSL_FLAG) == NSS_KEY_SIZE_POLICY_SSL_FLAG); ++ } + +- rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH); ++ rv = usePolicyLength ? NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH) ++ : SECFailure; + if (rv != SECSuccess || minDH <= 0) { + minDH = SSL_DH_MIN_P_BITS; + } +@@ -11411,13 +11418,20 @@ ssl_SetAuthKeyBits(sslSocket *ss, const + SECStatus rv; + PRUint32 minKey; + PRInt32 optval; ++ PRBool usePolicyLength = PR_TRUE; ++ ++ rv = NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optval); ++ if (rv == SECSuccess) { ++ usePolicyLength = (PRBool)((optval & NSS_KEY_SIZE_POLICY_SSL_FLAG) == NSS_KEY_SIZE_POLICY_SSL_FLAG); ++ } + + ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); + switch (SECKEY_GetPublicKeyType(pubKey)) { + case rsaKey: + case rsaPssKey: + case rsaOaepKey: +- rv = NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &optval); ++ rv = usePolicyLength ? NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &optval) ++ : SECFailure; + if (rv == SECSuccess && optval > 0) { + minKey = (PRUint32)optval; + } else { +@@ -11426,7 +11440,8 @@ ssl_SetAuthKeyBits(sslSocket *ss, const + break; + + case dsaKey: +- rv = NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &optval); ++ rv = usePolicyLength ? NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &optval) ++ : SECFailure; + if (rv == SECSuccess && optval > 0) { + minKey = (PRUint32)optval; + } else { +@@ -11435,7 +11450,8 @@ ssl_SetAuthKeyBits(sslSocket *ss, const + break; + + case dhKey: +- rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &optval); ++ rv = usePolicyLength ? NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &optval) ++ : SECFailure; + if (rv == SECSuccess && optval > 0) { + minKey = (PRUint32)optval; + } else { +@@ -11444,9 +11460,15 @@ ssl_SetAuthKeyBits(sslSocket *ss, const + break; + + case ecKey: +- /* Don't check EC strength here on the understanding that we only +- * support curves we like. */ +- minKey = ss->sec.authKeyBits; ++ rv = usePolicyLength ? NSS_OptionGet(NSS_ECC_MIN_KEY_SIZE, &optval) ++ : SECFailure; ++ if (rv == SECSuccess && optval > 0) { ++ minKey = (PRUint32)optval; ++ } else { ++ /* Don't check EC strength here on the understanding that we ++ * only support curves we like. */ ++ minKey = ss->sec.authKeyBits; ++ } + break; + + default: +diff -up ./tests/policy/crypto-policy.txt.sign_policy ./tests/policy/crypto-policy.txt +--- ./tests/policy/crypto-policy.txt.sign_policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./tests/policy/crypto-policy.txt 2022-06-20 16:47:35.028785660 -0700 +@@ -6,6 +6,8 @@ + 0 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA1:HMAC-SHA384:HMAC-SHA512:SECP256R1:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:aes256-cbc:camellia256-cbc:aes128-gcm:aes128-cbc:camellia128-cbc:SHA256:SHA384:SHA512:SHA1:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:rsa-pkcs:rsa-pss:ecdsa:tls-version-min=tls1.0:dtls-version-min=dtls1.0:DH-MIN=1023:DSA-MIN=2048:RSA-MIN=2048 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Standard policy + 0 disallow=ALL_allow=HMAC-SHA1:HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP256R1:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:aes256-cbc:camellia256-cbc:aes128-gcm:aes128-cbc:camellia128-cbc:des-ede3-cbc:rc4:SHA256:SHA384:SHA512:SHA1:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:DHE-DSS:rsa-pkcs:rsa-pss:ecdsa:tls-version-min=tls1.0:dtls-version-min=tls1.0:DH-MIN=1023:DSA-MIN=1023:RSA-MIN=1023 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Legacy policy + 0 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:SHA384:SHA512:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:rsa-pkcs:rsa-pss:ecdsa:tls-version-min=tls1.2:dtls-version-min=dtls1.2:DH-MIN=3072:DSA-MIN=3072:RSA-MIN=3072 NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Reduced policy ++0 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:SHA384:SHA512:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:rsa-pkcs:rsa-pss:ecdsa:tls-version-min=tls1.2:dtls-version-min=dtls1.2:DH-MIN=3072:DSA-MIN=3072:RSA-MIN=3072:KEY-SIZE-FLAGS=KEY-SIZE-SSL,KEY-SIZE-SIGN,KEY-SIZE-VERIFY NSS-POLICY-INFO.*LOADED-SUCCESSFULLY Valid key size ++2 disallow=ALL_allow=HMAC-SHA256:HMAC-SHA384:HMAC-SHA512:SECP384R1:SECP521R1:aes256-gcm:chacha20-poly1305:SHA384:SHA512:ECDHE-RSA:ECDHE-ECDSA:RSA:DHE-RSA:rsa-pkcs:rsa-pss:ecdsa:tls-version-min=tls1.2:dtls-version-min=dtls1.2:DH-MIN=3072:DSA-MIN=3072:RSA-MIN=3072:KEY-SIZE-FLAGS=UNKNOWN,KEY-SIZE-SIGN,KEY-SIZE-VERIFY NSS-POLICY-FAIL.*unknown.* Invalid key size + 2 disallow=ALL_allow=dtls-version-min=:dtls-version-max= NSS-POLICY-FAIL Missing value + 2 disallow=ALL_allow=RSA-MIN=whatever NSS-POLICY-FAIL Invalid value + 2 disallow=ALL_allow=flower NSS-POLICY-FAIL Invalid identifier +diff -up ./tests/ssl/sslpolicy.txt.sign_policy ./tests/ssl/sslpolicy.txt +--- ./tests/ssl/sslpolicy.txt.sign_policy 2022-06-20 16:47:35.028785660 -0700 ++++ ./tests/ssl/sslpolicy.txt 2022-06-20 16:50:08.958742135 -0700 +@@ -196,6 +196,11 @@ + # rsa-pkcs, rsa-pss, and ecdsa policy checking reverted in rhel8 for binary + # compatibility reasons + # 1 noECC SSL3 d disallow=rsa-pkcs Disallow RSA PKCS 1 Signatures Explicitly ++ 1 noECC SSL3 d allow=rsa-min=16384:key-size-flags=key-size-verify Restrict RSA keys on signature verification ++ 1 noECC SSL3 d allow=rsa-min=16384:key-size-flags=key-size-sign Restrict RSA keys on signing ++ 1 noECC SSL3 d allow=rsa-min=16384:key-size-flags=key-size-ssl Restrict RSA keys when used in SSL ++ 0 noECC SSL3 d allow=rsa-min=1023 Restrict RSA keys when used in SSL ++ + # test default settings + # NOTE: tstclient will attempt to overide the defaults, so we detect we + # were successful by locking in our settings +diff -up ./tests/dbupgrade/dbupgrade.sh.sign_policy ./tests/dbupgrade/dbupgrade.sh +--- ./tests/dbupgrade/dbupgrade.sh.sign_policy 2022-06-22 08:43:55.905407738 -0700 ++++ ./tests/dbupgrade/dbupgrade.sh 2022-06-22 08:43:58.837426779 -0700 +@@ -69,7 +69,7 @@ dbupgrade_main() + echo $i + if [ -d $i ]; then + echo "upgrading db $i" +- ${BINDIR}/certutil -G -g 512 -d sql:$i -f ${PWFILE} -z ${NOISE_FILE} 2>&1 ++ ${BINDIR}/certutil -G -g 1024 -d sql:$i -f ${PWFILE} -z ${NOISE_FILE} 2>&1 + html_msg $? 0 "Upgrading $i" + else + echo "skipping db $i" 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..bf8c1f2 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: 10%{?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,9 @@ Source25: key3.db.xml Source26: key4.db.xml Source27: secmod.db.xml Source28: nss-p11-kit.config -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, @@ -138,29 +151,22 @@ Patch40: nss-3.66-disable-signature-policies.patch 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 +# Local Patch: restore expired distrusted certs for now +Patch51: nss-3.79-revert-distrusted-certs.patch +# Local Patch: update fipsdefaults to AES +Patch52: nss-3.79-pkcs12-fips-defaults.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 - - +# https://bugzilla.redhat.com/show_bug.cgi?id=1774659 +Patch60: nss-3.79-dbtool.patch +Patch61: nss-3.79-dont-verify-default.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1774654 +Patch63: nss-3.79-fix-client-cert-crash.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1767883 +Patch64: nss-3.79-rhel-8-fips-signature-policy.patch +Patch65: nss-3.79-enable-POST-rerun.patch +Patch66: nss-3.79-increase-pbe-cache.patch +Patch67: nss-3.79-pkcs12-fix-null-password.patch +Patch68: nss-3.79-fips.patch %description Network Security Services (NSS) is a set of libraries designed to @@ -203,7 +209,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 +230,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 +238,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 +247,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 +284,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,15 +296,12 @@ 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 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/ - %build export FREEBL_NO_DEPEND=1 @@ -312,7 +315,14 @@ 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}" +export NSS_FIPS_140_3=1 +export NSS_ENABLE_FIPS_INDICATORS=1 # Enable compiler optimizations and disable debugging code export BUILD_OPT=1 @@ -603,7 +613,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 +738,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 +896,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 +944,46 @@ update-crypto-policies --no-reload &> /dev/null || : %changelog +* Thu Aug 11 2022 Bob Relyea - 3.79.0-11 +- Fix QA found failures: +- remove extra '+' from sslpolicy.txt file causing test error values +- only use GRND_RANDOM if the kernel is in FIPS mode. + +* Fri Aug 5 2022 Bob Relyea - 3.79.0-9 +- FIPS 140-3 changes + +* Wed Jul 13 2022 Bob Relyea - 3.79.0-8 +- Update fips default for pk12util to AES rather than TDES +- Fix bug in pkcs12 files with null passwords + +* Wed Jul 6 2022 Bob Relyea - 3.79.0-7 +- Better fix for test regressions + +* Mon Jun 27 2022 Bob Relyea - 3.79.0-6 +- fix nss.spec so it works in a rhel-8.1.0 buildroot + +* Mon Jun 20 2022 Bob Relyea - 3.79.0-5 +- FIPS 140-3 changes +- Reject Small RSA keys, 1024 bit keys are marked as FIP OK when verifying, reject + signature keys by policy +- Allow applications to retrigger selftests on demand. + +* 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