Skip to content

Commit 837b784

Browse files
authored
Feat: add support for TLSv1.3 (#447)
Signed-off-by: Tero Saarni <[email protected]>
1 parent 01648ba commit 837b784

File tree

13 files changed

+124
-29
lines changed

13 files changed

+124
-29
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 6.3.0
2+
- Added support for TLSv1.3. [#447](https://github.com/logstash-plugins/logstash-input-beats/pull/447)
3+
14
## 6.2.6
25
- Update guidance regarding the private key format and encoding [#445](https://github.com/logstash-plugins/logstash-input-beats/pull/445)
36

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6.2.6
1+
6.3.0

docs/index.asciidoc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,10 @@ Flag to determine whether to add `host` field to event using the value supplied
199199
===== `cipher_suites`
200200

201201
* Value type is <<array,array>>
202-
* Default value is `java.lang.String[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256]@459cfcca`
202+
* Default value is `java.lang.String[TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256]@459cfcca`
203203

204204
The list of ciphers suite to use, listed by priorities.
205+
The default values applies for OpenJDK 11.0.14 and higher, for older versions the list does not include suites not supported by the JDK, such as the ChaCha20 family of ciphers.
205206

206207
[id="plugins-{type}s-{plugin}-client_inactivity_timeout"]
207208
===== `client_inactivity_timeout`
@@ -360,10 +361,10 @@ This option is only valid when `ssl_verify_mode` is set to `peer` or `force_peer
360361
===== `tls_max_version`
361362

362363
* Value type is <<number,number>>
363-
* Default value is `1.2`
364+
* Default value is `1.3`
364365

365366
The maximum TLS version allowed for the encrypted connections. The value must be the one of the following:
366-
1.0 for TLS 1.0, 1.1 for TLS 1.1, 1.2 for TLS 1.2
367+
1.0 for TLS 1.0, 1.1 for TLS 1.1, 1.2 for TLS 1.2, 1.3 for TLS 1.3
367368

368369
[id="plugins-{type}s-{plugin}-tls_min_version"]
369370
===== `tls_min_version`
@@ -372,12 +373,11 @@ The maximum TLS version allowed for the encrypted connections. The value must be
372373
* Default value is `1`
373374

374375
The minimum TLS version allowed for the encrypted connections. The value must be one of the following:
375-
1.0 for TLS 1.0, 1.1 for TLS 1.1, 1.2 for TLS 1.2
376+
1.0 for TLS 1.0, 1.1 for TLS 1.1, 1.2 for TLS 1.2, 1.3 for TLS 1.3
376377

377378

378379

379380
[id="plugins-{type}s-{plugin}-common-options"]
380381
include::{include_path}/{type}.asciidoc[]
381382

382383
:default_codec!:
383-

lib/logstash/inputs/beats/tls.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ def <=>(other)
1818
TLS_PROTOCOL_OPTIONS = [
1919
TLSOption.new("TLSv1", 1),
2020
TLSOption.new("TLSv1.1", 1.1),
21-
TLSOption.new("TLSv1.2", 1.2)
21+
TLSOption.new("TLSv1.2", 1.2),
22+
TLSOption.new("TLSv1.3", 1.3)
2223
]
2324

2425
def self.min

lib/tasks/test.rake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ VENDOR_PATH = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "ve
44

55
#TODO: Figure out better means to keep this version in sync
66
if OS_PLATFORM == "linux"
7-
FILEBEAT_URL = "https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.5.4-linux-x86_64.tar.gz"
7+
FILEBEAT_URL = "https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.6.0-linux-x86_64.tar.gz"
88
elsif OS_PLATFORM == "darwin"
9-
FILEBEAT_URL = "https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.5.4-darwin-x86_64.tar.gz"
9+
FILEBEAT_URL = "https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.6.0-darwin-x86_64.tar.gz"
1010
end
1111

1212
LSF_URL = "https://download.elastic.co/logstash-forwarder/binaries/logstash-forwarder_#{OS_PLATFORM}_amd64"

spec/inputs/beats/tls_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
end
1111

1212
it "returns the maximum supported tls" do
13-
expect(subject.max.version).to eq(1.2)
14-
expect(subject.max.name).to eq("TLSv1.2")
13+
expect(subject.max.version).to eq(1.3)
14+
expect(subject.max.name).to eq("TLSv1.3")
1515
end
1616

1717
describe ".get_supported" do

spec/integration/filebeat_spec.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
let(:filebeat_config) do
3838
{
3939
"filebeat" => {
40-
"prospectors" => [{ "paths" => [log_file], "type" => "log" }],
40+
"inputs" => [{ "paths" => [log_file], "type" => "log" }],
4141
"scan_frequency" => "1s"
4242
},
4343
"output" => {
@@ -174,6 +174,34 @@
174174
end
175175
end
176176

177+
context "with TLSv1.3 client" do
178+
let(:filebeat_config) do
179+
super().merge({
180+
"output" => {
181+
"logstash" => {
182+
"hosts" => ["#{host}:#{port}"],
183+
"ssl" => {
184+
"certificate_authorities" => certificate_authorities,
185+
"versions" => ["TLSv1.3"],
186+
}
187+
}
188+
},
189+
"logging" => { "level" => "debug" }
190+
})
191+
end
192+
include_examples "send events"
193+
194+
context "when TLSv1.3 enforced in plugin" do
195+
let(:input_config) {
196+
super().merge({
197+
"tls_min_version" => "1.3"
198+
})
199+
}
200+
201+
include_examples "send events"
202+
end
203+
end
204+
177205
# Refactor this to use Flores's PKI instead of openssl command line
178206
# see: https://github.com/jordansissel/ruby-flores/issues/7
179207
context "with a passphrase" do

spec/support/file_helpers.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def self.included(base)
1919
end
2020

2121
def write_to_tmp_file(content)
22-
file = Stud::Temporary.file
22+
file = Stud::Temporary.file("test-logstash-input-beats", "w+", 0600)
2323
file.write(content.to_s)
2424
file.close
2525
file.path

src/main/java/org/logstash/beats/Runner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static public void main(String[] args) throws Exception {
3333

3434

3535
SslContextBuilder sslBuilder = new SslContextBuilder(sslCertificate, sslKey, null)
36-
.setProtocols(new String[] { "TLSv1.2" })
36+
.setProtocols(new String[] { "TLSv1.2", "TLSv1.3" })
3737
.setCertificateAuthorities(certificateAuthorities);
3838
SslHandlerProvider sslHandlerProvider = new SslHandlerProvider(sslBuilder.buildContext(), 10000);
3939
server.setSslHandlerProvider(sslHandlerProvider);

src/main/java/org/logstash/netty/SslContextBuilder.java

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import java.security.cert.X509Certificate;
2020
import java.util.ArrayList;
2121
import java.util.Arrays;
22+
import java.util.HashSet;
2223
import java.util.List;
24+
import java.util.Set;
2325

2426
/**
2527
* Created by ph on 2016-05-27.
@@ -38,22 +40,36 @@ public enum SslClientVerifyMode {
3840
private File sslCertificateFile;
3941
private SslClientVerifyMode verifyMode = SslClientVerifyMode.FORCE_PEER;
4042

41-
private long handshakeTimeoutMilliseconds = 10000;
43+
static final Set<String> SUPPORTED_CIPHERS = new HashSet<>(Arrays.asList(
44+
((SSLServerSocketFactory) SSLServerSocketFactory.getDefault()).getSupportedCipherSuites()
45+
));
4246

4347
/*
4448
Mordern Ciphers List from
4549
https://wiki.mozilla.org/Security/Server_Side_TLS
4650
*/
47-
private final static String[] DEFAULT_CIPHERS = new String[] {
51+
private final static String[] DEFAULT_CIPHERS;
52+
static {
53+
String[] defaultCipherCandidates = new String[] {
54+
// Modern compatibility
55+
"TLS_AES_128_GCM_SHA256", // TLS 1.3
56+
"TLS_AES_256_GCM_SHA384", // TLS 1.3
57+
"TLS_CHACHA20_POLY1305_SHA256", // TLS 1.3 (since Java 11.0.14)
58+
// Intermediate compatibility
4859
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
4960
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
61+
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", // (since Java 11.0.14)
62+
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", // (since Java 11.0.14)
5063
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
5164
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
65+
// Backward compatibility
5266
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
5367
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
5468
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
5569
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
56-
};
70+
};
71+
DEFAULT_CIPHERS = Arrays.stream(defaultCipherCandidates).filter(SUPPORTED_CIPHERS::contains).toArray(String[]::new);
72+
}
5773

5874
/*
5975
Reduced set of ciphers available when JCE Unlimited Strength Jurisdiction Policy is not installed.
@@ -65,10 +81,8 @@ public enum SslClientVerifyMode {
6581
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
6682
};
6783

68-
private String[] supportedCiphers = ((SSLServerSocketFactory)SSLServerSocketFactory
69-
.getDefault()).getSupportedCipherSuites();
7084
private String[] ciphers = DEFAULT_CIPHERS;
71-
private String[] protocols = new String[] { "TLSv1.2" };
85+
private String[] protocols = new String[] { "TLSv1.2", "TLSv1.3" };
7286
private String[] certificateAuthorities;
7387
private String passPhrase;
7488

@@ -92,10 +106,10 @@ public SslContextBuilder setProtocols(String[] protocols) {
92106
}
93107

94108
public SslContextBuilder setCipherSuites(String[] ciphersSuite) throws IllegalArgumentException {
95-
for(String cipher : ciphersSuite) {
96-
if(Arrays.asList(supportedCiphers).contains(cipher)) {
97-
logger.debug("Cipher is supported: {}", cipher);
98-
}else{
109+
for (String cipher : ciphersSuite) {
110+
if (SUPPORTED_CIPHERS.contains(cipher)) {
111+
logger.debug("{} cipher is supported", cipher);
112+
} else {
99113
if (!isUnlimitedJCEAvailable()) {
100114
logger.warn("JCE Unlimited Strength Jurisdiction Policy not installed");
101115
}
@@ -108,7 +122,7 @@ public SslContextBuilder setCipherSuites(String[] ciphersSuite) throws IllegalAr
108122
}
109123

110124
public static String[] getDefaultCiphers(){
111-
if (isUnlimitedJCEAvailable()){
125+
if (isUnlimitedJCEAvailable()) {
112126
return DEFAULT_CIPHERS;
113127
} else {
114128
logger.warn("JCE Unlimited Strength Jurisdiction Policy not installed - max key length is 128 bits");
@@ -146,7 +160,7 @@ public SslContext buildContext() throws Exception {
146160
io.netty.handler.ssl.SslContextBuilder builder = io.netty.handler.ssl.SslContextBuilder.forServer(sslCertificateFile, sslKeyFile, passPhrase);
147161

148162
if (logger.isDebugEnabled()) {
149-
logger.debug("Available ciphers: " + Arrays.toString(supportedCiphers));
163+
logger.debug("Available ciphers: " + SUPPORTED_CIPHERS);
150164
logger.debug("Ciphers: " + Arrays.toString(ciphers));
151165
}
152166

0 commit comments

Comments
 (0)