diff --git a/core/pva/TLS.md b/core/pva/TLS.md index 3be3b0be21..7129a59cd6 100644 --- a/core/pva/TLS.md +++ b/core/pva/TLS.md @@ -60,14 +60,17 @@ they are compatible with generic open SSL tools: openssl pkcs12 -info -in KEYSTORE -nodes ``` +The essential commands are also in `make_tls_simple.sh` + Step 3: Configure and run the demo server ------- -Set environment variables to inform the server about its keystore. +Set environment variable `EPICS_PVAS_TLS_KEYCHAIN` to inform the server about its keystore. The format of this setting is `/path/to/file;password`. -Then run a demo server: +If you used `make_tls_simple.sh`, that would be `demo/KEYSTORE;changeit`. +Then run a demo server: ``` export EPICS_PVAS_TLS_KEYCHAIN="/path/to/KEYSTORE;changeit" @@ -78,7 +81,8 @@ java -cp target/classes org.epics.pva.server.ServerDemo Step 4: Configure and run the demo client ------- -Set environment variables to inform the client about its truststore. +Set environment variable `EPICS_PVA_TLS_KEYCHAIN` to inform the client about its truststore. +If you used `make_tls_simple.sh`, that would be `demo/TRUSTSTORE;changeit`. Then run a demo client (`-v 5` to see protocol detail): ``` @@ -87,6 +91,7 @@ java -cp target/classes org.epics.pva.client.PVAClientMain get -v 5 demo # Or: ./pvaclient get -v 5 demo ``` +On both the server and the client note how they mention "TLS" in their log messages. Logging ------- @@ -192,6 +197,7 @@ keytool -list -v -keystore ioc.p12 -storepass changeit We can now run the server with `EPICS_PVAS_TLS_KEYCHAIN=/path/to/ioc.p12;changeit` and clients with `EPICS_PVA_TLS_KEYCHAIN=/path/to/trust_ca.p12;changeit`. +See `make_tls_ca.sh` for a copy of the essential commands. You can create additional server files `ioc1.p12`, `ioc2.p12` and have each IOC use its own key pair. Clients will trust them without any changes to the `trust_ca.p12` as long as the IOC certificates are signed by your CA. @@ -237,6 +243,12 @@ We can now run the server with `EPICS_PVAS_TLS_KEYCHAIN=/path/to/ioc.p12;changei `EPICS_PVA_TLS_KEYCHAIN=/path/to/client.p12;changeit`. The server will identify the client as "Fred F.". +By default, the server supports clients with certificate and x509 authentication, +but client certificates are not required. +By setting `EPICS_PVAS_TLS_OPTIONS="client_cert=require"`, the server will +abort the initial TLS handshake for clients that do not have a certificate. + + In total, we now have the following: * `KEYSTORE`, `TRUSTSTORE`: @@ -276,7 +288,10 @@ In total, we now have the following: providing a client name for x509 authentication. Clients can set their `EPICS_PVA_TLS_KEYCHAIN` to this file to communicate with IOCs using x509 authentication. - + If the server runs with `EPICS_PVAS_TLS_OPTIONS="client_cert=require"`, + the clients MUST use a client certificate like `client.p12`. + Clients with just `trust_ca.p12` will fail during the initial TLS handshake. + * `myclient.cer`, `myclient.csr`: Intermediate files used to sign the client certificate. May be deleted. diff --git a/core/pva/make_tls_ca b/core/pva/make_tls_ca.sh similarity index 86% rename from core/pva/make_tls_ca rename to core/pva/make_tls_ca.sh index a616d83584..18a61aa070 100755 --- a/core/pva/make_tls_ca +++ b/core/pva/make_tls_ca.sh @@ -1,38 +1,42 @@ +# More elaborate example, see TLS.md "Use a Certification Authority" rm -rf demo mkdir demo cd demo +# Create our own CA, and make its public certificate available as `myca.cer`: keytool -genkeypair -alias myca -keystore ca.p12 -storepass changeit -dname "CN=myca" -keyalg RSA -ext BasicConstraints=ca:true keytool -list -v -keystore ca.p12 -storepass changeit keytool -exportcert -alias myca -keystore ca.p12 -storepass changeit -rfc -file myca.cer keytool -printcert -file myca.cer +# For clients, create a truststore that holds the public certificate of our CA keytool -importcert -alias myca -keystore trust_ca.p12 -storepass changeit -file myca.cer -noprompt keytool -list -v -keystore trust_ca.p12 -storepass changeit +# Now create a server keypair for use by the IOC: keytool -genkeypair -alias myioc -keystore ioc.p12 -storepass changeit -dname "CN=myioc" -keyalg RSA keytool -list -v -keystore ioc.p12 -storepass changeit +# Create signing request, sign with our CA, import signed cert into ioc.p12 keytool -certreq -alias myioc -keystore ioc.p12 -storepass changeit -file myioc.csr keytool -gencert -alias myca -keystore ca.p12 -storepass changeit -ext SubjectAlternativeName=DNS:myioc -ext KeyUsage=digitalSignature -ext ExtendedKeyUsage=serverAuth,clientAuth -infile myioc.csr -outfile myioc.cer keytool -printcert -file myioc.cer - keytool -importcert -alias myca -keystore ioc.p12 -storepass changeit -file myca.cer -noprompt keytool -importcert -alias myioc -keystore ioc.p12 -storepass changeit -file myioc.cer keytool -list -v -keystore ioc.p12 -storepass changeit +# Create client keypair so client can authenticate as "Fred F." keytool -genkeypair -alias myclient -keystore client.p12 -storepass changeit -dname "CN=Fred F." -keyalg RSA keytool -list -v -keystore client.p12 -storepass changeit +# Sign client certificate with our CA keytool -certreq -alias myclient -keystore client.p12 -storepass changeit -file myclient.csr keytool -gencert -alias myca -keystore ca.p12 -storepass changeit -ext SubjectAlternativeName=DNS:client -ext KeyUsage=digitalSignature -ext ExtendedKeyUsage=serverAuth,clientAuth -infile myclient.csr -outfile myclient.cer keytool -printcert -file myclient.cer - keytool -importcert -alias myca -keystore client.p12 -storepass changeit -file myca.cer -noprompt keytool -importcert -alias myclient -keystore client.p12 -storepass changeit -file myclient.cer keytool -list -v -keystore client.p12 -storepass changeit - echo "*************************************************************" echo "***************** trust_ca **********************************" echo "*************************************************************" diff --git a/core/pva/make_tls_simple b/core/pva/make_tls_simple.sh similarity index 82% rename from core/pva/make_tls_simple rename to core/pva/make_tls_simple.sh index 70beb3d8a4..29926cbf9d 100755 --- a/core/pva/make_tls_simple +++ b/core/pva/make_tls_simple.sh @@ -1,9 +1,16 @@ +# Minimal example, see TLS.md steps 1-4 + rm -rf demo mkdir demo cd demo + +# Creates a key pair for the server keytool -genkey -alias mykey -dname "CN=server" -keystore KEYSTORE -storepass changeit -keyalg RSA +# Export the public key keytool -export -alias mykey -keystore KEYSTORE -storepass changeit -rfc -file mykey.cer + +# Create a trust store for the client to make it aware of the server's public key keytool -import -alias mykey -file mykey.cer -keystore TRUSTSTORE -storepass changeit -noprompt echo "*************************************************************" diff --git a/core/pva/src/main/java/org/epics/pva/PVASettings.java b/core/pva/src/main/java/org/epics/pva/PVASettings.java index da6666b90c..0be6ad82bd 100644 --- a/core/pva/src/main/java/org/epics/pva/PVASettings.java +++ b/core/pva/src/main/java/org/epics/pva/PVASettings.java @@ -144,6 +144,24 @@ public class PVASettings */ public static String EPICS_PVAS_TLS_KEYCHAIN = ""; + /** Secure server options + * + *
client_cert=optional
:
+ * Default; clients can provide certificate for "X509" authentication,
+ * but may also use "ca" or "anonymous" authentication
+ * client_cert=require
:
+ * Clients must provide certificate for "X509" authentication.
+ * Socket with otherwise be closed during initial handshake.
+ * Server will log "SSLHandshakeException: Empty client certificate chain",
+ * client will log "SSLHandshakeException: Received fatal alert: bad_certificate"
+ *