Reputation: 51
I wrote the HTTPS server using the example here.
Server code:
public class HTTPSServer {
public static void main(String[] args) throws Exception {
HttpsServer server = HttpsServer.create(new InetSocketAddress(8080), 5);
server.createContext("/", new MyHandler());
char[] storepass = "storepass".toCharArray();
char[] keypass = "serverpass".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(HTTPSServer.class.getClassLoader().getResourceAsStream("web-vision.jks"), storepass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keypass);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), new TrustManager[]{}, null);
server.setHttpsConfigurator(new HttpsConfigurator(sslContext) {
@Override
public void configure (HttpsParameters params) {
// get the remote address if needed
InetSocketAddress remote = params.getClientAddress();
SSLContext c = getSSLContext();
// get the default parameters
SSLParameters sslparams = c.getDefaultSSLParameters();
params.setSSLParameters(sslparams);
// statement above could throw IAE if any params invalid.
// eg. if app has a UI and parameters supplied by a user.
}
});
ExecutorService executor = Executors.newFixedThreadPool(5);
server.setExecutor(executor); // creates a default executor
server.start();
executor.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
}
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response = "This is the response";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
}
}
For this server, I've created a file with keys with the command:
keytool -genkey -keystore web-vision.jks -dname "CN=localhost, OU=gg, O=NA, L=Unknown, ST=Unknown, C=RU" -storepass storepass -alias server-test -keypass serverpass
Next, I put this file in the project resources.
Then I start this server and try to connect to it and to get an answer by visiting https://10.155.26.68:8080/
and https://localhost:8080/
, but there is no answer, the server is unavailable.
Prior to this, I implemented the simplest HTTP server and it worked fine.
Connecting to the HTTPS server with curl yields this error:
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 10.155.26.68:8080
Update:
Thanks for the help, but the problem was solved only by creating a new certificate using the command:
keytool -v -genkey -dname "CN=localhost, OU=Developers, O=NA, L=Ufa, C=RB" -alias parent -storetype jks -keystore vision.jks -validity 365 -keyalg RSA -keysize 2048 -storepass mystorepass -keypass mykeypass
I'm just learning SSL and maybe the first certificate was created incorrectly.
Upvotes: 2
Views: 2070
Reputation: 34313
The probable reason you encountered SSL_ERROR_SYSCALL
with curl, is that when creating your certificate with keytool
, you didn't specify the algorithm to use.
In this case, keytool
defaults to using DSA.
Then, during the handshake phase with curl, the server can't find a common authentication scheme and throws an exception:
javax.net.ssl.SSLHandshakeException: No available authentication scheme
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:308)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:255)
at java.base/sun.security.ssl.CertificateMessage$T13CertificateProducer.onProduceCertificate(CertificateMessage.java:945)
at java.base/sun.security.ssl.CertificateMessage$T13CertificateProducer.produce(CertificateMessage.java:934)
at java.base/sun.security.ssl.SSLHandshake.produce(SSLHandshake.java:436)
at java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.goServerHello(ClientHello.java:1224)
at java.base/sun.security.ssl.ClientHello$T13ClientHelloConsumer.consume(ClientHello.java:1160)
at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.onClientHello(ClientHello.java:849)
at java.base/sun.security.ssl.ClientHello$ClientHelloConsumer.consume(ClientHello.java:810)
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:448)
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1065)
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1052)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:999)
at jdk.httpserver/sun.net.httpserver.SSLStreams.doHandshake(SSLStreams.java:464)
at jdk.httpserver/sun.net.httpserver.SSLStreams.recvData(SSLStreams.java:418)
at jdk.httpserver/sun.net.httpserver.SSLStreams$InputStream.read(SSLStreams.java:522)
at jdk.httpserver/sun.net.httpserver.SSLStreams$InputStream.read(SSLStreams.java:591)
at jdk.httpserver/sun.net.httpserver.Request.readLine(Request.java:80)
at jdk.httpserver/sun.net.httpserver.Request.<init>(Request.java:50)
at jdk.httpserver/sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:551)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Since this exception is logged at log level FINER
by sun.net.httpserver.ServerImpl$Exchange.run
it's difficult to detect.
As you figured out, calling keytool
with -keyalg RSA
to generate the certificate, makes server and client find an authentication scheme which fixes that issue:
keytool -genkeypair -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass secret_password -dname "CN=localhost, OU=Developers, O=NA, L=Ufa, C=RB"
Upvotes: 2