The installation code has been modified such that it imports all
CA certificates from the PKCS #12 file for cloning before the
server is started using certutil. The user certificates will
continue to be imported using the existing JSS code after the
server is started. This is necessary since JSS is unable to
preserve the CA certificate nicknames.

The PKCS12Util has been modified to support multiple certificates
with the same nicknames.

The pki pkcs12-cert-find has been modified to show certificate ID
and another field indicating whether the certificate has a key.

The pki pkcs12-cert-export has been modified to accept either
certificate nickname or ID.

The pki pkcs12-import has been modified to provide options for
importing only user certificates or CA certificates.

https://fedorahosted.org/pki/ticket/1742

--
Endi S. Dewata
>From 8073309cb114e445da8ca88c8c4d4839fee5a7ab Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <[email protected]>
Date: Thu, 17 Mar 2016 15:23:34 +0100
Subject: [PATCH] Added support for cloning 3rd-party CA certificates.

The installation code has been modified such that it imports all
CA certificates from the PKCS #12 file for cloning before the
server is started using certutil. The user certificates will
continue to be imported using the existing JSS code after the
server is started. This is necessary since JSS is unable to
preserve the CA certificate nicknames.

The PKCS12Util has been modified to support multiple certificates
with the same nicknames.

The pki pkcs12-cert-find has been modified to show certificate ID
and another field indicating whether the certificate has a key.

The pki pkcs12-cert-export has been modified to accept either
certificate nickname or ID.

The pki pkcs12-import has been modified to provide options for
importing only user certificates or CA certificates.

https://fedorahosted.org/pki/ticket/1742
---
 base/common/python/pki/cli/pkcs12.py               | 207 +++++++++++++--------
 base/common/python/pki/nssdb.py                    |  13 +-
 .../netscape/cmstools/pkcs12/PKCS12CertCLI.java    |  15 +-
 .../cmstools/pkcs12/PKCS12CertExportCLI.java       |  54 +++++-
 .../cmstools/pkcs12/PKCS12CertFindCLI.java         |  10 +-
 .../deployment/scriptlets/security_databases.py    |  19 ++
 base/util/src/netscape/security/pkcs/PKCS12.java   |  43 +++--
 .../src/netscape/security/pkcs/PKCS12CertInfo.java |  10 +-
 .../src/netscape/security/pkcs/PKCS12Util.java     |  53 +++---
 9 files changed, 283 insertions(+), 141 deletions(-)

diff --git a/base/common/python/pki/cli/pkcs12.py b/base/common/python/pki/cli/pkcs12.py
index 2ab60322519c4871b84698d1746977a11a51d85e..dc999a1200e1c42bca7a779bc42b20a03b031fb6 100644
--- a/base/common/python/pki/cli/pkcs12.py
+++ b/base/common/python/pki/cli/pkcs12.py
@@ -53,6 +53,8 @@ class PKCS12ImportCLI(pki.cli.CLI):
         print('      --pkcs12-password <password>   Password for the PKCS #12 file.')
         print('      --pkcs12-password-file <path>  containing the PKCS #12 password.')
         print('      --no-trust-flags               Do not include trust flags')
+        print('      --no-user-certs                Do not import user certificates')
+        print('      --no-ca-certs                  Do not import CA certificates')
         print('  -v, --verbose                      Run in verbose mode.')
         print('      --debug                        Run in debug mode.')
         print('      --help                         Show help message.')
@@ -63,7 +65,8 @@ class PKCS12ImportCLI(pki.cli.CLI):
         try:
             opts, _ = getopt.gnu_getopt(args, 'v', [
                 'pkcs12-file=', 'pkcs12-password=', 'pkcs12-password-file=',
-                'no-trust-flags', 'verbose', 'debug', 'help'])
+                'no-trust-flags', 'no-user-certs', 'no-ca-certs',
+                'verbose', 'debug', 'help'])
 
         except getopt.GetoptError as e:
             print('ERROR: ' + str(e))
@@ -74,6 +77,9 @@ class PKCS12ImportCLI(pki.cli.CLI):
         pkcs12_password = None
         password_file = None
         no_trust_flags = False
+        import_user_certs = True
+        import_ca_certs = True
+        debug = False
 
         for o, a in opts:
             if o == '--pkcs12-file':
@@ -88,9 +94,18 @@ class PKCS12ImportCLI(pki.cli.CLI):
             elif o == '--no-trust-flags':
                 no_trust_flags = True
 
+            elif o == '--no-user-certs':
+                import_user_certs = False
+
+            elif o == '--no-ca-certs':
+                import_ca_certs = False
+
             elif o in ('-v', '--verbose'):
                 self.set_verbose(True)
 
+            elif o == '--debug':
+                debug = True
+
             elif o == '--help':
                 self.print_help()
                 sys.exit()
@@ -119,13 +134,11 @@ class PKCS12ImportCLI(pki.cli.CLI):
         if main_cli.verbose:
             print('Getting certificate infos in PKCS #12 file')
 
-        ca_certs = []
-        user_certs = []
+        certs = []
 
         tmpdir = tempfile.mkdtemp()
 
         try:
-
             # find all certs in PKCS #12 file
             output_file = os.path.join(tmpdir, 'pkcs12-cert-find.txt')
             with open(output_file, 'wb') as f:
@@ -144,106 +157,142 @@ class PKCS12ImportCLI(pki.cli.CLI):
                 if no_trust_flags:
                     cmd.extend(['--no-trust-flags'])
 
+                if self.verbose:
+                    cmd.extend(['--verbose'])
+
+                if debug:
+                    cmd.extend(['--debug'])
+
                 main_cli.execute_java(cmd, stdout=f)
 
-            # determine cert types
+            # parse results
             with open(output_file, 'r') as f:
                 cert_info = {}
 
                 for line in f:
-                    match = re.match(r'  Nickname: (.*)$', line)
+                    match = re.match(r'  Certificate ID: (.*)$', line)
                     if match:
-                        # store previous cert
-                        if cert_info:
-                            if 'key_id' in cert_info:
-                                # if cert has key, it's a user cert
-                                user_certs.append(cert_info)
-                            else:
-                                # otherwise it's a CA cert
-                                ca_certs.append(cert_info)
-
                         cert_info = {}
+                        cert_info['id'] = match.group(1)
+                        certs.append(cert_info)
+                        continue
+
+                    match = re.match(r'  Nickname: (.*)$', line)
+                    if match:
                         cert_info['nickname'] = match.group(1)
                         continue
 
-                    match = re.match(r'  Key ID: (.*)$', line)
-                    if match:
-                        cert_info['key_id'] = match.group(1)
-                        continue
-
                     match = re.match(r'  Trust Flags: (.*)$', line)
                     if match:
                         cert_info['trust_flags'] = match.group(1)
                         continue
 
-                # store last cert
-                if cert_info:
-                    if 'key_id' in cert_info:
-                        # if cert has key, it's a user cert
-                        user_certs.append(cert_info)
-                    else:
-                        # otherwise it's a CA cert
-                        ca_certs.append(cert_info)
-
-            cert_file = os.path.join(tmpdir, 'ca-cert.pem')
-
-            nssdb = pki.nssdb.NSSDatabase(
-                main_cli.database,
-                token=main_cli.token,
-                password=main_cli.password,
-                password_file=main_cli.password_file)
-
-            for cert_info in ca_certs:
-
-                nickname = cert_info['nickname']
-                trust_flags = cert_info['trust_flags']
-
-                if main_cli.verbose:
-                    print('Exporting %s from PKCS #12 file' % nickname)
-
-                cmd = ['pkcs12-cert-export']
-
-                if pkcs12_file:
-                    cmd.extend(['--pkcs12-file', pkcs12_file])
-
-                if pkcs12_password:
-                    cmd.extend(['--pkcs12-password', pkcs12_password])
-
-                if password_file:
-                    cmd.extend(['--pkcs12-password-file', password_file])
-
-                cmd.extend(['--cert-file', cert_file, nickname])
-
-                main_cli.execute_java(cmd)
-
-                if main_cli.verbose:
-                    print('Importing %s' % nickname)
-
-                nssdb.add_cert(nickname, cert_file, trust_flags)
+                    match = re.match(r'  Has Key: (.*)$', line)
+                    if match:
+                        cert_info['has_key'] = match.group(1) == 'true'
+                        continue
 
         finally:
             shutil.rmtree(tmpdir)
 
-        # importing user certs
+        # import CA certificates if requested
+        if import_ca_certs:
 
-        nicknames = []
-        for cert_info in user_certs:
-            nicknames.append(cert_info['nickname'])
+            if main_cli.verbose:
+                print('Importing CA certificates')
 
-        cmd = ['pkcs12-import']
+            tmpdir = tempfile.mkdtemp()
 
-        if pkcs12_file:
-            cmd.extend(['--pkcs12-file', pkcs12_file])
+            try:
+                cert_file = os.path.join(tmpdir, 'ca-cert.pem')
 
-        if pkcs12_password:
-            cmd.extend(['--pkcs12-password', pkcs12_password])
+                nssdb = pki.nssdb.NSSDatabase(
+                    main_cli.database,
+                    token=main_cli.token,
+                    password=main_cli.password,
+                    password_file=main_cli.password_file)
 
-        if password_file:
-            cmd.extend(['--pkcs12-password-file', password_file])
+                for cert_info in certs:
 
-        if no_trust_flags:
-            cmd.extend(['--no-trust-flags'])
+                    has_key = cert_info['has_key']
+                    if has_key:
+                        continue
 
-        cmd.extend(nicknames)
+                    cert_id = cert_info['id']
+                    nickname = cert_info['nickname']
+                    trust_flags = cert_info['trust_flags']
 
-        main_cli.execute_java(cmd)
+                    if main_cli.verbose:
+                        print('Exporting %s (%s) from PKCS #12 file' % (nickname, cert_id))
+
+                    cmd = ['pkcs12-cert-export']
+
+                    if pkcs12_file:
+                        cmd.extend(['--pkcs12-file', pkcs12_file])
+
+                    if pkcs12_password:
+                        cmd.extend(['--pkcs12-password', pkcs12_password])
+
+                    if password_file:
+                        cmd.extend(['--pkcs12-password-file', password_file])
+
+                    cmd.extend(['--cert-file', cert_file])
+
+                    cmd.extend(['--cert-id', cert_id])
+
+                    if self.verbose:
+                        cmd.extend(['--verbose'])
+
+                    if debug:
+                        cmd.extend(['--debug'])
+
+                    main_cli.execute_java(cmd)
+
+                    if main_cli.verbose:
+                        print('Importing %s' % nickname)
+
+                    nssdb.add_cert(nickname, cert_file, trust_flags)
+
+            finally:
+                shutil.rmtree(tmpdir)
+
+        # import user certificates if requested
+        if import_user_certs:
+
+            if main_cli.verbose:
+                print('Importing user certificates')
+
+            nicknames = []
+            for cert_info in certs:
+
+                has_key = cert_info['has_key']
+                if not has_key:
+                    continue
+
+                nickname = cert_info['nickname']
+                if nickname not in nicknames:
+                    nicknames.append(nickname)
+
+            cmd = ['pkcs12-import']
+
+            if pkcs12_file:
+                cmd.extend(['--pkcs12-file', pkcs12_file])
+
+            if pkcs12_password:
+                cmd.extend(['--pkcs12-password', pkcs12_password])
+
+            if password_file:
+                cmd.extend(['--pkcs12-password-file', password_file])
+
+            if no_trust_flags:
+                cmd.extend(['--no-trust-flags'])
+
+            if self.verbose:
+                cmd.extend(['--verbose'])
+
+            if debug:
+                cmd.extend(['--debug'])
+
+            cmd.extend(nicknames)
+
+            main_cli.execute_java(cmd)
diff --git a/base/common/python/pki/nssdb.py b/base/common/python/pki/nssdb.py
index 2fc2d420f4b6813efe53690337be86ec042a2a6f..9d276332aacb5a74b36c20406028e03a21c51b72 100644
--- a/base/common/python/pki/nssdb.py
+++ b/base/common/python/pki/nssdb.py
@@ -494,8 +494,11 @@ class NSSDatabase(object):
         finally:
             shutil.rmtree(tmpdir)
 
-    def import_pkcs12(self, pkcs12_file, pkcs12_password=None,
-                      pkcs12_password_file=None):
+    def import_pkcs12(self, pkcs12_file,
+                      pkcs12_password=None,
+                      pkcs12_password_file=None,
+                      no_user_certs=False,
+                      no_ca_certs=False):
 
         tmpdir = tempfile.mkdtemp()
 
@@ -526,6 +529,12 @@ class NSSDatabase(object):
                 '--pkcs12-password-file', password_file
             ])
 
+            if no_user_certs:
+                cmd.extend(['--no-user-certs'])
+
+            if no_ca_certs:
+                cmd.extend(['--no-ca-certs'])
+
             subprocess.check_call(cmd)
 
         finally:
diff --git a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertCLI.java
index 1ed88b1fa40f90594498f8c24d02d011e4f86c20..fe7092c00ef3e4ee202d47b479ec22caea5f36c1 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertCLI.java
@@ -18,9 +18,12 @@
 
 package com.netscape.cmstools.pkcs12;
 
+import java.math.BigInteger;
+
 import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.cmstools.cli.CLI;
 
+import netscape.security.pkcs.PKCS12;
 import netscape.security.pkcs.PKCS12CertInfo;
 
 /**
@@ -37,18 +40,20 @@ public class PKCS12CertCLI extends CLI {
         addModule(new PKCS12CertRemoveCLI(this));
     }
 
-    public static void printCertInfo(PKCS12CertInfo certInfo) throws Exception {
+    public static void printCertInfo(PKCS12 pkcs12, PKCS12CertInfo certInfo) throws Exception {
+
+        BigInteger id = certInfo.getID();
+        System.out.println("  Certificate ID: " + id.toString(16));
+
         System.out.println("  Serial Number: " + new CertId(certInfo.getCert().getSerialNumber()).toHexString());
         System.out.println("  Nickname: " + certInfo.getNickname());
         System.out.println("  Subject DN: " + certInfo.getCert().getSubjectDN());
         System.out.println("  Issuer DN: " + certInfo.getCert().getIssuerDN());
 
-        if (certInfo.getKeyID() != null) {
-            System.out.println("  Key ID: " + certInfo.getKeyID().toString(16));
-        }
-
         if (certInfo.getTrustFlags() != null) {
             System.out.println("  Trust Flags: " + certInfo.getTrustFlags());
         }
+
+        System.out.println("  Has Key: " + (pkcs12.getKeyInfoByID(id) != null));
     }
 }
diff --git a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertExportCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertExportCLI.java
index 04e2b7b6fcee28246ee7f21f3293cec69373a255..8fb526d489fea7b482e8af489879f7657f816996 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertExportCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertExportCLI.java
@@ -22,6 +22,9 @@ import java.io.BufferedReader;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.PrintStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -50,7 +53,7 @@ public class PKCS12CertExportCLI extends CLI {
     }
 
     public void printHelp() {
-        formatter.printHelp(getFullName() + " [OPTIONS...] <nickname>", options);
+        formatter.printHelp(getFullName() + " [OPTIONS...] [nickname]", options);
     }
 
     public void createOptions() {
@@ -70,6 +73,10 @@ public class PKCS12CertExportCLI extends CLI {
         option.setArgName("path");
         options.addOption(option);
 
+        option = new Option(null, "cert-id", true, "Certificate ID to export");
+        option.setArgName("ID");
+        options.addOption(option);
+
         options.addOption("v", "verbose", false, "Run in verbose mode.");
         options.addOption(null, "debug", false, "Run in debug mode.");
         options.addOption(null, "help", false, "Show help message.");
@@ -104,14 +111,28 @@ public class PKCS12CertExportCLI extends CLI {
         }
 
         String[] cmdArgs = cmd.getArgs();
+        String id = cmd.getOptionValue("cert-id");
 
-        if (cmdArgs.length < 1) {
-            System.err.println("Error: Missing certificate nickname.");
+        if (cmdArgs.length < 1 && id == null) {
+            System.err.println("Error: Missing certificate nickname or ID.");
             printHelp();
             System.exit(-1);
         }
 
-        String nickname = cmdArgs[0];
+        if (cmdArgs.length >= 1 && id != null) {
+            System.err.println("Error: Certificate nickname and ID are mutually exclusive.");
+            printHelp();
+            System.exit(-1);
+        }
+
+        String nickname = null;
+        BigInteger certID = null;
+
+        if (cmdArgs.length >= 1) {
+            nickname = cmdArgs[0];
+        } else {
+            certID = new BigInteger(id, 16);
+        }
 
         String pkcs12File = cmd.getOptionValue("pkcs12-file");
 
@@ -153,17 +174,30 @@ public class PKCS12CertExportCLI extends CLI {
             PKCS12Util util = new PKCS12Util();
             PKCS12 pkcs12 = util.loadFromFile(pkcs12File, password);
 
-            PKCS12CertInfo certInfo = pkcs12.getCertInfoByNickname(nickname);
-            if (certInfo == null) {
+            Collection<PKCS12CertInfo> certInfos = new ArrayList<PKCS12CertInfo>();
+
+            if (nickname != null) {
+                certInfos.addAll(pkcs12.getCertInfosByNickname(nickname));
+
+            } else {
+                PKCS12CertInfo certInfo = pkcs12.getCertInfoByID(certID);
+                if (certInfo != null) {
+                    certInfos.add(certInfo);
+                }
+            }
+
+            if (certInfos.isEmpty()) {
                 System.err.println("Error: Certificate not found.");
                 System.exit(-1);
             }
 
-            X509CertImpl cert = certInfo.getCert();
             try (PrintStream os = new PrintStream(new FileOutputStream(certFile))) {
-                os.println("-----BEGIN CERTIFICATE-----");
-                os.print(Utils.base64encode(cert.getEncoded()));
-                os.println("-----END CERTIFICATE-----");
+                for (PKCS12CertInfo certInfo : certInfos) {
+                    X509CertImpl cert = certInfo.getCert();
+                    os.println("-----BEGIN CERTIFICATE-----");
+                    os.print(Utils.base64encode(cert.getEncoded()));
+                    os.println("-----END CERTIFICATE-----");
+                }
             }
 
         } finally {
diff --git a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertFindCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertFindCLI.java
index a979331888bb909274010057fce3de062256eccd..9bb4ad3ba2113e2426e8d9a250c0041647e1e562 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertFindCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertFindCLI.java
@@ -133,17 +133,17 @@ public class PKCS12CertFindCLI extends CLI {
 
         Password password = new Password(passwordString.toCharArray());
 
-        Collection<PKCS12CertInfo> certInfos;
+        PKCS12 pkcs12;
         try {
             PKCS12Util util = new PKCS12Util();
-            PKCS12 pkcs12 = util.loadFromFile(filename, password);
-
-            certInfos = pkcs12.getCertInfos();
+            pkcs12 = util.loadFromFile(filename, password);
 
         } finally {
             password.clear();
         }
 
+        Collection<PKCS12CertInfo> certInfos = pkcs12.getCertInfos();
+
         MainCLI.printMessage(certInfos.size() + " entries found");
         if (certInfos.size() == 0) return;
 
@@ -156,7 +156,7 @@ public class PKCS12CertFindCLI extends CLI {
                 System.out.println();
             }
 
-            PKCS12CertCLI.printCertInfo(certInfo);
+            PKCS12CertCLI.printCertInfo(pkcs12, certInfo);
         }
     }
 }
diff --git a/base/server/python/pki/server/deployment/scriptlets/security_databases.py b/base/server/python/pki/server/deployment/scriptlets/security_databases.py
index 3947ad64cec7aa8b0a622e1e89136889196ea074..a567b7cdf6ef164b60b9924412388892cbb02efa 100644
--- a/base/server/python/pki/server/deployment/scriptlets/security_databases.py
+++ b/base/server/python/pki/server/deployment/scriptlets/security_databases.py
@@ -108,6 +108,25 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
             if external_certs_path is not None:
                 self.update_external_certs_conf(external_certs_path, deployer)
 
+        # import CA certificates from PKCS #12 file for cloning
+        pki_clone_pkcs12_path = deployer.mdict['pki_clone_pkcs12_path']
+
+        if pki_clone_pkcs12_path:
+
+            pki_clone_pkcs12_password = deployer.mdict[
+                'pki_clone_pkcs12_password']
+            if not pki_clone_pkcs12_password:
+                raise Exception('Missing pki_clone_pkcs12_password property.')
+
+            nssdb = pki.nssdb.NSSDatabase(
+                directory=deployer.mdict['pki_database_path'],
+                password_file=deployer.mdict['pki_shared_pfile'])
+
+            nssdb.import_pkcs12(
+                pkcs12_file=pki_clone_pkcs12_path,
+                pkcs12_password=pki_clone_pkcs12_password,
+                no_user_certs=True)
+
         if len(deployer.instance.tomcat_instance_subsystems()) < 2:
             # only create a self signed cert for a new instance
             #
diff --git a/base/util/src/netscape/security/pkcs/PKCS12.java b/base/util/src/netscape/security/pkcs/PKCS12.java
index 4f2f1600b36fbae6c8b3dd18597e3a1ba050b2dc..6c7880aa8039e3f568285fe55adc0adb15ebeb22 100644
--- a/base/util/src/netscape/security/pkcs/PKCS12.java
+++ b/base/util/src/netscape/security/pkcs/PKCS12.java
@@ -18,6 +18,7 @@
 package netscape.security.pkcs;
 
 import java.math.BigInteger;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -141,7 +142,7 @@ public class PKCS12 {
 
     Map<BigInteger, PKCS12KeyInfo> keyInfosByID = new LinkedHashMap<BigInteger, PKCS12KeyInfo>();
 
-    Map<String, PKCS12CertInfo> certInfosByNickname = new LinkedHashMap<String, PKCS12CertInfo>();
+    Map<BigInteger, PKCS12CertInfo> certInfosByID = new LinkedHashMap<BigInteger, PKCS12CertInfo>();
 
     public PKCS12() {
     }
@@ -163,28 +164,42 @@ public class PKCS12 {
     }
 
     public Collection<PKCS12CertInfo> getCertInfos() {
-        return certInfosByNickname.values();
+        return certInfosByID.values();
     }
 
     public void addCertInfo(PKCS12CertInfo certInfo, boolean replace) {
-        String nickname = certInfo.nickname;
-        if (!replace && certInfosByNickname.containsKey(nickname))
+        BigInteger id = certInfo.getID();
+
+        if (!replace && certInfosByID.containsKey(id))
             return;
 
-        certInfosByNickname.put(nickname, certInfo);
+        certInfosByID.put(id, certInfo);
     }
 
-    public PKCS12CertInfo getCertInfoByNickname(String nickname) {
-        return certInfosByNickname.get(nickname);
+    public PKCS12CertInfo getCertInfoByID(BigInteger id) {
+        return certInfosByID.get(id);
     }
 
-    public PKCS12CertInfo removeCertInfoByNickname(String nickname) {
-        // remove cert
-        PKCS12CertInfo certInfo = certInfosByNickname.remove(nickname);
-        if (certInfo == null) return null;
+    public Collection<PKCS12CertInfo> getCertInfosByNickname(String nickname) {
 
-        // remove private key
-        keyInfosByID.remove(certInfo.getKeyID());
-        return certInfo;
+        Collection<PKCS12CertInfo> result = new ArrayList<PKCS12CertInfo>();
+
+        for (PKCS12CertInfo certInfo : certInfosByID.values()) {
+            if (!nickname.equals(certInfo.getNickname())) continue;
+            result.add(certInfo);
+        }
+
+        return result;
+    }
+
+    public void removeCertInfoByNickname(String nickname) {
+
+        Collection<PKCS12CertInfo> result = getCertInfosByNickname(nickname);
+
+        for (PKCS12CertInfo certInfo : result) {
+            // remove cert and key
+            certInfosByID.remove(certInfo.getID());
+            keyInfosByID.remove(certInfo.getID());
+        }
     }
 }
diff --git a/base/util/src/netscape/security/pkcs/PKCS12CertInfo.java b/base/util/src/netscape/security/pkcs/PKCS12CertInfo.java
index 3ac643eb1507d528e02ec23c1517f2b135745528..ec7b0e332f8909c4a7aefae8ed58c9117e485a89 100644
--- a/base/util/src/netscape/security/pkcs/PKCS12CertInfo.java
+++ b/base/util/src/netscape/security/pkcs/PKCS12CertInfo.java
@@ -23,7 +23,7 @@ import netscape.security.x509.X509CertImpl;
 
 public class PKCS12CertInfo {
 
-    BigInteger keyID;
+    BigInteger id;
     X509CertImpl cert;
     String nickname;
     String trustFlags;
@@ -31,12 +31,12 @@ public class PKCS12CertInfo {
     public PKCS12CertInfo() {
     }
 
-    public BigInteger getKeyID() {
-        return keyID;
+    public BigInteger getID() {
+        return id;
     }
 
-    public void setKeyID(BigInteger keyID) {
-        this.keyID = keyID;
+    public void setID(BigInteger id) {
+        this.id = id;
     }
 
     public X509CertImpl getCert() {
diff --git a/base/util/src/netscape/security/pkcs/PKCS12Util.java b/base/util/src/netscape/security/pkcs/PKCS12Util.java
index 35b9ed598b98c782c963c3838f1dc9952fd803a1..7c9ab2fb4e9554b18c3bf09c9e7c90f8349918fd 100644
--- a/base/util/src/netscape/security/pkcs/PKCS12Util.java
+++ b/base/util/src/netscape/security/pkcs/PKCS12Util.java
@@ -28,6 +28,7 @@ import java.security.MessageDigest;
 import java.security.Principal;
 import java.security.PublicKey;
 import java.security.cert.CertificateException;
+import java.util.Collection;
 import java.util.logging.Logger;
 
 import org.mozilla.jss.CryptoManager;
@@ -160,7 +161,7 @@ public class PKCS12Util {
         safeContents.addElement(safeBag);
     }
 
-    BigInteger createLocalKeyID(X509Certificate cert) throws Exception {
+    BigInteger createLocalID(X509Certificate cert) throws Exception {
 
         // SHA1 hash of the X509Cert DER encoding
         byte[] certDer = cert.getEncoded();
@@ -209,12 +210,12 @@ public class PKCS12Util {
 
         attrs.addElement(nicknameAttr);
 
-        if (certInfo.keyID != null) {
+        if (certInfo.getID() != null) {
             SEQUENCE localKeyAttr = new SEQUENCE();
             localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID);
 
             SET localKeySet = new SET();
-            localKeySet.addElement(new OCTET_STRING(certInfo.keyID.toByteArray()));
+            localKeySet.addElement(new OCTET_STRING(certInfo.id.toByteArray()));
             localKeyAttr.addElement(localKeySet);
 
             attrs.addElement(localKeyAttr);
@@ -250,24 +251,28 @@ public class PKCS12Util {
     public void loadCertFromNSS(PKCS12 pkcs12, String nickname) throws Exception {
 
         CryptoManager cm = CryptoManager.getInstance();
-        X509Certificate cert = cm.findCertByNickname(nickname);
-        loadCertChainFromNSS(pkcs12, cert);
+
+        X509Certificate[] certs = cm.findCertsByNickname(nickname);
+        for (X509Certificate cert : certs) {
+            loadCertChainFromNSS(pkcs12, cert);
+        }
     }
 
-    public void loadCertFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger keyID, boolean replace) throws Exception {
+    public void loadCertFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id, boolean replace) throws Exception {
 
         String nickname = cert.getNickname();
         logger.info("Loading certificate \"" + nickname + "\" from NSS database");
 
         PKCS12CertInfo certInfo = new PKCS12CertInfo();
-        certInfo.keyID = keyID;
+        certInfo.id = id;
         certInfo.nickname = nickname;
         certInfo.cert = new X509CertImpl(cert.getEncoded());
         certInfo.trustFlags = getTrustFlags(cert);
+
         pkcs12.addCertInfo(certInfo, replace);
     }
 
-    public void loadCertKeyFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger keyID) throws Exception {
+    public void loadCertKeyFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id) throws Exception {
 
         String nickname = cert.getNickname();
         logger.info("Loading private key for certificate \"" + nickname + "\" from NSS database");
@@ -279,7 +284,7 @@ public class PKCS12Util {
             logger.fine("Certificate \"" + nickname + "\" has private key");
 
             PKCS12KeyInfo keyInfo = new PKCS12KeyInfo();
-            keyInfo.id = keyID;
+            keyInfo.id = id;
             keyInfo.subjectDN = cert.getSubjectDN().toString();
 
             byte[] privateData = getEncodedKey(privateKey);
@@ -297,17 +302,20 @@ public class PKCS12Util {
 
         CryptoManager cm = CryptoManager.getInstance();
 
-        BigInteger keyID = createLocalKeyID(cert);
+        BigInteger id = createLocalID(cert);
 
-        // load cert with key
-        loadCertFromNSS(pkcs12, cert, keyID, true);
-        loadCertKeyFromNSS(pkcs12, cert, keyID);
+        // load cert key if exists
+        loadCertKeyFromNSS(pkcs12, cert, id);
+
+        // load cert
+        loadCertFromNSS(pkcs12, cert, id, true);
 
         // load parent certs without key
         X509Certificate[] certChain = cm.buildCertificateChain(cert);
         for (int i = 1; i < certChain.length; i++) {
             X509Certificate c = certChain[i];
-            loadCertFromNSS(pkcs12, c, null, false);
+            BigInteger cid = createLocalID(c);
+            loadCertFromNSS(pkcs12, c, cid, false);
         }
     }
 
@@ -379,7 +387,7 @@ public class PKCS12Util {
                 OCTET_STRING keyID = (OCTET_STRING) new OCTET_STRING.Template().decode(bis);
 
                 keyInfo.id = new BigInteger(1, keyID.toByteArray());
-                logger.fine("Key ID: " + keyInfo.id.toString(16));
+                logger.fine("ID: " + keyInfo.id.toString(16));
             }
         }
 
@@ -428,8 +436,8 @@ public class PKCS12Util {
                 ByteArrayInputStream bis = new ByteArrayInputStream(value.getEncoded());
                 OCTET_STRING keyID = (OCTET_STRING) new OCTET_STRING.Template().decode(bis);
 
-                certInfo.keyID = new BigInteger(1, keyID.toByteArray());
-                logger.fine("Key ID: " + certInfo.keyID.toString(16));
+                certInfo.id = new BigInteger(1, keyID.toByteArray());
+                logger.fine("ID: " + certInfo.id.toString(16));
 
             } else if (oid.equals(PKCS12.CERT_TRUST_FLAGS_OID) && trustFlagsEnabled) {
 
@@ -596,8 +604,8 @@ public class PKCS12Util {
         CryptoManager cm = CryptoManager.getInstance();
 
         X509Certificate cert;
-        BigInteger keyID = certInfo.getKeyID();
-        PKCS12KeyInfo keyInfo = keyID == null ? null : pkcs12.getKeyInfoByID(keyID);
+        BigInteger id = certInfo.getID();
+        PKCS12KeyInfo keyInfo = pkcs12.getKeyInfoByID(id);
 
         if (keyInfo != null) { // cert has key
             logger.fine("Importing user key for " + certInfo.nickname);
@@ -608,6 +616,7 @@ public class PKCS12Util {
 
         } else { // cert has no key
             logger.fine("Importing CA certificate " + certInfo.nickname);
+            // Note: JSS does not preserve CA certificate nickname
             cert = cm.importCACertPackage(certInfo.cert.getEncoded());
         }
 
@@ -616,8 +625,10 @@ public class PKCS12Util {
     }
 
     public void storeCertIntoNSS(PKCS12 pkcs12, String nickname) throws Exception {
-        PKCS12CertInfo certInfo = pkcs12.getCertInfoByNickname(nickname);
-        storeCertIntoNSS(pkcs12, certInfo);
+        Collection<PKCS12CertInfo> certInfos = pkcs12.getCertInfosByNickname(nickname);
+        for (PKCS12CertInfo certInfo : certInfos) {
+            storeCertIntoNSS(pkcs12, certInfo);
+        }
     }
 
     public void storeIntoNSS(PKCS12 pkcs12) throws Exception {
-- 
2.4.3

_______________________________________________
Pki-devel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/pki-devel

Reply via email to