Blob Blame History Raw
From b216472ddd80f64b136b3ac367d3415b526c97d4 Mon Sep 17 00:00:00 2001
From: Matthew Harmsen <mharmsen@redhat.com>
Date: Fri, 1 Apr 2016 14:57:07 -0600
Subject: [PATCH] Fixed missing trust flags in certificate backup.

The ConfigurationUtils.backupKeys() has been modified to use
PKCS12Util to export the certificates and their trust flags into
a PKCS #12 file such that the file can be used for cloning.

The code to generate PFX object has been refactored from the
PKCS12Util.storeIntoFile() into a separate generatePFX() method.

The PKCS12Util.loadCertFromNSS() has been modified to provide
options to load a certificate from NSS database without the key
or the certificate chain. The CLIs have been modified to provide
the same options.

The PKCS12Util.getCertInfo() has modified to ignore missing
certificate attributes in the PKCS #12 file and generate a new
local ID.

https://fedorahosted.org/pki/ticket/2257
---
 base/java-tools/bin/pki                            |   3 +
 .../netscape/cmstools/pkcs12/PKCS12CertAddCLI.java |   7 +-
 .../netscape/cmstools/pkcs12/PKCS12ExportCLI.java  |  12 ++-
 .../cms/servlet/csadmin/ConfigurationUtils.java    |  39 ++++----
 .../src/netscape/security/pkcs/PKCS12Util.java     | 108 ++++++++++++---------
 5 files changed, 97 insertions(+), 72 deletions(-)

diff --git a/base/java-tools/bin/pki b/base/java-tools/bin/pki
index e476cfc..88490f7 100644
--- a/base/java-tools/bin/pki
+++ b/base/java-tools/bin/pki
@@ -138,6 +138,9 @@ class PKICLI(pki.cli.CLI):
         if self.token and self.token != 'internal':
             cmd.extend(['--token', self.token])
 
+        if self.verbose:
+            cmd.extend(['--verbose'])
+
         cmd.extend(args)
 
         if self.verbose:
diff --git a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertAddCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertAddCLI.java
index 48e4907..a422b20 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertAddCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertAddCLI.java
@@ -65,6 +65,8 @@ public class PKCS12CertAddCLI extends CLI {
 
         options.addOption(null, "new-file", false, "Create a new PKCS #12 file");
         options.addOption(null, "no-trust-flags", false, "Do not include trust flags");
+        options.addOption(null, "no-key", false, "Do not include private key");
+        options.addOption(null, "no-chain", false, "Do not include certificate chain");
 
         options.addOption("v", "verbose", false, "Run in verbose mode.");
         options.addOption(null, "debug", false, "Run in debug mode.");
@@ -139,6 +141,8 @@ public class PKCS12CertAddCLI extends CLI {
 
         boolean newFile = cmd.hasOption("new-file");
         boolean includeTrustFlags = !cmd.hasOption("no-trust-flags");
+        boolean includeKey = !cmd.hasOption("no-key");
+        boolean includeChain = !cmd.hasOption("no-chain");
 
         try {
             PKCS12Util util = new PKCS12Util();
@@ -155,7 +159,8 @@ public class PKCS12CertAddCLI extends CLI {
                 pkcs12 = util.loadFromFile(filename, password);
             }
 
-            util.loadCertFromNSS(pkcs12, nickname);
+            // load the specified certificate
+            util.loadCertFromNSS(pkcs12, nickname, includeKey, includeChain);
             util.storeIntoFile(pkcs12, filename, password);
 
         } finally {
diff --git a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java
index d42c449..fab5ecd 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java
@@ -63,6 +63,8 @@ public class PKCS12ExportCLI extends CLI {
 
         options.addOption(null, "new-file", false, "Create a new PKCS #12 file");
         options.addOption(null, "no-trust-flags", false, "Do not include trust flags");
+        options.addOption(null, "no-key", false, "Do not include private key");
+        options.addOption(null, "no-chain", false, "Do not include certificate chain");
 
         options.addOption("v", "verbose", false, "Run in verbose mode.");
         options.addOption(null, "debug", false, "Run in debug mode.");
@@ -127,11 +129,13 @@ public class PKCS12ExportCLI extends CLI {
         Password password = new Password(passwordString.toCharArray());
 
         boolean newFile = cmd.hasOption("new-file");
-        boolean trustFlagsEnabled = !cmd.hasOption("no-trust-flags");
+        boolean includeTrustFlags = !cmd.hasOption("no-trust-flags");
+        boolean includeKey = !cmd.hasOption("no-key");
+        boolean includeChain = !cmd.hasOption("no-chain");
 
         try {
             PKCS12Util util = new PKCS12Util();
-            util.setTrustFlagsEnabled(trustFlagsEnabled);
+            util.setTrustFlagsEnabled(includeTrustFlags);
 
             PKCS12 pkcs12;
 
@@ -149,9 +153,9 @@ public class PKCS12ExportCLI extends CLI {
                 util.loadFromNSS(pkcs12);
 
             } else {
-                // load specified certificates
+                // load the specified certificates
                 for (String nickname : nicknames) {
-                    util.loadCertFromNSS(pkcs12, nickname);
+                    util.loadCertFromNSS(pkcs12, nickname, includeKey, includeChain);
                 }
             }
 
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index f092eac..713e1b0 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -32,7 +32,6 @@ import java.net.ConnectException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URLEncoder;
-import java.security.DigestException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.KeyPair;
@@ -171,6 +170,8 @@ import netscape.ldap.LDAPSearchResults;
 import netscape.ldap.LDAPv3;
 import netscape.security.pkcs.ContentInfo;
 import netscape.security.pkcs.PKCS10;
+import netscape.security.pkcs.PKCS12;
+import netscape.security.pkcs.PKCS12Util;
 import netscape.security.pkcs.PKCS7;
 import netscape.security.pkcs.SignerInfo;
 import netscape.security.util.DerOutputStream;
@@ -3352,11 +3353,8 @@ public class ConfigurationUtils {
         }
     }
 
-    public static void backupKeys(String pwd, String fname) throws EPropertyNotFound, EBaseException,
-            NotInitializedException, ObjectNotFoundException, TokenException, DigestException,
-            InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidBERException,
-            CertificateEncodingException, IllegalStateException, IllegalBlockSizeException, BadPaddingException,
-            IOException {
+    public static void backupKeys(String pwd, String fname) throws Exception {
+
         CMS.debug("backupKeys(): start");
         IConfigStore cs = CMS.getConfigStore();
         String certlist = cs.getString("preop.cert.list");
@@ -3365,9 +3363,13 @@ public class ConfigurationUtils {
         CryptoManager cm = CryptoManager.getInstance();
 
         Password pass = new org.mozilla.jss.util.Password(pwd.toCharArray());
-        SEQUENCE encSafeContents = new SEQUENCE();
-        SEQUENCE safeContents = new SEQUENCE();
+
+        PKCS12Util util = new PKCS12Util();
+        PKCS12 pkcs12 = new PKCS12();
+
+        // load system certificate (with key but without chain)
         while (st.hasMoreTokens()) {
+
             String t = st.nextToken();
             if (t.equals("sslserver"))
                 continue;
@@ -3377,27 +3379,20 @@ public class ConfigurationUtils {
             if (!modname.equals("Internal Key Storage Token"))
                 nickname = modname + ":" + nickname;
 
-            X509Certificate x509cert = cm.findCertByNickname(nickname);
-            byte localKeyId[] = addCertBag(x509cert, nickname, safeContents);
-            PrivateKey pkey = cm.findPrivKeyByCert(x509cert);
-            addKeyBag(pkey, x509cert, pass, localKeyId, encSafeContents);
+            util.loadCertFromNSS(pkcs12, nickname, true, false);
         }
 
-        X509Certificate[] cacerts = cm.getCACerts();
-
-        for (int i = 0; i < cacerts.length; i++) {
-            String nickname = null;
-            addCertBag(cacerts[i], nickname, safeContents);
+        // load CA certificates (without keys or chains)
+        for (X509Certificate caCert : cm.getCACerts()) {
+            util.loadCertFromNSS(pkcs12, caCert, false, false);
         }
 
-        AuthenticatedSafes authSafes = new AuthenticatedSafes();
-        authSafes.addSafeContents(safeContents);
-        authSafes.addSafeContents(encSafeContents);
-        PFX pfx = new PFX(authSafes);
-        pfx.computeMacData(pass, null, 5);
+        PFX pfx = util.generatePFX(pkcs12, pass);
+
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         pfx.encode(bos);
         byte[] output = bos.toByteArray();
+
         cs.putString("preop.pkcs12", CryptoUtil.byte2string(output));
         pass.clear();
         cs.commit(false);
diff --git a/base/util/src/netscape/security/pkcs/PKCS12Util.java b/base/util/src/netscape/security/pkcs/PKCS12Util.java
index 7c9ab2f..967479b 100644
--- a/base/util/src/netscape/security/pkcs/PKCS12Util.java
+++ b/base/util/src/netscape/security/pkcs/PKCS12Util.java
@@ -162,13 +162,14 @@ public class PKCS12Util {
     }
 
     BigInteger createLocalID(X509Certificate cert) throws Exception {
-
         // SHA1 hash of the X509Cert DER encoding
-        byte[] certDer = cert.getEncoded();
+        return createLocalID(cert.getEncoded());
+    }
 
-        MessageDigest md = MessageDigest.getInstance("SHA");
+    BigInteger createLocalID(byte[] bytes) throws Exception {
 
-        md.update(certDer);
+        MessageDigest md = MessageDigest.getInstance("SHA");
+        md.update(bytes);
         return new BigInteger(1, md.digest());
     }
 
@@ -244,21 +245,46 @@ public class PKCS12Util {
         CryptoStore store = token.getCryptoStore();
 
         for (X509Certificate cert : store.getCertificates()) {
-            loadCertChainFromNSS(pkcs12, cert);
+            loadCertFromNSS(pkcs12, cert, true, true);
         }
     }
 
-    public void loadCertFromNSS(PKCS12 pkcs12, String nickname) throws Exception {
+    public void loadCertFromNSS(PKCS12 pkcs12, String nickname, boolean includeKey, boolean includeChain) throws Exception {
 
         CryptoManager cm = CryptoManager.getInstance();
 
         X509Certificate[] certs = cm.findCertsByNickname(nickname);
         for (X509Certificate cert : certs) {
-            loadCertChainFromNSS(pkcs12, cert);
+            loadCertFromNSS(pkcs12, cert, includeKey, includeChain);
         }
     }
 
-    public void loadCertFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id, boolean replace) throws Exception {
+    public void loadCertFromNSS(PKCS12 pkcs12, X509Certificate cert, boolean includeKey, boolean includeChain) throws Exception {
+
+        CryptoManager cm = CryptoManager.getInstance();
+
+        BigInteger id = createLocalID(cert);
+
+        // load cert info
+        loadCertInfoFromNSS(pkcs12, cert, id, true);
+
+        if (includeKey) {
+            // load key info if exists
+            loadKeyInfoFromNSS(pkcs12, cert, id);
+        }
+
+        if (includeChain) {
+            // load cert chain
+            X509Certificate[] certChain = cm.buildCertificateChain(cert);
+            for (int i = 1; i < certChain.length; i++) {
+                X509Certificate c = certChain[i];
+                BigInteger cid = createLocalID(c);
+                loadCertInfoFromNSS(pkcs12, c, cid, false);
+            }
+        }
+    }
+
+    public void loadCertInfoFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id, boolean replace) throws Exception {
 
         String nickname = cert.getNickname();
         logger.info("Loading certificate \"" + nickname + "\" from NSS database");
@@ -272,7 +298,7 @@ public class PKCS12Util {
         pkcs12.addCertInfo(certInfo, replace);
     }
 
-    public void loadCertKeyFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id) throws Exception {
+    public void loadKeyInfoFromNSS(PKCS12 pkcs12, X509Certificate cert, BigInteger id) throws Exception {
 
         String nickname = cert.getNickname();
         logger.info("Loading private key for certificate \"" + nickname + "\" from NSS database");
@@ -298,30 +324,9 @@ public class PKCS12Util {
         }
     }
 
-    public void loadCertChainFromNSS(PKCS12 pkcs12, X509Certificate cert) throws Exception {
-
-        CryptoManager cm = CryptoManager.getInstance();
+    public PFX generatePFX(PKCS12 pkcs12, Password password) throws Exception {
 
-        BigInteger id = createLocalID(cert);
-
-        // 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];
-            BigInteger cid = createLocalID(c);
-            loadCertFromNSS(pkcs12, c, cid, false);
-        }
-    }
-
-    public void storeIntoFile(PKCS12 pkcs12, String filename, Password password) throws Exception {
-
-        logger.info("Storing data into PKCS #12 file");
+        logger.info("Generating PKCS #12 data");
 
         SEQUENCE safeContents = new SEQUENCE();
 
@@ -342,6 +347,14 @@ public class PKCS12Util {
         PFX pfx = new PFX(authSafes);
         pfx.computeMacData(password, null, 5);
 
+        return pfx;
+    }
+
+    public void storeIntoFile(PKCS12 pkcs12, String filename, Password password) throws Exception {
+
+        PFX pfx = generatePFX(pkcs12, password);
+
+        logger.info("Storing data into PKCS #12 file");
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         pfx.encode(bos);
         byte[] data = bos.toByteArray();
@@ -362,7 +375,7 @@ public class PKCS12Util {
         // get key attributes
         SET bagAttrs = bag.getBagAttributes();
 
-        for (int i = 0; i < bagAttrs.size(); i++) {
+        for (int i = 0; bagAttrs != null && i < bagAttrs.size(); i++) {
 
             Attribute attr = (Attribute) bagAttrs.elementAt(i);
             OBJECT_IDENTIFIER oid = attr.getType();
@@ -376,7 +389,7 @@ public class PKCS12Util {
                 BMPString subjectDN = (BMPString) new BMPString.Template().decode(bis);
 
                 keyInfo.subjectDN = subjectDN.toString();
-                logger.fine("Subject DN: " + keyInfo.subjectDN);
+                logger.fine("   Subject DN: " + keyInfo.subjectDN);
 
             } else if (oid.equals(SafeBag.LOCAL_KEY_ID)) {
 
@@ -387,12 +400,10 @@ public class PKCS12Util {
                 OCTET_STRING keyID = (OCTET_STRING) new OCTET_STRING.Template().decode(bis);
 
                 keyInfo.id = new BigInteger(1, keyID.toByteArray());
-                logger.fine("ID: " + keyInfo.id.toString(16));
+                logger.fine("   ID: " + keyInfo.id.toString(16));
             }
         }
 
-        logger.fine("Found private key " + keyInfo.subjectDN);
-
         return keyInfo;
     }
 
@@ -406,12 +417,11 @@ public class PKCS12Util {
         byte[] x509cert = certStr.toByteArray();
 
         certInfo.cert = new X509CertImpl(x509cert);
-        logger.fine("Found certificate " + certInfo.cert.getSubjectDN());
+        logger.fine("   Subject DN: " + certInfo.cert.getSubjectDN());
 
         SET bagAttrs = bag.getBagAttributes();
-        if (bagAttrs == null) return certInfo;
 
-        for (int i = 0; i < bagAttrs.size(); i++) {
+        for (int i = 0; bagAttrs != null && i < bagAttrs.size(); i++) {
 
             Attribute attr = (Attribute) bagAttrs.elementAt(i);
             OBJECT_IDENTIFIER oid = attr.getType();
@@ -425,7 +435,7 @@ public class PKCS12Util {
                 BMPString nickname = (BMPString) (new BMPString.Template()).decode(bis);
 
                 certInfo.nickname = nickname.toString();
-                logger.fine("Nickname: " + certInfo.nickname);
+                logger.fine("   Nickname: " + certInfo.nickname);
 
 
             } else if (oid.equals(SafeBag.LOCAL_KEY_ID)) {
@@ -437,7 +447,7 @@ public class PKCS12Util {
                 OCTET_STRING keyID = (OCTET_STRING) new OCTET_STRING.Template().decode(bis);
 
                 certInfo.id = new BigInteger(1, keyID.toByteArray());
-                logger.fine("ID: " + certInfo.id.toString(16));
+                logger.fine("   ID: " + certInfo.id.toString(16));
 
             } else if (oid.equals(PKCS12.CERT_TRUST_FLAGS_OID) && trustFlagsEnabled) {
 
@@ -448,16 +458,22 @@ public class PKCS12Util {
                 BMPString trustFlags = (BMPString) (new BMPString.Template()).decode(is);
 
                 certInfo.trustFlags = trustFlags.toString();
-                logger.fine("Trust flags: " + certInfo.trustFlags);
+                logger.fine("   Trust flags: " + certInfo.trustFlags);
             }
         }
 
+        if (certInfo.id == null) {
+            logger.fine("   ID not specified, generating new ID");
+            certInfo.id = createLocalID(x509cert);
+            logger.fine("   ID: " + certInfo.id.toString(16));
+        }
+
         return certInfo;
     }
 
     public void getKeyInfos(PKCS12 pkcs12, PFX pfx, Password password) throws Exception {
 
-        logger.fine("Getting private keys");
+        logger.fine("Load private keys:");
 
         AuthenticatedSafes safes = pfx.getAuthSafes();
 
@@ -472,6 +488,7 @@ public class PKCS12Util {
 
                 if (!oid.equals(SafeBag.PKCS8_SHROUDED_KEY_BAG)) continue;
 
+                logger.fine(" - Private key:");
                 PKCS12KeyInfo keyInfo = getKeyInfo(bag, password);
                 pkcs12.addKeyInfo(keyInfo);
             }
@@ -480,7 +497,7 @@ public class PKCS12Util {
 
     public void getCertInfos(PKCS12 pkcs12, PFX pfx, Password password) throws Exception {
 
-        logger.fine("Getting certificates");
+        logger.fine("Loading certificates:");
 
         AuthenticatedSafes safes = pfx.getAuthSafes();
 
@@ -495,6 +512,7 @@ public class PKCS12Util {
 
                 if (!oid.equals(SafeBag.CERT_BAG)) continue;
 
+                logger.fine(" - Certificate:");
                 PKCS12CertInfo certInfo = getCertInfo(bag);
                 pkcs12.addCertInfo(certInfo, true);
             }
-- 
1.8.3.1