Skip to content

Commit 69f2a0d

Browse files
authored
Merge pull request #3337 from ControlSystemStudio/spva_notes
Secure PVA info
2 parents dcc692c + e2aa50f commit 69f2a0d

File tree

3 files changed

+160
-16
lines changed

3 files changed

+160
-16
lines changed

core/pva/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ To debug connection issues on Linux, it can be helpful to disable the firewall:
9292

9393
To enable access to the first PVA server on a Linux host and list resulting settings:
9494

95+
# Depending on Linux release, similar to this..
96+
sudo firewall-cmd --add-port=5075/tcp
97+
sudo firewall-cmd --add-port=5076/udp
98+
99+
# .. or this
95100
sudo firewall-cmd --direct --add-rule ipv4 filter IN_public_allow 0 -m udp -p udp --dport 5076 -j ACCEPT
96101
sudo firewall-cmd --direct --add-rule ipv4 filter IN_public_allow 0 -m tcp -p tcp --dport 5075 -j ACCEPT
97102
sudo firewall-cmd --direct --get-rules ipv4 filter IN_public_allow

core/pva/TLS.md

Lines changed: 148 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,151 @@
1-
Secure Socket Support
2-
=====================
3-
4-
By default, the server and client will use plain TCP sockets to communicate.
5-
By configuring a keystore for the server and a truststore for the client,
6-
the communication can be switched to secure (TLS) sockets.
7-
The sockets are encrypted, and clients will only communicate with trusted servers.
8-
The following describes a minimal setup for initial tests,
9-
followed by a more elaborate setup later in this document.
1+
Secure PV Access
2+
================
3+
4+
By default, the PV Access server and client will use plain TCP sockets to communicate.
5+
Secure PV Access uses Transport Layer Security (TLS) sockets.
6+
TLS sockets, also known as secure sockets, are encrypted.
7+
Clients will only communicate with trusted servers, and servers can
8+
determine the identity of their clients in a trusted way.
9+
10+
Secure PV Access is under development for PVXS, the current C++ implementation
11+
of PV Access. This java implementation aims to be compatible with recent versions of PVXS.
12+
Secure PV Access is not supported in the original C++ (pvAccessCpp) and Java (pvAccessJava) implementations,
13+
but PVXS and this java library can still communicate with the original implementations
14+
using plain TCP sockets.
15+
16+
TLS relies on private and public encryption key pairs, where public keys are
17+
exchanged in the form of certificates.
18+
In a secure EPICS environment, the PV Access Certificate Management Service (pvacms)
19+
issues certificates for servers and clients and allows online checks of their
20+
validity.
21+
22+
23+
PV Access Certificate Management Service (pvacms)
24+
=================================================
25+
26+
An EPICS administrator needs to deploy `pvacms` as a service and maintain
27+
certificates for servers (IOCs) and clients (users running CS-Studio
28+
as well as IOCs reading from other IOCs).
29+
This is an example recipe for getting started.
30+
31+
1) Build EPICS base and PVXS as described on
32+
https://george-mcintyre.github.io/pvxs/spvaqstart.html
33+
34+
2) Start `pvacms -v`. It will create several files, including
35+
36+
* `~/.config/pva/1.3/admin.p12`: Certificate for the `admin` user
37+
38+
3) For an IOC, request a hybrid server and client certificate.
39+
Note its "Certificate identifier":
40+
41+
```
42+
$ authnstd --name ioc --cert-usage hybrid
43+
Keychain file created : /home/user/.config/pva/1.3/server.p12
44+
Certificate identifier : e53ed409:15273288300286014953
45+
```
46+
47+
As `admin`, accept that certificate:
48+
49+
```
50+
$ EPICS_PVA_TLS_KEYCHAIN=~/.config/pva/1.3/admin.p12 \
51+
pvxcert --approve e53ed409:15273288300286014953
52+
Approve ==> CERT:STATUS:e53ed409:15273288300286014953 ==> Completed Successfully
53+
```
54+
55+
* `~/.config/pva/1.3/server.p12`: Our server certificate (hybrid, for IOC)
56+
57+
4) Request a client certificate, note its identifier:
58+
59+
```
60+
$ authnstd
61+
Keychain file created : /home/user/.config/pva/1.3/client.p12
62+
Certificate identifier : e53ed409:11521018863975115478
63+
```
64+
65+
Accept that certificate:
66+
67+
```
68+
$ EPICS_PVA_TLS_KEYCHAIN=~/.config/pva/1.3/admin.p12 \
69+
pvxcert --approve e53ed409:11521018863975115478
70+
Approve ==> CERT:STATUS:e53ed409:11521018863975115478 ==> Completed Successfully
71+
```
72+
73+
* `~/.config/pva/1.3/client.p12`: Our client (user) certificate
74+
75+
76+
You now have a server and a client certificate.
77+
Example for checking the status:
78+
79+
```
80+
$ pvxcert -f ~/.config/pva/1.3/client.p12
81+
...
82+
Subject : CN=fred, C=US, O=host.site.org
83+
...
84+
Cert Expires : Wed Apr 16 18:08:58 2025 UTC
85+
...
86+
Certificate ID : e53ed409:11521018863975115478
87+
Status : VALID
88+
...
89+
```
90+
91+
To list certificate details:
92+
93+
```
94+
keytool -list -v -keystore ~/.config/pva/1.3/client.p12 -storepass ""
95+
```
96+
97+
For a test setup, all the above can be executed by a single user on one host.
98+
In a production setup, however, each human user should only have access to their own `client.p12` file.
99+
Pseudo-users running IOCs would have a `server.p12` file.
100+
Only an admin user on a designated host would have access to the remaining `pvacms` files,
101+
including the `admin.p12` file that permits accepting and revoking certificates.
102+
103+
104+
Secure IOC
105+
==========
106+
107+
Example for running a secure IOC:
108+
109+
```
110+
$ EPICS_PVAS_TLS_KEYCHAIN=~/.config/pva/1.3/server.p12 \
111+
softIocPVX -m user=fred -d pvxs/test/testioc.db
112+
```
113+
114+
The command `pvxsr 10` will list all connected clients
115+
with their connection credentials.
116+
117+
118+
Secure Java PVA Client
119+
======================
120+
121+
Example for running Java PVA client command line tool:
122+
123+
```
124+
$ export EPICS_PVA_TLS_KEYCHAIN=~/.config/pva/1.3/client.p12
125+
$ pvaclient monitor -v 5 fred:aiExample
126+
```
127+
128+
Example for running CS-Studio:
129+
130+
```
131+
$ export EPICS_PVA_TLS_KEYCHAIN=~/.config/pva/1.3/client.p12
132+
$ phoebus.sh
133+
```
134+
135+
136+
For more, refer to the PVXS documentation.
137+
138+
139+
--------------------------------------------------------
140+
141+
142+
Manually creating certificates
143+
==============================
144+
145+
In this section we describe an earlier approach to creating certificates.
146+
It is left for reference, the suggested approach is now based on `pvacms`.
147+
148+
We start with a minimal setup for initial tests.
10149

11150
Step 1: Create a server KEYSTORE that contains a public and private key.
12151
-------

core/pva/src/main/java/org/epics/pva/common/SecureSockets.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
import java.security.KeyStore;
1717
import java.util.logging.Level;
1818

19+
import javax.naming.ldap.LdapName;
20+
import javax.naming.ldap.Rdn;
1921
import javax.net.ssl.KeyManagerFactory;
2022
import javax.net.ssl.SSLContext;
2123
import javax.net.ssl.SSLServerSocket;
@@ -173,18 +175,16 @@ public static Socket createClientSocket(final InetSocketAddress address, final b
173175
/** Get name from local principal
174176
*
175177
* @param socket {@link SSLSocket} that may have local principal
176-
* @return Name (without "CN=..") or <code>null</code> if socket has certificate to authenticate
178+
* @return Name (without "CN=..") if socket has certificate to authenticate or <code>null</code>
177179
*/
178180
public static String getLocalPrincipalName(final SSLSocket socket)
179181
{
180182
try
181183
{
182-
String name = socket.getSession().getLocalPrincipal().getName();
183-
if (name.startsWith("CN="))
184-
name = name.substring(3);
185-
else
186-
logger.log(Level.WARNING, "Client has principal '" + name + "', expected 'CN=...'");
187-
return name;
184+
final LdapName ldn = new LdapName(socket.getSession().getLocalPrincipal().getName());
185+
for (Rdn rdn : ldn.getRdns())
186+
if (rdn.getType().equals("CN"))
187+
return (String) rdn.getValue();
188188
}
189189
catch (Exception ex)
190190
{ // May not have certificate with name

0 commit comments

Comments
 (0)