Reputation: 698
I'm not getting the X509 Certificates in incoming client request after Jetty Upgrade to
9.4.19.v20190610
certifcates = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
Here the certificates are null. Though they were coming in Jetty version
9.4.11.v20180605
My Client Program:
private static String loginWithCertificate(String aEndPointURL) {
String line = "";
try {
final String CERT_ALIAS = "employee1";
String CERT_PASSWORD = "changeit";
KeyStore identityKeyStore = KeyStore.getInstance("jks");
FileInputStream identityKeyStoreFile = new FileInputStream(new File(ResourceUtils.getFile("./stores/client1.jks").getAbsolutePath()));
identityKeyStore.load(identityKeyStoreFile, CERT_PASSWORD.toCharArray());
KeyStore trustKeyStore = KeyStore.getInstance("jks");
FileInputStream trustKeyStoreFile = new FileInputStream(new File(ResourceUtils.getFile("./stores/truststore1.jks").getAbsolutePath()));
trustKeyStore.load(trustKeyStoreFile, CERT_PASSWORD.toCharArray());
SSLContext sslContext = SSLContexts.custom()
// load identity keystore
.loadKeyMaterial(identityKeyStore, CERT_PASSWORD.toCharArray(), new PrivateKeyStrategy() {
@Override
public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
return CERT_ALIAS;
}
})
// load trust keystore
.loadTrustMaterial(trustKeyStore, null).build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }, null, SSLConnectionSocketFactory.STRICT_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
HttpPost req = new HttpPost(aEndPointURL);
StringEntity entity = new StringEntity(
"{\"ipAddress\" : \"172.20.186.74\", \"port\" : 1363, \"protocol\" : \"tls1.2\"}");
req.setHeader("Content-type", "application/json");
req.setHeader("X-XSRF-TOKEN", "Y2hlY2tpdA==");
req.setHeader("CertificateAuthentication", "true");
req.setEntity(entity);
HttpResponse response = client.execute(req);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
} catch (Exception ex) {
System.out.println("Exception : " + ex);
ex.printStackTrace();
}
return line;
}
My SSL Connector at Server:
public EmbeddedServletContainerFactory customizeJetty() {
JettyEmbeddedServletContainerFactory container = new JettyEmbeddedServletContainerFactory();
container.addServerCustomizers(new JettyServerCustomizer() {
@Override
public void customize(Server server) {
// HTTP
try (ServerConnector connector = new ServerConnector(server);) {
validateHttpPort(httpPort, securedPort);
connector.setPort(Integer.parseInt(httpPort));
// HTTPS
SslContextFactory sslContextFactory = new SslContextFactory();
URL urlKeyStore = null;
Path keyStoreFilePath = null;
File keyStoreFile = null;
// Appscan Vulnerability - Should not use Hardcoded paths using File Separator.
// We should use Path API to read the files.
keyStoreFilePath = Paths.get("WebServices", "src", "main", "resources");
keyStoreFile = Paths.get(keyStoreFilePath.toString(), keyStoreName).toFile();
if (!keyStoreFile.exists()) {
keyStoreFilePath = fetchPathForKeyStore();
keyStoreFile = keyStoreFilePath.toFile();
}
urlKeyStore = fetchKeyStoreUrl(keyStoreFile);
validateUrlKeyStore(urlKeyStore);
sslContextFactory.setKeyStoreResource(Resource.newResource(urlKeyStore));
// Getting Credentials from hidden file
String encodedProperty = MFTUtils.fetchCredentialForKeyStore();
validateEncodedProperty(encodedProperty);
StringTokenizer tokenizer = new StringTokenizer(encodedProperty,
MFTConstants.HTTP_CREDENTIAL_DELIMITER); // constant
validateTokens(tokenizer);
String encodedCredential = tokenizer.nextToken();
String credentialKey = tokenizer.nextToken();
String credential = AESEncryptionDecryption.decrypt(encodedCredential, credentialKey);
// null checking credentials
validateCredential(credential, credentialKey);
sslContextFactory.setKeyStorePassword(credential);
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
sslContextFactory.setExcludeProtocols("");
HttpConfiguration https = new HttpConfiguration();
https.addCustomizer(new SecureRequestCustomizer());
if (System.getProperty(MFTConstants.SERVER_SSL_ENABLED).equalsIgnoreCase(MFTConstants.TRUE)) {
UtilLogger.debug(logger, "HTTPS is enabled.");
try (ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, MFTConstants.HTTP_PROTOCOL),
new HttpConnectionFactory(https));) {
sslConnector.setPort(Integer.parseInt(securedPort));
server.setConnectors(new Connector[] { connector, sslConnector });
}
} else {
UtilLogger.debug(logger, "HTTPS is disabled. Application will run over HTTP only.");
try (ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, MFTConstants.HTTP_PROTOCOL));) {
server.setConnectors(new Connector[] { connector });
}
}
}
}
I am trying with Self Signed Certificates.
Update I'm using jks keystore. i.e. Certificates without key.
:
Any Help would be highly appreciated.
Upvotes: 0
Views: 1082
Reputation: 49515
Looking closer at your server side SslContextFactory usage, with an eye on what you are actually using (stripping away to only show SslContextFactory usage)
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStoreResource(Resource.newResource(urlKeyStore));
sslContextFactory.setKeyStorePassword(credential);
sslContextFactory.setExcludeCipherSuites(
"SSL_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_RSA_WITH_DES_CBC_SHA",
"SSL_DHE_DSS_WITH_DES_CBC_SHA",
"SSL_RSA_EXPORT_WITH_RC4_40_MD5",
"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
sslContextFactory.setExcludeProtocols("");
A few things stand out.
First, since you are a server, you should use the server version ...
SslContextFactory sslContextFactory = new SslContextFactory.Server();
Next, your use of .setExcludedCipherSuites()
is incomplete and introduces vulnerabilties.
Remove (or comment out) that entire line.
Use the defaults that SslContextFactory offers you.
With that line, it's possible to use no-certificate, and no-encryption, configurations for TLS/SSL.
Also, your use of setExcludedProtocols("")
is bad. It's setting a single blank protocol to be excluded. This is bad, as you are exposing yourself to all manner of SSL vulnerabilities (let alone TLS vulnerabilities)
Remove (or comment out) that entire line also.
Use the defaults that SslContextFactory offers you.
With that line, it's possible to use no-protocol (which means no-encryption) configurations for TLS/SSL.
There's a myriad of warning logs produced with those 2 above configurations, you should strive to have a configuration that has no warnings.
For the two issues above, you might learn something from the name of the cipher suite that was used in your connection.
String cipherSuiteName =
(String) HttpServletRequest.getAttribute("javax.servlet.request.cipher_suite");
You can even obtain the javax.net.ssl.SSLSession
used in the connection.
SslSession sslSession =
(SslSession) HttpServletRequest.getAttribute(
"org.eclipse.jetty.servlet.request.ssl_session");
System.out.println("protocol is " + sslSession.getProtocol());
System.out.println("cipher suite is " + sslSession.getCipherSuite());
System.out.println("peer certs is " + sslSession.getPeerCertificates());
Finally, your code has no indication that you even want client certificates from that configuration.
Have you forgotten one of ...
sslContextFactory.setNeedClientAuth(true);
sslContextFactory.setWantClientAuth(true);
Or are you really not wanting client certificates?
Upvotes: 1