Blob Blame History Raw
From a5d1c9dab35030c839e3a2b506bd3dfcf631ccdb Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 11 Aug 2020 11:56:27 -0500
Subject: [PATCH 1/5] Disabled AIA and cert policy extensions in ACME examples

The ACME NSS issuer has been modified to disable the AIA and
certificate policy extensions by default since they contain
non-functional URLs that might cause certbot to generate
error messages.

https://bugzilla.redhat.com/show_bug.cgi?id=1868233
---
 base/acme/issuer/nss/ca_signing.conf | 9 +++++----
 base/acme/issuer/nss/sslserver.conf  | 9 +++++----
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/base/acme/issuer/nss/ca_signing.conf b/base/acme/issuer/nss/ca_signing.conf
index aedcd4b0e..b9a82a2d1 100644
--- a/base/acme/issuer/nss/ca_signing.conf
+++ b/base/acme/issuer/nss/ca_signing.conf
@@ -1,8 +1,9 @@
 basicConstraints       = critical, CA:TRUE
 subjectKeyIdentifier   = hash
-authorityInfoAccess    = OCSP;URI:http://ocsp.example.com, caIssuers;URI:http://cert.example.com
 keyUsage               = critical, digitalSignature, keyCertSign, cRLSign
-certificatePolicies    = 2.23.140.1.2.1, @cps_policy
 
-cps_policy.id          = 1.3.6.1.4.1.44947.1.1.1
-cps_policy.CPS.1       = http://cps.example.com
+# authorityInfoAccess    = OCSP;URI:http://ocsp.example.com, caIssuers;URI:http://cert.example.com
+
+# certificatePolicies    = 2.23.140.1.2.1, @cps_policy
+# cps_policy.id          = 1.3.6.1.4.1.44947.1.1.1
+# cps_policy.CPS.1       = http://cps.example.com
diff --git a/base/acme/issuer/nss/sslserver.conf b/base/acme/issuer/nss/sslserver.conf
index f9e04902b..e153c223e 100644
--- a/base/acme/issuer/nss/sslserver.conf
+++ b/base/acme/issuer/nss/sslserver.conf
@@ -1,10 +1,11 @@
 basicConstraints       = critical, CA:FALSE
 subjectKeyIdentifier   = hash
 authorityKeyIdentifier = keyid:always
-authorityInfoAccess    = OCSP;URI:http://ocsp.example.com, caIssuers;URI:http://cert.example.com
 keyUsage               = critical, digitalSignature, keyEncipherment
 extendedKeyUsage       = serverAuth, clientAuth
-certificatePolicies    = 2.23.140.1.2.1, @cps_policy
 
-cps_policy.id          = 1.3.6.1.4.1.44947.1.1.1
-cps_policy.CPS.1       = http://cps.example.com
+# authorityInfoAccess    = OCSP;URI:http://ocsp.example.com, caIssuers;URI:http://cert.example.com
+
+# certificatePolicies    = 2.23.140.1.2.1, @cps_policy
+# cps_policy.id          = 1.3.6.1.4.1.44947.1.1.1
+# cps_policy.CPS.1       = http://cps.example.com
-- 
2.26.2


From a48e731d0faab11929fd9bf3d54a0638bbf40a16 Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
Date: Tue, 11 Aug 2020 14:41:16 -0400
Subject: [PATCH 2/5] Start NSSCertExportCLI

Can be tested with pki nss-cert-export

Signed-off-by: Alexander Scheel <ascheel@redhat.com>
---
 .../com/netscape/cmstools/nss/NSSCertCLI.java |   3 +-
 .../cmstools/nss/NSSCertExportCLI.java        | 128 ++++++++++++++++++
 2 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java

diff --git a/base/java-tools/src/com/netscape/cmstools/nss/NSSCertCLI.java b/base/java-tools/src/com/netscape/cmstools/nss/NSSCertCLI.java
index 0313ffae5..2f1f8cac5 100644
--- a/base/java-tools/src/com/netscape/cmstools/nss/NSSCertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/nss/NSSCertCLI.java
@@ -12,8 +12,9 @@ public class NSSCertCLI extends CLI {
     public NSSCertCLI(NSSCLI nssCLI) {
         super("cert", "NSS certificate management commands", nssCLI);
 
+        addModule(new NSSCertExportCLI(this));
         addModule(new NSSCertImportCLI(this));
-        addModule(new NSSCertRequestCLI(this));
         addModule(new NSSCertIssueCLI(this));
+        addModule(new NSSCertRequestCLI(this));
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java b/base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java
new file mode 100644
index 000000000..06150fe41
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java
@@ -0,0 +1,128 @@
+//
+// Copyright Red Hat, Inc.
+//
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+package com.netscape.cmstools.nss;
+
+import java.io.FileOutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import javax.net.ssl.KeyManagerFactory;
+import java.security.cert.X509Certificate;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.io.IOUtils;
+import org.dogtagpki.cli.CommandCLI;
+import org.dogtagpki.nss.NSSDatabase;
+import org.mozilla.jss.pkcs11.PK11Cert;
+import org.mozilla.jss.netscape.security.util.Cert;
+import org.mozilla.jss.netscape.security.util.Utils;
+import org.mozilla.jss.netscape.security.x509.X509CertImpl;
+import org.mozilla.jss.provider.javax.crypto.JSSKeyManager;
+
+import com.netscape.certsrv.client.ClientConfig;
+import com.netscape.cmstools.cli.MainCLI;
+
+public class NSSCertExportCLI extends CommandCLI {
+
+    public static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(NSSCertExportCLI.class);
+
+    public NSSCertExportCLI(NSSCertCLI nssCertCLI) {
+        super("export", "Export certificate", nssCertCLI);
+    }
+
+    public void printHelp() {
+        formatter.printHelp(getFullName() + " [OPTIONS...] nickname [path]", options);
+    }
+
+    public void createOptions() {
+        Option option = new Option(null, "format", true, "Certificate format: PEM (default), DER, RAW");
+        option.setArgName("format");
+        options.addOption(option);
+
+        option = new Option(null, "with-chain", false, "Export with certificate chain from NSS DB");
+        option.setArgName("with-chain");
+        options.addOption(option);
+    }
+
+    public void execute(CommandLine cmd) throws Exception {
+
+        String[] cmdArgs = cmd.getArgs();
+        String nickname = null;
+        String path = null;
+
+        if (cmdArgs.length < 1) {
+            throw new Exception("Missing required positional argument: nickname");
+        }
+        nickname = cmdArgs[0];
+
+        if (cmdArgs.length >= 2) {
+            path = cmdArgs[1];
+        }
+
+        String format = cmd.getOptionValue("format", "PEM").toUpperCase();
+        boolean chain = cmd.hasOption("with-chain");
+
+        if (!format.equals("PEM") && !format.equals("DER") && !format.equals("RAW")) {
+            throw new Exception("Unknown type of output format: " + format);
+        }
+
+        if (chain && format.equals("DER")) {
+            throw new Exception("Unable to write chain of DER-encoded certificates; use PEM instead.");
+        }
+
+        MainCLI mainCLI = (MainCLI) getRoot();
+        mainCLI.init();
+
+        X509Certificate[] certs;
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NssX509", "Mozilla-JSS");
+        JSSKeyManager km = (JSSKeyManager) kmf.getKeyManagers()[0];
+
+        if (chain) {
+            certs = km.getCertificateChain(nickname);
+        } else {
+            certs = new X509Certificate[] {
+                (PK11Cert) km.getCertificate(nickname)
+            };
+        }
+
+        byte[] output = null;
+
+        if (format.equals("RAW")) {
+            StringBuffer buffer = new StringBuffer();
+            for (X509Certificate cert : certs) {
+                buffer.append(cert.toString());
+            }
+
+            output = buffer.toString().getBytes();
+        } else if (format.equals("PEM")) {
+            StringBuffer buffer = new StringBuffer();
+
+            for (X509Certificate cert : certs) {
+                byte[] encoded = cert.getEncoded();
+                buffer.append(Cert.HEADER);
+                buffer.append("\r\n");
+                buffer.append(Utils.base64encodeMultiLine(encoded));
+                buffer.append(Cert.FOOTER);
+                buffer.append("\r\n\r\n");
+            }
+
+            output = buffer.toString().getBytes();
+        } else if (format.equals("DER")) {
+            for (X509Certificate cert : certs) {
+                output = cert.getEncoded();
+            }
+        }
+
+        if (path == null) {
+            System.out.println(new String(output));
+        } else {
+            try (FileOutputStream fos = new FileOutputStream(path)) {
+                fos.write(output);
+            }
+        }
+    }
+}
-- 
2.26.2


From 0c6b6e916420faa583a25a12621100a35bba1b57 Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
Date: Tue, 11 Aug 2020 15:16:01 -0400
Subject: [PATCH 3/5] Fix export on FIPS-enabled HSMs

Signed-off-by: Alexander Scheel <ascheel@redhat.com>
---
 base/common/python/pki/nssdb.py | 70 +++++++++++++++++----------------
 1 file changed, 37 insertions(+), 33 deletions(-)

diff --git a/base/common/python/pki/nssdb.py b/base/common/python/pki/nssdb.py
index 599cd9895..ff2af4a40 100644
--- a/base/common/python/pki/nssdb.py
+++ b/base/common/python/pki/nssdb.py
@@ -1351,6 +1351,38 @@ class NSSDatabase(object):
         epoch = datetime.datetime.utcfromtimestamp(0)
         return (date - epoch).total_seconds() * 1000
 
+    def export_cert_from_db(self,
+                            nickname,
+                            output_file,
+                            include_chain=False,
+                            output_format=None):
+        cmd = [
+            'pki',
+            '-d', self.directory
+        ]
+
+        if self.password_file:
+            cmd.extend(['-C', self.password_file])
+
+        if self.token:
+            cmd.extend(['--token', self.token])
+            full_name = self.token + ':' + nickname
+        else:
+            full_name = nickname
+
+        cmd.extend(['nss-cert-export'])
+
+        if include_chain:
+            cmd.extend(['--with-chain'])
+
+        if output_format:
+            cmd.extend(['--format', output_format])
+
+        cmd.extend([full_name, output_file])
+
+        logger.debug('Command: %s', ' '.join(map(str, cmd)))
+        subprocess.check_call(cmd)
+
     def export_cert(self,
                     nickname,
                     pkcs12_file,
@@ -1752,39 +1784,11 @@ class NSSDatabase(object):
             shutil.rmtree(tmpdir)
 
     def extract_ca_cert(self, ca_path, nickname):
-        tmpdir = tempfile.mkdtemp()
-
-        try:
-            p12_file = os.path.join(tmpdir, "sslserver.p12")
-            password = pki.generate_password()
-
-            # Build a chain containing the certificate we're trying to
-            # export. OpenSSL gets confused if we don't have a key for
-            # the end certificate: rh-bz#1246371
-            self.export_pkcs12(p12_file, pkcs12_password=password,
-                               nicknames=[nickname], include_key=False,
-                               include_chain=True)
-
-            # This command is similar to the one from server/__init__.py.
-            # However, to work during the initial startup, we do not
-            # specify the cacerts option! This ensures we always get
-            cmd_export_ca = [
-                'openssl', 'pkcs12',
-                '-in', p12_file,
-                '-out', ca_path,
-                '-nodes', '-nokeys',
-                '-passin', 'pass:' + password
-            ]
-
-            # Remove CA.crt prior to starting; openssl gets annoyed otherwise.
-            if os.path.exists(ca_path):
-                os.remove(ca_path)
-
-            res_ca = subprocess.check_output(cmd_export_ca,
-                                             stderr=subprocess.STDOUT).decode('utf-8')
-            logger.debug('Result of CA cert export: %s', res_ca)
-        finally:
-            shutil.rmtree(tmpdir)
+        # Build a chain containing the certificate we're trying to
+        # export. OpenSSL gets confused if we don't have a key for
+        # the end certificate: rh-bz#1246371
+        self.export_cert_from_db(nickname, ca_path, include_chain=True,
+                                 output_format="PEM")
 
     @staticmethod
     def __generate_key_args(key_type=None, key_size=None, curve=None):
-- 
2.26.2


From 2df13c4195e8e6b184294888b2c6376043047e33 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 11 Aug 2020 19:39:39 -0500
Subject: [PATCH 4/5] Fixed cert nickname in NSSDatabase.export_cert_from_db()

The NSSDatabase.export_cert_from_db() has been modified to
no longer prepend the token name to the cert nickname since
the cert nickname obtained from serverCertNick.conf already
contains the token name.
---
 base/common/python/pki/nssdb.py | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/base/common/python/pki/nssdb.py b/base/common/python/pki/nssdb.py
index ff2af4a40..c7ce89336 100644
--- a/base/common/python/pki/nssdb.py
+++ b/base/common/python/pki/nssdb.py
@@ -1366,9 +1366,6 @@ class NSSDatabase(object):
 
         if self.token:
             cmd.extend(['--token', self.token])
-            full_name = self.token + ':' + nickname
-        else:
-            full_name = nickname
 
         cmd.extend(['nss-cert-export'])
 
@@ -1378,7 +1375,7 @@ class NSSDatabase(object):
         if output_format:
             cmd.extend(['--format', output_format])
 
-        cmd.extend([full_name, output_file])
+        cmd.extend([nickname, output_file])
 
         logger.debug('Command: %s', ' '.join(map(str, cmd)))
         subprocess.check_call(cmd)
-- 
2.26.2


From eb28b09fb030fe5df2b6b4cfa16338ddd0325b30 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 11 Aug 2020 20:07:56 -0500
Subject: [PATCH 5/5] Removed blank lines in pki nss-cert-export output

The pki nss-cert-export has been modified to remove the extra
blank lines between certs and at the end of the output.
---
 .../src/com/netscape/cmstools/nss/NSSCertExportCLI.java      | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java b/base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java
index 06150fe41..9aaf83a30 100644
--- a/base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/nss/NSSCertExportCLI.java
@@ -107,7 +107,7 @@ public class NSSCertExportCLI extends CommandCLI {
                 buffer.append("\r\n");
                 buffer.append(Utils.base64encodeMultiLine(encoded));
                 buffer.append(Cert.FOOTER);
-                buffer.append("\r\n\r\n");
+                buffer.append("\r\n");
             }
 
             output = buffer.toString().getBytes();
@@ -118,7 +118,8 @@ public class NSSCertExportCLI extends CommandCLI {
         }
 
         if (path == null) {
-            System.out.println(new String(output));
+            System.out.print(new String(output));
+            System.out.flush();
         } else {
             try (FileOutputStream fos = new FileOutputStream(path)) {
                 fos.write(output);
-- 
2.26.2