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 Aug 10, 2022 by Niklas Mertsch
Assignee Loading
Time tracking Loading