Skip to content

Commit 69311b6

Browse files
committed
Update RTMPS document and adjust code for pathing
1 parent c528168 commit 69311b6

File tree

6 files changed

+347
-86
lines changed

6 files changed

+347
-86
lines changed

RTMPS.md

Lines changed: 214 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,190 @@
22

33
RTMPS is a secure version of RTMP that uses TLS/SSL to encrypt the data. This is a guide to setting up RTMPS with Red5. An example keystore and truststore creation process will be explained as these files are required for the RTMPS feature. Examples will be provided for both the server and client side which will demonstrate how to use RTMPS and PKCS12 type keystores; JKS keystores can also be used, but are not covered here.
44

5-
## Configuration
5+
## Keystore and Truststore Creation
66

7-
### Server
7+
The following commands will create the necessary files for the RTMPS feature. The keystore will contain the server certificate and private key, while the truststore will contain the CA certificate. The client will use the truststore to verify the server certificate. Self-signed certificates are used in this example and are not expected to prevent the client from connecting to the server; in testing, the `ffplay` worked without issue. Examples show sample input for the certificate creation process.
88

9-
On a server where RTMPS will be employed, two files in `conf` must be updated: `red5.properties` and `red5-core.xml`. This is in-addition to the keystore and truststore proceedure.
9+
* Create our CA key and certificate for self-signing:
1010

11-
* In `red5-core.xml` uncomment the beans named `rtmpsMinaIoHandler` and `rtmpsTransport` which may be updated as required, otherwise their values come from the `red5.properties` file. See [Advanced-configuration](#advanced-configuration) for more information.
11+
```bash
12+
openssl ecparam -name prime256v1 -genkeopenssl ecparam -name prime256v1 -genkey -noout -out ca.key
1213

13-
* In `red5.properties`, update these properties to utilize your values; especially for store passwords and locations:
14+
openssl req -new -x509 -sha256 -key ca.key -out ca.crt -days 3650
1415

15-
```properties
16-
# RTMPS
17-
rtmps.host=0.0.0.0
18-
rtmps.port=8443
19-
rtmps.ping_interval=5000
20-
rtmps.max_inactivity=60000
21-
rtmps.max_keep_alive_requests=-1
22-
rtmps.max_threads=8
23-
rtmps.acceptor_thread_count=2
24-
rtmps.processor_cache=20
25-
# RTMPS Key and Trust store parameters
26-
rtmps.keystorepass=password123
27-
rtmps.keystorefile=conf/server.p12
28-
rtmps.truststorepass=password123
29-
rtmps.truststorefile=conf/truststore.p12
16+
You are about to be asked to enter information that will be incorporated
17+
into your certificate request.
18+
What you are about to enter is what is called a Distinguished Name or a DN.
19+
There are quite a few fields but you can leave some blank
20+
For some fields there will be a default value,
21+
If you enter '.', the field will be left blank.
22+
-----
23+
Country Name (2 letter code) [AU]:US
24+
State or Province Name (full name) [Some-State]:Nevada
25+
Locality Name (eg, city) []:Henderson
26+
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Red5
27+
Organizational Unit Name (eg, section) []:dev
28+
Common Name (e.g. server FQDN or YOUR name) []:Paul Gregoire
29+
Email Address []:[email protected]
3030
```
3131

32-
### Client
32+
* Create the server key and certificate request:
3333

34+
```bash
35+
openssl ecparam -name prime256v1 -genkey -noout -out server.key
3436

35-
```java
36-
TLSFactory.setKeystorePath("/workspace/client/conf/rtmps_server.p12");
37-
TLSFactory.setTruststorePath("/workspace/client/conf/rtmps_truststore.p12");
37+
openssl req -new -sha256 -key server.key -out server.csr
38+
39+
You are about to be asked to enter information that will be incorporated
40+
into your certificate request.
41+
What you are about to enter is what is called a Distinguished Name or a DN.
42+
There are quite a few fields but you can leave some blank
43+
For some fields there will be a default value,
44+
If you enter '.', the field will be left blank.
45+
-----
46+
Country Name (2 letter code) [AU]:US
47+
State or Province Name (full name) [Some-State]:Nevada
48+
Locality Name (eg, city) []:Henderson
49+
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Red5
50+
Organizational Unit Name (eg, section) []:dev
51+
Common Name (e.g. server FQDN or YOUR name) []:mondain-XPS-8930
52+
Email Address []:[email protected]
53+
54+
Please enter the following 'extra' attributes
55+
to be sent with your certificate request
56+
A challenge password []:
57+
An optional company name []:
3858
```
3959

40-
## Testing
60+
* CA sign the server certificate request:
4161

42-
Using ffplay issue the following, update for your server IP and stream name as needed: `ffplay rtmps://localhost:8443/live/stream1`
62+
```bash
63+
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650
4364

65+
Certificate request self-signature ok
66+
subject=C = US, ST = Nevada, L = Henderson, O = Red5, OU = dev, CN = mondain-XPS-8930, emailAddress = [email protected]
67+
```
4468

45-
### Useful System Properties
69+
* Create the client key and certificate request:
70+
71+
```bash
72+
openssl ecparam -name prime256v1 -genkey -noout -out client.key
73+
74+
openssl req -new -sha256 -key client.key -out client.csr
75+
76+
You are about to be asked to enter information that will be incorporated
77+
into your certificate request.
78+
What you are about to enter is what is called a Distinguished Name or a DN.
79+
There are quite a few fields but you can leave some blank
80+
For some fields there will be a default value,
81+
If you enter '.', the field will be left blank.
82+
-----
83+
Country Name (2 letter code) [AU]:US
84+
State or Province Name (full name) [Some-State]:Nevada
85+
Locality Name (eg, city) []:Henderson
86+
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Red5
87+
Organizational Unit Name (eg, section) []:dev
88+
Common Name (e.g. server FQDN or YOUR name) []:mondain-XPS-8930
89+
Email Address []:[email protected]
90+
91+
Please enter the following 'extra' attributes
92+
to be sent with your certificate request
93+
A challenge password []:
94+
An optional company name []:
95+
```
96+
97+
* CA sign the client certificate request:
98+
99+
```bash
100+
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650
101+
102+
Certificate request self-signature ok
103+
subject=C = US, ST = Nevada, L = Henderson, O = Red5, OU = dev, CN = mondain-XPS-8930, emailAddress = [email protected]
104+
```
105+
106+
* Add the server certificate to the keystore (_Make sure to use the same password for the key and store_):
107+
108+
```bash
109+
keytool -genkey -dname "CN=mondain-XPS-8930, OU=dev, O=Red5, L=Henderson, S=Nevada, C=US" -keystore rtmps_keystore.jks -storepass password123 -keypass password123 -alias server -keyalg RSA -file server.crt
110+
111+
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 90 days
112+
for: CN=mondain-XPS-8930, OU=dev, O=Red5, L=Henderson, ST=Nevada, C=US
113+
```
114+
115+
* Add the self-signed CA root certificate to the truststore (_Make sure to use the same password for the store_):
116+
117+
```bash
118+
keytool -import -trustcacerts -file ca.crt -alias CARoot -keystore rtmps_truststore.jks -storepass password123
119+
120+
Owner: [email protected], CN=Paul Gregoire, OU=dev, O=Red5, L=Henderson, ST=Nevada, C=US
121+
Issuer: [email protected], CN=Paul Gregoire, OU=dev, O=Red5, L=Henderson, ST=Nevada, C=US
122+
Serial number: 7139dce6b44a5e3d50ace573849cf88e63366153
123+
Valid from: Mon Mar 04 18:10:14 PST 2024 until: Thu Mar 02 18:10:14 PST 2034
124+
Certificate fingerprints:
125+
SHA1: 48:CC:8A:65:5B:96:5B:7B:39:6C:55:27:30:84:24:B8:67:B0:91:6A
126+
SHA256: C0:41:37:4C:DB:49:12:6B:14:C5:B4:8E:4A:28:1C:33:A0:C2:38:C7:76:44:97:6B:5E:A0:7B:20:01:0F:C9:2C
127+
Signature algorithm name: SHA256withECDSA
128+
Subject Public Key Algorithm: 256-bit EC (secp256r1) key
129+
Version: 3
130+
131+
Extensions:
132+
133+
#1: ObjectId: 2.5.29.35 Criticality=false
134+
AuthorityKeyIdentifier [
135+
KeyIdentifier [
136+
0000: FF 05 5E DA 39 EB B5 40 E2 0D 5F 6A 90 DC C3 0B ..^.9..@.._j....
137+
0010: 12 B2 6D F6 ..m.
138+
]
139+
]
140+
141+
#2: ObjectId: 2.5.29.19 Criticality=true
142+
BasicConstraints:[
143+
CA:true
144+
PathLen: no limit
145+
]
146+
147+
#3: ObjectId: 2.5.29.14 Criticality=false
148+
SubjectKeyIdentifier [
149+
KeyIdentifier [
150+
0000: FF 05 5E DA 39 EB B5 40 E2 0D 5F 6A 90 DC C3 0B ..^.9..@.._j....
151+
0010: 12 B2 6D F6 ..m.
152+
]
153+
]
154+
155+
Trust this certificate? [no]: yes
156+
Certificate was added to keystore
157+
```
158+
159+
* Last step is to convert the keystore and truststore to PKCS12 format (_Make sure to use the same passwords_):
160+
161+
```bash
162+
163+
keytool -importkeystore -srckeystore rtmps_keystore.jks -destkeystore rtmps_keystore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password123 -deststorepass password123 -srcalias server -destalias server -noprompt
164+
165+
keytool -importkeystore -srckeystore rtmps_truststore.jks -destkeystore rtmps_truststore.p12 -srcstoretype JKS -deststoretype PKCS12 -srcstorepass password123 -deststorepass password123
166+
```
167+
168+
## Configuration
169+
170+
The following configuration changes are required to enable RTMPS in Red5.
46171

172+
### Server
173+
174+
On a server where RTMPS will be employed, two files in `conf` must be updated: `red5.properties` and `red5-core.xml`. This is in-addition to the keystore and truststore proceedure.
47175

48-
`-Djavax.net.debug=SSL,handshake,verbose,trustmanager,keymanager,record,plaintext`
176+
* In `red5-core.xml` uncomment the beans named `rtmpsMinaIoHandler` and `rtmpsTransport` which may be updated as required, otherwise their values come from the `red5.properties` file.
49177

50-
## Advanced configuration
178+
```xml
179+
<bean id="rtmpsMinaIoHandler" class="org.red5.server.net.rtmps.RTMPSMinaIoHandler">
180+
<property name="handler" ref="rtmpHandler" />
181+
<property name="keystorePassword" value="${rtmps.keystorepass}" />
182+
<property name="keystoreFile" value="${rtmps.keystorefile}" />
183+
<property name="truststorePassword" value="${rtmps.truststorepass}" />
184+
<property name="truststoreFile" value="${rtmps.truststorefile}" />
185+
</bean>
186+
```
51187

52-
* The ciphers and protocols can be modified in the `rtmpsMinaIoHandler` bean in `red5-core.xml` to suit any special needs.
188+
To modify the ciphers and / or protocols in the `rtmpsMinaIoHandler` bean in `red5-core.xml`, see the example below:
53189

54190
```xml
55191
<bean id="rtmpsMinaIoHandler" class="org.red5.server.net.rtmps.RTMPSMinaIoHandler">
@@ -72,3 +208,51 @@ Using ffplay issue the following, update for your server IP and stream name as n
72208
</property>
73209
</bean>
74210
```
211+
212+
* In `red5.properties`, update these properties to utilize your values; especially for store passwords and locations:
213+
214+
```properties
215+
# RTMPS
216+
rtmps.host=0.0.0.0
217+
rtmps.port=8443
218+
rtmps.ping_interval=5000
219+
rtmps.max_inactivity=60000
220+
rtmps.max_keep_alive_requests=-1
221+
rtmps.max_threads=8
222+
rtmps.acceptor_thread_count=2
223+
rtmps.processor_cache=20
224+
# RTMPS Key and Trust store parameters
225+
rtmps.keystorepass=password123
226+
rtmps.keystorefile=conf/rtmps_keystore.p12
227+
rtmps.truststorepass=password123
228+
rtmps.truststorefile=conf/rtmps_truststore.p12
229+
```
230+
231+
### Client
232+
233+
When connecting to a server that uses RTMPS, the client must have the server's certificate in its truststore. The following example demonstrates how to use the truststore with the Red5 client. Before connecting to the server, the client must set the keystore and truststore paths with password.
234+
235+
* Using full paths to the keystore and truststore files:
236+
237+
```java
238+
TLSFactory.setKeystorePath("/workspace/client/conf/rtmps_keystore.p12");
239+
TLSFactory.setTruststorePath("/workspace/client/conf/rtmps_truststore.p12");
240+
```
241+
242+
* When the keystore and truststore are contained within a jar file, use the following format: `jar:file:/path/to/your.jar!/path/to/file/in/jar` for the keystore and truststore paths. This example assumes the jar file which is named `my_rtmps_client.jar` file is contained in a `lib` sub-directory of the application client launch location and the keystore and truststore are in the root:
243+
244+
```java
245+
String jarKeystorePath = String.format("jar:file:%s/lib/my_rtmps_client.jar!/rtmps_%s.p12", Paths.get(System.getProperty("user.dir"), "keystore");
246+
TLSFactory.setKeystorePath(jarKeystorePath);
247+
String jarTruststorePath = String.format("jar:file:%s/lib/my_rtmps_client.jar!/rtmps_%s.p12", Paths.get(System.getProperty("user.dir"), "truststore");
248+
TLSFactory.setTruststorePath(jarTruststorePath);
249+
```
250+
251+
## Testing
252+
253+
Using ffplay to test playback, issue the following, but make sure to update the command for your server IP and stream name: `ffplay rtmps://localhost:8443/live/stream1` (this assumes a stream named `stream1` is being published already).
254+
255+
### Useful System Properties
256+
257+
* To enable SSL debugging, add the following system property to the JVM: `-Djavax.net.debug=SSL`
258+
* To enable more detailed SSL debugging, add the following system property to the JVM: `-Djavax.net.debug=SSL,handshake,verbose,trustmanager,keymanager,record,plaintext`

client/src/main/java/org/red5/client/net/rtmps/RTMPSClient.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77

88
package org.red5.client.net.rtmps;
99

10+
import java.io.IOException;
11+
import java.io.InputStream;
1012
import java.net.InetSocketAddress;
13+
import java.net.URI;
14+
import java.nio.file.Files;
15+
import java.nio.file.Paths;
1116

1217
import javax.net.ssl.SSLContext;
1318

@@ -50,6 +55,11 @@ public class RTMPSClient extends RTMPClient {
5055
*/
5156
private char[] password = "password123".toCharArray();
5257

58+
/**
59+
* Path to the keystore and truststore files.
60+
*/
61+
private InputStream keystoreStream, truststoreStream;
62+
5363
/**
5464
* The keystore type, valid options are JKS and PKCS12
5565
*/
@@ -87,6 +97,26 @@ public RTMPSClient(String keyStoreType, String password) {
8797
ioHandler.setHandler(this);
8898
}
8999

100+
/**
101+
* Creates a new RTMPSClient with the given keystore type, password, and paths to store files. If the stores
102+
* are inside a jar file, use the following format: jar:file:/path/to/your.jar!/path/to/file/in/jar
103+
*
104+
* @param keyStoreType keystore type
105+
* @param password keystore password
106+
* @param keystorePath path to keystore file
107+
* @param truststorePath path to truststore file
108+
* @throws IOException
109+
*/
110+
public RTMPSClient(String keyStoreType, String password, String keystorePath, String truststorePath) throws IOException {
111+
protocol = "rtmps";
112+
this.keyStoreType = keyStoreType;
113+
this.password = password.toCharArray();
114+
this.keystoreStream = Files.newInputStream(Paths.get(URI.create(keystorePath)));
115+
this.truststoreStream = Files.newInputStream(Paths.get(URI.create(truststorePath)));
116+
ioHandler = new RTMPSClientIoHandler();
117+
ioHandler.setHandler(this);
118+
}
119+
90120
@SuppressWarnings({ "rawtypes" })
91121
@Override
92122
protected void startConnector(String server, int port) {
@@ -141,8 +171,13 @@ private class RTMPSClientIoHandler extends RTMPMinaIoHandler {
141171
@Override
142172
public void sessionOpened(IoSession session) throws Exception {
143173
log.debug("RTMPS sessionOpened: {}", session);
144-
// do tls stuff
145-
SSLContext context = TLSFactory.getTLSContext(keyStoreType, password);
174+
// if we're using a input streams, pass them to the ctor
175+
SSLContext context = null;
176+
if (keystoreStream != null && truststoreStream != null) {
177+
context = TLSFactory.getTLSContext(keyStoreType, password, keystoreStream, password, truststoreStream);
178+
} else {
179+
context = TLSFactory.getTLSContext(keyStoreType, password);
180+
}
146181
SslFilter sslFilter = new SslFilter(context);
147182
if (sslFilter != null) {
148183
// we are a client

0 commit comments

Comments
 (0)