From a482f275d6f6be517e22d3f15334cd463e84a898 Mon Sep 17 00:00:00 2001 From: edmocosta <11836452+edmocosta@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:38:57 +0100 Subject: [PATCH 1/6] Fix SSL keystore and truststore support --- build.gradle | 1 + docs/index.asciidoc | 43 ++- lib/logstash/inputs/http.rb | 104 ++++-- spec/fixtures/certs/generate.sh | 2 + .../certs/generated/server_from_root.p12 | Bin 0 -> 6019 bytes spec/fixtures/certs/generated/truststore.jks | Bin 0 -> 1798 bytes spec/inputs/http_spec.rb | 86 ++++- .../inputs/http/util/JksSslBuilder.java | 44 --- .../inputs/http/util/SslSimpleBuilder.java | 204 ++++++++-- .../http/util/SslSimpleBuilderTest.java | 350 ++++++++++++++---- .../inputs/http/util/TestCertificates.java | 21 ++ src/test/resources/certificates/generate.sh | 15 + .../resources/certificates/host-keystore.p12 | Bin 0 -> 5843 bytes src/test/resources/certificates/host.crt | 32 ++ src/test/resources/certificates/host.enc.key | 54 +++ src/test/resources/certificates/host.key | 52 +++ src/test/resources/certificates/root-ca.crt | 34 ++ src/test/resources/certificates/root-ca.key | 52 +++ src/test/resources/certificates/root-ca.srl | 1 + .../resources/certificates/truststore.jks | Bin 0 -> 1862 bytes src/test/resources/host.crt | 32 -- src/test/resources/host.enc.key | 53 --- src/test/resources/host.key | 52 --- src/test/resources/root-ca.crt | 34 -- 24 files changed, 916 insertions(+), 350 deletions(-) create mode 100644 spec/fixtures/certs/generated/server_from_root.p12 create mode 100644 spec/fixtures/certs/generated/truststore.jks delete mode 100644 src/main/java/org/logstash/plugins/inputs/http/util/JksSslBuilder.java create mode 100644 src/test/java/org/logstash/plugins/inputs/http/util/TestCertificates.java create mode 100755 src/test/resources/certificates/generate.sh create mode 100644 src/test/resources/certificates/host-keystore.p12 create mode 100644 src/test/resources/certificates/host.crt create mode 100644 src/test/resources/certificates/host.enc.key create mode 100644 src/test/resources/certificates/host.key create mode 100644 src/test/resources/certificates/root-ca.crt create mode 100644 src/test/resources/certificates/root-ca.key create mode 100644 src/test/resources/certificates/root-ca.srl create mode 100644 src/test/resources/certificates/truststore.jks delete mode 100644 src/test/resources/host.crt delete mode 100644 src/test/resources/host.enc.key delete mode 100644 src/test/resources/host.key delete mode 100644 src/test/resources/root-ca.crt diff --git a/build.gradle b/build.gradle index d28beb86..16d99ce0 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,7 @@ dependencies { testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}" testImplementation 'org.hamcrest:hamcrest-library:2.2' testImplementation "org.apache.logging.log4j:log4j-core:${log4jVersion}" + testImplementation 'org.elasticsearch:securemock:1.2' implementation "io.netty:netty-buffer:${nettyVersion}" implementation "io.netty:netty-codec:${nettyVersion}" diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 2ad05927..5c345413 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -112,7 +112,11 @@ This plugin supports the following configuration options plus the <> |<>|No | <> |<>|No | <> |<>|No +| <> |<>|No | <> |<>|No +| <> |<>|No +| <> |<>|No +| <> |<>|No | <> |<>, one of `["none", "peer", "force_peer"]`|__Deprecated__ | <> |<>|No | <> |<>|__Deprecated__ @@ -405,7 +409,18 @@ SSL key passphrase to use. * Value type is <> * There is no default value for this setting. -The JKS keystore to validate the client's certificates +The path for the keystore file that contains a private key and certificate. +It must be either a Java keystore (jks) or a PKCS#12 file. + +NOTE: You cannot use this setting and <> at the same time. + +[id="plugins-{type}s-{plugin}-ssl_keystore_type"] +===== `ssl_keystore_type` + + * Value can be any of: `jks`, `pkcs12` + * If not provided, the value will be inferred from the keystore filename. + +The format of the keystore file. It must be either `jks` or `pkcs12`. [id="plugins-{type}s-{plugin}-ssl_keystore_password"] ===== `ssl_keystore_password` @@ -432,6 +447,32 @@ NOTE: If you configure the plugin to use `'TLSv1.1'` on any recent JVM, such as the protocol is disabled by default and needs to be enabled manually by changing `jdk.tls.disabledAlgorithms` in the *$JDK_HOME/conf/security/java.security* configuration file. That is, `TLSv1.1` needs to be removed from the list. +[id="plugins-{type}s-{plugin}-ssl_truststore_password"] +===== `ssl_truststore_password` + + * Value type is <> + * There is no default value for this setting. + +Set the truststore password + +[id="plugins-{type}s-{plugin}-ssl_truststore_path"] +===== `ssl_truststore_path` + + * Value type is <> + * There is no default value for this setting. + +The path for the keystore that contains the certificates to trust. It must be either a Java keystore (jks) or a PKCS#12 file. + +NOTE: You cannot use this setting and <> at the same time. + +[id="plugins-{type}s-{plugin}-ssl_truststore_type"] +===== `ssl_truststore_type` + +* Value can be any of: `jks`, `pkcs12` +* If not provided, the value will be inferred from the truststore filename. + +The format of the truststore file. It must be either `jks` or `pkcs12`. + [id="plugins-{type}s-{plugin}-ssl_verify_mode"] ===== `ssl_verify_mode` deprecated[3.7.0, Replaced by <>] diff --git a/lib/logstash/inputs/http.rb b/lib/logstash/inputs/http.rb index df1aeeb8..69c03416 100644 --- a/lib/logstash/inputs/http.rb +++ b/lib/logstash/inputs/http.rb @@ -76,12 +76,24 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base # The JKS keystore password config :ssl_keystore_password, :validate => :password - # The JKS keystore to validate the client's certificates + # The path for the keystore file that contains a private key and certificate config :ssl_keystore_path, :validate => :path + # The format of the keystore file. It must be either jks or pkcs12 + config :ssl_keystore_type, :validate => %w[pkcs12 jks] + # SSL key passphrase to use. config :ssl_key_passphrase, :validate => :password + # Set the truststore password + config :ssl_truststore_password, :validate => :password + + # The path for the keystore that contains the certificates to trust. It must be either a Java keystore (jks) or a PKCS#12 file + config :ssl_truststore_path, :validate => :path + + # The format of the truststore file. It must be either jks or pkcs12 + config :ssl_truststore_type, :validate => %w[pkcs12 jks] + # Validate client certificates against these authorities. # You can define multiple files or paths. All the certificates will # be read and added to the trust store. You need to configure the `ssl_client_authentication` @@ -301,18 +313,31 @@ def validate_ssl_settings! raise LogStash::ConfigurationError, 'An `ssl_certificate` is required when using an `ssl_key`' end - unless ssl_key_configured? || ssl_jks_configured? + unless ssl_certificate_configured? || ssl_keystore_configured? raise LogStash::ConfigurationError, "Either an `ssl_certificate` or `ssl_keystore_path` is required when SSL is enabled `#{ssl_config_name} => true`" end - if require_certificate_authorities? && !certificate_authorities_configured? - config_name, optional, required = provided_client_authentication_config([SSL_CLIENT_AUTH_OPTIONAL, SSL_CLIENT_AUTH_REQUIRED]) - raise LogStash::ConfigurationError, "Using `#{config_name}` set to `#{optional}` or `#{required}`, requires the configuration of `ssl_certificate_authorities`" + if ssl_certificate_configured? && ssl_keystore_configured? + raise LogStash::ConfigurationError, 'Use either an `ssl_certificate` or an `ssl_keystore_path`' end - if !require_certificate_authorities? && certificate_authorities_configured? - config_name, optional, required = provided_client_authentication_config([SSL_CLIENT_AUTH_OPTIONAL, SSL_CLIENT_AUTH_REQUIRED]) - raise LogStash::ConfigurationError, "The configuration of `ssl_certificate_authorities` requires setting `#{config_name}` to `#{optional}` or '#{required}'" + if ssl_certificate_authorities_configured? && ssl_truststore_configured? + raise LogStash::ConfigurationError, 'Use either an `ssl_certificate_authorities` or an `ssl_truststore_path`' + end + + cli_auth_config_name, cli_auth_optional_val, cli_auth_required_val = provided_ssl_client_authentication_config([SSL_CLIENT_AUTH_OPTIONAL, SSL_CLIENT_AUTH_REQUIRED]) + if ssl_client_authentication_enabled? + # Ensure any CA is configured. By default, the keystore can also be used as CA + unless ssl_certificate_authorities_configured? || ssl_truststore_configured? || ssl_keystore_configured? + raise LogStash::ConfigurationError, "Using `#{cli_auth_config_name}` set to `#{cli_auth_optional_val}` or `#{cli_auth_required_val}`, requires the configuration of `ssl_certificate_authorities` or `ssl_truststore_path`" + end + else + if ssl_truststore_configured? + raise LogStash::ConfigurationError, "The configuration of `ssl_truststore_path` requires setting `#{cli_auth_config_name}` to `#{cli_auth_optional_val}` or '#{cli_auth_required_val}'" + end + if ssl_certificate_authorities_configured? + raise LogStash::ConfigurationError, "The configuration of `ssl_certificate_authorities` requires setting `#{cli_auth_config_name}` to `#{cli_auth_optional_val}` or '#{cli_auth_required_val}'" + end end end @@ -372,73 +397,76 @@ def create_http_server(message_handler) def build_ssl_params return nil unless @ssl_enabled - if @ssl_keystore_path && @ssl_keystore_password - ssl_builder = org.logstash.plugins.inputs.http.util.JksSslBuilder.new(@ssl_keystore_path, @ssl_keystore_password.value) - else - ssl_builder = new_ssl_simple_builder - end - - new_ssl_handshake_provider(ssl_builder) + new_ssl_handshake_provider(new_ssl_simple_builder) end def new_ssl_simple_builder - passphrase = @ssl_key_passphrase.nil? ? nil : @ssl_key_passphrase.value begin - ssl_context_builder = SslSimpleBuilder.new(@ssl_certificate, @ssl_key, passphrase) - .setProtocols(@ssl_supported_protocols) - .setCipherSuites(normalized_cipher_suites) + if ssl_keystore_configured? + ssl_context_builder = SslSimpleBuilder.withKeyStore(@ssl_keystore_type, @ssl_keystore_path, @ssl_keystore_password&.value) + else + ssl_context_builder = SslSimpleBuilder.withPemCertificate(@ssl_certificate, @ssl_key, @ssl_key_passphrase&.value) + end - if client_authentication_enabled? - ssl_context_builder.setClientAuthentication(ssl_simple_builder_verify_mode, @ssl_certificate_authorities) + ssl_context_builder.setProtocols(@ssl_supported_protocols) + .setCipherSuites(normalized_cipher_suites) + .setClientAuthentication(ssl_simple_builder_verify_mode) + + if ssl_client_authentication_enabled? + if ssl_certificate_authorities_configured? + ssl_context_builder.setCertificateAuthorities(@ssl_certificate_authorities) + elsif ssl_truststore_configured? + ssl_context_builder.setTrustStore(@ssl_truststore_type, @ssl_truststore_path, @ssl_truststore_password&.value) + end end ssl_context_builder - rescue java.lang.IllegalArgumentException => e + rescue => e @logger.error("SSL configuration invalid", error_details(e)) raise LogStash::ConfigurationError, e end end def ssl_simple_builder_verify_mode - return SslSimpleBuilder::SslClientVerifyMode::OPTIONAL if client_authentication_optional? - return SslSimpleBuilder::SslClientVerifyMode::REQUIRED if client_authentication_required? - return SslSimpleBuilder::SslClientVerifyMode::NONE if client_authentication_none? + return SslSimpleBuilder::SslClientVerifyMode::OPTIONAL if ssl_client_authentication_optional? + return SslSimpleBuilder::SslClientVerifyMode::REQUIRED if ssl_client_authentication_required? + return SslSimpleBuilder::SslClientVerifyMode::NONE if ssl_client_authentication_none? raise LogStash::ConfigurationError, "Invalid `ssl_client_authentication` value #{@ssl_client_authentication}" end - def ssl_key_configured? - !!(@ssl_certificate && @ssl_key) + def ssl_certificate_configured? + !(@ssl_certificate.nil? || @ssl_certificate.empty?) end - def ssl_jks_configured? - !!(@ssl_keystore_path && @ssl_keystore_password) + def ssl_keystore_configured? + !(@ssl_keystore_path.nil? || @ssl_keystore_path.empty?) end - def client_authentication_enabled? - client_authentication_optional? || client_authentication_required? + def ssl_truststore_configured? + !(@ssl_truststore_path.nil? || @ssl_truststore_path.empty?) end - def require_certificate_authorities? - client_authentication_required? || client_authentication_optional? + def ssl_client_authentication_enabled? + ssl_client_authentication_optional? || ssl_client_authentication_required? end - def certificate_authorities_configured? + def ssl_certificate_authorities_configured? @ssl_certificate_authorities && @ssl_certificate_authorities.size > 0 end - def client_authentication_required? + def ssl_client_authentication_required? @ssl_client_authentication && @ssl_client_authentication.downcase == SSL_CLIENT_AUTH_REQUIRED end - def client_authentication_none? + def ssl_client_authentication_none? @ssl_client_authentication && @ssl_client_authentication.downcase == SSL_CLIENT_AUTH_NONE end - def client_authentication_optional? + def ssl_client_authentication_optional? @ssl_client_authentication && @ssl_client_authentication.downcase == SSL_CLIENT_AUTH_OPTIONAL end - def provided_client_authentication_config(values = [@ssl_client_authentication]) + def provided_ssl_client_authentication_config(values = [@ssl_client_authentication]) if original_params.include?('ssl_verify_mode') ['ssl_verify_mode', *values.map { |v| SSL_VERIFY_MODE_TO_CLIENT_AUTHENTICATION_MAP.key(v) }] elsif original_params.include?('verify_mode') diff --git a/spec/fixtures/certs/generate.sh b/spec/fixtures/certs/generate.sh index c1c71498..847428b2 100755 --- a/spec/fixtures/certs/generate.sh +++ b/spec/fixtures/certs/generate.sh @@ -12,11 +12,13 @@ echo "DO NOT USE THESE CERTIFICATES IN PRODUCTION" >> ./README.txt # certificate authority openssl genrsa -out root.key 4096 openssl req -new -x509 -days 1826 -extensions ca -key root.key -out root.crt -subj "/C=LS/ST=NA/L=Http Input/O=Logstash/CN=root" -config ../openssl.cnf +keytool -import -file root.crt -alias rootCA -keystore truststore.jks -noprompt -storepass 12345678 # server certificate from root openssl genrsa -out server_from_root.key 4096 openssl req -new -key server_from_root.key -out server_from_root.csr -subj "/C=LS/ST=NA/L=Http Input/O=Logstash/CN=server" -config ../openssl.cnf openssl x509 -req -extensions server_cert -extfile ../openssl.cnf -days 1096 -in server_from_root.csr -CA root.crt -CAkey root.key -set_serial 03 -out server_from_root.crt +openssl pkcs12 -export -out server_from_root.p12 -inkey server_from_root.key -in server_from_root.crt -certfile root.crt -password pass:12345678 # client certificate from root openssl genrsa -out client_from_root.key 4096 diff --git a/spec/fixtures/certs/generated/server_from_root.p12 b/spec/fixtures/certs/generated/server_from_root.p12 new file mode 100644 index 0000000000000000000000000000000000000000..aec9a662768826b5266eb5ab9ffb407c3bc4b1f7 GIT binary patch literal 6019 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 literal 0 HcmV?d00001 diff --git a/spec/inputs/http_spec.rb b/spec/inputs/http_spec.rb index b594d0ca..15996a19 100644 --- a/spec/inputs/http_spec.rb +++ b/spec/inputs/http_spec.rb @@ -735,6 +735,16 @@ def setup_server_client(url = self.url) end end + context "and with :ssl_keystore_path" do + let(:config) do + super().merge('ssl_keystore_path' => certificate_path( 'server_from_root.p12'), 'ssl_enabled' => true ) + end + + it "should raise a configuration error" do + expect { subject.register }.to raise_error LogStash::ConfigurationError, /Use either an `ssl_certificate` or an `ssl_keystore_path`/i + end + end + context "with ssl_client_authentication" do context "normalized from ssl_verify_mode 'none'" do let(:config) { super().merge("ssl_verify_mode" => "none") } @@ -766,7 +776,7 @@ def setup_server_client(url = self.url) context "with no ssl_certificate_authorities set " do let(:config) { super().reject { |key| "ssl_certificate_authorities".eql?(key) } } it "raise a configuration error" do - expect {subject.register}.to raise_error(LogStash::ConfigurationError, "Using `ssl_verify_mode` set to `peer` or `force_peer`, requires the configuration of `ssl_certificate_authorities`") + expect {subject.register}.to raise_error(LogStash::ConfigurationError, "Using `ssl_verify_mode` set to `peer` or `force_peer`, requires the configuration of `ssl_certificate_authorities` or `ssl_truststore_path`") end end end @@ -786,13 +796,21 @@ def setup_server_client(url = self.url) expect {subject.register}.to raise_error(LogStash::ConfigurationError, "The configuration of `ssl_certificate_authorities` requires setting `ssl_client_authentication` to `optional` or 'required'") end end + + context "with ssl_truststore_path set" do + let(:config) { super().merge("ssl_truststore_path" => [certificate_path( 'server_from_root.p12')], "ssl_truststore_password" => "12345678") } + + it "raise a configuration error" do + expect {subject.register}.to raise_error(LogStash::ConfigurationError, "The configuration of `ssl_truststore_path` requires setting `ssl_client_authentication` to `optional` or 'required'") + end + end end context "configured to 'required'" do let(:config) { super().merge("ssl_client_authentication" => "required") } it "raise a ConfigurationError when certificate_authorities is not set" do - expect {subject.register}.to raise_error(LogStash::ConfigurationError, "Using `ssl_client_authentication` set to `optional` or `required`, requires the configuration of `ssl_certificate_authorities`") + expect {subject.register}.to raise_error(LogStash::ConfigurationError, "Using `ssl_client_authentication` set to `optional` or `required`, requires the configuration of `ssl_certificate_authorities` or `ssl_truststore_path`") end context "with ssl_certificate_authorities set" do @@ -802,13 +820,21 @@ def setup_server_client(url = self.url) expect {subject.register}.not_to raise_error end end + + context "with ssl_truststore_path set" do + let(:config) { super().merge("ssl_truststore_path" => [certificate_path( 'server_from_root.p12')], "ssl_truststore_password" => "12345678") } + + it "doesn't raise a configuration error" do + expect {subject.register}.not_to raise_error + end + end end context "configured to 'optional'" do let(:config) { super().merge("ssl_client_authentication" => "optional") } it "raise a ConfigurationError when certificate_authorities is not set" do - expect {subject.register}.to raise_error(LogStash::ConfigurationError, "Using `ssl_client_authentication` set to `optional` or `required`, requires the configuration of `ssl_certificate_authorities`") + expect {subject.register}.to raise_error(LogStash::ConfigurationError, "Using `ssl_client_authentication` set to `optional` or `required`, requires the configuration of `ssl_certificate_authorities` or `ssl_truststore_path`") end context "with certificate_authorities set" do @@ -818,9 +844,63 @@ def setup_server_client(url = self.url) expect {subject.register}.not_to raise_error end end + + context "with ssl_truststore_path set" do + let(:config) { super().merge("ssl_truststore_path" => [certificate_path( 'server_from_root.p12')], "ssl_truststore_password" => "12345678") } + + it "doesn't raise a configuration error" do + expect {subject.register}.not_to raise_error + end + end + end + end + end + context "with :ssl_keystore_path" do + let(:config) do + { + "port" => port, + "ssl_enabled" => true, + "ssl_keystore_path" => certificate_path( 'server_from_root.p12'), + "ssl_keystore_password" => "12345678" + } + end + + subject { LogStash::Inputs::Http.new(config) } + + it "should not raise exception" do + expect { subject.register }.to_not raise_exception + end + end + context "with :ssl_truststore_path" do + let(:config) do + { + "port" => port, + "ssl_enabled" => true, + "ssl_client_authentication" => "optional", + "ssl_keystore_path" => certificate_path( 'server_from_root.p12'), + "ssl_keystore_password" => "12345678", + "ssl_truststore_path" => certificate_path( 'truststore.jks'), + "ssl_truststore_password" => "12345678" + } + end + + subject { LogStash::Inputs::Http.new(config) } + + it "should not raise exception" do + expect { subject.register }.to_not raise_exception + end + + context "and with :ssl_certificate_authorities configured" do + let(:config) do + super().merge('ssl_certificate_authorities' => [certificate_path( 'root.crt')], 'ssl_enabled' => true ) + end + + it "should raise a configuration error" do + expect { subject.register }.to raise_error LogStash::ConfigurationError, /Use either an `ssl_certificate_authorities` or an `ssl_truststore_path`/i end end end + end end diff --git a/src/main/java/org/logstash/plugins/inputs/http/util/JksSslBuilder.java b/src/main/java/org/logstash/plugins/inputs/http/util/JksSslBuilder.java deleted file mode 100644 index c326278c..00000000 --- a/src/main/java/org/logstash/plugins/inputs/http/util/JksSslBuilder.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.logstash.plugins.inputs.http.util; - -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.TrustManagerFactory; -import java.io.FileInputStream; -import java.security.KeyStore; -import java.security.Security; - -public class JksSslBuilder implements SslBuilder { - private static final String ALGORITHM_SUN_X509 = "SunX509"; - private static final String ALGORITHM = "ssl.KeyManagerFactory.algorithm"; - private final String keyStorePath; - private final char[] keyStorePassword; - - public JksSslBuilder(String keyStorePath, String keyStorePassword) { - this.keyStorePath = keyStorePath; - this.keyStorePassword = keyStorePassword.toCharArray(); - } - - public SslContext build() throws Exception { - String algorithm = Security.getProperty(ALGORITHM); - if (algorithm == null) { - algorithm = ALGORITHM_SUN_X509; - } - KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); - KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType()); - ks.load(new FileInputStream(keyStorePath), keyStorePassword); - ts.load(new FileInputStream(keyStorePath), keyStorePassword); - - KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); - kmf.init(ks, keyStorePassword); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); - tmf.init(ts); - - SslContextBuilder builder = SslContextBuilder.forServer(kmf); - builder.trustManager(tmf); - - return SslSimpleBuilder.doBuild(builder); - } -} diff --git a/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java b/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java index 25f17fa5..f816da72 100644 --- a/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java +++ b/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java @@ -10,18 +10,30 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; +import java.util.Enumeration; import java.util.HashSet; import java.util.List; +import java.util.Locale; +import java.util.Objects; import java.util.Set; import javax.crypto.Cipher; +import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLException; import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.TrustManagerFactory; public class SslSimpleBuilder implements SslBuilder { @@ -86,26 +98,47 @@ public ClientAuth toClientAuth() { private String[] protocols = new String[] { "TLSv1.2", "TLSv1.3" }; private String[] ciphers = getDefaultCiphers(); - private final File sslKeyFile; - private final File sslCertificateFile; + private File sslKeyFile; + private File sslCertificateFile; private String[] certificateAuthorities; - private final String passphrase; + private KeyStore keyStore; + private char[] keyStorePassword; + private KeyStore trustStore; + private String passphrase; private SslClientVerifyMode verifyMode = SslClientVerifyMode.NONE; - public SslSimpleBuilder(String sslCertificateFilePath, String sslKeyFilePath, String pass) { - sslCertificateFile = new File(sslCertificateFilePath); - if (!sslCertificateFile.canRead()) { + public static SslSimpleBuilder withPemCertificate(String sslCertificateFilePath, String sslKeyFilePath, String pass) { + SslSimpleBuilder builder = new SslSimpleBuilder(); + + builder.sslCertificateFile = new File(sslCertificateFilePath); + if (!builder.sslCertificateFile.canRead()) { throw new IllegalArgumentException( String.format("Certificate file cannot be read. Please confirm the user running Logstash has permissions to read: %s", sslCertificateFilePath)); } - sslKeyFile = new File(sslKeyFilePath); - if (!sslKeyFile.canRead()) { + builder.sslKeyFile = new File(sslKeyFilePath); + if (!builder.sslKeyFile.canRead()) { throw new IllegalArgumentException( String.format("Private key file cannot be read. Please confirm the user running Logstash has permissions to read: %s", sslKeyFilePath)); } - passphrase = pass; + builder.passphrase = pass; + return builder; + } + + public static SslSimpleBuilder withKeyStore(String keyStoreType, String keyStoreFile, String keyStorePassword) throws Exception { + SslSimpleBuilder builder = new SslSimpleBuilder(); + final Path keyStorePath = Paths.get(Objects.requireNonNull(keyStoreFile, "Keystore path cannot be null")); + if (!Files.isReadable(keyStorePath)) { + throw new IllegalArgumentException(String.format("Keystore file cannot be read. Please confirm the user running Logstash has permissions to read: %s", keyStoreFile)); + } + + builder.keyStorePassword = formatJksPassword(keyStorePassword); + builder.keyStore = readKeyStore(keyStorePath, resolveKeyStoreType(keyStoreType, keyStorePath), builder.keyStorePassword); + return builder; + } + + private SslSimpleBuilder() { } public SslSimpleBuilder setProtocols(String[] protocols) { @@ -129,16 +162,39 @@ public SslSimpleBuilder setCipherSuites(String[] ciphersSuite) throws IllegalArg return this; } - public SslSimpleBuilder setClientAuthentication(SslClientVerifyMode verifyMode, String[] certificateAuthorities) { - if (isClientAuthenticationEnabled(verifyMode) && (certificateAuthorities == null || certificateAuthorities.length < 1)) { - throw new IllegalArgumentException("Certificate authorities are required to enable client authentication"); + public SslSimpleBuilder setClientAuthentication(SslClientVerifyMode verifyMode) { + this.verifyMode = verifyMode; + return this; + } + + public SslSimpleBuilder setCertificateAuthorities(String[] certificateAuthorities) { + if (certificateAuthorities == null || certificateAuthorities.length == 0){ + throw new IllegalArgumentException("SSL certificate authorities is required"); } - this.verifyMode = verifyMode; this.certificateAuthorities = certificateAuthorities; return this; } + public SslSimpleBuilder setTrustStore(String trustStoreType, String trustStoreFile, String trustStorePassword) throws Exception { + final Path trustStorePath = Paths.get(Objects.requireNonNull(trustStoreFile, "Trust Store path cannot be null")); + if (!Files.isReadable(trustStorePath)) { + throw new IllegalArgumentException(String.format("Trust Store file cannot be read. Please confirm the user running Logstash has permissions to read: %s", trustStoreFile)); + } + + this.trustStore = readKeyStore( + trustStorePath, + resolveKeyStoreType(trustStoreType, trustStorePath), + formatJksPassword(trustStorePassword) + ); + + if (!hasTrustStoreEntry(this.trustStore)) { + logger.warn("The provided Trust Store file does not contains any trusted certificate entry: {}. Please confirm this is the correct certificate and the password is correct", trustStoreFile); + } + + return this; + } + private boolean isClientAuthenticationEnabled(final SslClientVerifyMode mode) { return mode == SslClientVerifyMode.OPTIONAL || mode == SslClientVerifyMode.REQUIRED; } @@ -148,28 +204,80 @@ public boolean isClientAuthenticationRequired() { } public SslContext build() throws Exception { + if (this.trustStore != null && this.certificateAuthorities != null) { + throw new IllegalStateException("Use either an SSL certificate authorities or a Trust Store to configure client authentication"); + } + if (logger.isDebugEnabled()) { logger.debug("Available ciphers: {}", SUPPORTED_CIPHERS); logger.debug("Ciphers: {}", Arrays.toString(ciphers)); } - SslContextBuilder builder = SslContextBuilder - .forServer(sslCertificateFile, sslKeyFile, passphrase) + SslContextBuilder builder = createSslContextBuilder() .ciphers(Arrays.asList(ciphers)) - .protocols(protocols); + .protocols(protocols) + .clientAuth(verifyMode.toClientAuth()); if (isClientAuthenticationEnabled(verifyMode)) { - if (logger.isDebugEnabled()) { - logger.debug("Certificate Authorities: {}", Arrays.toString(certificateAuthorities)); - } + if (certificateAuthorities != null) { + if (logger.isDebugEnabled()) { + logger.debug("Certificate Authorities: {}", Arrays.toString(certificateAuthorities)); + } - builder.clientAuth(verifyMode.toClientAuth()) - .trustManager(loadCertificateCollection(certificateAuthorities)); + builder.trustManager(loadCertificateCollection(certificateAuthorities)); + } else if (trustStore != null || keyStore != null) { + builder.trustManager(createTrustManagerFactory()); + } else { + throw new IllegalStateException("Either an SSL certificate or an SSL Trust Store is required when SSL is enabled"); + } } return doBuild(builder); } + private SslContextBuilder createSslContextBuilder() throws Exception { + if (sslCertificateFile != null) { + return SslContextBuilder.forServer(sslCertificateFile, sslKeyFile, passphrase); + } + + if (keyStore != null) { + return SslContextBuilder.forServer(createKeyManagerFactory()); + } + + throw new IllegalStateException("Either an KeyStore or an SSL certificate must be provided"); + } + + private KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException { + final KeyManagerFactory kmf = getDefaultKeyManagerFactory(); + kmf.init(this.keyStore, this.keyStorePassword); + return kmf; + } + + KeyManagerFactory getDefaultKeyManagerFactory() throws NoSuchAlgorithmException { + return KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + } + + private TrustManagerFactory createTrustManagerFactory() throws Exception { + final TrustManagerFactory tmf = getDefaultTrustManagerFactory(); + if (this.trustStore == null) { + logger.info("SSL Trust Store not configured, using the provided Key Store instead."); + + if (logger.isDebugEnabled() && !hasTrustStoreEntry(this.keyStore)) { + logger.debug("The provided SSL Key Store, used as Trust Store, has no trusted certificate entry."); + } + + tmf.init(this.keyStore); + return tmf; + } + + tmf.init(this.trustStore); + return tmf; + } + + TrustManagerFactory getDefaultTrustManagerFactory() throws NoSuchAlgorithmException { + return TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + } + // NOTE: copy-pasta from input-beats static SslContext doBuild(final SslContextBuilder builder) throws Exception { try { @@ -240,4 +348,58 @@ String[] getCiphers() { SslClientVerifyMode getVerifyMode() { return verifyMode; } + + static String resolveKeyStoreType(String type, Path path) { + if (type == null || type.isEmpty()) { + return inferKeyStoreType(path); + } + return type; + } + + private static String inferKeyStoreType(Path path) { + String name = path == null ? "" : path.getFileName().toString().toLowerCase(Locale.ROOT); + if (name.endsWith(".p12") || name.endsWith(".pfx") || name.endsWith(".pkcs12")) { + return "PKCS12"; + } else { + return "jks"; + } + } + + private static char[] formatJksPassword(String password) { + if (password == null){ + return null; + } + + return password.toCharArray(); + } + + private static KeyStore readKeyStore(Path path, String ksType, char[] password) throws GeneralSecurityException, IOException { + final KeyStore keyStore = KeyStore.getInstance(ksType); + if (path != null) { + try (InputStream in = Files.newInputStream(path)) { + keyStore.load(in, password); + } + } + return keyStore; + } + + private boolean hasTrustStoreEntry(KeyStore store) throws GeneralSecurityException { + Enumeration aliases = store.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + if (store.isCertificateEntry(alias)) { + return true; + } + } + + return false; + } + + KeyStore getKeyStore() { + return keyStore; + } + + KeyStore getTrustStore() { + return trustStore; + } } diff --git a/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java b/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java index 38659ff6..55ae39c5 100644 --- a/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java +++ b/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java @@ -5,16 +5,24 @@ import io.netty.handler.ssl.SslContext; import org.junit.jupiter.api.Test; +import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.TrustManagerFactorySpi; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.Security; import java.util.Arrays; import java.util.List; +import static org.elasticsearch.mock.orig.Mockito.spy; +import static org.elasticsearch.mock.orig.Mockito.verify; +import static org.elasticsearch.mock.orig.Mockito.when; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.arrayWithSize; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.isIn; -import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Every.everyItem; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -26,23 +34,29 @@ import static org.logstash.plugins.inputs.http.util.SslSimpleBuilder.SUPPORTED_CIPHERS; import static org.logstash.plugins.inputs.http.util.SslSimpleBuilder.SslClientVerifyMode; import static org.logstash.plugins.inputs.http.util.SslSimpleBuilder.getDefaultCiphers; -import static org.logstash.plugins.inputs.http.util.TestUtils.resourcePath; +import static org.logstash.plugins.inputs.http.util.TestCertificates.CA; +import static org.logstash.plugins.inputs.http.util.TestCertificates.CERTIFICATE; +import static org.logstash.plugins.inputs.http.util.TestCertificates.KEY; +import static org.logstash.plugins.inputs.http.util.TestCertificates.KEYSTORE; +import static org.logstash.plugins.inputs.http.util.TestCertificates.KEYSTORE_PASSWORD; +import static org.logstash.plugins.inputs.http.util.TestCertificates.KEYSTORE_TYPE; +import static org.logstash.plugins.inputs.http.util.TestCertificates.KEY_ENCRYPTED; +import static org.logstash.plugins.inputs.http.util.TestCertificates.KEY_ENCRYPTED_PASS; +import static org.logstash.plugins.inputs.http.util.TestCertificates.TRUSTSTORE; +import static org.logstash.plugins.inputs.http.util.TestCertificates.TRUSTSTORE_PASSWORD; +import static org.logstash.plugins.inputs.http.util.TestCertificates.TRUSTSTORE_TYPE; +import static org.mockito.Matchers.eq; /** * Unit test for {@link SslSimpleBuilder} */ class SslSimpleBuilderTest { - private static final String CERTIFICATE = resourcePath("host.crt"); - private static final String KEY = resourcePath("host.key"); - private static final String KEY_ENCRYPTED = resourcePath("host.enc.key"); - private static final String KEY_ENCRYPTED_PASS = "1234"; - private static final String CA = resourcePath("root-ca.crt"); @Test - void testConstructorShouldFailWhenCertificatePathIsInvalid() { + void testWithPemCertificateShouldFailWhenCertificatePathIsInvalid() { final IllegalArgumentException thrown = assertThrows( IllegalArgumentException.class, - () -> new SslSimpleBuilder("foo-bar.crt", KEY_ENCRYPTED, KEY_ENCRYPTED_PASS) + () -> SslSimpleBuilder.withPemCertificate("foo-bar.crt", KEY_ENCRYPTED, KEY_ENCRYPTED_PASS) ); assertEquals( @@ -52,10 +66,10 @@ void testConstructorShouldFailWhenCertificatePathIsInvalid() { } @Test - void testConstructorShouldFailWhenKeyPathIsInvalid() { + void testWithPemCertificateShouldFailWhenKeyPathIsInvalid() { final IllegalArgumentException thrown = assertThrows( IllegalArgumentException.class, - () -> new SslSimpleBuilder(CERTIFICATE, "invalid.key", KEY_ENCRYPTED_PASS) + () -> SslSimpleBuilder.withPemCertificate(CERTIFICATE, "invalid.key", KEY_ENCRYPTED_PASS) ); assertEquals( @@ -64,15 +78,44 @@ void testConstructorShouldFailWhenKeyPathIsInvalid() { ); } + @Test + void testWithPemCertificateShouldNotFailWithValidConfig() { + assertDoesNotThrow(this::createPemSslSimpleBuilder); + } + + @Test + void testWithKeyStoreShouldFailWhenKeystorePathIsInvalid() { + final IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> SslSimpleBuilder.withKeyStore(KEYSTORE_TYPE, "foo-bar.jks", KEYSTORE_PASSWORD) + ); + + assertEquals( + "Keystore file cannot be read. Please confirm the user running Logstash has permissions to read: foo-bar.jks", + thrown.getMessage() + ); + } + + @Test + void testWithKeyStoreShouldNotFailWithValidConfig() { + assertDoesNotThrow(this::createJksSslSimpleBuilder); + } + + @Test + void testWithKeyStoreShouldNotFailWithNullType() throws Exception { + final SslSimpleBuilder sslSimpleBuilder = SslSimpleBuilder.withKeyStore(null, KEYSTORE, KEYSTORE_PASSWORD); + assertEquals(KEYSTORE_TYPE, sslSimpleBuilder.getKeyStore().getType()); + } + @Test void testSetCipherSuitesShouldNotFailIfAllCiphersAreValid() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder(); assertDoesNotThrow(() -> sslSimpleBuilder.setCipherSuites(SUPPORTED_CIPHERS.toArray(new String[0]))); } @Test void testSetCipherSuitesShouldThrowIfAnyCiphersIsInValid() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder(); final String[] ciphers = SUPPORTED_CIPHERS .toArray(new String[SUPPORTED_CIPHERS.size() + 1]); @@ -88,7 +131,7 @@ void testSetCipherSuitesShouldThrowIfAnyCiphersIsInValid() { @Test void testSetProtocols() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder(); assertArrayEquals(new String[]{"TLSv1.2", "TLSv1.3"}, sslSimpleBuilder.getProtocols()); sslSimpleBuilder.setProtocols(new String[]{"TLSv1.1"}); @@ -110,66 +153,70 @@ void testGetDefaultCiphers() { } @Test - void testSetClientAuthentication() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); + void testSetCertificateAuthorities() { final String[] certificateAuthorities = {CA}; - sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.REQUIRED, certificateAuthorities); + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED) + .setCertificateAuthorities(certificateAuthorities); assertThat(sslSimpleBuilder.getVerifyMode(), is(SslClientVerifyMode.REQUIRED)); assertThat(Arrays.asList(sslSimpleBuilder.getCertificateAuthorities()), everyItem(isIn(certificateAuthorities))); } @Test - void testSetClientAuthenticationWithRequiredAndNoCertAuthorities() { - assertSetClientAuthenticationThrowsWhenCAIsNullOrEmpty(SslClientVerifyMode.REQUIRED); + void testSetCertificateAuthoritiesWithNoValue() { + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED); + + final IllegalArgumentException emptyThrown = assertThrows( + IllegalArgumentException.class, + ()-> sslSimpleBuilder.setCertificateAuthorities(new String[0]) + ); + + final IllegalArgumentException nullThrown = assertThrows( + IllegalArgumentException.class, + ()-> sslSimpleBuilder.setCertificateAuthorities(null) + ); + + final String expectedMessage = "SSL certificate authorities is required"; + assertEquals(expectedMessage, emptyThrown.getMessage()); + assertEquals(expectedMessage, nullThrown.getMessage()); } @Test - void testSetClientAuthenticationWithOptionalAndNoCertAuthorities() { - assertSetClientAuthenticationThrowsWhenCAIsNullOrEmpty(SslClientVerifyMode.OPTIONAL); + void testSetTrustStoreWithInvalidPath() { + final SslSimpleBuilder sslSimpleBuilder = createJksSslSimpleBuilder(); + + final IllegalArgumentException thrown = assertThrows( + IllegalArgumentException.class, + () -> sslSimpleBuilder.setTrustStore(TRUSTSTORE_TYPE, "trust-me.jks", TRUSTSTORE_PASSWORD) + ); + + assertEquals( + "Trust Store file cannot be read. Please confirm the user running Logstash has permissions to read: trust-me.jks", + thrown.getMessage() + ); } @Test - void testSetClientAuthenticationWithNoneAndEmptyCA() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); - sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.NONE, new String[0]); - assertThat(sslSimpleBuilder.getVerifyMode(), is(SslClientVerifyMode.NONE)); - assertThat(sslSimpleBuilder.getCertificateAuthorities(), arrayWithSize(0)); + void testSetTrustStoreWithValidArguments() { + assertDoesNotThrow(() -> createPemSslSimpleBuilder().setTrustStore(TRUSTSTORE_TYPE, TRUSTSTORE, TRUSTSTORE_PASSWORD)); } @Test - void testSetClientAuthenticationWithNoneAndNullCA() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); - sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.NONE, null); - assertThat(sslSimpleBuilder.getVerifyMode(), is(SslClientVerifyMode.NONE)); - assertThat(sslSimpleBuilder.getCertificateAuthorities(), nullValue()); + void testSetTrustStoreWithNullTrustStoreType() throws Exception { + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder() + .setTrustStore(null, TRUSTSTORE, TRUSTSTORE_PASSWORD); + assertEquals(TRUSTSTORE_TYPE, sslSimpleBuilder.getTrustStore().getType()); } @Test - void testDefaultVerifyMode() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); + void testDefaultVerifyModeIsNone() { + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder(); assertThat(sslSimpleBuilder.getVerifyMode(), is(SslClientVerifyMode.NONE)); } - private void assertSetClientAuthenticationThrowsWhenCAIsNullOrEmpty(SslClientVerifyMode mode) { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); - final String expectedMessage = "Certificate authorities are required to enable client authentication"; - - final IllegalArgumentException emptyThrown = assertThrows( - IllegalArgumentException.class, - () -> sslSimpleBuilder.setClientAuthentication(mode, new String[0]) - ); - - final IllegalArgumentException nullThrown = assertThrows(IllegalArgumentException.class, - () -> sslSimpleBuilder.setClientAuthentication(mode, null), - expectedMessage - ); - - assertEquals(expectedMessage, emptyThrown.getMessage()); - assertEquals(expectedMessage, nullThrown.getMessage()); - } - @Test void testSslClientVerifyModeToClientAuth() { assertThat(SslClientVerifyMode.REQUIRED.toClientAuth(), is(ClientAuth.REQUIRE)); @@ -178,21 +225,28 @@ void testSslClientVerifyModeToClientAuth() { } @Test - void testBuildContextWithNonEncryptedKey() { - final SslSimpleBuilder sslSimpleBuilder = new SslSimpleBuilder(CERTIFICATE, KEY, null); + void testBuildContextWithNonEncryptedCertificateKey() { + final SslSimpleBuilder sslSimpleBuilder = SslSimpleBuilder.withPemCertificate(CERTIFICATE, KEY, null); + assertDoesNotThrow(sslSimpleBuilder::build); + } + + @Test + void testBuildContextWithEncryptedCertificateKey() { + final SslSimpleBuilder sslSimpleBuilder = SslSimpleBuilder.withPemCertificate(CERTIFICATE, KEY_ENCRYPTED, KEY_ENCRYPTED_PASS); assertDoesNotThrow(sslSimpleBuilder::build); } @Test - void testBuildContextWithEncryptedKey() { - final SslSimpleBuilder sslSimpleBuilder = new SslSimpleBuilder(CERTIFICATE, KEY_ENCRYPTED, "1234"); + void testBuildContextWithKeyStore() throws Exception { + final SslSimpleBuilder sslSimpleBuilder = SslSimpleBuilder.withKeyStore(KEYSTORE_TYPE, KEYSTORE, KEYSTORE_PASSWORD); assertDoesNotThrow(sslSimpleBuilder::build); } @Test - void testBuildContextWhenClientAuthenticationIsRequired() throws Exception { - final SSLEngine sslEngine = assertSSlEngineFromBuilder(createSslSimpleBuilder() - .setClientAuthentication(SslClientVerifyMode.REQUIRED, new String[]{CA}) + void testBuildContextWithClientAuthenticationRequiredAndCAs() throws Exception { + final SSLEngine sslEngine = assertSSlEngineFromBuilder(createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED) + .setCertificateAuthorities(new String[]{CA}) ); assertTrue(sslEngine.getNeedClientAuth()); @@ -200,9 +254,32 @@ void testBuildContextWhenClientAuthenticationIsRequired() throws Exception { } @Test - void testBuildContextWhenClientAuthenticationIsOptional() throws Exception { - final SSLEngine sslEngine = assertSSlEngineFromBuilder(createSslSimpleBuilder() - .setClientAuthentication(SslClientVerifyMode.OPTIONAL, new String[]{CA}) + void testBuildContextWithClientAuthenticationRequiredAndTrustStore() throws Exception { + final SSLEngine sslEngine = assertSSlEngineFromBuilder(createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED) + .setTrustStore(TRUSTSTORE_TYPE, TRUSTSTORE, TRUSTSTORE_PASSWORD) + ); + + assertTrue(sslEngine.getNeedClientAuth()); + assertFalse(sslEngine.getWantClientAuth()); + } + + @Test + void testBuildContextWithClientAuthenticationOptionalAndCAs() throws Exception { + final SSLEngine sslEngine = assertSSlEngineFromBuilder(createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.OPTIONAL) + .setCertificateAuthorities(new String[]{CA}) + ); + + assertFalse(sslEngine.getNeedClientAuth()); + assertTrue(sslEngine.getWantClientAuth()); + } + + @Test + void testBuildContextWithClientAuthenticationOptionalAndTrustStore() throws Exception { + final SSLEngine sslEngine = assertSSlEngineFromBuilder(createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.OPTIONAL) + .setTrustStore(TRUSTSTORE_TYPE, TRUSTSTORE, TRUSTSTORE_PASSWORD) ); assertFalse(sslEngine.getNeedClientAuth()); @@ -210,29 +287,128 @@ void testBuildContextWhenClientAuthenticationIsOptional() throws Exception { } @Test - void testBuildContextWhenClientAuthenticationIsNone() throws Exception { - final SSLEngine sslEngine = assertSSlEngineFromBuilder(createSslSimpleBuilder() - .setClientAuthentication(SslClientVerifyMode.NONE, new String[]{CA})); + void testBuildContextWithClientAuthenticationNone() throws Exception { + final SSLEngine sslEngine = assertSSlEngineFromBuilder(createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.NONE)); + + assertFalse(sslEngine.getNeedClientAuth()); + assertFalse(sslEngine.getWantClientAuth()); + } + + @Test + void testBuildContextWithClientAuthenticationNoneAndTrustStore() throws Exception { + final SSLEngine sslEngine = assertSSlEngineFromBuilder(createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.NONE) + .setTrustStore(TRUSTSTORE_TYPE, TRUSTSTORE, TRUSTSTORE_PASSWORD) + ); assertFalse(sslEngine.getNeedClientAuth()); assertFalse(sslEngine.getWantClientAuth()); } + @Test + void testBuildContextWithClientAuthenticationAndKeyStoreAsTrustStore() throws Exception { + final SSLEngine sslEngine = assertSSlEngineFromBuilder(createJksSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED) + ); + + assertTrue(sslEngine.getNeedClientAuth()); + assertFalse(sslEngine.getWantClientAuth()); + } + + @Test + void testBuildContextWithCAsAndTrustStore() throws Exception { + final SslSimpleBuilder sslSimpleBuilder = createJksSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED) + .setCertificateAuthorities(new String[]{CA}) + .setTrustStore(TRUSTSTORE_TYPE, TRUSTSTORE, TRUSTSTORE_PASSWORD); + + final IllegalStateException thrown = assertThrows( + IllegalStateException.class, + sslSimpleBuilder::build + ); + + assertEquals("Use either an SSL certificate authorities or a Trust Store to configure client authentication", thrown.getMessage()); + } + + @Test + void testBuildContextWithPemCertificateAndNoCAsNeitherTrustStore() { + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED); + + final IllegalStateException thrown = assertThrows( + IllegalStateException.class, + sslSimpleBuilder::build + ); + + assertEquals("Either an SSL certificate or an SSL Trust Store is required when SSL is enabled", thrown.getMessage()); + } + @Test void testIsClientAuthenticationRequired() { - final SslSimpleBuilder sslSimpleBuilder = createSslSimpleBuilder(); - final String[] certificateAuthorities = {CA}; + final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder(); - sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.NONE, certificateAuthorities); + sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.NONE); assertFalse(sslSimpleBuilder.isClientAuthenticationRequired()); - sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.OPTIONAL, certificateAuthorities); + sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.OPTIONAL); assertFalse(sslSimpleBuilder.isClientAuthenticationRequired()); - sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.REQUIRED, certificateAuthorities); + sslSimpleBuilder.setClientAuthentication(SslClientVerifyMode.REQUIRED); assertTrue(sslSimpleBuilder.isClientAuthenticationRequired()); } + @Test + void testClientAuthenticationWithTrustStoreUsesTruststore() throws Exception { + final SslSimpleBuilder jksSslBuilder = spy(createJksSslSimpleBuilder()) + .setClientAuthentication(SslClientVerifyMode.REQUIRED) + .setTrustStore(TRUSTSTORE_TYPE, TRUSTSTORE, TRUSTSTORE_PASSWORD); + + final DummyTrustManagerFactorySpi factorySpi = spy(new DummyTrustManagerFactorySpi()); + final TrustManagerFactory trustManagerFactory = new DummyTrustManagerFactory(factorySpi); + + when(jksSslBuilder.getDefaultTrustManagerFactory()) + .thenReturn(trustManagerFactory); + + jksSslBuilder.build(); + + verify(factorySpi).engineInit(eq(jksSslBuilder.getTrustStore())); + } + + @Test + void testClientAuthenticationUsesKeystoreWhenNoTrustStoreIsConfigured() throws Exception { + final SslSimpleBuilder jksSslBuilder = spy(createJksSslSimpleBuilder()); + jksSslBuilder.setClientAuthentication(SslClientVerifyMode.REQUIRED); + + final DummyTrustManagerFactorySpi factorySpi = spy(new DummyTrustManagerFactorySpi()); + final TrustManagerFactory trustManagerFactory = new DummyTrustManagerFactory(factorySpi); + + when(jksSslBuilder.getDefaultTrustManagerFactory()) + .thenReturn(trustManagerFactory); + + jksSslBuilder.build(); + + verify(factorySpi).engineInit(eq(jksSslBuilder.getKeyStore())); + } + + @Test + void testResolveKeyStoreType() { + assertEquals("PKCS12", SslSimpleBuilder.resolveKeyStoreType(null, Paths.get("dummy.p12"))); + assertEquals("PKCS12", SslSimpleBuilder.resolveKeyStoreType(null, Paths.get("dummy.P12"))); + + assertEquals("PKCS12", SslSimpleBuilder.resolveKeyStoreType(null, Paths.get("dummy.pfx"))); + assertEquals("PKCS12", SslSimpleBuilder.resolveKeyStoreType(null, Paths.get("dummy.PfX"))); + + assertEquals("PKCS12", SslSimpleBuilder.resolveKeyStoreType(null, Paths.get("dummy.pkcs12"))); + assertEquals("PKCS12", SslSimpleBuilder.resolveKeyStoreType(null, Paths.get("dummy.PKCS12"))); + + assertEquals("jks", SslSimpleBuilder.resolveKeyStoreType(null, Paths.get("dummy.anyOther"))); + + assertEquals("foo", SslSimpleBuilder.resolveKeyStoreType("foo", Paths.get("foo.p12"))); + assertEquals("bar", SslSimpleBuilder.resolveKeyStoreType("bar", Paths.get("bar.pfx"))); + assertEquals("any", SslSimpleBuilder.resolveKeyStoreType("any", Paths.get("any.pkcs12"))); + } + private SSLEngine assertSSlEngineFromBuilder(SslSimpleBuilder sslSimpleBuilder) throws Exception { final SslContext context = sslSimpleBuilder.build(); assertTrue(context.isServer()); @@ -244,7 +420,37 @@ private SSLEngine assertSSlEngineFromBuilder(SslSimpleBuilder sslSimpleBuilder) return sslEngine; } - private SslSimpleBuilder createSslSimpleBuilder() { - return new SslSimpleBuilder(CERTIFICATE, KEY_ENCRYPTED, KEY_ENCRYPTED_PASS); + private SslSimpleBuilder createPemSslSimpleBuilder() { + return SslSimpleBuilder.withPemCertificate(CERTIFICATE, KEY_ENCRYPTED, KEY_ENCRYPTED_PASS); + } + + private SslSimpleBuilder createJksSslSimpleBuilder() { + try { + return SslSimpleBuilder.withKeyStore(KEYSTORE_TYPE, KEYSTORE, KEYSTORE_PASSWORD); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static class DummyTrustManagerFactorySpi extends TrustManagerFactorySpi { + @Override + public void engineInit(KeyStore ks) { + } + + @Override + public void engineInit(ManagerFactoryParameters spec) { + + } + + @Override + protected TrustManager[] engineGetTrustManagers() { + return new TrustManager[0]; + } + } + + private static class DummyTrustManagerFactory extends TrustManagerFactory { + DummyTrustManagerFactory(TrustManagerFactorySpi spi) { + super(spi, Security.getProviders()[0], "SunX509"); + } } } \ No newline at end of file diff --git a/src/test/java/org/logstash/plugins/inputs/http/util/TestCertificates.java b/src/test/java/org/logstash/plugins/inputs/http/util/TestCertificates.java new file mode 100644 index 00000000..6f0fdb6d --- /dev/null +++ b/src/test/java/org/logstash/plugins/inputs/http/util/TestCertificates.java @@ -0,0 +1,21 @@ +package org.logstash.plugins.inputs.http.util; + +import static org.logstash.plugins.inputs.http.util.TestUtils.resourcePath; + +interface TestCertificates { + String CERTIFICATE = resourcePath("certificates/host.crt"); + String KEY = resourcePath("certificates/host.key"); + String KEY_ENCRYPTED = resourcePath("certificates/host.enc.key"); + String KEY_ENCRYPTED_PASS = "changeme"; + String CA = resourcePath("certificates/root-ca.crt"); + + + String KEYSTORE = resourcePath("certificates/host-keystore.p12"); + String KEYSTORE_TYPE = "PKCS12"; + String KEYSTORE_PASSWORD = "changeme"; + + + String TRUSTSTORE = resourcePath("certificates/truststore.jks"); + String TRUSTSTORE_TYPE = "jks"; + String TRUSTSTORE_PASSWORD = "changeme"; +} diff --git a/src/test/resources/certificates/generate.sh b/src/test/resources/certificates/generate.sh new file mode 100755 index 00000000..07d173c0 --- /dev/null +++ b/src/test/resources/certificates/generate.sh @@ -0,0 +1,15 @@ +# Warning: do not use the certificates produced by this tool in production. This is for testing purposes only +# CA +openssl genrsa 4096 | openssl pkcs8 -topk8 -nocrypt -out root-ca.key +openssl req -sha256 -x509 -newkey rsa:4096 -nodes -key root-ca.key -sha256 -days 999999 -out root-ca.crt -subj "/C=ES/ST=The Internet/L=The Internet/O=Logstash CA/OU=Logstash/CN=127.0.0.1" +keytool -import -file root-ca.crt -alias rootCA -keystore truststore.jks -noprompt -storepass changeme + +# Server +openssl genrsa 4096 | openssl pkcs8 -topk8 -nocrypt -out host.key +openssl req -sha256 -key host.key -newkey rsa:4096 -out host.csr -subj "/C=ES/ST=The Internet/L=The Internet/O=Logstash CA/OU=Logstash/CN=127.0.0.1" +openssl x509 -req -in host.csr -CA root-ca.crt -CAkey root-ca.key -CAcreateserial -out host.crt -sha256 -days 999999 +openssl pkcs12 -export -out host-keystore.p12 -inkey host.key -in host.crt -certfile root-ca.crt -password pass:changeme +openssl pkcs8 -topk8 -passout "pass:changeme" -in host.key -out host.enc.key + +rm -rf ./*.csr +rm -rf ./*.srl \ No newline at end of file diff --git a/src/test/resources/certificates/host-keystore.p12 b/src/test/resources/certificates/host-keystore.p12 new file mode 100644 index 0000000000000000000000000000000000000000..044a0afb45fd4bb0e9ca4962d1221a4047b9a3bf GIT binary patch literal 5843 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 R?Cy>NoKKqJVgHGG{{vZS@lgN( literal 0 HcmV?d00001 diff --git a/src/test/resources/certificates/host.crt b/src/test/resources/certificates/host.crt new file mode 100644 index 00000000..539826c4 --- /dev/null +++ b/src/test/resources/certificates/host.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFeTCCA2ECFBXbdq6k5O7NPXVDva8uMq7VU8ZlMA0GCSqGSIb3DQEBCwUAMHgx +CzAJBgNVBAYTAkVTMRUwEwYDVQQIDAxUaGUgSW50ZXJuZXQxFTATBgNVBAcMDFRo +ZSBJbnRlcm5ldDEUMBIGA1UECgwLTG9nc3Rhc2ggQ0ExETAPBgNVBAsMCExvZ3N0 +YXNoMRIwEAYDVQQDDAkxMjcuMC4wLjEwIBcNMjMxMTE1MTQxNTUxWhgPNDc2MTEw +MTExNDE1NTFaMHgxCzAJBgNVBAYTAkVTMRUwEwYDVQQIDAxUaGUgSW50ZXJuZXQx +FTATBgNVBAcMDFRoZSBJbnRlcm5ldDEUMBIGA1UECgwLTG9nc3Rhc2ggQ0ExETAP +BgNVBAsMCExvZ3N0YXNoMRIwEAYDVQQDDAkxMjcuMC4wLjEwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQC0foYD+YvW8POFHaPllMD/KTzaIxo6yGpbhX5e +EzFOODjG3Z2WuVoojUli8LRKOBU2LRCQpNTfE+0YdGHPeaFoOgNT4QbamVXHtOkr ++GE5bVCXB48fqU8/xrP3YNmZfZE+wax+xWExn7+mrbWbiz6VpRVkZIPcWiKHXlPJ +MUteLRDVTPlnqB4kaktaQ/husqlcbvorNfTtsaJCK6ImyVEWi6zvIyhJtDF2C8C8 +0Gf/Ph/DCIMJeETgnF9iqIWo/Ixw/B5wW9Um4ew/hznnjzcAFaB7oLU4OLaEycvR +cu6J3DsoZy5cczzBcJkjicx7vbF2Bqf1uNj2JyXNqt+AdWQ5ZX2tAySxwuDLo0CK +OdJDl1vuII58iaESED2Za6XhEXeAPUAIzOsbJCXzzwZLtPp0dd8J8Fo1laPc+I0Q +v4pr+4m2xgLnMCUjZzZsYftlt3mvBtr0IZ5s9zUA4eujj8pKRUgnrJQozbR0prDf +OGrMhYunOBYSOq91uI61afmFujFWIyM9Ulr+aEwDRrfEciF47g3Ft3Y4xh23Ukna +oI+FAJZC1V1XaUutx1umeJUGY1qOKyraggMZULWCHk0PeArreMW338RgG+yYxpFC +oyf6JCx6IHiaEVNOISo3JRzNzKJvjIjAmh56phYli9bYQseUme9Xq99hAXtDxZXT +FeGt7wIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQADGYGKj9wWMf6Baj/Pr6R3uMXc +9yqmCf15mHsmmjiSB3zsSf8tfHc3sn0BnEX5U0vS7EIt0TW2LwMlEsU6K+qe5BAv +WxF4VqrqBWnHWkGi0mVPB/IkUlA6/NQbj1XQH7+Irop9ewMme9x/AGubRgqNyvtv +sVXvZy/XdQ3ZSpstmIl/OqzGDjX5CXbGeNPhAEtnWfMZXpBm7wDI/cye1bZI8+y/ +bH8iwHtpGHZXSiTR73cG3QSw1oSRJ2rX+By4L33THemD7AMymi5m5Dl82UKxVco4 +DotrIu3GKNrym8F7B5WmTNyUa/aa3HPRvrMXRM9XEwvof0fFiNvoviOodfsXrGjy +gr7m0NfkglL32aZj3ffcn2gBMEpYIMLuUE8OiG9YZB7dlRjihvUAWmZcUBaSGh1Y +rOmGm2EWd6TpSAIRG+2/PeGHoEu773n4Qe56VmHZ5z/cbqrUIvA3yd+INmudt+GT +u18rmt9gUVesRqrR8vhkI5oJBzz1k8Zen2s6MFpJ0tUIXKH3xt0953fFu0UqYf9J +xGxE9R4YBLc9fwsqDqmknGek4zxH4mMySiEiTBInIKXJu7t8jU7FFpfOpVm0tcRr +AGr+dv5AhwrEc2zUU87vWysfVZzVqu9N4ENTYUh96uM1amfJVt7tPDrpsDAB2Prk +idL9Q+QpOvWSDyFS2w== +-----END CERTIFICATE----- diff --git a/src/test/resources/certificates/host.enc.key b/src/test/resources/certificates/host.enc.key new file mode 100644 index 00000000..301a6a0e --- /dev/null +++ b/src/test/resources/certificates/host.enc.key @@ -0,0 +1,54 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +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 +-----END ENCRYPTED PRIVATE KEY----- diff --git a/src/test/resources/certificates/host.key b/src/test/resources/certificates/host.key new file mode 100644 index 00000000..c6a7ec55 --- /dev/null +++ b/src/test/resources/certificates/host.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +w5W8n4FakTGMeSV3N4sjO2njwP2lIg== +-----END PRIVATE KEY----- diff --git a/src/test/resources/certificates/root-ca.crt b/src/test/resources/certificates/root-ca.crt new file mode 100644 index 00000000..7aa5e05a --- /dev/null +++ b/src/test/resources/certificates/root-ca.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +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 +ZbxJygnaWA== +-----END CERTIFICATE----- diff --git a/src/test/resources/certificates/root-ca.key b/src/test/resources/certificates/root-ca.key new file mode 100644 index 00000000..ea6d4cb6 --- /dev/null +++ b/src/test/resources/certificates/root-ca.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +kc6q2HJgyEXdg0HTeTvM+RMmkPmDew== +-----END PRIVATE KEY----- diff --git a/src/test/resources/certificates/root-ca.srl b/src/test/resources/certificates/root-ca.srl new file mode 100644 index 00000000..9aeae6c3 --- /dev/null +++ b/src/test/resources/certificates/root-ca.srl @@ -0,0 +1 @@ +1AC05519C300E6D21EE96D118E24EE4D622F313F diff --git a/src/test/resources/certificates/truststore.jks b/src/test/resources/certificates/truststore.jks new file mode 100644 index 0000000000000000000000000000000000000000..b7ee170ef79b3504a9a3d62c849dc76c9ce2bb80 GIT binary patch literal 1862 zcmV-M2f6q#f(JqZ0Ru3C2J8k2Duzgg_YDCD0ic2g-2{RL*)W0z)i8nv(FO@BhDe6@ z4FLxRpn?X%FoFiY0s#Opf(Ew+2`Yw2hW8Bt2LUi<1_>&LNQU+thDZTr0|Wso1Q6pGlU_EpgF18qi_U6oJjZ~720(g%yS1kdAxRb<{dCbn&enZQ z^LMPPUMkNfW%~S;Pth+pU;XK0#?K~WW_;R&#b*b4d*RIV=#HM#DL*WMfZ>lcr==Ah z1~^_i;TPiYd+-mWYYYBK#f{A}7!TQrh-rBR9{}%d9+getG?`rG;U7ubPk2jdt8UN}fdlfIi zEX|9MiKjdExqsNHfd@}Zwo8PKVwlZ8VNdk&p9t|uAN4bhECzy5Y?WrVc~^G->uOs6pVdOE{8#G9WURwMq zpTzkxMyRe#I04+PvF8*S*wKP$|C5qAGB#uRDK7ap;+7Ec;l%XQ{jD_{A{E$-MrQgw zTBm3!kF{o9oj*YtYDX*IG@AN>XMuj~D!xM^|G3~?ZmoHCfU{tIPCknMb_P0V<`4@= zQT#y@z~9IGE8oDbK!_+4&h%pf;unYu#EjWiW`{ z=#`lu8T;@am&`xoekdlJGN!A@Q6NkYsA!?ciem?H4gW9Nf2wsn|@gf8v-o-{4Au)JUQ5J9T z6LR5wbjE$YEwq5Dvu_ool&aPGGQi|GxWx`hw+2IzK4{0vI#3 zEH>uL;9bL_A?vwYO5I-c%~d1b8?pGaASw>abyE`*p>w62-5_gQ*bpdO*&T05oj47m zp%w?LQSnkl8NR+~^xRPH0-bVwee=AmnMgaNw_jk+&YrX9jNl|}ZWCQM#9e(CSF(<~ zhrswG^OmA>?!yI9%Q?ezsW3&WgYLxH1|ABhPAgYWO0k_dGG^^4sTeD?B#n;aM*!ff|EZ=CCNlekDDEyr?DydfCJ1oJ zFAKDm=w;D%uVK;R1Tzlm)26E5@dC-F)zCHaibM@q>r^>ylpQE=nFJ zHA5}P+7i7B6JuEOS+xF*6!~91^zsSn7co?A=h=4A;~1I><8YC7*oI+At zC`CXN{eF+J44Y^_;(qmjEWwk#ryIw_Gomvk2|y$*&NCByKU3w-BeUVLz;Nng50K`#6}_3LFNZf#?45~I48}mz=r1sE?bz(O4m2nsAWD~ z0bh|bljlPNql6k7fAFfywpz9PpVde=)Szg;X{KHf=Mh8UGEm1UJ<_YzB}r+ehx#7` z4&FsY4JJl~p-=vN3h~vfh8TI)vXY~aQA<#N>>g55Q;&bLJnU$YF`+)zof`>s0x@xO zjGFqQe;=*WU~TW@J2Ku;)pjfHEo6R);UC7;(%H?}g@D#$^> zBVGSB?;c_k$Io~AhhuHeoUqM}U5Hbm=m4FrrO3rny&eaaUU*B-ZtY(RT=7Qt_RTNF zk|?=gF>Hcvq;L1idDZ@byDURP_BBx{=LmL1nQ)|?nPbcHUv5C#hfz!@rc$7pc7c~o zk}?)lLaM*~^0uf)zUy|zzR=wsi7qHLcXnF9I%GLLJ*~5LicjaL!V87BLDAjjn5SPq zT{m+jn!aJv+dw}RhUcPJZpzG9RR`H9qF)WgVfb}EZ=1)AI_VZ5qR6+vz}eR z$4@=*e%5vb$w}nj;;|PNl=ALNPq7F%OnEqeDB!jRT2PzJ{yW&QntS%2aP*KJ+NC9O71OfpC00bax{P~GqgP#OT z1PgXy-5@~o2rSU*<}1U|Yh=rUf)9=a6jOwHV=LkPhP~Am%eaAjOn0j86aoS#5Gqq_ A?EnA( literal 0 HcmV?d00001 diff --git a/src/test/resources/host.crt b/src/test/resources/host.crt deleted file mode 100644 index 63c22df9..00000000 --- a/src/test/resources/host.crt +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFezCCA2MCFAwv/gPfChqhnJU0fI/a3Ft3A8DTMA0GCSqGSIb3DQEBCwUAMHgx -CzAJBgNVBAYTAlVTMRUwEwYDVQQIDAxUaGUgSW50ZXJuZXQxFTATBgNVBAcMDFRo -ZSBJbnRlcm5ldDEUMBIGA1UECgwLTG9nc3Rhc2ggQ0ExETAPBgNVBAsMCExvZ3N0 -YXNoMRIwEAYDVQQDDAlsb2NhbGhvc3QwIBcNMjMwMzMwMTEzOTIzWhgPMjI5NzAx -MTExMTM5MjNaMHoxCzAJBgNVBAYTAlVTMRUwEwYDVQQIDAxUaGUgSW50ZXJuZXQx -FTATBgNVBAcMDFRoZSBJbnRlcm5ldDEWMBQGA1UECgwNTG9nc3Rhc2ggSG9zdDER -MA8GA1UECwwITG9nc3Rhc2gxEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZI -hvcNAQEBBQADggIPADCCAgoCggIBAOwLooFUlwzwae9GACzrlO/E+b0w1yAsRRYP -0yD3EfCogTjGibHEV/MM3y34ZSUUExZWERt1SXs3SPqfUTOkDhXjAzu8HbNjBJk3 -3R6Yzju+kJGxSxtheQLK+9tjP2O6/j6KXFhMwB7RqfN/aEB+BtmDBAdiTRuMMrWs -qViAcMt76of8lvnUXhvb7K1Um17eyc9wv7JLQN5TSG5EtB4x6zqvbfmTcCXLa7D8 -9PN3ayaBSLxAllv82RWts11i+PnVHYyU24qmdwmRIv6eKN9BRmgPqKw34yeCk4xT -T8pDXoiS9vGXxmrU1i1pZNUeVEAN+h4o8sWcseItUKsPSFFYga653XFtqzxyk4Cq -3gEPp05yH7s68T6T2H+CAyV0YuOgAL6gtt2Y97+oTwjJ1pxLjUaVz5nOjFZqxBQC -hjBItBtpO+wtngZbErfziWx2PTTSJ99lI1KSQbC8cBEUYXG3kdiiUHUm8meq7Mja -8OjUiSi2x2Qv1WBvHrbOpw5Vw1/v8QcW/OY1TwdByW4iJnBiqw+p1hA6bGANc+sP -Lcr5jz7VPHuAxRNecQmqvhjAHGIAkqCJecT9314lgehM3YpcsDVLXnGT96FF5Aq0 -LSEDKFTyC1OXDf2pfQOu9yVTz/SXSr91kj+3+ZeY9Ot9D8L1Xu6dwMsmf/CtV3+4 -lPRbQEEDAgMBAAEwDQYJKoZIhvcNAQELBQADggIBADygVFQGSy4R2htt6WX4DCb7 -FiB/KSxmhh2K+mRC77sqGDP3xRfHsWh2s1eejDde0Vp1OBjDXjsWidFuGzxhV3WC -svt5K8y47+wFboFKuIJUlK17mM3NlsArfwI2/58zIdMokJttSwX37M/jZamTG5kK -xqr3gpGjUxr+qPEizlsFlx1T4d2XIRu8/RZMoqHxI1IZSxlU6GYsvUa2T3vzz9/C -WCxj+CJ1kUnYf3SxeGX+IPVid55LOyWicRO5hKVfKfL1c9AwGL6+0lFYFdz+q5Ku -AMZ0KHk11up4c5oB8xrSet/WHRqIgEy78JxfolkIT5wAlx3sTcmo9mZOjv2tB2AD -1H95Sod/dAD84EWM5Epbt2wlldAGpMbxWH7Yp5gpH5PP8lob9ImNcf9v+wkj9alK -n+C/yhA+B8+hxPClHHgM6M4bdaXREjZ5iYa68riZtBQ3SuIWHJgOl3ZPInRs01kA -IvVFteKu5S4pnEXLAP5EpcM6Mpoxvf+H5z5sdxq3R7uVrbpmzRm7FtW188x0e/dB -ydA2Oz3kSWzwDHRc/WWglbHingf1472aNM02lPuUeN4ALILtIu38e/9IvhhyOkm9 -o7w0jVXCsB/hCcnfchgwG33NvWB2BZ/Zc5f2nTufxUYNODE2MZDaZYZeKd8LzerW -buJc6LvltjYly0HXsNf0 ------END CERTIFICATE----- diff --git a/src/test/resources/host.enc.key b/src/test/resources/host.enc.key deleted file mode 100644 index a7d420ef..00000000 --- a/src/test/resources/host.enc.key +++ /dev/null @@ -1,53 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -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 -DR5g0lBs888AHpjmPQ== ------END ENCRYPTED PRIVATE KEY----- diff --git a/src/test/resources/host.key b/src/test/resources/host.key deleted file mode 100644 index 7c171495..00000000 --- a/src/test/resources/host.key +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -C8kebbjUgzIkPvLG87A6BCgFBj2p9UU= ------END PRIVATE KEY----- diff --git a/src/test/resources/root-ca.crt b/src/test/resources/root-ca.crt deleted file mode 100644 index f6c5a76c..00000000 --- a/src/test/resources/root-ca.crt +++ /dev/null @@ -1,34 +0,0 @@ ------BEGIN CERTIFICATE----- -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 -jMMZNVWQzQ== ------END CERTIFICATE----- From bfe820c572f95017960148ccc34d7e6b55bbe811 Mon Sep 17 00:00:00 2001 From: edmocosta <11836452+edmocosta@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:20:25 +0100 Subject: [PATCH 2/6] Fix SSL keystore and truststore support --- src/test/resources/certificates/root-ca.srl | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/test/resources/certificates/root-ca.srl diff --git a/src/test/resources/certificates/root-ca.srl b/src/test/resources/certificates/root-ca.srl deleted file mode 100644 index 9aeae6c3..00000000 --- a/src/test/resources/certificates/root-ca.srl +++ /dev/null @@ -1 +0,0 @@ -1AC05519C300E6D21EE96D118E24EE4D622F313F From dd8e7d4e366ff0d9d30e4dc5792005bf5275f87b Mon Sep 17 00:00:00 2001 From: edmocosta <11836452+edmocosta@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:59:24 +0100 Subject: [PATCH 3/6] Update CHANGELOG and bump version --- CHANGELOG.md | 5 +++++ VERSION | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efb046df..881436bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.8.0 + - Fixed SSL Java KeyStore support [#171](https://github.com/logstash-plugins/logstash-input-http/pull/171) + - Added `ssl_keystore_type` configuration + - Added SSL Java TrustStore configurations (`ssl_truststore_type`, `ssl_truststore_path` and `ssl_truststore_password`) + ## 3.7.3 - bump netty to 4.1.100 [#170](https://github.com/logstash-plugins/logstash-input-http/pull/170) diff --git a/VERSION b/VERSION index c1e43e6d..19811903 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.7.3 +3.8.0 From 30a9478e8dbdcb71c139536b2ed9fa17122a35a8 Mon Sep 17 00:00:00 2001 From: Edmo Vamerlatti Costa <11836452+edmocosta@users.noreply.github.com> Date: Mon, 27 Nov 2023 17:54:31 +0100 Subject: [PATCH 4/6] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Duarte --- spec/fixtures/certs/generate.sh | 3 +++ .../logstash/plugins/inputs/http/util/SslSimpleBuilder.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/spec/fixtures/certs/generate.sh b/spec/fixtures/certs/generate.sh index 847428b2..95549791 100755 --- a/spec/fixtures/certs/generate.sh +++ b/spec/fixtures/certs/generate.sh @@ -12,6 +12,9 @@ echo "DO NOT USE THESE CERTIFICATES IN PRODUCTION" >> ./README.txt # certificate authority openssl genrsa -out root.key 4096 openssl req -new -x509 -days 1826 -extensions ca -key root.key -out root.crt -subj "/C=LS/ST=NA/L=Http Input/O=Logstash/CN=root" -config ../openssl.cnf +# using keytool here as openssl < 3.2 won't add the "2.16.840.1.113894.746875.1.1" OID to make the cert "trusted" # See more: +# * https://github.com/openssl/openssl/pull/19025 +# * https://github.com/openssl/openssl/commit/e869c867c1c405de3b6538586f17b67937556a4b keytool -import -file root.crt -alias rootCA -keystore truststore.jks -noprompt -storepass 12345678 # server certificate from root diff --git a/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java b/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java index f816da72..955326fc 100644 --- a/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java +++ b/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java @@ -205,7 +205,7 @@ public boolean isClientAuthenticationRequired() { public SslContext build() throws Exception { if (this.trustStore != null && this.certificateAuthorities != null) { - throw new IllegalStateException("Use either an SSL certificate authorities or a Trust Store to configure client authentication"); + throw new IllegalStateException("Use either a bundle of Certificate Authorities or a Trust Store to configure client authentication"); } if (logger.isDebugEnabled()) { @@ -244,7 +244,7 @@ private SslContextBuilder createSslContextBuilder() throws Exception { return SslContextBuilder.forServer(createKeyManagerFactory()); } - throw new IllegalStateException("Either an KeyStore or an SSL certificate must be provided"); + throw new IllegalStateException("Either a KeyStore or an SSL certificate must be provided"); } private KeyManagerFactory createKeyManagerFactory() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException { From 967734c422cd6b45790a5c2cf1c38307b3daf1dc Mon Sep 17 00:00:00 2001 From: edmocosta <11836452+edmocosta@users.noreply.github.com> Date: Mon, 27 Nov 2023 17:56:53 +0100 Subject: [PATCH 5/6] Apply suggestions from code review --- .../logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java b/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java index 55ae39c5..d5a55901 100644 --- a/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java +++ b/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java @@ -328,7 +328,7 @@ void testBuildContextWithCAsAndTrustStore() throws Exception { sslSimpleBuilder::build ); - assertEquals("Use either an SSL certificate authorities or a Trust Store to configure client authentication", thrown.getMessage()); + assertEquals("Use either a bundle of Certificate Authorities or a Trust Store to configure client authentication", thrown.getMessage()); } @Test From 0595a054d1fbe1f390d9b75d5c82c4116da79d23 Mon Sep 17 00:00:00 2001 From: edmocosta <11836452+edmocosta@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:33:05 +0100 Subject: [PATCH 6/6] Apply suggestions from code review --- spec/inputs/http_spec.rb | 25 ++++++++++++++++--- .../inputs/http/util/SslSimpleBuilder.java | 4 +-- .../http/util/SslSimpleBuilderTest.java | 11 ++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/spec/inputs/http_spec.rb b/spec/inputs/http_spec.rb index 15996a19..ba539954 100644 --- a/spec/inputs/http_spec.rb +++ b/spec/inputs/http_spec.rb @@ -798,7 +798,7 @@ def setup_server_client(url = self.url) end context "with ssl_truststore_path set" do - let(:config) { super().merge("ssl_truststore_path" => [certificate_path( 'server_from_root.p12')], "ssl_truststore_password" => "12345678") } + let(:config) { super().merge("ssl_truststore_path" => certificate_path('truststore.jks'), "ssl_truststore_password" => "12345678") } it "raise a configuration error" do expect {subject.register}.to raise_error(LogStash::ConfigurationError, "The configuration of `ssl_truststore_path` requires setting `ssl_client_authentication` to `optional` or 'required'") @@ -821,13 +821,22 @@ def setup_server_client(url = self.url) end end - context "with ssl_truststore_path set" do - let(:config) { super().merge("ssl_truststore_path" => [certificate_path( 'server_from_root.p12')], "ssl_truststore_password" => "12345678") } + context "with ssl_truststore_path set to a valid truststore" do + let(:config) { super().merge("ssl_truststore_path" => certificate_path('truststore.jks'), "ssl_truststore_password" => "12345678") } it "doesn't raise a configuration error" do expect {subject.register}.not_to raise_error end end + + context "with ssl_truststore_path set with no trusted certificate" do + let(:truststore_path) { certificate_path('server_from_root.p12') } + let(:config) { super().merge("ssl_truststore_path" => truststore_path, "ssl_truststore_password" => "12345678") } + + it "raise a configuration error" do + expect {subject.register}.to raise_error(LogStash::ConfigurationError, "The provided Trust Store file does not contains any trusted certificate entry: #{truststore_path}") + end + end end context "configured to 'optional'" do @@ -846,7 +855,15 @@ def setup_server_client(url = self.url) end context "with ssl_truststore_path set" do - let(:config) { super().merge("ssl_truststore_path" => [certificate_path( 'server_from_root.p12')], "ssl_truststore_password" => "12345678") } + let(:config) { super().merge("ssl_truststore_path" => certificate_path('truststore.jks'), "ssl_truststore_password" => "12345678") } + + it "doesn't raise a configuration error" do + expect {subject.register}.not_to raise_error + end + end + + context "with ssl_truststore_path set with no trusted certificate" do + let(:config) { super().merge("ssl_truststore_path" => certificate_path('server_from_root.p12'), "ssl_truststore_password" => "12345678") } it "doesn't raise a configuration error" do expect {subject.register}.not_to raise_error diff --git a/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java b/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java index 955326fc..5c8fc56e 100644 --- a/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java +++ b/src/main/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilder.java @@ -188,8 +188,8 @@ public SslSimpleBuilder setTrustStore(String trustStoreType, String trustStoreFi formatJksPassword(trustStorePassword) ); - if (!hasTrustStoreEntry(this.trustStore)) { - logger.warn("The provided Trust Store file does not contains any trusted certificate entry: {}. Please confirm this is the correct certificate and the password is correct", trustStoreFile); + if (!hasTrustStoreEntry(this.trustStore) && isClientAuthenticationRequired()) { + throw new IllegalArgumentException(String.format("The provided Trust Store file does not contains any trusted certificate entry: %s", trustStoreFile)); } return this; diff --git a/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java b/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java index d5a55901..53b4e386 100644 --- a/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java +++ b/src/test/java/org/logstash/plugins/inputs/http/util/SslSimpleBuilderTest.java @@ -211,6 +211,17 @@ void testSetTrustStoreWithNullTrustStoreType() throws Exception { assertEquals(TRUSTSTORE_TYPE, sslSimpleBuilder.getTrustStore().getType()); } + @Test + void testSetTrustStoreWithNoTrustedCertificate() { + assertThrows( + IllegalArgumentException.class, + () -> createPemSslSimpleBuilder() + .setClientAuthentication(SslClientVerifyMode.REQUIRED) + .setTrustStore(KEYSTORE_TYPE, KEYSTORE, KEYSTORE_PASSWORD), + String.format("The provided Trust Store file does not contains any trusted certificate entry: %s", KEYSTORE) + ); + } + @Test void testDefaultVerifyModeIsNone() { final SslSimpleBuilder sslSimpleBuilder = createPemSslSimpleBuilder();