summaryrefslogtreecommitdiffstats
path: root/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java')
-rw-r--r--base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java1292
1 files changed, 1292 insertions, 0 deletions
diff --git a/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
new file mode 100644
index 000000000..bf8a9cfc1
--- /dev/null
+++ b/base/util/src/com/netscape/cmsutil/crypto/CryptoUtil.java
@@ -0,0 +1,1292 @@
+// --- 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) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cmsutil.crypto;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.CharConversionException;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import netscape.security.pkcs.PKCS10;
+import netscape.security.pkcs.PKCS7;
+import netscape.security.util.BigInt;
+import netscape.security.util.DerInputStream;
+import netscape.security.util.DerOutputStream;
+import netscape.security.util.DerValue;
+import netscape.security.util.ObjectIdentifier;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.CertificateAlgorithmId;
+import netscape.security.x509.CertificateChain;
+import netscape.security.x509.CertificateExtensions;
+import netscape.security.x509.CertificateIssuerName;
+import netscape.security.x509.CertificateSerialNumber;
+import netscape.security.x509.CertificateSubjectName;
+import netscape.security.x509.CertificateValidity;
+import netscape.security.x509.CertificateVersion;
+import netscape.security.x509.CertificateX509Key;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.X500Signer;
+import netscape.security.x509.X509CertImpl;
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X509Key;
+
+import org.mozilla.jss.CryptoManager;
+import org.mozilla.jss.CryptoManager.NotInitializedException;
+import org.mozilla.jss.NoSuchTokenException;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.asn1.BIT_STRING;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.crypto.Algorithm;
+import org.mozilla.jss.crypto.BadPaddingException;
+import org.mozilla.jss.crypto.Cipher;
+import org.mozilla.jss.crypto.CryptoStore;
+import org.mozilla.jss.crypto.CryptoToken;
+import org.mozilla.jss.crypto.DigestAlgorithm;
+import org.mozilla.jss.crypto.EncryptionAlgorithm;
+import org.mozilla.jss.crypto.IVParameterSpec;
+import org.mozilla.jss.crypto.IllegalBlockSizeException;
+import org.mozilla.jss.crypto.InternalCertificate;
+import org.mozilla.jss.crypto.InvalidKeyFormatException;
+import org.mozilla.jss.crypto.KeyGenAlgorithm;
+import org.mozilla.jss.crypto.KeyGenerator;
+import org.mozilla.jss.crypto.KeyPairAlgorithm;
+import org.mozilla.jss.crypto.KeyPairGenerator;
+import org.mozilla.jss.crypto.KeyWrapAlgorithm;
+import org.mozilla.jss.crypto.KeyWrapper;
+import org.mozilla.jss.crypto.NoSuchItemOnTokenException;
+import org.mozilla.jss.crypto.ObjectNotFoundException;
+import org.mozilla.jss.crypto.PBEAlgorithm;
+import org.mozilla.jss.crypto.PrivateKey;
+import org.mozilla.jss.crypto.Signature;
+import org.mozilla.jss.crypto.SignatureAlgorithm;
+import org.mozilla.jss.crypto.SymmetricKey;
+import org.mozilla.jss.crypto.TokenException;
+import org.mozilla.jss.crypto.X509Certificate;
+import org.mozilla.jss.pkcs11.PK11ECPublicKey;
+import org.mozilla.jss.pkcs12.PasswordConverter;
+import org.mozilla.jss.pkcs7.EncryptedContentInfo;
+import org.mozilla.jss.pkix.crmf.CertReqMsg;
+import org.mozilla.jss.pkix.crmf.CertRequest;
+import org.mozilla.jss.pkix.crmf.CertTemplate;
+import org.mozilla.jss.pkix.crmf.EncryptedKey;
+import org.mozilla.jss.pkix.crmf.EncryptedValue;
+import org.mozilla.jss.pkix.crmf.PKIArchiveOptions;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
+import org.mozilla.jss.util.Base64OutputStream;
+import org.mozilla.jss.util.Password;
+
+import com.netscape.cmsutil.util.Cert;
+import com.netscape.cmsutil.util.Utils;
+
+public class CryptoUtil {
+
+ public static final String CERTREQ_BEGIN_HEADING = "-----BEGIN CERTIFICATE REQUEST-----";
+ public static final String CERTREQ_END_HEADING = "-----END CERTIFICATE REQUEST-----";
+ public static final int LINE_COUNT = 76;
+ public static final String CERT_BEGIN_HEADING = "-----BEGIN CERTIFICATE-----";
+ public static final String CERT_END_HEADING = "-----END CERTIFICATE-----";
+
+ /*
+ * encodes cert
+ */
+ // private static BASE64Encoder mEncoder = new BASE64Encoder();
+ public static String toMIME64(X509CertImpl cert) {
+ try {
+ return "-----BEGIN CERTIFICATE-----\n"
+ // + mEncoder.encodeBuffer(cert.getEncoded())
+ + Utils.base64encode(cert.getEncoded())
+ + "-----END CERTIFICATE-----\n";
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ public static boolean arraysEqual(byte[] bytes, byte[] ints) {
+ if (bytes == null || ints == null) {
+ return false;
+ }
+
+ if (bytes.length != ints.length) {
+ return false;
+ }
+
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != ints[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Retrieves handle to a JSS token.
+ */
+ public static CryptoToken getTokenByName(String token)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ CryptoToken t = null;
+
+ if (token.equals("internal")) {
+ t = cm.getInternalKeyStorageToken();
+ } else {
+ t = cm.getTokenByName(token);
+ }
+ return t;
+ }
+
+ /**
+ * Generates a RSA key pair.
+ */
+ public static KeyPair generateRSAKeyPair(String token, int keysize)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ CryptoToken t = getTokenByName(token);
+ KeyPairGenerator g = t.getKeyPairGenerator(KeyPairAlgorithm.RSA);
+
+ g.initialize(keysize);
+ KeyPair pair = g.genKeyPair();
+
+ return pair;
+ }
+
+ public static boolean isECCKey(X509Key key) {
+ String keyAlgo = key.getAlgorithm();
+ if (keyAlgo.equals("EC") ||
+ keyAlgo.equals("OID.1.2.840.10045.44")) { // ECC
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Generates an ecc key pair.
+ */
+ public static KeyPair generateECCKeyPair(String token, int keysize)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ return generateECCKeyPair(token, keysize, null, null);
+ }
+
+ public static KeyPair generateECCKeyPair(String token, int keysize,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_ops,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_mask)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ CryptoToken t = getTokenByName(token);
+
+ KeyPairAlgorithm alg = KeyPairAlgorithm.EC;
+ KeyPairGenerator g = t.getKeyPairGenerator(alg);
+
+ g.setKeyPairUsages(usage_ops, usage_mask);
+ g.initialize(keysize);
+
+ KeyPair pair = g.genKeyPair();
+
+ return pair;
+ }
+
+ /**
+ * Generates an ecc key pair by curve name
+ */
+ public static KeyPair generateECCKeyPair(String token, String curveName)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ return generateECCKeyPair(token, curveName, null, null);
+ }
+
+ public static KeyPair generateECCKeyPair(CryptoToken token, String curveName)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ return generateECCKeyPair(token, curveName, null, null);
+ }
+
+ public static KeyPair generateECCKeyPair(String token, String curveName,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_ops,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_mask)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ CryptoToken t = getTokenByName(token);
+ return generateECCKeyPair(t, curveName, usage_ops, usage_mask);
+ }
+
+ public static KeyPair generateECCKeyPair(CryptoToken token, String curveName,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_ops,
+ org.mozilla.jss.crypto.KeyPairGeneratorSpi.Usage[] usage_mask)
+ throws CryptoManager.NotInitializedException,
+ NoSuchTokenException,
+ NoSuchAlgorithmException,
+ TokenException {
+ KeyPairAlgorithm alg = KeyPairAlgorithm.EC;
+ KeyPairGenerator g = token.getKeyPairGenerator(alg);
+
+ g.setKeyPairUsages(usage_ops, usage_mask);
+
+ System.out.println("CryptoUtil: generateECCKeyPair: curve = " + curveName);
+ int curveCode = 0;
+ try {
+ curveCode = g.getCurveCodeByName(curveName);
+ } catch (Exception e) {
+ System.out.println("CryptoUtil: generateECCKeyPair: " + e.toString());
+ throw new NoSuchAlgorithmException();
+ }
+ g.initialize(curveCode);
+
+ System.out.println("CryptoUtil: generateECCKeyPair: after KeyPairGenerator initialize with:" + curveName);
+ KeyPair pair = g.genKeyPair();
+
+ return pair;
+ }
+
+ public static byte[] getModulus(PublicKey pubk) {
+ RSAPublicKey rsaKey = (RSAPublicKey) pubk;
+
+ return rsaKey.getModulus().toByteArray();
+ }
+
+ public static byte[] getPublicExponent(PublicKey pubk) {
+ RSAPublicKey rsaKey = (RSAPublicKey) pubk;
+
+ return rsaKey.getPublicExponent().toByteArray();
+ }
+
+ public static String base64Encode(byte[] bytes) throws IOException {
+ // All this streaming is lame, but Base64OutputStream needs a
+ // PrintStream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 = new Base64OutputStream(new
+ PrintStream(new
+ FilterOutputStream(output)));
+
+ b64.write(bytes);
+ b64.flush();
+
+ // This is internationally safe because Base64 chars are
+ // contained within 8859_1
+ return output.toString("8859_1");
+ }
+
+ public static byte[] base64Decode(String s) throws IOException {
+ // BASE64Decoder base64 = new BASE64Decoder();
+ // byte[] d = base64.decodeBuffer(s);
+ byte[] d = Utils.base64decode(s);
+
+ return d;
+ }
+
+ /*
+ * formats a cert request
+ */
+ public static String reqFormat(String content) {
+ String result = CERTREQ_BEGIN_HEADING + "\n";
+
+ while (content.length() >= LINE_COUNT) {
+ result = result + content.substring(0, LINE_COUNT) + "\n";
+ content = content.substring(LINE_COUNT);
+ }
+ if (content.length() > 0) {
+ result = result + content + "\n" + CERTREQ_END_HEADING;
+ } else {
+ result = result + CERTREQ_END_HEADING;
+ }
+
+ return result;
+ }
+
+ public static String getPKCS10FromKey(String dn,
+ byte modulus[], byte exponent[], byte prikdata[])
+ throws IOException,
+ InvalidKeyException,
+ TokenException,
+ NoSuchProviderException,
+ CertificateException,
+ SignatureException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException {
+ X509Key x509key = getPublicX509Key(modulus, exponent);
+ PrivateKey prik = findPrivateKeyFromID(prikdata);
+ PKCS10 pkcs10 = createCertificationRequest(dn, x509key, prik);
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+ pkcs10.print(ps);
+ return bs.toString();
+ }
+
+ public static String getPKCS10FromKey(String dn,
+ byte modulus[], byte exponent[], byte prikdata[], String alg)
+ throws IOException,
+ InvalidKeyException,
+ TokenException,
+ NoSuchProviderException,
+ CertificateException,
+ SignatureException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException {
+ X509Key x509key = getPublicX509Key(modulus, exponent);
+ PrivateKey prik = findPrivateKeyFromID(prikdata);
+ PKCS10 pkcs10 = createCertificationRequest(dn, x509key, prik, alg);
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(bs);
+ pkcs10.print(ps);
+ return bs.toString();
+ }
+
+ /*
+ * formats a cert
+ */
+ public static String certFormat(String content) {
+ if (content == null || content.length() == 0) {
+ return "";
+ }
+ String result = CERT_BEGIN_HEADING + "\n";
+
+ while (content.length() >= LINE_COUNT) {
+ result = result + content.substring(0, LINE_COUNT) + "\n";
+ content = content.substring(LINE_COUNT);
+ }
+ if (content.length() > 0) {
+ result = result + content + "\n" + CERT_END_HEADING;
+ } else {
+ result = result + CERT_END_HEADING;
+ }
+
+ return result;
+ }
+
+ /**
+ * strips out the begin and end certificate brackets
+ *
+ * @param s the string potentially bracketed with
+ * "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----"
+ * @return string without the brackets
+ */
+ public static String stripCertBrackets(String s) {
+ if (s == null) {
+ return s;
+ }
+
+ if (s.startsWith(CERT_BEGIN_HEADING) && s.endsWith(CERT_END_HEADING)) {
+ return (s.substring(27, (s.length() - 25)));
+ }
+
+ // To support Thawte's header and footer
+ if ((s.startsWith("-----BEGIN PKCS #7 SIGNED DATA-----"))
+ && (s.endsWith("-----END PKCS #7 SIGNED DATA-----"))) {
+ return (s.substring(35, (s.length() - 33)));
+ }
+
+ return s;
+ }
+
+ public static String normalizeCertAndReq(String s) {
+ if (s == null) {
+ return s;
+ }
+ s = s.replaceAll("-----BEGIN CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----BEGIN NEW CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----END CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----END NEW CERTIFICATE REQUEST-----", "");
+ s = s.replaceAll("-----BEGIN CERTIFICATE-----", "");
+ s = s.replaceAll("-----END CERTIFICATE-----", "");
+
+ StringBuffer sb = new StringBuffer();
+ StringTokenizer st = new StringTokenizer(s, "\r\n ");
+
+ while (st.hasMoreTokens()) {
+ String nextLine = st.nextToken();
+
+ nextLine = nextLine.trim();
+ if (nextLine.equals("-----BEGIN CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----BEGIN NEW CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----END CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----END NEW CERTIFICATE REQUEST-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----BEGIN CERTIFICATE-----")) {
+ continue;
+ }
+ if (nextLine.equals("-----END CERTIFICATE-----")) {
+ continue;
+ }
+ sb.append(nextLine);
+ }
+ return sb.toString();
+ }
+
+ public static String normalizeCertStr(String s) {
+ String val = "";
+
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '\n') {
+ continue;
+ } else if (s.charAt(i) == '\r') {
+ continue;
+ } else if (s.charAt(i) == '"') {
+ continue;
+ } else if (s.charAt(i) == ' ') {
+ continue;
+ }
+ val += s.charAt(i);
+ }
+ return val;
+ }
+
+ public static void importCertificateChain(String certchain)
+ throws IOException,
+ CryptoManager.NotInitializedException,
+ TokenException,
+ CertificateEncodingException,
+ CertificateException {
+ byte[] blah = base64Decode(certchain);
+ CryptoManager manager = CryptoManager.getInstance();
+ PKCS7 pkcs7 = null;
+ try {
+ // try PKCS7 first
+ pkcs7 = new PKCS7(blah);
+ } catch (Exception e) {
+ }
+ X509Certificate cert = null;
+ if (pkcs7 == null) {
+ cert = manager.importCACertPackage(blah);
+ } else {
+ java.security.cert.X509Certificate certsInP7[] =
+ pkcs7.getCertificates();
+ if (certsInP7 == null) {
+ cert = manager.importCACertPackage(blah);
+ } else {
+ for (int i = 0; i < certsInP7.length; i++) {
+ // import P7 one by one
+ cert = manager.importCACertPackage(certsInP7[i].getEncoded());
+ }
+ }
+ }
+ X509Certificate[] certchains =
+ CryptoManager.getInstance().buildCertificateChain(cert);
+
+ if (certchains != null) {
+ cert = certchains[certchains.length - 1];
+ }
+ InternalCertificate icert = (InternalCertificate) cert;
+ icert.setSSLTrust(InternalCertificate.TRUSTED_CA
+ | InternalCertificate.TRUSTED_CLIENT_CA
+ | InternalCertificate.VALID_CA);
+ }
+
+ public static SEQUENCE parseCRMFMsgs(byte cert_request[])
+ throws IOException, InvalidBERException {
+ ByteArrayInputStream crmfBlobIn =
+ new ByteArrayInputStream(cert_request);
+ SEQUENCE crmfMsgs = (SEQUENCE)
+ new SEQUENCE.OF_Template(new CertReqMsg.Template()).decode(
+ crmfBlobIn);
+ return crmfMsgs;
+ }
+
+ public static X509Key getX509KeyFromCRMFMsgs(SEQUENCE crmfMsgs)
+ throws IOException, NoSuchAlgorithmException,
+ InvalidKeyException, InvalidKeyFormatException {
+ int nummsgs = crmfMsgs.size();
+ if (nummsgs <= 0) {
+ throw new IOException("invalid certificate requests");
+ }
+ CertReqMsg msg = (CertReqMsg) crmfMsgs.elementAt(0);
+ CertRequest certreq = msg.getCertReq();
+ CertTemplate certTemplate = certreq.getCertTemplate();
+ SubjectPublicKeyInfo spkinfo = certTemplate.getPublicKey();
+ PublicKey pkey = spkinfo.toPublicKey();
+ X509Key x509key = convertPublicKeyToX509Key(pkey);
+ return x509key;
+ }
+
+ public static X509Key getPublicX509Key(byte modulus[], byte exponent[])
+ throws InvalidKeyException {
+ return new netscape.security.provider.RSAPublicKey(new BigInt(modulus),
+ new BigInt(exponent));
+ }
+
+ public static X509Key getPublicX509ECCKey(byte encoded[])
+ throws InvalidKeyException {
+ try {
+ return X509Key.parse(new DerValue(encoded));
+ } catch (IOException e) {
+ throw new InvalidKeyException();
+ }
+ }
+
+ public static X509Key convertPublicKeyToX509Key(PublicKey pubk)
+ throws InvalidKeyException {
+ X509Key xKey;
+
+ if (pubk instanceof RSAPublicKey) {
+ RSAPublicKey rsaKey = (RSAPublicKey) pubk;
+
+ xKey = new netscape.security.provider.RSAPublicKey(
+ new BigInt(rsaKey.getModulus()),
+ new BigInt(rsaKey.getPublicExponent()));
+ } else if (pubk instanceof PK11ECPublicKey) {
+ byte encoded[] = pubk.getEncoded();
+ xKey = CryptoUtil.getPublicX509ECCKey(encoded);
+ } else {
+ // Assert.assert(pubk instanceof DSAPublicKey);
+ DSAPublicKey dsaKey = (DSAPublicKey) pubk;
+ DSAParams params = dsaKey.getParams();
+
+ xKey = new netscape.security.provider.DSAPublicKey(dsaKey.getY(),
+ params.getP(), params.getQ(), params.getG());
+ }
+ return xKey;
+ }
+
+ public static String getSubjectName(SEQUENCE crmfMsgs)
+ throws IOException {
+ int nummsgs = crmfMsgs.size();
+ if (nummsgs <= 0) {
+ throw new IOException("invalid certificate requests");
+ }
+ CertReqMsg msg = (CertReqMsg) crmfMsgs.elementAt(0);
+ CertRequest certreq = msg.getCertReq();
+ CertTemplate certTemplate = certreq.getCertTemplate();
+ Name n = certTemplate.getSubject();
+ ByteArrayOutputStream subjectEncStream = new ByteArrayOutputStream();
+ n.encode(subjectEncStream);
+
+ byte[] b = subjectEncStream.toByteArray();
+ X500Name subject = new X500Name(b);
+ return subject.toString();
+ }
+
+ /**
+ * Creates a Certificate template.
+ */
+ public static X509CertInfo createX509CertInfo(KeyPair pair,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException {
+ return createX509CertInfo(convertPublicKeyToX509Key(pair.getPublic()),
+ serialno, issuername, subjname, notBefore, notAfter);
+ }
+
+ public static X509CertInfo createX509CertInfo(PublicKey publickey,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException {
+ return createX509CertInfo(convertPublicKeyToX509Key(publickey), serialno,
+ issuername, subjname, notBefore, notAfter);
+ }
+
+ public static X509CertInfo createX509CertInfo(X509Key x509key,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException {
+ // set default; use the other call with "alg" to set algorithm
+ String alg = "SHA256withRSA";
+ try {
+ return createX509CertInfo(x509key, serialno, issuername, subjname, notBefore, notAfter, alg);
+ } catch (NoSuchAlgorithmException ex) {
+ // for those that calls the old call without alg
+ throw new CertificateException("createX509CertInfo old call should not be here");
+ }
+ }
+
+ public static X509CertInfo createX509CertInfo(X509Key x509key,
+ int serialno, String issuername, String subjname,
+ Date notBefore, Date notAfter, String alg)
+ throws IOException,
+ CertificateException,
+ InvalidKeyException,
+ NoSuchAlgorithmException {
+ X509CertInfo info = new X509CertInfo();
+
+ info.set(X509CertInfo.VERSION, new
+ CertificateVersion(CertificateVersion.V3));
+ info.set(X509CertInfo.SERIAL_NUMBER, new
+ CertificateSerialNumber(serialno));
+ info.set(X509CertInfo.ISSUER, new
+ CertificateIssuerName(new X500Name(issuername)));
+ info.set(X509CertInfo.SUBJECT, new
+ CertificateSubjectName(new X500Name(subjname)));
+ info.set(X509CertInfo.VALIDITY, new
+ CertificateValidity(notBefore, notAfter));
+ info.set(X509CertInfo.ALGORITHM_ID, new
+ CertificateAlgorithmId(AlgorithmId.get(alg)));
+ info.set(X509CertInfo.KEY, new CertificateX509Key(x509key));
+ info.set(X509CertInfo.EXTENSIONS, new CertificateExtensions());
+ return info;
+ }
+
+ public static X509CertImpl signECCCert(PrivateKey privateKey,
+ X509CertInfo certInfo)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+ // set default; use the other call with "alg" to specify algorithm
+ String alg = "SHA256withEC";
+ return signECCCert(privateKey, certInfo, alg);
+ }
+
+ public static X509CertImpl signECCCert(PrivateKey privateKey,
+ X509CertInfo certInfo, String alg)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+ return signCert(privateKey, certInfo,
+ Cert.mapAlgorithmToJss(alg));
+ }
+
+ /**
+ * Signs certificate.
+ */
+ public static X509CertImpl signCert(PrivateKey privateKey,
+ X509CertInfo certInfo, String alg)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+ return signCert(privateKey, certInfo,
+ Cert.mapAlgorithmToJss(alg));
+ }
+
+ public static X509CertImpl signCert(PrivateKey privateKey,
+ X509CertInfo certInfo, SignatureAlgorithm sigAlg)
+ throws NoSuchTokenException,
+ CryptoManager.NotInitializedException,
+ NoSuchAlgorithmException,
+ NoSuchTokenException,
+ TokenException,
+ InvalidKeyException,
+ SignatureException,
+ IOException,
+ CertificateException {
+
+ DerInputStream ds = new DerInputStream(ASN1Util.encode(sigAlg.toOID()));
+ ObjectIdentifier sigAlgOID = new ObjectIdentifier(ds);
+ AlgorithmId aid = new AlgorithmId(sigAlgOID);
+ certInfo.set(X509CertInfo.ALGORITHM_ID,
+ new CertificateAlgorithmId(aid));
+
+ org.mozilla.jss.crypto.PrivateKey priKey =
+ (org.mozilla.jss.crypto.PrivateKey) privateKey;
+ CryptoToken token = priKey.getOwningToken();
+
+ DerOutputStream tmp = new DerOutputStream();
+ DerOutputStream out = new DerOutputStream();
+
+ certInfo.encode(tmp);
+ Signature signer = token.getSignatureContext(sigAlg);
+
+ signer.initSign(priKey);
+ signer.update(tmp.toByteArray());
+ byte signed[] = signer.sign();
+
+ aid.encode(tmp);
+ tmp.putBitString(signed);
+ out.write(DerValue.tag_Sequence, tmp);
+ X509CertImpl signedCert = new X509CertImpl(out.toByteArray());
+
+ return signedCert;
+ }
+
+ /**
+ * Creates a PKCS#10 request.
+ */
+ public static PKCS10 createCertificationRequest(String subjectName,
+ X509Key pubk, PrivateKey prik)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ // give default
+ String alg = "SHA256withRSA";
+ if (isECCKey(pubk)) {
+ alg = "SHA256withEC";
+ }
+ return createCertificationRequest(subjectName, pubk, prik, alg);
+ }
+
+ public static PKCS10 createCertificationRequest(String subjectName,
+ X509Key pubk, PrivateKey prik, String alg)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ X509Key key = pubk;
+ java.security.Signature sig = java.security.Signature.getInstance(alg,
+ "Mozilla-JSS");
+
+ sig.initSign(prik);
+ PKCS10 pkcs10 = new PKCS10(key);
+ X500Name name = new X500Name(subjectName);
+ X500Signer signer = new X500Signer(sig, name);
+
+ pkcs10.encodeAndSign(signer);
+ return pkcs10;
+ }
+
+ /**
+ * Creates a PKCS#10 request.
+ */
+ public static PKCS10 createCertificationRequest(String subjectName,
+ KeyPair keyPair)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ String alg;
+ PublicKey pubk = keyPair.getPublic();
+ X509Key key = convertPublicKeyToX509Key(pubk);
+ if (pubk instanceof RSAPublicKey) {
+ alg = "SHA256withRSA";
+ } else if (isECCKey(key)) {
+ alg = "SHA256withEC";
+ } else {
+ // Assert.assert(pubk instanceof DSAPublicKey);
+ alg = "DSA";
+ }
+ return createCertificationRequest(subjectName, keyPair, alg);
+ }
+
+ public static PKCS10 createCertificationRequest(String subjectName,
+ KeyPair keyPair, String alg)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, IOException, CertificateException,
+ SignatureException {
+ PublicKey pubk = keyPair.getPublic();
+ X509Key key = convertPublicKeyToX509Key(pubk);
+
+ java.security.Signature sig = java.security.Signature.getInstance(alg,
+ "Mozilla-JSS");
+
+ sig.initSign(keyPair.getPrivate());
+
+ PKCS10 pkcs10 = new PKCS10(key);
+
+ X500Name name = new X500Name(subjectName);
+ X500Signer signer = new X500Signer(sig, name);
+
+ pkcs10.encodeAndSign(signer);
+
+ return pkcs10;
+ }
+
+ public static void unTrustCert(InternalCertificate cert) {
+ // remove TRUSTED_CA
+ int flag = cert.getSSLTrust();
+
+ flag ^= InternalCertificate.VALID_CA;
+ cert.setSSLTrust(flag);
+ }
+
+ /**
+ * Trusts a certificate by nickname.
+ */
+ public static void trustCertByNickname(String nickname)
+ throws CryptoManager.NotInitializedException,
+ TokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate certs[] = cm.findCertsByNickname(nickname);
+
+ if (certs == null) {
+ return;
+ }
+ for (int i = 0; i < certs.length; i++) {
+ trustCert((InternalCertificate) certs[i]);
+ }
+ }
+
+ /**
+ * Trusts a certificate.
+ */
+ public static void trustCert(InternalCertificate cert) {
+ int flag = InternalCertificate.VALID_CA | InternalCertificate.TRUSTED_CA
+ | InternalCertificate.USER
+ | InternalCertificate.TRUSTED_CLIENT_CA;
+
+ cert.setSSLTrust(flag);
+ cert.setObjectSigningTrust(flag);
+ cert.setEmailTrust(flag);
+ }
+
+ /**
+ * To certificate server point of view, SSL trust is
+ * what we referring.
+ */
+ public static boolean isCertTrusted(InternalCertificate cert) {
+ if (isTrust(cert.getSSLTrust()) && isTrust(cert.getObjectSigningTrust())
+ && isTrust(cert.getEmailTrust())) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean isTrust(int flag) {
+ if (((flag & InternalCertificate.VALID_CA) > 0)
+ && ((flag & InternalCertificate.TRUSTED_CA) > 0)
+ && ((flag & InternalCertificate.USER) > 0)
+ && ((flag & InternalCertificate.TRUSTED_CLIENT_CA) > 0)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Generates a symmetric key.
+ */
+ public static SymmetricKey generateKey(CryptoToken token,
+ KeyGenAlgorithm alg)
+ throws TokenException, NoSuchAlgorithmException,
+ IllegalStateException {
+ try {
+ KeyGenerator kg = token.getKeyGenerator(alg);
+
+ return kg.generate();
+ } catch (CharConversionException e) {
+ throw new RuntimeException(
+ "CharConversionException while generating symmetric key");
+ }
+ }
+
+ /**
+ * Compares 2 byte arrays to see if they are the same.
+ */
+ public static boolean compare(byte src[], byte dest[]) {
+ if (src != null && dest != null) {
+ if (src.length == dest.length) {
+ boolean matched = true;
+
+ for (int i = 0; i < src.length; i++) {
+ if (src[i] != dest[i]) {
+ matched = false;
+ }
+ }
+ if (matched) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public static String byte2string(byte id[]) {
+ return new BigInteger(id).toString(16);
+ }
+
+ public static byte[] string2byte(String id) {
+ return (new BigInteger(id, 16)).toByteArray();
+ }
+
+ /**
+ * Retrieves a private key from a unique key ID.
+ */
+ public static PrivateKey findPrivateKeyFromID(byte id[])
+ throws CryptoManager.NotInitializedException,
+ TokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ @SuppressWarnings("unchecked")
+ Enumeration<CryptoToken> enums = cm.getAllTokens();
+
+ while (enums.hasMoreElements()) {
+ CryptoToken token = enums.nextElement();
+ CryptoStore store = token.getCryptoStore();
+ PrivateKey keys[] = store.getPrivateKeys();
+
+ if (keys != null) {
+ for (int i = 0; i < keys.length; i++) {
+ if (compare(keys[i].getUniqueID(), id)) {
+ return keys[i];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retrieves all user certificates from all tokens.
+ */
+ public static X509CertImpl[] getAllUserCerts()
+ throws CryptoManager.NotInitializedException,
+ TokenException {
+ Vector<X509CertImpl> certs = new Vector<X509CertImpl>();
+ CryptoManager cm = CryptoManager.getInstance();
+ @SuppressWarnings("unchecked")
+ Enumeration<CryptoToken> enums = cm.getAllTokens();
+
+ while (enums.hasMoreElements()) {
+ CryptoToken token = (CryptoToken) enums.nextElement();
+
+ CryptoStore store = token.getCryptoStore();
+ org.mozilla.jss.crypto.X509Certificate list[] = store.getCertificates();
+
+ for (int i = 0; i < list.length; i++) {
+ try {
+ @SuppressWarnings("unused")
+ PrivateKey key = cm.findPrivKeyByCert(list[i]); // check for errors
+ X509CertImpl impl = null;
+
+ try {
+ impl = new X509CertImpl(list[i].getEncoded());
+ } catch (CertificateException e) {
+ continue;
+ }
+ certs.addElement(impl);
+ } catch (TokenException e) {
+ continue;
+ } catch (ObjectNotFoundException e) {
+ continue;
+ }
+ }
+ }
+ if (certs.size() == 0) {
+ return null;
+ } else {
+ X509CertImpl c[] = new X509CertImpl[certs.size()];
+
+ certs.copyInto(c);
+ return c;
+ }
+ }
+
+ /**
+ * Deletes a private key.
+ */
+ public static void deletePrivateKey(PrivateKey prikey)
+ throws CryptoManager.NotInitializedException, TokenException {
+
+ try {
+ CryptoToken token = prikey.getOwningToken();
+ CryptoStore store = token.getCryptoStore();
+
+ store.deletePrivateKey(prikey);
+ } catch (NoSuchItemOnTokenException e) {
+ }
+ }
+
+ /**
+ * Retrieves a private key by nickname.
+ */
+ public static PrivateKey getPrivateKey(String nickname)
+ throws CryptoManager.NotInitializedException, TokenException {
+ try {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate cert = cm.findCertByNickname(nickname);
+ org.mozilla.jss.crypto.PrivateKey prikey = cm.findPrivKeyByCert(cert);
+
+ return prikey;
+ } catch (ObjectNotFoundException e) {
+ }
+ return null;
+ }
+
+ /**
+ * Deletes all certificates by a nickname.
+ */
+ public static void deleteAllCertificates(String nickname)
+ throws CryptoManager.NotInitializedException, TokenException {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate certs[] = cm.findCertsByNickname(nickname);
+
+ if (certs == null) {
+ return;
+ }
+ for (int i = 0; i < certs.length; i++) {
+ try {
+ X509Certificate cert = certs[i];
+ org.mozilla.jss.crypto.PrivateKey prikey = cm.findPrivKeyByCert(
+ cert);
+ CryptoToken token = prikey.getOwningToken();
+ CryptoStore store = token.getCryptoStore();
+
+ store.deleteCert(cert);
+ } catch (NoSuchItemOnTokenException e) {
+ } catch (ObjectNotFoundException e) {
+ }
+ }
+ }
+
+ /**
+ * Imports a PKCS#7 certificate chain that includes the user
+ * certificate, and trusts the certificate.
+ */
+ public static X509Certificate importUserCertificateChain(String c,
+ String nickname)
+ throws CryptoManager.NotInitializedException,
+ CryptoManager.NicknameConflictException,
+ CryptoManager.UserCertConflictException,
+ NoSuchItemOnTokenException,
+ TokenException,
+ CertificateEncodingException {
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate cert = cm.importCertPackage(c.getBytes(), nickname);
+
+ trustCertByNickname(nickname);
+ return cert;
+ }
+
+ /**
+ * Imports a user certificate, and trusts the certificate.
+ */
+ public static void importUserCertificate(X509CertImpl cert, String nickname)
+ throws CryptoManager.NotInitializedException,
+ CertificateEncodingException,
+ NoSuchItemOnTokenException,
+ TokenException,
+ CryptoManager.NicknameConflictException,
+ CryptoManager.UserCertConflictException {
+ CryptoManager cm = CryptoManager.getInstance();
+
+ cm.importUserCACertPackage(cert.getEncoded(), nickname);
+ trustCertByNickname(nickname);
+ }
+
+ public static void importUserCertificate(X509CertImpl cert, String nickname,
+ boolean trust)
+ throws CryptoManager.NotInitializedException,
+ CertificateEncodingException,
+ NoSuchItemOnTokenException,
+ TokenException,
+ CryptoManager.NicknameConflictException,
+ CryptoManager.UserCertConflictException {
+ CryptoManager cm = CryptoManager.getInstance();
+
+ cm.importUserCACertPackage(cert.getEncoded(), nickname);
+ if (trust)
+ trustCertByNickname(nickname);
+ }
+
+ public static java.security.cert.X509Certificate[] getX509CertificateFromPKCS7(byte[] b) throws IOException {
+ ByteArrayInputStream bis = new ByteArrayInputStream(b);
+ CertificateChain certchain = new CertificateChain();
+
+ certchain.decode(bis);
+ java.security.cert.X509Certificate[] certs = certchain.getChain();
+
+ return certs;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static String unwrapUsingPassphrase(String wrappedRecoveredKey, String recoveryPassphrase)
+ throws IOException, InvalidBERException, InvalidKeyException, IllegalStateException,
+ NoSuchAlgorithmException, InvalidAlgorithmParameterException, NotInitializedException, TokenException,
+ IllegalBlockSizeException, BadPaddingException {
+ EncryptedContentInfo cInfo = null;
+ String unwrappedData = null;
+
+ //We have to do this to get the decoding to work.
+ @SuppressWarnings("unused")
+ PBEAlgorithm pbeAlg = PBEAlgorithm.PBE_SHA1_DES3_CBC;
+
+ Password pass = new Password(recoveryPassphrase.toCharArray());
+ PasswordConverter passConverter = new
+ PasswordConverter();
+
+ byte[] encoded = Utils.base64decode(wrappedRecoveredKey);
+
+ ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+ cInfo = (EncryptedContentInfo)
+ new EncryptedContentInfo.Template().decode(inStream);
+
+ byte[] decodedData = cInfo.decrypt(pass, passConverter);
+
+ unwrappedData = Utils.base64encode(decodedData);
+
+ return unwrappedData;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static String unwrapUsingSymmetricKey(CryptoToken token, IVParameterSpec IV, byte[] wrappedRecoveredKey,
+ SymmetricKey recoveryKey, EncryptionAlgorithm alg) throws NoSuchAlgorithmException, TokenException,
+ BadPaddingException,
+ IllegalBlockSizeException, InvalidKeyException, InvalidAlgorithmParameterException {
+
+ Cipher decryptor = token.getCipherContext(alg);
+ decryptor.initDecrypt(recoveryKey, IV);
+ byte[] unwrappedData = decryptor.doFinal(wrappedRecoveredKey);
+ String unwrappedS = Utils.base64encode(unwrappedData);
+
+ return unwrappedS;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static byte[] wrapPassphrase(CryptoToken token, String passphrase, IVParameterSpec IV, SymmetricKey sk,
+ EncryptionAlgorithm alg)
+ throws NoSuchAlgorithmException, TokenException, InvalidKeyException,
+ InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException {
+ byte[] wrappedPassphrase = null;
+ Cipher encryptor = null;
+
+ encryptor = token.getCipherContext(alg);
+
+ if (encryptor != null) {
+ encryptor.initEncrypt(sk, IV);
+ wrappedPassphrase = encryptor.doFinal(passphrase.getBytes("UTF-8"));
+ } else {
+ throw new IOException("Failed to create cipher");
+ }
+
+ return wrappedPassphrase;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static byte[] wrapSymmetricKey(CryptoManager manager, CryptoToken token, String transportCert,
+ SymmetricKey sk) throws CertificateEncodingException, TokenException, NoSuchAlgorithmException,
+ InvalidKeyException, InvalidAlgorithmParameterException {
+ byte transport[] = Utils.base64decode(transportCert);
+ X509Certificate tcert = manager.importCACertPackage(transport);
+ KeyWrapper rsaWrap = token.getKeyWrapper(KeyWrapAlgorithm.RSA);
+ rsaWrap.initWrap(tcert.getPublicKey(), null);
+ byte session_data[] = rsaWrap.wrap(sk);
+ return session_data;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static byte[] createPKIArchiveOptions(CryptoManager manager, CryptoToken token, String transportCert,
+ SymmetricKey vek, String passphrase, KeyGenAlgorithm keyGenAlg, IVParameterSpec IV) throws TokenException,
+ CharConversionException,
+ NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException,
+ CertificateEncodingException, IOException, IllegalStateException, IllegalBlockSizeException,
+ BadPaddingException, InvalidBERException {
+ byte[] key_data = null;
+
+ //generate session key
+ SymmetricKey sk = CryptoUtil.generateKey(token, keyGenAlg);
+
+ if (passphrase != null) {
+ key_data = wrapPassphrase(token, passphrase, IV, sk, EncryptionAlgorithm.DES3_CBC_PAD);
+ } else {
+ // wrap payload using session key
+ KeyWrapper wrapper1 = token.getKeyWrapper(KeyWrapAlgorithm.DES3_CBC_PAD);
+ wrapper1.initWrap(sk, IV);
+ key_data = wrapper1.wrap(vek);
+ }
+
+ // wrap session key using transport key
+ byte[] session_data = wrapSymmetricKey(manager, token, transportCert, sk);
+
+ // create PKIArchiveOptions structure
+ AlgorithmIdentifier algS = new AlgorithmIdentifier(new OBJECT_IDENTIFIER("1.2.840.113549.3.7"),
+ new OCTET_STRING(IV.getIV()));
+ EncryptedValue encValue = new EncryptedValue(null, algS, new BIT_STRING(session_data, 0), null, null,
+ new BIT_STRING(key_data, 0));
+ EncryptedKey key = new EncryptedKey(encValue);
+ PKIArchiveOptions opt = new PKIArchiveOptions(key);
+
+ byte[] encoded = null;
+
+ //Let's make sure we can decode the encoded PKIArchiveOptions..
+ ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+
+ opt.encode(oStream);
+
+ encoded = oStream.toByteArray();
+ ByteArrayInputStream inStream = new ByteArrayInputStream(encoded);
+
+ @SuppressWarnings("unused")
+ PKIArchiveOptions options = (PKIArchiveOptions)
+ (new PKIArchiveOptions.Template()).decode(inStream);
+
+ return encoded;
+ }
+}
+
+// START ENABLE_ECC
+// This following can be removed when JSS with ECC capability
+// is integrated.
+class CryptoAlgorithm extends Algorithm {
+ protected CryptoAlgorithm(int oidIndex, String name) {
+ super(oidIndex, name);
+ }
+}
+
+class CryptoKeyPairAlgorithm extends KeyPairAlgorithm {
+ protected CryptoKeyPairAlgorithm(int oidIndex, String name, Algorithm algFamily) {
+ super(oidIndex, name, algFamily);
+ }
+}
+
+class CryptoSignatureAlgorithm extends SignatureAlgorithm {
+ protected CryptoSignatureAlgorithm(int oidIndex, String name,
+ SignatureAlgorithm signingAlg, DigestAlgorithm digestAlg,
+ OBJECT_IDENTIFIER oid) {
+ super(oidIndex, name, signingAlg, digestAlg, oid);
+ }
+}
+// END ENABLE_ECC