From de2abf3fa9eb71f368063ff4c1ff829ce3b7a3fe Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 20 Sep 2022 07:46:47 -0400 Subject: [PATCH] import nss-3.79.0-14.el9_0 --- .gitignore | 5 +- .nss.metadata | 5 +- SOURCES/fips_algorithms.h | 173 + .../nspr-4.34-fix-coverity-loop-issue.patch | 51 + SOURCES/nspr-4.34-server-passive.patch | 12 + SOURCES/nss-3.67-cve-2021-43527-test.patch | 325 -- SOURCES/nss-3.67-cve-2021-43527.patch | 279 -- SOURCES/nss-3.71-fips-module-name.patch | 825 ---- SOURCES/nss-3.71-ipv6-fix.patch | 36 - SOURCES/nss-3.75-fix-pkcs12-passwords.patch | 257 -- SOURCES/nss-3.79-dbtool.patch | 3411 +++++++++++++++++ SOURCES/nss-3.79-distrusted-certs.patch | 375 ++ 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 + .../nss-3.79-pkcs12-fix-null-password.patch | 21 + ...ss-3.79-rhel-9-fips-signature-policy.patch | 672 ++++ SOURCES/nss-disable-dc.patch | 32 + SPECS/nss.spec | 207 +- 21 files changed, 6387 insertions(+), 1778 deletions(-) create mode 100644 SOURCES/fips_algorithms.h create mode 100644 SOURCES/nspr-4.34-fix-coverity-loop-issue.patch create mode 100644 SOURCES/nspr-4.34-server-passive.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.71-fips-module-name.patch delete mode 100644 SOURCES/nss-3.71-ipv6-fix.patch delete mode 100644 SOURCES/nss-3.75-fix-pkcs12-passwords.patch create mode 100644 SOURCES/nss-3.79-dbtool.patch create mode 100644 SOURCES/nss-3.79-distrusted-certs.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-fix-null-password.patch create mode 100644 SOURCES/nss-3.79-rhel-9-fips-signature-policy.patch create mode 100644 SOURCES/nss-disable-dc.patch diff --git a/.gitignore b/.gitignore index d651e6d..5f1d603 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ -SOURCES/PayPalEE.cert SOURCES/blank-cert9.db SOURCES/blank-key4.db -SOURCES/nspr-4.32.tar.gz -SOURCES/nss-3.71.tar.gz +SOURCES/nspr-4.34.tar.gz +SOURCES/nss-3.79.tar.gz diff --git a/.nss.metadata b/.nss.metadata index 2aedeb3..bb45cf6 100644 --- a/.nss.metadata +++ b/.nss.metadata @@ -1,5 +1,4 @@ -5c92efcd23ae5dc57c4f0a3903d662365bca008c SOURCES/PayPalEE.cert b5570125fbf6bfb410705706af48217a0817c03a SOURCES/blank-cert9.db f9c9568442386da370193474de1b25c3f68cdaf6 SOURCES/blank-key4.db -28e05ef5cbe6e7cde239d3cdcccabf571ec73f69 SOURCES/nspr-4.32.tar.gz -b60e3e0a2765d4009347e08dc9792a4dc4aded03 SOURCES/nss-3.71.tar.gz +efea1385dc83c55018183257036206b5f2c77c59 SOURCES/nspr-4.34.tar.gz +3719dd97c8ec9cb04aa61e6aca41b129b4adc004 SOURCES/nss-3.79.tar.gz diff --git a/SOURCES/fips_algorithms.h b/SOURCES/fips_algorithms.h new file mode 100644 index 0000000..5f6dbe3 --- /dev/null +++ b/SOURCES/fips_algorithms.h @@ -0,0 +1,173 @@ +/* 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/. */ + +/* + * Vendors should replace this header file with the file containing those + * algorithms which have NIST algorithm Certificates. + */ + +/* handle special cases. Classes require existing code to already be + * in place for that class */ +typedef enum { + SFTKFIPSNone = 0, + SFTKFIPSDH, /* allow only specific primes */ + SFTKFIPSECC, /* not just keys but specific curves */ + SFTKFIPSAEAD /* single shot AEAD functions not allowed in FIPS mode */ +} SFTKFIPSSpecialClass; + +typedef struct SFTKFIPSAlgorithmListStr SFTKFIPSAlgorithmList; +struct SFTKFIPSAlgorithmListStr { + CK_MECHANISM_TYPE type; + CK_MECHANISM_INFO info; + CK_ULONG step; + SFTKFIPSSpecialClass special; +}; + +SFTKFIPSAlgorithmList sftk_fips_mechs[] = { +/* A sample set of algorithms to allow basic testing in our continous + * testing infrastructure. The vendor version should replace this with + * a version that matches their algorithm testing and security policy */ +/* NOTE, This looks a lot like the PKCS #11 mechanism list in pkcs11.c, it + * differs in the following ways: + * 1) the addition of step and class elements to help restrict + * the supported key sizes and types. + * 2) The mechanism flags are restricted to only those that map to + * fips approved operations. + * 3) All key sizes are in bits, independent of mechanism. + * 4) You can add more then one entry for the same mechanism to handle + * multiple descrete keys where the MIN/MAX/STEP semantics doesn't apply + * or where different operations have different key requirements. + * This table does not encode all the modules legal FIPS semantics, only + * those semantics that might possibly change due to algorithms dropping + * of the security policy late in the process. */ +/* handy common flag types */ +#define CKF_KPG CKF_GENERATE_KEY_PAIR +#define CKF_GEN CKF_GENERATE +#define CKF_SGN (CKF_SIGN | CKF_VERIFY) +#define CKF_ENC (CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP) +#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 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, 8192 /* 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 }, + + /* -------------- 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_SHA224, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone }, + { CKM_DSA_SHA256, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone }, + { CKM_DSA_SHA384, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone }, + { CKM_DSA_SHA512, { DSA_FB_KEY, CKF_VERIFY }, DSA_FB_STEP, SFTKFIPSNone }, + /* -------------------- Diffie Hellman Operations --------------------- */ + /* no diffie hellman yet */ + { CKM_DH_PKCS_KEY_PAIR_GEN, { DH_FB_KEY, CKF_KPG }, DH_FB_STEP, SFTKFIPSDH }, + { CKM_DH_PKCS_DERIVE, { DH_FB_KEY, CKF_KEA }, DH_FB_STEP, SFTKFIPSDH }, + /* -------------------- Elliptic Curve Operations --------------------- */ + { CKM_EC_KEY_PAIR_GEN, { EC_FB_KEY, CKF_KPG }, EC_FB_STEP, SFTKFIPSECC }, + { CKM_ECDH1_DERIVE, { EC_FB_KEY, CKF_KEA }, EC_FB_STEP, SFTKFIPSECC }, + { CKM_ECDSA_SHA224, { EC_FB_KEY, CKF_SGN }, EC_FB_STEP, SFTKFIPSECC }, + { 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_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 }, + /* ------------------------- 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, { 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, { 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, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone }, + { CKM_SHA512_HMAC_GENERAL, { 112, 512, CKF_SGN }, 1, SFTKFIPSNone }, + /* --------------------- Secret Key Operations ------------------------ */ + { 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, { 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, { 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, { 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, { 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, { 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, { 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/SOURCES/nspr-4.34-fix-coverity-loop-issue.patch b/SOURCES/nspr-4.34-fix-coverity-loop-issue.patch new file mode 100644 index 0000000..c8c4149 --- /dev/null +++ b/SOURCES/nspr-4.34-fix-coverity-loop-issue.patch @@ -0,0 +1,51 @@ +diff --git a/pr/src/misc/prnetdb.c b/pr/src/misc/prnetdb.c +--- a/pr/src/misc/prnetdb.c ++++ b/pr/src/misc/prnetdb.c +@@ -2209,28 +2209,38 @@ PR_GetPrefLoopbackAddrInfo(PRNetAddr *re + PRBool result_still_empty = PR_TRUE; + PRADDRINFO *ai = res; + do { + PRNetAddr aNetAddr; + + while (ai && ai->ai_addrlen > sizeof(PRNetAddr)) + ai = ai->ai_next; + +- if (ai) { +- /* copy sockaddr to PRNetAddr */ +- memcpy(&aNetAddr, ai->ai_addr, ai->ai_addrlen); +- aNetAddr.raw.family = ai->ai_addr->sa_family; ++ if (!ai) { ++ break; ++ } ++ ++ /* copy sockaddr to PRNetAddr */ ++ memcpy(&aNetAddr, ai->ai_addr, ai->ai_addrlen); ++ aNetAddr.raw.family = ai->ai_addr->sa_family; + #ifdef _PR_INET6 +- if (AF_INET6 == aNetAddr.raw.family) +- aNetAddr.raw.family = PR_AF_INET6; ++ if (AF_INET6 == aNetAddr.raw.family) ++ aNetAddr.raw.family = PR_AF_INET6; + #endif +- if (ai->ai_addrlen < sizeof(PRNetAddr)) +- memset(((char*)result)+ai->ai_addrlen, 0, +- sizeof(PRNetAddr) - ai->ai_addrlen); ++ if (ai->ai_addrlen < sizeof(PRNetAddr)) ++ memset(((char*)&aNetAddr)+ai->ai_addrlen, 0, ++ sizeof(PRNetAddr) - ai->ai_addrlen); ++ ++ if (result->raw.family == PR_AF_INET) { ++ aNetAddr.inet.port = htons(port); + } ++ else { ++ aNetAddr.ipv6.port = htons(port); ++ } ++ + + /* If we obtain more than one result, prefer IPv6. */ + if (result_still_empty || aNetAddr.raw.family == PR_AF_INET6) { + memcpy(result, &aNetAddr, sizeof(PRNetAddr)); + } + result_still_empty = PR_FALSE; + ai = ai->ai_next; + } diff --git a/SOURCES/nspr-4.34-server-passive.patch b/SOURCES/nspr-4.34-server-passive.patch new file mode 100644 index 0000000..ed8d713 --- /dev/null +++ b/SOURCES/nspr-4.34-server-passive.patch @@ -0,0 +1,12 @@ +diff -r c75b4e36b7e8 pr/src/misc/prnetdb.c +--- a/pr/src/misc/prnetdb.c Wed May 25 23:39:48 2022 +0200 ++++ b/pr/src/misc/prnetdb.c Tue Jun 14 18:48:03 2022 -0400 +@@ -2204,6 +2204,7 @@ + + memset(&hints, 0, sizeof(hints)); + ++ hints.ai_flags = AI_PASSIVE; + rv = GETADDRINFO(NULL, tmpBuf, &hints, &res); + if (rv == 0) { + PRBool result_still_empty = PR_TRUE; + 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.71-fips-module-name.patch b/SOURCES/nss-3.71-fips-module-name.patch deleted file mode 100644 index a1ec103..0000000 --- a/SOURCES/nss-3.71-fips-module-name.patch +++ /dev/null @@ -1,825 +0,0 @@ -diff --git a/cmd/manifest.mn b/cmd/manifest.mn ---- a/cmd/manifest.mn -+++ b/cmd/manifest.mn -@@ -76,6 +76,7 @@ - symkeyutil \ - tests \ - tstclnt \ -+ validation \ - vfychain \ - vfyserv \ - modutil \ -diff --git a/cmd/validation/Makefile b/cmd/validation/Makefile -new file mode 100644 ---- /dev/null -+++ b/cmd/validation/Makefile -@@ -0,0 +1,48 @@ -+#! 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) # -+####################################################################### -+ -+ -+ -+####################################################################### -+# (7) Execute "local" rules. (OPTIONAL). # -+####################################################################### -+ -+ -+include ../platrules.mk -+ -diff --git a/cmd/validation/manifest.mn b/cmd/validation/manifest.mn -new file mode 100644 ---- /dev/null -+++ b/cmd/validation/manifest.mn -@@ -0,0 +1,23 @@ -+# -+# 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 = ../.. -+ -+DEFINES += -DNSPR20 -+ -+# MODULE public and private header directories are implicitly REQUIRED. -+MODULE = nss -+ -+CSRCS = \ -+ validation.c \ -+ $(NULL) -+ -+# The MODULE is always implicitly required. -+# Listing it here in REQUIRES makes it appear twice in the cc command line. -+REQUIRES = dbm seccmd -+ -+PROGRAM = validation -+ -+# USE_STATIC_LIBS = 1 -diff --git a/cmd/validation/validation.c b/cmd/validation/validation.c -new file mode 100644 ---- /dev/null -+++ b/cmd/validation/validation.c -@@ -0,0 +1,249 @@ -+/* 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/. */ -+ -+#ifdef _CRTDBG_MAP_ALLOC -+#include -+#include -+#endif -+ -+#include "nspr.h" -+#include "secutil.h" -+#include "pk11func.h" -+#include "nss.h" -+#include "secport.h" -+#include "secpkcs5.h" -+#include "sechash.h" -+#include "certdb.h" -+#include "secmod.h" -+ -+#define PKCS12_IN_BUFFER_SIZE 200 -+ -+static char *progName; -+PRBool debug = PR_FALSE; -+ -+#define ERR_USAGE 2 -+#define ERR_PK11GETSLOT 13 -+ -+static void -+Usage() -+{ -+#define FPS PR_fprintf(PR_STDERR, -+ FPS "Usage: %s [-d certdir] [-P dbprefix] [-h tokenname]\n", -+ progName); -+ FPS "\t\t [-k slotpwfile | -K slotpw] [-v]\n"); -+ -+ exit(ERR_USAGE); -+} -+ -+typedef enum { -+ tagULong, -+ tagVersion, -+ tagUtf8 -+} tagType; -+ -+typedef struct { -+ const char *attributeName; -+ tagType attributeStorageType; -+} attributeTag; -+ -+enum { -+ opt_CertDir = 0, -+ opt_TokenName, -+ opt_SlotPWFile, -+ opt_SlotPW, -+ opt_DBPrefix, -+ opt_Debug -+}; -+ -+static secuCommandFlag validation_options[] = -+ { -+ { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_TokenName */ 'h', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_SlotPWFile */ 'k', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_SlotPW */ 'K', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_DBPrefix */ 'P', PR_TRUE, 0, PR_FALSE }, -+ { /* opt_Debug */ 'v', PR_FALSE, 0, PR_FALSE } -+ }; -+ -+void -+dump_Raw(char *label, CK_ATTRIBUTE *attr) -+{ -+ int i; -+ unsigned char *value = (unsigned char *)attr->pValue; -+ printf("0x"); -+ for (i = 0; i < attr->ulValueLen; i++) { -+ printf("%02x", value[i]); -+ } -+ printf("<%s>\n", label); -+} -+ -+SECStatus -+dump_validations(CK_OBJECT_CLASS objc, CK_ATTRIBUTE *template, int count, -+ attributeTag *tags, PK11SlotInfo *slot) -+{ -+ PK11GenericObject *objs, *obj; -+ -+ objs = PK11_FindGenericObjects(slot, objc); -+ -+ for (obj = objs; obj != NULL; obj = PK11_GetNextGenericObject(obj)) { -+ int i; -+ printf("Validation Object:\n"); -+ PK11_ReadRawAttributes(NULL, PK11_TypeGeneric, obj, template, count); -+ for (i = 0; i < count; i++) { -+ CK_ULONG ulong; -+ CK_VERSION version; -+ int len = template[i].ulValueLen; -+ printf(" %s: ", tags[i].attributeName); -+ if (len < 0) { -+ printf("\n"); -+ } else if (len == 0) { -+ printf("\n"); -+ } else -+ switch (tags[i].attributeStorageType) { -+ case tagULong: -+ if (len != sizeof(CK_ULONG)) { -+ dump_Raw("bad ulong", &template[i]); -+ break; -+ } -+ ulong = *(CK_ULONG *)template[i].pValue; -+ printf("%ld\n", ulong); -+ break; -+ case tagVersion: -+ if (len != sizeof(CK_VERSION)) { -+ dump_Raw("bad version", &template[i]); -+ break; -+ } -+ version = *(CK_VERSION *)template[i].pValue; -+ printf("%d.%d\n", version.major, version.minor); -+ break; -+ case tagUtf8: -+ printf("%.*s\n", len, (char *)template[i].pValue); -+ break; -+ default: -+ dump_Raw("unknown tag", &template[i]); -+ break; -+ } -+ PORT_Free(template[i].pValue); -+ template[i].pValue = NULL; -+ template[i].ulValueLen = 0; -+ } -+ } -+ PK11_DestroyGenericObjects(objs); -+ return SECSuccess; -+} -+ -+int -+main(int argc, char **argv) -+{ -+ secuPWData slotPw = { PW_NONE, NULL }; -+ secuPWData p12FilePw = { PW_NONE, NULL }; -+ PK11SlotInfo *slot; -+ char *slotname = NULL; -+ char *dbprefix = ""; -+ char *nssdir = NULL; -+ SECStatus rv; -+ secuCommand validation; -+ int local_errno = 0; -+ -+ CK_ATTRIBUTE validation_template[] = { -+ { CKA_NSS_VALIDATION_TYPE, NULL, 0 }, -+ { CKA_NSS_VALIDATION_VERSION, NULL, 0 }, -+ { CKA_NSS_VALIDATION_LEVEL, NULL, 0 }, -+ { CKA_NSS_VALIDATION_MODULE_ID, NULL, 0 } -+ }; -+ attributeTag validation_tags[] = { -+ { "Validation Type", tagULong }, -+ { "Validation Version", tagVersion }, -+ { "Validation Level", tagULong }, -+ { "Validation Module ID", tagUtf8 }, -+ }; -+ -+#ifdef _CRTDBG_MAP_ALLOC -+ _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); -+#endif -+ -+ validation.numCommands = 0; -+ validation.commands = 0; -+ validation.numOptions = PR_ARRAY_SIZE(validation_options); -+ validation.options = validation_options; -+ -+ progName = strrchr(argv[0], '/'); -+ progName = progName ? progName + 1 : argv[0]; -+ -+ rv = SECU_ParseCommandLine(argc, argv, progName, &validation); -+ -+ if (rv != SECSuccess) -+ Usage(); -+ -+ debug = validation.options[opt_Debug].activated; -+ -+ slotname = SECU_GetOptionArg(&validation, opt_TokenName); -+ -+ if (validation.options[opt_SlotPWFile].activated) { -+ slotPw.source = PW_FROMFILE; -+ slotPw.data = PORT_Strdup(validation.options[opt_SlotPWFile].arg); -+ } -+ -+ if (validation.options[opt_SlotPW].activated) { -+ slotPw.source = PW_PLAINTEXT; -+ slotPw.data = PORT_Strdup(validation.options[opt_SlotPW].arg); -+ } -+ -+ if (validation.options[opt_CertDir].activated) { -+ nssdir = validation.options[opt_CertDir].arg; -+ } -+ if (validation.options[opt_DBPrefix].activated) { -+ dbprefix = validation.options[opt_DBPrefix].arg; -+ } -+ -+ PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); -+ if (nssdir == NULL && NSS_NoDB_Init("") == SECSuccess) { -+ rv = SECSuccess; -+ /* if the system isn't already in FIPS mode, we need -+ * to switch to FIPS mode */ -+ if (!PK11_IsFIPS()) { -+ /* flip to FIPS mode */ -+ SECMODModule *module = SECMOD_GetInternalModule(); -+ rv = SECMOD_DeleteInternalModule(module->commonName); -+ } -+ } else { -+ rv = NSS_Initialize(nssdir, dbprefix, dbprefix, -+ "secmod.db", 0); -+ } -+ if (rv != SECSuccess) { -+ SECU_PrintPRandOSError(progName); -+ exit(-1); -+ } -+ -+ if (!slotname || PL_strcmp(slotname, "internal") == 0) -+ slot = PK11_GetInternalKeySlot(); -+ else -+ slot = PK11_FindSlotByName(slotname); -+ -+ if (!slot) { -+ SECU_PrintError(progName, "Invalid slot \"%s\"", slotname); -+ local_errno = ERR_PK11GETSLOT; -+ goto done; -+ } -+ -+ rv = dump_validations(CKO_NSS_VALIDATION, -+ validation_template, -+ PR_ARRAY_SIZE(validation_template), -+ validation_tags, -+ slot); -+ -+done: -+ if (slotPw.data != NULL) -+ PORT_ZFree(slotPw.data, PL_strlen(slotPw.data)); -+ if (p12FilePw.data != NULL) -+ PORT_ZFree(p12FilePw.data, PL_strlen(p12FilePw.data)); -+ if (slot) -+ PK11_FreeSlot(slot); -+ if (NSS_Shutdown() != SECSuccess) { -+ local_errno = 1; -+ } -+ PL_ArenaFinish(); -+ PR_Cleanup(); -+ return local_errno; -+} -diff --git a/cmd/validation/validation.gyp b/cmd/validation/validation.gyp -new file mode 100644 ---- /dev/null -+++ b/cmd/validation/validation.gyp -@@ -0,0 +1,30 @@ -+# 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': 'validation', -+ 'type': 'executable', -+ 'sources': [ -+ 'validation.c' -+ ], -+ 'dependencies': [ -+ '<(DEPTH)/exports.gyp:dbm_exports', -+ '<(DEPTH)/exports.gyp:nss_exports' -+ ] -+ } -+ ], -+ 'target_defaults': { -+ 'defines': [ -+ 'NSPR20' -+ ] -+ }, -+ 'variables': { -+ 'module': 'nss' -+ } -+} -diff --git a/lib/softoken/config.mk b/lib/softoken/config.mk ---- a/lib/softoken/config.mk -+++ b/lib/softoken/config.mk -@@ -59,3 +59,7 @@ - DEFINES += -DNSS_ENABLE_FIPS_INDICATORS - endif - -+ifdef NSS_FIPS_MODULE_ID -+DEFINES += -DNSS_FIPS_MODULE_ID=\"${NSS_FIPS_MODULE_ID}\" -+endif -+ -diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c ---- a/lib/softoken/pkcs11.c -+++ b/lib/softoken/pkcs11.c -@@ -75,7 +75,6 @@ - * failure so that there are at most 60 login attempts per minute. - */ - static PRIntervalTime loginWaitTime; --static PRUint32 minSessionObjectHandle = 1U; - - #define __PASTE(x, y) x##y - -@@ -1672,8 +1671,6 @@ - { - SFTKSlot *slot = session->slot; - SFTKAttribute *attribute; -- SFTKObject *duplicateObject = NULL; -- CK_OBJECT_HANDLE handle; - CK_BBOOL ckfalse = CK_FALSE; - CK_BBOOL cktrue = CK_TRUE; - CK_RV crv; -@@ -1711,30 +1708,13 @@ - * token objects and will have a token object handle assigned to - * them by a call to sftk_mkHandle in the handler for each object - * class, invoked below. -- * -+ * - * It may be helpful to note/remember that - * sftk_narrowToXxxObject uses sftk_isToken, - * sftk_isToken examines the sign bit of the object's handle, but - * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute. - */ -- do { -- PRUint32 wrappedAround; -- -- duplicateObject = NULL; -- PZ_Lock(slot->objectLock); -- wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK; -- handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK; -- if (!handle) /* don't allow zero handle */ -- handle = minSessionObjectHandle; -- slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround; -- /* Is there already a session object with this handle? */ -- if (wrappedAround) { -- sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable, -- slot->sessObjHashSize); -- } -- PZ_Unlock(slot->objectLock); -- } while (duplicateObject != NULL); -- object->handle = handle; -+ object->handle = sftk_getNextHandle(slot); - - /* get the object class */ - attribute = sftk_FindAttribute(object, CKA_CLASS); -@@ -2875,10 +2855,15 @@ - goto mem_loser; - - slot->sessionIDCount = 0; -- slot->sessionObjectHandleCount = minSessionObjectHandle; -+ slot->sessionObjectHandleCount = NSC_MIN_SESSION_OBJECT_HANDLE; - slot->slotID = slotID; - sftk_setStringName(params->slotdes ? params->slotdes : sftk_getDefSlotName(slotID), slot->slotDescription, - sizeof(slot->slotDescription), PR_TRUE); -+ crv = sftk_InitSession(&slot->moduleObjects, slot, slotID, NULL, NULL, -+ CKF_SERIAL_SESSION); -+ if (crv != CKR_OK) { -+ goto loser; -+ } - - /* call the reinit code to set everything that changes between token - * init calls */ -@@ -2887,6 +2872,12 @@ - if (crv != CKR_OK) { - goto loser; - } -+ if (sftk_isFIPS(slotID)) { -+ crv = sftk_CreateValidationObjects(slot); -+ if (crv != CKR_OK) { -+ goto loser; -+ } -+ } - crv = sftk_RegisterSlot(slot, moduleIndex); - if (crv != CKR_OK) { - goto loser; -@@ -3032,6 +3023,8 @@ - - SFTK_ShutdownSlot(slot); - -+ sftk_ClearSession(&slot->moduleObjects); -+ - if (slot->tokObjHashTable) { - PL_HashTableDestroy(slot->tokObjHashTable); - slot->tokObjHashTable = NULL; -@@ -3262,6 +3255,7 @@ - CK_RV crv = CKR_OK; - SECStatus rv; - CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *)pReserved; -+ PRBool destroy_freelist_on_error = PR_TRUE; - int i; - unsigned int moduleIndex = isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE; - -@@ -3341,7 +3335,14 @@ - "disabled FIPS mode"); - } - } -+ /* if we have a peer open, we don't want to destroy the freelist -+ * from under the peer if we fail, the free list will be -+ * destroyed in that case when the C_Finalize is called for -+ * the peer */ -+ destroy_freelist_on_error = PR_FALSE; - } -+ /* allow us to create objects in SFTK_SlotInit */ -+ sftk_InitFreeLists(); - - for (i = 0; i < paramStrings.token_count; i++) { - crv = SFTK_SlotInit(paramStrings.configdir, -@@ -3355,8 +3356,9 @@ - loser: - sftk_freeParams(¶mStrings); - } -- if (CKR_OK == crv) { -- sftk_InitFreeLists(); -+ if (destroy_freelist_on_error && (CKR_OK != crv)) { -+ /* idempotent. If the list are already freed, this is a noop */ -+ sftk_CleanupFreeLists(); - } - - #ifndef NO_FORK_CHECK -diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h ---- a/lib/softoken/pkcs11i.h -+++ b/lib/softoken/pkcs11i.h -@@ -49,6 +49,8 @@ - #define NSC_SEARCH_BLOCK_SIZE 5 - #define NSC_SLOT_LIST_BLOCK_SIZE 10 - -+#define NSC_MIN_SESSION_OBJECT_HANDLE 1U -+ - #define NSC_FIPS_MODULE 1 - #define NSC_NON_FIPS_MODULE 0 - -@@ -375,6 +377,9 @@ - char tokDescription[33]; /* per load */ - char updateTokDescription[33]; /* per load */ - char slotDescription[65]; /* invariant */ -+ SFTKSession moduleObjects; /* global session to hang module specific -+ * objects like profile objects or -+ * validation objects */ - }; - - /* -@@ -766,6 +771,7 @@ - extern void sftk_ReferenceObject(SFTKObject *object); - extern SFTKObject *sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, - SFTKSession *session); -+extern CK_OBJECT_HANDLE sftk_getNextHandle(SFTKSlot *slot); - extern void sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object); - extern void sftk_AddObject(SFTKSession *session, SFTKObject *object); - /* clear out all the existing object ID to database key mappings. -@@ -787,7 +793,11 @@ - extern CK_SLOT_ID sftk_SlotIDFromSessionHandle(CK_SESSION_HANDLE handle); - extern SFTKSession *sftk_SessionFromHandle(CK_SESSION_HANDLE handle); - extern void sftk_FreeSession(SFTKSession *session); -+extern void sftk_ClearSession(SFTKSession *session); - extern void sftk_DestroySession(SFTKSession *session); -+extern CK_RV sftk_InitSession(SFTKSession *session, SFTKSlot *slot, -+ CK_SLOT_ID slotID, CK_NOTIFY notify, -+ CK_VOID_PTR pApplication, CK_FLAGS flags); - extern SFTKSession *sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, - CK_VOID_PTR pApplication, CK_FLAGS flags); - extern void sftk_update_state(SFTKSlot *slot, SFTKSession *session); -@@ -955,6 +965,9 @@ - * FIPS security policy */ - PRBool sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, - CK_ATTRIBUTE_TYPE op, SFTKObject *source); -+/* add validation objects to the slot */ -+CK_RV sftk_CreateValidationObjects(SFTKSlot *slot); -+ - SEC_END_PROTOS - - #endif /* _PKCS11I_H_ */ -diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c ---- a/lib/softoken/pkcs11u.c -+++ b/lib/softoken/pkcs11u.c -@@ -14,6 +14,7 @@ - #include "sftkdb.h" - #include "softoken.h" - #include "secoid.h" -+#include "softkver.h" - - #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS) - /* this file should be supplied by the vendor and include all the -@@ -1243,6 +1244,32 @@ - return SFTK_Busy; - } - -+/* find the next available object handle that isn't currently in use */ -+CK_OBJECT_HANDLE -+sftk_getNextHandle(SFTKSlot *slot) -+{ -+ CK_OBJECT_HANDLE handle; -+ SFTKObject *duplicateObject = NULL; -+ do { -+ PRUint32 wrappedAround; -+ -+ duplicateObject = NULL; -+ PZ_Lock(slot->objectLock); -+ wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK; -+ handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK; -+ if (!handle) /* don't allow zero handle */ -+ handle = NSC_MIN_SESSION_OBJECT_HANDLE; -+ slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround; -+ /* Is there already a session object with this handle? */ -+ if (wrappedAround) { -+ sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable, -+ slot->sessObjHashSize); -+ } -+ PZ_Unlock(slot->objectLock); -+ } while (duplicateObject != NULL); -+ return handle; -+} -+ - /* - * add an object to a slot and session queue. These two functions - * adopt the object. -@@ -1848,23 +1875,13 @@ - } - - /* -- * create a new nession. NOTE: The session handle is not set, and the -+ * Init a new session. NOTE: The session handle is not set, and the - * session is not added to the slot's session queue. - */ --SFTKSession * --sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, -- CK_FLAGS flags) -+CK_RV -+sftk_InitSession(SFTKSession *session, SFTKSlot *slot, CK_SLOT_ID slotID, -+ CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags) - { -- SFTKSession *session; -- SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); -- -- if (slot == NULL) -- return NULL; -- -- session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession)); -- if (session == NULL) -- return NULL; -- - session->next = session->prev = NULL; - session->enc_context = NULL; - session->hash_context = NULL; -@@ -1873,8 +1890,7 @@ - session->objectIDCount = 1; - session->objectLock = PZ_NewLock(nssILockObject); - if (session->objectLock == NULL) { -- PORT_Free(session); -- return NULL; -+ return CKR_HOST_MEMORY; - } - session->objects[0] = NULL; - -@@ -1887,12 +1903,38 @@ - sftk_update_state(slot, session); - /* no ops completed yet, so the last one couldn't be a FIPS op */ - session->lastOpWasFIPS = PR_FALSE; -+ return CKR_OK; -+} -+ -+/* -+ * Create a new session and init it. -+ */ -+SFTKSession * -+sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication, -+ CK_FLAGS flags) -+{ -+ SFTKSession *session; -+ SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE); -+ CK_RV crv; -+ -+ if (slot == NULL) -+ return NULL; -+ -+ session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession)); -+ if (session == NULL) -+ return NULL; -+ -+ crv = sftk_InitSession(session, slot, slotID, notify, pApplication, flags); -+ if (crv != CKR_OK) { -+ PORT_Free(session); -+ return NULL; -+ } - return session; - } - - /* free all the data associated with a session. */ - void --sftk_DestroySession(SFTKSession *session) -+sftk_ClearSession(SFTKSession *session) - { - SFTKObjectList *op, *next; - -@@ -1918,6 +1960,13 @@ - if (session->search) { - sftk_FreeSearch(session->search); - } -+} -+ -+/* free the data associated with the session, and the session */ -+void -+sftk_DestroySession(SFTKSession *session) -+{ -+ sftk_ClearSession(session); - PORT_Free(session); - } - -@@ -2386,3 +2435,70 @@ - return PR_FALSE; - #endif - } -+ -+/* -+ * create the FIPS Validation objects. If the vendor -+ * doesn't supply an NSS_FIPS_MODULE_ID, at compile time, -+ * then we assumethis is an unvalidated module. -+ */ -+CK_RV -+sftk_CreateValidationObjects(SFTKSlot *slot) -+{ -+ const char *module_id; -+ int module_id_len; -+ CK_RV crv = CKR_OK; -+ /* we currently use vendor specific values until the validation -+ * objects are approved for PKCS #11 v3.2. */ -+ CK_OBJECT_CLASS cko_validation = CKO_NSS_VALIDATION; -+ CK_NSS_VALIDATION_TYPE ckv_fips = CKV_NSS_FIPS_140; -+ CK_VERSION fips_version = { 3, 0 }; /* FIPS-140-3 */ -+ CK_ULONG fips_level = 1; /* or 2 if you validated at level 2 */ -+ -+#ifndef NSS_FIPS_MODULE_ID -+#define NSS_FIPS_MODULE_ID "Generic NSS " SOFTOKEN_VERSION " Unvalidated" -+#endif -+ module_id = NSS_FIPS_MODULE_ID; -+ module_id_len = sizeof(NSS_FIPS_MODULE_ID) - 1; -+ SFTKObject *object; -+ -+ object = sftk_NewObject(slot); /* fill in the handle later */ -+ if (object == NULL) { -+ return CKR_HOST_MEMORY; -+ } -+ object->isFIPS = PR_FALSE; -+ -+ crv = sftk_AddAttributeType(object, CKA_CLASS, -+ &cko_validation, sizeof(cko_validation)); -+ if (crv != CKR_OK) { -+ goto loser; -+ } -+ crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_TYPE, -+ &ckv_fips, sizeof(ckv_fips)); -+ if (crv != CKR_OK) { -+ goto loser; -+ } -+ crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_VERSION, -+ &fips_version, sizeof(fips_version)); -+ if (crv != CKR_OK) { -+ goto loser; -+ } -+ crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_LEVEL, -+ &fips_level, sizeof(fips_level)); -+ if (crv != CKR_OK) { -+ goto loser; -+ } -+ crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_MODULE_ID, -+ module_id, module_id_len); -+ if (crv != CKR_OK) { -+ goto loser; -+ } -+ -+ /* future, fill in validation certificate information from a supplied -+ * pointer to a config file */ -+ object->handle = sftk_getNextHandle(slot); -+ object->slot = slot; -+ sftk_AddObject(&slot->moduleObjects, object); -+loser: -+ sftk_FreeObject(object); -+ return crv; -+} -diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h ---- a/lib/util/pkcs11n.h -+++ b/lib/util/pkcs11n.h -@@ -38,6 +38,9 @@ - #define CKO_NSS_BUILTIN_ROOT_LIST (CKO_NSS + 4) - #define CKO_NSS_NEWSLOT (CKO_NSS + 5) - #define CKO_NSS_DELSLOT (CKO_NSS + 6) -+#define CKO_NSS_VALIDATION (CKO_NSS + 7) -+ -+#define CKV_NSS_FIPS_140 (CKO_NSS + 1) - - /* - * NSS-defined key types -@@ -99,6 +102,11 @@ - #define CKA_NSS_SERVER_DISTRUST_AFTER (CKA_NSS + 35) - #define CKA_NSS_EMAIL_DISTRUST_AFTER (CKA_NSS + 36) - -+#define CKA_NSS_VALIDATION_TYPE (CKA_NSS + 36) -+#define CKA_NSS_VALIDATION_VERSION (CKA_NSS + 37) -+#define CKA_NSS_VALIDATION_LEVEL (CKA_NSS + 38) -+#define CKA_NSS_VALIDATION_MODULE_ID (CKA_NSS + 39) -+ - /* - * Trust attributes: - * -@@ -344,6 +352,9 @@ - #define CKR_NSS_CERTDB_FAILED (CKR_NSS + 1) - #define CKR_NSS_KEYDB_FAILED (CKR_NSS + 2) - -+/* NSS specific types */ -+typedef CK_ULONG CK_NSS_VALIDATION_TYPE; -+ - /* Mandatory parameter for the CKM_NSS_HKDF_* key deriviation mechanisms. - See RFC 5869. - -diff --git a/nss.gyp b/nss.gyp ---- a/nss.gyp -+++ b/nss.gyp -@@ -131,6 +131,7 @@ - 'cmd/smimetools/smimetools.gyp:cmsutil', - 'cmd/ssltap/ssltap.gyp:ssltap', - 'cmd/symkeyutil/symkeyutil.gyp:symkeyutil', -+ 'cmd/validation/validation.gyp:validation', - 'nss-tool/nss_tool.gyp:nss', - 'nss-tool/nss_tool.gyp:hw-support', - ], - diff --git a/SOURCES/nss-3.71-ipv6-fix.patch b/SOURCES/nss-3.71-ipv6-fix.patch deleted file mode 100644 index b72c80f..0000000 --- a/SOURCES/nss-3.71-ipv6-fix.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff -up ./cmd/selfserv/selfserv.c.ipv6_fix ./cmd/selfserv/selfserv.c ---- ./cmd/selfserv/selfserv.c.ipv6_fix 2021-09-14 11:40:06.176408531 -0700 -+++ ./cmd/selfserv/selfserv.c 2021-09-14 11:49:46.361907308 -0700 -@@ -1717,14 +1717,28 @@ getBoundListenSocket(unsigned short port - 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"); - } -+ /* NSPR has a bug where set inheritable doesn't work unless it's a pure -+ * NSPR socket. If we have an IPV6 emulator on an IPV4 socket, it will fail. -+ * In that case just open an IPV4 socket instead */ -+ if (PR_NSPR_IO_LAYER != PR_GetLayersIdentity(listen_sock)) { -+ PR_Close(listen_sock); -+ addr.inet.family = PR_AF_INET; -+ addr.inet.ip = PR_INADDR_ANY; -+ addr.inet.port = PR_htons(port); -+ -+ listen_sock = PR_NewTCPSocket(); -+ if (listen_sock == NULL) { -+ errExit("PR_NewTCPSocket"); -+ } -+ } - - opt.option = PR_SockOpt_Nonblocking; - opt.value.non_blocking = PR_FALSE; diff --git a/SOURCES/nss-3.75-fix-pkcs12-passwords.patch b/SOURCES/nss-3.75-fix-pkcs12-passwords.patch deleted file mode 100644 index fffe693..0000000 --- a/SOURCES/nss-3.75-fix-pkcs12-passwords.patch +++ /dev/null @@ -1,257 +0,0 @@ -diff --git a/cmd/pk12util/pk12util.c b/cmd/pk12util/pk12util.c ---- a/cmd/pk12util/pk12util.c -+++ b/cmd/pk12util/pk12util.c -@@ -660,16 +660,27 @@ P12U_ExportPKCS12Object(char *nn, char * - } - - /* Password to use for PKCS12 file. */ - pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw); - if (!pwitem) { - goto loser; - } - -+ /* we are passing UTF8, drop the NULL in the normal password value. -+ * UCS2 conversion will add it back if necessary. This only affects -+ * password > Blocksize of the Hash function and pkcs5v2 pbe (if password -+ * <=Blocksize then the password is zero padded anyway, so an extra NULL -+ * at the end has not effect). This is allows us to work with openssl and -+ * gnutls. Older versions of NSS already fail to decrypt long passwords -+ * in this case, so we aren't breaking anyone with this code */ -+ if ((pwitem->len > 1) && (!pwitem->data[pwitem->len-1])) { -+ pwitem->len--; -+ } -+ - p12cxt = p12u_InitContext(PR_FALSE, outfile); - if (!p12cxt) { - SECU_PrintError(progName, "Initialization failed: %s", outfile); - pk12uErrno = PK12UERR_INIT_FILE; - goto loser; - } - - if (certlist) { -diff --git a/lib/pkcs12/p12local.c b/lib/pkcs12/p12local.c ---- a/lib/pkcs12/p12local.c -+++ b/lib/pkcs12/p12local.c -@@ -903,31 +903,35 @@ sec_pkcs12_find_object(SEC_PKCS12SafeCon - i++; - } - } - - PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME); - return NULL; - } - --/* this function converts a password to unicode and encures that the -- * required double 0 byte be placed at the end of the string -+/* this function converts a password to unicode and ensures that the -+ * required double 0 byte be placed at the end of the string (if zeroTerm -+ * is set), or the 0 bytes at the end are dropped (if zeroTerm is not set). - */ - PRBool - sec_pkcs12_convert_item_to_unicode(PLArenaPool *arena, SECItem *dest, - SECItem *src, PRBool zeroTerm, - PRBool asciiConvert, PRBool toUnicode) - { - PRBool success = PR_FALSE; -+ int bufferSize; -+ - if (!src || !dest) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return PR_FALSE; - } - -- dest->len = src->len * 3 + 2; -+ bufferSize = src->len * 3 + 2; -+ dest->len = bufferSize; - if (arena) { - dest->data = (unsigned char *)PORT_ArenaZAlloc(arena, dest->len); - } else { - dest->data = (unsigned char *)PORT_ZAlloc(dest->len); - } - - if (!dest->data) { - dest->len = 0; -@@ -951,34 +955,44 @@ sec_pkcs12_convert_item_to_unicode(PLAre - if (!arena) { - PORT_Free(dest->data); - dest->data = NULL; - dest->len = 0; - } - return PR_FALSE; - } - -- if ((dest->len >= 2) && -- (dest->data[dest->len - 1] || dest->data[dest->len - 2]) && zeroTerm) { -- if (dest->len + 2 > 3 * src->len) { -- if (arena) { -- dest->data = (unsigned char *)PORT_ArenaGrow(arena, -- dest->data, dest->len, -- dest->len + 2); -- } else { -- dest->data = (unsigned char *)PORT_Realloc(dest->data, -- dest->len + 2); -+ /* in some cases we need to add NULL terminations and in others -+ * we need to drop null terminations */ -+ if (zeroTerm) { -+ /* unicode adds two nulls a the end */ -+ if (toUnicode) { -+ 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; - } -- -- if (!dest->data) { -- return PR_FALSE; -+ /* ascii/utf-8 adds just 1 */ -+ } else if ((dest->len >= 1) && dest->data[dest->len-1]) { -+ PORT_Assert(dest->len + 1 <= bufferSize); -+ dest->len ++; -+ dest->data[dest->len-1] = 0; -+ } -+ } else { -+ /* handle the drop case, no need to do any allocations here. */ -+ if (toUnicode) { -+ while ((dest->len >=2) && !dest->data[dest->len - 1] && -+ !dest->data[dest->len - 2]) { -+ dest->len -= 2; - } -+ } else while (dest->len && !dest->data[dest->len-1]) { -+ dest->len--; - } -- dest->len += 2; -- dest->data[dest->len - 1] = dest->data[dest->len - 2] = 0; - } - - return PR_TRUE; - } - - PRBool - sec_pkcs12_is_pkcs12_pbe_algorithm(SECOidTag algorithm) - { -@@ -1006,27 +1020,28 @@ sec_pkcs12_is_pkcs12_pbe_algorithm(SECOi - } - } - - /* this function decodes a password from Unicode if necessary, - * according to the PBE algorithm. - * - * we assume that the pwitem is already encoded in Unicode by the - * caller. if the encryption scheme is not the one defined in PKCS -- * #12, decode the pwitem back into UTF-8. */ -+ * #12, decode the pwitem back into UTF-8. NOTE: UTF-8 strings are -+ * used in the PRF without the trailing NULL */ - PRBool - sec_pkcs12_decode_password(PLArenaPool *arena, - SECItem *result, - SECOidTag algorithm, - const SECItem *pwitem) - { - if (!sec_pkcs12_is_pkcs12_pbe_algorithm(algorithm)) - return sec_pkcs12_convert_item_to_unicode(arena, result, - (SECItem *)pwitem, -- PR_TRUE, PR_FALSE, PR_FALSE); -+ PR_FALSE, PR_FALSE, PR_FALSE); - - return SECITEM_CopyItem(arena, result, pwitem) == SECSuccess; - } - - /* this function encodes a password into Unicode if necessary, - * according to the PBE algorithm. - * - * we assume that the pwitem holds a raw password. if the encryption -diff --git a/tests/common/init.sh b/tests/common/init.sh ---- a/tests/common/init.sh -+++ b/tests/common/init.sh -@@ -78,25 +78,27 @@ if [ -z "${INIT_SOURCED}" -o "${INIT_SOU - - CERT_EXTENSIONS_DIR=${HOSTDIR}/cert_extensions - STAPLINGDIR=${HOSTDIR}/stapling - NOLOGINDIR=${HOSTDIR}/nologin - SSLGTESTDIR=${HOSTDIR}/ssl_gtests - GTESTDIR=${HOSTDIR}/gtests - - PWFILE=${HOSTDIR}/tests.pw -+ LONGPWFILE=${HOSTDIR}/tests.longpw - EMPTY_FILE=${HOSTDIR}/tests_empty - NOISE_FILE=${HOSTDIR}/tests_noise - CORELIST_FILE=${HOSTDIR}/clist - - FIPSPWFILE=${HOSTDIR}/tests.fipspw - FIPSBADPWFILE=${HOSTDIR}/tests.fipsbadpw - FIPSP12PWFILE=${HOSTDIR}/tests.fipsp12pw - - echo nss > ${PWFILE} -+ echo "nss123456789012345678901234567890123456789012345678901234567890_" > ${LONGPWFILE} - echo > ${EMPTY_FILE} - echo "fIps140" > ${FIPSPWFILE} - echo "fips104" > ${FIPSBADPWFILE} - echo "pKcs12fips140" > ${FIPSP12PWFILE} - - noise - - P_SERVER_CADIR=${SERVER_CADIR} -@@ -656,16 +658,17 @@ if [ -z "${INIT_SOURCED}" -o "${INIT_SOU - P_R_NOLOGINDIR="multiaccess:${D_NOLOGIN}" - P_R_EXT_SERVERDIR="multiaccess:${D_EXT_SERVER}" - P_R_EXT_CLIENTDIR="multiaccess:${D_EXT_CLIENT}" - P_R_IMPLICIT_INIT_DIR="multiaccess:${D_IMPLICIT_INIT}" - P_R_RSAPSSDIR="multiaccess:${D_RSAPSS}" - fi - - R_PWFILE=../tests.pw -+ R_LONGPWFILE=../tests.longpw - R_EMPTY_FILE=../tests_empty - R_NOISE_FILE=../tests_noise - - R_FIPSPWFILE=../tests.fipspw - R_FIPSBADPWFILE=../tests.fipsbadpw - R_FIPSP12PWFILE=../tests.fipsp12pw - - trap "Exit $0 Signal_caught" 2 3 -diff --git a/tests/tools/tools.sh b/tests/tools/tools.sh ---- a/tests/tools/tools.sh -+++ b/tests/tools/tools.sh -@@ -382,16 +382,40 @@ tools_p12_export_list_import_with_defaul - check_tmpfile - - echo "$SCRIPTNAME: Listing Alice's pk12 EC file -----------------" - echo "pk12util -l Alice-ec.p12 -w ${R_PWFILE}" - ${BINDIR}/pk12util -l Alice-ec.p12 -w ${R_PWFILE} 2>&1 - ret=$? - html_msg $ret 0 "Listing Alice's pk12 EC file (pk12util -l)" - check_tmpfile -+ -+ echo "$SCRIPTNAME: Exporting Alice's email EC cert & key with long pw------" -+ echo "pk12util -o Alice-ec-long.p12 -n \"Alice-ec\" -d ${P_R_ALICEDIR} -k ${R_PWFILE} \\" -+ echo " -w ${R_LONGPWFILE}" -+ ${BINDIR}/pk12util -o Alice-ec-long.p12 -n "Alice-ec" -d ${P_R_ALICEDIR} -k ${R_PWFILE} \ -+ -w ${R_LONGPWFILE} 2>&1 -+ ret=$? -+ html_msg $ret 0 "Exporting Alice's email EC cert & key with long pw (pk12util -o)" -+ check_tmpfile -+ verify_p12 Alice-ec-long.p12 "default" "default" "default" -+ -+ echo "$SCRIPTNAME: Importing Alice's email EC cert & key with long pw-----" -+ echo "pk12util -i Alice-ec-long.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_LONGPWFILE}" -+ ${BINDIR}/pk12util -i Alice-ec-long.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_LONGPWFILE} 2>&1 -+ ret=$? -+ html_msg $ret 0 "Importing Alice's email EC cert & key with long pw (pk12util -i)" -+ check_tmpfile -+ -+ echo "$SCRIPTNAME: Listing Alice's pk12 EC file with long pw ------------" -+ echo "pk12util -l Alice-ec-long.p12 -w ${R_LONGPWFILE}" -+ ${BINDIR}/pk12util -l Alice-ec-long.p12 -w ${R_LONGPWFILE} 2>&1 -+ ret=$? -+ html_msg $ret 0 "Listing Alice's pk12 EC file with long pw (pk12util -l)" -+ check_tmpfile - } - - tools_p12_import_old_files() - { - echo "$SCRIPTNAME: Importing PKCS#12 files created with older NSS --------------" - echo "pk12util -i TestOldCA.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_PWFILE}" - ${BINDIR}/pk12util -i ${TOOLSDIR}/data/TestOldCA.p12 -d ${P_R_COPYDIR} -k ${R_PWFILE} -w ${R_PWFILE} 2>&1 - ret=$? diff --git a/SOURCES/nss-3.79-dbtool.patch b/SOURCES/nss-3.79-dbtool.patch new file mode 100644 index 0000000..b61942b --- /dev/null +++ b/SOURCES/nss-3.79-dbtool.patch @@ -0,0 +1,3411 @@ +diff --git a/cmd/dbtool/Makefile b/cmd/dbtool/Makefile +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/Makefile +@@ -0,0 +1,46 @@ ++#! gmake ++# ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this ++# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++####################################################################### ++# (1) Include initial platform-independent assignments (MANDATORY). # ++####################################################################### ++ ++include manifest.mn ++ ++####################################################################### ++# (2) Include "global" configuration information. (OPTIONAL) # ++####################################################################### ++ ++include $(CORE_DEPTH)/coreconf/config.mk ++ ++####################################################################### ++# (3) Include "component" configuration information. (OPTIONAL) # ++####################################################################### ++ ++####################################################################### ++# (4) Include "local" platform-dependent assignments (OPTIONAL). # ++####################################################################### ++ ++include ../platlibs.mk ++ ++####################################################################### ++# (5) Execute "global" rules. (OPTIONAL) # ++####################################################################### ++ ++include $(CORE_DEPTH)/coreconf/rules.mk ++ ++####################################################################### ++# (6) Execute "component" rules. (OPTIONAL) # ++####################################################################### ++ ++#include ../platlibs.mk ++ ++####################################################################### ++# (7) Execute "local" rules. (OPTIONAL). # ++####################################################################### ++ ++include ../platrules.mk ++ +diff --git a/cmd/dbtool/dbtool.c b/cmd/dbtool/dbtool.c +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/dbtool.c +@@ -0,0 +1,806 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++ ++/* ++** dbtool.c ++** ++** tool to dump the underlying encoding of a database. This tool duplicates ++** some private functions in softoken. It uses libsec and libutil, but no ++** other portions of NSS. It currently only works on sqlite databases. For ++** an even more primitive dump, use sqlite3 on the individual files. ++** ++** TODO: dump the meta data for the databases. ++** optionally dump more PKCS5 information (KDF/salt/iterations) ++** take a password and decode encrypted attributes/verify signed ++** attributes. ++*/ ++#include ++#include ++ ++#if defined(WIN32) ++#include "fcntl.h" ++#include "io.h" ++#endif ++ ++#include "secutil.h" ++#include "pk11pub.h" ++ ++#if defined(XP_UNIX) ++#include ++#endif ++ ++#include "nspr.h" ++#include "prtypes.h" ++#include "certdb.h" ++#include "nss.h" ++#include "../modutil/modutil.h" ++#include "pk11table.h" ++#include "sftkdbt.h" ++#include "sdb.h" ++#include "secoid.h" ++ ++#include "plgetopt.h" ++ ++static char *progName; ++ ++char *dbDir = NULL; ++ ++static void ++Usage() ++{ ++ printf("Usage: %s [-c certprefix] [-k keyprefix] " ++ "[-V certversion] [-v keyversion]\n" ++ " [-d dbdir]\n", ++ progName); ++ printf("%-20s Directory with cert database (default is .)\n", ++ "-d certdir"); ++ printf("%-20s prefix for the cert database (default is \"\")\n", ++ "-c certprefix"); ++ printf("%-20s prefix for the key database (default is \"\")\n", ++ "-k keyprefix"); ++ printf("%-20s version of the cert database (default is 9)\n", ++ "-V certversion"); ++ printf("%-20s version of the key database (default is 4)\n", ++ "-v keyversion"); ++ exit(1); ++} ++#define SFTK_KEYDB_TYPE 0x40000000 ++#define SFTK_TOKEN_TYPE 0x80000000 ++ ++/* ++ * known attributes ++ */ ++static const CK_ATTRIBUTE_TYPE known_attributes[] = { ++ CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, ++ CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, ++ CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, ++ CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, ++ CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, ++ CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, ++ CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, ++ CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, ++ CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, ++ CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, ++ CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, ++ CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, ++ CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, ++ CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, ++ CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, ++ CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, ++ CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, ++ CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, ++ CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, ++ CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, ++ CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, ++ CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL, ++ CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, ++ CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, ++ CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, ++ CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, ++ CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, ++ CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, ++ CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, ++ CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, ++ CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, ++ CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, ++ CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, ++ CKA_NSS_DB, CKA_NSS_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS, ++ CKA_PUBLIC_KEY_INFO ++}; ++ ++static unsigned int known_attributes_size = sizeof(known_attributes) / ++ sizeof(known_attributes[0]); ++ ++PRBool ++isULONGAttribute(CK_ATTRIBUTE_TYPE type) ++{ ++ switch (type) { ++ case CKA_CERTIFICATE_CATEGORY: ++ case CKA_CERTIFICATE_TYPE: ++ case CKA_CLASS: ++ case CKA_JAVA_MIDP_SECURITY_DOMAIN: ++ case CKA_KEY_GEN_MECHANISM: ++ case CKA_KEY_TYPE: ++ case CKA_MECHANISM_TYPE: ++ case CKA_MODULUS_BITS: ++ case CKA_PRIME_BITS: ++ case CKA_SUBPRIME_BITS: ++ case CKA_VALUE_BITS: ++ case CKA_VALUE_LEN: ++ ++ case CKA_TRUST_DIGITAL_SIGNATURE: ++ case CKA_TRUST_NON_REPUDIATION: ++ case CKA_TRUST_KEY_ENCIPHERMENT: ++ case CKA_TRUST_DATA_ENCIPHERMENT: ++ case CKA_TRUST_KEY_AGREEMENT: ++ case CKA_TRUST_KEY_CERT_SIGN: ++ case CKA_TRUST_CRL_SIGN: ++ ++ case CKA_TRUST_SERVER_AUTH: ++ case CKA_TRUST_CLIENT_AUTH: ++ case CKA_TRUST_CODE_SIGNING: ++ case CKA_TRUST_EMAIL_PROTECTION: ++ case CKA_TRUST_IPSEC_END_SYSTEM: ++ case CKA_TRUST_IPSEC_TUNNEL: ++ case CKA_TRUST_IPSEC_USER: ++ case CKA_TRUST_TIME_STAMPING: ++ case CKA_TRUST_STEP_UP_APPROVED: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++/* are the attributes private? */ ++static PRBool ++isPrivateAttribute(CK_ATTRIBUTE_TYPE type) ++{ ++ switch (type) { ++ case CKA_VALUE: ++ case CKA_PRIVATE_EXPONENT: ++ case CKA_PRIME_1: ++ case CKA_PRIME_2: ++ case CKA_EXPONENT_1: ++ case CKA_EXPONENT_2: ++ case CKA_COEFFICIENT: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++/* These attributes must be authenticated with an hmac. */ ++static PRBool ++isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) ++{ ++ switch (type) { ++ case CKA_MODULUS: ++ case CKA_PUBLIC_EXPONENT: ++ case CKA_CERT_SHA1_HASH: ++ case CKA_CERT_MD5_HASH: ++ case CKA_TRUST_SERVER_AUTH: ++ case CKA_TRUST_CLIENT_AUTH: ++ case CKA_TRUST_EMAIL_PROTECTION: ++ case CKA_TRUST_CODE_SIGNING: ++ case CKA_TRUST_STEP_UP_APPROVED: ++ case CKA_NSS_OVERRIDE_EXTENSIONS: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++/* ++ * convert a database ulong back to a native ULONG. (reverse of the above ++ * function. ++ */ ++static CK_ULONG ++sdbULong2ULong(unsigned char *data) ++{ ++ int i; ++ CK_ULONG value = 0; ++ ++ for (i = 0; i < SDB_ULONG_SIZE; i++) { ++ value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) ++ * PR_BITS_PER_BYTE); ++ } ++ return value; ++} ++ ++/* PBE defines and functions */ ++ ++typedef struct EncryptedDataInfoStr { ++ SECAlgorithmID algorithm; ++ SECItem encryptedData; ++} EncryptedDataInfo; ++ ++static const SEC_ASN1Template encryptedDataInfoTemplate[] = { ++ { SEC_ASN1_SEQUENCE, ++ 0, NULL, sizeof(EncryptedDataInfo) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(EncryptedDataInfo, algorithm), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { SEC_ASN1_OCTET_STRING, ++ offsetof(EncryptedDataInfo, encryptedData) }, ++ { 0 } ++}; ++ ++typedef struct PBEParameterStr { ++ SECAlgorithmID prfAlg; ++ SECItem salt; ++ SECItem iteration; ++ SECItem keyLength; ++} PBEParameter; ++ ++static const SEC_ASN1Template pkcs5V1PBEParameterTemplate[] = ++ { ++ { SEC_ASN1_SEQUENCE, ++ 0, NULL, sizeof(PBEParameter) }, ++ { SEC_ASN1_OCTET_STRING, ++ offsetof(PBEParameter, salt) }, ++ { SEC_ASN1_INTEGER, ++ offsetof(PBEParameter, iteration) }, ++ { 0 } ++ }; ++ ++static const SEC_ASN1Template pkcs12V2PBEParameterTemplate[] = ++ { ++ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, ++ { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, ++ { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, ++ { 0 } ++ }; ++ ++ ++static const SEC_ASN1Template pkcs5V2PBEParameterTemplate[] = ++ { ++ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, ++ /* this is really a choice, but since we don't understand any other ++ * choice, just inline it. */ ++ { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, ++ { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, ++ { SEC_ASN1_INTEGER, offsetof(PBEParameter, keyLength) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(PBEParameter, prfAlg), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { 0 } ++ }; ++ ++typedef struct Pkcs5v2PBEParameterStr { ++ SECAlgorithmID keyParams; /* parameters of the key generation */ ++ SECAlgorithmID algParams; /* parameters for the encryption or mac op */ ++} Pkcs5v2PBEParameter; ++ ++static const SEC_ASN1Template pkcs5v2PBES2ParameterTemplate[] = { ++ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(Pkcs5v2PBEParameter) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(Pkcs5v2PBEParameter, keyParams), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { SEC_ASN1_INLINE | SEC_ASN1_XTRN, ++ offsetof(Pkcs5v2PBEParameter, algParams), ++ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, ++ { 0 } ++}; ++ ++static inline PRBool ++isPKCS12PBE(SECOidTag alg) { ++ switch (alg) { ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: ++ case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: ++ return PR_TRUE; ++ default: ++ break; ++ } ++ return PR_FALSE; ++} ++ ++ ++/* helper functions */ ++ ++/* output an NSS specific attribute or name that wasn't found in our ++ * pkcs #11 table */ ++const char * ++makeNSSVendorName(CK_ATTRIBUTE_TYPE attribute, const char *nameType) ++{ ++ static char nss_name[256]; ++ const char *name = NULL; ++ if ((attribute >= CKA_NSS) && (attribute <= 0xffffffff)) { ++ sprintf(nss_name,"%s+%d", nameType, (int)(attribute-CKA_NSS)); ++ name = nss_name; ++ } ++ return name; ++} ++ ++/* turn and attribute into a name */ ++const char * ++AttributeName(CK_ATTRIBUTE_TYPE attribute) ++{ ++ const char *name = getNameFromAttribute(attribute); ++ if (!name) { ++ name = makeNSSVendorName(attribute, "CKA_NSS"); ++ } ++ ++ return name ? name : "UNKNOWN_ATTRIBUTE_TYPE"; ++} ++ ++/* turn and error code into a name */ ++const char * ++ErrorName(CK_RV crv) ++{ ++ const char *error = getName(crv, ConstResult); ++ if (!error) { ++ error = makeNSSVendorName(crv, "CKR_NSS"); ++ } ++ return error ? error : "UNKNOWN_ERROR"; ++} ++ ++/* turn an oud tag into a string */ ++const char * ++oid2string(SECOidTag alg) ++{ ++ const char *oidstring = SECOID_FindOIDTagDescription(alg); ++ const char *def="Invalid oid tag"; /* future build a dotted oid string value here */ ++ return oidstring ? oidstring : def; ++} ++ ++/* dump an arbitary data blob. Dump it has hex with ascii on the side */ ++#define ASCCHAR(val) ((val) >= ' ' && (val) <= 0x7e ? (val) : '.') ++#define LINE_LENGTH 16 ++void ++dumpValue(const unsigned char *v, int len) ++{ ++ int i, next = 0; ++ char string[LINE_LENGTH+1]; ++ char space[LINE_LENGTH*2+1]; ++ char *nl = ""; ++ char *sp = ""; ++ PORT_Memset(string, 0, sizeof(string)); ++ ++ for (i=0; i < len; i++) { ++ if ((i % LINE_LENGTH) == 0) { ++ printf("%s%s%s ", sp, string, nl); ++ PORT_Memset(string, 0, sizeof(string)); ++ next = 0; ++ nl = "\n"; ++ sp = " "; ++ } ++ printf("%02x", v[i]); ++ string[next++] = ASCCHAR(v[i]); ++ } ++ PORT_Memset(space, 0, sizeof(space)); ++ i = LINE_LENGTH - (len % LINE_LENGTH); ++ if (i != LINE_LENGTH) { ++ int j; ++ for (j=0 ; j < i; j++) { ++ space[j*2] = ' '; ++ space[j*2+1] = ' '; ++ } ++ } ++ printf("%s%s%s%s", space, sp, string, nl); ++} ++ ++/* dump a PKCS5/12 PBE blob */ ++void ++dumpPKCS(unsigned char *val, CK_ULONG len, PRBool *hasSig) ++{ ++ EncryptedDataInfo edi; ++ SECStatus rv; ++ SECItem data; ++ PLArenaPool *arena; ++ SECOidTag alg, prfAlg; ++ PBEParameter pbeParam; ++ unsigned char zero = 0; ++ const SEC_ASN1Template *template = pkcs5V1PBEParameterTemplate; ++ int iter, keyLen, i; ++ ++ if (hasSig) { *hasSig = PR_FALSE; } ++ ++ ++ data.data = val; ++ data.len = len; ++ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); ++ if (arena == NULL) { ++ printf("Couldn't allocate arena\n"); ++ return; ++ } ++ ++ /* initialize default values */ ++ PORT_Memset(&pbeParam, 0, sizeof(pbeParam)); ++ pbeParam.keyLength.data = &zero; ++ pbeParam.keyLength.len = sizeof(zero); ++ SECOID_SetAlgorithmID(arena, &pbeParam.prfAlg, SEC_OID_SHA1, NULL); ++ ++ /* first crack the encrypted data from the PBE algorithm ID */ ++ rv = SEC_QuickDERDecodeItem(arena, &edi, encryptedDataInfoTemplate, &data); ++ if (rv != SECSuccess) { ++ printf("Encrypted Data, failed to decode\n"); ++ dumpValue(val,len); ++ PORT_FreeArena(arena, PR_FALSE); ++ return; ++ } ++ /* now use the pbe secalg to dump info on the pbe */ ++ alg = SECOID_GetAlgorithmTag(&edi.algorithm); ++ if ((alg == SEC_OID_PKCS5_PBES2) || (alg == SEC_OID_PKCS5_PBMAC1)){ ++ Pkcs5v2PBEParameter param; ++ SECOidTag palg; ++ const char *typeName = (alg == SEC_OID_PKCS5_PBES2) ? ++ "Encrypted Data PBES2" : ++ "Mac Data PBMAC1"; ++ ++ rv = SEC_QuickDERDecodeItem(arena, ¶m, ++ pkcs5v2PBES2ParameterTemplate, ++ &edi.algorithm.parameters); ++ if (rv != SECSuccess) { ++ printf("%s, failed to decode\n", typeName); ++ dumpValue(val,len); ++ PORT_FreeArena(arena, PR_FALSE); ++ return; ++ } ++ palg = SECOID_GetAlgorithmTag(¶m.algParams); ++ printf("%s alg=%s ", typeName, oid2string(palg)); ++ if (hasSig && palg == SEC_OID_AES_256_CBC) { ++ *hasSig = PR_TRUE; ++ } ++ template = pkcs5V2PBEParameterTemplate; ++ edi.algorithm.parameters = param.keyParams.parameters; ++ } else { ++ printf("Encrypted Data alg=%s ", oid2string(alg)); ++ if (alg == SEC_OID_PKCS5_PBKDF2) { ++ template = pkcs5V2PBEParameterTemplate; ++ } else if (isPKCS12PBE(alg)) { ++ template = pkcs12V2PBEParameterTemplate; ++ } else { ++ template = pkcs5V1PBEParameterTemplate; ++ } ++ } ++ rv = SEC_QuickDERDecodeItem(arena, &pbeParam, ++ template, ++ &edi.algorithm.parameters); ++ if (rv != SECSuccess) { ++ printf("( failed to decode params)\n"); ++ PORT_FreeArena(arena, PR_FALSE); ++ return; ++ } ++ /* dump the pbe parmeters */ ++ iter = DER_GetInteger(&pbeParam.iteration); ++ keyLen = DER_GetInteger(&pbeParam.keyLength); ++ prfAlg = SECOID_GetAlgorithmTag(&pbeParam.prfAlg); ++ printf("(prf=%s iter=%d keyLen=%d salt=0x", ++ oid2string(prfAlg), iter, keyLen); ++ for(i=0;i < pbeParam.salt.len; i++) printf("%02x",pbeParam.salt.data[i]); ++ printf(")\n"); ++ /* finally dump the raw encrypted data */ ++ dumpValue(edi.encryptedData.data, edi.encryptedData.len); ++ PORT_FreeArena(arena, PR_FALSE); ++} ++ ++/* dump a long attribute, convert to an unsigned long. PKCS #11 Longs are ++ * limited to 32 bits by the spec, even if the CK_ULONG is longer */ ++void ++dumpLongAttribute(CK_ATTRIBUTE_TYPE type, CK_ULONG value) ++{ ++ const char *nameType = "CK_NSS"; ++ ConstType constType = ConstNone; ++ const char *valueName = NULL; ++ ++ switch (type) { ++ case CKA_CLASS: ++ nameType = "CKO_NSS"; ++ constType = ConstObject; ++ break; ++ case CKA_CERTIFICATE_TYPE: ++ nameType = "CKC_NSS"; ++ constType = ConstCertType; ++ break; ++ case CKA_KEY_TYPE: ++ nameType = "CKK_NSS"; ++ constType = ConstKeyType; ++ break; ++ case CKA_MECHANISM_TYPE: ++ nameType = "CKM_NSS"; ++ constType = ConstMechanism; ++ break; ++ case CKA_TRUST_SERVER_AUTH: ++ case CKA_TRUST_CLIENT_AUTH: ++ case CKA_TRUST_CODE_SIGNING: ++ case CKA_TRUST_EMAIL_PROTECTION: ++ case CKA_TRUST_IPSEC_END_SYSTEM: ++ case CKA_TRUST_IPSEC_TUNNEL: ++ case CKA_TRUST_IPSEC_USER: ++ case CKA_TRUST_TIME_STAMPING: ++ nameType = "CKT_NSS"; ++ constType = ConstTrust; ++ break; ++ default: ++ break; ++ } ++ /* if value has a symbolic name, use it */ ++ if (constType != ConstNone) { ++ valueName = getName(value, constType); ++ } ++ if (!valueName) { ++ valueName = makeNSSVendorName(value, nameType); ++ } ++ if (!valueName) { ++ printf("%d (0x%08x)\n", (int) value, (int)value); ++ } else { ++ printf("%s (0x%08x)\n", valueName, (int)value); ++ } ++} ++ ++/* dump a signature for an object */ ++static const char META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; ++void ++dumpSignature(CK_ATTRIBUTE_TYPE attribute, SDB *keydb, PRBool isKey, ++ CK_OBJECT_HANDLE objectID, PRBool force) ++{ ++ char id[30]; ++ CK_RV crv; ++ SECItem signText; ++ unsigned char signData[SDB_MAX_META_DATA_LEN]; ++ ++ if (!force && !isAuthenticatedAttribute(attribute)) { ++ return; ++ } ++ sprintf(id, META_SIG_TEMPLATE, ++ isKey ? "key" : "cert", ++ (unsigned int)objectID, (unsigned int)attribute); ++ printf(" Signature %s:",id); ++ signText.data = signData; ++ signText.len = sizeof(signData); ++ ++ ++ crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); ++ if ((crv != CKR_OK) && isKey) { ++ sprintf(id, META_SIG_TEMPLATE, ++ isKey ? "key" : "cert", (unsigned int) ++ (objectID | SFTK_KEYDB_TYPE | SFTK_TOKEN_TYPE), ++ (unsigned int)attribute); ++ crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); ++ } ++ if (crv != CKR_OK) { ++ printf(" FAILED %s with %s (0x%08x)\n", id, ErrorName(crv), (int) crv); ++ return; ++ } ++ dumpPKCS(signText.data, signText.len, NULL); ++ return; ++} ++ ++/* dump an attribute. use the helper functions above */ ++void ++dumpAttribute(CK_ATTRIBUTE *template, SDB *keydb, PRBool isKey, ++ CK_OBJECT_HANDLE id) ++{ ++ CK_ATTRIBUTE_TYPE attribute = template->type; ++ printf(" %s(0x%08x): ", AttributeName(attribute), (int)attribute); ++ if (template->pValue == NULL) { ++ printf("NULL (%d)\n", (int)template->ulValueLen); ++ return; ++ } ++ if (template->ulValueLen == SDB_ULONG_SIZE ++ && isULONGAttribute(attribute)) { ++ CK_ULONG value=sdbULong2ULong(template->pValue); ++ dumpLongAttribute(attribute, value); ++ return; ++ } ++ if (template->ulValueLen == 1) { ++ unsigned char val = *(unsigned char *)template->pValue; ++ switch (val) { ++ case 0: ++ printf("CK_FALSE\n"); ++ break; ++ case 1: ++ printf("CK_TRUE\n"); ++ break; ++ default: ++ printf("%d 0x%02x %c\n", val, val, ASCCHAR(val)); ++ break; ++ } ++ return; ++ } ++ if (isKey && isPrivateAttribute(attribute)) { ++ PRBool hasSig = PR_FALSE; ++ dumpPKCS(template->pValue, template->ulValueLen, &hasSig); ++ if (hasSig) { ++ dumpSignature(attribute, keydb, isKey, id, PR_TRUE); ++ } ++ return; ++ } ++ if (template->ulValueLen == 0) { printf("empty"); } ++ printf("\n"); ++ dumpValue(template->pValue, template->ulValueLen); ++} ++ ++/* dump all the attributes in an object */ ++void ++dumpObject(CK_OBJECT_HANDLE id, SDB *db, SDB *keydb, PRBool isKey) ++{ ++ CK_RV crv; ++ int i; ++ CK_ATTRIBUTE template; ++ char buffer[2048]; ++ char * alloc = NULL; ++ ++ printf(" Object 0x%08x:\n", (int)id); ++ for (i = 0; i < known_attributes_size; i++) { ++ CK_ATTRIBUTE_TYPE attribute = known_attributes[i]; ++ template.type = attribute; ++ template.pValue = NULL; ++ template.ulValueLen = 0; ++ crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); ++ ++ if (crv != CKR_OK) { ++ if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { ++ PR_fprintf(PR_STDERR, " " ++ "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", ++ AttributeName(attribute), (int)attribute, ++ ErrorName(crv), (int)crv); ++ } ++ continue; ++ } ++ ++ if (template.ulValueLen < sizeof(buffer)) { ++ template.pValue = buffer; ++ } else { ++ alloc = PORT_Alloc(template.ulValueLen); ++ template.pValue = alloc; ++ } ++ if (template.pValue == NULL) { ++ PR_fprintf(PR_STDERR, " " ++ "Could allocate %d bytes for Attribute %s (0x%08x)\n", ++ (int) template.ulValueLen, ++ AttributeName(attribute), (int)attribute); ++ continue; ++ } ++ crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); ++ ++ if (crv != CKR_OK) { ++ if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { ++ PR_fprintf(PR_STDERR, " " ++ "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", ++ AttributeName(attribute), (int)attribute, ++ ErrorName(crv), (int)crv); ++ } ++ if (alloc) { ++ PORT_Free(alloc); ++ alloc = NULL; ++ } ++ continue; ++ } ++ ++ dumpAttribute(&template, keydb, isKey, id); ++ dumpSignature(template.type, keydb, isKey, id, PR_FALSE); ++ if (alloc) { ++ PORT_Free(alloc); ++ alloc = NULL; ++ } ++ } ++} ++ ++/* dump all the objects in a database */ ++void ++dumpDB(SDB *db, const char *name, SDB *keydb, PRBool isKey) ++{ ++ SDBFind *findHandle= NULL; ++ CK_BBOOL isTrue = 1; ++ CK_ATTRIBUTE allObjectTemplate = {CKA_TOKEN, NULL, 1 }; ++ CK_ULONG allObjectTemplateCount = 1; ++ PRBool recordFound = PR_FALSE; ++ CK_RV crv = CKR_OK; ++ CK_ULONG objectCount = 0; ++ printf("%s:\n",name); ++ ++ allObjectTemplate.pValue = &isTrue; ++ crv = (*db->sdb_FindObjectsInit)(db, &allObjectTemplate, ++ allObjectTemplateCount, &findHandle); ++ do { ++ CK_OBJECT_HANDLE id; ++ recordFound = PR_FALSE; ++ crv =(*db->sdb_FindObjects)(db, findHandle, &id, 1, &objectCount); ++ if ((crv == CKR_OK) && (objectCount == 1)) { ++ recordFound = PR_TRUE; ++ dumpObject(id, db, keydb, isKey); ++ } ++ } while (recordFound); ++ if (crv != CKR_OK) { ++ PR_fprintf(PR_STDERR, ++ "Last record return PKCS #11 error = %s (0x%08x)\n", ++ ErrorName(crv), (int)crv); ++ } ++ (*db->sdb_FindObjectsFinal)(db,findHandle); ++} ++ ++int ++main(int argc, char **argv) ++{ ++ PLOptState *optstate; ++ PLOptStatus optstatus; ++ char *certPrefix="", *keyPrefix=""; ++ int cert_version = 9; ++ int key_version = 4; ++ SDB *certdb = NULL; ++ SDB *keydb = NULL; ++ PRBool isNew = PR_FALSE; ++ ++ CK_RV crv; ++ ++ progName = strrchr(argv[0], '/'); ++ if (!progName) ++ progName = strrchr(argv[0], '\\'); ++ progName = progName ? progName + 1 : argv[0]; ++ ++ optstate = PL_CreateOptState(argc, argv, "d:c:k:v:V:h"); ++ ++ while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { ++ switch (optstate->option) { ++ case 'h': ++ default: ++ Usage(); ++ break; ++ ++ case 'd': ++ dbDir = PORT_Strdup(optstate->value); ++ break; ++ ++ case 'c': ++ certPrefix = PORT_Strdup(optstate->value); ++ break; ++ ++ case 'k': ++ keyPrefix = PORT_Strdup(optstate->value); ++ break; ++ ++ case 'v': ++ key_version = atoi(optstate->value); ++ break; ++ ++ case 'V': ++ cert_version = atoi(optstate->value); ++ break; ++ ++ } ++ } ++ PL_DestroyOptState(optstate); ++ if (optstatus == PL_OPT_BAD) ++ Usage(); ++ ++ if (dbDir) { ++ char *tmp = dbDir; ++ dbDir = SECU_ConfigDirectory(tmp); ++ PORT_Free(tmp); ++ } else { ++ /* Look in $SSL_DIR */ ++ dbDir = SECU_ConfigDirectory(SECU_DefaultSSLDir()); ++ } ++ PR_fprintf(PR_STDERR, "dbdir selected is %s\n\n", dbDir); ++ ++ if (dbDir[0] == '\0') { ++ PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir); ++ return 1; ++ } ++ ++ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); ++ SECOID_Init(); ++ ++ crv = s_open(dbDir, certPrefix, keyPrefix, cert_version, key_version, ++ SDB_RDONLY, &certdb, &keydb, &isNew); ++ if (crv != CKR_OK) { ++ PR_fprintf(PR_STDERR, ++ "Couldn't open databased in %s, error=%s (0x%08x)\n", ++ dbDir, ErrorName(crv), (int)crv); ++ return 1; ++ } ++ ++ /* now dump the objects in the cert database */ ++ dumpDB(certdb, "CertDB", keydb, PR_FALSE); ++ dumpDB(keydb, "KeyDB", keydb, PR_TRUE); ++ return 0; ++} +diff --git a/cmd/dbtool/dbtool.gyp b/cmd/dbtool/dbtool.gyp +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/dbtool.gyp +@@ -0,0 +1,25 @@ ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this ++# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++{ ++ 'includes': [ ++ '../../coreconf/config.gypi', ++ '../../cmd/platlibs.gypi' ++ ], ++ 'targets': [ ++ { ++ 'target_name': 'dbtest', ++ 'type': 'executable', ++ 'sources': [ ++ 'dbtest.c' ++ ], ++ 'dependencies': [ ++ '<(DEPTH)/exports.gyp:dbm_exports', ++ '<(DEPTH)/exports.gyp:nss_exports' ++ ] ++ } ++ ], ++ 'variables': { ++ 'module': 'nss' ++ } ++} +\ No newline at end of file +diff --git a/cmd/dbtool/manifest.mn b/cmd/dbtool/manifest.mn +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/manifest.mn +@@ -0,0 +1,18 @@ ++# ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this ++# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++CORE_DEPTH = ../.. ++ ++# MODULE public and private header directories are implicitly REQUIRED. ++MODULE = nss ++ ++USE_STATIC_LIBS = 1 ++ ++# DIRS = ++ ++CSRCS = dbtool.c sdb.c ++ ++PROGRAM = dbtool ++ +diff --git a/cmd/dbtool/sdb.c b/cmd/dbtool/sdb.c +new file mode 100644 +--- /dev/null ++++ b/cmd/dbtool/sdb.c +@@ -0,0 +1,2469 @@ ++/* This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ ++/* ++ * This file implements PKCS 11 on top of our existing security modules ++ * ++ * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. ++ * This implementation has two slots: ++ * slot 1 is our generic crypto support. It does not require login. ++ * It supports Public Key ops, and all they bulk ciphers and hashes. ++ * It can also support Private Key ops for imported Private keys. It does ++ * not have any token storage. ++ * slot 2 is our private key support. It requires a login before use. It ++ * can store Private Keys and Certs as token objects. Currently only private ++ * keys and their associated Certificates are saved on the token. ++ * ++ * In this implementation, session objects are only visible to the session ++ * that created or generated them. ++ */ ++ ++#include "sdb.h" ++#include "pkcs11t.h" ++#include "seccomon.h" ++#include ++#include "prthread.h" ++#include "prio.h" ++#include ++#include "secport.h" ++#include "prmon.h" ++#include "prenv.h" ++#include "prprf.h" ++#include "prsystem.h" /* for PR_GetDirectorySeparator() */ ++#include ++#if defined(_WIN32) ++#include ++#include ++#elif defined(XP_UNIX) ++#include ++#endif ++#if defined(LINUX) && !defined(ANDROID) ++#include ++#include ++#endif ++#include "utilpars.h" ++ ++#ifdef SQLITE_UNSAFE_THREADS ++#include "prlock.h" ++/* ++ * SQLite can be compiled to be thread safe or not. ++ * turn on SQLITE_UNSAFE_THREADS if the OS does not support ++ * a thread safe version of sqlite. ++ */ ++static PRLock *sqlite_lock = NULL; ++ ++#define LOCK_SQLITE() PR_Lock(sqlite_lock); ++#define UNLOCK_SQLITE() PR_Unlock(sqlite_lock); ++#else ++#define LOCK_SQLITE() ++#define UNLOCK_SQLITE() ++#endif ++ ++typedef enum { ++ SDB_CERT = 1, ++ SDB_KEY = 2 ++} sdbDataType; ++ ++/* ++ * defines controlling how long we wait to acquire locks. ++ * ++ * SDB_SQLITE_BUSY_TIMEOUT specifies how long (in milliseconds) ++ * sqlite will wait on lock. If that timeout expires, sqlite will ++ * return SQLITE_BUSY. ++ * SDB_BUSY_RETRY_TIME specifies how many seconds the sdb_ code waits ++ * after receiving a busy before retrying. ++ * SDB_MAX_BUSY_RETRIES specifies how many times the sdb_ will retry on ++ * a busy condition. ++ * ++ * SDB_SQLITE_BUSY_TIMEOUT affects all opertions, both manual ++ * (prepare/step/reset/finalize) and automatic (sqlite3_exec()). ++ * SDB_BUSY_RETRY_TIME and SDB_MAX_BUSY_RETRIES only affect manual operations ++ * ++ * total wait time for automatic operations: ++ * 1 second (SDB_SQLITE_BUSY_TIMEOUT/1000). ++ * total wait time for manual operations: ++ * (1 second + SDB_BUSY_RETRY_TIME) * 30 = 30 seconds. ++ * (SDB_SQLITE_BUSY_TIMEOUT/1000 + SDB_BUSY_RETRY_TIME)*SDB_MAX_BUSY_RETRIES ++ */ ++#define SDB_SQLITE_BUSY_TIMEOUT 1000 /* milliseconds */ ++#define SDB_BUSY_RETRY_TIME 5 /* 'ticks', varies by platforms */ ++#define SDB_MAX_BUSY_RETRIES 30 ++ ++/* ++ * known attributes ++ */ ++static const CK_ATTRIBUTE_TYPE known_attributes[] = { ++ CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, ++ CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, ++ CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, ++ CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, ++ CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, ++ CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, ++ CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, ++ CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, ++ CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, ++ CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, ++ CKA_PUBLIC_KEY_INFO, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, ++ CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, ++ CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, ++ CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, ++ CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, ++ CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_HW_FEATURE_TYPE, ++ CKA_RESET_ON_INIT, CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, ++ CKA_RESOLUTION, CKA_CHAR_ROWS, CKA_CHAR_COLUMNS, CKA_COLOR, ++ CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, CKA_ENCODING_METHODS, CKA_MIME_TYPES, ++ CKA_MECHANISM_TYPE, CKA_REQUIRED_CMS_ATTRIBUTES, ++ CKA_DEFAULT_CMS_ATTRIBUTES, CKA_SUPPORTED_CMS_ATTRIBUTES, ++ CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE, CKA_NSS_TRUST, CKA_NSS_URL, ++ CKA_NSS_EMAIL, CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, ++ CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, ++ CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, ++ CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, ++ CKA_NSS_OVERRIDE_EXTENSIONS, CKA_NSS_SERVER_DISTRUST_AFTER, ++ CKA_NSS_EMAIL_DISTRUST_AFTER, CKA_TRUST_DIGITAL_SIGNATURE, ++ CKA_TRUST_NON_REPUDIATION, CKA_TRUST_KEY_ENCIPHERMENT, ++ CKA_TRUST_DATA_ENCIPHERMENT, CKA_TRUST_KEY_AGREEMENT, ++ CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, CKA_TRUST_SERVER_AUTH, ++ CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, ++ CKA_TRUST_IPSEC_END_SYSTEM, CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, ++ CKA_TRUST_TIME_STAMPING, CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, ++ CKA_CERT_MD5_HASH, CKA_NSS_DB ++}; ++ ++static const int known_attributes_size = PR_ARRAY_SIZE(known_attributes); ++ ++/* ++ * Note on use of sqlReadDB: Only one thread at a time may have an actual ++ * operation going on given sqlite3 * database. An operation is defined as ++ * the time from a sqlite3_prepare() until the sqlite3_finalize(). ++ * Multiple sqlite3 * databases can be open and have simultaneous operations ++ * going. We use the sqlXactDB for all write operations. This database ++ * is only opened when we first create a transaction and closed when the ++ * transaction is complete. sqlReadDB is open when we first opened the database ++ * and is used for all read operation. It's use is protected by a monitor. This ++ * is because an operation can span the use of FindObjectsInit() through the ++ * call to FindObjectsFinal(). In the intermediate time it is possible to call ++ * other operations like NSC_GetAttributeValue */ ++ ++struct SDBPrivateStr { ++ char *sqlDBName; /* invariant, path to this database */ ++ sqlite3 *sqlXactDB; /* access protected by dbMon, use protected ++ * by the transaction. Current transaction db*/ ++ PRThread *sqlXactThread; /* protected by dbMon, ++ * current transaction thread */ ++ sqlite3 *sqlReadDB; /* use protected by dbMon, value invariant */ ++ PRIntervalTime lastUpdateTime; /* last time the cache was updated */ ++ PRIntervalTime updateInterval; /* how long the cache can go before it ++ * must be updated again */ ++ sdbDataType type; /* invariant, database type */ ++ char *table; /* invariant, SQL table which contains the db */ ++ char *cacheTable; /* invariant, SQL table cache of db */ ++ PRMonitor *dbMon; /* invariant, monitor to protect ++ * sqlXact* fields, and use of the sqlReadDB */ ++ CK_ATTRIBUTE_TYPE *schemaAttrs; /* Attribute columns that exist in the table. */ ++ unsigned int numSchemaAttrs; ++}; ++ ++typedef struct SDBPrivateStr SDBPrivate; ++ ++/* Magic for an explicit NULL. NOTE: ideally this should be ++ * out of band data. Since it's not completely out of band, pick ++ * a value that has no meaning to any existing PKCS #11 attributes. ++ * This value is 1) not a valid string (imbedded '\0'). 2) not a U_LONG ++ * or a normal key (too short). 3) not a bool (too long). 4) not an RSA ++ * public exponent (too many bits). ++ */ ++const unsigned char SQLITE_EXPLICIT_NULL[] = { 0xa5, 0x0, 0x5a }; ++#define SQLITE_EXPLICIT_NULL_LEN 3 ++ ++/* ++ * determine when we've completed our tasks ++ */ ++static int ++sdb_done(int err, int *count) ++{ ++ /* allow as many rows as the database wants to give */ ++ if (err == SQLITE_ROW) { ++ *count = 0; ++ return 0; ++ } ++ if (err != SQLITE_BUSY) { ++ return 1; ++ } ++ /* err == SQLITE_BUSY, Dont' retry forever in this case */ ++ if (++(*count) >= SDB_MAX_BUSY_RETRIES) { ++ return 1; ++ } ++ return 0; ++} ++ ++#if defined(_WIN32) ++/* ++ * NSPR functions and narrow CRT functions do not handle UTF-8 file paths that ++ * sqlite3 expects. ++ */ ++ ++static int ++sdb_chmod(const char *filename, int pmode) ++{ ++ int result; ++ ++ if (!filename) { ++ return -1; ++ } ++ ++ wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename); ++ if (!filenameWide) { ++ return -1; ++ } ++ result = _wchmod(filenameWide, pmode); ++ PORT_Free(filenameWide); ++ ++ return result; ++} ++#else ++#define sdb_chmod(filename, pmode) chmod((filename), (pmode)) ++#endif ++ ++/* ++ * find out where sqlite stores the temp tables. We do this by replicating ++ * the logic from sqlite. ++ */ ++#if defined(_WIN32) ++static char * ++sdb_getFallbackTempDir(void) ++{ ++ /* sqlite uses sqlite3_temp_directory if it is not NULL. We don't have ++ * access to sqlite3_temp_directory because it is not exported from ++ * sqlite3.dll. Assume sqlite3_win32_set_directory isn't called and ++ * sqlite3_temp_directory is NULL. ++ */ ++ char path[MAX_PATH]; ++ DWORD rv; ++ size_t len; ++ ++ rv = GetTempPathA(MAX_PATH, path); ++ if (rv > MAX_PATH || rv == 0) ++ return NULL; ++ len = strlen(path); ++ if (len == 0) ++ return NULL; ++ /* The returned string ends with a backslash, for example, "C:\TEMP\". */ ++ if (path[len - 1] == '\\') ++ path[len - 1] = '\0'; ++ return PORT_Strdup(path); ++} ++#elif defined(XP_UNIX) ++static char * ++sdb_getFallbackTempDir(void) ++{ ++ const char *azDirs[] = { ++ NULL, ++ NULL, ++ "/var/tmp", ++ "/usr/tmp", ++ "/tmp", ++ NULL /* List terminator */ ++ }; ++ unsigned int i; ++ struct stat buf; ++ const char *zDir = NULL; ++ ++ azDirs[0] = sqlite3_temp_directory; ++ azDirs[1] = PR_GetEnvSecure("TMPDIR"); ++ ++ for (i = 0; i < PR_ARRAY_SIZE(azDirs); i++) { ++ zDir = azDirs[i]; ++ if (zDir == NULL) ++ continue; ++ if (stat(zDir, &buf)) ++ continue; ++ if (!S_ISDIR(buf.st_mode)) ++ continue; ++ if (access(zDir, 07)) ++ continue; ++ break; ++ } ++ ++ if (zDir == NULL) ++ return NULL; ++ return PORT_Strdup(zDir); ++} ++#else ++#error "sdb_getFallbackTempDir not implemented" ++#endif ++ ++#ifndef SQLITE_FCNTL_TEMPFILENAME ++/* SQLITE_FCNTL_TEMPFILENAME was added in SQLite 3.7.15 */ ++#define SQLITE_FCNTL_TEMPFILENAME 16 ++#endif ++ ++static char * ++sdb_getTempDir(sqlite3 *sqlDB) ++{ ++ int sqlrv; ++ char *result = NULL; ++ char *tempName = NULL; ++ char *foundSeparator = NULL; ++ ++ /* Obtain temporary filename in sqlite's directory for temporary tables */ ++ sqlrv = sqlite3_file_control(sqlDB, 0, SQLITE_FCNTL_TEMPFILENAME, ++ (void *)&tempName); ++ if (sqlrv == SQLITE_NOTFOUND) { ++ /* SQLITE_FCNTL_TEMPFILENAME not implemented because we are using ++ * an older SQLite. */ ++ return sdb_getFallbackTempDir(); ++ } ++ if (sqlrv != SQLITE_OK) { ++ return NULL; ++ } ++ ++ /* We'll extract the temporary directory from tempName */ ++ foundSeparator = PORT_Strrchr(tempName, PR_GetDirectorySeparator()); ++ if (foundSeparator) { ++ /* We shorten the temp filename string to contain only ++ * the directory name (including the trailing separator). ++ * We know the byte after the foundSeparator position is ++ * safe to use, in the shortest scenario it contains the ++ * end-of-string byte. ++ * By keeping the separator at the found position, it will ++ * even work if tempDir consists of the separator, only. ++ * (In this case the toplevel directory will be used for ++ * access speed testing). */ ++ ++foundSeparator; ++ *foundSeparator = 0; ++ ++ /* Now we copy the directory name for our caller */ ++ result = PORT_Strdup(tempName); ++ } ++ ++ sqlite3_free(tempName); ++ return result; ++} ++ ++/* ++ * Map SQL_LITE errors to PKCS #11 errors as best we can. ++ */ ++static CK_RV ++sdb_mapSQLError(sdbDataType type, int sqlerr) ++{ ++ switch (sqlerr) { ++ /* good matches */ ++ case SQLITE_OK: ++ case SQLITE_DONE: ++ return CKR_OK; ++ case SQLITE_NOMEM: ++ return CKR_HOST_MEMORY; ++ case SQLITE_READONLY: ++ return CKR_TOKEN_WRITE_PROTECTED; ++ /* close matches */ ++ case SQLITE_AUTH: ++ case SQLITE_PERM: ++ /*return CKR_USER_NOT_LOGGED_IN; */ ++ case SQLITE_CANTOPEN: ++ case SQLITE_NOTFOUND: ++ /* NSS distiguishes between failure to open the cert and the key db */ ++ return type == SDB_CERT ? CKR_NSS_CERTDB_FAILED : CKR_NSS_KEYDB_FAILED; ++ case SQLITE_IOERR: ++ return CKR_DEVICE_ERROR; ++ default: ++ break; ++ } ++ return CKR_GENERAL_ERROR; ++} ++ ++/* ++ * build up database name from a directory, prefix, name, version and flags. ++ */ ++static char * ++sdb_BuildFileName(const char *directory, ++ const char *prefix, const char *type, ++ int version) ++{ ++ char *dbname = NULL; ++ /* build the full dbname */ ++ dbname = sqlite3_mprintf("%s%c%s%s%d.db", directory, ++ (int)(unsigned char)PR_GetDirectorySeparator(), ++ prefix, type, version); ++ return dbname; ++} ++ ++/* ++ * find out how expensive the access system call is for non-existant files ++ * in the given directory. Return the number of operations done in 33 ms. ++ */ ++static PRUint32 ++sdb_measureAccess(const char *directory) ++{ ++ PRUint32 i; ++ PRIntervalTime time; ++ PRIntervalTime delta; ++ PRIntervalTime duration = PR_MillisecondsToInterval(33); ++ const char *doesntExistName = "_dOeSnotExist_.db"; ++ char *temp, *tempStartOfFilename; ++ size_t maxTempLen, maxFileNameLen, directoryLength, tmpdirLength = 0; ++#ifdef SDB_MEASURE_USE_TEMP_DIR ++ /* ++ * on some OS's and Filesystems, creating a bunch of files and deleting ++ * them messes up the systems's caching, but if we create the files in ++ * a temp directory which we later delete, then the cache gets cleared ++ * up. This code uses several OS dependent calls, and it's not clear ++ * that temp directory use won't mess up other filesystems and OS caching, ++ * so if you need this for your OS, you can turn on the ++ * 'SDB_MEASURE_USE_TEMP_DIR' define in coreconf ++ */ ++ const char template[] = "dbTemp.XXXXXX"; ++ tmpdirLength = sizeof(template); ++#endif ++ /* no directory, just return one */ ++ if (directory == NULL) { ++ return 1; ++ } ++ ++ /* our calculation assumes time is a 4 bytes == 32 bit integer */ ++ PORT_Assert(sizeof(time) == 4); ++ ++ directoryLength = strlen(directory); ++ ++ maxTempLen = directoryLength + 1 /* dirname + / */ ++ + tmpdirLength /* tmpdirname includes / */ ++ + strlen(doesntExistName) /* filename base */ ++ + 11 /* max chars for 32 bit int plus potential sign */ ++ + 1; /* zero terminator */ ++ ++ temp = PORT_ZAlloc(maxTempLen); ++ if (!temp) { ++ return 1; ++ } ++ ++ /* We'll copy directory into temp just once, then ensure it ends ++ * with the directory separator. */ ++ ++ strcpy(temp, directory); ++ if (directory[directoryLength - 1] != PR_GetDirectorySeparator()) { ++ temp[directoryLength++] = PR_GetDirectorySeparator(); ++ } ++ ++#ifdef SDB_MEASURE_USE_TEMP_DIR ++ /* add the template for a temporary subdir, and create it */ ++ strcat(temp, template); ++ if (!mkdtemp(temp)) { ++ PORT_Free(temp); ++ return 1; ++ } ++ /* and terminate that tmp subdir with a / */ ++ strcat(temp, "/"); ++#endif ++ ++ /* Remember the position after the last separator, and calculate the ++ * number of remaining bytes. */ ++ tempStartOfFilename = temp + directoryLength + tmpdirLength; ++ maxFileNameLen = maxTempLen - directoryLength; ++ ++ /* measure number of Access operations that can be done in 33 milliseconds ++ * (1/30'th of a second), or 10000 operations, which ever comes first. ++ */ ++ time = PR_IntervalNow(); ++ for (i = 0; i < 10000u; i++) { ++ PRIntervalTime next; ++ ++ /* We'll use the variable part first in the filename string, just in ++ * case it's longer than assumed, so if anything gets cut off, it ++ * will be cut off from the constant part. ++ * This code assumes the directory name at the beginning of ++ * temp remains unchanged during our loop. */ ++ PR_snprintf(tempStartOfFilename, maxFileNameLen, ++ ".%lu%s", (PRUint32)(time + i), doesntExistName); ++ PR_Access(temp, PR_ACCESS_EXISTS); ++ next = PR_IntervalNow(); ++ delta = next - time; ++ if (delta >= duration) ++ break; ++ } ++ ++#ifdef SDB_MEASURE_USE_TEMP_DIR ++ /* turn temp back into our tmpdir path by removing doesntExistName, and ++ * remove the tmp dir */ ++ *tempStartOfFilename = '\0'; ++ (void)rmdir(temp); ++#endif ++ PORT_Free(temp); ++ ++ /* always return 1 or greater */ ++ return i ? i : 1u; ++} ++ ++/* ++ * some file sytems are very slow to run sqlite3 on, particularly if the ++ * access count is pretty high. On these filesystems is faster to create ++ * a temporary database on the local filesystem and access that. This ++ * code uses a temporary table to create that cache. Temp tables are ++ * automatically cleared when the database handle it was created on ++ * Is freed. ++ */ ++static const char DROP_CACHE_CMD[] = "DROP TABLE %s"; ++static const char CREATE_CACHE_CMD[] = ++ "CREATE TEMPORARY TABLE %s AS SELECT * FROM %s"; ++static const char CREATE_ISSUER_INDEX_CMD[] = ++ "CREATE INDEX issuer ON %s (a81)"; ++static const char CREATE_SUBJECT_INDEX_CMD[] = ++ "CREATE INDEX subject ON %s (a101)"; ++static const char CREATE_LABEL_INDEX_CMD[] = "CREATE INDEX label ON %s (a3)"; ++static const char CREATE_ID_INDEX_CMD[] = "CREATE INDEX ckaid ON %s (a102)"; ++ ++static CK_RV ++sdb_buildCache(sqlite3 *sqlDB, sdbDataType type, ++ const char *cacheTable, const char *table) ++{ ++ char *newStr; ++ int sqlerr = SQLITE_OK; ++ ++ newStr = sqlite3_mprintf(CREATE_CACHE_CMD, cacheTable, table); ++ if (newStr == NULL) { ++ return CKR_HOST_MEMORY; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ return sdb_mapSQLError(type, sqlerr); ++ } ++ /* failure to create the indexes is not an issue */ ++ newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, cacheTable); ++ if (newStr == NULL) { ++ return CKR_OK; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ return CKR_OK; ++} ++ ++/* ++ * update the cache and the data records describing it. ++ * The cache is updated by dropping the temp database and recreating it. ++ */ ++static CK_RV ++sdb_updateCache(SDBPrivate *sdb_p) ++{ ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ char *newStr; ++ ++ /* drop the old table */ ++ newStr = sqlite3_mprintf(DROP_CACHE_CMD, sdb_p->cacheTable); ++ if (newStr == NULL) { ++ return CKR_HOST_MEMORY; ++ } ++ sqlerr = sqlite3_exec(sdb_p->sqlReadDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if ((sqlerr != SQLITE_OK) && (sqlerr != SQLITE_ERROR)) { ++ /* something went wrong with the drop, don't try to refresh... ++ * NOTE: SQLITE_ERROR is returned if the table doesn't exist. In ++ * that case, we just continue on and try to reload it */ ++ return sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ /* set up the new table */ ++ error = sdb_buildCache(sdb_p->sqlReadDB, sdb_p->type, ++ sdb_p->cacheTable, sdb_p->table); ++ if (error == CKR_OK) { ++ /* we have a new cache! */ ++ sdb_p->lastUpdateTime = PR_IntervalNow(); ++ } ++ return error; ++} ++ ++/* ++ * The sharing of sqlite3 handles across threads is tricky. Older versions ++ * couldn't at all, but newer ones can under strict conditions. Basically ++ * no 2 threads can use the same handle while another thread has an open ++ * stmt running. Once the sqlite3_stmt is finalized, another thread can then ++ * use the database handle. ++ * ++ * We use monitors to protect against trying to use a database before ++ * it's sqlite3_stmt is finalized. This is preferable to the opening and ++ * closing the database each operation because there is significant overhead ++ * in the open and close. Also continually opening and closing the database ++ * defeats the cache code as the cache table is lost on close (thus ++ * requiring us to have to reinitialize the cache every operation). ++ * ++ * An execption to the shared handle is transations. All writes happen ++ * through a transaction. When we are in a transaction, we must use the ++ * same database pointer for that entire transation. In this case we save ++ * the transaction database and use it for all accesses on the transaction ++ * thread. Other threads use the common database. ++ * ++ * There can only be once active transaction on the database at a time. ++ * ++ * sdb_openDBLocal() provides us with a valid database handle for whatever ++ * state we are in (reading or in a transaction), and acquires any locks ++ * appropriate to that state. It also decides when it's time to refresh ++ * the cache before we start an operation. Any database handle returned ++ * just eventually be closed with sdb_closeDBLocal(). ++ * ++ * The table returned either points to the database's physical table, or ++ * to the cached shadow. Tranactions always return the physical table ++ * and read operations return either the physical table or the cache ++ * depending on whether or not the cache exists. ++ */ ++static CK_RV ++sdb_openDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB, const char **table) ++{ ++ *sqlDB = NULL; ++ ++ PR_EnterMonitor(sdb_p->dbMon); ++ ++ if (table) { ++ *table = sdb_p->table; ++ } ++ ++ /* We're in a transaction, use the transaction DB */ ++ if ((sdb_p->sqlXactDB) && (sdb_p->sqlXactThread == PR_GetCurrentThread())) { ++ *sqlDB = sdb_p->sqlXactDB; ++ /* only one thread can get here, safe to unlock */ ++ PR_ExitMonitor(sdb_p->dbMon); ++ return CKR_OK; ++ } ++ ++ /* ++ * if we are just reading from the table, we may have the table ++ * cached in a temporary table (especially if it's on a shared FS). ++ * In that case we want to see updates to the table, the the granularity ++ * is on order of human scale, not computer scale. ++ */ ++ if (table && sdb_p->cacheTable) { ++ PRIntervalTime now = PR_IntervalNow(); ++ if ((now - sdb_p->lastUpdateTime) > sdb_p->updateInterval) { ++ sdb_updateCache(sdb_p); ++ } ++ *table = sdb_p->cacheTable; ++ } ++ ++ *sqlDB = sdb_p->sqlReadDB; ++ ++ /* leave holding the lock. only one thread can actually use a given ++ * database connection at once */ ++ ++ return CKR_OK; ++} ++ ++/* closing the local database currenly means unlocking the monitor */ ++static CK_RV ++sdb_closeDBLocal(SDBPrivate *sdb_p, sqlite3 *sqlDB) ++{ ++ if (sdb_p->sqlXactDB != sqlDB) { ++ /* if we weren't in a transaction, we got a lock */ ++ PR_ExitMonitor(sdb_p->dbMon); ++ } ++ return CKR_OK; ++} ++ ++/* ++ * wrapper to sqlite3_open which also sets the busy_timeout ++ */ ++static int ++sdb_openDB(const char *name, sqlite3 **sqlDB, int flags) ++{ ++ int sqlerr; ++ int openFlags; ++ ++ *sqlDB = NULL; ++ ++ if (flags & SDB_RDONLY) { ++ openFlags = SQLITE_OPEN_READONLY; ++ } else { ++ openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; ++ /* sqlite 3.34 seem to incorrectly open readwrite. ++ * when the file is readonly. Explicitly reject that issue here */ ++ if ((_NSSUTIL_Access(name, PR_ACCESS_EXISTS) == PR_SUCCESS) && (_NSSUTIL_Access(name, PR_ACCESS_WRITE_OK) != PR_SUCCESS)) { ++ return SQLITE_READONLY; ++ } ++ } ++ ++ /* Requires SQLite 3.5.0 or newer. */ ++ sqlerr = sqlite3_open_v2(name, sqlDB, openFlags, NULL); ++ if (sqlerr != SQLITE_OK) { ++ return sqlerr; ++ } ++ ++ sqlerr = sqlite3_busy_timeout(*sqlDB, SDB_SQLITE_BUSY_TIMEOUT); ++ if (sqlerr != SQLITE_OK) { ++ sqlite3_close(*sqlDB); ++ *sqlDB = NULL; ++ return sqlerr; ++ } ++ return SQLITE_OK; ++} ++ ++/* Sigh, if we created a new table since we opened the database, ++ * the database handle will not see the new table, we need to close this ++ * database and reopen it. Caller must be in a transaction or holding ++ * the dbMon. sqlDB is changed on success. */ ++static int ++sdb_reopenDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB) ++{ ++ sqlite3 *newDB; ++ int sqlerr; ++ ++ /* open a new database */ ++ sqlerr = sdb_openDB(sdb_p->sqlDBName, &newDB, SDB_RDONLY); ++ if (sqlerr != SQLITE_OK) { ++ return sqlerr; ++ } ++ ++ /* if we are in a transaction, we may not be holding the monitor. ++ * grab it before we update the transaction database. This is ++ * safe since are using monitors. */ ++ PR_EnterMonitor(sdb_p->dbMon); ++ /* update our view of the database */ ++ if (sdb_p->sqlReadDB == *sqlDB) { ++ sdb_p->sqlReadDB = newDB; ++ } else if (sdb_p->sqlXactDB == *sqlDB) { ++ sdb_p->sqlXactDB = newDB; ++ } ++ PR_ExitMonitor(sdb_p->dbMon); ++ ++ /* close the old one */ ++ sqlite3_close(*sqlDB); ++ ++ *sqlDB = newDB; ++ return SQLITE_OK; ++} ++ ++struct SDBFindStr { ++ sqlite3 *sqlDB; ++ sqlite3_stmt *findstmt; ++}; ++ ++static const char FIND_OBJECTS_CMD[] = "SELECT ALL id FROM %s WHERE %s;"; ++static const char FIND_OBJECTS_ALL_CMD[] = "SELECT ALL id FROM %s;"; ++CK_RV ++sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count, ++ SDBFind **find) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ const char *table; ++ char *newStr, *findStr = NULL; ++ sqlite3_stmt *findstmt = NULL; ++ char *join = ""; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ unsigned int i; ++ ++ LOCK_SQLITE() ++ *find = NULL; ++ error = sdb_openDBLocal(sdb_p, &sqlDB, &table); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ findStr = sqlite3_mprintf(""); ++ for (i = 0; findStr && i < count; i++) { ++ newStr = sqlite3_mprintf("%s%sa%x=$DATA%d", findStr, join, ++ template[i].type, i); ++ join = " AND "; ++ sqlite3_free(findStr); ++ findStr = newStr; ++ } ++ ++ if (findStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ if (count == 0) { ++ newStr = sqlite3_mprintf(FIND_OBJECTS_ALL_CMD, table); ++ } else { ++ newStr = sqlite3_mprintf(FIND_OBJECTS_CMD, table, findStr); ++ } ++ sqlite3_free(findStr); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &findstmt, NULL); ++ sqlite3_free(newStr); ++ for (i = 0; sqlerr == SQLITE_OK && i < count; i++) { ++ const void *blobData = template[i].pValue; ++ unsigned int blobSize = template[i].ulValueLen; ++ if (blobSize == 0) { ++ blobSize = SQLITE_EXPLICIT_NULL_LEN; ++ blobData = SQLITE_EXPLICIT_NULL; ++ } ++ sqlerr = sqlite3_bind_blob(findstmt, i + 1, blobData, blobSize, ++ SQLITE_TRANSIENT); ++ } ++ if (sqlerr == SQLITE_OK) { ++ *find = PORT_New(SDBFind); ++ if (*find == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ (*find)->findstmt = findstmt; ++ (*find)->sqlDB = sqlDB; ++ UNLOCK_SQLITE() ++ return CKR_OK; ++ } ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ ++loser: ++ if (findstmt) { ++ sqlite3_reset(findstmt); ++ sqlite3_finalize(findstmt); ++ } ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++CK_RV ++sdb_FindObjects(SDB *sdb, SDBFind *sdbFind, CK_OBJECT_HANDLE *object, ++ CK_ULONG arraySize, CK_ULONG *count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3_stmt *stmt = sdbFind->findstmt; ++ int sqlerr = SQLITE_OK; ++ int retry = 0; ++ ++ *count = 0; ++ ++ if (arraySize == 0) { ++ return CKR_OK; ++ } ++ LOCK_SQLITE() ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ /* only care about the id */ ++ *object++ = sqlite3_column_int(stmt, 0); ++ arraySize--; ++ (*count)++; ++ } ++ } while (!sdb_done(sqlerr, &retry) && (arraySize > 0)); ++ ++ /* we only have some of the objects, there is probably more, ++ * set the sqlerr to an OK value so we return CKR_OK */ ++ if (sqlerr == SQLITE_ROW && arraySize == 0) { ++ sqlerr = SQLITE_DONE; ++ } ++ UNLOCK_SQLITE() ++ ++ return sdb_mapSQLError(sdb_p->type, sqlerr); ++} ++ ++CK_RV ++sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3_stmt *stmt = sdbFind->findstmt; ++ sqlite3 *sqlDB = sdbFind->sqlDB; ++ int sqlerr = SQLITE_OK; ++ ++ LOCK_SQLITE() ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlerr = sqlite3_finalize(stmt); ++ } ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ PORT_Free(sdbFind); ++ ++ UNLOCK_SQLITE() ++ return sdb_mapSQLError(sdb_p->type, sqlerr); ++} ++ ++static CK_RV ++sdb_GetValidAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id, ++ CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ const char *table = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int found = 0; ++ int retry = 0; ++ unsigned int i; ++ ++ if (count == 0) { ++ error = CKR_OBJECT_HANDLE_INVALID; ++ goto loser; ++ } ++ ++ /* open a new db if necessary */ ++ error = sdb_openDBLocal(sdb_p, &sqlDB, &table); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ char *columns = NULL; ++ for (i = 0; i < count; i++) { ++ char *newColumns; ++ if (columns) { ++ newColumns = sqlite3_mprintf("%s, a%x", columns, template[i].type); ++ sqlite3_free(columns); ++ columns = NULL; ++ } else { ++ newColumns = sqlite3_mprintf("a%x", template[i].type); ++ } ++ if (!newColumns) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ columns = newColumns; ++ } ++ ++ PORT_Assert(columns); ++ ++ char *statement = sqlite3_mprintf("SELECT DISTINCT %s FROM %s where id=$ID LIMIT 1;", ++ columns, table); ++ sqlite3_free(columns); ++ columns = NULL; ++ if (!statement) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ sqlerr = sqlite3_prepare_v2(sqlDB, statement, -1, &stmt, NULL); ++ sqlite3_free(statement); ++ statement = NULL; ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ // NB: indices in sqlite3_bind_int are 1-indexed ++ sqlerr = sqlite3_bind_int(stmt, 1, object_id); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ PORT_Assert(!found); ++ for (i = 0; i < count; i++) { ++ unsigned int blobSize; ++ const char *blobData; ++ ++ // NB: indices in sqlite_column_{bytes,blob} are 0-indexed ++ blobSize = sqlite3_column_bytes(stmt, i); ++ blobData = sqlite3_column_blob(stmt, i); ++ if (blobData == NULL) { ++ /* PKCS 11 requires that get attributes process all the ++ * attributes in the template, marking the attributes with ++ * issues with -1. Mark the error but continue */ ++ template[i].ulValueLen = -1; ++ error = CKR_ATTRIBUTE_TYPE_INVALID; ++ continue; ++ } ++ /* If the blob equals our explicit NULL value, then the ++ * attribute is a NULL. */ ++ if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) && ++ (PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL, ++ SQLITE_EXPLICIT_NULL_LEN) == 0)) { ++ blobSize = 0; ++ } ++ if (template[i].pValue) { ++ if (template[i].ulValueLen < blobSize) { ++ /* like CKR_ATTRIBUTE_TYPE_INVALID, continue processing */ ++ template[i].ulValueLen = -1; ++ error = CKR_BUFFER_TOO_SMALL; ++ continue; ++ } ++ PORT_Memcpy(template[i].pValue, blobData, blobSize); ++ } ++ template[i].ulValueLen = blobSize; ++ } ++ found = 1; ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ stmt = NULL; ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ if (!found && error == CKR_OK) { ++ error = CKR_OBJECT_HANDLE_INVALID; ++ } ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ /* if we had to open a new database, free it now */ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ return error; ++} ++ ++/* NOTE: requires sdb_p->schemaAttrs to be sorted asc. */ ++inline static PRBool ++sdb_attributeExists(SDB *sdb, CK_ATTRIBUTE_TYPE attr) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ int first = 0; ++ int last = (int)sdb_p->numSchemaAttrs - 1; ++ while (last >= first) { ++ int mid = first + (last - first) / 2; ++ if (sdb_p->schemaAttrs[mid] == attr) { ++ return PR_TRUE; ++ } ++ if (attr > sdb_p->schemaAttrs[mid]) { ++ first = mid + 1; ++ } else { ++ last = mid - 1; ++ } ++ } ++ ++ return PR_FALSE; ++} ++ ++CK_RV ++sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, ++ CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ CK_RV crv = CKR_OK; ++ unsigned int tmplIdx; ++ unsigned int resIdx = 0; ++ unsigned int validCount = 0; ++ unsigned int i; ++ ++ if (count == 0) { ++ return crv; ++ } ++ ++ CK_ATTRIBUTE *validTemplate; ++ PRBool invalidExists = PR_FALSE; ++ for (tmplIdx = 0; tmplIdx < count; tmplIdx++) { ++ if (!sdb_attributeExists(sdb, template[tmplIdx].type)) { ++ template[tmplIdx].ulValueLen = -1; ++ crv = CKR_ATTRIBUTE_TYPE_INVALID; ++ invalidExists = PR_TRUE; ++ break; ++ } ++ } ++ ++ if (!invalidExists) { ++ validTemplate = template; ++ validCount = count; ++ } else { ++ /* Create a new template containing only the valid subset of ++ * input |template|, and query with that. */ ++ validCount = tmplIdx; ++ validTemplate = malloc(sizeof(CK_ATTRIBUTE) * count); ++ if (!validTemplate) { ++ return CKR_HOST_MEMORY; ++ } ++ /* Copy in what we already know is valid. */ ++ for (i = 0; i < validCount; i++) { ++ validTemplate[i] = template[i]; ++ } ++ ++ /* tmplIdx was left at the index of the first invalid ++ * attribute, which has been handled. We only need to ++ * deal with the remainder. */ ++ tmplIdx++; ++ for (; tmplIdx < count; tmplIdx++) { ++ if (sdb_attributeExists(sdb, template[tmplIdx].type)) { ++ validTemplate[validCount++] = template[tmplIdx]; ++ } else { ++ template[tmplIdx].ulValueLen = -1; ++ } ++ } ++ } ++ ++ if (validCount) { ++ LOCK_SQLITE() ++ CK_RV crv2 = sdb_GetValidAttributeValueNoLock(sdb, object_id, validTemplate, validCount); ++ UNLOCK_SQLITE() ++ ++ /* If an invalid attribute was removed above, let ++ * the caller know. Any other error from the actual ++ * query should propogate. */ ++ crv = (crv2 == CKR_OK) ? crv : crv2; ++ } ++ ++ if (invalidExists) { ++ /* Copy out valid lengths. */ ++ tmplIdx = 0; ++ for (resIdx = 0; resIdx < validCount; resIdx++) { ++ for (; tmplIdx < count; tmplIdx++) { ++ if (template[tmplIdx].type != validTemplate[resIdx].type) { ++ continue; ++ } ++ template[tmplIdx].ulValueLen = validTemplate[resIdx].ulValueLen; ++ tmplIdx++; ++ break; ++ } ++ } ++ free(validTemplate); ++ } ++ ++ return crv; ++} ++ ++static const char SET_ATTRIBUTE_CMD[] = "UPDATE %s SET %s WHERE id=$ID;"; ++CK_RV ++sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, ++ const CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ char *setStr = NULL; ++ char *newStr = NULL; ++ int sqlerr = SQLITE_OK; ++ int retry = 0; ++ CK_RV error = CKR_OK; ++ unsigned int i; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ if (count == 0) { ++ return CKR_OK; ++ } ++ ++ LOCK_SQLITE() ++ setStr = sqlite3_mprintf(""); ++ for (i = 0; setStr && i < count; i++) { ++ if (i == 0) { ++ sqlite3_free(setStr); ++ setStr = sqlite3_mprintf("a%x=$VALUE%d", ++ template[i].type, i); ++ continue; ++ } ++ newStr = sqlite3_mprintf("%s,a%x=$VALUE%d", setStr, ++ template[i].type, i); ++ sqlite3_free(setStr); ++ setStr = newStr; ++ } ++ newStr = NULL; ++ ++ if (setStr == NULL) { ++ return CKR_HOST_MEMORY; ++ } ++ newStr = sqlite3_mprintf(SET_ATTRIBUTE_CMD, sdb_p->table, setStr); ++ sqlite3_free(setStr); ++ if (newStr == NULL) { ++ UNLOCK_SQLITE() ++ return CKR_HOST_MEMORY; ++ } ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ for (i = 0; i < count; i++) { ++ if (template[i].ulValueLen != 0) { ++ sqlerr = sqlite3_bind_blob(stmt, i + 1, template[i].pValue, ++ template[i].ulValueLen, SQLITE_STATIC); ++ } else { ++ sqlerr = sqlite3_bind_blob(stmt, i + 1, SQLITE_EXPLICIT_NULL, ++ SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ sqlerr = sqlite3_bind_int(stmt, i + 1, object_id); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ if (newStr) { ++ sqlite3_free(newStr); ++ } ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++/* ++ * check to see if a candidate object handle already exists. ++ */ ++static PRBool ++sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate) ++{ ++ CK_RV crv; ++ CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 }; ++ ++ crv = sdb_GetValidAttributeValueNoLock(sdb, candidate, &template, 1); ++ if (crv == CKR_OBJECT_HANDLE_INVALID) { ++ return PR_FALSE; ++ } ++ return PR_TRUE; ++} ++ ++/* ++ * if we're here, we are in a transaction, so it's safe ++ * to examine the current state of the database ++ */ ++static CK_OBJECT_HANDLE ++sdb_getObjectId(SDB *sdb) ++{ ++ CK_OBJECT_HANDLE candidate; ++ static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE; ++ int count; ++ /* ++ * get an initial object handle to use ++ */ ++ if (next_obj == CK_INVALID_HANDLE) { ++ PRTime time; ++ time = PR_Now(); ++ ++ next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL); ++ } ++ candidate = next_obj++; ++ /* detect that we've looped through all the handles... */ ++ for (count = 0; count < 0x40000000; count++, candidate = next_obj++) { ++ /* mask off excess bits */ ++ candidate &= 0x3fffffff; ++ /* if we hit zero, go to the next entry */ ++ if (candidate == CK_INVALID_HANDLE) { ++ continue; ++ } ++ /* make sure we aren't already using */ ++ if (!sdb_objectExists(sdb, candidate)) { ++ /* this one is free */ ++ return candidate; ++ } ++ } ++ ++ /* no handle is free, fail */ ++ return CK_INVALID_HANDLE; ++} ++ ++CK_RV ++sdb_GetNewObjectID(SDB *sdb, CK_OBJECT_HANDLE *object) ++{ ++ CK_OBJECT_HANDLE id; ++ ++ id = sdb_getObjectId(sdb); ++ if (id == CK_INVALID_HANDLE) { ++ return CKR_DEVICE_MEMORY; /* basically we ran out of resources */ ++ } ++ *object = id; ++ return CKR_OK; ++} ++ ++static const char CREATE_CMD[] = "INSERT INTO %s (id%s) VALUES($ID%s);"; ++CK_RV ++sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, ++ const CK_ATTRIBUTE *template, CK_ULONG count) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ char *columnStr = NULL; ++ char *valueStr = NULL; ++ char *newStr = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ CK_OBJECT_HANDLE this_object = CK_INVALID_HANDLE; ++ int retry = 0; ++ unsigned int i; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ if ((*object_id != CK_INVALID_HANDLE) && ++ !sdb_objectExists(sdb, *object_id)) { ++ this_object = *object_id; ++ } else { ++ this_object = sdb_getObjectId(sdb); ++ } ++ if (this_object == CK_INVALID_HANDLE) { ++ UNLOCK_SQLITE(); ++ return CKR_HOST_MEMORY; ++ } ++ columnStr = sqlite3_mprintf(""); ++ valueStr = sqlite3_mprintf(""); ++ *object_id = this_object; ++ for (i = 0; columnStr && valueStr && i < count; i++) { ++ newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type); ++ sqlite3_free(columnStr); ++ columnStr = newStr; ++ newStr = sqlite3_mprintf("%s,$VALUE%d", valueStr, i); ++ sqlite3_free(valueStr); ++ valueStr = newStr; ++ } ++ newStr = NULL; ++ if ((columnStr == NULL) || (valueStr == NULL)) { ++ if (columnStr) { ++ sqlite3_free(columnStr); ++ } ++ if (valueStr) { ++ sqlite3_free(valueStr); ++ } ++ UNLOCK_SQLITE() ++ return CKR_HOST_MEMORY; ++ } ++ newStr = sqlite3_mprintf(CREATE_CMD, sdb_p->table, columnStr, valueStr); ++ sqlite3_free(columnStr); ++ sqlite3_free(valueStr); ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_int(stmt, 1, *object_id); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ for (i = 0; i < count; i++) { ++ if (template[i].ulValueLen) { ++ sqlerr = sqlite3_bind_blob(stmt, i + 2, template[i].pValue, ++ template[i].ulValueLen, SQLITE_STATIC); ++ } else { ++ sqlerr = sqlite3_bind_blob(stmt, i + 2, SQLITE_EXPLICIT_NULL, ++ SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ if (newStr) { ++ sqlite3_free(newStr); ++ } ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ ++ return error; ++} ++ ++/* ++ * Generic destroy that can destroy metadata or objects ++ */ ++static const char DESTROY_CMD[] = "DELETE FROM %s WHERE (id=$ID);"; ++CK_RV ++sdb_destroyAnyObject(SDB *sdb, const char *table, ++ CK_OBJECT_HANDLE object_id, const char *string_id) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ char *newStr = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ newStr = sqlite3_mprintf(DESTROY_CMD, table); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ if (string_id == NULL) { ++ sqlerr = sqlite3_bind_int(stmt, 1, object_id); ++ } else { ++ sqlerr = sqlite3_bind_text(stmt, 1, string_id, ++ PORT_Strlen(string_id), SQLITE_STATIC); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++CK_RV ++sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ return sdb_destroyAnyObject(sdb, sdb_p->table, object_id, NULL); ++} ++ ++CK_RV ++sdb_DestroyMetaData(SDB *sdb, const char *id) ++{ ++ return sdb_destroyAnyObject(sdb, "metaData", 0, id); ++} ++ ++static const char BEGIN_CMD[] = "BEGIN IMMEDIATE TRANSACTION;"; ++ ++/* ++ * start a transaction. ++ * ++ * We need to open a new database, then store that new database into ++ * the private data structure. We open the database first, then use locks ++ * to protect storing the data to prevent deadlocks. ++ */ ++CK_RV ++sdb_Begin(SDB *sdb) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ ++ /* get a new version that we will use for the entire transaction */ ++ sqlerr = sdb_openDB(sdb_p->sqlDBName, &sqlDB, SDB_RDWR); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ sqlerr = sqlite3_prepare_v2(sqlDB, BEGIN_CMD, -1, &stmt, NULL); ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ /* don't retry BEGIN transaction*/ ++ retry = 0; ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++loser: ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ ++ /* we are starting a new transaction, ++ * and if we succeeded, then save this database for the rest of ++ * our transaction */ ++ if (error == CKR_OK) { ++ /* we hold a 'BEGIN TRANSACTION' and a sdb_p->lock. At this point ++ * sdb_p->sqlXactDB MUST be null */ ++ PR_EnterMonitor(sdb_p->dbMon); ++ PORT_Assert(sdb_p->sqlXactDB == NULL); ++ sdb_p->sqlXactDB = sqlDB; ++ sdb_p->sqlXactThread = PR_GetCurrentThread(); ++ PR_ExitMonitor(sdb_p->dbMon); ++ } else { ++ /* we failed to start our transaction, ++ * free any databases we opened. */ ++ if (sqlDB) { ++ sqlite3_close(sqlDB); ++ } ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++/* ++ * Complete a transaction. Basically undo everything we did in begin. ++ * There are 2 flavors Abort and Commit. Basically the only differerence between ++ * these 2 are what the database will show. (no change in to former, change in ++ * the latter). ++ */ ++static CK_RV ++sdb_complete(SDB *sdb, const char *cmd) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ /* We must have a transation database, or we shouldn't have arrived here */ ++ PR_EnterMonitor(sdb_p->dbMon); ++ PORT_Assert(sdb_p->sqlXactDB); ++ if (sdb_p->sqlXactDB == NULL) { ++ PR_ExitMonitor(sdb_p->dbMon); ++ return CKR_GENERAL_ERROR; /* shouldn't happen */ ++ } ++ PORT_Assert(sdb_p->sqlXactThread == PR_GetCurrentThread()); ++ if (sdb_p->sqlXactThread != PR_GetCurrentThread()) { ++ PR_ExitMonitor(sdb_p->dbMon); ++ return CKR_GENERAL_ERROR; /* shouldn't happen */ ++ } ++ sqlDB = sdb_p->sqlXactDB; ++ sdb_p->sqlXactDB = NULL; /* no one else can get to this DB, ++ * safe to unlock */ ++ sdb_p->sqlXactThread = NULL; ++ PR_ExitMonitor(sdb_p->dbMon); ++ ++ sqlerr = sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ /* Pending BEGIN TRANSACTIONS Can move forward at this point. */ ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ /* we we have a cached DB image, update it as well */ ++ if (sdb_p->cacheTable) { ++ PR_EnterMonitor(sdb_p->dbMon); ++ sdb_updateCache(sdb_p); ++ PR_ExitMonitor(sdb_p->dbMon); ++ } ++ ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ ++ /* We just finished a transaction. ++ * Free the database, and remove it from the list */ ++ sqlite3_close(sqlDB); ++ ++ return error; ++} ++ ++static const char COMMIT_CMD[] = "COMMIT TRANSACTION;"; ++CK_RV ++sdb_Commit(SDB *sdb) ++{ ++ CK_RV crv; ++ LOCK_SQLITE() ++ crv = sdb_complete(sdb, COMMIT_CMD); ++ UNLOCK_SQLITE() ++ return crv; ++} ++ ++static const char ROLLBACK_CMD[] = "ROLLBACK TRANSACTION;"; ++CK_RV ++sdb_Abort(SDB *sdb) ++{ ++ CK_RV crv; ++ LOCK_SQLITE() ++ crv = sdb_complete(sdb, ROLLBACK_CMD); ++ UNLOCK_SQLITE() ++ return crv; ++} ++ ++static int tableExists(sqlite3 *sqlDB, const char *tableName); ++ ++static const char GET_PW_CMD[] = "SELECT ALL * FROM metaData WHERE id=$ID;"; ++CK_RV ++sdb_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = sdb_p->sqlXactDB; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int found = 0; ++ int retry = 0; ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ /* handle 'test' versions of the sqlite db */ ++ sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); ++ /* Sigh, if we created a new table since we opened the database, ++ * the database handle will not see the new table, we need to close this ++ * database and reopen it. This is safe because we are holding the lock ++ * still. */ ++ if (sqlerr == SQLITE_SCHEMA) { ++ sqlerr = sdb_reopenDBLocal(sdb_p, &sqlDB); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); ++ } ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ const char *blobData; ++ unsigned int len = item1->len; ++ item1->len = sqlite3_column_bytes(stmt, 1); ++ if (item1->len > len) { ++ error = CKR_BUFFER_TOO_SMALL; ++ continue; ++ } ++ blobData = sqlite3_column_blob(stmt, 1); ++ PORT_Memcpy(item1->data, blobData, item1->len); ++ if (item2) { ++ len = item2->len; ++ item2->len = sqlite3_column_bytes(stmt, 2); ++ if (item2->len > len) { ++ error = CKR_BUFFER_TOO_SMALL; ++ continue; ++ } ++ blobData = sqlite3_column_blob(stmt, 2); ++ PORT_Memcpy(item2->data, blobData, item2->len); ++ } ++ found = 1; ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ if (!found && error == CKR_OK) { ++ error = CKR_OBJECT_HANDLE_INVALID; ++ } ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ ++ return error; ++} ++ ++static const char PW_CREATE_TABLE_CMD[] = ++ "CREATE TABLE metaData (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, item1, item2);"; ++static const char PW_CREATE_CMD[] = ++ "INSERT INTO metaData (id,item1,item2) VALUES($ID,$ITEM1,$ITEM2);"; ++static const char MD_CREATE_CMD[] = ++ "INSERT INTO metaData (id,item1) VALUES($ID,$ITEM1);"; ++ ++CK_RV ++sdb_PutMetaData(SDB *sdb, const char *id, const SECItem *item1, ++ const SECItem *item2) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = sdb_p->sqlXactDB; ++ sqlite3_stmt *stmt = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ int retry = 0; ++ const char *cmd = PW_CREATE_CMD; ++ ++ if ((sdb->sdb_flags & SDB_RDONLY) != 0) { ++ return CKR_TOKEN_WRITE_PROTECTED; ++ } ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ if (!tableExists(sqlDB, "metaData")) { ++ sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ if (item2 == NULL) { ++ cmd = MD_CREATE_CMD; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ sqlerr = sqlite3_bind_blob(stmt, 2, item1->data, item1->len, SQLITE_STATIC); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ if (item2) { ++ sqlerr = sqlite3_bind_blob(stmt, 3, item2->data, ++ item2->len, SQLITE_STATIC); ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (stmt) { ++ sqlite3_reset(stmt); ++ sqlite3_finalize(stmt); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ UNLOCK_SQLITE() ++ ++ return error; ++} ++ ++static const char RESET_CMD[] = "DELETE FROM %s;"; ++CK_RV ++sdb_Reset(SDB *sdb) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ sqlite3 *sqlDB = NULL; ++ char *newStr; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ ++ /* only Key databases can be reset */ ++ if (sdb_p->type != SDB_KEY) { ++ return CKR_OBJECT_HANDLE_INVALID; ++ } ++ ++ LOCK_SQLITE() ++ error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ ++ if (tableExists(sqlDB, sdb_p->table)) { ++ /* delete the contents of the key table */ ++ newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ ++ if (sqlerr != SQLITE_OK) ++ goto loser; ++ } ++ ++ /* delete the password entry table */ ++ sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;", ++ NULL, 0, NULL); ++ ++loser: ++ /* fix up the error if necessary */ ++ if (error == CKR_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ } ++ ++ if (sqlDB) { ++ sdb_closeDBLocal(sdb_p, sqlDB); ++ } ++ ++ UNLOCK_SQLITE() ++ return error; ++} ++ ++CK_RV ++sdb_Close(SDB *sdb) ++{ ++ SDBPrivate *sdb_p = sdb->private; ++ int sqlerr = SQLITE_OK; ++ sdbDataType type = sdb_p->type; ++ ++ sqlerr = sqlite3_close(sdb_p->sqlReadDB); ++ PORT_Free(sdb_p->sqlDBName); ++ if (sdb_p->cacheTable) { ++ sqlite3_free(sdb_p->cacheTable); ++ } ++ if (sdb_p->dbMon) { ++ PR_DestroyMonitor(sdb_p->dbMon); ++ } ++ free(sdb_p->schemaAttrs); ++ free(sdb_p); ++ free(sdb); ++ return sdb_mapSQLError(type, sqlerr); ++} ++ ++/* ++ * functions to support open ++ */ ++ ++static const char CHECK_TABLE_CMD[] = "SELECT ALL * FROM %s LIMIT 0;"; ++ ++/* return 1 if sqlDB contains table 'tableName */ ++static int ++tableExists(sqlite3 *sqlDB, const char *tableName) ++{ ++ char *cmd = sqlite3_mprintf(CHECK_TABLE_CMD, tableName); ++ int sqlerr = SQLITE_OK; ++ ++ if (cmd == NULL) { ++ return 0; ++ } ++ ++ sqlerr = sqlite3_exec(sqlDB, cmd, NULL, 0, 0); ++ sqlite3_free(cmd); ++ ++ return (sqlerr == SQLITE_OK) ? 1 : 0; ++} ++ ++void ++sdb_SetForkState(PRBool forked) ++{ ++ /* XXXright now this is a no-op. The global fork state in the softokn3 ++ * shared library is already taken care of at the PKCS#11 level. ++ * If and when we add fork state to the sqlite shared library and extern ++ * interface, we will need to set it and reset it from here */ ++} ++ ++static int ++sdb_attributeComparator(const void *a, const void *b) ++{ ++ if (*(CK_ATTRIBUTE_TYPE *)a < *(CK_ATTRIBUTE_TYPE *)b) { ++ return -1; ++ } ++ if (*(CK_ATTRIBUTE_TYPE *)a > *(CK_ATTRIBUTE_TYPE *)b) { ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * initialize a single database ++ */ ++static const char INIT_CMD[] = ++ "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)"; ++ ++CK_RV ++sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, ++ int *newInit, int inFlags, PRUint32 accessOps, SDB **pSdb) ++{ ++ int i; ++ char *initStr = NULL; ++ char *newStr; ++ char *queryStr = NULL; ++ int inTransaction = 0; ++ SDB *sdb = NULL; ++ SDBPrivate *sdb_p = NULL; ++ sqlite3 *sqlDB = NULL; ++ int sqlerr = SQLITE_OK; ++ CK_RV error = CKR_OK; ++ char *cacheTable = NULL; ++ PRIntervalTime now = 0; ++ char *env; ++ PRBool enableCache = PR_FALSE; ++ PRBool checkFSType = PR_FALSE; ++ PRBool measureSpeed = PR_FALSE; ++ PRBool create; ++ int flags = inFlags & 0x7; ++ ++ *pSdb = NULL; ++ *inUpdate = 0; ++ ++ /* sqlite3 doesn't have a flag to specify that we want to ++ * open the database read only. If the db doesn't exist, ++ * sqlite3 will always create it. ++ */ ++ LOCK_SQLITE(); ++ create = (_NSSUTIL_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS); ++ if ((flags == SDB_RDONLY) && create) { ++ error = sdb_mapSQLError(type, SQLITE_CANTOPEN); ++ goto loser; ++ } ++ sqlerr = sdb_openDB(dbname, &sqlDB, flags); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ /* ++ * SQL created the file, but it doesn't set appropriate modes for ++ * a database. ++ * ++ * NO NSPR call for chmod? :( ++ */ ++ if (create && sdb_chmod(dbname, 0600) != 0) { ++ error = sdb_mapSQLError(type, SQLITE_CANTOPEN); ++ goto loser; ++ } ++ ++ if (flags != SDB_RDONLY) { ++ sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ inTransaction = 1; ++ } ++ if (!tableExists(sqlDB, table)) { ++ *newInit = 1; ++ if (flags != SDB_CREATE) { ++ error = sdb_mapSQLError(type, SQLITE_CANTOPEN); ++ goto loser; ++ } ++ initStr = sqlite3_mprintf(""); ++ for (i = 0; initStr && i < known_attributes_size; i++) { ++ newStr = sqlite3_mprintf("%s, a%x", initStr, known_attributes[i]); ++ sqlite3_free(initStr); ++ initStr = newStr; ++ } ++ if (initStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(INIT_CMD, table, initStr); ++ sqlite3_free(initStr); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, table); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, table); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, table); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ ++ newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, table); ++ if (newStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); ++ sqlite3_free(newStr); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(type, sqlerr); ++ goto loser; ++ } ++ } ++ /* ++ * detect the case where we have created the database, but have ++ * not yet updated it. ++ * ++ * We only check the Key database because only the key database has ++ * a metaData table. The metaData table is created when a password ++ * is set, or in the case of update, when a password is supplied. ++ * If no key database exists, then the update would have happened immediately ++ * on noticing that the cert database didn't exist (see newInit set above). ++ */ ++ if (type == SDB_KEY && !tableExists(sqlDB, "metaData")) { ++ *newInit = 1; ++ } ++ ++ /* access to network filesystems are significantly slower than local ones ++ * for database operations. In those cases we need to create a cached copy ++ * of the database in a temporary location on the local disk. SQLITE ++ * already provides a way to create a temporary table and initialize it, ++ * so we use it for the cache (see sdb_buildCache for how it's done).*/ ++ ++ /* ++ * we decide whether or not to use the cache based on the following input. ++ * ++ * NSS_SDB_USE_CACHE environment variable is set to anything other than ++ * "yes" or "no" (for instance, "auto"): NSS will measure the performance ++ * of access to the temp database versus the access to the user's ++ * passed-in database location. If the temp database location is ++ * "significantly" faster we will use the cache. ++ * ++ * NSS_SDB_USE_CACHE environment variable is nonexistent or set to "no": ++ * cache will not be used. ++ * ++ * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will ++ * always be used. ++ * ++ * It is expected that most applications will not need this feature, and ++ * thus it is disabled by default. ++ */ ++ ++ env = PR_GetEnvSecure("NSS_SDB_USE_CACHE"); ++ ++ /* Variables enableCache, checkFSType, measureSpeed are PR_FALSE by default, ++ * which is the expected behavior for NSS_SDB_USE_CACHE="no". ++ * We don't need to check for "no" here. */ ++ if (!env) { ++ /* By default, with no variable set, we avoid expensive measuring for ++ * most FS types. We start with inexpensive FS type checking, and ++ * might perform measuring for some types. */ ++ checkFSType = PR_TRUE; ++ } else if (PORT_Strcasecmp(env, "yes") == 0) { ++ enableCache = PR_TRUE; ++ } else if (PORT_Strcasecmp(env, "no") != 0) { /* not "no" => "auto" */ ++ measureSpeed = PR_TRUE; ++ } ++ ++ if (checkFSType) { ++#if defined(LINUX) && !defined(ANDROID) ++ struct statfs statfs_s; ++ if (statfs(dbname, &statfs_s) == 0) { ++ switch (statfs_s.f_type) { ++ case SMB_SUPER_MAGIC: ++ case 0xff534d42: /* CIFS_MAGIC_NUMBER */ ++ case NFS_SUPER_MAGIC: ++ /* We assume these are slow. */ ++ enableCache = PR_TRUE; ++ break; ++ case CODA_SUPER_MAGIC: ++ case 0x65735546: /* FUSE_SUPER_MAGIC */ ++ case NCP_SUPER_MAGIC: ++ /* It's uncertain if this FS is fast or slow. ++ * It seems reasonable to perform slow measuring for users ++ * with questionable FS speed. */ ++ measureSpeed = PR_TRUE; ++ break; ++ case AFS_SUPER_MAGIC: /* Already implements caching. */ ++ default: ++ break; ++ } ++ } ++#endif ++ } ++ ++ if (measureSpeed) { ++ char *tempDir = NULL; ++ PRUint32 tempOps = 0; ++ /* ++ * Use PR_Access to determine how expensive it ++ * is to check for the existance of a local file compared to the same ++ * check in the temp directory. If the temp directory is faster, cache ++ * the database there. */ ++ tempDir = sdb_getTempDir(sqlDB); ++ if (tempDir) { ++ tempOps = sdb_measureAccess(tempDir); ++ PORT_Free(tempDir); ++ ++ /* There is a cost to continually copying the database. ++ * Account for that cost with the arbitrary factor of 10 */ ++ enableCache = (PRBool)(tempOps > accessOps * 10); ++ } ++ } ++ ++ if (enableCache) { ++ /* try to set the temp store to memory.*/ ++ sqlite3_exec(sqlDB, "PRAGMA temp_store=MEMORY", NULL, 0, NULL); ++ /* Failure to set the temp store to memory is not fatal, ++ * ignore the error */ ++ ++ cacheTable = sqlite3_mprintf("%sCache", table); ++ if (cacheTable == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ /* build the cache table */ ++ error = sdb_buildCache(sqlDB, type, cacheTable, table); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ /* initialize the last cache build time */ ++ now = PR_IntervalNow(); ++ } ++ ++ sdb = (SDB *)malloc(sizeof(SDB)); ++ if (!sdb) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sdb_p = (SDBPrivate *)malloc(sizeof(SDBPrivate)); ++ if (!sdb_p) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ ++ /* Cache the attributes that are held in the table, so we can later check ++ * that queried attributes actually exist. We don't assume the schema ++ * to be exactly |known_attributes|, as it may change over time. */ ++ sdb_p->schemaAttrs = NULL; ++ if (!PORT_Strcmp("nssPublic", table) || ++ !PORT_Strcmp("nssPrivate", table)) { ++ sqlite3_stmt *stmt = NULL; ++ int retry = 0; ++ unsigned int backedAttrs = 0; ++ ++ /* Can't bind parameters to a PRAGMA. */ ++ queryStr = sqlite3_mprintf("PRAGMA table_info(%s);", table); ++ if (queryStr == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ sqlerr = sqlite3_prepare_v2(sqlDB, queryStr, -1, &stmt, NULL); ++ sqlite3_free(queryStr); ++ queryStr = NULL; ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ unsigned int schemaAttrsCapacity = known_attributes_size; ++ sdb_p->schemaAttrs = malloc(schemaAttrsCapacity * sizeof(CK_ATTRIBUTE_TYPE)); ++ if (!sdb_p->schemaAttrs) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ do { ++ sqlerr = sqlite3_step(stmt); ++ if (sqlerr == SQLITE_BUSY) { ++ PR_Sleep(SDB_BUSY_RETRY_TIME); ++ } ++ if (sqlerr == SQLITE_ROW) { ++ if (backedAttrs == schemaAttrsCapacity) { ++ schemaAttrsCapacity += known_attributes_size; ++ sdb_p->schemaAttrs = realloc(sdb_p->schemaAttrs, ++ schemaAttrsCapacity * sizeof(CK_ATTRIBUTE_TYPE)); ++ if (!sdb_p->schemaAttrs) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ } ++ /* Record the ULONG attribute value. */ ++ char *val = (char *)sqlite3_column_text(stmt, 1); ++ if (val && val[0] == 'a') { ++ CK_ATTRIBUTE_TYPE attr = strtoul(&val[1], NULL, 16); ++ sdb_p->schemaAttrs[backedAttrs++] = attr; ++ } ++ } ++ } while (!sdb_done(sqlerr, &retry)); ++ ++ if (sqlerr != SQLITE_DONE) { ++ goto loser; ++ } ++ sqlerr = sqlite3_reset(stmt); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ sqlerr = sqlite3_finalize(stmt); ++ if (sqlerr != SQLITE_OK) { ++ goto loser; ++ } ++ ++ sdb_p->numSchemaAttrs = backedAttrs; ++ ++ /* Sort these once so we can shortcut invalid attribute searches. */ ++ qsort(sdb_p->schemaAttrs, sdb_p->numSchemaAttrs, ++ sizeof(CK_ATTRIBUTE_TYPE), sdb_attributeComparator); ++ } ++ ++ /* invariant fields */ ++ sdb_p->sqlDBName = PORT_Strdup(dbname); ++ sdb_p->type = type; ++ sdb_p->table = table; ++ sdb_p->cacheTable = cacheTable; ++ sdb_p->lastUpdateTime = now; ++ /* set the cache delay time. This is how long we will wait before we ++ * decide the existing cache is stale. Currently set to 10 sec */ ++ sdb_p->updateInterval = PR_SecondsToInterval(10); ++ sdb_p->dbMon = PR_NewMonitor(); ++ /* these fields are protected by the lock */ ++ sdb_p->sqlXactDB = NULL; ++ sdb_p->sqlXactThread = NULL; ++ sdb->private = sdb_p; ++ sdb->version = 1; ++ sdb->sdb_flags = inFlags | SDB_HAS_META; ++ sdb->app_private = NULL; ++ sdb->sdb_FindObjectsInit = sdb_FindObjectsInit; ++ sdb->sdb_FindObjects = sdb_FindObjects; ++ sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal; ++ sdb->sdb_GetAttributeValue = sdb_GetAttributeValue; ++ sdb->sdb_SetAttributeValue = sdb_SetAttributeValue; ++ sdb->sdb_CreateObject = sdb_CreateObject; ++ sdb->sdb_DestroyObject = sdb_DestroyObject; ++ sdb->sdb_GetMetaData = sdb_GetMetaData; ++ sdb->sdb_PutMetaData = sdb_PutMetaData; ++ sdb->sdb_DestroyMetaData = sdb_DestroyMetaData; ++ sdb->sdb_Begin = sdb_Begin; ++ sdb->sdb_Commit = sdb_Commit; ++ sdb->sdb_Abort = sdb_Abort; ++ sdb->sdb_Reset = sdb_Reset; ++ sdb->sdb_Close = sdb_Close; ++ sdb->sdb_SetForkState = sdb_SetForkState; ++ sdb->sdb_GetNewObjectID = sdb_GetNewObjectID; ++ ++ if (inTransaction) { ++ sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL); ++ if (sqlerr != SQLITE_OK) { ++ error = sdb_mapSQLError(sdb_p->type, sqlerr); ++ goto loser; ++ } ++ inTransaction = 0; ++ } ++ ++ sdb_p->sqlReadDB = sqlDB; ++ ++ *pSdb = sdb; ++ UNLOCK_SQLITE(); ++ return CKR_OK; ++ ++loser: ++ /* lots of stuff to do */ ++ if (inTransaction) { ++ sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL); ++ } ++ if (sdb) { ++ free(sdb); ++ } ++ if (sdb_p) { ++ if (sdb_p->schemaAttrs) { ++ free(sdb_p->schemaAttrs); ++ } ++ free(sdb_p); ++ } ++ if (sqlDB) { ++ sqlite3_close(sqlDB); ++ } ++ UNLOCK_SQLITE(); ++ return error; ++} ++ ++/* sdbopen */ ++CK_RV ++s_open(const char *directory, const char *certPrefix, const char *keyPrefix, ++ int cert_version, int key_version, int flags, ++ SDB **certdb, SDB **keydb, int *newInit) ++{ ++ char *cert = sdb_BuildFileName(directory, certPrefix, ++ "cert", cert_version); ++ char *key = sdb_BuildFileName(directory, keyPrefix, ++ "key", key_version); ++ CK_RV error = CKR_OK; ++ int inUpdate; ++ PRUint32 accessOps; ++ ++ if (certdb) ++ *certdb = NULL; ++ if (keydb) ++ *keydb = NULL; ++ *newInit = 0; ++ ++#ifdef SQLITE_UNSAFE_THREADS ++ if (sqlite_lock == NULL) { ++ sqlite_lock = PR_NewLock(); ++ if (sqlite_lock == NULL) { ++ error = CKR_HOST_MEMORY; ++ goto loser; ++ } ++ } ++#endif ++ ++ /* how long does it take to test for a non-existant file in our working ++ * directory? Allows us to test if we may be on a network file system */ ++ accessOps = 1; ++ { ++ char *env; ++ env = PR_GetEnvSecure("NSS_SDB_USE_CACHE"); ++ /* If the environment variable is undefined or set to yes or no, ++ * sdb_init() will ignore the value of accessOps, and we can skip the ++ * measuring.*/ ++ if (env && PORT_Strcasecmp(env, "no") != 0 && ++ PORT_Strcasecmp(env, "yes") != 0) { ++ accessOps = sdb_measureAccess(directory); ++ } ++ } ++ ++ /* ++ * open the cert data base ++ */ ++ if (certdb) { ++ /* initialize Certificate database */ ++ error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate, ++ newInit, flags, accessOps, certdb); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ } ++ ++ /* ++ * open the key data base: ++ * NOTE:if we want to implement a single database, we open ++ * the same database file as the certificate here. ++ * ++ * cert an key db's have different tables, so they will not ++ * conflict. ++ */ ++ if (keydb) { ++ /* initialize the Key database */ ++ error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, ++ newInit, flags, accessOps, keydb); ++ if (error != CKR_OK) { ++ goto loser; ++ } ++ } ++ ++loser: ++ if (cert) { ++ sqlite3_free(cert); ++ } ++ if (key) { ++ sqlite3_free(key); ++ } ++ ++ if (error != CKR_OK) { ++ /* currently redundant, but could be necessary if more code is added ++ * just before loser */ ++ if (keydb && *keydb) { ++ sdb_Close(*keydb); ++ } ++ if (certdb && *certdb) { ++ sdb_Close(*certdb); ++ } ++ } ++ ++ return error; ++} ++ ++CK_RV ++s_shutdown() ++{ ++#ifdef SQLITE_UNSAFE_THREADS ++ if (sqlite_lock) { ++ PR_DestroyLock(sqlite_lock); ++ sqlite_lock = NULL; ++ } ++#endif ++ return CKR_OK; ++} +diff --git a/cmd/manifest.mn b/cmd/manifest.mn +--- a/cmd/manifest.mn ++++ b/cmd/manifest.mn +@@ -36,16 +36,17 @@ NSS_SRCDIRS = \ + addbuiltin \ + atob \ + btoa \ + certutil \ + chktest \ + crlutil \ + crmftest \ + dbtest \ ++ dbtool \ + derdump \ + digest \ + httpserv \ + listsuites \ + makepqg \ + multinit \ + nss-policy-check \ + ocspclnt \ diff --git a/SOURCES/nss-3.79-distrusted-certs.patch b/SOURCES/nss-3.79-distrusted-certs.patch new file mode 100644 index 0000000..14a5b0c --- /dev/null +++ b/SOURCES/nss-3.79-distrusted-certs.patch @@ -0,0 +1,375 @@ +# HG changeset patch +# User John M. Schanck +# Date 1648094761 0 +# Thu Mar 24 04:06:01 2022 +0000 +# Node ID b722e523d66297fe4bc1fac0ebb06203138eccbb +# Parent 853b64626b19a46f41f4ba9c684490dc15923c94 +Bug 1751305 - Remove expired explicitly distrusted certificates from certdata.txt. r=KathleenWilson + +Differential Revision: https://phabricator.services.mozilla.com/D141919 + +diff --git a/lib/ckfw/builtins/certdata.txt b/lib/ckfw/builtins/certdata.txt +--- a/lib/ckfw/builtins/certdata.txt ++++ b/lib/ckfw/builtins/certdata.txt +@@ -7663,197 +7663,16 @@ CKA_SERIAL_NUMBER MULTILINE_OCTAL + \377\377 + END + CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED + CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED + CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED + CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + + # +-# Certificate "Explicitly Distrusted DigiNotar PKIoverheid G2" +-# +-# Issuer: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Serial Number: 268435455 (0xfffffff) +-# Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Not Valid Before: Wed May 12 08:51:39 2010 +-# Not Valid After : Mon Mar 23 09:50:05 2020 +-# Fingerprint (MD5): 2E:61:A2:D1:78:CE:EE:BF:59:33:B0:23:14:0F:94:1C +-# Fingerprint (SHA1): D5:F2:57:A9:BF:2D:D0:3F:8B:46:57:F9:2B:C9:A4:C6:92:E1:42:42 +-CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "Explicitly Distrusted DigiNotar PKIoverheid G2" +-CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509 +-CKA_SUBJECT MULTILINE_OCTAL +-\060\132\061\013\060\011\006\003\125\004\006\023\002\116\114\061 +-\027\060\025\006\003\125\004\012\014\016\104\151\147\151\116\157 +-\164\141\162\040\102\056\126\056\061\062\060\060\006\003\125\004 +-\003\014\051\104\151\147\151\116\157\164\141\162\040\120\113\111 +-\157\166\145\162\150\145\151\144\040\103\101\040\117\162\147\141 +-\156\151\163\141\164\151\145\040\055\040\107\062 +-END +-CKA_ID UTF8 "0" +-CKA_ISSUER MULTILINE_OCTAL +-\060\132\061\013\060\011\006\003\125\004\006\023\002\116\114\061 +-\027\060\025\006\003\125\004\012\014\016\104\151\147\151\116\157 +-\164\141\162\040\102\056\126\056\061\062\060\060\006\003\125\004 +-\003\014\051\104\151\147\151\116\157\164\141\162\040\120\113\111 +-\157\166\145\162\150\145\151\144\040\103\101\040\117\162\147\141 +-\156\151\163\141\164\151\145\040\055\040\107\062 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\017\377\377\377 +-END +-CKA_VALUE MULTILINE_OCTAL +-\060\202\006\225\060\202\004\175\240\003\002\001\002\002\004\017 +-\377\377\377\060\015\006\011\052\206\110\206\367\015\001\001\013 +-\005\000\060\132\061\013\060\011\006\003\125\004\006\023\002\116 +-\114\061\027\060\025\006\003\125\004\012\014\016\104\151\147\151 +-\116\157\164\141\162\040\102\056\126\056\061\062\060\060\006\003 +-\125\004\003\014\051\104\151\147\151\116\157\164\141\162\040\120 +-\113\111\157\166\145\162\150\145\151\144\040\103\101\040\117\162 +-\147\141\156\151\163\141\164\151\145\040\055\040\107\062\060\036 +-\027\015\061\060\060\065\061\062\060\070\065\061\063\071\132\027 +-\015\062\060\060\063\062\063\060\071\065\060\060\065\132\060\132 +-\061\013\060\011\006\003\125\004\006\023\002\116\114\061\027\060 +-\025\006\003\125\004\012\014\016\104\151\147\151\116\157\164\141 +-\162\040\102\056\126\056\061\062\060\060\006\003\125\004\003\014 +-\051\104\151\147\151\116\157\164\141\162\040\120\113\111\157\166 +-\145\162\150\145\151\144\040\103\101\040\117\162\147\141\156\151 +-\163\141\164\151\145\040\055\040\107\062\060\202\002\042\060\015 +-\006\011\052\206\110\206\367\015\001\001\001\005\000\003\202\002 +-\017\000\060\202\002\012\002\202\002\001\000\261\023\031\017\047 +-\346\154\324\125\206\113\320\354\211\212\105\221\170\254\107\275 +-\107\053\344\374\105\353\117\264\046\163\133\067\323\303\177\366 +-\343\336\327\243\370\055\150\305\010\076\113\224\326\344\207\045 +-\066\153\204\265\030\164\363\050\130\163\057\233\152\317\274\004 +-\036\366\336\335\257\374\113\252\365\333\146\142\045\001\045\202 +-\336\362\227\132\020\156\335\135\251\042\261\004\251\043\163\072 +-\370\161\255\035\317\204\104\353\107\321\257\155\310\174\050\253 +-\307\362\067\172\164\137\137\305\002\024\212\243\132\343\033\154 +-\001\343\135\216\331\150\326\364\011\033\062\334\221\265\054\365 +-\040\353\214\003\155\046\111\270\223\304\205\135\330\322\233\257 +-\126\152\314\005\063\314\240\102\236\064\125\104\234\153\240\324 +-\022\320\053\124\315\267\211\015\345\366\353\350\373\205\001\063 +-\117\172\153\361\235\162\063\226\016\367\262\204\245\245\047\304 +-\047\361\121\163\051\167\272\147\156\376\114\334\264\342\241\241 +-\201\057\071\111\215\103\070\023\316\320\245\134\302\207\072\000 +-\147\145\102\043\361\066\131\012\035\243\121\310\274\243\224\052 +-\061\337\343\074\362\235\032\074\004\260\357\261\012\060\023\163 +-\266\327\363\243\114\001\165\024\205\170\300\327\212\071\130\205 +-\120\372\056\346\305\276\317\213\077\257\217\066\324\045\011\055 +-\322\017\254\162\223\362\277\213\324\120\263\371\025\120\233\231 +-\365\024\331\373\213\221\243\062\046\046\240\370\337\073\140\201 +-\206\203\171\133\053\353\023\075\051\072\301\155\335\275\236\216 +-\207\326\112\256\064\227\005\356\024\246\366\334\070\176\112\351 +-\044\124\007\075\227\150\067\106\153\015\307\250\041\257\023\124 +-\344\011\152\361\115\106\012\311\135\373\233\117\275\336\373\267 +-\124\313\270\070\234\247\071\373\152\055\300\173\215\253\245\247 +-\127\354\112\222\212\063\305\341\040\134\163\330\220\222\053\200 +-\325\017\206\030\151\174\071\117\204\206\274\367\114\133\363\325 +-\264\312\240\302\360\067\042\312\171\122\037\123\346\252\363\220 +-\260\073\335\362\050\375\254\353\305\006\044\240\311\324\057\017 +-\130\375\265\236\354\017\317\262\131\320\242\004\172\070\152\256 +-\162\373\275\360\045\142\224\011\247\005\013\002\003\001\000\001 +-\243\202\001\141\060\202\001\135\060\110\006\003\125\035\040\004 +-\101\060\077\060\075\006\004\125\035\040\000\060\065\060\063\006 +-\010\053\006\001\005\005\007\002\001\026\047\150\164\164\160\072 +-\057\057\167\167\167\056\144\151\147\151\156\157\164\141\162\056 +-\156\154\057\143\160\163\057\160\153\151\157\166\145\162\150\145 +-\151\144\060\017\006\003\125\035\023\001\001\377\004\005\060\003 +-\001\001\377\060\016\006\003\125\035\017\001\001\377\004\004\003 +-\002\001\006\060\201\205\006\003\125\035\043\004\176\060\174\200 +-\024\071\020\213\111\222\134\333\141\022\040\315\111\235\032\216 +-\332\234\147\100\271\241\136\244\134\060\132\061\013\060\011\006 +-\003\125\004\006\023\002\116\114\061\036\060\034\006\003\125\004 +-\012\014\025\123\164\141\141\164\040\144\145\162\040\116\145\144 +-\145\162\154\141\156\144\145\156\061\053\060\051\006\003\125\004 +-\003\014\042\123\164\141\141\164\040\144\145\162\040\116\145\144 +-\145\162\154\141\156\144\145\156\040\122\157\157\164\040\103\101 +-\040\055\040\107\062\202\004\000\230\226\364\060\111\006\003\125 +-\035\037\004\102\060\100\060\076\240\074\240\072\206\070\150\164 +-\164\160\072\057\057\143\162\154\056\160\153\151\157\166\145\162 +-\150\145\151\144\056\156\154\057\104\157\155\117\162\147\141\156 +-\151\163\141\164\151\145\114\141\164\145\163\164\103\122\114\055 +-\107\062\056\143\162\154\060\035\006\003\125\035\016\004\026\004 +-\024\274\135\224\073\331\253\173\003\045\163\141\302\333\055\356 +-\374\253\217\145\241\060\015\006\011\052\206\110\206\367\015\001 +-\001\013\005\000\003\202\002\001\000\217\374\055\114\267\331\055 +-\325\037\275\357\313\364\267\150\027\165\235\116\325\367\335\234 +-\361\052\046\355\237\242\266\034\003\325\123\263\354\010\317\064 +-\342\343\303\364\265\026\057\310\303\276\327\323\163\253\000\066 +-\371\032\112\176\326\143\351\136\106\272\245\266\216\025\267\243 +-\052\330\103\035\357\135\310\037\201\205\263\213\367\377\074\364 +-\331\364\106\010\077\234\274\035\240\331\250\114\315\045\122\116 +-\012\261\040\367\037\351\103\331\124\106\201\023\232\300\136\164 +-\154\052\230\062\352\374\167\273\015\245\242\061\230\042\176\174 +-\174\347\332\244\255\354\267\056\032\031\161\370\110\120\332\103 +-\217\054\204\335\301\100\047\343\265\360\025\116\226\324\370\134 +-\343\206\051\106\053\327\073\007\353\070\177\310\206\127\227\323 +-\357\052\063\304\027\120\325\144\151\153\053\153\105\136\135\057 +-\027\312\132\116\317\303\327\071\074\365\073\237\106\271\233\347 +-\016\111\227\235\326\325\343\033\017\352\217\001\116\232\023\224 +-\131\012\002\007\110\113\032\140\253\177\117\355\013\330\125\015 +-\150\157\125\234\151\145\025\102\354\300\334\335\154\254\303\026 +-\316\013\035\126\233\244\304\304\322\056\340\017\342\104\047\053 +-\120\151\244\334\142\350\212\041\051\102\154\314\000\072\226\166 +-\233\357\100\300\244\136\167\204\062\154\046\052\071\146\256\135 +-\343\271\271\262\054\150\037\036\232\220\003\071\360\252\263\244 +-\314\111\213\030\064\351\067\311\173\051\307\204\174\157\104\025 +-\057\354\141\131\004\311\105\313\242\326\122\242\174\177\051\222 +-\326\112\305\213\102\250\324\376\352\330\307\207\043\030\344\235 +-\172\175\163\100\122\230\240\256\156\343\005\077\005\017\340\245 +-\306\155\115\355\203\067\210\234\307\363\334\102\232\152\266\327 +-\041\111\066\167\362\357\030\117\305\160\331\236\351\336\267\053 +-\213\364\274\176\050\337\015\100\311\205\134\256\235\305\061\377 +-\320\134\016\265\250\176\360\351\057\272\257\210\256\345\265\321 +-\130\245\257\234\161\247\051\001\220\203\151\067\202\005\272\374 +-\011\301\010\156\214\170\073\303\063\002\200\077\104\205\010\035 +-\337\125\126\010\255\054\205\055\135\261\003\341\256\252\164\305 +-\244\363\116\272\067\230\173\202\271 +-END +- +-# Trust for Certificate "Explicitly Distrusted DigiNotar PKIoverheid G2" +-# Issuer: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Serial Number: 268435455 (0xfffffff) +-# Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2,O=DigiNotar B.V.,C=NL +-# Not Valid Before: Wed May 12 08:51:39 2010 +-# Not Valid After : Mon Mar 23 09:50:05 2020 +-# Fingerprint (MD5): 2E:61:A2:D1:78:CE:EE:BF:59:33:B0:23:14:0F:94:1C +-# Fingerprint (SHA1): D5:F2:57:A9:BF:2D:D0:3F:8B:46:57:F9:2B:C9:A4:C6:92:E1:42:42 +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "Explicitly Distrusted DigiNotar PKIoverheid G2" +-CKA_CERT_SHA1_HASH MULTILINE_OCTAL +-\325\362\127\251\277\055\320\077\213\106\127\371\053\311\244\306 +-\222\341\102\102 +-END +-CKA_CERT_MD5_HASH MULTILINE_OCTAL +-\056\141\242\321\170\316\356\277\131\063\260\043\024\017\224\034 +-END +-CKA_ISSUER MULTILINE_OCTAL +-\060\132\061\013\060\011\006\003\125\004\006\023\002\116\114\061 +-\027\060\025\006\003\125\004\012\014\016\104\151\147\151\116\157 +-\164\141\162\040\102\056\126\056\061\062\060\060\006\003\125\004 +-\003\014\051\104\151\147\151\116\157\164\141\162\040\120\113\111 +-\157\166\145\162\150\145\151\144\040\103\101\040\117\162\147\141 +-\156\151\163\141\164\151\145\040\055\040\107\062 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\017\377\377\377 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- +-# + # Certificate "Security Communication RootCA2" + # + # Issuer: OU=Security Communication RootCA2,O="SECOM Trust Systems CO.,LTD.",C=JP + # Serial Number: 0 (0x0) + # Subject: OU=Security Communication RootCA2,O="SECOM Trust Systems CO.,LTD.",C=JP + # Not Valid Before: Fri May 29 05:00:39 2009 + # Not Valid After : Tue May 29 05:00:39 2029 + # Fingerprint (SHA-256): 51:3B:2C:EC:B8:10:D4:CD:E5:DD:85:39:1A:DF:C6:C2:DD:60:D8:7B:B7:36:D2:B5:21:48:4A:A4:7A:0E:BE:F6 +@@ -8337,78 +8156,16 @@ END + CKA_SERIAL_NUMBER MULTILINE_OCTAL + \002\001\000 + END + CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR + CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_TRUSTED_DELEGATOR + CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST + CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +-# Explicitly Distrust "MITM subCA 1 issued by Trustwave", Bug 724929 +-# Issuer: E=ca@trustwave.com,CN="Trustwave Organization Issuing CA, Level 2",O="Trustwave Holdings, Inc.",L=Chicago,ST=Illinois,C=US +-# Serial Number: 1800000005 (0x6b49d205) +-# Not Before: Apr 7 15:37:15 2011 GMT +-# Not After : Apr 4 15:37:15 2021 GMT +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "MITM subCA 1 issued by Trustwave" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\253\061\013\060\011\006\003\125\004\006\023\002\125\123 +-\061\021\060\017\006\003\125\004\010\023\010\111\154\154\151\156 +-\157\151\163\061\020\060\016\006\003\125\004\007\023\007\103\150 +-\151\143\141\147\157\061\041\060\037\006\003\125\004\012\023\030 +-\124\162\165\163\164\167\141\166\145\040\110\157\154\144\151\156 +-\147\163\054\040\111\156\143\056\061\063\060\061\006\003\125\004 +-\003\023\052\124\162\165\163\164\167\141\166\145\040\117\162\147 +-\141\156\151\172\141\164\151\157\156\040\111\163\163\165\151\156 +-\147\040\103\101\054\040\114\145\166\145\154\040\062\061\037\060 +-\035\006\011\052\206\110\206\367\015\001\011\001\026\020\143\141 +-\100\164\162\165\163\164\167\141\166\145\056\143\157\155 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\153\111\322\005 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- +-# Explicitly Distrust "MITM subCA 2 issued by Trustwave", Bug 724929 +-# Issuer: E=ca@trustwave.com,CN="Trustwave Organization Issuing CA, Level 2",O="Trustwave Holdings, Inc.",L=Chicago,ST=Illinois,C=US +-# Serial Number: 1800000006 (0x6b49d206) +-# Not Before: Apr 18 21:09:30 2011 GMT +-# Not After : Apr 15 21:09:30 2021 GMT +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "MITM subCA 2 issued by Trustwave" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\253\061\013\060\011\006\003\125\004\006\023\002\125\123 +-\061\021\060\017\006\003\125\004\010\023\010\111\154\154\151\156 +-\157\151\163\061\020\060\016\006\003\125\004\007\023\007\103\150 +-\151\143\141\147\157\061\041\060\037\006\003\125\004\012\023\030 +-\124\162\165\163\164\167\141\166\145\040\110\157\154\144\151\156 +-\147\163\054\040\111\156\143\056\061\063\060\061\006\003\125\004 +-\003\023\052\124\162\165\163\164\167\141\166\145\040\117\162\147 +-\141\156\151\172\141\164\151\157\156\040\111\163\163\165\151\156 +-\147\040\103\101\054\040\114\145\166\145\154\040\062\061\037\060 +-\035\006\011\052\206\110\206\367\015\001\011\001\026\020\143\141 +-\100\164\162\165\163\164\167\141\166\145\056\143\157\155 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\004\153\111\322\006 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- + # + # Certificate "Actalis Authentication Root CA" + # + # Issuer: CN=Actalis Authentication Root CA,O=Actalis S.p.A./03358520967,L=Milan,C=IT + # Serial Number:57:0a:11:97:42:c4:e3:cc + # Subject: CN=Actalis Authentication Root CA,O=Actalis S.p.A./03358520967,L=Milan,C=IT + # Not Valid Before: Thu Sep 22 11:22:02 2011 + # Not Valid After : Sun Sep 22 11:22:02 2030 +@@ -9042,84 +8799,16 @@ END + CKA_SERIAL_NUMBER MULTILINE_OCTAL + \002\001\001 + END + CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR + CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_MUST_VERIFY_TRUST + CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_MUST_VERIFY_TRUST + CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE + +-# Explicitly Distrust "TURKTRUST Mis-issued Intermediate CA 1", Bug 825022 +-# Issuer: O=T..RKTRUST Bilgi ..leti..im ve Bili..im G..venli..i Hizmetleri A...,C=TR,CN=T..RKTRUST Elektronik Sunucu Sertifikas.. Hizmetleri +-# Serial Number: 2087 (0x827) +-# Subject: CN=*.EGO.GOV.TR,OU=EGO BILGI ISLEM,O=EGO,L=ANKARA,ST=ANKARA,C=TR +-# Not Valid Before: Mon Aug 08 07:07:51 2011 +-# Not Valid After : Tue Jul 06 07:07:51 2021 +-# Fingerprint (MD5): F8:F5:25:FF:0C:31:CF:85:E1:0C:86:17:C1:CE:1F:8E +-# Fingerprint (SHA1): C6:9F:28:C8:25:13:9E:65:A6:46:C4:34:AC:A5:A1:D2:00:29:5D:B1 +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "TURKTRUST Mis-issued Intermediate CA 1" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\254\061\075\060\073\006\003\125\004\003\014\064\124\303 +-\234\122\113\124\122\125\123\124\040\105\154\145\153\164\162\157 +-\156\151\153\040\123\165\156\165\143\165\040\123\145\162\164\151 +-\146\151\153\141\163\304\261\040\110\151\172\155\145\164\154\145 +-\162\151\061\013\060\011\006\003\125\004\006\023\002\124\122\061 +-\136\060\134\006\003\125\004\012\014\125\124\303\234\122\113\124 +-\122\125\123\124\040\102\151\154\147\151\040\304\260\154\145\164 +-\151\305\237\151\155\040\166\145\040\102\151\154\151\305\237\151 +-\155\040\107\303\274\166\145\156\154\151\304\237\151\040\110\151 +-\172\155\145\164\154\145\162\151\040\101\056\305\236\056\040\050 +-\143\051\040\113\141\163\304\261\155\040\040\062\060\060\065 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\002\010\047 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- +-# Explicitly Distrust "TURKTRUST Mis-issued Intermediate CA 2", Bug 825022 +-# Issuer: O=T..RKTRUST Bilgi ..leti..im ve Bili..im G..venli..i Hizmetleri A...,C=TR,CN=T..RKTRUST Elektronik Sunucu Sertifikas.. Hizmetleri +-# Serial Number: 2148 (0x864) +-# Subject: E=ileti@kktcmerkezbankasi.org,CN=e-islem.kktcmerkezbankasi.org,O=KKTC Merkez Bankasi,L=Lefkosa,ST=Lefkosa,C=TR +-# Not Valid Before: Mon Aug 08 07:07:51 2011 +-# Not Valid After : Thu Aug 05 07:07:51 2021 +-# Fingerprint (MD5): BF:C3:EC:AD:0F:42:4F:B4:B5:38:DB:35:BF:AD:84:A2 +-# Fingerprint (SHA1): F9:2B:E5:26:6C:C0:5D:B2:DC:0D:C3:F2:DC:74:E0:2D:EF:D9:49:CB +-CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST +-CKA_TOKEN CK_BBOOL CK_TRUE +-CKA_PRIVATE CK_BBOOL CK_FALSE +-CKA_MODIFIABLE CK_BBOOL CK_FALSE +-CKA_LABEL UTF8 "TURKTRUST Mis-issued Intermediate CA 2" +-CKA_ISSUER MULTILINE_OCTAL +-\060\201\254\061\075\060\073\006\003\125\004\003\014\064\124\303 +-\234\122\113\124\122\125\123\124\040\105\154\145\153\164\162\157 +-\156\151\153\040\123\165\156\165\143\165\040\123\145\162\164\151 +-\146\151\153\141\163\304\261\040\110\151\172\155\145\164\154\145 +-\162\151\061\013\060\011\006\003\125\004\006\023\002\124\122\061 +-\136\060\134\006\003\125\004\012\014\125\124\303\234\122\113\124 +-\122\125\123\124\040\102\151\154\147\151\040\304\260\154\145\164 +-\151\305\237\151\155\040\166\145\040\102\151\154\151\305\237\151 +-\155\040\107\303\274\166\145\156\154\151\304\237\151\040\110\151 +-\172\155\145\164\154\145\162\151\040\101\056\305\236\056\040\050 +-\143\051\040\113\141\163\304\261\155\040\040\062\060\060\065 +-END +-CKA_SERIAL_NUMBER MULTILINE_OCTAL +-\002\002\010\144 +-END +-CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_EMAIL_PROTECTION CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_CODE_SIGNING CK_TRUST CKT_NSS_NOT_TRUSTED +-CKA_TRUST_STEP_UP_APPROVED CK_BBOOL CK_FALSE +- + # + # Certificate "D-TRUST Root Class 3 CA 2 2009" + # + # Issuer: CN=D-TRUST Root Class 3 CA 2 2009,O=D-Trust GmbH,C=DE + # Serial Number: 623603 (0x983f3) + # Subject: CN=D-TRUST Root Class 3 CA 2 2009,O=D-Trust GmbH,C=DE + # Not Valid Before: Thu Nov 05 08:35:58 2009 + # Not Valid After : Mon Nov 05 08:35:58 2029 diff --git a/SOURCES/nss-3.79-dont-verify-default.patch b/SOURCES/nss-3.79-dont-verify-default.patch new file mode 100644 index 0000000..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..561113c --- /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,45 @@ 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 +107,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-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-rhel-9-fips-signature-policy.patch b/SOURCES/nss-3.79-rhel-9-fips-signature-policy.patch new file mode 100644 index 0000000..7d99e18 --- /dev/null +++ b/SOURCES/nss-3.79-rhel-9-fips-signature-policy.patch @@ -0,0 +1,672 @@ +diff -up ./cmd/crmftest/testcrmf.c.signature-policy ./cmd/crmftest/testcrmf.c +--- ./cmd/crmftest/testcrmf.c.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./cmd/crmftest/testcrmf.c 2022-06-21 09:16:23.916905015 -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.signature-policy ./gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc +--- ./gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./gtests/pk11_gtest/pk11_rsapkcs1_unittest.cc 2022-06-21 09:16:23.916905015 -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.signature-policy ./gtests/ssl_gtest/tls_subcerts_unittest.cc +--- ./gtests/ssl_gtest/tls_subcerts_unittest.cc.signature-policy 2022-06-21 09:16:23.901904919 -0700 ++++ ./gtests/ssl_gtest/tls_subcerts_unittest.cc 2022-06-21 09:19:12.482981408 -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" +@@ -357,9 +359,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 +@@ -399,6 +406,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; +@@ -421,6 +440,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.signature-policy ./lib/cryptohi/keyhi.h +--- ./lib/cryptohi/keyhi.h.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/keyhi.h 2022-06-21 09:16:23.917905021 -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.signature-policy ./lib/cryptohi/keyi.h +--- ./lib/cryptohi/keyi.h.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/keyi.h 2022-06-21 09:16:23.917905021 -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.signature-policy ./lib/cryptohi/seckey.c +--- ./lib/cryptohi/seckey.c.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/seckey.c 2022-06-21 09:16:23.917905021 -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.signature-policy ./lib/cryptohi/secsign.c +--- ./lib/cryptohi/secsign.c.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/secsign.c 2022-06-21 09:16:23.917905021 -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.signature-policy ./lib/cryptohi/secvfy.c +--- ./lib/cryptohi/secvfy.c.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/cryptohi/secvfy.c 2022-06-21 09:16:23.918905028 -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.signature-policy ./lib/freebl/blapit.h +--- ./lib/freebl/blapit.h.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/freebl/blapit.h 2022-06-21 09:16:23.918905028 -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.signature-policy ./lib/nss/nss.h +--- ./lib/nss/nss.h.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/nss/nss.h 2022-06-21 09:16:23.918905028 -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.signature-policy ./lib/nss/nssoptions.c +--- ./lib/nss/nssoptions.c.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/nss/nssoptions.c 2022-06-21 09:16:23.918905028 -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.signature-policy ./lib/nss/nssoptions.h +--- ./lib/nss/nssoptions.h.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/nss/nssoptions.h 2022-06-21 09:16:23.918905028 -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.signature-policy ./lib/pk11wrap/pk11kea.c +--- ./lib/pk11wrap/pk11kea.c.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/pk11wrap/pk11kea.c 2022-06-21 09:16:23.918905028 -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.signature-policy ./lib/pk11wrap/pk11pars.c +--- ./lib/pk11wrap/pk11pars.c.signature-policy 2022-06-21 09:16:23.898904900 -0700 ++++ ./lib/pk11wrap/pk11pars.c 2022-06-21 09:16:23.918905028 -0700 +@@ -430,12 +430,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 }, +@@ -543,6 +552,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, +@@ -551,7 +561,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.signature-policy ./lib/ssl/ssl3con.c +--- ./lib/ssl/ssl3con.c.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./lib/ssl/ssl3con.c 2022-06-21 09:16:23.920905040 -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.signature-policy ./tests/policy/crypto-policy.txt +--- ./tests/policy/crypto-policy.txt.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./tests/policy/crypto-policy.txt 2022-06-21 09:16:23.920905040 -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.signature-policy ./tests/ssl/sslpolicy.txt +--- ./tests/ssl/sslpolicy.txt.signature-policy 2022-05-26 02:54:33.000000000 -0700 ++++ ./tests/ssl/sslpolicy.txt 2022-06-21 09:16:23.920905040 -0700 +@@ -194,6 +194,10 @@ + 1 noECC SSL3 d disallow=all_allow=md2/all:md4/all:md5/all:sha1/all:sha256/all:sha384/all:sha512/all:rsa-pkcs/all:rsa-pss/all:ecdsa/all:dsa/all:hmac-sha1/all:hmac-sha224/all:hmac-sha256/all:hmac-sha384/all:hmac-sha512/all:hmac-md5/all:camellia128-cbc/all:camellia192-cbc/all:camellia256-cbc/all:seed-cbc/all:des-ede3-cbc/all:des-40-cbc/all:des-cbc/all:null-cipher/all:rc2/all:rc4/all:idea/all:rsa/all:rsa-export/all:dhe-rsa/all:dhe-dss/all:ecdhe-ecdsa/all:ecdhe-rsa/all:ecdh-ecdsa/all:ecdh-rsa/all:tls-version-min=tls1.0:tls-version-max=tls1.2 Disallow Version Implicitly + 0 noECC SSL3 d disallow=dsa Disallow DSA Signatures Explicitly + 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 --git a/SOURCES/nss-disable-dc.patch b/SOURCES/nss-disable-dc.patch new file mode 100644 index 0000000..6eae5e4 --- /dev/null +++ b/SOURCES/nss-disable-dc.patch @@ -0,0 +1,32 @@ +diff -up ./gtests/ssl_gtest/manifest.mn.orig ./gtests/ssl_gtest/manifest.mn +--- ./gtests/ssl_gtest/manifest.mn.orig 2021-06-02 15:40:48.677355426 -0700 ++++ ./gtests/ssl_gtest/manifest.mn 2021-06-02 15:42:31.248977261 -0700 +@@ -57,7 +57,6 @@ CPPSRCS = \ + tls_filter.cc \ + tls_protect.cc \ + tls_psk_unittest.cc \ +- tls_subcerts_unittest.cc \ + tls_ech_unittest.cc \ + $(SSLKEYLOGFILE_FILES) \ + $(NULL) +diff -up ./lib/ssl/sslsock.c.orig ./lib/ssl/sslsock.c +--- ./lib/ssl/sslsock.c.orig 2021-05-28 02:50:43.000000000 -0700 ++++ ./lib/ssl/sslsock.c 2021-06-02 15:40:48.676355420 -0700 +@@ -819,7 +819,7 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh + break; + + case SSL_ENABLE_DELEGATED_CREDENTIALS: +- ss->opt.enableDelegatedCredentials = val; ++ /* disable it for now */ + break; + + case SSL_ENABLE_NPN: +@@ -1337,7 +1337,7 @@ SSL_OptionSetDefault(PRInt32 which, PRIn + break; + + case SSL_ENABLE_DELEGATED_CREDENTIALS: +- ssl_defaults.enableDelegatedCredentials = val; ++ /* disable it for now */ + break; + + case SSL_ENABLE_NPN: diff --git a/SPECS/nss.spec b/SPECS/nss.spec index 755fc2b..fad31af 100644 --- a/SPECS/nss.spec +++ b/SPECS/nss.spec @@ -1,12 +1,13 @@ -%global nspr_version 4.32.0 +%global nss_version 3.79.0 +%global nspr_version 4.34.0 +%global baserelease 14 +%global nss_release %baserelease # NOTE: To avoid NVR clashes of nspr* packages: -# - reset %%{nspr_release} to 1, when updating %%{nspr_version} -# - increment %%{nspr_version}, when updating the NSS part only -# - put the nss_release number here next to nspr, as they both -# need to be updated on a given release -%global nss_release 7 -%global nspr_release %[ %nss_release+2] -%global nss_version 3.71.0 +# use "%%global nspr_release %%[%%baserelease+n]" to handle offsets when +# release number between nss and nspr are different. +# when a new nspr is released with nss, reset nspr_release to baserelease. +# for each new nss relase with the same nspr, change increment n by one. +%global nspr_release %baserelease # only need to update this as we added new # algorithms under nss policy control %global crypto_policies_version 20210118 @@ -56,6 +57,21 @@ 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} @@ -110,14 +126,13 @@ Source22: pkcs11.txt.xml Source24: cert9.db.xml Source26: key4.db.xml Source28: nss-p11-kit.config -Source30: PayPalEE.cert - +# fips algorithms are tied to the red hat validation, others +# will have their own validation +Source30: fips_algorithms.h Source100: nspr-%{nspr_archive_version}.tar.gz Source101: nspr-config.xml -# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=617723 -Patch2: nss-3.71-ipv6-fix.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, @@ -140,21 +155,37 @@ Patch32: nss-disable-md5.patch %else Patch33: nss-no-dbm-man-page.patch %endif - -# upstream bug https://bugzilla.mozilla.org/show_bug.cgi?id=1729550 -Patch50: nss-3.71-fips-module-name.patch -# upstream bug https://buzilla.mozilla.org/show_bug.cgi?id=1737470 -Patch60: nss-3.67-cve-2021-43527.patch -Patch70: nss-3.67-cve-2021-43527-test.patch # not upstreamable patch... -Patch80: nss-3.71-fix-lto-gtests.patch +Patch34: nss-3.71-fix-lto-gtests.patch # camellia pkcs12 docs. -patch85: nss-3.71-camellia-pkcs12-doc.patch -# fix issue with long passwords in pkcs12 -patch90: nss-3.75-fix-pkcs12-passwords.patch +Patch35: nss-3.71-camellia-pkcs12-doc.patch +# disable delegated credentials +Patch36: nss-disable-dc.patch + +# patches that expect to be upstreamed +# https://bugzilla.mozilla.org/show_bug.cgi?id=1774659 +Patch51: nss-3.79-dbtool.patch +# https://bugzilla.mozilla.org/show_bug.cgi?id=1774657 +Patch52: nss-3.79-dont-verify-default.patch +# https://bugzilla.mozilla.org/show_bug.cgi?id=1774654 +Patch53: nss-3.79-fix-client-cert-crash.patch +# https://bugzilla.mozilla.org/show_bug.cgi?id=1767883 +Patch54: nss-3.79-rhel-9-fips-signature-policy.patch +Patch55: nss-3.79-enable-POST-rerun.patch +Patch56: nss-3.79-increase-pbe-cache.patch +Patch57: nss-3.79-pkcs12-fix-null-password.patch +Patch58: nss-3.79-fips.patch Patch100: nspr-config-pc.patch Patch101: nspr-gcc-atomics.patch +# https://bugzilla.mozilla.org/show_bug.cgi?id=1769293 +Patch110: nspr-4.34-fix-coverity-loop-issue.patch +Patch120: nspr-4.34-server-passive.patch + + +# NSS reverse patches +Patch300: nss-3.79-distrusted-certs.patch + %description Network Security Services (NSS) is a set of libraries designed to @@ -313,17 +344,25 @@ Header files for doing development with the Netscape Portable Runtime. %setup -q -T -b 0 -n %{name}-%{nss_archive_version} mv ../nspr-%{nspr_archive_version}/nspr . cp ./nspr/config/nspr-config.in ./nspr/config/nspr-config-pc.in -%{__cp} %{SOURCE30} -f ./nss/tests/libpkix/certs %patch100 -p0 -b .flags pushd nspr %patch101 -p1 -b .gcc-atomics +%patch110 -p1 -b .coverity +%patch120 -p1 -b .server-passive popd + pushd nss %autopatch -p1 -M 99 +%patch300 -R -p1 popd +# copy the fips_algorithms.h for this release +# this file is release specific and matches what +# each vendors claim in their own FIPS certification +cp %{SOURCE30} nss/lib/softoken/ + # https://bugzilla.redhat.com/show_bug.cgi?id=1247353 find nss/lib/libpkix -perm /u+x -type f -exec chmod -x {} \; @@ -389,24 +428,13 @@ export IN_TREE_FREEBL_HEADERS_FIRST=1 # FIPS related defines export NSS_FORCE_FIPS=1 -export NSS_FIPS_VERSION="%{name}\ %{version}-$(date +%Y%m%d)" -%if %{defined rhel} -%if %{defined centos} - export NSS_FIPS_MODULE_ID="Centos\ %rhel\ ${NSS_FIPS_VERSION}\ unvalidated" -%else -if grep "Red Hat" /etc/system-release; then - export NSS_FIPS_MODULE_ID="Red\ Hat\ Enterprise\ Linux\ %rhel\ ${NSS_FIPS_VERSION}" -else - export NSS_FIPS_MODULE_ID="Generic\ Enterprise\ Linux\ %rhel\ ${NSS_FIPS_VERSION}\ unvalidated" -fi -%endif -%else -%if %{defined fedora} - export NSS_FIPS_MODULE_ID="Fedora\ %fedora\ ${NSS_FIPS_VERSION}\ unvalidated" -%else - export NSS_FIPS_MODULE_ID="Generic\ Linux\ ${NSS_FIPS_VERSION}\ unvalidated" -%endif -%endif +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}" +# remove when the infrastructure is fixed +export NSS_FIPS_140_3=1 +export NSS_ENABLE_FIPS_INDICATORS=1 # Enable compiler optimizations and disable debugging code export BUILD_OPT=1 @@ -433,6 +461,7 @@ export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 export NSPR_INCLUDE_DIR=$PWD/dist/include/nspr +export NSPR_LIB_DIR=$PWD/dist/lib export NSS_USE_SYSTEM_SQLITE=1 @@ -601,6 +630,15 @@ export USE_64=1 # End -- copied from the build section +# copy the nspr libraries into the NSS object directory so we use the +# newly compiled nspr binaries in our test rather than the build root +# versions +export LOBJDIR=`make -s -C ./nss/tests/common objdir_name` +for i in ./dist/lib/*.so +do + cp $i ./dist/${LOBJDIR}/lib +done + # This is necessary because the test suite tests algorithms that are # disabled by the system policy. export NSS_IGNORE_SYSTEM_POLICY=1 @@ -624,9 +662,9 @@ if [ $SPACEISBAD -ne 0 ]; then echo "error: filenames containing space are not supported (xargs)" exit 1 fi -MYRAND=`perl -e 'print 9000 + int rand 1000'`; echo $MYRAND ||: -RANDSERV=selfserv_${MYRAND}; echo $RANDSERV ||: -DISTBINDIR=`ls -d ./dist/*.OBJ/bin`; echo $DISTBINDIR ||: +export MYRAND=`perl -e 'print 9000 + int rand 1000'`; echo $MYRAND +export RANDSERV=selfserv_${MYRAND}; echo $RANDSERV +export DISTBINDIR=./dist/${LOBJDIR}/bin pushd "$DISTBINDIR" ln -s selfserv $RANDSERV popd @@ -685,6 +723,25 @@ for f in nspr-config; do done popd +# Begin -- copied from the build section +# this is needed to make sure LOBJDIR is correct + +export FREEBL_NO_DEPEND=1 + +export BUILD_OPT=1 +export NSS_DISABLE_PPC_GHASH=1 + +%ifnarch noarch +%if 0%{__isa_bits} == 64 +export USE_64=1 +%endif +%endif + +# End -- copied from the build section + +# get the objdir value from the test make file +export LOBJDIR=`make -s -C ./nss/tests/common objdir_name` + # There is no make install target so we'll do it ourselves. mkdir -p $RPM_BUILD_ROOT/%{_includedir}/nss3 @@ -713,7 +770,7 @@ mkdir -p $RPM_BUILD_ROOT%{_mandir}/man5 # Copy the binary libraries we want for file in libnssutil3.so libsoftokn3.so %{?with_dbm:libnssdbm3.so} libfreebl3.so libfreeblpriv3.so libnss3.so libnsssysinit.so libsmime3.so libssl3.so do - install -p -m 755 dist/*.OBJ/lib/$file $RPM_BUILD_ROOT/%{_libdir} + install -p -m 755 dist/${LOBJDIR}/lib/$file $RPM_BUILD_ROOT/%{_libdir} done # Install the empty NSS db files @@ -732,19 +789,19 @@ install -p -m 644 %{SOURCE15} $RPM_BUILD_ROOT/%{_sysconfdir}/pki/nssdb/pkcs11.tx # Copy the development libraries we want for file in libcrmf.a libnssb.a libnssckfw.a do - install -p -m 644 dist/*.OBJ/lib/$file $RPM_BUILD_ROOT/%{_libdir} + install -p -m 644 dist/${LOBJDIR}/lib/$file $RPM_BUILD_ROOT/%{_libdir} done # Copy the binaries we want for file in certutil cmsutil crlutil modutil nss-policy-check pk12util signver ssltap do - install -p -m 755 dist/*.OBJ/bin/$file $RPM_BUILD_ROOT/%{_bindir} + install -p -m 755 dist/${LOBJDIR}/bin/$file $RPM_BUILD_ROOT/%{_bindir} 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 validation 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} + install -p -m 755 dist/${LOBJDIR}/bin/$file $RPM_BUILD_ROOT/%{unsupported_tools_directory} done # Copy the include files we want @@ -762,7 +819,7 @@ done # Copy the static freebl library for file in libfreebl.a do -install -p -m 644 dist/*.OBJ/lib/$file $RPM_BUILD_ROOT/%{_libdir} +install -p -m 644 dist/${LOBJDIR}/lib/$file $RPM_BUILD_ROOT/%{_libdir} done # Copy the template files we want @@ -1047,6 +1104,7 @@ update-crypto-policies &> /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 @@ -1107,6 +1165,55 @@ update-crypto-policies &> /dev/null || : %changelog +* Wed Aug 24 2022 Bob Relyea - 3.79.0-14 +- Update fips_algorithms.h to match the final FIPS requirements +- Disable delegated credentials + +* Wed Aug 24 2022 Bob Relyea - 3.79.0-13 +- remove OAEP from the FIPS indicators + +* Thu Aug 11 2022 Bob Relyea - 3.79.0-12 +- only turn off rand changes on all non-fips kernels + +* Mon Aug 8 2022 Bob Relyea - 3.79.0-11 +- only turn off rand changes on ppc64le at build-test time. + +* Mon Aug 8 2022 Bob Relyea - 3.79.0-10 +- turn off rand changes on ppc64le + +* Sun Aug 7 2022 Bob Relyea - 3.79.0-9 +- FIPS 140-3 changes + +* Thu Jul 21 2022 Bob Relyea - 3.79.0-8 +- fix encoding issue with NULL passwords + +* Thu Jul 7 2022 Bob Relyea - 3.79.0-7 +- more complete fix for cert auth regression crash + +* Wed Jun 22 2022 Bob Relyea - 3.79.0-6 +- Remove debugging printf from a patch +- increase the pbe cache size to handle reusing the same token key. + +* 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. + +* Tue Jun 14 2022 Bob Relyea - 3.79.0-4 +- server passive fix + +* Sat Jun 11 2022 Bob Relyea - 3.79.0-3 +- fix regressions in test suite + +* Mon Jun 6 2022 Bob Relyea - 3.79.0-2 +- fix nspr coverify issues. + +* Wed Jun 1 2022 Bob Relyea - 3.79.0-1 +- update to NSS 3.79 +- update to NSPR 4.34 +- change FIPS Modulename to conform with our final module standard + * Wed Feb 16 2022 Bob Relyea - 3.71.0-7 - Fix handling of pkcs12 passwords for PKCS5v2 cases which causes failures on long passwords.