summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEndi S. Dewata <edewata@redhat.com>2016-02-13 09:42:14 +0100
committerEndi S. Dewata <edewata@redhat.com>2016-04-02 05:13:17 +0200
commit12127e52a70ce32272aed0c413d69178726a1a1a (patch)
tree73d6960b1cca76e8c734e0279fbe3a9b83ef93fb
parent73ce319613b1a8a6e24fd7a2c18259e3454a597d (diff)
downloadpki-12127e52a70ce32272aed0c413d69178726a1a1a.tar.gz
pki-12127e52a70ce32272aed0c413d69178726a1a1a.tar.xz
pki-12127e52a70ce32272aed0c413d69178726a1a1a.zip
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
-rw-r--r--base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12CertCLI.java10
-rw-r--r--base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java5
-rw-r--r--base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ImportCLI.java5
-rw-r--r--base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12KeyCLI.java2
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS12.java136
-rw-r--r--base/util/src/netscape/security/pkcs/PKCS12Util.java185
6 files changed, 291 insertions, 52 deletions
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 2179c186c..f4d97cd74 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/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java
index 1e6774004..e5acd0600 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ExportCLI.java
@@ -59,6 +59,8 @@ public class PKCS12ExportCLI extends CLI {
option.setArgName("path");
options.addOption(option);
+ options.addOption(null, "no-trust-flags", false, "Do not include trust flags");
+
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.");
@@ -120,8 +122,11 @@ public class PKCS12ExportCLI extends CLI {
Password password = new Password(passwordString.toCharArray());
+ boolean trustFlagsEnabled = !cmd.hasOption("no-trust-flags");
+
try {
PKCS12Util util = new PKCS12Util();
+ util.setTrustFlagsEnabled(trustFlagsEnabled);
util.exportData(filename, password);
} finally {
password.clear();
diff --git a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ImportCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ImportCLI.java
index 8add346fb..4e9ed23fc 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ImportCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12ImportCLI.java
@@ -59,6 +59,8 @@ public class PKCS12ImportCLI extends CLI {
option.setArgName("path");
options.addOption(option);
+ options.addOption(null, "no-trust-flags", false, "Do not include trust flags");
+
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.");
@@ -120,8 +122,11 @@ public class PKCS12ImportCLI extends CLI {
Password password = new Password(passwordString.toCharArray());
+ boolean trustFlagsEnabled = !cmd.hasOption("no-trust-flags");
+
try {
PKCS12Util util = new PKCS12Util();
+ util.setTrustFlagsEnabled(trustFlagsEnabled);
util.importData(filename, password);
} finally {
password.clear();
diff --git a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12KeyCLI.java b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12KeyCLI.java
index 5297a50ad..9f0779782 100644
--- a/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12KeyCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/pkcs12/PKCS12KeyCLI.java
@@ -34,7 +34,7 @@ public class PKCS12KeyCLI extends CLI {
}
public static void printKeyInfo(PKCS12KeyInfo keyInfo) throws Exception {
- System.out.println(" Subject: " + keyInfo.subjectDN);
+ System.out.println(" Subject DN: " + keyInfo.subjectDN);
if (keyInfo.privateKeyInfo != null) {
System.out.println(" Algorithm: " + keyInfo.privateKeyInfo.getAlgorithm());
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 000000000..df7fde447
--- /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 bcd48970e..6acace0b9 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;
@@ -73,6 +74,7 @@ public class PKCS12Util {
private static Logger logger = Logger.getLogger(PKCS12Util.class.getName());
PFX pfx;
+ boolean trustFlagsEnabled = true;
public static class PKCS12KeyInfo {
public EncryptedPrivateKeyInfo encPrivateKeyInfo;
@@ -83,6 +85,42 @@ public class PKCS12Util {
public static class PKCS12CertInfo {
public X509CertImpl cert;
public String nickname;
+ public String trustFlags;
+ }
+
+ public boolean isTrustFlagsEnabled() {
+ return trustFlagsEnabled;
+ }
+
+ public void setTrustFlagsEnabled(boolean trustFlagsEnabled) {
+ this.trustFlagsEnabled = trustFlagsEnabled;
+ }
+
+ 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(",");
+ if (flags.length < 3) throw new Exception("Invalid trust flags: " + trustFlags);
+
+ 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 +145,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 +158,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 +170,18 @@ 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 = null;
+ if (trustFlagsEnabled) {
+ 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 +202,66 @@ 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();
+ SEQUENCE nicknameAttr = new SEQUENCE();
nicknameAttr.addElement(SafeBag.FRIENDLY_NAME);
- SET nicknameSet = new SET();
+ SET nicknameSet = new SET();
nicknameSet.addElement(new BMPString(nickname));
nicknameAttr.addElement(nicknameSet);
+
attrs.addElement(nicknameAttr);
- SEQUENCE localKeyAttr = new SEQUENCE();
+ SEQUENCE localKeyAttr = new SEQUENCE();
localKeyAttr.addElement(SafeBag.LOCAL_KEY_ID);
- SET localKeySet = new SET();
+ SET localKeySet = new SET();
localKeySet.addElement(new OCTET_STRING(localKeyID));
localKeyAttr.addElement(localKeySet);
+
attrs.addElement(localKeyAttr);
+ if (trustFlags != null && trustFlagsEnabled) {
+ 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 +276,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 +285,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 +371,47 @@ public class PKCS12Util {
public PKCS12CertInfo getCertInfo(SafeBag bag) throws Exception {
+ PKCS12CertInfo certInfo = new PKCS12CertInfo();
+
CertBag certBag = (CertBag) bag.getInterpretedBagContent();
- OCTET_STRING str = (OCTET_STRING) certBag.getInterpretedCert();
- byte[] x509cert = str.toByteArray();
+ OCTET_STRING certStr = (OCTET_STRING) certBag.getInterpretedCert();
+ byte[] x509cert = certStr.toByteArray();
+
+ certInfo.cert = new X509CertImpl(x509cert);
+ logger.fine("Found certificate " + certInfo.cert.getSubjectDN());
- // find cert's nickname
SET bagAttrs = bag.getBagAttributes();
- String nickname = null;
+ if (bagAttrs == null) return certInfo;
- if (bagAttrs != null) {
+ for (int i = 0; i < bagAttrs.size(); i++) {
- for (int k = 0; k < bagAttrs.size(); k++) {
+ Attribute attr = (Attribute) bagAttrs.elementAt(i);
+ OBJECT_IDENTIFIER oid = attr.getType();
- Attribute attr = (Attribute) bagAttrs.elementAt(k);
- OBJECT_IDENTIFIER oid = attr.getType();
+ if (oid.equals(SafeBag.FRIENDLY_NAME)) {
- 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();
+ ByteArrayInputStream is = new ByteArrayInputStream(value.getEncoded());
+ BMPString nicknameStr = (BMPString) (new BMPString.Template()).decode(is);
- break;
- }
- }
+ certInfo.nickname = nicknameStr.toString();
+ logger.fine("Nickname: " + certInfo.nickname);
- X509CertImpl certImpl = new X509CertImpl(x509cert);
+ } else if (oid.equals(PKCS12.CERT_TRUST_FLAGS_OID) && trustFlagsEnabled) {
+
+ SET values = attr.getValues();
+ ANY value = (ANY) values.elementAt(0);
- logger.fine("Found certificate " + certImpl.getSubjectDN() + (nickname == null ? "" : " (" + nickname + ")"));
+ ByteArrayInputStream is = new ByteArrayInputStream(value.getEncoded());
+ BMPString trustFlagsStr = (BMPString) (new BMPString.Template()).decode(is);
- PKCS12CertInfo certInfo = new PKCS12CertInfo();
- certInfo.cert = certImpl;
- certInfo.nickname = nickname;
+ certInfo.trustFlags = trustFlagsStr.toString();
+ logger.fine("Trust flags: " + certInfo.trustFlags);
+ }
+ }
return certInfo;
}
@@ -481,35 +572,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());
- CryptoManager cm = CryptoManager.getInstance();
- return cm.importUserCACertPackage(cert.getEncoded(), nickname);
+ } else {
+ xcert = cm.importUserCACertPackage(cert.getEncoded(), nickname);
+ }
+
+ if (trustFlags != null && trustFlagsEnabled)
+ setTrustFlags(xcert, trustFlags);
+
+ return xcert;
}
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);
}
}