Open vbrandl opened 1 year ago
Firstly, use the "PKIX" KeyManager (resp. TrustManager) from "BCJSSE"; you can't mix the SunJSSE ones with the BCJSSE SSLContext.
Secondly, to use brainpool for your server cert with TLS 1.3 you have to enable the relevant signature scheme (e.g. "ecdsa_brainpoolP256r1tls13_sha256"), which is not enabled by default. See the system properties "jdk.tls.client.SignatureSchemes" and "jdk.tls.server.SignatureSchemes", or from JDK 19 you can use SSLParameters.setSignatureSchemes.
Enabling the curve i.e. NamedGroup.brainpoolP256r1tls13 is also a consideration, but that is enabled by default in BCJSSE.
Also try changing your java.util.logging API logging level down to FINEST to get more information from the server (and KeyManager) about the cipher suite selection process (which depends in turn on credentials selection).
I want to implement a TLS server and client that use a certificate with a
brainpoolP256r1
keypair.First here is how I generated the certificate:
Attached you can see my server and client code in
Server.java
andClient.java
respectively.I tried various variations of passing the Provider directly when creating the SSLContext and setting it in
java.security
like thisI tried both OpenJDK
11.0.19
and17.0.7
.From the exceptions below, I can see, the bouncycastle provider is actually used.
Server Side
Client Side
code
Server.java
Server.java
```java package org.example.tlsserver; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.security.KeyStore; import java.util.ArrayList; import java.util.List; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; public class Server { public static void main(String[] args) throws IOException { final short port = Short.parseShort(args[0]); final String keyStorePath = args[1]; final char[] keyStorePass = args.length < 3 ? "123456".toCharArray() : args[2].toCharArray(); InetSocketAddress address = new InetSocketAddress("0.0.0.0", port); startSingleThreaded(address, keyStorePath, keyStorePass); } public static void startSingleThreaded( InetSocketAddress address, final String keyStorePath, char[] keyStorePass) { System.out.println("Start single-threaded server at " + address); try (ServerSocket serverSocket = getServerSocket(address, keyStorePath, keyStorePass)) { java.nio.charset.Charset encoding = StandardCharsets.UTF_8; // This infinite loop is not CPU-intensive since method "accept" blocks // until a client has made a connection to the socket while (true) { try (java.net.Socket socket = serverSocket.accept(); // Use the socket to read the client's request BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), encoding)); // Writing to the output stream and then closing it sends // data to the client BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), encoding))) { getHeaderLines(reader).forEach(System.out::println); writer.write(getResponse()); writer.flush(); } catch (IOException e) { System.err.println("Exception while handling connection"); e.printStackTrace(); } } } catch (Exception e) { System.err.println("Could not create socket at " + address); e.printStackTrace(); } } private static ServerSocket getServerSocket( InetSocketAddress address, final String keyStore, final char[] keyStorePass) throws Exception { // Backlog is the maximum number of pending connections on the socket, // 0 means that an implementation-specific default is used int backlog = 0; Path keyStorePath = new File(keyStore).toPath(); // Bind the socket to the given port and address ServerSocket serverSocket = getSslContext(keyStorePath, keyStorePass) .getServerSocketFactory() .createServerSocket(address.getPort(), backlog, address.getAddress()); return serverSocket; } private static SSLContext getSslContext(Path keyStorePath, char[] keyStorePass) throws Exception { KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream(keyStorePath.toFile()), keyStorePass); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); keyManagerFactory.init(keyStore, keyStorePass); SSLContext sslContext = SSLContext.getInstance("TLSv1.3", new BouncyCastleJsseProvider(new BouncyCastleProvider())); // Null means using default implementations for TrustManager and SecureRandom sslContext.init(keyManagerFactory.getKeyManagers(), null, null); return sslContext; } private static String getResponse() { return "HTTP/1.1 404 not found\r\n\r\n"; } private static ListClient.java
Client.java
```java package org.example.mtls; import java.io.DataInputStream; import java.io.IOException; import java.net.URI; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import javax.net.ssl.SSLContext; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.config.TlsConfig; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; import org.apache.hc.client5.http.io.HttpClientConnectionManager; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; import org.apache.hc.client5.http.ssl.TrustAllStrategy; import org.apache.hc.core5.http.Header; import org.apache.hc.core5.http.ssl.TLS; import org.apache.hc.core5.ssl.SSLContextBuilder; import org.apache.hc.core5.util.Timeout; public final class Client { private static void usage() { System.err.println("Usage:"); System.err.println("\tjava -jar client.jar