package org.bouncycastle.test.est;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.SocketTimeoutException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.est.CACertsResponse;
import org.bouncycastle.est.ESTClient;
import org.bouncycastle.est.ESTClientProvider;
import org.bouncycastle.est.ESTException;
import org.bouncycastle.est.ESTRequest;
import org.bouncycastle.est.ESTResponse;
import org.bouncycastle.est.ESTService;
import org.bouncycastle.est.ESTServiceBuilder;
import org.bouncycastle.est.Source;
import org.bouncycastle.est.jcajce.JcaJceUtils;
import org.bouncycastle.est.jcajce.JsseESTServiceBuilder;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.bouncycastle.test.est.examples.ExampleUtils;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.test.SimpleTest;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
public class TestCACertsFetch
extends SimpleTest
{
public String getName()
{
return "TestCACertsFetch";
}
public void performTest()
throws Exception
{
ESTTestUtils.runJUnit(TestCACertsFetch.class);
}
private ESTServerUtils.ServerInstance startDefaultServer()
throws Exception
{
final ESTServerUtils.EstServerConfig config = new ESTServerUtils.EstServerConfig();
config.serverCertPemFile = ESTServerUtils.makeRelativeToServerHome("estCA/private/estservercertandkey.pem").getCanonicalPath();
config.serverKeyPemFile = ESTServerUtils.makeRelativeToServerHome("estCA/private/estservercertandkey.pem").getCanonicalPath();
config.realm = "estreal";
config.verbose = true;
config.tcpPort = 8443;
config.useBasicAuth = true;
config.estTRUSTEDCerts = ESTServerUtils.makeRelativeToServerHome("trustedcerts.crt").getCanonicalPath();
config.estCACERTSResp = ESTServerUtils.makeRelativeToServerHome("/estCA/cacert.crt").getCanonicalPath();
return ESTServerUtils.startServer(config);
}
/**
* Test Fetch CA certs without doing any SSL TLS verification.
* This is just a catch all to prove we can get some certificates back.
* Do not use this as an example of how to do it in the world, you need
* to make a conscious decision about accepting the certificates tended
* as part of the TLS handshake. See testFetchCaCertsWithBogusTrustAnchor()
*
* @throws Exception
*/
@Test
public void testFetchCaCerts()
throws Exception
{
ESTTestUtils.ensureProvider();
X509CertificateHolder[] theirCAs = null;
ESTServerUtils.ServerInstance serverInstance = null;
try
{
serverInstance = startDefaultServer();
System.setProperty("org.bouncycastle.debug.est", "all");
// SSLSocketFactoryCreatorBuilder sfcb = new SSLSockuetFactoryCreatorBuilder();
ESTService est = new JsseESTServiceBuilder("localhost:8443/", JcaJceUtils.getTrustAllTrustManager()).build();
CACertsResponse caCertsResponse = est.getCACerts();
X509CertificateHolder[] caCerts = ESTService.storeToArray(caCertsResponse.getCertificateStore());
FileReader fr = new FileReader(ESTServerUtils.makeRelativeToServerHome("/estCA/cacert.crt"));
PemReader reader = new PemReader(fr);
X509CertificateHolder fromFile = new X509CertificateHolder(reader.readPemObject().getContent());
reader.close();
fr.close();
Assert.assertFalse("Must not be trusted.", caCertsResponse.isTrusted());
Assert.assertEquals("Returned ca certs should be 1", caCerts.length, 1);
Assert.assertEquals("CA cert did match expected.", fromFile, caCerts[0]);
}
finally
{
if (serverInstance != null)
{
serverInstance.getServer().stop_server();
}
}
}
/**
* Test to ensure timeout behavior.
*
* @throws Exception
*/
@Test
public void testFetchCaCertsWithTimeout()
throws Exception
{
ESTTestUtils.ensureProvider();
X509CertificateHolder[] theirCAs = null;
HttpResponder res = new HttpResponder();
int port = res.open(null);
ESTService est = new JsseESTServiceBuilder("localhost:" + port , JcaJceUtils.getTrustAllTrustManager()).withTimeout(500).addCipherSuites(res.getEnabledSuites()).build();
try
{
CACertsResponse caCertsResponse = est.getCACerts();
Assert.fail("Must time out.");
}
catch (Exception ex)
{
Assert.assertEquals("", ESTException.class, ex.getClass());
Assert.assertEquals("", SocketTimeoutException.class, ex.getCause().getClass());
}
finally
{
res.getFinished().await(5, TimeUnit.SECONDS);
}
}
/**
* Fetch CA certs with a bogus trust anchor.
* Expect local library to fail.
*
* @throws Exception
*/
@Test
public void testFetchCaCertsWithBogusTrustAnchor()
throws Exception
{
ESTTestUtils.ensureProvider();
X509CertificateHolder[] theirCAs = null;
ESTServerUtils.ServerInstance serverInstance = null;
try
{
serverInstance = startDefaultServer();
//
// Create a self signed certificate to tend as trust anchor that will
// not be part of the servers path.
//
ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("prime256v1");
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDSA", "BC");
kpg.initialize(ecGenSpec, new SecureRandom());
KeyPair originalKeyPair = kpg.generateKeyPair();
X500NameBuilder builder = new X500NameBuilder();
builder.addRDN(BCStyle.C, "AI");
builder.addRDN(BCStyle.CN, "BogusCA");
builder.addRDN(BCStyle.O, "BogusCA providers.");
builder.addRDN(BCStyle.L, "Atlantis");
X500Name name = builder.build();
X509Certificate bogusCA = ESTTestUtils.createSelfsignedCert("SHA256WITHECDSA",
name,
SubjectPublicKeyInfo.getInstance(originalKeyPair.getPublic().getEncoded()),
originalKeyPair.getPrivate(),
1
);
//
// Use the trust anchor.
//
TrustAnchor ta = new TrustAnchor(bogusCA, null);
ESTService est =
new JsseESTServiceBuilder(
"localhost:8443",
JcaJceUtils.getCertPathTrustManager(ESTTestUtils.toTrustAnchor(ta), null)).build();
//
// Call expecting failure.
//
try
{
X509CertificateHolder[] caCerts = ESTService.storeToArray(est.getCACerts().getCertificateStore());
Assert.fail("Bogus CA must not validate the server.!");
}
catch (Exception ex)
{
Assert.assertEquals("Only ESTException", ex.getClass(), ESTException.class);
Assert.assertEquals("Cause must be SSLHandshakeException", ex.getCause().getClass(), SSLHandshakeException.class);
}
}
finally
{
if (serverInstance != null)
{
serverInstance.getServer().stop_server();
}
}
}
/**
* Fetch CA certs relying on TLS to validate the server by specifying a trust anchor.
*
* @throws Exception
*/
@Test
public void testFetchCaCertsWithTrustAnchor()
throws Exception
{
ESTTestUtils.ensureProvider();
X509CertificateHolder[] theirCAs = null;
ESTServerUtils.ServerInstance serverInstance = null;
try
{
serverInstance = startDefaultServer();
//
// Load the certificate that will become the trust anchor.
//
FileReader fr = new FileReader(ESTServerUtils.makeRelativeToServerHome("/estCA/cacert.crt"));
PemReader reader = new PemReader(fr);
X509CertificateHolder fromFile = new X509CertificateHolder(reader.readPemObject().getContent());
reader.close();
fr.close();
//
// Specify the trust anchor.
//
TrustAnchor ta = new TrustAnchor(ESTTestUtils.toJavaX509Certificate(fromFile), null);
ESTService est =
new JsseESTServiceBuilder(
"localhost:8443",
JcaJceUtils.getCertPathTrustManager(ESTTestUtils.toTrustAnchor(ta), null))
.build();
CACertsResponse caCertsResponse = est.getCACerts();
// Make the call. NB tlsAcceptAny is false.
X509CertificateHolder[] caCerts = ESTService.storeToArray(caCertsResponse.getCertificateStore());
// We expect the bootstrap authorizer to not be called.
Assert.assertEquals("Returned ca certs should be 1", caCerts.length, 1);
Assert.assertEquals("CA cert did match expected.", fromFile, caCerts[0]);
Assert.assertTrue("Must be trusted.", caCertsResponse.isTrusted());
}
finally
{
if (serverInstance != null)
{
serverInstance.getServer().stop_server();
}
}
}
/**
* This exercises the concept of bootstrapping as per RFC 7030.
* <p>
* We fetch the CA certs from the server using a TLS layer that will accept any certificate tendered by the server.
* In this situation some sort of out of band validation is expected for example, ask the user if they wish to proceed.
* <p>
* This test will fetch the CA certs and use the CertPath api to validate that the CA returned is as expected and
* it will use the CertPath API to validate the certificates tendered during the TLS handshake by the server.
*
* @throws Exception
*/
@Test
public void testFetchCaCertsChecksResponseUsingCertpath()
throws Exception
{
ESTTestUtils.ensureProvider();
X509CertificateHolder[] theirCAs = null;
final ESTServerUtils.ServerInstance serverInstance = startDefaultServer();
try
{
// SSLSocketFactoryCreatorBuilder sfcb = new SSLSocketFactoryCreatorBuilder(JcaJceUtils.getTrustAllTrustManager());
ESTService est =
new JsseESTServiceBuilder(
"localhost:8443",
JcaJceUtils.getTrustAllTrustManager()).build();
// // Note the constructor without TrustAnchors.
// ESTService est = new JcaESTServiceBuilder("localhost:8443/.well-known/est/").build();
CACertsResponse caCertsResponse = est.getCACerts(); //<= Accept any certs tendered by the server.
Assert.assertEquals("Returned ca certs should be 1", ESTService.storeToArray(caCertsResponse.getCertificateStore()).length, 1);
//
// This is more part of the test, we are checking that the CA cert returned is what we expect.
// We will later use the expectedCACert to validate the certificates tendered as part of TLS negotiation.
//
X509CertificateHolder expectedCACert;
{
X509CertificateHolder[] _caCerts = ESTService.storeToArray(caCertsResponse.getCertificateStore());
FileReader fr = new FileReader(ESTServerUtils.makeRelativeToServerHome("/estCA/cacert.crt"));
PemReader reader = new PemReader(fr);
expectedCACert = new X509CertificateHolder(reader.readPemObject().getContent());
reader.close();
fr.close();
assert _caCerts.length == 1;
assert expectedCACert.equals(_caCerts[0]);
}
//
// Use CertPath api to validate tls certs tended by the server expected against the CA.
//
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
CertPath cp = cf.generateCertPath(ESTTestUtils.toCertList(((SSLSession)caCertsResponse.getSession()).getPeerCertificates()));
CertPathValidator v = CertPathValidator.getInstance("PKIX", "BC");
PKIXParameters pkixParameters = new PKIXParameters(ESTTestUtils.toTrustAnchor(expectedCACert));
pkixParameters.setRevocationEnabled(false);
v.validate(cp, pkixParameters); // <= Throws exception if the path does not validate.
}
finally
{
if (serverInstance != null)
{
serverInstance.getServer().stop_server();
}
}
}
@Test(expected = IllegalStateException.class)
public void testEmptyCaCertsResponseZeroLength()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\r\n");
pw.print("Status: 200 OK\r\n");
pw.print("Content-Type: application/pkcs7-mime\r\n");
pw.print("Content-Transfer-Encoding: base64\r\n");
pw.print("Content-Length: 0\r\n");
pw.print("\r\n");
pw.flush();
final ESTResponse response = new ESTResponse(null, new Source()
{
public InputStream getInputStream()
throws IOException
{
return new ByteArrayInputStream(responseData.toByteArray());
}
public OutputStream getOutputStream()
throws IOException
{
return null;
}
public Object getSession()
{
return null;
}
public Object getTLSUnique()
{
return null;
}
public boolean isTLSUniqueAvailable()
{
return false;
}
public void close()
throws IOException
{
}
});
ESTServiceBuilder builder = new ESTServiceBuilder("foo.local")
{
@Override
public ESTService build()
{
return super.build();
}
};
builder.withClientProvider(new ESTClientProvider()
{
public ESTClient makeClient()
throws ESTException
{
return new ESTClient()
{
public ESTResponse doRequest(ESTRequest c)
throws IOException
{
return response;
}
};
}
public boolean isTrusted()
{
return false;
}
});
ESTService estService = builder.build();
CACertsResponse resp = estService.getCACerts();
Assert.assertFalse("Must be false, store is null", resp.hasCertificates());
resp.getCertificateStore();
}
@Test(expected = IllegalStateException.class)
public void testEmptyCaCertsResponse204()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 204 OK\r\n");
pw.print("Status: 204 OK\r\n");
pw.print("Content-Type: application/pkcs7-mime\r\n");
pw.print("Content-Transfer-Encoding: base64\r\n");
pw.print("\r\n");
pw.flush();
final ESTResponse response = new ESTResponse(null, new Source()
{
public InputStream getInputStream()
throws IOException
{
return new ByteArrayInputStream(responseData.toByteArray());
}
public OutputStream getOutputStream()
throws IOException
{
return null;
}
public Object getSession()
{
return null;
}
public Object getTLSUnique()
{
return null;
}
public boolean isTLSUniqueAvailable()
{
return false;
}
public void close()
throws IOException
{
}
});
ESTServiceBuilder builder = new ESTServiceBuilder("foo.local")
{
@Override
public ESTService build()
{
return super.build();
}
};
builder.withClientProvider(new ESTClientProvider()
{
public ESTClient makeClient()
throws ESTException
{
return new ESTClient()
{
public ESTResponse doRequest(ESTRequest c)
throws IOException
{
return response;
}
};
}
public boolean isTrusted()
{
return false;
}
});
ESTService estService = builder.build();
CACertsResponse resp = estService.getCACerts();
Assert.assertFalse("Must be false, store is null", resp.hasCertificates());
resp.getCertificateStore();
}
@Test()
public void testEmptyCaCertsResponseTruncated()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 10\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA");
pw.flush();
final ESTResponse response = new ESTResponse(null, new Source()
{
public InputStream getInputStream()
throws IOException
{
return new ByteArrayInputStream(responseData.toByteArray());
}
public OutputStream getOutputStream()
throws IOException
{
return null;
}
public Object getSession()
{
return null;
}
public Object getTLSUnique()
{
return null;
}
public boolean isTLSUniqueAvailable()
{
return false;
}
public void close()
throws IOException
{
}
});
ESTServiceBuilder builder = new ESTServiceBuilder("foo.local")
{
@Override
public ESTService build()
{
return super.build();
}
};
builder.withClientProvider(new ESTClientProvider()
{
public ESTClient makeClient()
throws ESTException
{
return new ESTClient()
{
public ESTResponse doRequest(ESTRequest c)
throws IOException
{
return response;
}
};
}
public boolean isTrusted()
{
return false;
}
});
ESTService estService = builder.build();
try
{
CACertsResponse resp = estService.getCACerts();
Assert.fail("Must fail on too small content length.");
}
catch (Exception ex)
{
Assert.assertEquals("Expect EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("Expect cause an IOException", EOFException.class, ex.getCause().getClass());
}
}
@Test()
public void testEmptyCaCertsResponseContentExceedsResponse()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 1000\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA");
pw.flush();
final ESTResponse response = new ESTResponse(null, new Source()
{
public InputStream getInputStream()
throws IOException
{
return new ByteArrayInputStream(responseData.toByteArray());
}
public OutputStream getOutputStream()
throws IOException
{
return null;
}
public Object getSession()
{
return null;
}
public Object getTLSUnique()
{
return null;
}
public boolean isTLSUniqueAvailable()
{
return false;
}
public void close()
throws IOException
{
}
});
ESTServiceBuilder builder = new ESTServiceBuilder("foo.local")
{
@Override
public ESTService build()
{
return super.build();
}
};
builder.withClientProvider(new ESTClientProvider()
{
public ESTClient makeClient()
throws ESTException
{
return new ESTClient()
{
public ESTResponse doRequest(ESTRequest c)
throws IOException
{
return response;
}
};
}
public boolean isTrusted()
{
return false;
}
});
ESTService estService = builder.build();
try
{
estService.getCACerts();
Assert.fail("Must fail on not reading all content.");
}
catch (Exception ex)
{
Assert.assertEquals("Must be EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("Cause is IO Exception.", IOException.class, IOException.class);
}
}
@Test()
public void testEmptyCaCertsResponseContentLengthExceedsAbsoluteLimit()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 1000\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(1000L);
builder.addCipherSuites(res.getEnabledSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail.");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("", IOException.class, ex.getCause().getClass());
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testContentLengthBelowAbsoluteLimit()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getEnabledSuites());
ESTService est = builder.build();
// This must not fail.
est.getCACerts();
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testResponseContentLengthInvalid()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: banana\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getSupportedCipherSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, content length = banana");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("", RuntimeException.class, ex.getCause().getClass());
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testResponseNoContentLengthHeader()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getSupportedCipherSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, no content length header");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("", IOException.class, ex.getCause().getClass());
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testResponseNegativeContentLength()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: -1\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getSupportedCipherSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, content length = banana");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("", IOException.class, ex.getCause().getClass());
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testIncorrectContentType()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/octet-stream\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getSupportedCipherSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, incorrect content type.");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testMissingContentType()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getSupportedCipherSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, incorrect content type.");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertTrue(ex.getMessage().contains("but was not present"));
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testRejectOnTLSv1Establishment()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder().withTlsProtocol("TLSv1");
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getSupportedCipherSuites());
builder.withTLSVersion("TLSv1");
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, incorrect content type.");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("", IOException.class, ex.getCause().getClass());
Assert.assertTrue(ex.getMessage().contains("must not use TLSv1"));
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testRejectOnNullCipherEstablishment()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
res.setCipherSuites(new String[]{
"TLS_RSA_WITH_NULL_SHA256",
"TLS_ECDHE_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_RSA_WITH_NULL_SHA",
"SSL_RSA_WITH_NULL_SHA",
"TLS_ECDH_ECDSA_WITH_NULL_SHA",
"TLS_ECDH_RSA_WITH_NULL_SHA",
"TLS_ECDH_anon_WITH_NULL_SHA",
"SSL_RSA_WITH_NULL_MD5"
});
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"127.0.0.1:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530).withHostNameAuthorizer(null);
builder.addCipherSuites(res.getEnabledSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, incorrect no null ciphers.");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertTrue("", ex.getCause() instanceof IOException);
Assert.assertTrue(ex.getMessage().contains("must not use NULL"));
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testRejectOnAnonCipherEstablishment()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
res.setCipherSuites(new String[]{
"TLS_DH_anon_WITH_AES_128_GCM_SHA256",
"TLS_DH_anon_WITH_AES_128_CBC_SHA256",
"TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
"TLS_DH_anon_WITH_AES_128_CBC_SHA",
"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
"SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_anon_WITH_RC4_128_SHA",
"SSL_DH_anon_WITH_RC4_128_MD5",
"SSL_DH_anon_WITH_DES_CBC_SHA",
"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
});
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"127.0.0.1:" + port, JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530).withHostNameAuthorizer(null);
builder.addCipherSuites(res.getEnabledSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, used anon cipher.");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertTrue("", ex.getCause() instanceof IOException);
Assert.assertTrue(ex.getMessage().contains("must not use anon"));
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
@Ignore("JVMs 7,8 etc don't easily support creation of EXPORT cipher suites, so this has been skipped.")
public void testRejectOnExportCipherEstablishment()
throws Exception
{
ExampleUtils.ensureProvider();
//
// We need a self signed certificate using transformations old enough
// to work with Export suites.
//
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
X509Certificate cert = ExampleUtils.toJavaX509Certificate(
ExampleUtils.createSelfsignedCert("SHA1withRSA", new X500Name("CN=127.0.0.1"), SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded()), kp.getPrivate(), 1)
);
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder().withTlsProtocol("TLSv1").withCreds(cert, kp.getPrivate());
res.setCipherSuites(new String[]{
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
// "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
// "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
// "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
// "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"
});
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"127.0.0.1:" + port, JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.withTLSVersion("TLSv1");
builder.withProvider("SunJSSE");
String[] k = res.getEnabledSuites();
builder.addCipherSuites(res.getEnabledSuites());
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, used export cipher.");
}
catch (Exception ex)
{
ex.printStackTrace();
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertTrue("Cause is IOException", ex.getCause() instanceof IOException);
Assert.assertTrue(ex.getMessage().contains("must not use export"));
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testRejectOnDESCipherEstablishment()
throws Exception
{
ExampleUtils.ensureProvider();
//
// We need a self signed certificate using transformations old enough
// to work with Export suites.
//
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
kpg.initialize(2048);
KeyPair kp = kpg.generateKeyPair();
X509Certificate cert = ExampleUtils.toJavaX509Certificate(
ExampleUtils.createSelfsignedCert("SHA1withRSA", new X500Name("CN=127.0.0.1"), SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded()), kp.getPrivate(), 1)
);
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 529\n" +
"\n" +
"MIIBggYJKoZIhvcNAQcCoIIBczCCAW8CAQExADALBgkqhkiG9w0BBwGgggFXMIIB\n" +
"UzCB+qADAgECAgkA+syTlV9djhkwCgYIKoZIzj0EAwIwFzEVMBMGA1UEAwwMZXN0\n" +
"RXhhbXBsZUNBMB4XDTE3MDIxODAyNTQ1OVoXDTE4MDIxODAyNTQ1OVowFzEVMBMG\n" +
"A1UEAwwMZXN0RXhhbXBsZUNBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEobjd\n" +
"xMcCE5GfVRE4f86ik6yK0erBhAbN8er0u6vWTXlyk5IXJy7HsUmC7Wv1SDRno/Rp\n" +
"pyVekSu4T0/h7uBeaKMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU8rjiAzjo\n" +
"Nldka5gT1bcbQqcESPMwCgYIKoZIzj0EAwIDSAAwRQIhAOwsMtixDryuVUYNBdaf\n" +
"3tQV1SlvBmCP6y3cKMST45sRAiBEUNYOsYnuFmH93I+0NSJPYuuBY+Zfqrc2awCs\n" +
"spOU3zEA\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder().withCreds(cert, kp.getPrivate());
res.setCipherSuites(new String[]{
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_DH_anon_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
"TLS_KRB5_WITH_DES_CBC_SHA",
"TLS_KRB5_WITH_DES_CBC_MD5",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"
});
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"127.0.0.1:" + port , JcaJceUtils.getTrustAllTrustManager());
builder.withReadLimit(530);
builder.addCipherSuites(res.getEnabledSuites());
builder.withTLSVersion("TLSv1"); // <- needed to get export suites to work.
ESTService est = builder.build();
try
{
est.getCACerts();
Assert.fail("Must fail, used export cipher.");
}
catch (Exception ex)
{
Assert.assertEquals("EST Exception", ESTException.class, ex.getClass());
Assert.assertEquals("Cause is IOException", IOException.class, ex.getCause().getClass());
Assert.assertTrue(ex.getMessage().contains("must not use DES"));
}
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testCertResponseWithCRL()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 655\n" +
"\n" +
"MIIB3QYJKoZIhvcNAQcCoIIBzjCCAcoCAQExADALBgkqhkiG9w0BBwGgggGwMIIB\n" +
"rDCCAVKgAwIBAgICLdwwCQYHKoZIzj0EATAXMRUwEwYDVQQDDAxlc3RFeGFtcGxl\n" +
"Q0EwHhcNMTQwNzA5MTY0NzExWhcNMzMwOTA3MTY0NzExWjAXMRUwEwYDVQQDDAxl\n" +
"c3RFeGFtcGxlQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATbixdp4YMKGmfj\n" +
"fF2rzwRQXMX+2YoJvsskqU3qMUAJhfrYvMPo3smPWbE0jftfw+UlsKD3HiHUCOCV\n" +
"ySHKSfPbo4GOMIGLMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFN0KrHLtKvSyE5OI\n" +
"c9MAA9sCAbTyMB8GA1UdIwQYMBaAFN0KrHLtKvSyE5OIc9MAA9sCAbTyMDsGA1Ud\n" +
"EQQ0MDKCCWxvY2FsaG9zdIINaXA2LWxvY2FsaG9zdIcEfwAAAYcQAAAAAAAAAAAA\n" +
"AAAAAAAAATAJBgcqhkjOPQQBA0kAMEYCIQDNq+Vjoi6mgSqXSLzJ7OVs+RzjGox3\n" +
"xXttoJ9B7eDjjgIhALpU+OVvyfhDJbHegWC02OX6laPTBNjAf6V8aVOP1rYdoQAx\n" +
"AA==\n");
pw.flush();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder();
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port, JcaJceUtils.getTrustAllTrustManager());
builder.addCipherSuites(res.getSupportedCipherSuites());
ESTService est = builder.build();
CACertsResponse resp = est.getCACerts();
Assert.assertTrue("Must have CRLS", resp.hasCRLs());
Assert.assertTrue("Must have Certs", resp.hasCertificates());
Store<X509CertificateHolder> x509CertificateHolderStore = resp.getCertificateStore();
Collection<X509CertificateHolder> x509CertificateHolders = x509CertificateHolderStore.getMatches(null);
Assert.assertTrue(!x509CertificateHolders.isEmpty());
Store<X509CRLHolder> x509CRLHolderStore = resp.getCrlStore();
Collection<X509CRLHolder> x509CRLHolders = x509CRLHolderStore.getMatches(null);
Assert.assertTrue(x509CRLHolders.isEmpty()); // CRL is actually empty.
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
@Test()
public void testCertResponseWithLabelApplication()
throws Exception
{
final ByteArrayOutputStream responseData = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(responseData);
pw.print("HTTP/1.1 200 OK\n" +
"Status: 200 OK\n" +
"Content-Type: application/pkcs7-mime\n" +
"Content-Transfer-Encoding: base64\n" +
"Content-Length: 655\n" +
"\n" +
"MIIB3QYJKoZIhvcNAQcCoIIBzjCCAcoCAQExADALBgkqhkiG9w0BBwGgggGwMIIB\n" +
"rDCCAVKgAwIBAgICLdwwCQYHKoZIzj0EATAXMRUwEwYDVQQDDAxlc3RFeGFtcGxl\n" +
"Q0EwHhcNMTQwNzA5MTY0NzExWhcNMzMwOTA3MTY0NzExWjAXMRUwEwYDVQQDDAxl\n" +
"c3RFeGFtcGxlQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATbixdp4YMKGmfj\n" +
"fF2rzwRQXMX+2YoJvsskqU3qMUAJhfrYvMPo3smPWbE0jftfw+UlsKD3HiHUCOCV\n" +
"ySHKSfPbo4GOMIGLMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFN0KrHLtKvSyE5OI\n" +
"c9MAA9sCAbTyMB8GA1UdIwQYMBaAFN0KrHLtKvSyE5OIc9MAA9sCAbTyMDsGA1Ud\n" +
"EQQ0MDKCCWxvY2FsaG9zdIINaXA2LWxvY2FsaG9zdIcEfwAAAYcQAAAAAAAAAAAA\n" +
"AAAAAAAAATAJBgcqhkjOPQQBA0kAMEYCIQDNq+Vjoi6mgSqXSLzJ7OVs+RzjGox3\n" +
"xXttoJ9B7eDjjgIhALpU+OVvyfhDJbHegWC02OX6laPTBNjAf6V8aVOP1rYdoQAx\n" +
"AA==\n");
pw.flush();
final ArrayList<String> lineBuffer = new ArrayList<String>();
//
// Test content length enforcement.
// Fail when content-length = read limit.
//
HttpResponder res = new HttpResponder(lineBuffer);
try
{
int port = res.open(responseData.toByteArray());
JsseESTServiceBuilder builder = new JsseESTServiceBuilder(
"localhost:" + port, JcaJceUtils.getTrustAllTrustManager());
builder.addCipherSuites(res.getSupportedCipherSuites());
builder.withLabel("the_label");
ESTService est = builder.build();
CACertsResponse resp = est.getCACerts();
Assert.assertTrue(lineBuffer.get(0).contains("/.well-known/est/the_label/cacerts"));
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
res.close();
}
res.getFinished().await(5, TimeUnit.SECONDS);
}
public static void main(String[] args)
throws Exception
{
ESTTestUtils.ensureProvider();
runTest(new TestCACertsFetch());
}
}