logstash-input-tcp 5.2.0-java → 5.2.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: 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: