Add pem-api module: PEMDecoder/PEMEncoder (JEP 538 preview on JDK 27, JEP 542 final in JDK 28) for JWT keys, TLS, encrypted keys and BouncyCastle migration
Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01CifR2BE7PBvRy5hT8TS9oz
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import com.sun.net.httpserver.HttpsConfigurator;
|
||||
import com.sun.net.httpserver.HttpsServer;
|
||||
import java.io.EOFException;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.*;
|
||||
|
||||
/** Build an SSLContext from three PEM files and talk to ourselves over TLS. */
|
||||
public class TlsFromPem {
|
||||
static List<Certificate> readAll(String pemText) throws Exception {
|
||||
List<Certificate> out = new ArrayList<>();
|
||||
try (InputStream in = new java.io.ByteArrayInputStream(pemText.getBytes())) {
|
||||
PEMDecoder d = PEMDecoder.of();
|
||||
while (true) {
|
||||
try { out.add(d.decode(in, X509Certificate.class)); }
|
||||
catch (EOFException end) { break; }
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
PEMDecoder d = PEMDecoder.of();
|
||||
|
||||
Fx.h("read a two-certificate chain file");
|
||||
List<Certificate> chain = readAll(Fx.read("server-chain.pem"));
|
||||
for (Certificate c : chain) System.out.println(" " + ((X509Certificate) c).getSubjectX500Principal());
|
||||
Fx.check(chain.size() == 2, "the stream decoder returns the two certificates one by one");
|
||||
|
||||
Fx.h("server side: key + chain -> KeyStore -> KeyManagerFactory -> SSLContext");
|
||||
PrivateKey key = d.decode(Fx.read("server-key.pem"), PrivateKey.class);
|
||||
char[] pw = new char[0];
|
||||
KeyStore ks = KeyStore.getInstance("PKCS12");
|
||||
ks.load(null, null);
|
||||
ks.setKeyEntry("server", key, pw, chain.toArray(new Certificate[0]));
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(ks, pw);
|
||||
SSLContext serverCtx = SSLContext.getInstance("TLS");
|
||||
serverCtx.init(kmf.getKeyManagers(), null, null);
|
||||
|
||||
HttpsServer server = HttpsServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
|
||||
server.setHttpsConfigurator(new HttpsConfigurator(serverCtx));
|
||||
server.createContext("/", ex -> {
|
||||
byte[] body = "hello over TLS\n".getBytes();
|
||||
ex.sendResponseHeaders(200, body.length);
|
||||
ex.getResponseBody().write(body);
|
||||
ex.close();
|
||||
});
|
||||
server.start();
|
||||
URI uri = URI.create("https://localhost:" + server.getAddress().getPort() + "/");
|
||||
|
||||
try {
|
||||
Fx.h("client trusting only the CA certificate from ca.pem");
|
||||
KeyStore ts = KeyStore.getInstance("PKCS12");
|
||||
ts.load(null, null);
|
||||
ts.setCertificateEntry("ca", d.decode(Fx.read("ca.pem"), X509Certificate.class));
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(ts);
|
||||
SSLContext clientCtx = SSLContext.getInstance("TLS");
|
||||
clientCtx.init(null, tmf.getTrustManagers(), null);
|
||||
HttpClient trusting = HttpClient.newBuilder().sslContext(clientCtx).build();
|
||||
HttpResponse<String> r = trusting.send(HttpRequest.newBuilder(uri).build(), HttpResponse.BodyHandlers.ofString());
|
||||
System.out.println("HTTP " + r.statusCode() + " " + r.body().strip() + " (" + r.sslSession().get().getProtocol() + ")");
|
||||
System.out.println("server presented: " + ((X509Certificate) r.sslSession().get().getPeerCertificates()[0]).getSubjectX500Principal());
|
||||
Fx.check(r.statusCode() == 200, "request over TLS succeeds");
|
||||
|
||||
Fx.h("same request with the JVM's default trust store (the CA is not in it)");
|
||||
try {
|
||||
HttpClient.newHttpClient().send(HttpRequest.newBuilder(uri).build(), HttpResponse.BodyHandlers.ofString());
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
} finally {
|
||||
server.stop(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user