[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Pki-devel] [PATCH] 683 Added PKCS #12 attribute to store certificate trust flags.



A new PKCS #12 attribute has been defined to store NSS certificate
trust flags in PKCS #12 file. The PKCS12Util has been modified to
store the trust flags during export and reset the trust flags in
NSS database during import.

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

--
Endi S. Dewata
From 156f28c875ce9348df6ccbd036af18e4f37e031b Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata redhat com>
Date: Sat, 13 Feb 2016 09:42:14 +0100
Subject: [PATCH] Added PKCS #12 attribute to store certificate trust flags.

A new PKCS #12 attribute has been defined to store NSS certificate
trust flags in PKCS #12 file. The PKCS12Util has been modified to
store the trust flags during export and reset the trust flags in
NSS database during import.

https://fedorahosted.org/pki/ticket/1742
---
 .../netscape/cmstools/pkcs12/PKCS12CertCLI.java    |  10 +-
 base/util/src/netscape/security/pkcs/PKCS12.java   | 136 ++++++++++++++
 .../src/netscape/security/pkcs/PKCS12Util.java     | 198 ++++++++++++++-------
 3 files changed, 279 insertions(+), 65 deletions(-)
 create mode 100644 base/util/src/netscape/security/pkcs/PKCS12.java

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 2179c186c37ed324933f8f5867d954cc67a158ee..f4d97cd742ec294671008fece537ed4f0a09dc3b 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertCLI.java
@@ -18,6 +18,7 @@
 
 package com.netscape.cmstools.pkcs12;
 
+import com.netscape.certsrv.dbs.certdb.CertId;
 import com.netscape.cmstools.cli.CLI;
 
 import netscape.security.pkcs.PKCS12Util.PKCS12CertInfo;
@@ -34,8 +35,13 @@ public class PKCS12CertCLI extends CLI {
     }
 
     public static void printCertInfo(PKCS12CertInfo certInfo) throws Exception {
+        System.out.println("  Serial Number: " + new CertId(certInfo.cert.getSerialNumber()).toHexString());
         System.out.println("  Nickname: " + certInfo.nickname);
-        System.out.println("  Subject: " + certInfo.cert.getSubjectDN());
-        System.out.println("  Issuer: " + certInfo.cert.getIssuerDN());
+        System.out.println("  Subject DN: " + certInfo.cert.getSubjectDN());
+        System.out.println("  Issuer DN: " + certInfo.cert.getIssuerDN());
+
+        if (certInfo.trustFlags != null) {
+            System.out.println("  Trust flags: " + certInfo.trustFlags);
+        }
     }
 }
diff --git a/base/util/src/netscape/security/pkcs/PKCS12.java b/base/util/src/netscape/security/pkcs/PKCS12.java
new file mode 100644
index 0000000000000000000000000000000000000000..df7fde447745dc9f17ee7c0e0d1ea42de1aab796
--- /dev/null
+++ b/base/util/src/netscape/security/pkcs/PKCS12.java
@@ -0,0 +1,136 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2016 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+
+public class PKCS12 {
+
+    // PKI OID: 2.16.840.1.113730.5
+    public final static OBJECT_IDENTIFIER PKI_OID = new OBJECT_IDENTIFIER("2.16.840.1.113730.5");
+
+    // PKCS #12 OID: 2.16.840.1.113730.5.1
+    public final static OBJECT_IDENTIFIER PKCS12_OID = PKI_OID.subBranch(1);
+
+    // PKCS #12 attributes OID: 2.16.840.1.113730.5.1.1
+    public final static OBJECT_IDENTIFIER PKCS12_ATTRIBUTES_OID = PKCS12_OID.subBranch(1);
+
+    // Certificate trust flags OID: 2.16.840.1.113730.5.1.1.1
+    public final static OBJECT_IDENTIFIER CERT_TRUST_FLAGS_OID = PKCS12_ATTRIBUTES_OID.subBranch(1);
+
+    // based on certdb.h in NSS
+    public final static int TERMINAL_RECORD   = 1 << 0;
+    public final static int TRUSTED           = 1 << 1;
+    public final static int SEND_WARN         = 1 << 2;
+    public final static int VALID_CA          = 1 << 3;
+    public final static int TRUSTED_CA        = 1 << 4;
+    public final static int NS_TRUSTED_CA     = 1 << 5;
+    public final static int USER              = 1 << 6;
+    public final static int TRUSTED_CLIENT_CA = 1 << 7;
+    public final static int INVISIBLE_CA      = 1 << 8;
+    public final static int GOVT_APPROVED_CA  = 1 << 9;
+
+    public static boolean isFlagEnabled(int flag, int flags) {
+        return (flag & flags) > 0;
+    }
+
+    // based on printflags() in secutil.c in NSS
+    public static String encodeFlags(int flags) {
+
+        StringBuffer sb = new StringBuffer();
+
+        if (isFlagEnabled(VALID_CA, flags) && !isFlagEnabled(TRUSTED_CA, flags) && !isFlagEnabled(TRUSTED_CLIENT_CA, flags))
+            sb.append("c");
+
+        if (isFlagEnabled(TERMINAL_RECORD, flags) && !isFlagEnabled(TRUSTED, flags))
+            sb.append("p");
+
+        if (isFlagEnabled(TRUSTED_CA, flags))
+            sb.append("C");
+
+        if (isFlagEnabled(TRUSTED_CLIENT_CA, flags))
+            sb.append("T");
+
+        if (isFlagEnabled(TRUSTED, flags))
+            sb.append("P");
+
+        if (isFlagEnabled(USER, flags))
+            sb.append("u");
+
+        if (isFlagEnabled(SEND_WARN, flags))
+            sb.append("w");
+
+        if (isFlagEnabled(INVISIBLE_CA, flags))
+            sb.append("I");
+
+        if (isFlagEnabled(GOVT_APPROVED_CA, flags))
+            sb.append("G");
+
+        return sb.toString();
+    }
+
+    // based on CERT_DecodeTrustString() in certdb.c in NSS
+    public static int decodeFlags(String flags) throws Exception {
+
+        int value = 0;
+
+        for (char c : flags.toCharArray()) {
+            switch (c) {
+            case 'p':
+                value = value | TERMINAL_RECORD;
+                break;
+
+            case 'P':
+                value = value | TRUSTED | TERMINAL_RECORD;
+                break;
+
+            case 'w':
+                value = value | SEND_WARN;
+                break;
+
+            case 'c':
+                value = value | VALID_CA;
+                break;
+
+            case 'T':
+                value = value | TRUSTED_CLIENT_CA | VALID_CA;
+                break;
+
+            case 'C' :
+                value = value | TRUSTED_CA | VALID_CA;
+                break;
+
+            case 'u':
+                value = value | USER;
+                break;
+
+            case 'i':
+                value = value | INVISIBLE_CA;
+                break;
+            case 'g':
+                value = value | GOVT_APPROVED_CA;
+                break;
+
+            default:
+                throw new Exception("Invalid trust flag: " + c);
+            }
+        }
+
+        return value;
+    }
+}
diff --git a/base/util/src/netscape/security/pkcs/PKCS12Util.java b/base/util/src/netscape/security/pkcs/PKCS12Util.java
index bcd48970e3b5f66835987e1b65fee81dfcc4963e..709a438c267afc1945444433b2bedd234d63d7ea 100644
--- a/base/util/src/netscape/security/pkcs/PKCS12Util.java
+++ b/base/util/src/netscape/security/pkcs/PKCS12Util.java
@@ -45,6 +45,7 @@ import org.mozilla.jss.crypto.CryptoStore;
 import org.mozilla.jss.crypto.CryptoToken;
 import org.mozilla.jss.crypto.EncryptionAlgorithm;
 import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.InternalCertificate;
 import org.mozilla.jss.crypto.KeyGenAlgorithm;
 import org.mozilla.jss.crypto.KeyGenerator;
 import org.mozilla.jss.crypto.KeyWrapAlgorithm;
@@ -83,6 +84,33 @@ public class PKCS12Util {
     public static class PKCS12CertInfo {
         public X509CertImpl cert;
         public String nickname;
+        public String trustFlags;
+    }
+
+    public String getTrustFlags(X509Certificate cert) {
+
+        InternalCertificate icert = (InternalCertificate) cert;
+
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(PKCS12.encodeFlags(icert.getSSLTrust()));
+        sb.append(",");
+        sb.append(PKCS12.encodeFlags(icert.getEmailTrust()));
+        sb.append(",");
+        sb.append(PKCS12.encodeFlags(icert.getObjectSigningTrust()));
+
+        return sb.toString();
+    }
+
+    public void setTrustFlags(X509Certificate cert, String trustFlags) throws Exception {
+
+        InternalCertificate icert = (InternalCertificate) cert;
+
+        String[] flags = trustFlags.split(",");
+
+        icert.setSSLTrust(PKCS12.decodeFlags(flags[0]));
+        icert.setEmailTrust(PKCS12.decodeFlags(flags[1]));
+        icert.setObjectSigningTrust(PKCS12.decodeFlags(flags[2]));
     }
 
     byte[] getEncodedKey(PrivateKey privateKey) throws Exception {
@@ -107,6 +135,8 @@ public class PKCS12Util {
     public void addKeyBag(PrivateKey privateKey, X509Certificate x509cert,
             Password pass, byte[] localKeyID, SEQUENCE safeContents) throws Exception {
 
+        logger.fine("Creating key bag for " + x509cert.getSubjectDN());
+
         PasswordConverter passConverter = new PasswordConverter();
         byte salt[] = { 0x01, 0x01, 0x01, 0x01 };
         byte[] priData = getEncodedKey(privateKey);
@@ -118,7 +148,7 @@ public class PKCS12Util {
                 PBEAlgorithm.PBE_SHA1_DES3_CBC,
                 pass, salt, 1, passConverter, pki);
 
-        SET keyAttrs = createBagAttrs(
+        SET keyAttrs = createKeyBagAttrs(
                 x509cert.getSubjectDN().toString(), localKeyID);
 
         SafeBag keyBag = new SafeBag(SafeBag.PKCS8_SHROUDED_KEY_BAG,
@@ -130,12 +160,15 @@ public class PKCS12Util {
     public byte[] addCertBag(X509Certificate x509cert, String nickname,
             SEQUENCE safeContents) throws Exception {
 
+        logger.fine("Creating cert bag for " + nickname);
+
         ASN1Value cert = new OCTET_STRING(x509cert.getEncoded());
         byte[] localKeyID = createLocalKeyID(x509cert);
 
-        SET certAttrs = null;
-        if (nickname != null)
-            certAttrs = createBagAttrs(nickname, localKeyID);
+        String trustFlags = getTrustFlags(x509cert);
+        logger.fine("Trust flags: " + trustFlags);
+
+        SET certAttrs = createCertBagAttrs(nickname, localKeyID, trustFlags);
 
         SafeBag certBag = new SafeBag(SafeBag.CERT_BAG,
                 new CertBag(CertBag.X509_CERT_TYPE, cert), certAttrs);
@@ -156,27 +189,64 @@ public class PKCS12Util {
         return md.digest();
     }
 
-    SET createBagAttrs(String nickname, byte localKeyID[])
+    SET createKeyBagAttrs(String subjectDN, byte localKeyID[])
             throws Exception {
 
         SET attrs = new SET();
+
+        SEQUENCE subjectAttr = new SEQUENCE();
+        subjectAttr.addElement(SafeBag.FRIENDLY_NAME);
+
+        SET subjectSet = new SET();
+        subjectSet.addElement(new BMPString(subjectDN));
+        subjectAttr.addElement(subjectSet);
+
+        attrs.addElement(subjectAttr);
+
+        SEQUENCE localKeyAttr = new SEQUENCE();
+        localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID);
+
+        SET localKeySet = new SET();
+        localKeySet.addElement(new OCTET_STRING(localKeyID));
+        localKeyAttr.addElement(localKeySet);
+
+        attrs.addElement(localKeyAttr);
+
+        return attrs;
+    }
+
+    SET createCertBagAttrs(String nickname, byte localKeyID[], String trustFlags)
+            throws Exception {
+
+        SET attrs = new SET();
+
         SEQUENCE nicknameAttr = new SEQUENCE();
-
         nicknameAttr.addElement(SafeBag.FRIENDLY_NAME);
+
         SET nicknameSet = new SET();
-
         nicknameSet.addElement(new BMPString(nickname));
         nicknameAttr.addElement(nicknameSet);
+
         attrs.addElement(nicknameAttr);
+
         SEQUENCE localKeyAttr = new SEQUENCE();
-
         localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID);
+
         SET localKeySet = new SET();
-
         localKeySet.addElement(new OCTET_STRING(localKeyID));
         localKeyAttr.addElement(localKeySet);
+
         attrs.addElement(localKeyAttr);
 
+        SEQUENCE trustFlagsAttr = new SEQUENCE();
+        trustFlagsAttr.addElement(PKCS12.CERT_TRUST_FLAGS_OID);
+
+        SET trustFlagsSet = new SET();
+        trustFlagsSet.addElement(new BMPString(trustFlags));
+        trustFlagsAttr.addElement(trustFlagsSet);
+
+        attrs.addElement(trustFlagsAttr);
+
         return attrs;
     }
 
@@ -191,7 +261,7 @@ public class PKCS12Util {
         SEQUENCE encSafeContents = new SEQUENCE();
         SEQUENCE safeContents = new SEQUENCE();
 
-        logger.fine("Loading certificates:");
+        logger.fine("Loading certificates");
 
         X509Certificate[] certs = store.getCertificates();
 
@@ -200,13 +270,13 @@ public class PKCS12Util {
 
             try {
                 PrivateKey prikey = cm.findPrivKeyByCert(cert);
-                logger.fine(" - cert " + nickname + " with private key");
+                logger.fine("Found certificate " + nickname + " with private key");
 
                 byte localKeyID[] = addCertBag(cert, nickname, safeContents);
                 addKeyBag(prikey, cert, password, localKeyID, encSafeContents);
 
             } catch (ObjectNotFoundException e) {
-                logger.fine(" - cert " + nickname + " without private key");
+                logger.fine("Found certificate " + nickname + " without private key");
                 addCertBag(cert, nickname, safeContents);
             }
         }
@@ -286,41 +356,47 @@ public class PKCS12Util {
 
     public PKCS12CertInfo getCertInfo(SafeBag bag) throws Exception {
 
-        CertBag certBag = (CertBag) bag.getInterpretedBagContent();
-
-        OCTET_STRING str = (OCTET_STRING) certBag.getInterpretedCert();
-        byte[] x509cert = str.toByteArray();
-
-        // find cert's nickname
-        SET bagAttrs = bag.getBagAttributes();
-        String nickname = null;
-
-        if (bagAttrs != null) {
-
-            for (int k = 0; k < bagAttrs.size(); k++) {
-
-                Attribute attr = (Attribute) bagAttrs.elementAt(k);
-                OBJECT_IDENTIFIER oid = attr.getType();
-
-                if (!oid.equals(SafeBag.FRIENDLY_NAME)) continue;
-                SET values = attr.getValues();
-                ANY value = (ANY) values.elementAt(0);
-
-                ByteArrayInputStream bbis = new ByteArrayInputStream(value.getEncoded());
-                BMPString sss = (BMPString) (new BMPString.Template()).decode(bbis);
-                nickname = sss.toString();
-
-                break;
-            }
-        }
-
-        X509CertImpl certImpl = new X509CertImpl(x509cert);
-
-        logger.fine("Found certificate " + certImpl.getSubjectDN() + (nickname == null ? "" : " (" + nickname + ")"));
-
         PKCS12CertInfo certInfo = new PKCS12CertInfo();
-        certInfo.cert = certImpl;
-        certInfo.nickname = nickname;
+
+        CertBag certBag = (CertBag) bag.getInterpretedBagContent();
+
+        OCTET_STRING certStr = (OCTET_STRING) certBag.getInterpretedCert();
+        byte[] x509cert = certStr.toByteArray();
+
+        certInfo.cert = new X509CertImpl(x509cert);
+        logger.fine("Found certificate " + certInfo.cert.getSubjectDN());
+
+        SET bagAttrs = bag.getBagAttributes();
+        if (bagAttrs == null) return certInfo;
+
+        for (int i = 0; i < bagAttrs.size(); i++) {
+
+            Attribute attr = (Attribute) bagAttrs.elementAt(i);
+            OBJECT_IDENTIFIER oid = attr.getType();
+
+            if (oid.equals(SafeBag.FRIENDLY_NAME)) {
+
+                SET values = attr.getValues();
+                ANY value = (ANY) values.elementAt(0);
+
+                ByteArrayInputStream is = new ByteArrayInputStream(value.getEncoded());
+                BMPString nicknameStr = (BMPString) (new BMPString.Template()).decode(is);
+
+                certInfo.nickname = nicknameStr.toString();
+                logger.fine("Nickname: " + certInfo.nickname);
+
+            } else if (oid.equals(PKCS12.CERT_TRUST_FLAGS_OID)) {
+
+                SET values = attr.getValues();
+                ANY value = (ANY) values.elementAt(0);
+
+                ByteArrayInputStream is = new ByteArrayInputStream(value.getEncoded());
+                BMPString trustFlagsStr = (BMPString) (new BMPString.Template()).decode(is);
+
+                certInfo.trustFlags = trustFlagsStr.toString();
+                logger.fine("Trust flags: " + certInfo.trustFlags);
+            }
+        }
 
         return certInfo;
     }
@@ -481,35 +557,31 @@ public class PKCS12Util {
         }
     }
 
-    public X509Certificate importCert(X509CertImpl cert) throws Exception {
+    public X509Certificate importCert(X509CertImpl cert, String nickname, String trustFlags) throws Exception {
 
         logger.fine("Importing certificate " + cert.getSubjectDN());
 
         CryptoManager cm = CryptoManager.getInstance();
-        return cm.importCACertPackage(cert.getEncoded());
-    }
 
-    public X509Certificate importCert(X509CertImpl cert, String nickname) throws Exception {
+        X509Certificate xcert;
 
-        logger.fine("Importing certificate " + cert.getSubjectDN() + " (" + nickname + ")");
+        if (nickname == null) {
+            xcert = cm.importCACertPackage(cert.getEncoded());
+
+        } else {
+            xcert = cm.importUserCACertPackage(cert.getEncoded(), nickname);
+        }
+
+        setTrustFlags(xcert, trustFlags);
+
+        return xcert;
 
-        CryptoManager cm = CryptoManager.getInstance();
-        return cm.importUserCACertPackage(cert.getEncoded(), nickname);
     }
 
     public void importCerts(List<PKCS12CertInfo> certInfos) throws Exception {
 
         for (PKCS12CertInfo certInfo : certInfos) {
-
-            X509CertImpl cert = certInfo.cert;
-            String nickname = certInfo.nickname;
-
-            if (nickname == null) {
-                importCert(cert);
-                continue;
-            }
-
-            importCert(cert, nickname);
+            importCert(certInfo.cert, certInfo.nickname, certInfo.trustFlags);
         }
     }
 
-- 
2.4.3


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]