logstash-input-tcp 6.2.7-java → 6.3.1-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f83551a42283324a0f4f733c2f245b5fe3f2d71e482f15607257b2943f92e925
4
- data.tar.gz: 30d47775fcdec83e4be7834c79b3cbf7c233a35284f60b7eb9f0431235c6442c
3
+ metadata.gz: 2fb789cdfaf2019169729724b4ab5f0f330d7a136594310a5f823f90d59b807c
4
+ data.tar.gz: f385f458414136970b159cc1f4e20ff053da79ac55c9358a30e35a741969de0b
5
5
  SHA512:
6
- metadata.gz: d53bfe010749d42e0a7d7d288464b091678bb5f55da75008b0b2001f642ec36dde4d0c17050d981ec612c9a8b6fd263635473438b543e7ea7ecb7d5a00d8f530
7
- data.tar.gz: 76180a9c1d8ad885e9ab5adb1ce4befade31cb9124ae2727035c26797b1498ff22d8bdbe91ee6e14b1b8c3840667a277e14460a9cc8adfacd85cee25324b690a
6
+ metadata.gz: 990b51998a4229fd5638083df9ab64daad5dc5a1cf98f6d78fbd3b2e53cce22a8c2ecc0ee61afce2577901b9d68ded2fd27fe34504d92c1f03ee7efef7e885b7
7
+ data.tar.gz: 8495257bef6b00b3fd06e7bd8d5981adf688d268c531c10f9ae8bf24126f1a367e030d2622dd3a0a0b707b066e822bbc31628bc4f22d184494ceeb78e2987de4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 6.3.1
2
+ - Fixes a regression in which the ssl_subject was missing for SSL-secured connections in server mode [#199](https://github.com/logstash-plugins/logstash-input-tcp/pull/199)
3
+
4
+ ## 6.3.0
5
+ - Feat: ssl_supported_protocols (TLSv1.3) + ssl_cipher_suites [#198](https://github.com/logstash-plugins/logstash-input-tcp/pull/198)
6
+
1
7
  ## 6.2.7
2
8
  - Build: skip shadowing jar dependencies [#187](https://github.com/logstash-plugins/logstash-input-tcp/pull/187)
3
9
  * plugin no longer shadows dependencies into its *logstash-input-tcp.jar*
data/docs/index.asciidoc CHANGED
@@ -132,10 +132,12 @@ This plugin supports the following configuration options plus the <<plugins-{typ
132
132
  | <<plugins-{type}s-{plugin}-proxy_protocol>> |<<boolean,boolean>>|No
133
133
  | <<plugins-{type}s-{plugin}-ssl_cert>> |a valid filesystem path|No
134
134
  | <<plugins-{type}s-{plugin}-ssl_certificate_authorities>> |<<array,array>>|No
135
+ | <<plugins-{type}s-{plugin}-ssl_cipher_suites>> |<<string,string>>|No
135
136
  | <<plugins-{type}s-{plugin}-ssl_enable>> |<<boolean,boolean>>|No
136
137
  | <<plugins-{type}s-{plugin}-ssl_extra_chain_certs>> |<<array,array>>|No
137
138
  | <<plugins-{type}s-{plugin}-ssl_key>> |a valid filesystem path|No
138
139
  | <<plugins-{type}s-{plugin}-ssl_key_passphrase>> |<<password,password>>|No
140
+ | <<plugins-{type}s-{plugin}-ssl_supported_protocols>> |<<string,string>>|No
139
141
  | <<plugins-{type}s-{plugin}-ssl_verify>> |<<boolean,boolean>>|No
140
142
  | <<plugins-{type}s-{plugin}-tcp_keep_alive>> |<<boolean,boolean>>|No
141
143
  |=======================================================================
@@ -158,13 +160,13 @@ at the TCP layer and IPs will not be resolved to hostnames.
158
160
  [id="plugins-{type}s-{plugin}-ecs_compatibility"]
159
161
  ===== `ecs_compatibility`
160
162
 
161
- * Value type is <<string,string>>
162
- * Supported values are:
163
- ** `disabled`: unstructured connection metadata added at root level
164
- ** `v1`,`v8`: structured connection metadata added under `[@metadata][input][tcp]`
165
- * Default value depends on which version of Logstash is running:
166
- ** When Logstash provides a `pipeline.ecs_compatibility` setting, its value is used as the default
167
- ** Otherwise, the default value is `disabled`.
163
+ * Value type is <<string,string>>
164
+ * Supported values are:
165
+ ** `disabled`: unstructured connection metadata added at root level
166
+ ** `v1`,`v8`: structured connection metadata added under `[@metadata][input][tcp]`
167
+ * Default value depends on which version of Logstash is running:
168
+ ** When Logstash provides a `pipeline.ecs_compatibility` setting, its value is used as the default
169
+ ** Otherwise, the default value is `disabled`.
168
170
 
169
171
  Controls this plugin's compatibility with the https://www.elastic.co/guide/en/ecs/current/index.html[Elastic Common Schema (ECS)].
170
172
  The value of this setting affects the <<plugins-{type}s-{plugin}-ecs_metadata,placement of a TCP connection's metadata>> on events.
@@ -224,6 +226,18 @@ to the connecting clients.
224
226
  Validate client certificate or certificate chain against these authorities.
225
227
  You can define multiple files or paths. All the certificates will be read and added to the trust store.
226
228
 
229
+ [id="plugins-{type}s-{plugin}-ssl_cipher_suites"]
230
+ ===== `ssl_cipher_suites`
231
+
232
+ * Value type is <<string,string>>
233
+ * Default value includes _all_ cipher suites enabled by the JDK and depends on JDK configuration
234
+
235
+ Supported cipher suites vary depending on Java version used, and entries look like `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`.
236
+ For more information, see Oracle’s https://docs.oracle.com/en/java/javase/11/security/oracle-providers.html#GUID-7093246A-31A3-4304-AC5F-5FB6400405E2[JDK SunJSSE provider documentation] and
237
+ the table of supported https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#jsse-cipher-suite-names[Java cipher suite names].
238
+
239
+ NOTE: To check the supported cipher suites locally run the following script: `$LS_HOME/bin/ruby -e 'p javax.net.ssl.SSLServerSocketFactory.getDefault.getSupportedCipherSuites'`.
240
+
227
241
  [id="plugins-{type}s-{plugin}-ssl_enable"]
228
242
  ===== `ssl_enable`
229
243
 
@@ -258,6 +272,20 @@ The path to the private key corresponding to the specified certificate (PEM form
258
272
 
259
273
  SSL key passphrase for the private key.
260
274
 
275
+ [id="plugins-{type}s-{plugin}-ssl_supported_protocols"]
276
+ ===== `ssl_supported_protocols`
277
+
278
+ * Value type is <<string,string>>
279
+ * Allowed values are: `'TLSv1.1'`, `'TLSv1.2'`, `'TLSv1.3'`
280
+ * Default depends on the JDK being used. With up-to-date Logstash, the default is `['TLSv1.2', 'TLSv1.3']`.
281
+ `'TLSv1.1'` is not considered secure and is only provided for legacy applications.
282
+
283
+ List of allowed SSL/TLS versions to use when establishing a secure connection.
284
+
285
+ NOTE: If you configure the plugin to use `'TLSv1.1'` on any recent JVM, such as the one packaged with Logstash,
286
+ the protocol is disabled by default and needs to be enabled manually by changing `jdk.tls.disabledAlgorithms` in
287
+ the *$JDK_HOME/conf/security/java.security* configuration file. That is, `TLSv1.1` needs to be removed from the list.
288
+
261
289
  [id="plugins-{type}s-{plugin}-ssl_verify"]
262
290
  ===== `ssl_verify`
263
291
 
@@ -11,16 +11,17 @@ class LogStash::Inputs::Tcp::DecoderImpl
11
11
  @first_read = true
12
12
  end
13
13
 
14
- def decode(channel_addr, data)
14
+ def decode(ctx, data)
15
+ channel = ctx.channel()
15
16
  bytes = Java::byte[data.readableBytes].new
16
17
  data.getBytes(0, bytes)
17
18
  data.release
18
19
  tbuf = String.from_java_bytes bytes, "ASCII-8BIT"
19
20
  if @first_read
20
- tbuf = init_first_read(channel_addr, tbuf)
21
+ tbuf = init_first_read(channel, tbuf)
21
22
  end
22
23
  @tcp.decode_buffer(@ip_address, @address, @port, @codec,
23
- @proxy_address, @proxy_port, tbuf, nil)
24
+ @proxy_address, @proxy_port, tbuf, @sslsubject)
24
25
  end
25
26
 
26
27
  def copy
@@ -28,11 +29,12 @@ class LogStash::Inputs::Tcp::DecoderImpl
28
29
  end
29
30
 
30
31
  def flush
31
- @tcp.flush_codec(@codec, @ip_address, @address, @port, nil)
32
+ @tcp.flush_codec(@codec, @ip_address, @address, @port, @sslsubject)
32
33
  end
33
34
 
34
35
  private
35
- def init_first_read(channel_addr, received)
36
+ def init_first_read(channel, received)
37
+ channel_addr = channel.remoteAddress()
36
38
  if @tcp.proxy_protocol
37
39
  pp_hdr, filtered = received.split("\r\n", 2)
38
40
  pp_info = pp_hdr.split(/\s/)
@@ -53,10 +55,20 @@ class LogStash::Inputs::Tcp::DecoderImpl
53
55
  @address = extract_host_name(channel_addr) # name _or_ address of sender
54
56
  @port = channel_addr.get_port # outgoing port of sender (probably random)
55
57
  end
58
+ @sslsubject = extract_sslsubject(channel)
56
59
  @first_read = false
57
60
  filtered
58
61
  end
59
62
 
63
+ private
64
+ def extract_sslsubject(channel)
65
+ return nil unless @tcp.ssl_enable && @tcp.ssl_verify
66
+
67
+ channel.pipeline().get("ssl-handler").engine().getSession().getPeerPrincipal().getName()
68
+ rescue Exception => e
69
+ nil
70
+ end
71
+
60
72
  private
61
73
  def extract_host_name(channel_addr)
62
74
  channel_addr = java.net.InetSocketAddress.new(channel_addr, 0) if channel_addr.kind_of?(String)
@@ -112,6 +112,13 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
112
112
  # All the certificates will be read and added to the trust store.
113
113
  config :ssl_certificate_authorities, :validate => :array, :default => []
114
114
 
115
+ # NOTE: the default setting [] uses Java SSL engine defaults.
116
+ config :ssl_supported_protocols, :validate => ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'], :default => [], :list => true
117
+
118
+ # The list of ciphers suite to use, listed by priorities.
119
+ # NOTE: the default setting [] uses Java SSL defaults.
120
+ config :ssl_cipher_suites, :validate => SslContextBuilder.getSupportedCipherSuites.to_a, :default => [], :list => true
121
+
115
122
  # Instruct the socket to use TCP keep alives. Uses OS defaults for keep alive settings.
116
123
  config :tcp_keep_alive, :validate => :boolean, :default => false
117
124
 
@@ -183,19 +190,19 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
183
190
  end
184
191
 
185
192
  def decode_buffer(client_ip_address, client_address, client_port, codec, proxy_address,
186
- proxy_port, tbuf, socket)
193
+ proxy_port, tbuf, ssl_subject)
187
194
  codec.decode(tbuf) do |event|
188
195
  if @proxy_protocol
189
196
  event.set(@field_proxy_host, proxy_address) unless event.get(@field_proxy_host)
190
197
  event.set(@field_proxy_port, proxy_port) unless event.get(@field_proxy_port)
191
198
  end
192
- enqueue_decorated(event, client_ip_address, client_address, client_port, socket)
199
+ enqueue_decorated(event, client_ip_address, client_address, client_port, ssl_subject)
193
200
  end
194
201
  end
195
202
 
196
- def flush_codec(codec, client_ip_address, client_address, client_port, socket)
203
+ def flush_codec(codec, client_ip_address, client_address, client_port, ssl_subject)
197
204
  codec.flush do |event|
198
- enqueue_decorated(event, client_ip_address, client_address, client_port, socket)
205
+ enqueue_decorated(event, client_ip_address, client_address, client_port, ssl_subject)
199
206
  end
200
207
  end
201
208
 
@@ -215,10 +222,14 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
215
222
  client_socket.close rescue nil
216
223
  end
217
224
 
225
+ # only called in client mode
218
226
  def handle_socket(socket)
219
227
  client_address = socket.peeraddr[3]
220
228
  client_ip_address = socket.peeraddr[2]
221
229
  client_port = socket.peeraddr[1]
230
+
231
+ # Client mode sslsubject extraction, server mode happens in DecoderImpl#decode
232
+ ssl_subject = socket.peer_cert.subject.to_s if @ssl_enable && @ssl_verify
222
233
  peer = "#{client_address}:#{client_port}"
223
234
  first_read = true
224
235
  codec = @codec.clone
@@ -242,7 +253,7 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
242
253
  end
243
254
  end
244
255
  decode_buffer(client_ip_address, client_address, client_port, codec, proxy_address,
245
- proxy_port, tbuf, socket)
256
+ proxy_port, tbuf, ssl_subject)
246
257
  end
247
258
  rescue EOFError
248
259
  @logger.debug? && @logger.debug("Connection closed", :client => peer)
@@ -256,14 +267,14 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
256
267
  ensure
257
268
  # catch all rescue nil on close to discard any close errors or invalid socket
258
269
  socket.close rescue nil
259
- flush_codec(codec, client_ip_address, client_address, client_port, socket)
270
+ flush_codec(codec, client_ip_address, client_address, client_port, ssl_subject)
260
271
  end
261
272
 
262
- def enqueue_decorated(event, client_ip_address, client_address, client_port, socket)
273
+ def enqueue_decorated(event, client_ip_address, client_address, client_port, ssl_subject)
263
274
  event.set(@field_host, client_address) unless event.get(@field_host)
264
275
  event.set(@field_host_ip, client_ip_address) unless event.get(@field_host_ip)
265
276
  event.set(@field_port, client_port) unless event.get(@field_port)
266
- event.set(@field_sslsubject, socket.peer_cert.subject.to_s) if socket && @ssl_enable && @ssl_verify && event.get(@field_sslsubject).nil?
277
+ event.set(@field_sslsubject, ssl_subject) unless ssl_subject.nil? || event.get(@field_sslsubject)
267
278
  decorate(event)
268
279
  @output_queue << event
269
280
  end
@@ -286,7 +297,7 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
286
297
  return @ssl_context if @ssl_context
287
298
 
288
299
  begin
289
- @ssl_context = OpenSSL::SSL::SSLContext.new
300
+ @ssl_context = new_ssl_context
290
301
  @ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(@ssl_cert))
291
302
  @ssl_context.key = OpenSSL::PKey::RSA.new(File.read(@ssl_key),@ssl_key_passphrase.value)
292
303
  if @ssl_extra_chain_certs.any?
@@ -297,6 +308,21 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
297
308
  @ssl_context.cert_store = load_cert_store
298
309
  @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
299
310
  end
311
+
312
+ @ssl_context.min_version = :TLS1_1 # not strictly required - JVM should have disabled TLSv1
313
+ if ssl_supported_protocols.any?
314
+ disabled_protocols = ['TLSv1.1', 'TLSv1.2', 'TLSv1.3'] - ssl_supported_protocols
315
+ unless OpenSSL::SSL.const_defined? :OP_NO_TLSv1_3 # work-around JRuby-OpenSSL bug - missing constant
316
+ @ssl_context.max_version = :TLS1_2 if disabled_protocols.delete('TLSv1.3')
317
+ end
318
+ # mapping 'TLSv1.2' -> OpenSSL::SSL::OP_NO_TLSv1_2
319
+ disabled_protocols.map! { |v| OpenSSL::SSL.const_get "OP_NO_#{v.sub('.', '_')}" }
320
+ @ssl_context.options = disabled_protocols.reduce(@ssl_context.options, :|)
321
+ end
322
+
323
+ if ssl_cipher_suites.any?
324
+ @ssl_context.ciphers = ssl_cipher_suites # Java cipher names work with JOSSL >= 0.12.2
325
+ end
300
326
  rescue => e
301
327
  @logger.error("Could not inititalize SSL context", :message => e.message, :exception => e.class, :backtrace => e.backtrace)
302
328
  raise e
@@ -305,6 +331,11 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
305
331
  @ssl_context
306
332
  end
307
333
 
334
+ # @note to be able to hook up into #ssl_context from tests
335
+ def new_ssl_context
336
+ OpenSSL::SSL::SSLContext.new
337
+ end
338
+
308
339
  def load_cert_store
309
340
  cert_store = OpenSSL::X509::Store.new
310
341
  cert_store.set_default_paths
@@ -379,6 +410,8 @@ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
379
410
  .set_ssl_key_password(@ssl_key_passphrase.value)
380
411
  .set_ssl_extra_chain_certs(@ssl_extra_chain_certs.to_java(:string))
381
412
  .set_ssl_certificate_authorities(@ssl_certificate_authorities.to_java(:string))
413
+ .set_ssl_supported_protocols(ssl_supported_protocols.to_java(:string))
414
+ .set_ssl_cipher_suites(ssl_cipher_suites.to_java(:string))
382
415
  .build_context
383
416
  rescue java.lang.IllegalArgumentException => e
384
417
  @logger.error("SSL configuration invalid", error_details(e))
@@ -4,4 +4,4 @@ require 'jar_dependencies'
4
4
  require_jar('io.netty', 'netty-all', '4.1.65.Final')
5
5
  require_jar('commons-io', 'commons-io', '2.8.0')
6
6
 
7
- require_jar('org.logstash.inputs', 'logstash-input-tcp', '6.2.7')
7
+ require_jar('org.logstash.inputs', 'logstash-input-tcp', '6.3.1')
@@ -23,10 +23,10 @@ Gem::Specification.new do |s|
23
23
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
24
  s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.2'
25
25
 
26
- s.add_runtime_dependency 'logstash-core', '>= 6.7.0'
26
+ s.add_runtime_dependency 'logstash-core', '>= 8.1.0'
27
27
 
28
28
  # we depend on bouncycastle's bcpkix-jdk15on being on the class-path
29
- s.add_runtime_dependency 'jruby-openssl', '>= 0.10.2'
29
+ s.add_runtime_dependency 'jruby-openssl', '>= 0.12.2' # 0.12 supports TLSv1.3
30
30
 
31
31
  # line vs streaming codecs required for fix_streaming_codecs
32
32
  # TODO: fix_streaming_codecs should be refactored to not
@@ -541,7 +541,7 @@ describe LogStash::Inputs::Tcp, :ecs_compatibility_support do
541
541
  end
542
542
  end
543
543
 
544
- describe "#receive" do
544
+ describe "#receive", :ecs_compatibility_support do
545
545
  shared_examples "receiving events" do
546
546
  # TODO(sissel): Implement normal event-receipt tests as as a shared example
547
547
  end
@@ -549,7 +549,10 @@ describe LogStash::Inputs::Tcp, :ecs_compatibility_support do
549
549
  context "when ssl_enable is true" do
550
550
  let(:input) { subject }
551
551
  let(:queue) { Queue.new }
552
- before(:each) { subject.register }
552
+ before(:each) do
553
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility) if defined?(ecs_compatibility)
554
+ subject.register
555
+ end
553
556
 
554
557
  context "when using a certificate chain" do
555
558
  chain_of_certificates = TcpHelpers.new.chain_of_certificates
@@ -568,18 +571,21 @@ describe LogStash::Inputs::Tcp, :ecs_compatibility_support do
568
571
  let(:sslsocket) { OpenSSL::SSL::SSLSocket.new(tcp, sslcontext) }
569
572
  let(:message) { "message to #{port}" }
570
573
 
571
- context "with a non encrypted private key" do
572
- let(:config) do
573
- {
574
+ let(:base_config) do
575
+ {
574
576
  "host" => "127.0.0.1",
575
577
  "port" => port,
576
578
  "ssl_enable" => true,
577
579
  "ssl_cert" => chain_of_certificates[:b_cert].path,
578
580
  "ssl_key" => chain_of_certificates[:b_key].path,
579
581
  "ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
580
- "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ],
581
- "ssl_verify" => true
582
- }
582
+ "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ]
583
+ }
584
+ end
585
+
586
+ context "with a non encrypted private key" do
587
+ let(:config) do
588
+ base_config.merge "ssl_verify" => true
583
589
  end
584
590
  it "should be able to connect and write data" do
585
591
  result = TcpHelpers.pipelineless_input(subject, 1) do
@@ -620,6 +626,7 @@ describe LogStash::Inputs::Tcp, :ecs_compatibility_support do
620
626
  expect(result.first.get("message")).to eq(message)
621
627
  end
622
628
  end
629
+
623
630
  context "when using an encrypted private pkcs8 key" do
624
631
  let(:config) do
625
632
  {
@@ -646,6 +653,141 @@ describe LogStash::Inputs::Tcp, :ecs_compatibility_support do
646
653
  expect(result.first.get("message")).to eq(message)
647
654
  end
648
655
  end
656
+
657
+ context "with a regular TLS setup" do
658
+ let(:config) do
659
+ {
660
+ "host" => "127.0.0.1",
661
+ "port" => port,
662
+ "ssl_enable" => true,
663
+ "ssl_cert" => chain_of_certificates[:b_cert].path,
664
+ "ssl_key" => chain_of_certificates[:b_key].path,
665
+ "ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
666
+ "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ],
667
+ "ssl_verify" => true
668
+ }
669
+ end
670
+
671
+ ecs_compatibility_matrix(:disabled,:v1, :v8 => :v1) do |ecs_select|
672
+ it "extracts the TLS subject from connections" do
673
+ result = TcpHelpers.pipelineless_input(subject, 1) do
674
+ sslsocket.connect
675
+ sslsocket.write("#{message}\n")
676
+ tcp.flush
677
+ sslsocket.close
678
+ tcp.close
679
+ end
680
+ expect(result.size).to eq(1)
681
+ event = result.first
682
+
683
+ ssl_subject_field = ecs_select[disabled: 'sslsubject', v1:'[@metadata][input][tcp][tls][client][subject]']
684
+ expect(event.get(ssl_subject_field)).to eq("CN=RubyAA_Cert,DC=ruby-lang,DC=org")
685
+ end
686
+ end
687
+ end
688
+
689
+ context "with enforced protocol version" do
690
+ let(:config) do
691
+ base_config.merge 'ssl_supported_protocols' => [ tls_version ]
692
+ end
693
+
694
+ let(:tls_version) { 'TLSv1.3' }
695
+
696
+ it "should be able to connect and write data" do
697
+ used_tls_protocol = nil
698
+ result = TcpHelpers.pipelineless_input(subject, 1) do
699
+ sslsocket.connect
700
+ sslsocket.write("#{message}\n")
701
+ used_tls_protocol = sslsocket.session.to_java(javax.net.ssl.SSLSession).getProtocol
702
+ tcp.flush
703
+ sslsocket.close
704
+ tcp.close
705
+ end
706
+ expect(result.size).to eq(1)
707
+ expect(used_tls_protocol).to eql tls_version
708
+ end
709
+ end
710
+
711
+ context "with enforced protocol range" do
712
+ let(:config) do
713
+ base_config.merge 'ssl_supported_protocols' => [ 'TLSv1.3', 'TLSv1.2' ]
714
+ end
715
+ let(:sslcontext) do
716
+ super().tap { |ctx| ctx.ssl_version = 'TLSv1.2' }
717
+ end
718
+
719
+ it "should be able to connect and write data" do
720
+ used_tls_protocol = nil
721
+ result = TcpHelpers.pipelineless_input(subject, 1) do
722
+ sslsocket.connect
723
+ sslsocket.write("#{message}\n")
724
+ used_tls_protocol = sslsocket.session.to_java(javax.net.ssl.SSLSession).getProtocol
725
+ tcp.flush
726
+ sslsocket.close
727
+ tcp.close
728
+ end
729
+ expect(result.size).to eq(1)
730
+ expect(used_tls_protocol).to eql 'TLSv1.2'
731
+ end
732
+ end if TcpHelpers.tls13_available_by_default? # till CI testing against 6.x
733
+
734
+ context "with unsupported client protocol" do
735
+ let(:config) do
736
+ base_config.merge 'ssl_supported_protocols' => [ 'TLSv1.2' ]
737
+ end
738
+ let(:sslcontext) do
739
+ super().tap { |ctx| ctx.ssl_version = 'TLSv1.1' }
740
+ end
741
+
742
+ it "should not be able to connect" do
743
+ TcpHelpers.pipelineless_input(subject, 0) do
744
+ expect { sslsocket.connect }.to raise_error(OpenSSL::SSL::SSLError, /No appropriate protocol|protocol_version/i)
745
+ sslsocket.close
746
+ tcp.close
747
+ end
748
+ end
749
+ end
750
+
751
+ context "with specified cipher suites" do
752
+ let(:config) do
753
+ base_config.merge 'ssl_cipher_suites' => [ cipher_suite ]
754
+ end
755
+
756
+ let(:cipher_suite) { 'TLS_RSA_WITH_AES_128_GCM_SHA256' }
757
+
758
+ it "should be able to connect and write data" do
759
+ used_cipher_suite = nil
760
+ result = TcpHelpers.pipelineless_input(subject, 1) do
761
+ sslsocket.connect
762
+ sslsocket.write("#{message}\n")
763
+ used_cipher_suite = sslsocket.session.to_java(javax.net.ssl.SSLSession).getCipherSuite
764
+ tcp.flush
765
+ sslsocket.close
766
+ tcp.close
767
+ end
768
+ expect(result.size).to eq(1)
769
+ expect(used_cipher_suite).to eql cipher_suite
770
+ end
771
+ end
772
+
773
+ context "with unsupported client cipher" do
774
+ let(:config) do
775
+ base_config.merge 'ssl_cipher_suites' => [ 'TLS_RSA_WITH_AES_128_GCM_SHA256', 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' ]
776
+ end
777
+
778
+ let(:sslcontext) do
779
+ super().tap { |ctx| ctx.ciphers = [ 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256' ] }
780
+ end
781
+
782
+ it "should not be able to connect" do
783
+ TcpHelpers.pipelineless_input(subject, 0) do
784
+ expect { sslsocket.connect }.to raise_error(OpenSSL::SSL::SSLError, /handshake_failure|no cipher match/i)
785
+ sslsocket.close
786
+ tcp.close
787
+ end
788
+ end
789
+ end
790
+
649
791
  end
650
792
 
651
793
  context "with a poorly-behaving client" do
@@ -717,4 +859,83 @@ describe LogStash::Inputs::Tcp, :ecs_compatibility_support do
717
859
  let(:config) { { "port" => port } }
718
860
  end
719
861
  end
862
+
863
+ context 'ssl context (client mode)' do
864
+
865
+ let(:chain_of_certificates) do
866
+ TcpHelpers.new.chain_of_certificates
867
+ end
868
+
869
+ let(:config) do
870
+ {
871
+ "host" => "127.0.0.1",
872
+ "port" => port,
873
+ "mode" => 'client',
874
+ "ssl_enable" => true,
875
+ "ssl_cert" => chain_of_certificates[:b_cert].path,
876
+ "ssl_key" => chain_of_certificates[:b_key].path,
877
+ "ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
878
+ "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ]
879
+ }
880
+ end
881
+
882
+ subject(:plugin) { LogStash::Inputs::Tcp.new(config) }
883
+
884
+ let(:ssl_context) { plugin.send :ssl_context }
885
+
886
+ context "with cipher suites" do
887
+ let(:config) do
888
+ super().merge 'ssl_cipher_suites' => [ cipher_suite ]
889
+ end
890
+
891
+ let(:cipher_suite) { 'TLS_RSA_WITH_AES_128_GCM_SHA256' }
892
+
893
+ it "sets ciphers" do
894
+ cipher_ary = ssl_context.ciphers.first
895
+ expect( cipher_ary[0] ).to eql 'AES128-GCM-SHA256'
896
+ end
897
+
898
+ end
899
+
900
+ context "with forced protocol" do
901
+ let(:config) do
902
+ super().merge 'ssl_supported_protocols' => [ 'TLSv1.1' ]
903
+ end
904
+
905
+ it "limits protocol selection" do
906
+ if OpenSSL::SSL.const_defined? :OP_NO_TLSv1_3
907
+ ssl_context = subject.send :ssl_context
908
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_3).to_not eql 0
909
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_2).to_not eql 0
910
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_1).to eql 0
911
+ else
912
+ ssl_context = OpenSSL::SSL::SSLContext.new
913
+ allow(subject).to receive(:new_ssl_context).and_return(ssl_context)
914
+ expect(ssl_context).to receive(:max_version=).with(:'TLS1_2').and_call_original
915
+ ssl_context = subject.send :ssl_context
916
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_2).to_not eql 0
917
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_1).to eql 0
918
+ end
919
+ end
920
+
921
+ end
922
+
923
+ context "with protocol range" do
924
+ let(:config) do
925
+ super().merge 'ssl_supported_protocols' => [ 'TLSv1.3', 'TLSv1.1', 'TLSv1.2' ]
926
+ end
927
+
928
+ it "does not limit protocol selection (except min_version)" do
929
+ ssl_context = OpenSSL::SSL::SSLContext.new
930
+ allow(subject).to receive(:new_ssl_context).and_return(ssl_context)
931
+ expect(ssl_context).to receive(:min_version=).with(:'TLS1_1').and_call_original
932
+ ssl_context = subject.send :ssl_context
933
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_3).to eql 0 if OpenSSL::SSL.const_defined? :OP_NO_TLSv1_3
934
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_2).to eql 0
935
+ expect(ssl_context.options & OpenSSL::SSL::OP_NO_TLSv1_1).to eql 0
936
+ end
937
+ end
938
+
939
+ end
940
+
720
941
  end
data/spec/spec_helper.rb CHANGED
@@ -7,6 +7,17 @@ require "stud/temporary"
7
7
 
8
8
  class TcpHelpers
9
9
 
10
+ def self.tls13_available_by_default?
11
+ begin
12
+ context = javax.net.ssl.SSLContext.getInstance('TLS')
13
+ context.init nil, nil, nil
14
+ context.getDefaultSSLParameters.getProtocols.include? 'TLSv1.3'
15
+ rescue => e
16
+ warn "failed to detect TLSv1.3 support: #{e.inspect}"
17
+ nil
18
+ end
19
+ end
20
+
10
21
  java_import 'org.bouncycastle.openssl.PEMParser'
11
22
  java_import 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder'
12
23
  java_import 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter'
data/version CHANGED
@@ -1 +1 @@
1
- 6.2.7
1
+ 6.3.1
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-tcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.7
4
+ version: 6.3.1
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-01 00:00:00.000000000 Z
11
+ date: 2022-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  requirements:
50
50
  - - ">="
51
51
  - !ruby/object:Gem::Version
52
- version: 6.7.0
52
+ version: 8.1.0
53
53
  name: logstash-core
54
54
  prerelease: false
55
55
  type: :runtime
@@ -57,13 +57,13 @@ dependencies:
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 6.7.0
60
+ version: 8.1.0
61
61
  - !ruby/object:Gem::Dependency
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
- version: 0.10.2
66
+ version: 0.12.2
67
67
  name: jruby-openssl
68
68
  prerelease: false
69
69
  type: :runtime
@@ -71,7 +71,7 @@ dependencies:
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: 0.10.2
74
+ version: 0.12.2
75
75
  - !ruby/object:Gem::Dependency
76
76
  requirement: !ruby/object:Gem::Requirement
77
77
  requirements:
@@ -233,7 +233,7 @@ files:
233
233
  - spec/spec_helper.rb
234
234
  - vendor/jar-dependencies/commons-io/commons-io/2.8.0/commons-io-2.8.0.jar
235
235
  - vendor/jar-dependencies/io/netty/netty-all/4.1.65.Final/netty-all-4.1.65.Final.jar
236
- - vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/6.2.7/logstash-input-tcp-6.2.7.jar
236
+ - vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/6.3.1/logstash-input-tcp-6.3.1.jar
237
237
  - version
238
238
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
239
239
  licenses: