import java.io.*;
import java.security.KeyStore;
import javax.net.ssl.*;

/**
 * Runs a TLS 1.3 server and client in one JVM over loopback and prints what the handshake offered.
 * Use -Djavax.net.debug=ssl:handshake to see the named groups on the wire.
 * Args: keystorePath [clientNamedGroups comma list] [serverNamedGroups comma list]
 */
public class HybridTls {
    public static void main(String[] a) throws Exception {
        char[] pw = "changeit".toCharArray();
        KeyStore ks = KeyStore.getInstance("PKCS12");
        try (InputStream in = new FileInputStream(a[0])) { ks.load(in, pw); }
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(ks, pw);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        SSLContext ctx = SSLContext.getInstance("TLSv1.3");
        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

        SSLServerSocket server = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(0);
        server.setNeedClientAuth(false);
        if (a.length > 2 && !a[2].isEmpty()) {
            SSLParameters sp = server.getSSLParameters(); sp.setNamedGroups(a[2].split(",")); server.setSSLParameters(sp);
        }
        int port = server.getLocalPort();
        Thread t = new Thread(() -> {
            try (SSLSocket s = (SSLSocket) server.accept()) {
                while (s.getInputStream().read() != -1) { }   // read until the client closes
            } catch (Exception e) { System.out.println("server side: " + e); }
        });
        t.start();

        SSLSocket c = (SSLSocket) ctx.getSocketFactory().createSocket("localhost", port);
        if (a.length > 1 && !a[1].isEmpty()) {
            SSLParameters cp = c.getSSLParameters(); cp.setNamedGroups(a[1].split(",")); c.setSSLParameters(cp);
        }
        c.startHandshake();
        c.getOutputStream().write(1);
        System.out.println("java.version=" + System.getProperty("java.version"));
        System.out.println("protocol=" + c.getSession().getProtocol() + " cipher=" + c.getSession().getCipherSuite());
        c.close(); t.join(); server.close();
    }
}
