// --- 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.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.osutil.OSUtil; 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()) + OSUtil.BtoA(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 = OSUtil.AtoB(s); return d; } /* * formats a cert request */ public static String reqFormat(String content) { int beginIndex = CERTREQ_BEGIN_HEADING.length(); int endIndex = CERTREQ_END_HEADING.length(); String result = CERTREQ_BEGIN_HEADING + "\n"; int index = 0; 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 ""; } int beginIndex = CERT_BEGIN_HEADING.length(); int endIndex = CERT_END_HEADING.length(); String result = CERT_BEGIN_HEADING + "\n"; int index = 0; 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 { // 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 enums = cm.getAllTokens(); while (enums.hasMoreElements()) { CryptoToken token = enums.nextElement(); String tokenName = token.getName(); 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 certs = new Vector(); CryptoManager cm = CryptoManager.getInstance(); @SuppressWarnings("unchecked") Enumeration enums = cm.getAllTokens(); while (enums.hasMoreElements()) { CryptoToken token = (CryptoToken) enums.nextElement(); String tokenName = token.getName(); CryptoStore store = token.getCryptoStore(); org.mozilla.jss.crypto.X509Certificate list[] = store.getCertificates(); for (int i = 0; i < list.length; i++) { try { PrivateKey key = cm.findPrivKeyByCert(list[i]); 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 = com.netscape.osutil.OSUtil.AtoB(wrappedRecoveredKey); ByteArrayInputStream inStream = new ByteArrayInputStream(encoded); cInfo = (EncryptedContentInfo) new EncryptedContentInfo.Template().decode(inStream); byte[] decodedData = cInfo.decrypt(pass, passConverter); unwrappedData = com.netscape.osutil.OSUtil.BtoA(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 = com.netscape.osutil.OSUtil.BtoA(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[] = com.netscape.osutil.OSUtil.AtoB(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