package org.bouncycastle.tls.test; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.RSAPrivateCrtKeySpec; import java.util.Vector; import org.bouncycastle.asn1.pkcs.RSAPrivateKey; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.crypto.util.PrivateKeyFactory; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.tls.Certificate; import org.bouncycastle.tls.SignatureAndHashAlgorithm; import org.bouncycastle.tls.TlsContext; import org.bouncycastle.tls.TlsCredentialedAgreement; import org.bouncycastle.tls.TlsCredentialedDecryptor; import org.bouncycastle.tls.TlsCredentialedSigner; import org.bouncycastle.tls.TlsUtils; import org.bouncycastle.tls.crypto.TlsCertificate; import org.bouncycastle.tls.crypto.TlsCrypto; import org.bouncycastle.tls.crypto.TlsCryptoParameters; import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedAgreement; import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedDecryptor; import org.bouncycastle.tls.crypto.impl.bc.BcDefaultTlsCredentialedSigner; import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; import org.bouncycastle.tls.crypto.impl.jcajce.JcaDefaultTlsCredentialedSigner; import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto; import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedAgreement; import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedDecryptor; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; public class TlsTestUtils { static final byte[] rsaCertData = Base64 .decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA2MDIwNVoXDTEzMDIyNT" + "A2MDM0NVowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCBSAwEgYDVR" + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAHU55Ncz" + "eglREcTg54YLUlGWu2WOYWhit/iM1eeq8Kivro7q98eW52jTuMI3CI5ulqd0hYzshQKQaZ5GDzErMyM="); static final byte[] dudRsaCertData = Base64 .decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA1NDcyOFoXDTEzMDIyNT" + "A1NDkwOFowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCAAEwEgYDVR" + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS" + "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0="); static String fingerprint(org.bouncycastle.asn1.x509.Certificate c) throws IOException { byte[] der = c.getEncoded(); byte[] sha1 = sha256DigestOf(der); byte[] hexBytes = Hex.encode(sha1); String hex = new String(hexBytes, "ASCII").toUpperCase(); StringBuffer fp = new StringBuffer(); int i = 0; fp.append(hex.substring(i, i + 2)); while ((i += 2) < hex.length()) { fp.append(':'); fp.append(hex.substring(i, i + 2)); } return fp.toString(); } static byte[] sha256DigestOf(byte[] input) { SHA256Digest d = new SHA256Digest(); d.update(input, 0, input.length); byte[] result = new byte[d.getDigestSize()]; d.doFinal(result, 0); return result; } static TlsCredentialedAgreement loadAgreementCredentials(TlsContext context, String[] certResources, String keyResource) throws IOException { TlsCrypto crypto = context.getCrypto(); Certificate certificate = loadCertificateChain(crypto, certResources); // TODO[tls-ops] Need to have TlsCrypto construct the credentials from the certs/key (as raw data) if (crypto instanceof BcTlsCrypto) { AsymmetricKeyParameter privateKey = loadBcPrivateKeyResource(keyResource); return new BcDefaultTlsCredentialedAgreement((BcTlsCrypto)context.getCrypto(), certificate, privateKey); } else { PrivateKey privateKey = loadJcaPrivateKeyResource(keyResource); return new JceDefaultTlsCredentialedAgreement((JcaTlsCrypto)context.getCrypto(), certificate, privateKey); } } static TlsCredentialedDecryptor loadEncryptionCredentials(TlsContext context, String[] certResources, String keyResource) throws IOException { TlsCrypto crypto = context.getCrypto(); Certificate certificate = loadCertificateChain(crypto, certResources); // TODO[tls-ops] Need to have TlsCrypto construct the credentials from the certs/key (as raw data) if (crypto instanceof BcTlsCrypto) { AsymmetricKeyParameter privateKey = loadBcPrivateKeyResource(keyResource); return new BcDefaultTlsCredentialedDecryptor((BcTlsCrypto)crypto, certificate, privateKey); } else { PrivateKey privateKey = loadJcaPrivateKeyResource(keyResource); return new JceDefaultTlsCredentialedDecryptor((JcaTlsCrypto)crypto, certificate, privateKey); } } static TlsCredentialedSigner loadSignerCredentials(TlsContext context, String[] certResources, String keyResource, SignatureAndHashAlgorithm signatureAndHashAlgorithm) throws IOException { TlsCrypto crypto = context.getCrypto(); Certificate certificate = loadCertificateChain(crypto, certResources); // TODO[tls-ops] Need to have TlsCrypto construct the credentials from the certs/key (as raw data) if (crypto instanceof BcTlsCrypto) { AsymmetricKeyParameter privateKey = loadBcPrivateKeyResource(keyResource); return new BcDefaultTlsCredentialedSigner(new TlsCryptoParameters(context), (BcTlsCrypto)crypto, privateKey, certificate, signatureAndHashAlgorithm); } else { PrivateKey privateKey = loadJcaPrivateKeyResource(keyResource); return new JcaDefaultTlsCredentialedSigner(new TlsCryptoParameters(context), (JcaTlsCrypto)crypto, privateKey, certificate, signatureAndHashAlgorithm); } } static TlsCredentialedSigner loadSignerCredentials(TlsContext context, Vector supportedSignatureAlgorithms, short signatureAlgorithm, String certResource, String keyResource) throws IOException { SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; if (supportedSignatureAlgorithms == null) { supportedSignatureAlgorithms = TlsUtils.getDefaultSignatureAlgorithms(signatureAlgorithm); } for (int i = 0; i < supportedSignatureAlgorithms.size(); ++i) { SignatureAndHashAlgorithm alg = (SignatureAndHashAlgorithm) supportedSignatureAlgorithms.elementAt(i); if (alg.getSignature() == signatureAlgorithm) { // Just grab the first one we find signatureAndHashAlgorithm = alg; break; } } if (signatureAndHashAlgorithm == null) { return null; } return loadSignerCredentials(context, new String[]{ certResource, "x509-ca.pem" }, keyResource, signatureAndHashAlgorithm); } static Certificate loadCertificateChain(TlsCrypto crypto, String[] resources) throws IOException { TlsCertificate[] chain = new TlsCertificate[resources.length]; for (int i = 0; i < resources.length; ++i) { chain[i] = loadCertificateResource(crypto, resources[i]); } return new Certificate(chain); } static org.bouncycastle.asn1.x509.Certificate loadBcCertificateResource(String resource) throws IOException { PemObject pem = loadPemResource(resource); if (pem.getType().endsWith("CERTIFICATE")) { return org.bouncycastle.asn1.x509.Certificate.getInstance(pem.getContent()); } throw new IllegalArgumentException("'resource' doesn't specify a valid certificate"); } static TlsCertificate loadCertificateResource(TlsCrypto crypto, String resource) throws IOException { PemObject pem = loadPemResource(resource); if (pem.getType().endsWith("CERTIFICATE")) { return crypto.createCertificate(pem.getContent()); } throw new IllegalArgumentException("'resource' doesn't specify a valid certificate"); } static AsymmetricKeyParameter loadBcPrivateKeyResource(String resource) throws IOException { PemObject pem = loadPemResource(resource); if (pem.getType().endsWith("RSA PRIVATE KEY")) { RSAPrivateKey rsa = RSAPrivateKey.getInstance(pem.getContent()); return new RSAPrivateCrtKeyParameters(rsa.getModulus(), rsa.getPublicExponent(), rsa.getPrivateExponent(), rsa.getPrime1(), rsa.getPrime2(), rsa.getExponent1(), rsa.getExponent2(), rsa.getCoefficient()); } if (pem.getType().endsWith("PRIVATE KEY")) { return PrivateKeyFactory.createKey(pem.getContent()); } throw new IllegalArgumentException("'resource' doesn't specify a valid private key"); } static PrivateKey loadJcaPrivateKeyResource(String resource) throws IOException { PemObject pem = loadPemResource(resource); if (pem.getType().endsWith("RSA PRIVATE KEY")) { RSAPrivateKey rsa = RSAPrivateKey.getInstance(pem.getContent()); try { KeyFactory keyFact = KeyFactory.getInstance("RSA", new BouncyCastleProvider()); return keyFact.generatePrivate(new RSAPrivateCrtKeySpec(rsa.getModulus(), rsa.getPublicExponent(), rsa.getPrivateExponent(), rsa.getPrime1(), rsa.getPrime2(), rsa.getExponent1(), rsa.getExponent2(), rsa.getCoefficient())); } catch (GeneralSecurityException e) { throw new IllegalArgumentException("'resource' doesn't specify a valid private key", e); } } if (pem.getType().endsWith("PRIVATE KEY")) { return null; // TODO: } throw new IllegalArgumentException("'resource' doesn't specify a valid private key"); } static PemObject loadPemResource(String resource) throws IOException { InputStream s = TlsTestUtils.class.getResourceAsStream(resource); PemReader p = new PemReader(new InputStreamReader(s)); PemObject o = p.readPemObject(); p.close(); return o; } static boolean areSameCertificate(TlsCrypto crypto, TlsCertificate cert, String resource) throws IOException { // TODO Cache test resources? return areSameCertificate(cert, loadCertificateResource(crypto, resource)); } static boolean areSameCertificate(TlsCertificate a, TlsCertificate b) throws IOException { // TODO[tls-ops] Support equals on TlsCertificate? return Arrays.areEqual(a.getEncoded(), b.getEncoded()); } static boolean isCertificateOneOf(TlsCrypto crypto, TlsCertificate cert, String[] resources) throws IOException { for (int i = 0; i < resources.length; ++i) { if (areSameCertificate(crypto, cert, resources[i])) { return true; } } return false; } }