Abhishek
Abhishek

Reputation: 698

X509 Certificates are not coming in incoming client request after Jetty Upgrade to 9.4.19.v20190610

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

Answers (1)

Joakim Erdfelt
Joakim Erdfelt

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

Related Questions