Encrypted communication not working with generated certificate
What I want to do
I want to start a server with a self-signed certificate and connect a client to it. Code (without imports):
public class Main {
public static void main(String[] args) throws IOException {
ServerInformation serverInformation = new ServerInformation("ExampleType",
"Example description",
"https://example.com",
"0.1"
);
final Path keyFile = Paths.get(System.getProperty("user.home"), "key.pem");
final Path certFile = Paths.get(System.getProperty("user.home"), "cert.pem");
final int port = 50052;
// start server
try (SiLAServer server = SiLAServer.Builder.withoutConfig(serverInformation)
.withPersistedTLS(keyFile, certFile,null)
.withPort(port)
.start()) {
// try to connect to server and print its name
try (InputStream certStream = Files.newInputStream(certFile.toFile().toPath())) {
Channel channel = ChannelFactory.getTLSEncryptedChannel("127.0.0.1", port, certStream);
SiLAServiceGrpc.SiLAServiceBlockingStub stub = SiLAServiceGrpc.newBlockingStub(channel);
String serverName = stub.getServerName(SiLAServiceOuterClass.Get_ServerName_Parameters.newBuilder().build()).getServerName().getValue();
System.out.println("Server name is " + serverName);
}
}
}
}
Repo: https://gitlab.com/NMertsch/sila-java-maven-issue
What I expect
The program prints the server name.
What actually happens
Client cannot communicate with the server. Excerpt of the error:
- java.lang.reflect.InvocationTargetException
- Caused by: io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
- Caused by: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem
- Caused by: java.security.cert.CertificateException: No subject alternative names present
Additional information
It appears to be a server-side error with the generated certificate:
The client-side code works just fine with a sila_python server (also using a self-signed, auto-generated certificate)
Server code (requires Python >= 3.7 and pip install sila2):
from pathlib import Path
from sila2.server import SilaServer
server = SilaServer("ServerName", "ServerType", "Description", "0.1", "https://gitlab.com/SiLA2/sila_python")
server.start("127.0.0.1", 50052)
with open(Path.home() / "ca.pem", "wb") as ca_file:
ca_file.write(server.generated_ca)
print("Server started, press Return to stop it.")
input()
print("Server stopped")
Client code (using sila_java 0.6.0):
public class Client {
public static void main(String[] args) throws IOException {
final int port = 50052;
final Path caFile = Paths.get(System.getProperty("user.home"), "ca.pem");
try (InputStream certStream = Files.newInputStream(caFile.toFile().toPath())) {
Channel channel = ChannelFactory.getTLSEncryptedChannel("127.0.0.1", port, certStream);
SiLAServiceGrpc.SiLAServiceBlockingStub stub = SiLAServiceGrpc.newBlockingStub(channel);
String serverName = stub.getServerName(SiLAServiceOuterClass.Get_ServerName_Parameters.newBuilder().build()).getServerName().getValue();
System.out.println("Server name is " + serverName);
}
}
}
Everything works just fine when using a self-signed certificate generated using sila_python for the Java server and clients
Python code to generate UUID and certificate:
from pathlib import Path
import uuid
from sila2.server.encryption import generate_self_signed_certificate
server_uuid = uuid.uuid4()
key, cert = generate_self_signed_certificate(server_uuid, "localhost")
open(Path.home() / "uuid.txt", "w").write(str(server_uuid))
open(Path.home() / "cert.pem", "wb").write(cert)
open(Path.home() / "key.pem", "wb").write(key)
Java code to run server and client:
import io.grpc.Channel;
import sila2.org.silastandard.core.silaservice.v1.SiLAServiceGrpc;
import sila2.org.silastandard.core.silaservice.v1.SiLAServiceOuterClass;
import sila_java.library.core.sila.clients.ChannelFactory;
import sila_java.library.server_base.SiLAServer;
import sila_java.library.server_base.config.IServerConfigWrapper;
import sila_java.library.server_base.config.PersistentServerConfigWrapper;
import sila_java.library.server_base.config.ServerConfiguration;
import sila_java.library.server_base.identification.ServerInformation;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
public class Main {
public static void main(String[] args) throws IOException {
ServerInformation serverInformation = new ServerInformation("ExampleType",
"Example description",
"https://example.com",
"0.1"
);
final String serverName = "Server Name";
final UUID serverUuid = UUID.fromString(Files.readAllLines(Paths.get(System.getProperty("user.home"), "uuid.txt")).get(0));
final ServerConfiguration serverConfiguration = new ServerConfiguration(serverName, serverUuid);
final Path configFilePath = Paths.get(System.getProperty("user.home"), "server-config.json");
final IServerConfigWrapper configWrapper = new PersistentServerConfigWrapper(configFilePath, serverName);
configWrapper.setConfig(serverConfiguration);
final Path keyFile = Paths.get(System.getProperty("user.home"), "key.pem");
final Path certFile = Paths.get(System.getProperty("user.home"), "cert.pem");
final int port = 50052;
try (SiLAServer server = SiLAServer.Builder.withConfig(configFilePath, serverInformation)
.withPersistedTLS(keyFile, certFile,null)
.withPort(port)
.start()) {
try (InputStream certStream = Files.newInputStream(certFile.toFile().toPath())) {
Channel channel = ChannelFactory.getTLSEncryptedChannel("127.0.0.1", port, certStream);
SiLAServiceGrpc.SiLAServiceBlockingStub stub = SiLAServiceGrpc.newBlockingStub(channel);
String receivedServerName = stub.getServerName(SiLAServiceOuterClass.Get_ServerName_Parameters.newBuilder().build()).getServerName().getValue();
System.out.println("Server name is " + receivedServerName);
}
}
}
}
Edited by Niklas Mertsch