diff --git a/.gitignore b/.gitignore index 0b4d90a..8f61835 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules .next yarn-error.log dist -assets \ No newline at end of file +assets +.yarnrc.yml \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..5edcff0 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v16 \ No newline at end of file diff --git a/README.md b/README.md index 55b5d75..5a46853 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ If you notice any outdated, missing, or errant docs, pull requests are strongly Documentation for each technology lives in its corresponding directory in the [docs/](docs/) folder. -To get rolling on local development, clone this repository and start the local dev server: +To get rolling on local development, clone this repository, have yarn ready (`yarn set version classic` if you have yarn 3 installed) +and use Node 16 (`nvm use`) and start the local dev server: ``` $ yarn install diff --git a/docs/java/config.yaml b/docs/java/config.yaml new file mode 100644 index 0000000..a3796d4 --- /dev/null +++ b/docs/java/config.yaml @@ -0,0 +1,12 @@ +name: Java +protocol: https +server_port: 443 +topics: + client: + links: + - text: Java Key Store format + url: https://docs.oracle.com/cd/E19509-01/820-3503/ggfen/index.html + - text: "PKCS #12" + url: https://en.wikipedia.org/wiki/PKCS_12 + - text: Introduction to the Java HTTP Client + url: https://openjdk.org/groups/net/httpclient/intro.html diff --git a/docs/java/logo.png b/docs/java/logo.png new file mode 100644 index 0000000..43dd906 Binary files /dev/null and b/docs/java/logo.png differ diff --git a/docs/java/topics/client.md b/docs/java/topics/client.md new file mode 100644 index 0000000..223da36 --- /dev/null +++ b/docs/java/topics/client.md @@ -0,0 +1,56 @@ +This example assumes only Java 11 or newer and does not require any libraries. + +There are multiple ways to convert certificate, private key and root CA certificate to a format that java can digest. +Java works with "key stores" which can be in the (java proprietary) `JKS` or `PKCS #12` format (among others), +and can also be created at runtime. But here we will use only `step` and a minimal amount of code. + +Trust store and key store can also be configured on a JVM level, but on the client we probably want to configure +them on a per-connection basis, so this is what we will do here. + +Make sure to set a password for trust and key store in the next steps: + +1. Package the root CA certificate: `step certificate p12 truststore.p12 --ca {{ ca_cert }}` +2. Package certificate and key: `step certificate p12 keystore.p12 {{ client_cert }} {{ client_key }} --ca {{ ca_cert }}` + +You can now put these files on your classpath or read them from the file system: + +```java +// imports omitted + +public class HelloMtlsClient { + public static void main(String[] args) throws Exception { + var keyStore = KeyStore.getInstance("PKCS12"); + var trustStore = KeyStore.getInstance("PKCS12"); + var keyStorePassword = "changeit"; + var trustStorePassword = "changeit"; + + try (var keystoreFile = Files.newInputStream(Path.of("keystore.p12")); + var truststoreFile = Files.newInputStream(Path.of("truststore.p12"))) { + keyStore.load(keystoreFile, keyStorePassword.toCharArray()); + trustStore.load(truststoreFile, trustStorePassword.toCharArray()); + } + + var keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManager.init(keyStore, keyStorePassword.toCharArray()); + + var trustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + trustManager.init(trustStore); + + var sslContext = SSLContext.getInstance("TLSv1.3"); + sslContext.init(keyManager.getKeyManagers(), trustManager.getTrustManagers(), null); + + SSLParameters sslParameters = new SSLParameters(); + sslParameters.setNeedClientAuth(true); + + var httpClient = HttpClient.newBuilder() + .sslContext(sslContext) + .sslParameters(sslParameters) + .build(); + + var request = HttpRequest.newBuilder(URI.create("https://{{ server_name }}:{{ server_port }}")).GET().build(); + var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + // Do something with the response + } +} +``` diff --git a/package.json b/package.json index 9d61722..eebe115 100644 --- a/package.json +++ b/package.json @@ -42,5 +42,6 @@ "peerDependencies": { "react": "^16.9.0", "react-dom": "^16.9.0" - } + }, + "packageManager": "yarn@1.22.19" }