logstash-input-tcp 5.2.0-java → 5.2.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f821e3a9df2b90606b5fd46026262b5c7a0054d5e24bf7545d322efbedec40a
4
- data.tar.gz: 202f4eeb3fe522d4df635599b7557faaab6884db8d80c1a92a17f140915c1d02
3
+ metadata.gz: 6ee7c79fca2dceea8688b100903ab8318ad2cd652740b0538c102504209bd1e0
4
+ data.tar.gz: fee6f5e7d1804c8ef60fd771a3d50caeeee289c9e517a93c2a33a5d207202bdb
5
5
  SHA512:
6
- metadata.gz: cee3f82c41bfefea68c3e0337a5ad15f50e17ba6e72fe4fbcf004c6580d755107d47435667c73022938fe852a7e4a7401e793f6640c70bac0486f8fcbbd63642
7
- data.tar.gz: a588b4ca240e7eb9e6cca0aec296999270c89b375d7b8038de989529447bf8f5df1c38faae49d71821f2051906e34e32e5f834f248ad2a2856583a7b16704caf
6
+ metadata.gz: 970218c4f6ed173209de6d40113423a49e356e1eeb3a8cf8603b5ddd7c51ae4766cadf73e78d917a17ba36b4d447fc1d9512ea12081dbd1cbb2e28e0f8ea9340
7
+ data.tar.gz: 0b4120780dcae5f582c118247a064025a57f998ddbe20ff5cb15d3c4ecbdef0a0a522cd6bd2968e77db75ff034d6810f4e13f8372f2de49ce08ea1cada19e573
@@ -1,3 +1,10 @@
1
+ ## 5.2.1
2
+ - Support multiple certificates per file [#140](https://github.com/logstash-plugins/logstash-input-tcp/pull/140)
3
+ - Fixed support for encrypted pkcs8 private keys [#133](https://github.com/logstash-plugins/logstash-input-tcp/pull/133)
4
+ - Added support for encrypted pem pkcs1 private keys [#131](https://github.com/logstash-plugins/logstash-input-tcp/pull/131)
5
+ - Changed testing to docker [#128](https://github.com/logstash-plugins/logstash-input-tcp/pull/128)
6
+ - Fixed heading for `ssl_certificate_authorities` docs [#130](https://github.com/logstash-plugins/logstash-input-tcp/pull/130)
7
+
1
8
  ## 5.2.0
2
9
  - Added support for pkcs1 and pkcs8 key formats [#122](https://github.com/logstash-plugins/logstash-input-tcp/issues/122)
3
10
  - Changed server-mode SSL to run on top of Netty [#122](https://github.com/logstash-plugins/logstash-input-tcp/issues/122)
@@ -145,7 +145,7 @@ Path to certificate in PEM format. This certificate will be presented
145
145
  to the connecting clients.
146
146
 
147
147
  [id="plugins-{type}s-{plugin}-ssl_certificate_authorities"]
148
- ===== `ssl_extra_chain_certs`
148
+ ===== `ssl_certificate_authorities`
149
149
 
150
150
  * Value type is <<array,array>>
151
151
  * Default value is `[]`
@@ -218,4 +218,4 @@ at the TCP layer and IPs will not be resolved to hostnames.
218
218
  [id="plugins-{type}s-{plugin}-common-options"]
219
219
  include::{include_path}/{type}.asciidoc[]
220
220
 
221
- :default_codec!:
221
+ :default_codec!:
@@ -7,9 +7,15 @@ java_import 'java.io.FileReader'
7
7
  java_import 'java.security.cert.CertificateFactory'
8
8
  java_import 'java.security.cert.X509Certificate'
9
9
  java_import 'org.bouncycastle.asn1.pkcs.PrivateKeyInfo'
10
+ java_import 'org.bouncycastle.jce.provider.BouncyCastleProvider'
10
11
  java_import 'org.bouncycastle.openssl.PEMKeyPair'
11
12
  java_import 'org.bouncycastle.openssl.PEMParser'
13
+ java_import 'org.bouncycastle.openssl.PEMEncryptedKeyPair'
12
14
  java_import 'org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter'
15
+ java_import 'org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder'
16
+ java_import 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder'
17
+ java_import 'org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo'
18
+
13
19
 
14
20
  # Simulate a normal SslOptions builder:
15
21
  #
@@ -70,34 +76,63 @@ class SslOptions
70
76
  # create certificate object
71
77
  cf = CertificateFactory.getInstance("X.509")
72
78
  cert_chain = []
73
- cert_chain << cf.generateCertificate(FileInputStream.new(@ssl_cert_path))
79
+ fetch_certificates_from_file(@ssl_cert_path, cf) do |cert|
80
+ cert_chain << cert
81
+ end
74
82
 
75
83
  # convert key from pkcs1 to pkcs8 and get PrivateKey object
76
84
  pem_parser = PEMParser.new(FileReader.new(@ssl_key_path))
77
-
78
- case obj = pem_parser.read_object
79
- when PEMKeyPair # likely pkcs#1
80
- private_key = JcaPEMKeyConverter.new.get_key_pair(obj).private
81
- when PrivateKeyInfo # likely pkcs#8
82
- private_key = JcaPEMKeyConverter.new.get_private_key(obj)
85
+ java.security.Security.addProvider(BouncyCastleProvider.new)
86
+ converter = JcaPEMKeyConverter.new
87
+ case obj = pem_parser.readObject
88
+ when PEMKeyPair # unencrypted pkcs#1
89
+ private_key = converter.getKeyPair(obj).private
90
+ when PrivateKeyInfo # unencrypted pkcs#8
91
+ private_key = converter.getPrivateKey(obj)
92
+ when PEMEncryptedKeyPair # encrypted pkcs#1
93
+ key_char_array = @ssl_key_passphrase.to_java.toCharArray
94
+ decryptor = JcePEMDecryptorProviderBuilder.new.build(key_char_array)
95
+ key_pair = obj.decryptKeyPair(decryptor)
96
+ private_key = converter.getKeyPair(key_pair).private
97
+ when PKCS8EncryptedPrivateKeyInfo # encrypted pkcs#8
98
+ key_char_array = @ssl_key_passphrase.to_java.toCharArray
99
+ key = JceOpenSSLPKCS8DecryptorProviderBuilder.new.build(key_char_array)
100
+ private_key = converter.getPrivateKey(obj.decryptPrivateKeyInfo(key))
83
101
  else
84
102
  raise "Could not recognize 'ssl_key' format. Class: #{obj.class}"
85
103
  end
86
104
 
87
- @ssl_extra_chain_certs.each do |cert|
88
- cert_chain << cf.generateCertificate(FileInputStream.new(cert))
105
+ @ssl_extra_chain_certs.each do |file|
106
+ fetch_certificates_from_file(file, cf) do |cert|
107
+ cert_chain << cert
108
+ end
89
109
  end
90
- sslContextBuilder = SslContextBuilder.forServer(private_key, @ssl_key_passphrase, cert_chain.to_java(java.security.cert.X509Certificate))
110
+ sslContextBuilder = SslContextBuilder.forServer(private_key, @ssl_key_passphrase, cert_chain.to_java(X509Certificate))
111
+
112
+ trust_certs = []
91
113
 
92
- trust_certs = @ssl_certificate_authorities.map do |cert|
93
- cf.generateCertificate(FileInputStream.new(cert))
114
+ @ssl_certificate_authorities.each do |file|
115
+ fetch_certificates_from_file(file, cf) do |cert|
116
+ trust_certs << cert
117
+ end
94
118
  end
95
119
 
96
120
  if trust_certs.any?
97
- sslContextBuilder.trustManager(trust_certs.to_java(java.security.cert.X509Certificate))
121
+ sslContextBuilder.trustManager(trust_certs.to_java(X509Certificate))
98
122
  end
99
123
 
100
124
  sslContextBuilder.clientAuth(@ssl_verify ? ClientAuth::REQUIRE : ClientAuth::NONE)
101
125
  sslContextBuilder.build()
102
126
  end
127
+
128
+ private
129
+ def fetch_certificates_from_file(file, cf)
130
+ fis = FileInputStream.new(file)
131
+
132
+ while (fis.available > 0) do
133
+ yield cf.generateCertificate(fis)
134
+ end
135
+ ensure
136
+ fis.close if fis
137
+ end
103
138
  end
@@ -391,41 +391,21 @@ describe LogStash::Inputs::Tcp do
391
391
  end
392
392
 
393
393
  context "when ssl_enable is true" do
394
- let(:ssc) { SelfSignedCertificate.new }
395
- let(:certificate_file) { ssc.certificate }
396
- let(:key_file) { ssc.private_key}
397
- let(:queue) { Queue.new }
398
-
399
- let(:config) do
400
- {
401
- "host" => "127.0.0.1",
402
- "port" => port,
403
- "ssl_enable" => true,
404
- "ssl_cert" => certificate_file.path,
405
- "ssl_key" => key_file.path,
406
- "ssl_certificate_authorities" => [ certificate_file.path ]
407
- }
408
- end
409
-
410
394
  let(:input) { subject }
411
- before(:each) { input.register }
412
- after(:each) { ssc.delete }
395
+ let(:queue) { Queue.new }
396
+ before(:each) { subject.register }
413
397
 
414
398
  context "when using a certificate chain" do
415
- let(:chain_of_certificates) { helper.chain_of_certificates }
416
- let(:config) do
417
- {
418
- "host" => "127.0.0.1",
419
- "port" => port,
420
- "ssl_enable" => true,
421
- "ssl_cert" => chain_of_certificates[:b_cert].path,
422
- "ssl_key" => chain_of_certificates[:b_key].path,
423
- "ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
424
- "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ],
425
- "ssl_verify" => true
426
- }
399
+ chain_of_certificates = TcpHelpers.new.chain_of_certificates
400
+
401
+ let(:tcp) do
402
+ begin
403
+ socket = TCPSocket.new("127.0.0.1", port)
404
+ rescue Errno::ECONNREFUSED
405
+ sleep 1
406
+ socket = TCPSocket.new("127.0.0.1", port)
407
+ end
427
408
  end
428
- let(:tcp) { TCPSocket.new("127.0.0.1", port) }
429
409
  let(:sslcontext) do
430
410
  sslcontext = OpenSSL::SSL::SSLContext.new
431
411
  sslcontext.verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -435,23 +415,86 @@ describe LogStash::Inputs::Tcp do
435
415
  sslcontext
436
416
  end
437
417
  let(:sslsocket) { OpenSSL::SSL::SSLSocket.new(tcp, sslcontext) }
438
- let(:input_task) { Stud::Task.new { input.run(queue) } }
439
-
440
- before do
441
- input_task
418
+ let(:message) { "message to #{port}" }
419
+
420
+ context "with a non encrypted private key" do
421
+ let(:config) do
422
+ {
423
+ "host" => "127.0.0.1",
424
+ "port" => port,
425
+ "ssl_enable" => true,
426
+ "ssl_cert" => chain_of_certificates[:b_cert].path,
427
+ "ssl_key" => chain_of_certificates[:b_key].path,
428
+ "ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
429
+ "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ],
430
+ "ssl_verify" => true
431
+ }
432
+ end
433
+ it "should be able to connect and write data" do
434
+ result = TcpHelpers.pipelineless_input(subject, 1) do
435
+ sslsocket.connect
436
+ sslsocket.write("#{message}\n")
437
+ tcp.flush
438
+ sslsocket.close
439
+ tcp.close
440
+ end
441
+ expect(result.size).to eq(1)
442
+ expect(result.first.get("message")).to eq(message)
443
+ end
442
444
  end
443
445
 
444
- it "should be able to connect and write data" do
445
- sslsocket.connect
446
- sslsocket.write("Hello world\n")
447
- tcp.flush
448
- sslsocket.close
449
- tcp.close
450
- result = input_task.thread.join(0.5)
451
- expect(result).to be_nil
452
- expect(queue.size).to eq(1)
446
+ context "when using an encrypted private pkcs1 key" do
447
+ let(:config) do
448
+ {
449
+ "host" => "127.0.0.1",
450
+ "port" => port,
451
+ "ssl_enable" => true,
452
+ "ssl_cert" => chain_of_certificates[:be_cert].path,
453
+ "ssl_key" => chain_of_certificates[:be_key].path,
454
+ "ssl_key_passphrase" => "passpasspassword",
455
+ "ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
456
+ "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ],
457
+ "ssl_verify" => true
458
+ }
459
+ end
460
+ it "should be able to connect and write data" do
461
+ result = TcpHelpers.pipelineless_input(subject, 1) do
462
+ sslsocket.connect
463
+ sslsocket.write("#{message}\n")
464
+ tcp.flush
465
+ sslsocket.close
466
+ tcp.close
467
+ end
468
+ expect(result.size).to eq(1)
469
+ expect(result.first.get("message")).to eq(message)
470
+ end
471
+ end
472
+ context "when using an encrypted private pkcs8 key" do
473
+ let(:config) do
474
+ {
475
+ "host" => "127.0.0.1",
476
+ "port" => port,
477
+ "ssl_enable" => true,
478
+ "ssl_cert" => chain_of_certificates[:be_cert].path,
479
+ "ssl_key" => chain_of_certificates[:be_key_pkcs8].path,
480
+ "ssl_key_passphrase" => "passpasspassword",
481
+ "ssl_extra_chain_certs" => [ chain_of_certificates[:a_cert].path ],
482
+ "ssl_certificate_authorities" => [ chain_of_certificates[:root_ca].path ],
483
+ "ssl_verify" => true
484
+ }
485
+ end
486
+ it "should be able to connect and write data" do
487
+ result = TcpHelpers.pipelineless_input(subject, 1) do
488
+ sslsocket.connect
489
+ sslsocket.write("#{message}\n")
490
+ tcp.flush
491
+ sslsocket.close
492
+ tcp.close
493
+ end
494
+ expect(result.size).to eq(1)
495
+ expect(result.first.get("message")).to eq(message)
496
+ end
453
497
  end
454
-
455
498
  end
456
499
 
457
500
  context "with a poorly-behaving client" do
@@ -459,8 +502,14 @@ describe LogStash::Inputs::Tcp do
459
502
 
460
503
  context "that disconnects before doing TLS handshake" do
461
504
  before do
462
- client = TCPSocket.new("127.0.0.1", port)
463
- client.close
505
+ begin
506
+ client = TCPSocket.new("127.0.0.1", port)
507
+ client.close
508
+ rescue Errno::ECONNREFUSED
509
+ sleep 1
510
+ client = TCPSocket.new("127.0.0.1", port)
511
+ client.close
512
+ end
464
513
  end
465
514
 
466
515
  it "should not negatively impact the plugin" do
@@ -3,11 +3,15 @@ require "logstash/devutils/rspec/spec_helper"
3
3
  require "tempfile"
4
4
  require "stud/temporary"
5
5
 
6
+ java_import 'org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8EncryptorBuilder'
7
+ java_import 'org.bouncycastle.openssl.jcajce.JcaPEMWriter'
8
+ java_import 'org.bouncycastle.openssl.jcajce.JcaPKCS8Generator'
9
+ java_import 'org.bouncycastle.jce.provider.BouncyCastleProvider'
6
10
  # this has been taken from the udp input, it should be DRYed
7
11
 
8
12
  class TcpHelpers
9
13
 
10
- def pipelineless_input(plugin, size, &block)
14
+ def self.pipelineless_input(plugin, size, &block)
11
15
  queue = Queue.new
12
16
  input_thread = Thread.new do
13
17
  plugin.run(queue)
@@ -32,12 +36,32 @@ class TcpHelpers
32
36
  a_cert, a_key = build_certificate(root_ca, root_key, "A_Cert")
33
37
  aa_cert, aa_key = build_certificate(root_ca, root_key, "AA_Cert")
34
38
  b_cert, b_key = build_certificate(a_cert, a_key, "B_Cert")
39
+ be_cert, be_key, be_key_text = build_certificate(a_cert, a_key, "BE_Cert", "passpasspassword")
40
+ be_key_pkcs8 = convert_private_key_to_pkcs8_with_passpharse(be_key, "passpasspassword")
35
41
  c_cert, c_key = build_certificate(b_cert, b_key, "C_Cert")
36
42
  { :root_ca => new_temp_file('', root_ca), :root_key => new_temp_file('', root_key),
37
43
  :a_cert => new_temp_file('', a_cert), :a_key => new_temp_file('', a_key),
38
44
  :aa_cert => new_temp_file('', aa_cert), :aa_key => new_temp_file('', aa_key),
39
45
  :b_cert => new_temp_file('', b_cert), :b_key => new_temp_file('', b_key),
40
- :c_cert => new_temp_file('', c_cert), :c_key => new_temp_file('', c_key)}
46
+ :be_cert => new_temp_file('', be_cert), :be_key => new_temp_file('', be_key_text), :be_key_pkcs8 => new_temp_file('', be_key_pkcs8),
47
+ :c_cert => new_temp_file('', c_cert), :c_key => new_temp_file('', c_key),
48
+ }
49
+ end
50
+
51
+ def convert_private_key_to_pkcs8_with_passpharse(pkcs1key, passphrase)
52
+ pem_parser = PEMParser.new(java.io.StringReader.new(pkcs1key.to_pem))
53
+ kp = pem_parser.read_object
54
+ java.security.Security.addProvider(BouncyCastleProvider.new)
55
+ converter = JcaPEMKeyConverter.new.setProvider("BC")
56
+ key = converter.getPrivateKey(kp.get_private_key_info)
57
+ alg = org.bouncycastle.openssl.PKCS8Generator::PBE_SHA1_RC4_128
58
+ enc = JceOpenSSLPKCS8EncryptorBuilder.new(alg).set_passsword(passphrase.to_java.to_char_array).build
59
+ sw = java.io.StringWriter.new
60
+ writer = JcaPEMWriter.new(sw)
61
+ writer.write_object(JcaPKCS8Generator.new(key, enc))
62
+ writer.flush
63
+ writer.close
64
+ sw
41
65
  end
42
66
 
43
67
  private
@@ -49,12 +73,17 @@ class TcpHelpers
49
73
  file
50
74
  end
51
75
 
52
- def build_certificate(root_ca, root_key=nil, name="")
76
+ def build_certificate(root_ca, root_key, name, password=nil)
53
77
  key = ( root_key.nil? ? OpenSSL::PKey::RSA.new(2048) : root_key )
54
78
  options = { :serial => 2, :subject => "/DC=org/DC=ruby-lang/CN=Ruby#{name}", :key => key, :issuer => root_ca.subject}
55
79
  cert = new_certificate(options)
56
80
  add_ca_extensions(cert, nil, root_ca)
57
- [ cert.sign(key, OpenSSL::Digest::SHA256.new), key ]
81
+ if password
82
+ key_text = key.to_pem(OpenSSL::Cipher::AES256.new(:CFB), password)
83
+ [ cert.sign(key, OpenSSL::Digest::SHA256.new), key, key_text ]
84
+ else
85
+ [ cert.sign(key, OpenSSL::Digest::SHA256.new), key ]
86
+ end
58
87
  end
59
88
 
60
89
  def build_root_ca
data/version CHANGED
@@ -1 +1 @@
1
- 5.2.0
1
+ 5.2.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: 5.2.0
4
+ version: 5.2.1
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-24 00:00:00.000000000 Z
11
+ date: 2019-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -164,7 +164,7 @@ files:
164
164
  - logstash-input-tcp.gemspec
165
165
  - spec/inputs/tcp_spec.rb
166
166
  - spec/spec_helper.rb
167
- - vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/5.2.0/logstash-input-tcp-5.2.0.jar
167
+ - vendor/jar-dependencies/org/logstash/inputs/logstash-input-tcp/5.2.1/logstash-input-tcp-5.2.1.jar
168
168
  - version
169
169
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
170
170
  licenses: