I'm trying to make a ssl webserver with jetty, but I do not want to provide the server certificate if any client tries to connect. On normal cases anybody can download the server certificate, trust and connect to the server. But I would like to install the server certificate manuelly on my client to be sure, that only my client has that cert and can connect to my server.
Is that possible? I didn't find anything around the web related to Jetty.
I'm playing with some example code and my truststore. Nothing special.
final Server server = new Server();
server.setHandler(new HelloWorld());
final HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.setSecureScheme("https");
httpConfiguration.setSecurePort(8085);
final ServerConnector http = new ServerConnector(server,
new HttpConnectionFactory(httpConfiguration));
http.setPort(8081);
server.addConnector(http);
final SslContextFactory sslContextFactory = new SslContextFactory("mykey.jks");
sslContextFactory.setKeyStorePassword("tester");
sslContextFactory.setNeedClientAuth(true);
final HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration);
httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
final ServerConnector httpsConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(httpsConfiguration));
httpsConnector.setPort(8085);
server.addConnector(httpsConnector);
server.start();
server.join();
I know, that's a special usecase. If there is a better solution, let me know (and no, login session is no option for me). It has to be as simple as it is possible.
Instead of attempting security though obscurity you should implement Two Way SSL. You can take a look at 2-Way SSL with Java: The Keystore Strikes Back article.
The client can always blindly trust or ignore any certificate presented by the server. As long as someone knows the server address they will be able to make a request.
Related
I am using Jetty HTTP2 Client 9.4.12 to support HTTP/2 server connection. It's working fine but on top of verifying the certificate, I also want to verify the Hostname using my javax.net.ssl.HostnameVerifier implementation. According to the doc https://www.eclipse.org/jetty/javadoc/9.4.12.v20180830/org/eclipse/jetty/util/ssl/SslContextFactory.html I can use setEndpointIdentificationAlgorithm("HTTPS") to enable hostname verification but how do I configure Jetty to use my implementation?
Thanks.
Jetty's HttpClient does not support javax.net.ssl.HostnameVerifier.
An enhancement request exists for this ...
https://github.com/eclipse/jetty.project/issues/3154
Feel free to comment on the open enhancement requesting it, and providing an example of how you would use it.
The support has been added in Jetty v9.4.15.v20190215.
final SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setHostnameVerifier((hostname, sslSession) -> {
// logic to verify hostname
return false;
});
I have an SSL-enabled tcp server that can listen to multiple rsyslog clients. Each client has its own certificate that is added in the server's truststore. This setup is working fine. TThe question is whether there is a way to get the client certificate information like CN, location etc. after the socket accepts connection?
Below is the code sample of simple tcp server.
SSLServerSocketFactory sf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss = sf.createServerSocket(514);
while(true){
SSLSocket s = (SSL)ss.accept();
// here I need to get client certificate information
}
You need to configure the SSLServerSocket to need or want client authentication, depending on which of those applies. Then you can get the peer certificates out of the SSLSocket's SSLSession, if they were sent.
Unfortunately I'm completely new to SSL. Currently I'm trying to set up a secure connection between a client and a server application in Java and the following code works for me (transmitted data is encrypted), but I don't know if this is a correct and secure solution.
Client side:
socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket(host, port);
socket.setUseClientMode(true);
socket.setEnabledCipherSuites(socket.getSupportedCipherSuites());
socket.startHandshake();
Server side:
sslServerSocket = (SSLServerSocket) serverSocketFactory.createServerSocket(requestPort());
sslServerSocket.setUseClientMode(false);
sslServerSocket.setEnabledCipherSuites(sslServerSocket.getSupportedCipherSuites());
It is not advisable to enable all ciphers/protocols. Better that you enabled only the ciphers and protocols you want. If both server and server is written by you, choose what you want and configure only that.
socket.setEnabledCipherSuites(...);
socket.setEnabledProtocols(...);
Supported ciphers and protocols can be seen in JSSE documentation
Or you can use "jdk.tls.disabledAlgorithm" to control what algs you want to use.
I have a machine running Jetty. On there I have multiple jetty instances running on different ports. For instance I have the "live" version running on the default port 80. I also have the "R&D" version running on the same machine but on port 2280. This works just fine, however the client needed to add SSL so the default would now be running off port 443. The issue is when I try to run both at the same time the R&D version will fail because it is trying to map to 443 because of the SSL. The config still has the R&D pointing to 2280 but does not start. Is there a way to run both at the same time using the single SSL certificate? I tried adding connectors in the jetty.xml file but that did not work. Thanks.
How are you adding the connector? You can definitely configure the port of the connector.
I typically run Jetty programmatically, and my code is as follows:
int httpsPort = ...;
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecureScheme("https");
httpConfig.setSecurePort(httpsPort);
SslContextFactory sslContextFactory = new SslContextFactory();
// configure sslContextFactory: keystore, session timeout, exlcluded protocols etc...
ServerConnector httpsCon = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"), new HttpConnectionFactory(httpConfig));
httpsCon.setPort(httpsPort);
server.addConnector(httpsCon);
Sorry, I am not sure how to configure that via XML server configuration, but they tend to map very closely between XML config and programmatic config.
I've been serving a web application over HTTPS on the default port of 443 with embedded Jetty (let's call that serverA) on Ubuntu 14.04 (using a self-signed certificate). It's been working fine for ages now, but I want to run another embedded Jetty web server (serverB) on the same machine. I'd like serverB to run SSL using the default port 443, so I need to change serverA to listen for requests on some other port.
I've been trying serverA with 444 and 8080. The server fires up just fine, telling me that it's listening for requests on the correct port. but requests just hang and the server logs are telling me nothing. If I start the server up listening on port 443, then everything works fine.
I didn't think it matters which port I use as long as I have the web server configured to use SSL. Is there something else I need to do?
Here's my launch code:
// Java 7 bug (feature?) - this disables SNI everywhere...
// required or else outgoing HTTPS requests will fail
System.setProperty("jsse.enableSNIExtension", "false");
PropertyConfigurator.configure("./log4j.properties");
Server server = new Server();
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar("war");
server.setHandler(webapp);
HttpConfiguration https = new HttpConfiguration();
https.addCustomizer(new SecureRequestCustomizer());
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("keystore.jks");
sslContextFactory.setKeyStorePassword("password");
sslContextFactory.setKeyManagerPassword("password");
ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, "http/1.1"),
new HttpConnectionFactory(https));
sslConnector.setPort(port);
server.setConnectors(new Connector[] { sslConnector });
try {
LOG.info("Starting server on port " + port);
server.start();
server.join();
} catch (Exception e) {
LOG.fatal("The web server has crashed", e);
}
Note: The reason this is on StackOverflow and not SuperUser or something else is because, from what I understand, the port used for HTTPS is not important. I'm assuming this is a Jetty issue, then.
Edit:
Sorry, forgot to mention Jetty version. It's 9.2.0
Try this, as you didn't tell jetty what is considered secure, its just using defaults.
HttpConfiguration https = new HttpConfiguration();
https.setSecurePort(port); /* missing this */
https.addCustomizer(new SecureRequestCustomizer());
This might seem strange, but is actually needed, because you can be considered secure even if the connection arrived in a non-secure way. Such as from a proxy or an ssl terminated load balancer in front of jetty (the variety of ways is quite stunning)