diff --git a/.gitignore b/.gitignore
index 8d0656a..5fa55f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/jss-4.4.7.tar.gz
+SOURCES/jss-4.4.9.tar.gz
diff --git a/.jss.metadata b/.jss.metadata
index 9b6805b..d7bc2bd 100644
--- a/.jss.metadata
+++ b/.jss.metadata
@@ -1 +1 @@
-73cfcfdf2eefc39351b4b1dd9ee6f517faa64f19 SOURCES/jss-4.4.7.tar.gz
+02c4d780ddfaded425618a17070909b6c3c424fa SOURCES/jss-4.4.9.tar.gz
diff --git a/SOURCES/0001-JSS-CVE-2019-14823-fix.patch b/SOURCES/0001-JSS-CVE-2019-14823-fix.patch
deleted file mode 100644
index 46d1e4e..0000000
--- a/SOURCES/0001-JSS-CVE-2019-14823-fix.patch
+++ /dev/null
@@ -1,346 +0,0 @@
-From 4c44f138e67db9c583baf78c7aa0460a941e9842 Mon Sep 17 00:00:00 2001
-From: Alexander Scheel <ascheel@redhat.com>
-Date: Wed, 4 Sep 2019 08:33:14 -0400
-Subject: [PATCH] Fix root certificate validation
-
-When the Leaf and Chain OCSP checking policy is enabled in
-CryptoManager, JSS will switch to alternative certificate verification
-logic in JSSL_DefaultCertAuthCallback. In this method, the root
-certificate was incorrectly trusted without being verified to exist in
-the trust store.
-
-This patch cleans up the logic in JSSL_verifyCertPKIX and makes it
-more explicit in addition to fixing the error.
-
-Fixes CVE-2019-14823
-
-Signed-off-by: Alexander Scheel <ascheel@redhat.com>
----
- org/mozilla/jss/ssl/common.c | 239 ++++++++++++++++++++---------------
- 1 file changed, 136 insertions(+), 103 deletions(-)
-
-diff --git a/org/mozilla/jss/ssl/common.c b/org/mozilla/jss/ssl/common.c
-index cd4d4425..3a448c54 100644
---- a/org/mozilla/jss/ssl/common.c
-+++ b/org/mozilla/jss/ssl/common.c
-@@ -901,7 +901,6 @@ finish:
- }
- 
- /* Get the trusted anchor for pkix */
--
- CERTCertificate *getRoot(CERTCertificate *cert,
-     SECCertUsage certUsage) 
- {
-@@ -935,79 +934,84 @@ finish:
-     return root; 
- }
- 
--/* Verify a cert using explicit PKIX call.
-- * For now only used in OCSP AIA context.
-- * The result of this call will be a full chain
-- * and leaf network AIA ocsp validation.
-- * The policy param will be used in the future to
-- * handle more scenarios.
-- */
--
--SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert,
--      SECCertificateUsage certificateUsage,secuPWData *pwdata, int ocspPolicy,
--      CERTVerifyLog *log, SECCertificateUsage *usage) 
-+/* Internal helper for the below call. */
-+static SECStatus
-+JSSL_verifyCertPKIXInternal(CERTCertificate *cert,
-+    SECCertificateUsage certificateUsage, secuPWData *pwdata, int ocspPolicy,
-+    CERTVerifyLog *log, SECCertificateUsage *usage,
-+    CERTCertList *trustedCertList)
- {
--
--    /* put the first set of possible flags internally here first */
--    /* later there could be a more complete list to choose from */
--    /* support our hard core fetch aia ocsp policy for now */
--
--    static PRUint64 ocsp_Enabled_Hard_Policy_LeafFlags[2] = {
-+    /* Put the first set of possible flags internally here first. Later
-+     * there could be a more complete list to choose from; for now we only
-+     * support our hard core fetch AIA OCSP policy. Note that we disable
-+     * CRL fetching as Dogtag doesn't support it. Additionally, enable OCSP
-+     * checking on the chained CA certificates. Since NSS/PKIX's
-+     * CERT_GetClassicOCSPEnabledHardFailurePolicy doesn't do what we want,
-+     * we construct the policy ourselves. */
-+    PRUint64 ocsp_Enabled_Hard_Policy_LeafFlags[2] = {
-         /* crl */
--        0,
-+        CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD,
-         /* ocsp */
-         CERT_REV_M_TEST_USING_THIS_METHOD |
--        CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
-+            CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
-     };
- 
--    static PRUint64 ocsp_Enabled_Hard_Policy_ChainFlags[2] = {
-+    PRUint64 ocsp_Enabled_Hard_Policy_ChainFlags[2] = {
-         /* crl */
--        0,
-+        CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD,
-         /* ocsp */
-         CERT_REV_M_TEST_USING_THIS_METHOD |
--        CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
-+            CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
-     };
- 
--    static CERTRevocationMethodIndex
--        ocsp_Enabled_Hard_Policy_Method_Preference = {
--            cert_revocation_method_ocsp
--        };
--
--    static CERTRevocationFlags ocsp_Enabled_Hard_Policy = {
--    { /* leafTests */
--      2,
--      ocsp_Enabled_Hard_Policy_LeafFlags,
--      1,
--      &ocsp_Enabled_Hard_Policy_Method_Preference,
--      0 },
--    { /* chainTests */
--      2,
--      ocsp_Enabled_Hard_Policy_ChainFlags,
--      1,
--      &ocsp_Enabled_Hard_Policy_Method_Preference,
--      0 }
-+    CERTRevocationMethodIndex ocsp_Enabled_Hard_Policy_Method_Preference[1] = {
-+        cert_revocation_method_ocsp
-     };
- 
--    /* for future expansion */
-+    CERTRevocationFlags ocsp_Enabled_Hard_Policy = {
-+        /* CERTRevocationTests - leafTests */
-+        {
-+            /* number_of_defined_methods */
-+            2,
-+            /* cert_rev_flags_per_method */
-+            ocsp_Enabled_Hard_Policy_LeafFlags,
-+            /* number_of_preferred_methods */
-+            1,
-+            /* preferred_methods */
-+            ocsp_Enabled_Hard_Policy_Method_Preference,
-+            /* cert_rev_method_independent_flags */
-+            0
-+        },
-+        /* CERTRevocationTests - chainTests */
-+        {
-+            /* number_of_defined_methods */
-+            2,
-+            /* cert_rev_flags_per_method */
-+            ocsp_Enabled_Hard_Policy_ChainFlags,
-+            /* number_of_preferred_methods */
-+            1,
-+            /* preferred_methods */
-+            ocsp_Enabled_Hard_Policy_Method_Preference,
-+            /* cert_rev_method_independent_flags */
-+            0
-+        }
-+    };
- 
--    CERTValOutParam cvout[20] = {0};
--    CERTValInParam cvin[20] = {0};
-+    /* The size of these objects are defined here based upon maximum possible
-+     * inputs. A dynamic allocation could reallocate based upon actual usage,
-+     * however this would affect the size by at most one or two. Note that,
-+     * due to the required usage of cert_pi_end/cert_po_end, these sizes are
-+     * inflated by one. */
-+    CERTValOutParam cvout[3] = {{0}};
-+    CERTValInParam cvin[6] = {{0}};
- 
-+    int usageIndex = -1;
-     int inParamIndex = 0;
-     int outParamIndex = 0;
--    CERTRevocationFlags *rev = NULL;
--
--    CERTCertList *trustedCertList = NULL;
--
--    PRBool fetchCerts = PR_FALSE;
- 
--    SECCertUsage certUsage = certUsageSSLClient /* 0 */;
--    
-     SECStatus res =  SECFailure;
- 
--    CERTCertificate *root = NULL;
--
--    if(cert == NULL) {
-+    if (cert == NULL) {
-         goto finish;
-     }
- 
-@@ -1015,93 +1019,122 @@ SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert,
-         goto finish;
-     }
- 
--    /* Force the strict ocsp network check on chain
--       and leaf.
--    */
--
--    fetchCerts = PR_TRUE;   
--    rev = &ocsp_Enabled_Hard_Policy;
--
--    /* fetch aia over net */
-- 
-+    /* Enable live AIA fetching over the network. */
-     cvin[inParamIndex].type = cert_pi_useAIACertFetch;
--    cvin[inParamIndex].value.scalar.b = fetchCerts;
--    inParamIndex++; 
--
--    /* time */
-+    cvin[inParamIndex].value.scalar.b = PR_TRUE;
-+    inParamIndex++;
- 
-+    /* By setting the time to zero, we choose the current time when the
-+     * check is performed. */
-     cvin[inParamIndex].type = cert_pi_date;
--    cvin[inParamIndex].value.scalar.time = PR_Now();
-+    cvin[inParamIndex].value.scalar.time = 0;
-     inParamIndex++;
- 
--    /* flags */
--
-+    /* Force the strict OCSP check on both the leaf and its chain. */
-     cvin[inParamIndex].type = cert_pi_revocationFlags;
--    cvin[inParamIndex].value.pointer.revocation = rev;
-+    cvin[inParamIndex].value.pointer.revocation = &ocsp_Enabled_Hard_Policy;
-     inParamIndex++;
- 
--    /* establish trust anchor */
--
--    /* We need to convert the SECCertificateUsage to a SECCertUsage to obtain
--     * the root.
--    */
--
--    SECCertificateUsage testUsage = certificateUsage;
--    while (0 != (testUsage = testUsage >> 1)) { certUsage++; }
--
--    root = getRoot(cert,certUsage);
--
--    /* Try to add the root as the trust anchor so all the
--       other memebers of the ca chain will get validated.
--    */
--
--    if( root != NULL ) {
--        trustedCertList = CERT_NewCertList();
--        CERT_AddCertToListTail(trustedCertList, root);        
--
-+    /* Establish a trust anchor if it is passed to us. NOTE: this trust anchor
-+     * must previously be validated before it is passed to us here. */
-+    if (trustedCertList != NULL) {
-         cvin[inParamIndex].type = cert_pi_trustAnchors;
-         cvin[inParamIndex].value.pointer.chain = trustedCertList;
--
-         inParamIndex++;
-     }
- 
-+    /* Done establishing input parameters. */
-     cvin[inParamIndex].type = cert_pi_end;
- 
--    if(log != NULL) {
-+    /* When we need to log rationale for failure, pass it as an output
-+     * parameter. */
-+    if (log != NULL) {
-         cvout[outParamIndex].type = cert_po_errorLog;
-         cvout[outParamIndex].value.pointer.log = log;
-         outParamIndex ++;
-     }
- 
--    int usageIndex = 0;
--    if(usage != NULL) {
-+    /* When we need to inquire about the resulting certificate usage, pass it
-+     * here. */
-+    if (usage != NULL) {
-         usageIndex = outParamIndex;
-         cvout[outParamIndex].type = cert_po_usages;
-         cvout[outParamIndex].value.scalar.usages = 0;
-         outParamIndex ++;
-     }
- 
-+    /* Done establishing output parameters. */
-     cvout[outParamIndex].type = cert_po_end;
- 
-+    /* Call into NSS's PKIX library to validate our certificate. */
-     res = CERT_PKIXVerifyCert(cert, certificateUsage, cvin, cvout, &pwdata);
- 
- finish:
--    /* clean up any trusted cert list */
--
-+    /* Clean up any certificates in the trusted certificate list. This was
-+     * a passed input parameter, but by taking ownership of it and clearing it,
-+     * we enable tail calls to this function. */
-     if (trustedCertList) {
-+        /* CERT_DestroyCertList destroys interior certs for us. */
-         CERT_DestroyCertList(trustedCertList);
-         trustedCertList = NULL;
-     }
- 
--    /* CERT_DestroyCertList destroys interior certs for us. */
--
--    if(root) {
--       root = NULL;
--    }
--
--    if(res == SECSuccess && usage) {
-+    if (res == SECSuccess && usage && usageIndex != -1) {
-         *usage = cvout[usageIndex].value.scalar.usages;
-     }
- 
-     return res;
- }
-+
-+/* Verify a cert using an explicit PKIX call. For now only perform this call
-+ * when the OCSP policy is set to leaf and chain. Performs a blocking, online
-+ * OCSP status refresh. The result of this call will be a full-chain OCSP
-+ * validation.
-+ *
-+ * In the future, we'll use ocspPolicy to condition around additional policies
-+ * and handle them all with this method (and a call to PKIX).
-+ *
-+ * Note that this currently requires the certificate to be added directly
-+ * to the NSS DB. We can't otherwise validate against root certificates in
-+ * the default NSS DB.
-+ */
-+SECStatus JSSL_verifyCertPKIX(CERTCertificate *cert,
-+      SECCertificateUsage certificateUsage, secuPWData *pwdata, int ocspPolicy,
-+      CERTVerifyLog *log, SECCertificateUsage *usage)
-+{
-+    SECCertUsage certUsage = certUsageSSLClient /* 0 */;
-+
-+    /* We need to convert the SECCertificateUsage to a SECCertUsage to obtain
-+     * the root.
-+     */
-+
-+    SECCertificateUsage testUsage = certificateUsage;
-+    while (0 != (testUsage = testUsage >> 1)) { certUsage++; }
-+
-+    CERTCertificate *root = getRoot(cert, certUsage);
-+
-+    // Two cases: either the root is present, or it isn't.
-+    if (root == NULL) {
-+        /* In this case, we've had a hard time finding the root. In all
-+         * likelihood, the following call will fail to validate the end cert
-+         * as well and thus fail to validate. I don't believe there's a risk
-+         * in trying it however. */
-+        return JSSL_verifyCertPKIXInternal(cert, certificateUsage, pwdata,
-+                                           ocspPolicy, log, usage, NULL);
-+    } else {
-+        /* In this case, we've found the root certificate. Before passing it
-+         * to the leaf, explicitly validate it with strict OCSP checking. Then
-+         * validate the leaf certificate with a known and trusted root
-+         * certificate. */
-+        SECStatus ret = JSSL_verifyCertPKIXInternal(root, certificateUsageSSLCA,
-+            pwdata, ocspPolicy, log, usage, NULL);
-+        if (ret != SECSuccess) {
-+            return ret;
-+        }
-+
-+        CERTCertList *rootList = CERT_NewCertList();
-+        CERT_AddCertToListTail(rootList, root);
-+        return JSSL_verifyCertPKIXInternal(cert, certificateUsage, pwdata,
-+                                           ocspPolicy, log, usage, rootList);
-+    }
-+}
--- 
-2.21.0
-
diff --git a/SOURCES/0001-Remove-space-from-AlgorithmId.toString.patch b/SOURCES/0001-Remove-space-from-AlgorithmId.toString.patch
new file mode 100644
index 0000000..fc7fee6
--- /dev/null
+++ b/SOURCES/0001-Remove-space-from-AlgorithmId.toString.patch
@@ -0,0 +1,39 @@
+From a6fd897651ab28ca79a36b38eab7b107357cc218 Mon Sep 17 00:00:00 2001
+From: Alexander Scheel <ascheel@redhat.com>
+Date: Mon, 13 Apr 2020 09:27:50 -0400
+Subject: [PATCH 1/4] Remove space from AlgorithmId.toString()
+
+In cadc299fa69554e2e7ab9226298be639219476ab and v4.4.x commit
+e1ee07a3c19cd15d7dab1dedf383128a2b83b925, AlgorithmId was updated
+to unconditionally add an extra space to toString, to separate the
+algorithm name from the parameters. This suffices in some cases, but
+AlgorithmId.toString() is used by PKI to compare against a tokenized
+list of characters. Removing the extraneous whitespace was the solution
+proposed in PKI commit 53de751485b04fe2a1555228342ed642c9a9e347, but
+this should really be handled in JSS instead of PKI.
+
+Signed-off-by: Alexander Scheel <ascheel@redhat.com>
+---
+ org/mozilla/jss/netscape/security/x509/AlgorithmId.java | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+index 46c5a258..9936b6e9 100644
+--- a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
++++ b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+@@ -627,7 +627,11 @@ public class AlgorithmId implements Serializable, DerEncoder {
+      * Returns a string describing the algorithm and its parameters.
+      */
+     public String toString() {
+-        return (algName() + " " + paramsToString());
++        if (params == null) {
++            return algName();
++        }
++
++        return algName() + " " + paramsToString();
+     }
+ 
+     /**
+-- 
+2.26.2
+
diff --git a/SOURCES/0002-Add-script-to-add-common-root-CAs.patch b/SOURCES/0002-Add-script-to-add-common-root-CAs.patch
deleted file mode 100644
index cde61fe..0000000
--- a/SOURCES/0002-Add-script-to-add-common-root-CAs.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 61985f642b0b5cc75fc3f254ef6c99aeb56acbe2 Mon Sep 17 00:00:00 2001
-From: Alexander Scheel <ascheel@redhat.com>
-Date: Thu, 29 Aug 2019 16:14:08 -0400
-Subject: [PATCH 2/3] Add script to add common root CAs
-
-When given an NSS DB, common_roots.sh uses the trust command to extract
-the root CAs trusted by the local system and add them to said NSS DB.
-
-Signed-off-by: Alexander Scheel <ascheel@redhat.com>
----
- tools/common_roots.sh | 36 ++++++++++++++++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
- create mode 100755 tools/common_roots.sh
-
-diff --git a/tools/common_roots.sh b/tools/common_roots.sh
-new file mode 100755
-index 00000000..97341c4c
---- /dev/null
-+++ b/tools/common_roots.sh
-@@ -0,0 +1,36 @@
-+#!/bin/bash
-+
-+# This script reads the contents of the OS CA bundle store,
-+#   /usr/share/pki/ca-trust-source/ca-bundle.trust.p11-kit
-+# and places the contained CAs into the specified NSS DB.
-+#
-+# This NSS DB is used by various JSS tests that aren't enabled
-+# by default because they require an active internet connection.
-+
-+nssdb="$1"
-+
-+if [ -z "$nssdb" ] && [ -e "build" ]; then
-+    nssdb="build/results/cadb"
-+elif [ -z "$nssdb" ] && [ -e "../build" ]; then
-+    nssdb="../build/results/cadb"
-+else
-+    echo "Must provide path to NSS DB!" 1>&2
-+    exit 1
-+fi
-+
-+if [ -e "$nssdb" ]; then
-+    rm -rf "$nssdb"
-+fi
-+
-+mkdir -p "$nssdb"
-+echo "" > "$nssdb/password.txt"
-+certutil -N -d "$nssdb" -f "$nssdb/password.txt"
-+
-+trust extract --format=pem-bundle  --filter=ca-anchors "$nssdb/complete.pem"
-+
-+# From: https://serverfault.com/questions/391396/how-to-split-a-pem-file
-+csplit -f "$nssdb/individual-" "$nssdb/complete.pem" '/-----BEGIN CERTIFICATE-----/' '{*}'
-+
-+for cert in "$nssdb"/individual*; do
-+    certutil -A -a -i "$cert" -n "$cert" -t CT,C,C -d "$nssdb" -f "$nssdb/password.txt"
-+done
--- 
-2.21.0
-
diff --git a/SOURCES/0002-Fix-SHA512withRSA-PSS-identifier.patch b/SOURCES/0002-Fix-SHA512withRSA-PSS-identifier.patch
new file mode 100644
index 0000000..fe381ec
--- /dev/null
+++ b/SOURCES/0002-Fix-SHA512withRSA-PSS-identifier.patch
@@ -0,0 +1,26 @@
+From 7e04acac65fd6d14fb24e49ec0d3fb0f111fc6e9 Mon Sep 17 00:00:00 2001
+From: Alexander Scheel <ascheel@redhat.com>
+Date: Thu, 23 Apr 2020 12:11:20 -0400
+Subject: [PATCH 2/4] Fix SHA512withRSA/PSS identifier
+
+Signed-off-by: Alexander Scheel <ascheel@redhat.com>
+---
+ org/mozilla/jss/netscape/security/x509/AlgorithmId.java | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+index 9936b6e9..ed899fd0 100644
+--- a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
++++ b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+@@ -1034,7 +1034,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
+      */
+     public static final String[] ALL_SIGNING_ALGORITHMS = new String[]
+     {
+-            "SHA256withRSA", "SHA384withRSA", "SHA512withRSA", "SHA1withRSA","SHA256withRSA/PSS","SHA384withRSA/PSS","SHA5121withRSA/PSS",
++            "SHA256withRSA", "SHA384withRSA", "SHA512withRSA", "SHA1withRSA","SHA256withRSA/PSS","SHA384withRSA/PSS","SHA512withRSA/PSS",
+             "SHA256withEC", "SHA384withEC", "SHA512withEC", "SHA1withEC" };
+ 
+     public static void dumpBytes(byte[] data)
+-- 
+2.26.2
+
diff --git a/SOURCES/0003-Add-AlgorithmId.toStringWithParams-fix-toString.patch b/SOURCES/0003-Add-AlgorithmId.toStringWithParams-fix-toString.patch
new file mode 100644
index 0000000..8b8b758
--- /dev/null
+++ b/SOURCES/0003-Add-AlgorithmId.toStringWithParams-fix-toString.patch
@@ -0,0 +1,43 @@
+From 3dcc932854381d56ce6701082921096848801e1c Mon Sep 17 00:00:00 2001
+From: Alexander Scheel <ascheel@redhat.com>
+Date: Thu, 23 Apr 2020 16:54:00 -0400
+Subject: [PATCH 3/4] Add AlgorithmId.toStringWithParams, fix toString
+
+PKI's usage of AlgorithmId.toString() doesn't handle having the
+parameters encoded in the toString() representation of the id.
+Move toString() back to only having the contents of algName, and
+move parameters to a separate method.
+
+Signed-off-by: Alexander Scheel <ascheel@redhat.com>
+---
+ .../jss/netscape/security/x509/AlgorithmId.java      | 12 +++++++++++-
+ 1 file changed, 11 insertions(+), 1 deletion(-)
+
+diff --git a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+index ed899fd0..4440fd4d 100644
+--- a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
++++ b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+@@ -624,9 +624,19 @@ public class AlgorithmId implements Serializable, DerEncoder {
+     }
+ 
+     /**
+-     * Returns a string describing the algorithm and its parameters.
++     * Returns a string describing only the algorithm without parameters.
++     *
++     * Use toStringWithParams() for algorithm name and paramaters, or
++     * paramsToString() for just parameters.
+      */
+     public String toString() {
++        return algName();
++    }
++
++    /**
++     * Returns a string describing the algorithm and its parameters.
++     */
++    public String toStringWithParams() {
+         if (params == null) {
+             return algName();
+         }
+-- 
+2.26.2
+
diff --git a/SOURCES/0003-Add-optional-test-case-against-badssl.com.patch b/SOURCES/0003-Add-optional-test-case-against-badssl.com.patch
deleted file mode 100644
index ba155f1..0000000
--- a/SOURCES/0003-Add-optional-test-case-against-badssl.com.patch
+++ /dev/null
@@ -1,233 +0,0 @@
-From 7b4c0fa04f5e4469fc8bc442c9f12f975c5e1610 Mon Sep 17 00:00:00 2001
-From: Alexander Scheel <ascheel@redhat.com>
-Date: Wed, 28 Aug 2019 09:23:41 -0400
-Subject: [PATCH 3/3] Add optional test case against badssl.com
-
-badssl.com maintains a number of subdomains with valid and invalid TLS
-configurations. A number of these test certificates which fail in
-certain scenarios (revoked, expired, etc). Add a test runner which
-validates SSLSocket's implementation against badssl.com.
-
-Signed-off-by: Alexander Scheel <ascheel@redhat.com>
----
- org/mozilla/jss/tests/BadSSL.java | 208 ++++++++++++++++++++++++++++++
- 1 file changed, 208 insertions(+)
- create mode 100644 org/mozilla/jss/tests/BadSSL.java
-
-diff --git a/org/mozilla/jss/tests/BadSSL.java b/org/mozilla/jss/tests/BadSSL.java
-new file mode 100644
-index 00000000..60bfe820
---- /dev/null
-+++ b/org/mozilla/jss/tests/BadSSL.java
-@@ -0,0 +1,208 @@
-+package org.mozilla.jss.tests;
-+
-+import org.mozilla.jss.CryptoManager;
-+
-+import org.mozilla.jss.ssl.SSLSocket;
-+import org.mozilla.jss.ssl.SSLSocketException;
-+
-+import org.mozilla.jss.util.NativeErrcodes;
-+
-+/**
-+ * The BadSSL test case maintains an internal mapping from badssl.com
-+ * subdomains to expected exceptions and validates they occur.
-+ *
-+ * Since badssl.com offers no guaranteed SLA or availability, we likely
-+ * shouldn't add this site to automated tests.
-+ */
-+
-+public class BadSSL {
-+    public static void main(String[] args) throws Exception {
-+        boolean ocsp = false;
-+
-+        if (args.length < 1) {
-+            System.out.println("Usage: BadSSL nssdb [LEAF_AND_CHAIN]");
-+            return;
-+        }
-+
-+        if (args.length >= 2 && args[1].equals("LEAF_AND_CHAIN")) {
-+            System.out.println("Enabling leaf and chain policy...");
-+            ocsp = true;
-+        }
-+
-+        CryptoManager.initialize(args[0]);
-+        CryptoManager cm = CryptoManager.getInstance();
-+
-+        if (ocsp) {
-+            cm.setOCSPPolicy(CryptoManager.OCSPPolicy.LEAF_AND_CHAIN);
-+        }
-+
-+
-+        // Test cases which should fail due to various certificate errors.
-+        testExpired();
-+        testWrongHost();
-+        testSelfSigned();
-+        testUntrustedRoot();
-+
-+        // The following test cases depend on crypto-policies or local NSS
-+        // configuration.
-+        testSHA1();
-+        testRC4MD5();
-+        testRC4();
-+        test3DES();
-+        testNULL();
-+
-+        // The following test cases depend on OCSP being enabled.
-+        if (ocsp) {
-+            testRevoked();
-+        }
-+
-+        // Test cases which should pass given the correct root certs.
-+        testSHA256();
-+        testSHA384();
-+        testSHA512();
-+
-+        testECC256();
-+        testECC384();
-+
-+        testRSA2048();
-+        testRSA4096();
-+        testRSA8192();
-+
-+        testExtendedValidation();
-+    }
-+
-+    /* Test cases whose handshakes should fail below. */
-+
-+    public static void testExpired() throws Exception {
-+        testHelper("expired.badssl.com", 443, new String[]{ "(-8181)", "has expired" });
-+    }
-+
-+    public static void testWrongHost() throws Exception {
-+        testHelper("wrong.host.badssl.com", 443, new String[]{ "(-12276)", "domain name does not match" });
-+    }
-+
-+    public static void testSelfSigned() throws Exception {
-+        testHelper("self-signed.badssl.com", 443, new String[]{ "(-8101)", "(-8156)", "type not approved", "issuer certificate is invalid" });
-+    }
-+
-+    public static void testUntrustedRoot() throws Exception {
-+        testHelper("untrusted-root.badssl.com", 443, new String[]{ "(-8172)", "certificate issuer has been marked as not trusted" });
-+    }
-+
-+    public static void testRevoked() throws Exception {
-+        testHelper("revoked.badssl.com", 443, new String[]{ "(-8180)", "has been revoked" });
-+    }
-+
-+    public static void testSHA1() throws Exception {
-+        testHelper("sha1-intermediate.badssl.com", 443, new String[] { "(-12286)", "Cannot communicate securely" });
-+    }
-+
-+    public static void testRC4MD5() throws Exception {
-+        testHelper("rc4-md5.badssl.com", 443, new String[] { "(-12286)", "Cannot communicate securely" });
-+    }
-+
-+    public static void testRC4() throws Exception {
-+        testHelper("rc4.badssl.com", 443, new String[] { "(-12286)", "Cannot communicate securely" });
-+    }
-+
-+    public static void test3DES() throws Exception {
-+        testHelper("3des.badssl.com", 443, new String[] { "(-12286)", "Cannot communicate securely" });
-+    }
-+
-+    public static void testNULL() throws Exception {
-+        testHelper("null.badssl.com", 443, new String[] { "(-12286)", "Cannot communicate securely" });
-+    }
-+
-+    /* Test cases which should handshake successfully below. */
-+
-+    public static void testSHA256() throws Exception {
-+        testHelper("sha256.badssl.com", 443);
-+    }
-+
-+    public static void testSHA384() throws Exception {
-+        testHelper("sha384.badssl.com", 443);
-+    }
-+
-+    public static void testSHA512() throws Exception {
-+        testHelper("sha512.badssl.com", 443);
-+    }
-+
-+    public static void testECC256() throws Exception {
-+        testHelper("ecc256.badssl.com", 443);
-+    }
-+
-+    public static void testECC384() throws Exception {
-+        testHelper("ecc384.badssl.com", 443);
-+    }
-+
-+    public static void testRSA2048() throws Exception {
-+        testHelper("rsa2048.badssl.com", 443);
-+    }
-+
-+    public static void testRSA4096() throws Exception {
-+        testHelper("rsa4096.badssl.com", 443);
-+    }
-+
-+    public static void testRSA8192() throws Exception {
-+        testHelper("rsa8192.badssl.com", 443);
-+    }
-+
-+    public static void testExtendedValidation() throws Exception {
-+        testHelper("extended-validation.badssl.com", 443);
-+    }
-+
-+    /* Test case helpers. */
-+
-+    public static void testHelper(String host, int port) throws Exception {
-+        testSite(host, port);
-+        System.out.println("\t...ok");
-+    }
-+
-+    public static void testHelper(String host, int port, String[] substrs) throws Exception {
-+        try {
-+            testSite(host, port);
-+        } catch (SSLSocketException sse) {
-+            String actual = sse.getMessage().toLowerCase();
-+
-+            for (String expected : substrs) {
-+                if (actual.contains(expected.toLowerCase())) {
-+                    System.out.println("\t...got expected error message.");
-+                    return;
-+                }
-+            }
-+
-+            System.err.println("\tUnexpected error message: " + actual);
-+            throw sse;
-+        }
-+
-+        throw new RuntimeException("Expected to get an exception, but didn't!");
-+    }
-+
-+    public static void testHelper(String host, int port, int[] codes) throws Exception {
-+        try {
-+            testSite(host, port);
-+        } catch (SSLSocketException sse) {
-+            int actual = sse.getErrcode();
-+            for (int expected : codes) {
-+                if (actual == expected) {
-+                    System.out.println("\t...got expected error code.");
-+                    return;
-+                }
-+            }
-+
-+            System.err.println("\tUnexpected error code: " + actual);
-+            throw sse;
-+        }
-+
-+        throw new RuntimeException("Expected to get an exception, but didn't!");
-+    }
-+
-+    public static void testSite(String host, int port) throws Exception {
-+        System.out.println("Testing connection to " + host + ":" + port);
-+        SSLSocket sock = new SSLSocket(host, 443);
-+        sock.forceHandshake();
-+        sock.shutdownOutput();
-+        sock.shutdownInput();
-+        sock.close();
-+    }
-+}
--- 
-2.21.0
-
diff --git a/SOURCES/0004-More-SHA256withRSA-PSS-algorithm-fixes.-Various-typo.patch b/SOURCES/0004-More-SHA256withRSA-PSS-algorithm-fixes.-Various-typo.patch
new file mode 100644
index 0000000..1e22313
--- /dev/null
+++ b/SOURCES/0004-More-SHA256withRSA-PSS-algorithm-fixes.-Various-typo.patch
@@ -0,0 +1,40 @@
+From eb9e9114295999eb490f81f232332b32aa0d76da Mon Sep 17 00:00:00 2001
+From: Jack Magne <jmagne@test.host.com>
+Date: Wed, 6 May 2020 21:31:28 -0400
+Subject: [PATCH 4/4] More SHA256withRSA/PSS algorithm fixes. Various typos
+ resolved to result in this algorithm being able to function correctly.
+
+---
+ org/mozilla/jss/crypto/SignatureAlgorithm.java          | 2 +-
+ org/mozilla/jss/netscape/security/x509/AlgorithmId.java | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/org/mozilla/jss/crypto/SignatureAlgorithm.java b/org/mozilla/jss/crypto/SignatureAlgorithm.java
+index c41b5401..a46c2b92 100644
+--- a/org/mozilla/jss/crypto/SignatureAlgorithm.java
++++ b/org/mozilla/jss/crypto/SignatureAlgorithm.java
+@@ -102,7 +102,7 @@ public class SignatureAlgorithm extends Algorithm {
+ 
+     public static final SignatureAlgorithm
+     RSAPSSSignatureWithSHA512Digest = new SignatureAlgorithm(SEC_OID_PKCS1_RSA_PSS_SIGNATURE, "RSAPSSSignatureWithSHA512Digest",
+-            null, DigestAlgorithm.SHA384, OBJECT_IDENTIFIER.PKCS1.subBranch(10) );
++            null, DigestAlgorithm.SHA512, OBJECT_IDENTIFIER.PKCS1.subBranch(10) );
+ 
+     /**********************************************************************
+      * Raw RSA signing. This algorithm does not do any hashing, it merely
+diff --git a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+index 4440fd4d..0a332f23 100644
+--- a/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
++++ b/org/mozilla/jss/netscape/security/x509/AlgorithmId.java
+@@ -763,7 +763,7 @@ public class AlgorithmId implements Serializable, DerEncoder {
+         } else if ("SHA384withRSA/PSS".equals(algName)) {
+             pssSpec = new PSSParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, 48, 1);
+ 
+-        } else if ("SHA384withRSA/PSS".equals(algName)) {
++        } else if ("SHA512withRSA/PSS".equals(algName)) {
+             pssSpec = new PSSParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, 64, 1);
+         }
+         try {
+-- 
+2.26.2
+
diff --git a/SPECS/jss.spec b/SPECS/jss.spec
index 59edb0f..b578c43 100644
--- a/SPECS/jss.spec
+++ b/SPECS/jss.spec
@@ -6,8 +6,8 @@ Summary:        Java Security Services (JSS)
 URL:            http://www.dogtagpki.org/wiki/JSS
 License:        MPLv1.1 or GPLv2+ or LGPLv2+
 
-Version:        4.4.7
-Release:        2%{?dist}
+Version:        4.4.9
+Release:        3%{?dist}
 
 # To generate the source tarball:
 # $ git clone https://github.com/dogtagpki/jss.git
@@ -23,9 +23,10 @@ Source:         https://github.com/dogtagpki/%{name}/archive/v%{version}/%{name}
 #     --stdout \
 #     <version tag> \
 #     > jss-VERSION-RELEASE.patch
-Patch1: 0001-JSS-CVE-2019-14823-fix.patch
-Patch2: 0002-Add-script-to-add-common-root-CAs.patch
-Patch3: 0003-Add-optional-test-case-against-badssl.com.patch
+Patch0: 0001-Remove-space-from-AlgorithmId.toString.patch
+Patch1: 0002-Fix-SHA512withRSA-PSS-identifier.patch
+Patch2: 0003-Add-AlgorithmId.toStringWithParams-fix-toString.patch
+Patch3: 0004-More-SHA256withRSA-PSS-algorithm-fixes.-Various-typo.patch
 
 Conflicts:      idm-console-framework < 1.1.17-4
 Conflicts:      pki-base < 10.4.0
@@ -180,6 +181,22 @@ cp -p jss/*.txt $RPM_BUILD_ROOT%{_javadocdir}/%{name}-%{version}
 
 ################################################################################
 %changelog
+* Thu May 7 2020 Dogtag PKI Team <pki-devel@redhat.com> 4.4.9-3
+- Fix issue with RSA/PSS and SHA-512
+  Bugzilla #1710105
+
+* Fri Apr 3 2020 Dogtag PKI Team <pki-devel@redhat.com> 4.4.9-2
+- Update v4.4.9 to match upstream
+
+* Fri Apr 3 2020 Dogtag PKI Team <pki-devel@redhat.com> 4.4.9-1
+- Rebase to JSS v4.4.9
+  Bugzilla #1818631 - Rebase JSS to v4.4.9 in RHEL 7.9
+
+* Sun Mar 29 2020 Dogtag PKI Team <pki-devel@redhat.com> 4.4.7-3
+- Bugzilla #1710105 - JSS: add RSA PSS support (jmagne)
+- Bugzilla #1796642 - JSS -- remove hardcoded native library
+  /usr/lib{64}/jss/libjss4.so (ascheel)
+
 * Wed Sep 11 2019 Dogtag PKI Team <pki-devel@redhat.com> 4.4.7-2
 - Bugzilla #1747967 - CVE 2019-14823 jss: OCSP policy "Leaf and Chain" implicitly trusts the root certificate