Open Distro for Elasticsearch Security SSL initial release

This commit is contained in:
Hardik Shah 2019-03-02 20:43:33 -08:00
commit cf5050404f
67 changed files with 6802 additions and 0 deletions

16
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,16 @@
<!--
Github is a place only for reporting bugs or feature requests.
If you report a bug please include always the following informations:
* Security plugin and Elasticsearch version
* JVM version and operating system version
* Number of nodes in your cluster
* Description of the bug
These informations are optional but are very valueable and
typically would lead to get bugs fixed faster:
* Steps to reproduce
* Logfiles on DEBUG level
-->

8
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,8 @@
<!--
Issue #, if available:
Description of changes:
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
-->

46
.gitignore vendored Normal file
View File

@ -0,0 +1,46 @@
logstash*/
target/
test-output/
*.tar.gz
*gen-*conf*
netty*jar
logstash*/
/build.gradle
*.log
.externalToolBuilders
maven-eclipse.xml
## eclipse ignores (use 'mvn eclipse:eclipse' to build eclipse projects)
## The only configuration files which are not ignored are certain files in
## .settings (as listed below) since these files ensure common coding
## style across Eclipse and IDEA.
## Other files (.project, .classpath) should be generated through Maven which
## will correctly set the classpath based on the declared dependencies.
.project
.classpath
eclipse-build
*/.project
*/.classpath
*/eclipse-build
/.settings/
!/.settings/org.eclipse.core.resources.prefs
!/.settings/org.eclipse.jdt.core.prefs
!/.settings/org.eclipse.jdt.ui.prefs
!/.settings/org.eclipse.jdt.groovy.core.prefs
bin
tomcat.*
elasticsearch-*/
*node_key.key
securekey.key
/target/
.DS_Store
data/
example-pki-scripts/**/*.jks
example-pki-scripts/**/*.p12
example-pki-scripts/**/*.pem
example-pki-scripts/**/db/
example-pki-scripts/**/*.csr
example-pki-scripts/**/*.crt
example-pki-scripts/**/*.key
.vagrant/

4
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,4 @@
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.

61
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,61 @@
# Contributing Guidelines
Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional
documentation, we greatly value feedback and contributions from our community.
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary
information to effectively respond to your bug report or contribution.
## Reporting Bugs/Feature Requests
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
When filing an issue, please check [existing open](https://github.com/OpenDistro/elasticsearch-security-ssl/issues), or [recently closed](https://github.com/OpenDistro/elasticsearch-security-ssl/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already
reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
* A reproducible test case or series of steps
* The version of our code being used
* Any modifications you've made relevant to the bug
* Anything unusual about your environment or deployment
## Contributing via Pull Requests
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
1. You are working against the latest source on the *master* branch.
2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
3. You open an issue to discuss any significant work - we would hate for your time to be wasted.
To send us a pull request, please:
1. Fork the repository.
2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
3. Ensure local tests pass.
4. Commit to your fork using clear commit messages.
5. Send us a pull request, answering any default questions in the pull request interface.
6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and
[creating a pull request](https://help.github.com/articles/creating-a-pull-request/).
## Finding contributions to work on
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/OpenDistro/elasticsearch-security-ssl/labels/help%20wanted) issues is a great place to start.
## Code of Conduct
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
opensource-codeofconduct@amazon.com with any additional questions or comments.
## Security issue notifications
If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue.
## Licensing
See the [LICENSE](https://github.com/OpenDistro/elasticsearch-security-ssl/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution.
We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes.

202
LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

10
NOTICE.txt Normal file
View File

@ -0,0 +1,10 @@
floragunn GmbH Copyright 2015-2018 floragunn GmbH
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
This product includes software developed by The Apache Software
Foundation (http://www.apache.org/).
This product includes software developed by Mort Bay Consulting Pty. Ltd.
See THIRD-PARTY.txt for additional third party licenses used by this product.

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# Open Distro For Elasticsearch Security SSL
Open Distro For Elasticsearch Security SSL is a free and open source plugin for Elasticsearch which provides SSL/TLS support for Elasticsearch.
## Features
* Node-to-node encryption through SSL/TLS (Transport layer)
* Secure REST layer through HTTPS (SSL/TLS)
* Supports JDK SSL and OpenSSL
* Works with Kibana, Logstash and Beats
## Documentation
Please refer to the [Official documentation] for detailed information on installing and configuring opendistro-elasticsearch-security-ssl plugin.
## License
Open Distro For Elasticsearch Security SSL is licensed under the Apache 2.0 license.
## Legal
Open Distro For Elasticsearch Security SSL
Copyright 2019- Amazon.com, Inc. or its affiliates. All Rights Reserved.

52
THIRD-PARTY.txt Normal file
View File

@ -0,0 +1,52 @@
Lists of 50 third-party dependencies.
(The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
(The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.8.10 - https://github.com/FasterXML/jackson-core)
(The Apache Software License, Version 2.0) Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.8.10 - http://github.com/FasterXML/jackson-dataformats-binary)
(The Apache Software License, Version 2.0) Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.8.10 - http://github.com/FasterXML/jackson-dataformats-binary)
(The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.8.10 - https://github.com/FasterXML/jackson)
(The Apache Software License, Version 2.0) T-Digest (com.tdunning:t-digest:3.0 - https://github.com/tdunning/t-digest)
(The Apache Software License, Version 2.0) Apache Commons Codec (commons-codec:commons-codec:1.9 - http://commons.apache.org/proper/commons-codec/)
(Apache License, Version 2.0) Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
(The Apache Software License, Version 2.0) Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/)
(Apache License, Version 2.0) Netty/Buffer (io.netty:netty-buffer:4.1.16.Final - http://netty.io/netty-buffer/)
(Apache License, Version 2.0) Netty/Codec (io.netty:netty-codec:4.1.16.Final - http://netty.io/netty-codec/)
(Apache License, Version 2.0) Netty/Codec/HTTP (io.netty:netty-codec-http:4.1.16.Final - http://netty.io/netty-codec-http/)
(Apache License, Version 2.0) Netty/Common (io.netty:netty-common:4.1.16.Final - http://netty.io/netty-common/)
(Apache License, Version 2.0) Netty/Handler (io.netty:netty-handler:4.1.16.Final - http://netty.io/netty-handler/)
(Apache License, Version 2.0) Netty/Resolver (io.netty:netty-resolver:4.1.16.Final - http://netty.io/netty-resolver/)
(Apache License, Version 2.0) Netty/TomcatNative [OpenSSL - Dynamic] (io.netty:netty-tcnative:2.0.7.Final - https://github.com/netty/netty-tcnative/netty-tcnative/)
(Apache License, Version 2.0) Netty/Transport (io.netty:netty-transport:4.1.16.Final - http://netty.io/netty-transport/)
(Apache 2) Joda-Time (joda-time:joda-time:2.9.9 - http://www.joda.org/joda-time/)
(Eclipse Public License 1.0) JUnit (junit:junit:4.12 - http://junit.org)
(The MIT License) JOpt Simple (net.sf.jopt-simple:jopt-simple:5.0.2 - http://pholser.github.io/jopt-simple)
(Apache License, Version 2.0) Apache HttpClient Fluent API (org.apache.httpcomponents:fluent-hc:4.5.3 - http://hc.apache.org/httpcomponents-client)
(Apache License, Version 2.0) Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.3 - http://hc.apache.org/httpcomponents-client)
(Apache License, Version 2.0) Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.6 - http://hc.apache.org/httpcomponents-core-ga)
(Apache License, Version 2.0) Apache Log4j API (org.apache.logging.log4j:log4j-api:2.9.1 - https://logging.apache.org/log4j/2.x/log4j-api/)
(Apache License, Version 2.0) Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.9.1 - https://logging.apache.org/log4j/2.x/log4j-core/)
(Apache 2) Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
(Apache 2) Lucene Memory (org.apache.lucene:lucene-backward-codecs:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-backward-codecs)
(Apache 2) Lucene Core (org.apache.lucene:lucene-core:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-core)
(Apache 2) Lucene Grouping (org.apache.lucene:lucene-grouping:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-grouping)
(Apache 2) Lucene Highlighter (org.apache.lucene:lucene-highlighter:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
(Apache 2) Lucene Join (org.apache.lucene:lucene-join:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-join)
(Apache 2) Lucene Memory (org.apache.lucene:lucene-memory:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-memory)
(Apache 2) Lucene Miscellaneous (org.apache.lucene:lucene-misc:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-misc)
(Apache 2) Lucene Queries (org.apache.lucene:lucene-queries:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-queries)
(Apache 2) Lucene QueryParsers (org.apache.lucene:lucene-queryparser:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
(Apache 2) Lucene Sandbox (org.apache.lucene:lucene-sandbox:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-sandbox)
(Apache 2) Lucene Spatial (org.apache.lucene:lucene-spatial:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-spatial)
(Apache 2) Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-spatial-extras)
(Apache 2) Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-spatial3d)
(Apache 2) Lucene Suggest (org.apache.lucene:lucene-suggest:7.2.1 - http://lucene.apache.org/lucene-parent/lucene-suggest)
(The Apache Software License, Version 2.0) server (org.elasticsearch:elasticsearch:6.2.0 - https://github.com/elastic/elasticsearch)
(The Apache Software License, Version 2.0) cli (org.elasticsearch:elasticsearch-cli:6.2.0 - https://github.com/elastic/elasticsearch)
(The Apache Software License, Version 2.0) elasticsearch-core (org.elasticsearch:elasticsearch-core:6.2.0 - https://github.com/elastic/elasticsearch)
(The Apache Software License, Version 2.0) Elastic JNA Distribution (org.elasticsearch:jna:4.5.1 - https://github.com/java-native-access/jna)
(The Apache Software License, Version 2.0) Elasticsearch SecureSM (org.elasticsearch:securesm:1.2 - http://nexus.sonatype.org/oss-repository-hosting.html/securesm)
(The Apache Software License, Version 2.0) transport-netty4 (org.elasticsearch.plugin:transport-netty4-client:6.2.0 - https://github.com/elastic/elasticsearch)
(New BSD License) Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
(New BSD License) Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core)
(Public Domain, per Creative Commons CC0) HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.9 - http://hdrhistogram.github.io/HdrHistogram/)
(Apache License, Version 2.0) SnakeYAML (org.yaml:snakeyaml:1.17 - http://www.snakeyaml.org)

View File

@ -0,0 +1,149 @@
#############################################################################################
# OPEN DISTRO SECURITY SSL #
# Configuration #
#############################################################################################
#############################################################################################
# Transport layer SSL #
# #
#############################################################################################
# Enable or disable node-to-node ssl encryption (default: true)
#opendistro_security.ssl.transport.enabled: false
# JKS or PKCS12 (default: JKS)
#opendistro_security.ssl.transport.keystore_type: PKCS12
# Relative path to the keystore file (mandatory, this stores the server certificates), must be placed under the config/ dir
#opendistro_security.ssl.transport.keystore_filepath: keystore_node1.jks
# Alias name (default: first alias which could be found)
#opendistro_security.ssl.transport.keystore_alias: my_alias
# Keystore password (default: changeit)
#opendistro_security.ssl.transport.keystore_password: changeit
# JKS or PKCS12 (default: JKS)
#opendistro_security.ssl.transport.truststore_type: PKCS12
# Relative path to the truststore file (mandatory, this stores the client/root certificates), must be placed under the config/ dir
#opendistro_security.ssl.transport.truststore_filepath: truststore.jks
# Alias name (default: trust all aliases)
#opendistro_security.ssl.transport.truststore_alias: my_alias
# Truststore password (default: changeit)
#opendistro_security.ssl.transport.truststore_password: changeit
# Enforce hostname verification (default: true)
#opendistro_security.ssl.transport.enforce_hostname_verification: true
# If hostname verification is enabled specify if hostname should be resolved (default: true)
#opendistro_security.ssl.transport.resolve_hostname: true
# Use native Open SSL instead of JDK SSL if available (default: true)
#opendistro_security.ssl.transport.enable_openssl_if_available: false
# As an alternative to JKS/PCKS12 based configuration
# you can also use X.509 PEM certificates and PKCS #8 keys.
# This, for example, makes it pretty easy to configure letsencrypt certificates.
# Relative path to the certificates key file (PKCS #8), must be placed under the config/ dir
#opendistro_security.ssl.transport.pemkey_filepath: privkey.pem
# Key password (omit this setting if the key has no password)
#opendistro_security.ssl.transport.pemkey_password: "secret"
# X509 node certificate chain in PEM format, must be placed under the config/ dir
#opendistro_security.ssl.transport.pemcert_filepath: fullchain.pem
# Trusted certificates
#opendistro_security.ssl.transport.pemtrustedcas_filepath: chain.pem
# Enabled SSL cipher suites for transport protocol (only Java format is supported)
# WARNING: Expert setting, do only use if you know what you are doing
# If you set wrong values here this this could be a security risk
#opendistro_security.ssl.transport.enabled_ciphers:
# - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"
# - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"
# Enabled SSL protocols for transport protocol (only Java format is supported)
# WARNING: Expert setting, do only use if you know what you are doing
# If you set wrong values here this this could be a security risk
#opendistro_security.ssl.transport.enabled_protocols:
# - "TLSv1.2"
#############################################################################################
# HTTP/REST layer SSL #
# #
#############################################################################################
# Enable or disable rest layer security - https, (default: false)
#opendistro_security.ssl.http.enabled: true
# JKS or PKCS12 (default: JKS)
#opendistro_security.ssl.http.keystore_type: PKCS12
# Relative path to the keystore file (this stores the server certificates), must be placed under the config/ dir
#opendistro_security.ssl.http.keystore_filepath: keystore_https_node1.jks
# Alias name (default: first alias which could be found)
#opendistro_security.ssl.http.keystore_alias: my_alias
# Keystore password (default: changeit)
#opendistro_security.ssl.http.keystore_password: changeit
# Do the clients (typically the browser or the proxy) have to authenticate themself to the http server, default is OPTIONAL
# To enforce authentication use REQUIRE, to completely disable client certificates use NONE
#opendistro_security.ssl.http.clientauth_mode: REQUIRE
# JKS or PKCS12 (default: JKS)
#opendistro_security.ssl.http.truststore_type: PKCS12
# Relative path to the truststore file (this stores the client certificates), must be placed under the config/ dir
#opendistro_security.ssl.http.truststore_filepath: truststore_https.jks
# Alias name (default: first alias which could be found)
#opendistro_security.ssl.http.truststore_alias: my_alias
# Truststore password (default: changeit)
#opendistro_security.ssl.http.truststore_password: changeit
# Use native Open SSL instead of JDK SSL if available (default: true)
#opendistro_security.ssl.http.enable_openssl_if_available: false
# As an alternative to JKS/PCKS12 based configuration
# you can also use X.509 PEM certificates and PKCS #8 keys.
# This, for example, makes it pretty easy to configure letsencrypt certificates.
# Relative path to the certificates key file (PKCS #8), must be placed under the config/ dir
#opendistro_security.ssl.http.pemkey_filepath: privkey.pem
# Key password (omit this setting if the key has no password)
#opendistro_security.ssl.http.pemkey_password: "secret"
# X509 node certificate chain in PEM format, must be placed under the config/ dir
#opendistro_security.ssl.http.pemcert_filepath: fullchain.pem
# Trusted certificates
#opendistro_security.ssl.http.pemtrustedcas_filepath: chain.pem
# Enabled SSL cipher suites for http protocol (only Java format is supported)
# WARNING: Expert setting, do only use if you know what you are doing
# If you set wrong values here this this could be a security risk
#opendistro_security.ssl.http.enabled_ciphers:
# - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"
# - "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"
# Enabled SSL protocols for http protocol (only Java format is supported)
# WARNING: Expert setting, do only use if you know what you are doing
# If you set wrong values here this this could be a security risk
#opendistro_security.ssl.http.enabled_protocols:
# - "TLSv1.2"
# Enables the usage of custom SSLContext's for Transport clients
# This setting does only apply to Transport clients
# WARNING: Expert setting, do only use if you know what you are doing
# If you set wrong values here this this could be a security risk
#opendistro_security.ssl.client.external_context_id: myid
# Class name of a class which is in classpath and implements com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor
# used to resolve the string representation of an principal from a x509 certificate
# WARNING: Expert setting, do only use if you know what you are doing
# If you set wrong values here this this could be a security risk
#opendistro_security.ssl.transport.principal_extractor_class: com.example.security.MyPrincipalExtractor
# CRL validation of HTTP client certificates
# WARNING: Expert setting, do only use if you know what you are doing
# If you set wrong values here this this could be a security risk
# Set to true to enable CRL validation (default is false)
#opendistro_security.ssl.http.crl.validate: true
# File based static revocation list, by default this is null
# if null then either OCSP or CRLDP needs to be enabled
# CRL file must be in config/ dir, so this path is relative here
#opendistro_security.ssl.http.crl.file_path: mycrl.crl
# Default is false (means we prefer OCSP over static CRL file)
#opendistro_security.ssl.http.crl.prefer_crlfile_over_ocsp: true
# Default is true (means we do not validate intermediate certificates)
#opendistro_security.ssl.http.crl.check_only_end_entities: false
# Default is false (means we use OCSP if available)
#opendistro_security.ssl.http.crl.disable_ocsp: true
# Default is false (means we use CRLDP if available)
#opendistro_security.ssl.http.crl.disable_crldp: true
# Sets the time (as unix epoch timestamp) for which the validity of the certification path should be determined
# If not set of set to -1 then the current time will be used
#opendistro_security.ssl.http.crl.validation_date: 1496070074

View File

@ -0,0 +1,25 @@
#
# 'description': simple summary of the plugin
description=Provides SSL for Elasticsearch 6
#
# 'version': plugin's version
version=0.7.0.0
#
# 'name': the plugin name
name=opendistro_security-ssl
#
# 'classname': the name of the class to load, fully-qualified.
classname=com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecuritySSLPlugin
#
# 'java.version' version of java the code is built against
# use the system property java.specification.version
# version string must be a sequence of nonnegative decimal integers
# separated by "."'s and may have leading zeros
java.version=1.8
#
# 'elasticsearch.version' version of elasticsearch compiled against
# You will have to release a new version of the plugin for each new
# elasticsearch release. This version is checked when the plugin
# is loaded so Elasticsearch will refuse to start in the presence of
# plugins with the incorrect elasticsearch.version.
elasticsearch.version=6.5.4

55
plugin-security.policy Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright 2015-2017 floragunn GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
//grant codeBase "${codebase.opendistro_security_ssl-0.7.0.0.jar}" {
grant {
//below permissions are needed for netty native open ssl support
permission java.lang.RuntimePermission "loadLibrary.*";
permission java.lang.RuntimePermission "getClassLoader";
permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
permission java.security.SecurityPermission "getProperty.ssl.KeyManagerFactory.algorithm";
permission java.lang.RuntimePermission "accessDeclaredMembers";
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.x509";
permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
permission java.io.FilePermission "/proc/sys/net/core/somaxconn","read";
permission java.util.PropertyPermission "sun.nio.ch.bugLevel", "write";
permission java.util.PropertyPermission "jdk.tls.rejectClientInitiatedRenegotiation", "write";
permission java.security.SecurityPermission "setProperty.ocsp.enable";
permission java.util.PropertyPermission "com.sun.security.enableCRLDP", "write";
permission java.util.PropertyPermission "es.set.netty.runtime.available.processors", "write";
permission java.net.NetPermission "getNetworkInformation";
permission java.net.SocketPermission "*", "connect,accept,resolve";
};

207
pom.xml Normal file
View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2015-2018 _floragunn_ GmbH
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!--
~ Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License").
~ You may not use this file except in compliance with the License.
~ A copy of the License is located at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ or in the "license" file accompanying this file. This file is distributed
~ on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
~ express or implied. See the License for the specific language governing
~ permissions and limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.amazon.opendistroforelasticsearch</groupId>
<artifactId>opendistro_security_parent</artifactId>
<version>0.7.0.0</version>
</parent>
<artifactId>opendistro_security_ssl</artifactId>
<version>0.7.0.0</version>
<packaging>jar</packaging>
<name>Open Distro Security SSL</name>
<description>Provides SSL Security for Elasticsearch 6</description>
<url>https://github.com/mauve-hedgehog/opendistro-elasticsearch-security-ssl</url>
<inceptionYear>2015</inceptionYear>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<properties>
<elasticsearch.version>6.5.4</elasticsearch.version>
<!-- deps -->
<netty-native.version>2.0.15.Final</netty-native.version>
<log4j.version>2.11.1</log4j.version>
</properties>
<scm>
<url>https://github.com/mauve-hedgehog/opendistro-elasticsearch-security-ssl</url>
<connection>scm:git:git@github.com:mauve-hedgehog/opendistro-elasticsearch-security-ssl.git</connection>
<developerConnection>scm:git:git@github.com:mauve-hedgehog/opendistro-elasticsearch-security-ssl.git</developerConnection>
<tag>v0.7.0.0</tag>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/mauve-hedgehog/opendistro-elasticsearch-security-ssl/issues</url>
</issueManagement>
<contributors />
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
<version>${elasticsearch.version}</version>
<exclusions>
<exclusion>
<artifactId>jna</artifactId>
<groupId>org.elasticsearch</groupId>
</exclusion>
<exclusion>
<artifactId>jts</artifactId>
<groupId>com.vividsolutions</groupId>
</exclusion>
<exclusion>
<artifactId>log4j-api</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
<exclusion>
<artifactId>spatial4j</artifactId>
<groupId>org.locationtech.spatial4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- Only test scoped dependencies hereafter -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
</plugins>
<extensions>
<extension>
<groupId>com.gkatzioura.maven.cloud</groupId>
<artifactId>s3-storage-wagon</artifactId>
<version>1.8</version>
</extension>
</extensions>
</build>
<profiles>
<profile>
<id>with-static-openssl-linux-non-fedora</id>
<dependencies>
<dependency>
<groupId>com.floragunn</groupId>
<artifactId>search-guard-static-tcnative-beta</artifactId>
<version>1.1.0j-${netty-native.version}-non-fedora-linux-x86_64</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>with-static-openssl-linux-fedora</id>
<dependencies>
<dependency>
<groupId>com.floragunn</groupId>
<artifactId>search-guard-static-tcnative-beta</artifactId>
<version>1.1.0j-${netty-native.version}-fedora-linux-x86_64</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>with-dynamic-openssl</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative</artifactId>
<version>${netty-native.version}</version>
<classifier>${os.detected.classifier}</classifier>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<assembly>
<id>plugin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<useStrictFiltering>true</useStrictFiltering>
<outputDirectory>${file.separator}</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<useTransitiveFiltering>true</useTransitiveFiltering>
</dependencySet>
<dependencySet>
<useStrictFiltering>true</useStrictFiltering>
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>com.amazon:opendistro_security_ssl</include>
</includes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<outputDirectory>${file.separator}</outputDirectory>
<includes>
<include>plugin-descriptor.properties</include>
<include>plugin-security.policy</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@ -0,0 +1,827 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import java.io.File;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.crypto.Cipher;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.SpecialPermission;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLCertificateHelper;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
public class DefaultOpenDistroSecurityKeyStore implements OpenDistroSecurityKeyStore {
private static final String DEFAULT_STORE_TYPE = "JKS";
private void printJCEWarnings() {
try {
final int aesMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES");
if (aesMaxKeyLength < 256) {
log.info("AES-256 not supported, max key length for AES is " + aesMaxKeyLength + " bit."
+ " (This is not an issue, it just limits possible encryption strength. To enable AES 256, install 'Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files')");
}
} catch (final NoSuchAlgorithmException e) {
log.error("AES encryption not supported (Security 1). " + e);
}
}
private final Settings settings;
private final Logger log = LogManager.getLogger(this.getClass());
public final SslProvider sslHTTPProvider;
public final SslProvider sslTransportServerProvider;
public final SslProvider sslTransportClientProvider;
private final boolean httpSSLEnabled;
private final boolean transportSSLEnabled;
private List<String> enabledHttpCiphersJDKProvider;
private List<String> enabledHttpCiphersOpenSSLProvider;
private List<String> enabledTransportCiphersJDKProvider;
private List<String> enabledTransportCiphersOpenSSLProvider;
private List<String> enabledHttpProtocolsJDKProvider;
private List<String> enabledHttpProtocolsOpenSSLProvider;
private List<String> enabledTransportProtocolsJDKProvider;
private List<String> enabledTransportProtocolsOpenSSLProvider;
private SslContext httpSslContext;
private SslContext transportServerSslContext;
private SslContext transportClientSslContext;
private final Environment env;
public DefaultOpenDistroSecurityKeyStore(final Settings settings, final Path configPath) {
super();
this.settings = settings;
Environment _env;
try {
_env = new Environment(settings, configPath);
} catch (IllegalStateException e) {
_env = null;
}
env = _env;
httpSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED,
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT);
transportSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED,
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT);
final boolean useOpenSSLForHttpIfAvailable = settings
.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, true);
final boolean useOpenSSLForTransportIfAvailable = settings
.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, true);
boolean openSSLInfoLogged = false;
if (httpSSLEnabled && useOpenSSLForHttpIfAvailable) {
sslHTTPProvider = SslContext.defaultServerProvider();
logOpenSSLInfos();
openSSLInfoLogged = true;
} else if (httpSSLEnabled) {
sslHTTPProvider = SslProvider.JDK;
} else {
sslHTTPProvider = null;
}
if (transportSSLEnabled && useOpenSSLForTransportIfAvailable) {
sslTransportClientProvider = SslContext.defaultClientProvider();
sslTransportServerProvider = SslContext.defaultServerProvider();
if (!openSSLInfoLogged) {
logOpenSSLInfos();
}
} else if (transportSSLEnabled) {
sslTransportClientProvider = sslTransportServerProvider = SslProvider.JDK;
} else {
sslTransportClientProvider = sslTransportServerProvider = null;
}
initEnabledSSLCiphers();
initSSLConfig();
printJCEWarnings();
log.info("TLS Transport Client Provider : {}", sslTransportClientProvider);
log.info("TLS Transport Server Provider : {}", sslTransportServerProvider);
log.info("TLS HTTP Provider : {}", sslHTTPProvider);
log.debug("sslTransportClientProvider:{} with ciphers {}", sslTransportClientProvider,
getEnabledSSLCiphers(sslTransportClientProvider, false));
log.debug("sslTransportServerProvider:{} with ciphers {}", sslTransportServerProvider,
getEnabledSSLCiphers(sslTransportServerProvider, false));
log.debug("sslHTTPProvider:{} with ciphers {}", sslHTTPProvider, getEnabledSSLCiphers(sslHTTPProvider, true));
log.info("Enabled TLS protocols for transport layer : {}",
Arrays.toString(getEnabledSSLProtocols(sslTransportServerProvider, false)));
log.info("Enabled TLS protocols for HTTP layer : {}",
Arrays.toString(getEnabledSSLProtocols(sslHTTPProvider, true)));
log.debug("sslTransportClientProvider:{} with protocols {}", sslTransportClientProvider,
getEnabledSSLProtocols(sslTransportClientProvider, false));
log.debug("sslTransportServerProvider:{} with protocols {}", sslTransportServerProvider,
getEnabledSSLProtocols(sslTransportServerProvider, false));
log.debug("sslHTTPProvider:{} with protocols {}", sslHTTPProvider, getEnabledSSLProtocols(sslHTTPProvider, true));
if (transportSSLEnabled && (getEnabledSSLCiphers(sslTransportClientProvider, false).isEmpty()
|| getEnabledSSLCiphers(sslTransportServerProvider, false).isEmpty())) {
throw new ElasticsearchSecurityException("no valid cipher suites for transport protocol");
}
if (httpSSLEnabled && getEnabledSSLCiphers(sslHTTPProvider, true).isEmpty()) {
throw new ElasticsearchSecurityException("no valid cipher suites for https");
}
if (transportSSLEnabled && getEnabledSSLCiphers(sslTransportServerProvider, false).isEmpty()) {
throw new ElasticsearchSecurityException("no ssl protocols for transport protocol");
}
if (transportSSLEnabled && getEnabledSSLCiphers(sslTransportClientProvider, false).isEmpty()) {
throw new ElasticsearchSecurityException("no ssl protocols for transport protocol");
}
if (httpSSLEnabled && getEnabledSSLCiphers(sslHTTPProvider, true).isEmpty()) {
throw new ElasticsearchSecurityException("no ssl protocols for https");
}
}
private String resolve(String propName, boolean mustBeValid) {
final String originalPath = settings.get(propName, null);
String path = originalPath;
log.debug("Value for {} is {}", propName, originalPath);
if (env != null && originalPath != null && originalPath.length() > 0) {
path = env.configFile().resolve(originalPath).toAbsolutePath().toString();
log.debug("Resolved {} to {} against {}", originalPath, path, env.configFile().toAbsolutePath().toString());
}
if (mustBeValid) {
checkPath(path, propName);
}
if ("".equals(path)) {
path = null;
}
return path;
}
private void initSSLConfig() {
if (env == null) {
log.info("No config directory, key- and truststore files are resolved absolutely");
} else {
log.info("Config directory is {}/, from there the key- and truststore files are resolved relatively",
env.configFile().toAbsolutePath());
}
if (transportSSLEnabled) {
final String rawKeyStoreFilePath = settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH, null);
final String rawPemCertFilePath = settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, null);
if (rawKeyStoreFilePath != null) {
final String keystoreFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH,
true);
final String keystoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE,
DEFAULT_STORE_TYPE);
final String keystorePassword = settings.get(
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_PASSWORD,
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
final String keystoreAlias = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS,
null);
final String truststoreFilePath = resolve(
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, true);
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, null) == null) {
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH
+ " must be set if transport ssl is requested.");
}
final String truststoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE,
DEFAULT_STORE_TYPE);
final String truststorePassword = settings.get(
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD,
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
final String truststoreAlias = settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_ALIAS, null);
try {
final KeyStore ks = KeyStore.getInstance(keystoreType);
ks.load(new FileInputStream(new File(keystoreFilePath)),
(keystorePassword == null || keystorePassword.length() == 0) ? null
: keystorePassword.toCharArray());
final X509Certificate[] transportKeystoreCert = SSLCertificateHelper.exportServerCertChain(ks,
keystoreAlias);
final PrivateKey transportKeystoreKey = SSLCertificateHelper.exportDecryptedKey(ks, keystoreAlias,
(keystorePassword == null || keystorePassword.length() == 0) ? null
: keystorePassword.toCharArray());
if (transportKeystoreKey == null) {
throw new ElasticsearchException(
"No key found in " + keystoreFilePath + " with alias " + keystoreAlias);
}
if (transportKeystoreCert != null && transportKeystoreCert.length > 0) {
// TODO create sensitive log property
/*
* for (int i = 0; i < transportKeystoreCert.length; i++) { X509Certificate
* x509Certificate = transportKeystoreCert[i];
*
* if(x509Certificate != null) {
* log.info("Transport keystore subject DN no. {} {}",i,x509Certificate.
* getSubjectX500Principal()); } }
*/
} else {
throw new ElasticsearchException(
"No certificates found in " + keystoreFilePath + " with alias " + keystoreAlias);
}
final KeyStore ts = KeyStore.getInstance(truststoreType);
ts.load(new FileInputStream(new File(truststoreFilePath)),
(truststorePassword == null || truststorePassword.length() == 0) ? null
: truststorePassword.toCharArray());
final X509Certificate[] trustedTransportCertificates = SSLCertificateHelper
.exportRootCertificates(ts, truststoreAlias);
if (trustedTransportCertificates == null) {
throw new ElasticsearchException("No truststore configured for server");
}
transportServerSslContext = buildSSLServerContext(transportKeystoreKey, transportKeystoreCert,
trustedTransportCertificates, getEnabledSSLCiphers(this.sslTransportServerProvider, false),
this.sslTransportServerProvider, ClientAuth.REQUIRE);
transportClientSslContext = buildSSLClientContext(transportKeystoreKey, transportKeystoreCert,
trustedTransportCertificates, getEnabledSSLCiphers(sslTransportClientProvider, false),
sslTransportClientProvider);
} catch (final Exception e) {
logExplanation(e);
throw new ElasticsearchSecurityException(
"Error while initializing transport SSL layer: " + e.toString(), e);
}
} else if (rawPemCertFilePath != null) {
final String pemCertFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH,
true);
final String pemKey = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, true);
final String trustedCas = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH,
true);
try {
transportServerSslContext = buildSSLServerContext(new File(pemKey), new File(pemCertFilePath),
new File(trustedCas),
settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD),
getEnabledSSLCiphers(this.sslTransportServerProvider, false),
this.sslTransportServerProvider, ClientAuth.REQUIRE);
transportClientSslContext = buildSSLClientContext(new File(pemKey), new File(pemCertFilePath),
new File(trustedCas),
settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD),
getEnabledSSLCiphers(sslTransportClientProvider, false), sslTransportClientProvider);
} catch (final Exception e) {
logExplanation(e);
throw new ElasticsearchSecurityException(
"Error while initializing transport SSL layer from PEM: " + e.toString(), e);
}
} else {
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH + " or "
+ SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH
+ " must be set if transport ssl is reqested.");
}
}
final boolean client = !"node".equals(this.settings.get(OpenDistroSecuritySSLPlugin.CLIENT_TYPE));
if (!client && httpSSLEnabled) {
final String rawKeystoreFilePath = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH,
null);
final String rawPemCertFilePath = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH,
null);
final ClientAuth httpClientAuthMode = ClientAuth.valueOf(settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CLIENTAUTH_MODE, ClientAuth.OPTIONAL.toString()));
if (rawKeystoreFilePath != null) {
final String keystoreFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH,
true);
final String keystoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_TYPE,
DEFAULT_STORE_TYPE);
final String keystorePassword = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD,
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
final String keystoreAlias = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, null);
log.info("HTTPS client auth mode {}", httpClientAuthMode);
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH, null) == null) {
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH
+ " must be set if https is reqested.");
}
if (httpClientAuthMode == ClientAuth.REQUIRE) {
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, null) == null) {
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH
+ " must be set if http ssl and client auth is reqested.");
}
}
try {
final KeyStore ks = KeyStore.getInstance(keystoreType);
try (FileInputStream fin = new FileInputStream(new File(keystoreFilePath))) {
ks.load(fin, (keystorePassword == null || keystorePassword.length() == 0) ? null
: keystorePassword.toCharArray());
}
final X509Certificate[] httpKeystoreCert = SSLCertificateHelper.exportServerCertChain(ks,
keystoreAlias);
final PrivateKey httpKeystoreKey = SSLCertificateHelper.exportDecryptedKey(ks, keystoreAlias,
(keystorePassword == null || keystorePassword.length() == 0) ? null
: keystorePassword.toCharArray());
if (httpKeystoreKey == null) {
throw new ElasticsearchException(
"No key found in " + keystoreFilePath + " with alias " + keystoreAlias);
}
if (httpKeystoreCert != null && httpKeystoreCert.length > 0) {
// TODO create sensitive log property
/*
* for (int i = 0; i < httpKeystoreCert.length; i++) { X509Certificate
* x509Certificate = httpKeystoreCert[i];
*
* if(x509Certificate != null) {
* log.info("HTTP keystore subject DN no. {} {}",i,x509Certificate.
* getSubjectX500Principal()); } }
*/
} else {
throw new ElasticsearchException(
"No certificates found in " + keystoreFilePath + " with alias " + keystoreAlias);
}
X509Certificate[] trustedHTTPCertificates = null;
if (settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, null) != null) {
final String truststoreFilePath = resolve(
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, true);
final String truststoreType = settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE, DEFAULT_STORE_TYPE);
final String truststorePassword = settings.get(
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD,
SSLConfigConstants.DEFAULT_STORE_PASSWORD);
final String truststoreAlias = settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS, null);
final KeyStore ts = KeyStore.getInstance(truststoreType);
try (FileInputStream fin = new FileInputStream(new File(truststoreFilePath))) {
ts.load(fin, (truststorePassword == null || truststorePassword.length() == 0) ? null
: truststorePassword.toCharArray());
}
trustedHTTPCertificates = SSLCertificateHelper.exportRootCertificates(ts, truststoreAlias);
}
httpSslContext = buildSSLServerContext(httpKeystoreKey, httpKeystoreCert, trustedHTTPCertificates,
getEnabledSSLCiphers(this.sslHTTPProvider, true), sslHTTPProvider, httpClientAuthMode);
} catch (final Exception e) {
logExplanation(e);
throw new ElasticsearchSecurityException("Error while initializing HTTP SSL layer: " + e.toString(),
e);
}
} else if (rawPemCertFilePath != null) {
final String trustedCas = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH,
false);
if (httpClientAuthMode == ClientAuth.REQUIRE) {
// if(trustedCas == null ||
// trustedCas.equals(env.config-File().toAbsolutePath().toString())) {
// throw new
// ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH
// + " must be set if http ssl and client auth is reqested.");
// }
checkPath(trustedCas, SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH);
}
final String pemCertFilePath = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, true);
final String pemKey = resolve(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, true);
try {
httpSslContext = buildSSLServerContext(new File(pemKey), new File(pemCertFilePath),
trustedCas == null ? null : new File(trustedCas),
settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD),
getEnabledSSLCiphers(this.sslHTTPProvider, true), sslHTTPProvider, httpClientAuthMode);
} catch (final Exception e) {
logExplanation(e);
throw new ElasticsearchSecurityException(
"Error while initializing http SSL layer from PEM: " + e.toString(), e);
}
} else {
throw new ElasticsearchException(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH + " or "
+ SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH
+ " must be set if http ssl is reqested.");
}
}
}
public SSLEngine createHTTPSSLEngine() throws SSLException {
final SSLEngine engine = httpSslContext.newEngine(PooledByteBufAllocator.DEFAULT);
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslHTTPProvider, true));
return engine;
}
public SSLEngine createServerTransportSSLEngine() throws SSLException {
final SSLEngine engine = transportServerSslContext.newEngine(PooledByteBufAllocator.DEFAULT);
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslTransportServerProvider, false));
return engine;
}
public SSLEngine createClientTransportSSLEngine(final String peerHost, final int peerPort) throws SSLException {
if (peerHost != null) {
final SSLEngine engine = transportClientSslContext.newEngine(PooledByteBufAllocator.DEFAULT, peerHost,
peerPort);
final SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
engine.setSSLParameters(sslParams);
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslTransportClientProvider, false));
return engine;
} else {
final SSLEngine engine = transportClientSslContext.newEngine(PooledByteBufAllocator.DEFAULT);
engine.setEnabledProtocols(getEnabledSSLProtocols(this.sslTransportClientProvider, false));
return engine;
}
}
@Override
public String getHTTPProviderName() {
return sslHTTPProvider == null ? null : sslHTTPProvider.toString();
}
@Override
public String getTransportServerProviderName() {
return sslTransportServerProvider == null ? null : sslTransportServerProvider.toString();
}
@Override
public String getTransportClientProviderName() {
return sslTransportClientProvider == null ? null : sslTransportClientProvider.toString();
}
private void logOpenSSLInfos() {
if (OpenSsl.isAvailable()) {
log.info("OpenSSL " + OpenSsl.versionString() + " (" + OpenSsl.version() + ") available");
if (OpenSsl.version() < 0x10002000L) {
log.warn(
"Outdated OpenSSL version detected. You should update to 1.0.2k or later. Currently installed: "
+ OpenSsl.versionString());
}
if (!OpenSsl.supportsHostnameValidation()) {
log.warn("Your OpenSSL version " + OpenSsl.versionString()
+ " does not support hostname verification. You should update to 1.0.2k or later.");
}
log.debug("OpenSSL available ciphers " + OpenSsl.availableOpenSslCipherSuites());
} else {
log.info("OpenSSL not available (this is not an error, we simply fallback to built-in JDK SSL) because of "
+ OpenSsl.unavailabilityCause());
}
}
private List<String> getEnabledSSLCiphers(final SslProvider provider, boolean http) {
if (provider == null) {
return Collections.emptyList();
}
if (http) {
return provider == SslProvider.JDK ? enabledHttpCiphersJDKProvider : enabledHttpCiphersOpenSSLProvider;
} else {
return provider == SslProvider.JDK ? enabledTransportCiphersJDKProvider
: enabledTransportCiphersOpenSSLProvider;
}
}
private String[] getEnabledSSLProtocols(final SslProvider provider, boolean http) {
if (provider == null) {
return new String[0];
}
if (http) {
return (provider == SslProvider.JDK ? enabledHttpProtocolsJDKProvider : enabledHttpProtocolsOpenSSLProvider).toArray(new String[0]);
} else {
return (provider == SslProvider.JDK ? enabledTransportProtocolsJDKProvider
: enabledTransportProtocolsOpenSSLProvider).toArray(new String[0]);
}
}
private void initEnabledSSLCiphers() {
final List<String> secureHttpSSLCiphers = SSLConfigConstants.getSecureSSLCiphers(settings, true);
final List<String> secureTransportSSLCiphers = SSLConfigConstants.getSecureSSLCiphers(settings, false);
final List<String> secureHttpSSLProtocols = Arrays.asList(SSLConfigConstants.getSecureSSLProtocols(settings, true));
final List<String> secureTransportSSLProtocols = Arrays.asList(SSLConfigConstants.getSecureSSLProtocols(settings, false));
if (OpenSsl.isAvailable()) {
final Set<String> openSSLSecureHttpCiphers = new HashSet<>();
for (final String secure : secureHttpSSLCiphers) {
if (OpenSsl.isCipherSuiteAvailable(secure)) {
openSSLSecureHttpCiphers.add(secure);
}
}
log.debug("OPENSSL "+OpenSsl.versionString()+" supports the following ciphers (java-style) {}", OpenSsl.availableJavaCipherSuites());
log.debug("OPENSSL "+OpenSsl.versionString()+" supports the following ciphers (openssl-style) {}", OpenSsl.availableOpenSslCipherSuites());
enabledHttpCiphersOpenSSLProvider = Collections
.unmodifiableList(new ArrayList<String>(openSSLSecureHttpCiphers));
} else {
enabledHttpCiphersOpenSSLProvider = Collections.emptyList();
}
if (OpenSsl.isAvailable()) {
final Set<String> openSSLSecureTransportCiphers = new HashSet<>();
for (final String secure : secureTransportSSLCiphers) {
if (OpenSsl.isCipherSuiteAvailable(secure)) {
openSSLSecureTransportCiphers.add(secure);
}
}
enabledTransportCiphersOpenSSLProvider = Collections
.unmodifiableList(new ArrayList<String>(openSSLSecureTransportCiphers));
} else {
enabledTransportCiphersOpenSSLProvider = Collections.emptyList();
}
if(OpenSsl.isAvailable() && OpenSsl.version() > 0x10101009L) {
enabledHttpProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.3","TLSv1.2","TLSv1.1"));
enabledHttpProtocolsOpenSSLProvider.retainAll(secureHttpSSLProtocols);
enabledTransportProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.3","TLSv1.2","TLSv1.1"));
enabledTransportProtocolsOpenSSLProvider.retainAll(secureTransportSSLProtocols);
log.info("OpenSSL supports TLSv1.3");
} else if(OpenSsl.isAvailable()){
enabledHttpProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.2","TLSv1.1"));
enabledHttpProtocolsOpenSSLProvider.retainAll(secureHttpSSLProtocols);
enabledTransportProtocolsOpenSSLProvider = new ArrayList(Arrays.asList("TLSv1.2","TLSv1.1"));
enabledTransportProtocolsOpenSSLProvider.retainAll(secureTransportSSLProtocols);
} else {
enabledHttpProtocolsOpenSSLProvider = Collections.emptyList();
enabledTransportProtocolsOpenSSLProvider = Collections.emptyList();
}
SSLEngine engine = null;
List<String> jdkSupportedCiphers = null;
List<String> jdkSupportedProtocols = null;
try {
final SSLContext serverContext = SSLContext.getInstance("TLS");
serverContext.init(null, null, null);
engine = serverContext.createSSLEngine();
jdkSupportedCiphers = Arrays.asList(engine.getEnabledCipherSuites());
jdkSupportedProtocols = Arrays.asList(engine.getEnabledProtocols());
log.debug("JVM supports the following {} protocols {}", jdkSupportedProtocols.size(),
jdkSupportedProtocols);
log.debug("JVM supports the following {} ciphers {}", jdkSupportedCiphers.size(),
jdkSupportedCiphers);
if(jdkSupportedProtocols.contains("TLSv1.3")) {
log.info("JVM supports TLSv1.3");
}
} catch (final Throwable e) {
log.error("Unable to determine supported ciphers due to " + e, e);
} finally {
if (engine != null) {
try {
engine.closeInbound();
} catch (SSLException e) {
log.debug("Unable to close inbound ssl engine", e);
}
engine.closeOutbound();
}
}
if(jdkSupportedCiphers == null || jdkSupportedCiphers.isEmpty() || jdkSupportedProtocols == null || jdkSupportedProtocols.isEmpty()) {
throw new ElasticsearchException("Unable to determine supported ciphers or protocols");
}
enabledHttpCiphersJDKProvider = new ArrayList<String>(jdkSupportedCiphers);
enabledHttpCiphersJDKProvider.retainAll(secureHttpSSLCiphers);
enabledTransportCiphersJDKProvider = new ArrayList<String>(jdkSupportedCiphers);
enabledTransportCiphersJDKProvider.retainAll(secureTransportSSLCiphers);
enabledHttpProtocolsJDKProvider = new ArrayList<String>(jdkSupportedProtocols);
enabledHttpProtocolsJDKProvider.retainAll(secureHttpSSLProtocols);
enabledTransportProtocolsJDKProvider = new ArrayList<String>(jdkSupportedProtocols);
enabledTransportProtocolsJDKProvider.retainAll(secureTransportSSLProtocols);
}
private SslContext buildSSLServerContext(final PrivateKey _key, final X509Certificate[] _cert,
final X509Certificate[] _trustedCerts, final Iterable<String> ciphers, final SslProvider sslProvider,
final ClientAuth authMode) throws SSLException {
final SslContextBuilder _sslContextBuilder = SslContextBuilder.forServer(_key, _cert).ciphers(ciphers)
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED)
.clientAuth(Objects.requireNonNull(authMode)) // https://github.com/netty/netty/issues/4722
.sessionCacheSize(0).sessionTimeout(0).sslProvider(sslProvider);
if (_trustedCerts != null && _trustedCerts.length > 0) {
_sslContextBuilder.trustManager(_trustedCerts);
}
return buildSSLContext0(_sslContextBuilder);
}
private SslContext buildSSLServerContext(final File _key, final File _cert, final File _trustedCerts,
final String pwd, final Iterable<String> ciphers, final SslProvider sslProvider, final ClientAuth authMode)
throws SSLException {
final SslContextBuilder _sslContextBuilder = SslContextBuilder.forServer(_cert, _key, pwd).ciphers(ciphers)
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED)
.clientAuth(Objects.requireNonNull(authMode)) // https://github.com/netty/netty/issues/4722
.sessionCacheSize(0).sessionTimeout(0).sslProvider(sslProvider);
if (_trustedCerts != null) {
_sslContextBuilder.trustManager(_trustedCerts);
}
return buildSSLContext0(_sslContextBuilder);
}
private SslContext buildSSLClientContext(final PrivateKey _key, final X509Certificate[] _cert,
final X509Certificate[] _trustedCerts, final Iterable<String> ciphers, final SslProvider sslProvider)
throws SSLException {
final SslContextBuilder _sslClientContextBuilder = SslContextBuilder.forClient().ciphers(ciphers)
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED).sessionCacheSize(0).sessionTimeout(0)
.sslProvider(sslProvider).trustManager(_trustedCerts).keyManager(_key, _cert);
return buildSSLContext0(_sslClientContextBuilder);
}
private SslContext buildSSLClientContext(final File _key, final File _cert, final File _trustedCerts,
final String pwd, final Iterable<String> ciphers, final SslProvider sslProvider) throws SSLException {
final SslContextBuilder _sslClientContextBuilder = SslContextBuilder.forClient().ciphers(ciphers)
.applicationProtocolConfig(ApplicationProtocolConfig.DISABLED).sessionCacheSize(0).sessionTimeout(0)
.sslProvider(sslProvider).trustManager(_trustedCerts).keyManager(_cert, _key, pwd);
return buildSSLContext0(_sslClientContextBuilder);
}
private SslContext buildSSLContext0(final SslContextBuilder sslContextBuilder) throws SSLException {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SpecialPermission());
}
SslContext sslContext = null;
try {
sslContext = AccessController.doPrivileged(new PrivilegedExceptionAction<SslContext>() {
@Override
public SslContext run() throws Exception {
return sslContextBuilder.build();
}
});
} catch (final PrivilegedActionException e) {
throw (SSLException) e.getCause();
}
return sslContext;
}
private void logExplanation(Exception e) {
if (ExceptionUtils.findMsg(e, "not contain valid private key") != null) {
log.error("Your keystore or PEM does not contain a key. "
+ "If you specified a key password, try removing it. "
+ "If you did not specify a key password, perhaps you need to if the key is in fact password-protected. "
+ "Maybe you just confused keys and certificates.");
}
if (ExceptionUtils.findMsg(e, "not contain valid certificates") != null) {
log.error("Your keystore or PEM does not contain a certificate. Maybe you confused keys and certificates.");
}
}
private static void checkPath(String keystoreFilePath, String fileNameLogOnly) {
if (keystoreFilePath == null || keystoreFilePath.length() == 0) {
throw new ElasticsearchException("Empty file path for " + fileNameLogOnly);
}
if (Files.isDirectory(Paths.get(keystoreFilePath), LinkOption.NOFOLLOW_LINKS)) {
throw new ElasticsearchException(
"Is a directory: " + keystoreFilePath + " Expected a file for " + fileNameLogOnly);
}
if (!Files.isReadable(Paths.get(keystoreFilePath))) {
throw new ElasticsearchException("Unable to read " + keystoreFilePath + " (" + Paths.get(keystoreFilePath)
+ "). Please make sure this files exists and is readable regarding to permissions. Property: "
+ fileNameLogOnly);
}
}
}

View File

@ -0,0 +1,152 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.settings.Settings;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
public class ExternalOpenDistroSecurityKeyStore implements OpenDistroSecurityKeyStore {
private static final String EXTERNAL = "EXTERNAL";
private static final Map<String, SSLContext> contextMap = new ConcurrentHashMap<String, SSLContext>();
private final SSLContext externalSslContext;
private final Settings settings;
public ExternalOpenDistroSecurityKeyStore(final Settings settings) {
this.settings = Objects.requireNonNull(settings);
final String externalContextId = settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID, null);
if(externalContextId == null || externalContextId.length() == 0) {
throw new ElasticsearchException("no external ssl context id was set");
}
externalSslContext = contextMap.get(externalContextId);
if(externalSslContext == null) {
throw new ElasticsearchException("no external ssl context for id "+externalContextId);
}
}
@Override
public SSLEngine createHTTPSSLEngine() throws SSLException {
throw new SSLException("not implemented");
}
@Override
public SSLEngine createServerTransportSSLEngine() throws SSLException {
throw new SSLException("not implemented");
}
@Override
public SSLEngine createClientTransportSSLEngine(final String peerHost, final int peerPort) throws SSLException {
if (peerHost != null) {
final SSLEngine engine = externalSslContext.createSSLEngine(peerHost, peerPort);
final SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
engine.setSSLParameters(sslParams);
engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, false)));
engine.setEnabledCipherSuites(evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, false).toArray(new String[0])));
engine.setUseClientMode(true);
return engine;
} else {
final SSLEngine engine = externalSslContext.createSSLEngine();
engine.setEnabledProtocols(evalSecure(engine.getEnabledProtocols(), SSLConfigConstants.getSecureSSLProtocols(settings, false)));
engine.setEnabledCipherSuites(evalSecure(engine.getEnabledCipherSuites(), SSLConfigConstants.getSecureSSLCiphers(settings, false).toArray(new String[0])));
engine.setUseClientMode(true);
return engine;
}
}
@Override
public String getHTTPProviderName() {
return null;
}
@Override
public String getTransportServerProviderName() {
return null;
}
@Override
public String getTransportClientProviderName() {
return EXTERNAL;
}
public static void registerExternalSslContext(String id, SSLContext externalSsslContext) {
contextMap.put(Objects.requireNonNull(id), Objects.requireNonNull(externalSsslContext));
}
public static boolean hasExternalSslContext(Settings settings) {
final String externalContextId = settings
.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID, null);
if(externalContextId == null || externalContextId.length() == 0) {
return false;
}
return contextMap.containsKey(externalContextId);
}
public static boolean hasExternalSslContext(String id) {
return contextMap.containsKey(id);
}
public static void removeExternalSslContext(String id) {
contextMap.remove(id);
}
public static void removeAllExternalSslContexts() {
contextMap.clear();
}
private String[] evalSecure(String[] engineEnabled, String[] secure) {
List<String> tmp = new ArrayList<>(Arrays.asList(engineEnabled));
tmp.retainAll(Arrays.asList(secure));
return tmp.toArray(new String[0]);
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
public interface OpenDistroSecurityKeyStore {
public SSLEngine createHTTPSSLEngine() throws SSLException;
public SSLEngine createServerTransportSSLEngine() throws SSLException;
public SSLEngine createClientTransportSSLEngine(String peerHost, int peerPort) throws SSLException;
public String getHTTPProviderName();
public String getTransportServerProviderName();
public String getTransportClientProviderName();
}

View File

@ -0,0 +1,385 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import io.netty.handler.ssl.OpenSsl;
import io.netty.util.internal.PlatformDependent;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.SpecialPermission;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.IndexScopedSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsFilter;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.util.PageCacheRecycler;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.http.HttpServerTransport.Dispatcher;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.NetworkPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.Transport;
import org.elasticsearch.transport.TransportInterceptor;
import org.elasticsearch.watcher.ResourceWatcherService;
import com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyHttpServerTransport;
import com.amazon.opendistroforelasticsearch.security.ssl.http.netty.ValidatingDispatcher;
import com.amazon.opendistroforelasticsearch.security.ssl.rest.OpenDistroSecuritySSLInfoAction;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.OpenDistroSecuritySSLNettyTransport;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.OpenDistroSecuritySSLTransportInterceptor;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
//For ES5 this class has only effect when SSL only plugin is installed
public class OpenDistroSecuritySSLPlugin extends Plugin implements ActionPlugin, NetworkPlugin {
protected final Logger log = LogManager.getLogger(this.getClass());
protected static final String CLIENT_TYPE = "client.type";
protected final boolean client;
protected final boolean httpSSLEnabled;
protected final boolean transportSSLEnabled;
protected final Settings settings;
protected final OpenDistroSecurityKeyStore odsks;
protected PrincipalExtractor principalExtractor;
protected final Path configPath;
private final static SslExceptionHandler NOOP_SSL_EXCEPTION_HANDLER = new SslExceptionHandler() {};
public OpenDistroSecuritySSLPlugin(final Settings settings, final Path configPath) {
this(settings, configPath, false);
}
protected OpenDistroSecuritySSLPlugin(final Settings settings, final Path configPath, boolean disabled) {
if(disabled) {
this.settings = null;
this.client = false;
this.httpSSLEnabled = false;
this.transportSSLEnabled = false;
this.odsks = null;
this.configPath = null;
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
System.setProperty("es.set.netty.runtime.available.processors", "false");
return null;
}
});
return;
}
this.configPath = configPath;
if(this.configPath != null) {
log.info("ES Config path is "+this.configPath.toAbsolutePath());
} else {
log.info("ES Config path is not set");
}
final boolean allowClientInitiatedRenegotiation = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_ALLOW_CLIENT_INITIATED_RENEGOTIATION, false);
final boolean rejectClientInitiatedRenegotiation = Boolean.parseBoolean(System.getProperty(SSLConfigConstants.JDK_TLS_REJECT_CLIENT_INITIATED_RENEGOTIATION));
if(allowClientInitiatedRenegotiation && !rejectClientInitiatedRenegotiation) {
final String renegoMsg = "Client side initiated TLS renegotiation enabled. This can open a vulnerablity for DoS attacks through client side initiated TLS renegotiation.";
log.warn(renegoMsg);
System.out.println(renegoMsg);
System.err.println(renegoMsg);
} else {
if(!rejectClientInitiatedRenegotiation) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SpecialPermission());
}
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
System.setProperty(SSLConfigConstants.JDK_TLS_REJECT_CLIENT_INITIATED_RENEGOTIATION, "true");
return null;
}
});
log.debug("Client side initiated TLS renegotiation forcibly disabled. This can prevent DoS attacks. (jdk.tls.rejectClientInitiatedRenegotiation set to true).");
} else {
log.debug("Client side initiated TLS renegotiation already disabled.");
}
}
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SpecialPermission());
}
//TODO check initialize native netty open ssl libs still neccessary
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
System.setProperty("es.set.netty.runtime.available.processors", "false");
PlatformDependent.newFixedMpscQueue(1);
OpenSsl.isAvailable();
return null;
}
});
this.settings = settings;
client = !"node".equals(this.settings.get(OpenDistroSecuritySSLPlugin.CLIENT_TYPE));
httpSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED,
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT);
transportSSLEnabled = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED,
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT);
if (!httpSSLEnabled && !transportSSLEnabled) {
log.error("SSL not activated for http and/or transport.");
System.out.println("SSL not activated for http and/or transport.");
System.err.println("SSL not activated for http and/or transport.");
}
if(ExternalOpenDistroSecurityKeyStore.hasExternalSslContext(settings)) {
this.odsks = new ExternalOpenDistroSecurityKeyStore(settings);
} else {
this.odsks = new DefaultOpenDistroSecurityKeyStore(settings, configPath);
}
}
@Override
public Map<String, Supplier<HttpServerTransport>> getHttpTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays,
CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry,
NamedXContentRegistry xContentRegistry, NetworkService networkService, Dispatcher dispatcher) {
final Map<String, Supplier<HttpServerTransport>> httpTransports = new HashMap<String, Supplier<HttpServerTransport>>(1);
if (!client && httpSSLEnabled) {
final ValidatingDispatcher validatingDispatcher = new ValidatingDispatcher(threadPool.getThreadContext(), dispatcher, settings, configPath, NOOP_SSL_EXCEPTION_HANDLER);
final OpenDistroSecuritySSLNettyHttpServerTransport sgsnht = new OpenDistroSecuritySSLNettyHttpServerTransport(settings, networkService, bigArrays, threadPool, odsks, xContentRegistry, validatingDispatcher, NOOP_SSL_EXCEPTION_HANDLER);
httpTransports.put("com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyHttpServerTransport", () -> sgsnht);
}
return httpTransports;
}
@Override
public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,
IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter,
IndexNameExpressionResolver indexNameExpressionResolver, Supplier<DiscoveryNodes> nodesInCluster) {
final List<RestHandler> handlers = new ArrayList<RestHandler>(1);
if (!client) {
handlers.add(new OpenDistroSecuritySSLInfoAction(settings, configPath, restController, odsks, Objects.requireNonNull(principalExtractor)));
}
return handlers;
}
@Override
public List<TransportInterceptor> getTransportInterceptors(NamedWriteableRegistry namedWriteableRegistry, ThreadContext threadContext) {
List<TransportInterceptor> interceptors = new ArrayList<TransportInterceptor>(1);
if(transportSSLEnabled && !client) {
interceptors.add(new OpenDistroSecuritySSLTransportInterceptor(settings, null, null, NOOP_SSL_EXCEPTION_HANDLER));
}
return interceptors;
}
@Override
public Map<String, Supplier<Transport>> getTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays,
PageCacheRecycler pageCacheRecycler, CircuitBreakerService circuitBreakerService,
NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) {
Map<String, Supplier<Transport>> transports = new HashMap<String, Supplier<Transport>>();
if (transportSSLEnabled) {
transports.put("com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyTransport",
() -> new OpenDistroSecuritySSLNettyTransport(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService, odsks, NOOP_SSL_EXCEPTION_HANDLER));
}
return transports;
}
@Override
public Collection<Object> createComponents(Client localClient, ClusterService clusterService, ThreadPool threadPool,
ResourceWatcherService resourceWatcherService, ScriptService scriptService, NamedXContentRegistry xContentRegistry,
Environment environment, NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry) {
final List<Object> components = new ArrayList<>(1);
if(client) {
return components;
}
final String principalExtractorClass = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PRINCIPAL_EXTRACTOR_CLASS, null);
if(principalExtractorClass == null) {
principalExtractor = new com.amazon.opendistroforelasticsearch.security.ssl.transport.DefaultPrincipalExtractor();
} else {
try {
log.debug("Try to load and instantiate '{}'", principalExtractorClass);
Class<?> principalExtractorClazz = Class.forName(principalExtractorClass);
principalExtractor = (PrincipalExtractor) principalExtractorClazz.newInstance();
} catch (Exception e) {
log.error("Unable to load '{}' due to", principalExtractorClass, e);
throw new ElasticsearchException(e);
}
}
components.add(principalExtractor);
return components;
}
@Override
public List<Setting<?>> getSettings() {
List<Setting<?>> settings = new ArrayList<Setting<?>>();
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CLIENTAUTH_MODE, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_TYPE, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, true, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED, SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, true,Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED, SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION, true, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME, true, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_ALIAS, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE, Property.NodeScope, Property.Filtered));
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
settings.add(Setting.listSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, Collections.emptyList(), Function.identity(), Property.NodeScope));//not filtered here
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PRINCIPAL_EXTRACTOR_CLASS, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, Property.NodeScope, Property.Filtered));
settings.add(Setting.simpleString(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, false, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_PREFER_CRLFILE_OVER_OCSP, false, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_CHECK_ONLY_END_ENTITIES, true, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_CRLDP, false, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_OCSP, false, Property.NodeScope, Property.Filtered));
settings.add(Setting.longSetting(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, -1, -1, Property.NodeScope, Property.Filtered));
return settings;
}
@Override
public Settings additionalSettings() {
final Settings.Builder builder = Settings.builder();
if(!client && httpSSLEnabled) {
if(settings.get("http.compression") == null) {
builder.put("http.compression", false);
log.info("Disabled https compression by default to mitigate BREACH attacks. You can enable it by setting 'http.compression: true' in elasticsearch.yml");
}
builder.put(NetworkModule.HTTP_TYPE_KEY, "com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyHttpServerTransport");
}
if (transportSSLEnabled) {
builder.put(NetworkModule.TRANSPORT_TYPE_KEY, "com.amazon.opendistroforelasticsearch.security.ssl.http.netty.OpenDistroSecuritySSLNettyTransport");
}
return builder.build();
}
@Override
public List<String> getSettingsFilter() {
List<String> settingsFilter = new ArrayList<>();
settingsFilter.add("opendistro_security.*");
return settingsFilter;
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.transport.TransportRequest;
public interface SslExceptionHandler {
default void logError(Throwable t, RestRequest request, int type) {
//no-op
}
default void logError(Throwable t, boolean isRest) {
//no-op
}
default void logError(Throwable t, final TransportRequest request, String action, Task task, int type) {
//no-op
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.http.netty;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.ssl.NotSslRecordException;
import io.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.http.netty4.Netty4HttpServerTransport;
import org.elasticsearch.threadpool.ThreadPool;
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecurityKeyStore;
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
public class OpenDistroSecuritySSLNettyHttpServerTransport extends Netty4HttpServerTransport {
private final OpenDistroSecurityKeyStore sgks;
private final ThreadContext threadContext;
private final SslExceptionHandler errorHandler;
public OpenDistroSecuritySSLNettyHttpServerTransport(final Settings settings, final NetworkService networkService, final BigArrays bigArrays,
final ThreadPool threadPool, final OpenDistroSecurityKeyStore sgks, final NamedXContentRegistry namedXContentRegistry, final ValidatingDispatcher dispatcher,
final SslExceptionHandler errorHandler) {
super(settings, networkService, bigArrays, threadPool, namedXContentRegistry, dispatcher);
this.sgks = sgks;
this.threadContext = threadPool.getThreadContext();
this.errorHandler = errorHandler;
}
@Override
public ChannelHandler configureServerChannelHandler() {
return new SSLHttpChannelHandler(this, sgks);
}
@Override
protected final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if(this.lifecycle.started()) {
if(cause instanceof DecoderException && cause != null) {
cause = cause.getCause();
}
errorHandler.logError(cause, true);
if(cause instanceof NotSslRecordException) {
logger.warn("Someone ({}) speaks http plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
ctx.channel().close();
return;
} else if (cause instanceof SSLException) {
logger.error("SSL Problem "+cause.getMessage(),cause);
ctx.channel().close();
return;
} else if (cause instanceof SSLHandshakeException) {
logger.error("Problem during handshake "+cause.getMessage());
ctx.channel().close();
return;
}
}
super.exceptionCaught(ctx, cause);
}
protected class SSLHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler {
protected SSLHttpChannelHandler(Netty4HttpServerTransport transport, final OpenDistroSecurityKeyStore sgks) {
super(transport, OpenDistroSecuritySSLNettyHttpServerTransport.this.detailedErrorsEnabled, OpenDistroSecuritySSLNettyHttpServerTransport.this.threadContext);
}
@Override
protected void initChannel(Channel ch) throws Exception {
super.initChannel(ch);
final SslHandler sslHandler = new SslHandler(OpenDistroSecuritySSLNettyHttpServerTransport.this.sgks.createHTTPSSLEngine());
ch.pipeline().addFirst("ssl_http", sslHandler);
}
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.http.netty;
import java.nio.file.Path;
import javax.net.ssl.SSLPeerUnverifiedException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.http.HttpServerTransport.Dispatcher;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestStatus;
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper;
public class ValidatingDispatcher implements Dispatcher {
private static final Logger logger = LogManager.getLogger(ValidatingDispatcher.class);
private final ThreadContext threadContext;
private final Dispatcher originalDispatcher;
private final SslExceptionHandler errorHandler;
private final Settings settings;
private final Path configPath;
public ValidatingDispatcher(final ThreadContext threadContext, final Dispatcher originalDispatcher,
final Settings settings, final Path configPath, final SslExceptionHandler errorHandler) {
super();
this.threadContext = threadContext;
this.originalDispatcher = originalDispatcher;
this.settings = settings;
this.configPath = configPath;
this.errorHandler = errorHandler;
}
@Override
public void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext) {
checkRequest(request, channel);
originalDispatcher.dispatchRequest(request, channel, threadContext);
}
@Override
public void dispatchBadRequest(RestRequest request, RestChannel channel, ThreadContext threadContext, Throwable cause) {
checkRequest(request, channel);
originalDispatcher.dispatchBadRequest(request, channel, threadContext, cause);
}
protected void checkRequest(final RestRequest request, final RestChannel channel) {
if(SSLRequestHelper.containsBadHeader(threadContext, "_opendistro_security_ssl_")) {
final ElasticsearchException exception = ExceptionUtils.createBadHeaderException();
errorHandler.logError(exception, request, 1);
throw exception;
}
try {
if(SSLRequestHelper.getSSLInfo(settings, configPath, request, null) == null) {
logger.error("Not an SSL request");
throw new ElasticsearchSecurityException("Not an SSL request", RestStatus.INTERNAL_SERVER_ERROR);
}
} catch (SSLPeerUnverifiedException e) {
logger.error("No client certificates found but such are needed (Security 8).");
errorHandler.logError(e, request, 0);
throw ExceptionsHelper.convertToElastic(e);
}
}
}

View File

@ -0,0 +1,136 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.rest;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import io.netty.handler.ssl.OpenSsl;
import java.io.IOException;
import java.nio.file.Path;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.BytesRestResponse;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestStatus;
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecurityKeyStore;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper.SSLInfo;
public class OpenDistroSecuritySSLInfoAction extends BaseRestHandler {
private final OpenDistroSecurityKeyStore sgks;
final PrincipalExtractor principalExtractor;
private final Path configPath;
public OpenDistroSecuritySSLInfoAction(final Settings settings, final Path configPath, final RestController controller,
final OpenDistroSecurityKeyStore sgks, final PrincipalExtractor principalExtractor) {
super(settings);
this.sgks = sgks;
this.principalExtractor = principalExtractor;
this.configPath = configPath;
controller.registerHandler(GET, "/_opendistro/_security/sslinfo", this);
}
@Override
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
return new RestChannelConsumer() {
final Boolean showDn = request.paramAsBoolean("show_dn", Boolean.FALSE);
@Override
public void accept(RestChannel channel) throws Exception {
XContentBuilder builder = channel.newBuilder();
BytesRestResponse response = null;
try {
SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor);
X509Certificate[] certs = sslInfo == null?null:sslInfo.getX509Certs();
X509Certificate[] localCerts = sslInfo == null?null:sslInfo.getLocalCertificates();
builder.startObject();
builder.field("principal", sslInfo == null?null:sslInfo.getPrincipal());
builder.field("peer_certificates", certs != null && certs.length > 0 ? certs.length + "" : "0");
if(showDn == Boolean.TRUE) {
builder.field("peer_certificates_list", certs == null?null:Arrays.stream(certs).map(c->c.getSubjectDN().getName()).collect(Collectors.toList()));
builder.field("local_certificates_list", localCerts == null?null:Arrays.stream(localCerts).map(c->c.getSubjectDN().getName()).collect(Collectors.toList()));
}
builder.field("ssl_protocol", sslInfo == null?null:sslInfo.getProtocol());
builder.field("ssl_cipher", sslInfo == null?null:sslInfo.getCipher());
builder.field("ssl_openssl_available", OpenSsl.isAvailable());
builder.field("ssl_openssl_version", OpenSsl.version());
builder.field("ssl_openssl_version_string", OpenSsl.versionString());
Throwable openSslUnavailCause = OpenSsl.unavailabilityCause();
builder.field("ssl_openssl_non_available_cause", openSslUnavailCause==null?"":openSslUnavailCause.toString());
builder.field("ssl_openssl_supports_key_manager_factory", OpenSsl.supportsKeyManagerFactory());
builder.field("ssl_openssl_supports_hostname_validation", OpenSsl.supportsHostnameValidation());
builder.field("ssl_provider_http", sgks.getHTTPProviderName());
builder.field("ssl_provider_transport_server", sgks.getTransportServerProviderName());
builder.field("ssl_provider_transport_client", sgks.getTransportClientProviderName());
builder.endObject();
response = new BytesRestResponse(RestStatus.OK, builder);
} catch (final Exception e1) {
logger.error("Error handle request "+e1, e1);
builder = channel.newBuilder();
builder.startObject();
builder.field("error", e1.toString());
builder.endObject();
response = new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, builder);
} finally {
if(builder != null) {
builder.close();
}
}
channel.sendResponse(response);
}
};
}
@Override
public String getName() {
return "Open Distro Security SSL Info";
}
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.security.auth.x500.X500Principal;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.SpecialPermission;
public class DefaultPrincipalExtractor implements PrincipalExtractor {
protected final Logger log = LogManager.getLogger(this.getClass());
@Override
public String extractPrincipal(final X509Certificate x509Certificate, final Type type) {
if (x509Certificate == null) {
return null;
}
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SpecialPermission());
}
String dnString = AccessController.doPrivileged(new PrivilegedAction<String>() {
@Override
public String run() {
final X500Principal principal = x509Certificate.getSubjectX500Principal();
return principal.toString();
}
});
//remove whitespaces
try {
final LdapName ln = new LdapName(dnString);
final List<Rdn> rdns = new ArrayList<>(ln.getRdns());
Collections.reverse(rdns);
dnString = String.join(",", rdns.stream().map(r->r.toString()).collect(Collectors.toList()));
} catch (InvalidNameException e) {
log.error("Unable to parse: {}",dnString, e);
}
if(log.isTraceEnabled()) {
log.trace("principal: {}", dnString);
}
return dnString;
}
}

View File

@ -0,0 +1,283 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.ssl.NotSslRecordException;
import io.netty.handler.ssl.SslHandler;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.network.NetworkService;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TcpChannel;
import org.elasticsearch.transport.netty4.Netty4Transport;
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecurityKeyStore;
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
public class OpenDistroSecuritySSLNettyTransport extends Netty4Transport {
private final OpenDistroSecurityKeyStore sgks;
private final SslExceptionHandler errorHandler;
public OpenDistroSecuritySSLNettyTransport(final Settings settings, final ThreadPool threadPool, final NetworkService networkService,
final BigArrays bigArrays, final NamedWriteableRegistry namedWriteableRegistry,
final CircuitBreakerService circuitBreakerService, final OpenDistroSecurityKeyStore sgks, final SslExceptionHandler errorHandler) {
super(settings, threadPool, networkService, bigArrays, namedWriteableRegistry, circuitBreakerService);
this.sgks = sgks;
this.errorHandler = errorHandler;
}
@Override
protected void onException(TcpChannel channel, Exception e) {
if (lifecycle.started()) {
Throwable cause = e;
if(e instanceof DecoderException && e != null) {
cause = e.getCause();
}
errorHandler.logError(cause, false);
if(cause instanceof NotSslRecordException) {
logger.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", channel.getLocalAddress());
TcpChannel.closeChannel(channel, false);
return;
} else if (cause instanceof SSLException) {
logger.error("SSL Problem "+cause.getMessage(),cause);
TcpChannel.closeChannel(channel, false);
return;
} else if (cause instanceof SSLHandshakeException) {
logger.error("Problem during handshake "+cause.getMessage());
TcpChannel.closeChannel(channel, false);
return;
}
}
super.onException(channel, e);
}
@Override
protected ChannelHandler getServerChannelInitializer(String name) {
return new SSLServerChannelInitializer(name);
}
@Override
protected ChannelHandler getClientChannelInitializer(DiscoveryNode node) {
return new SSLClientChannelInitializer(node);
}
protected class SSLServerChannelInitializer extends Netty4Transport.ServerChannelInitializer {
public SSLServerChannelInitializer(String name) {
super(name);
}
@Override
protected void initChannel(Channel ch) throws Exception {
super.initChannel(ch);
final SslHandler sslHandler = new SslHandler(sgks.createServerTransportSSLEngine());
ch.pipeline().addFirst("ssl_server", sslHandler);
}
@Override
public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if(OpenDistroSecuritySSLNettyTransport.this.lifecycle.started()) {
if(cause instanceof DecoderException && cause != null) {
cause = cause.getCause();
}
errorHandler.logError(cause, false);
if(cause instanceof NotSslRecordException) {
logger.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
ctx.channel().close();
return;
} else if (cause instanceof SSLException) {
logger.error("SSL Problem "+cause.getMessage(),cause);
ctx.channel().close();
return;
} else if (cause instanceof SSLHandshakeException) {
logger.error("Problem during handshake "+cause.getMessage());
ctx.channel().close();
return;
}
}
super.exceptionCaught(ctx, cause);
}
}
protected static class ClientSSLHandler extends ChannelOutboundHandlerAdapter {
private final Logger log = LogManager.getLogger(this.getClass());
private final OpenDistroSecurityKeyStore sgks;
private final boolean hostnameVerificationEnabled;
private final boolean hostnameVerificationResovleHostName;
private final SslExceptionHandler errorHandler;
private ClientSSLHandler(final OpenDistroSecurityKeyStore sgks, final boolean hostnameVerificationEnabled,
final boolean hostnameVerificationResovleHostName, final SslExceptionHandler errorHandler) {
this.sgks = sgks;
this.hostnameVerificationEnabled = hostnameVerificationEnabled;
this.hostnameVerificationResovleHostName = hostnameVerificationResovleHostName;
this.errorHandler = errorHandler;
}
@Override
public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if(cause instanceof DecoderException && cause != null) {
cause = cause.getCause();
}
errorHandler.logError(cause, false);
if(cause instanceof NotSslRecordException) {
log.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
ctx.channel().close();
return;
} else if (cause instanceof SSLException) {
log.error("SSL Problem "+cause.getMessage(),cause);
ctx.channel().close();
return;
} else if (cause instanceof SSLHandshakeException) {
log.error("Problem during handshake "+cause.getMessage());
ctx.channel().close();
return;
}
super.exceptionCaught(ctx, cause);
}
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
SSLEngine engine = null;
try {
if (hostnameVerificationEnabled) {
final InetSocketAddress inetSocketAddress = (InetSocketAddress) remoteAddress;
String hostname = null;
if (hostnameVerificationResovleHostName) {
hostname = inetSocketAddress.getHostName();
} else {
hostname = inetSocketAddress.getHostString();
}
if(log.isDebugEnabled()) {
log.debug("Hostname of peer is {} ({}/{}) with hostnameVerificationResovleHostName: {}", hostname, inetSocketAddress.getHostName(), inetSocketAddress.getHostString(), hostnameVerificationResovleHostName);
}
engine = sgks.createClientTransportSSLEngine(hostname, inetSocketAddress.getPort());
} else {
engine = sgks.createClientTransportSSLEngine(null, -1);
}
} catch (final SSLException e) {
throw ExceptionsHelper.convertToElastic(e);
}
final SslHandler sslHandler = new SslHandler(engine);
ctx.pipeline().replace(this, "ssl_client", sslHandler);
super.connect(ctx, remoteAddress, localAddress, promise);
}
}
protected class SSLClientChannelInitializer extends Netty4Transport.ClientChannelInitializer {
private final boolean hostnameVerificationEnabled;
private final boolean hostnameVerificationResovleHostName;
public SSLClientChannelInitializer(DiscoveryNode node) {
hostnameVerificationEnabled = settings.getAsBoolean(
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION, true);
hostnameVerificationResovleHostName = settings.getAsBoolean(
SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME, true);
}
@Override
protected void initChannel(Channel ch) throws Exception {
super.initChannel(ch);
ch.pipeline().addFirst("client_ssl_handler", new ClientSSLHandler(sgks, hostnameVerificationEnabled,
hostnameVerificationResovleHostName, errorHandler));
}
@Override
public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if(OpenDistroSecuritySSLNettyTransport.this.lifecycle.started()) {
if(cause instanceof DecoderException && cause != null) {
cause = cause.getCause();
}
errorHandler.logError(cause, false);
if(cause instanceof NotSslRecordException) {
logger.warn("Someone ({}) speaks transport plaintext instead of ssl, will close the channel", ctx.channel().remoteAddress());
ctx.channel().close();
return;
} else if (cause instanceof SSLException) {
logger.error("SSL Problem "+cause.getMessage(),cause);
ctx.channel().close();
return;
} else if (cause instanceof SSLHandshakeException) {
logger.error("Problem during handshake "+cause.getMessage());
ctx.channel().close();
return;
}
}
super.exceptionCaught(ctx, cause);
}
}
}

View File

@ -0,0 +1,185 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
import io.netty.channel.Channel;
import io.netty.handler.ssl.SslHandler;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import javax.net.ssl.SSLPeerUnverifiedException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TaskTransportChannel;
import org.elasticsearch.transport.TcpChannel;
import org.elasticsearch.transport.TcpTransportChannel;
import org.elasticsearch.transport.TransportChannel;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.transport.TransportRequestHandler;
import org.elasticsearch.transport.netty4.NettyTcpChannel;
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLRequestHelper;
public class OpenDistroSecuritySSLRequestHandler<T extends TransportRequest>
implements TransportRequestHandler<T> {
private final String action;
private final TransportRequestHandler<T> actualHandler;
private final ThreadPool threadPool;
protected final Logger log = LogManager.getLogger(this.getClass());
private final PrincipalExtractor principalExtractor;
private final SslExceptionHandler errorHandler;
public OpenDistroSecuritySSLRequestHandler(String action, TransportRequestHandler<T> actualHandler,
ThreadPool threadPool, final PrincipalExtractor principalExtractor, final SslExceptionHandler errorHandler) {
super();
this.action = action;
this.actualHandler = actualHandler;
this.threadPool = threadPool;
this.principalExtractor = principalExtractor;
this.errorHandler = errorHandler;
}
protected ThreadContext getThreadContext() {
if(threadPool == null) {
return null;
}
return threadPool.getThreadContext();
}
@Override
public final void messageReceived(T request, TransportChannel channel) throws Exception {
messageReceived(request, channel, null);
}
@Override
public final void messageReceived(T request, TransportChannel channel, Task task) throws Exception {
ThreadContext threadContext = getThreadContext() ;
if(SSLRequestHelper.containsBadHeader(threadContext, "_opendistro_security_ssl_")) {
final Exception exception = ExceptionUtils.createBadHeaderException();
channel.sendResponse(exception);
throw exception;
}
if (!"netty".equals(channel.getChannelType())) { //netty4
messageReceivedDecorate(request, actualHandler, channel, task);
return;
}
try {
NettyTcpChannel nettyChannel = null;
if (channel instanceof TaskTransportChannel) {
final TransportChannel inner = ((TaskTransportChannel) channel).getChannel();
nettyChannel = (NettyTcpChannel) ((TcpTransportChannel) inner).getChannel();
} else
if (channel instanceof TcpTransportChannel) {
final TcpChannel inner = ((TcpTransportChannel) channel).getChannel();
nettyChannel = (NettyTcpChannel) inner;
} else {
throw new Exception("Invalid channel of type "+channel.getClass()+ " ("+channel.getChannelType()+")");
}
final SslHandler sslhandler = (SslHandler) nettyChannel.getLowLevelChannel().pipeline().get("ssl_server");
if (sslhandler == null) {
final String msg = "No ssl handler found (Security 11)";
//log.error(msg);
final Exception exception = new ElasticsearchException(msg);
channel.sendResponse(exception);
throw exception;
}
final Certificate[] peerCerts = sslhandler.engine().getSession().getPeerCertificates();
final Certificate[] localCerts = sslhandler.engine().getSession().getLocalCertificates();
if (peerCerts != null
&& peerCerts.length > 0
&& peerCerts[0] instanceof X509Certificate
&& localCerts != null && localCerts.length > 0
&& localCerts[0] instanceof X509Certificate) {
final X509Certificate[] x509PeerCerts = Arrays.copyOf(peerCerts, peerCerts.length, X509Certificate[].class);
final X509Certificate[] x509LocalCerts = Arrays.copyOf(localCerts, localCerts.length, X509Certificate[].class);
final String principal = principalExtractor==null?null:principalExtractor.extractPrincipal(x509PeerCerts[0], PrincipalExtractor.Type.TRANSPORT);
addAdditionalContextValues(action, request, x509LocalCerts, x509PeerCerts, principal);
if(threadContext != null) {
//in the case of ssl plugin only: threadContext and principalExtractor are null
threadContext.putTransient("_opendistro_security_ssl_transport_principal", principal);
threadContext.putTransient("_opendistro_security_ssl_transport_peer_certificates", x509PeerCerts);
threadContext.putTransient("_opendistro_security_ssl_transport_local_certificates", x509LocalCerts);
threadContext.putTransient("_opendistro_security_ssl_transport_protocol", sslhandler.engine().getSession().getProtocol());
threadContext.putTransient("_opendistro_security_ssl_transport_cipher", sslhandler.engine().getSession().getCipherSuite());
}
messageReceivedDecorate(request, actualHandler, channel, task);
} else {
final String msg = "No X509 transport client certificates found (Security 12)";
//log.error(msg);
final Exception exception = new ElasticsearchException(msg);
errorHandler.logError(exception, request, action, task, 0);
channel.sendResponse(exception);
throw exception;
}
} catch (final SSLPeerUnverifiedException e) {
errorHandler.logError(e, request, action, task, 0);
final Exception exception = ExceptionsHelper.convertToElastic(e);
channel.sendResponse(exception);
throw exception;
} catch (final Exception e) {
errorHandler.logError(e, request, action, task, 0);
throw e;
}
}
protected void addAdditionalContextValues(final String action, final TransportRequest request, final X509Certificate[] localCerts, final X509Certificate[] peerCerts, final String principal)
throws Exception {
// no-op
}
protected void messageReceivedDecorate(final T request, final TransportRequestHandler<T> actualHandler, final TransportChannel transportChannel, Task task) throws Exception {
actualHandler.messageReceived(request, transportChannel, task);
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportInterceptor;
import org.elasticsearch.transport.TransportRequest;
import org.elasticsearch.transport.TransportRequestHandler;
import com.amazon.opendistroforelasticsearch.security.ssl.SslExceptionHandler;
public final class OpenDistroSecuritySSLTransportInterceptor implements TransportInterceptor {
protected final Logger log = LogManager.getLogger(this.getClass());
protected final ThreadPool threadPool;
protected final PrincipalExtractor principalExtractor;
protected final SslExceptionHandler errorHandler;
public OpenDistroSecuritySSLTransportInterceptor(final Settings settings, final ThreadPool threadPool,
PrincipalExtractor principalExtractor, final SslExceptionHandler errorHandler) {
this.threadPool = threadPool;
this.principalExtractor = principalExtractor;
this.errorHandler = errorHandler;
}
@Override
public <T extends TransportRequest> TransportRequestHandler<T> interceptHandler(String action, String executor, boolean forceExecution,
TransportRequestHandler<T> actualHandler) {
return new OpenDistroSecuritySSLRequestHandler<T>(action, actualHandler, threadPool, principalExtractor, errorHandler);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.transport;
import java.security.cert.X509Certificate;
public interface PrincipalExtractor {
public enum Type {
HTTP,
TRANSPORT
}
/**
* Extract the principal name
*
* Please note that this method gets called for principal extraction of other nodes
* as well as transport clients. It's up to the implementer to distinguish between them
* and handle them appropriately.
*
* Implementations must be public classes with a default public default constructor.
*
* @param x509Certificate The first X509 certificate in the peer certificate chain
* This can be null, in this case the method must also return <code>null</code>.
* @return The principal as string. This may be <code>null</code> in case where x509Certificate is null
* or the principal cannot be extracted because of any other circumstances.
*/
String extractPrincipal(X509Certificate x509Certificate, Type type);
}

View File

@ -0,0 +1,337 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.util;
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
import java.security.GeneralSecurityException;
import java.security.InvalidParameterException;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.CRL;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderResult;
import java.security.cert.CertPathValidator;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* Convenience class to handle validation of certificates, aliases and keystores
*
* Allows specifying Certificate Revocation List (CRL), as well as enabling
* CRL Distribution Points Protocol (CRLDP) certificate extension support,
* and also enabling On-Line Certificate Status Protocol (OCSP) support.
*
* IMPORTANT: at least one of the above mechanisms *MUST* be configured and
* operational, otherwise certificate validation *WILL FAIL* unconditionally.
*/
public class CertificateValidator
{
boolean isPreferCrl() {
return preferCrl;
}
void setPreferCrl(boolean preferCrl) {
this.preferCrl = preferCrl;
}
boolean isCheckOnlyEndEntities() {
return checkOnlyEndEntities;
}
void setCheckOnlyEndEntities(boolean checkOnlyEndEntities) {
this.checkOnlyEndEntities = checkOnlyEndEntities;
}
private KeyStore _trustStore;
private X509Certificate[] _trustedCert;
private Collection<? extends CRL> _crls;
/** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */
private int _maxCertPathLength = -1;
/** CRL Distribution Points (CRLDP) support */
private boolean _enableCRLDP = false;
/** On-Line Certificate Status Protocol (OCSP) support */
private boolean _enableOCSP = false;
/** Location of OCSP Responder */
private String _ocspResponderURL;
private boolean preferCrl = false;
private boolean checkOnlyEndEntities = true;
private Date date = null; //current date
/**
* creates an instance of the certificate validator
*
* @param trustStore the truststore to use
* @param crls the Certificate Revocation List to use
*/
public CertificateValidator(KeyStore trustStore, Collection<? extends CRL> crls)
{
if (trustStore == null)
{
throw new InvalidParameterException("TrustStore must be specified for CertificateValidator.");
}
_trustStore = trustStore;
_crls = crls;
}
public CertificateValidator(X509Certificate[] trustedCert, Collection<? extends CRL> crls)
{
if (trustedCert == null || trustedCert.length == 0)
{
throw new InvalidParameterException("trustedCert must be specified for CertificateValidator.");
}
_trustedCert = trustedCert;
_crls = crls;
}
public void validate(Certificate[] certChain) throws CertificateException
{
try
{
ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
for (Certificate item : certChain)
{
if (item == null)
continue;
if (!(item instanceof X509Certificate))
{
throw new IllegalStateException("Invalid certificate type in chain");
}
certList.add((X509Certificate)item);
}
if (certList.isEmpty())
{
throw new IllegalStateException("Invalid certificate chain");
}
X509CertSelector certSelect = new X509CertSelector();
certSelect.setCertificate(certList.get(0));
CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
Set<PKIXRevocationChecker.Option> opts = new HashSet<>();
if(preferCrl) {
opts.add(PKIXRevocationChecker.Option.PREFER_CRLS);
}
//opts.add(PKIXRevocationChecker.Option.SOFT_FAIL);
//opts.add(PKIXRevocationChecker.Option.NO_FALLBACK);
if(checkOnlyEndEntities) {
opts.add(PKIXRevocationChecker.Option.ONLY_END_ENTITY);
}
revocationChecker.setOptions(opts);
// Configure certification path builder parameters
PKIXBuilderParameters pbParams = null;
if(_trustStore != null) {
pbParams = new PKIXBuilderParameters(_trustStore, certSelect);
} else {
Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();
for (int i = 0; i < _trustedCert.length; i++) {
X509Certificate certificate = _trustedCert[i];
TrustAnchor trustAnchor = new TrustAnchor(certificate, null);
trustAnchors.add(trustAnchor);
}
pbParams = new PKIXBuilderParameters(trustAnchors, certSelect);
}
pbParams.addCertPathChecker(revocationChecker);
pbParams.setDate(date);
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList)));
// Set maximum certification path length
pbParams.setMaxPathLength(_maxCertPathLength);
// Enable revocation checking
pbParams.setRevocationEnabled(true);
// Set static Certificate Revocation List
if (_crls != null && !_crls.isEmpty())
{
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls)));
}
// Enable On-Line Certificate Status Protocol (OCSP) support
if (_enableOCSP)
{
Security.setProperty("ocsp.enable","true");
}
// Enable Certificate Revocation List Distribution Points (CRLDP) support
if (_enableCRLDP)
{
System.setProperty("com.sun.security.enableCRLDP","true");
}
// Build certification path
CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);
// Validate certification path
CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams);
}
catch (GeneralSecurityException gse)
{
throw new CertificateException("Unable to validate certificate: " + gse.getMessage(), gse);
}
}
public Collection<? extends CRL> getCrls()
{
return _crls;
}
/**
* @return Maximum number of intermediate certificates in
* the certification path (-1 for unlimited)
*/
public int getMaxCertPathLength()
{
return _maxCertPathLength;
}
/* ------------------------------------------------------------ */
/**
* @param maxCertPathLength
* maximum number of intermediate certificates in
* the certification path (-1 for unlimited)
*/
public void setMaxCertPathLength(int maxCertPathLength)
{
_maxCertPathLength = maxCertPathLength;
}
/* ------------------------------------------------------------ */
/**
* @return true if CRL Distribution Points support is enabled
*/
public boolean isEnableCRLDP()
{
return _enableCRLDP;
}
/* ------------------------------------------------------------ */
/** Enables CRL Distribution Points Support
* @param enableCRLDP true - turn on, false - turns off
*/
public void setEnableCRLDP(boolean enableCRLDP)
{
_enableCRLDP = enableCRLDP;
}
/* ------------------------------------------------------------ */
/**
* @return true if On-Line Certificate Status Protocol support is enabled
*/
public boolean isEnableOCSP()
{
return _enableOCSP;
}
/* ------------------------------------------------------------ */
/** Enables On-Line Certificate Status Protocol support
* @param enableOCSP true - turn on, false - turn off
*/
public void setEnableOCSP(boolean enableOCSP)
{
_enableOCSP = enableOCSP;
}
/* ------------------------------------------------------------ */
/**
* @return Location of the OCSP Responder
*/
public String getOcspResponderURL()
{
return _ocspResponderURL;
}
/* ------------------------------------------------------------ */
/** Set the location of the OCSP Responder.
* @param ocspResponderURL location of the OCSP Responder
*/
public void setOcspResponderURL(String ocspResponderURL)
{
_ocspResponderURL = ocspResponderURL;
}
public Date getDate() {
return date==null?null:(Date) date.clone();
}
public void setDate(Date date) {
this.date = date==null?null:(Date) date.clone();
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.util;
import org.elasticsearch.ElasticsearchException;
public class ExceptionUtils {
public static Throwable getRootCause(final Throwable e) {
if(e == null) {
return null;
}
final Throwable cause = e.getCause();
if(cause == null) {
return e;
}
return getRootCause(cause);
}
public static Throwable findMsg(final Throwable e, String msg) {
if(e == null) {
return null;
}
if(e.getMessage() != null && e.getMessage().contains(msg)) {
return e;
}
final Throwable cause = e.getCause();
if(cause == null) {
return null;
}
return findMsg(cause, msg);
}
public static ElasticsearchException createBadHeaderException() {
return new ElasticsearchException("Illegal parameter in http or transport request found."+System.lineSeparator()
+ "This means that one node is trying to connect to another with "+System.lineSeparator()
+ "a non-node certificate (no OID or opendistro_security.nodes_dn incorrect configured) or that someone "+System.lineSeparator()
+ "is spoofing requests. Check your TLS certificate setup as described in documentation");
}
}

View File

@ -0,0 +1,200 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.util;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.Strings;
public class SSLCertificateHelper {
private static final Logger log = LogManager.getLogger(SSLCertificateHelper.class);
private static boolean stripRootFromChain = true; //TODO check
public static X509Certificate[] exportRootCertificates(final KeyStore ks, final String alias) throws KeyStoreException {
logKeyStore(ks);
final List<X509Certificate> trustedCerts = new ArrayList<X509Certificate>();
if (Strings.isNullOrEmpty(alias)) {
if(log.isDebugEnabled()) {
log.debug("No alias given, will trust all of the certificates in the store");
}
final List<String> aliases = toList(ks.aliases());
for (final String _alias : aliases) {
if (ks.isCertificateEntry(_alias)) {
final X509Certificate cert = (X509Certificate) ks.getCertificate(_alias);
if (cert != null) {
trustedCerts.add(cert);
} else {
log.error("Alias {} does not exist", _alias);
}
}
}
} else {
if (ks.isCertificateEntry(alias)) {
final X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
if (cert != null) {
trustedCerts.add(cert);
} else {
log.error("Alias {} does not exist", alias);
}
} else {
log.error("Alias {} does not contain a certificate entry", alias);
}
}
return trustedCerts.toArray(new X509Certificate[0]);
}
public static X509Certificate[] exportServerCertChain(final KeyStore ks, String alias) throws KeyStoreException {
logKeyStore(ks);
final List<String> aliases = toList(ks.aliases());
if (Strings.isNullOrEmpty(alias)) {
if(aliases.isEmpty()) {
log.error("Keystore does not contain any aliases");
} else {
alias = aliases.get(0);
log.info("No alias given, use the first one: {}", alias);
}
}
final Certificate[] certs = ks.getCertificateChain(alias);
if (certs != null && certs.length > 0) {
X509Certificate[] x509Certs = Arrays.copyOf(certs, certs.length, X509Certificate[].class);
final X509Certificate lastCertificate = x509Certs[x509Certs.length - 1];
if (lastCertificate.getBasicConstraints() > -1
&& lastCertificate.getSubjectX500Principal().equals(lastCertificate.getIssuerX500Principal())) {
log.warn("Certificate chain for alias {} contains a root certificate", alias);
if(stripRootFromChain ) {
x509Certs = Arrays.copyOf(certs, certs.length-1, X509Certificate[].class);
}
}
return x509Certs;
} else {
log.error("Alias {} does not exist or contain a certificate chain", alias);
}
return new X509Certificate[0];
}
public static PrivateKey exportDecryptedKey(final KeyStore ks, final String alias, final char[] password) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {
logKeyStore(ks);
final List<String> aliases = toList(ks.aliases());
String evaluatedAlias = alias;
if (alias == null && aliases.size() > 0) {
evaluatedAlias = aliases.get(0);
}
if (evaluatedAlias == null) {
throw new KeyStoreException("null alias, current aliases: " + aliases);
}
final Key key = ks.getKey(evaluatedAlias, (password == null || password.length == 0) ? null:password);
if (key == null) {
throw new KeyStoreException("no key alias named " + evaluatedAlias);
}
if (key instanceof PrivateKey) {
return (PrivateKey) key;
}
return null;
}
private static void logKeyStore(final KeyStore ks) {
try {
final List<String> aliases = toList(ks.aliases());
if (log.isDebugEnabled()) {
log.debug("Keystore has {} entries/aliases", ks.size());
for (String _alias : aliases) {
log.debug("Alias {}: is a certificate entry?{}/is a key entry?{}", _alias, ks.isCertificateEntry(_alias),
ks.isKeyEntry(_alias));
Certificate[] certs = ks.getCertificateChain(_alias);
if (certs != null) {
log.debug("Alias {}: chain len {}", _alias, certs.length);
for (int i = 0; i < certs.length; i++) {
X509Certificate certificate = (X509Certificate) certs[i];
log.debug("cert {} of type {} -> {}", certificate.getSubjectX500Principal(), certificate.getBasicConstraints(),
certificate.getSubjectX500Principal().equals(certificate.getIssuerX500Principal()));
}
}
X509Certificate cert = (X509Certificate) ks.getCertificate(_alias);
if (cert != null) {
log.debug("Alias {}: single cert {} of type {} -> {}", _alias, cert.getSubjectX500Principal(),
cert.getBasicConstraints(), cert.getSubjectX500Principal().equals(cert.getIssuerX500Principal()));
}
}
}
} catch (Exception e) {
log.error("Error logging keystore due to "+e, e);
}
}
private static List<String> toList(final Enumeration<String> enumeration) {
final List<String> aliases = new ArrayList<>();
while (enumeration.hasMoreElements()) {
aliases.add(enumeration.nextElement());
}
return Collections.unmodifiableList(aliases);
}
}

View File

@ -0,0 +1,254 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.util;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.elasticsearch.common.settings.Settings;
public final class SSLConfigConstants {
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE = "opendistro_security.ssl.http.enable_openssl_if_available";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLED = "opendistro_security.ssl.http.enabled";
public static final boolean OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_DEFAULT = false;
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CLIENTAUTH_MODE = "opendistro_security.ssl.http.clientauth_mode";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS = "opendistro_security.ssl.http.keystore_alias";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_FILEPATH = "opendistro_security.ssl.http.keystore_filepath";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH = "opendistro_security.ssl.http.pemkey_filepath";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD = "opendistro_security.ssl.http.pemkey_password";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH = "opendistro_security.ssl.http.pemcert_filepath";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH = "opendistro_security.ssl.http.pemtrustedcas_filepath";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_PASSWORD = "opendistro_security.ssl.http.keystore_password";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_TYPE = "opendistro_security.ssl.http.keystore_type";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS = "opendistro_security.ssl.http.truststore_alias";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH = "opendistro_security.ssl.http.truststore_filepath";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD = "opendistro_security.ssl.http.truststore_password";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE = "opendistro_security.ssl.http.truststore_type";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE = "opendistro_security.ssl.transport.enable_openssl_if_available";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED = "opendistro_security.ssl.transport.enabled";
public static final boolean OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_DEFAULT = true;
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION = "opendistro_security.ssl.transport.enforce_hostname_verification";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME = "opendistro_security.ssl.transport.resolve_hostname";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS = "opendistro_security.ssl.transport.keystore_alias";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_FILEPATH = "opendistro_security.ssl.transport.keystore_filepath";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH = "opendistro_security.ssl.transport.pemkey_filepath";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD = "opendistro_security.ssl.transport.pemkey_password";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH = "opendistro_security.ssl.transport.pemcert_filepath";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH = "opendistro_security.ssl.transport.pemtrustedcas_filepath";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_PASSWORD = "opendistro_security.ssl.transport.keystore_password";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_TYPE = "opendistro_security.ssl.transport.keystore_type";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_ALIAS = "opendistro_security.ssl.transport.truststore_alias";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_FILEPATH = "opendistro_security.ssl.transport.truststore_filepath";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_PASSWORD = "opendistro_security.ssl.transport.truststore_password";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTSTORE_TYPE = "opendistro_security.ssl.transport.truststore_type";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS = "opendistro_security.ssl.transport.enabled_ciphers";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS = "opendistro_security.ssl.transport.enabled_protocols";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS = "opendistro_security.ssl.http.enabled_ciphers";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS = "opendistro_security.ssl.http.enabled_protocols";
public static final String OPENDISTRO_SECURITY_SSL_CLIENT_EXTERNAL_CONTEXT_ID = "opendistro_security.ssl.client.external_context_id";
public static final String OPENDISTRO_SECURITY_SSL_TRANSPORT_PRINCIPAL_EXTRACTOR_CLASS = "opendistro_security.ssl.transport.principal_extractor_class";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE = "opendistro_security.ssl.http.crl.file_path";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE = "opendistro_security.ssl.http.crl.validate";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_PREFER_CRLFILE_OVER_OCSP = "opendistro_security.ssl.http.crl.prefer_crlfile_over_ocsp";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_CHECK_ONLY_END_ENTITIES = "opendistro_security.ssl.http.crl.check_only_end_entities";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_OCSP = "opendistro_security.ssl.http.crl.disable_ocsp";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_CRLDP = "opendistro_security.ssl.http.crl.disable_crldp";
public static final String OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE = "opendistro_security.ssl.http.crl.validation_date";
public static final String OPENDISTRO_SECURITY_SSL_ALLOW_CLIENT_INITIATED_RENEGOTIATION = "opendistro_security.ssl.allow_client_initiated_renegotiation";
public static final String DEFAULT_STORE_PASSWORD = "changeit"; //#16
public static final String JDK_TLS_REJECT_CLIENT_INITIATED_RENEGOTIATION = "jdk.tls.rejectClientInitiatedRenegotiation";
private static final String[] _SECURE_SSL_PROTOCOLS = {"TLSv1.3", "TLSv1.2", "TLSv1.1"};
public static final String[] getSecureSSLProtocols(Settings settings, boolean http)
{
List<String> configuredProtocols = null;
if(settings != null) {
if(http) {
configuredProtocols = settings.getAsList(OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, Collections.emptyList());
} else {
configuredProtocols = settings.getAsList(OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, Collections.emptyList());
}
}
if(configuredProtocols != null && configuredProtocols.size() > 0) {
return configuredProtocols.toArray(new String[0]);
}
return _SECURE_SSL_PROTOCOLS.clone();
}
// @formatter:off
private static final String[] _SECURE_SSL_CIPHERS =
{
//TLS_<key exchange and authentication algorithms>_WITH_<bulk cipher and message authentication algorithms>
//Example (including unsafe ones)
//Protocol: TLS, SSL
//Key Exchange RSA, Diffie-Hellman, ECDH, SRP, PSK
//Authentication RSA, DSA, ECDSA
//Bulk Ciphers RC4, 3DES, AES
//Message Authentication HMAC-SHA256, HMAC-SHA1, HMAC-MD5
//thats what chrome 48 supports (https://cc.dcsec.uni-hannover.de/)
//(c0,2b)ECDHE-ECDSA-AES128-GCM-SHA256128 BitKey exchange: ECDH, encryption: AES, MAC: SHA256.
//(c0,2f)ECDHE-RSA-AES128-GCM-SHA256128 BitKey exchange: ECDH, encryption: AES, MAC: SHA256.
//(00,9e)DHE-RSA-AES128-GCM-SHA256128 BitKey exchange: DH, encryption: AES, MAC: SHA256.
//(cc,14)ECDHE-ECDSA-CHACHA20-POLY1305-SHA256128 BitKey exchange: ECDH, encryption: ChaCha20 Poly1305, MAC: SHA256.
//(cc,13)ECDHE-RSA-CHACHA20-POLY1305-SHA256128 BitKey exchange: ECDH, encryption: ChaCha20 Poly1305, MAC: SHA256.
//(c0,0a)ECDHE-ECDSA-AES256-SHA256 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
//(c0,14)ECDHE-RSA-AES256-SHA256 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
//(00,39)DHE-RSA-AES256-SHA256 BitKey exchange: DH, encryption: AES, MAC: SHA1.
//(c0,09)ECDHE-ECDSA-AES128-SHA128 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
//(c0,13)ECDHE-RSA-AES128-SHA128 BitKey exchange: ECDH, encryption: AES, MAC: SHA1.
//(00,33)DHE-RSA-AES128-SHA128 BitKey exchange: DH, encryption: AES, MAC: SHA1.
//(00,9c)RSA-AES128-GCM-SHA256128 BitKey exchange: RSA, encryption: AES, MAC: SHA256.
//(00,35)RSA-AES256-SHA256 BitKey exchange: RSA, encryption: AES, MAC: SHA1.
//(00,2f)RSA-AES128-SHA128 BitKey exchange: RSA, encryption: AES, MAC: SHA1.
//(00,0a)RSA-3DES-EDE-SHA168 BitKey exchange: RSA, encryption: 3DES, MAC: SHA1.
//thats what firefox 42 supports (https://cc.dcsec.uni-hannover.de/)
//(c0,2b) ECDHE-ECDSA-AES128-GCM-SHA256
//(c0,2f) ECDHE-RSA-AES128-GCM-SHA256
//(c0,0a) ECDHE-ECDSA-AES256-SHA
//(c0,09) ECDHE-ECDSA-AES128-SHA
//(c0,13) ECDHE-RSA-AES128-SHA
//(c0,14) ECDHE-RSA-AES256-SHA
//(00,33) DHE-RSA-AES128-SHA
//(00,39) DHE-RSA-AES256-SHA
//(00,2f) RSA-AES128-SHA
//(00,35) RSA-AES256-SHA
//(00,0a) RSA-3DES-EDE-SHA
//Mozilla modern browsers
//https://wiki.mozilla.org/Security/Server_Side_TLS
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
//TLS 1.3 Java
"TLS_AES_128_GCM_SHA256",
"TLS_AES_256_GCM_SHA384",
//TLS 1.3 OpenSSL
"TLS_CHACHA20_POLY1305_SHA256",
//IBM
"SSL_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"SSL_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
"SSL_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"SSL_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"SSL_DHE_RSA_WITH_AES_128_GCM_SHA256",
"SSL_DHE_DSS_WITH_AES_128_GCM_SHA256",
"SSL_DHE_DSS_WITH_AES_256_GCM_SHA384",
"SSL_DHE_RSA_WITH_AES_256_GCM_SHA384",
"SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"SSL_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"SSL_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"SSL_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"SSL_DHE_RSA_WITH_AES_128_CBC_SHA256",
"SSL_DHE_RSA_WITH_AES_128_CBC_SHA",
"SSL_DHE_DSS_WITH_AES_128_CBC_SHA256",
"SSL_DHE_RSA_WITH_AES_256_CBC_SHA256",
"SSL_DHE_DSS_WITH_AES_256_CBC_SHA",
"SSL_DHE_RSA_WITH_AES_256_CBC_SHA"
//some others
//"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
//"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
//"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
//"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
//"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
//"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
//"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
//"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
//"TLS_RSA_WITH_AES_128_CBC_SHA256",
//"TLS_RSA_WITH_AES_128_GCM_SHA256",
//"TLS_RSA_WITH_AES_128_CBC_SHA",
//"TLS_RSA_WITH_AES_256_CBC_SHA",
};
// @formatter:on
public static final List<String> getSecureSSLCiphers(Settings settings, boolean http) {
List<String> configuredCiphers = null;
if(settings != null) {
if(http) {
configuredCiphers = settings.getAsList(OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS, Collections.emptyList());
} else {
configuredCiphers = settings.getAsList(OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, Collections.emptyList());
}
}
if(configuredCiphers != null && configuredCiphers.size() > 0) {
return configuredCiphers;
}
return Collections.unmodifiableList(Arrays.asList(_SECURE_SSL_CIPHERS));
}
private SSLConfigConstants() {
}
}

View File

@ -0,0 +1,273 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.util;
import io.netty.handler.ssl.SslHandler;
import java.io.File;
import java.io.FileInputStream;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.KeyStore;
import java.security.PrivilegedAction;
import java.security.cert.CRL;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Map.Entry;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.SpecialPermission;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.http.netty4.Netty4HttpRequest;
import org.elasticsearch.rest.RestRequest;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor.Type;
public class SSLRequestHelper {
private static final Logger log = LogManager.getLogger(SSLRequestHelper.class);
public static class SSLInfo {
private final X509Certificate[] x509Certs;
private final X509Certificate[] localCertificates;
private final String principal;
private final String protocol;
private final String cipher;
public SSLInfo(final X509Certificate[] x509Certs, final String principal, final String protocol, final String cipher) {
this(x509Certs, principal, protocol, cipher, null);
}
public SSLInfo(final X509Certificate[] x509Certs, final String principal, final String protocol, final String cipher, X509Certificate[] localCertificates) {
super();
this.x509Certs = x509Certs;
this.principal = principal;
this.protocol = protocol;
this.cipher = cipher;
this.localCertificates = localCertificates;
}
public X509Certificate[] getX509Certs() {
return x509Certs == null ? null : x509Certs.clone();
}
public X509Certificate[] getLocalCertificates() {
return localCertificates == null ? null : localCertificates.clone();
}
public String getPrincipal() {
return principal;
}
public String getProtocol() {
return protocol;
}
public String getCipher() {
return cipher;
}
@Override
public String toString() {
return "SSLInfo [x509Certs=" + Arrays.toString(x509Certs) + ", principal=" + principal + ", protocol=" + protocol + ", cipher="
+ cipher + "]";
}
}
public static SSLInfo getSSLInfo(final Settings settings, final Path configPath, final RestRequest request, PrincipalExtractor principalExtractor) throws SSLPeerUnverifiedException {
if(request == null || !(request instanceof Netty4HttpRequest)) {
return null;
}
final Netty4HttpRequest nettyHttpRequest = (Netty4HttpRequest) request;
final SslHandler sslhandler = (SslHandler) nettyHttpRequest.getChannel().pipeline().get("ssl_http");
if(sslhandler == null) {
return null;
}
final SSLEngine engine = sslhandler.engine();
final SSLSession session = engine.getSession();
X509Certificate[] x509Certs = null;
final String protocol = session.getProtocol();
final String cipher = session.getCipherSuite();
String principal = null;
boolean validationFailure = false;
if (engine.getNeedClientAuth() || engine.getWantClientAuth()) {
try {
final Certificate[] certs = session.getPeerCertificates();
if (certs != null && certs.length > 0 && certs[0] instanceof X509Certificate) {
x509Certs = Arrays.copyOf(certs, certs.length, X509Certificate[].class);
final X509Certificate[] x509CertsF = x509Certs;
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SpecialPermission());
}
validationFailure = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return !validate(x509CertsF, settings, configPath);
}
});
if(validationFailure) {
throw new SSLPeerUnverifiedException("Unable to validate certificate (CRL)");
}
principal = principalExtractor == null?null: principalExtractor.extractPrincipal(x509Certs[0], Type.HTTP);
} else if (engine.getNeedClientAuth()) {
final ElasticsearchException ex = new ElasticsearchException("No client certificates found but such are needed (Security 9).");
throw ex;
}
} catch (final SSLPeerUnverifiedException e) {
if (engine.getNeedClientAuth() || validationFailure) {
throw e;
}
}
}
Certificate[] localCerts = session.getLocalCertificates();
return new SSLInfo(x509Certs, principal, protocol, cipher, localCerts==null?null:Arrays.copyOf(localCerts, localCerts.length, X509Certificate[].class));
}
public static boolean containsBadHeader(final ThreadContext context, String prefix) {
if (context != null) {
for (final Entry<String, String> header : context.getHeaders().entrySet()) {
if (header != null && header.getKey() != null && header.getKey().trim().toLowerCase().startsWith(prefix)) {
return true;
}
}
}
return false;
}
private static boolean validate(X509Certificate[] x509Certs, final Settings settings, final Path configPath) {
final boolean validateCrl = settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, false);
if(log.isTraceEnabled()) {
log.trace("validateCrl: "+validateCrl);
}
if(!validateCrl) {
return true;
}
final Environment env = new Environment(settings, configPath);
try {
Collection<? extends CRL> crls = null;
final String crlFile = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE);
if(crlFile != null) {
final File crl = env.configFile().resolve(crlFile).toAbsolutePath().toFile();
try(FileInputStream crlin = new FileInputStream(crl)) {
crls = CertificateFactory.getInstance("X.509").generateCRLs(crlin);
}
if(log.isTraceEnabled()) {
log.trace("crls from file: "+crls.size());
}
} else {
if(log.isTraceEnabled()) {
log.trace("no crl file configured");
}
}
final String truststore = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_FILEPATH);
CertificateValidator validator = null;
if(truststore != null) {
final String truststoreType = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_TYPE, "JKS");
final String truststorePassword = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_PASSWORD, "changeit");
//final String truststoreAlias = settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_TRUSTSTORE_ALIAS, null);
final KeyStore ts = KeyStore.getInstance(truststoreType);
try(FileInputStream fin = new FileInputStream(new File(env.configFile().resolve(truststore).toAbsolutePath().toString()))) {
ts.load(fin, (truststorePassword == null || truststorePassword.length() == 0) ?null:truststorePassword.toCharArray());
}
validator = new CertificateValidator(ts, crls);
} else {
final File trustedCas = env.configFile().resolve(settings.get(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, "")).toAbsolutePath().toFile();
try(FileInputStream trin = new FileInputStream(trustedCas)) {
Collection<? extends Certificate> cert = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
validator = new CertificateValidator(cert.toArray(new X509Certificate[0]), crls);
}
}
validator.setEnableCRLDP(!settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_CRLDP, false));
validator.setEnableOCSP(!settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_DISABLE_OCSP, false));
validator.setCheckOnlyEndEntities(settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_CHECK_ONLY_END_ENTITIES, true));
validator.setPreferCrl(settings.getAsBoolean(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_PREFER_CRLFILE_OVER_OCSP, false));
Long dateTimestamp = settings.getAsLong(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, null);
if(dateTimestamp != null && dateTimestamp.longValue() < 0) {
dateTimestamp = null;
}
validator.setDate(dateTimestamp==null?null:new Date(dateTimestamp.longValue()));
validator.validate(x509Certs);
return true;
} catch (Exception e) {
if(log.isDebugEnabled()) {
log.debug("Unable to validate CRL: "+ExceptionsHelper.stackTrace(e));
}
log.warn("Unable to validate CRL: "+ExceptionUtils.getRootCause(e));
}
return false;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl.util;
public class Utils {
public static <T> T coalesce(T first, T... more) {
if (first != null) {
return first;
}
if(more == null || more.length == 0) {
return null;
}
for (int i = 0; i < more.length; i++) {
T t = more[i];
if(t != null) {
return t;
}
}
return null;
}
}

View File

@ -0,0 +1,365 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import io.netty.handler.ssl.OpenSsl;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchTimeoutException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.PluginAwareNode;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.transport.Netty4Plugin;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecuritySSLPlugin;
@SuppressWarnings({"unchecked"})
public abstract class AbstractUnitTest {
static {
System.out.println("OS: " + System.getProperty("os.name") + " " + System.getProperty("os.arch") + " "
+ System.getProperty("os.version"));
System.out.println("Java Version: " + System.getProperty("java.version") + " " + System.getProperty("java.vendor"));
System.out.println("JVM Impl.: " + System.getProperty("java.vm.version") + " " + System.getProperty("java.vm.vendor") + " "
+ System.getProperty("java.vm.name"));
System.out.println("Open SSL available: "+OpenSsl.isAvailable());
System.out.println("Open SSL version: "+OpenSsl.versionString());
}
@Rule
public TestName name = new TestName();
protected final String clustername = "opendistro_security_ssl_testcluster";
private Node esNode1;
private Node esNode2;
private Node esNode3;
private String httpHost = null;
private int httpPort = -1;
protected String nodeHost;
protected int nodePort;
protected boolean enableHTTPClientSSL = false;
protected boolean enableHTTPClientSSLv3Only = false;
protected boolean sendHTTPClientCertificate = false;
protected boolean trustHTTPServerCertificate = false;
protected String keystore = "node-0-keystore.jks";
@Rule
public final TestWatcher testWatcher = new TestWatcher() {
@Override
protected void starting(final Description description) {
final String methodName = description.getMethodName();
String className = description.getClassName();
className = className.substring(className.lastIndexOf('.') + 1);
System.out.println("---------------- Starting JUnit-test: " + className + " " + methodName + " ----------------");
}
@Override
protected void failed(final Throwable e, final Description description) {
final String methodName = description.getMethodName();
String className = description.getClassName();
className = className.substring(className.lastIndexOf('.') + 1);
System.out.println(">>>> " + className + " " + methodName + " FAILED due to " + e);
}
@Override
protected void finished(final Description description) {
// System.out.println("-----------------------------------------------------------------------------------------");
}
};
protected AbstractUnitTest() {
super();
}
// @formatter:off
private Settings.Builder getDefaultSettingsBuilder(final int nodenum, final boolean dataNode, final boolean masterNode) {
return Settings.builder()
.put("node.name", "opendistro_security_testnode_" + nodenum)
.put("node.data", dataNode)
.put("node.master", masterNode)
.put("cluster.name", clustername)
.put("path.data", "data/data")
.put("path.logs", "data/logs")
.put("http.enabled", !dataNode)
.put("cluster.routing.allocation.disk.watermark.high","1mb")
.put("cluster.routing.allocation.disk.watermark.low","1mb")
.put("cluster.routing.allocation.disk.watermark.flood_stage", "1mb")
.put("http.cors.enabled", true)
.put("transport.type.default", "netty4")
.put("node.max_local_storage_nodes", 3)
.put("path.home",".");
}
// @formatter:on
protected final Logger log = LogManager.getLogger(this.getClass());
protected final String getHttpServerUri() {
final String address = "http" + (enableHTTPClientSSL ? "s" : "") + "://" + httpHost + ":" + httpPort;
log.debug("Connect to {}", address);
return address;
}
public final void startES(final Settings settings) throws Exception {
FileUtils.deleteDirectory(new File("data"));
esNode1 = new PluginAwareNode(getDefaultSettingsBuilder(1, false, true).put(
settings == null ? Settings.Builder.EMPTY_SETTINGS : settings).build(), Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class);
esNode2 = new PluginAwareNode(getDefaultSettingsBuilder(2, true, true).put(
settings == null ? Settings.Builder.EMPTY_SETTINGS : settings).build(), Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class);
esNode3 = new PluginAwareNode(getDefaultSettingsBuilder(3, true, false).put(
settings == null ? Settings.Builder.EMPTY_SETTINGS : settings).build(), Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class);
esNode1.start();
esNode2.start();
esNode3.start();
waitForGreenClusterState(esNode1.client());
}
@Before
public void setUp() throws Exception {
enableHTTPClientSSL = false;
enableHTTPClientSSLv3Only = false;
sendHTTPClientCertificate = false;
trustHTTPServerCertificate = false;
keystore = "node-0-keystore.jks";
}
@After
public void tearDown() throws Exception {
if (esNode3 != null) {
esNode3.close();
}
if (esNode2 != null) {
esNode2.close();
}
if (esNode1 != null) {
esNode1.close();
}
}
protected void waitForGreenClusterState(final Client client) throws IOException {
waitForCluster(ClusterHealthStatus.GREEN, TimeValue.timeValueSeconds(30), client);
}
protected void waitForCluster(final ClusterHealthStatus status, final TimeValue timeout, final Client client) throws IOException {
try {
log.debug("waiting for cluster state {}", status.name());
final ClusterHealthResponse healthResponse = client.admin().cluster().prepareHealth().setWaitForStatus(status)
.setTimeout(timeout).setWaitForNodes("3").execute().actionGet();
if (healthResponse.isTimedOut()) {
throw new IOException("cluster state is " + healthResponse.getStatus().name() + " with "
+ healthResponse.getNumberOfNodes() + " nodes");
} else {
log.debug("... cluster state ok " + healthResponse.getStatus().name() + " with " + healthResponse.getNumberOfNodes()
+ " nodes");
}
final NodesInfoResponse res = esNode1.client().admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet();
final List<NodeInfo> nodes = res.getNodes();
for (NodeInfo nodeInfo: nodes) {
if (nodeInfo.getHttp() != null && nodeInfo.getHttp().address() != null) {
final TransportAddress is = nodeInfo.getHttp().address().publishAddress();
httpPort = is.getPort();
httpHost = is.getAddress();
}
final TransportAddress is = nodeInfo.getTransport().getAddress().publishAddress();
nodePort = is.getPort();
nodeHost = is.getAddress();
}
} catch (final ElasticsearchTimeoutException e) {
throw new IOException("timeout, cluster does not respond to health request, cowardly refusing to continue with operations");
}
}
public Path getAbsoluteFilePathFromClassPath(final String fileNameFromClasspath) {
File file = null;
final URL fileUrl = AbstractUnitTest.class.getClassLoader().getResource(fileNameFromClasspath);
if (fileUrl != null) {
try {
file = new File(URLDecoder.decode(fileUrl.getFile(), "UTF-8"));
} catch (final UnsupportedEncodingException e) {
return null;
}
if (file.exists() && file.canRead()) {
return Paths.get(file.getAbsolutePath());
} else {
log.error("Cannot read from {}, maybe the file does not exists? ", file.getAbsolutePath());
}
} else {
log.error("Failed to load " + fileNameFromClasspath);
}
return null;
}
protected String executeSimpleRequest(final String request) throws Exception {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
try {
httpClient = getHTTPClient();
response = httpClient.execute(new HttpGet(getHttpServerUri() + "/" + request));
if (response.getStatusLine().getStatusCode() >= 300) {
throw new Exception("Statuscode " + response.getStatusLine().getStatusCode()+" - "+response.getStatusLine().getReasonPhrase()+ "-" +IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8));
}
return IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
} finally {
if (response != null) {
response.close();
}
if (httpClient != null) {
httpClient.close();
}
}
}
protected final CloseableHttpClient getHTTPClient() throws Exception {
final HttpClientBuilder hcb = HttpClients.custom();
if (enableHTTPClientSSL) {
log.debug("Configure HTTP client with SSL");
final KeyStore myTrustStore = KeyStore.getInstance("JKS");
myTrustStore.load(new FileInputStream(getAbsoluteFilePathFromClassPath("truststore.jks").toFile()), "changeit".toCharArray());
final KeyStore keyStore = KeyStore.getInstance(keystore.toLowerCase().endsWith("p12")?"PKCS12":"JKS");
keyStore.load(new FileInputStream(getAbsoluteFilePathFromClassPath(keystore).toFile()), "changeit".toCharArray());
final SSLContextBuilder sslContextbBuilder = SSLContexts.custom().useProtocol("TLS");
if (trustHTTPServerCertificate) {
sslContextbBuilder.loadTrustMaterial(myTrustStore, null);
}
if (sendHTTPClientCertificate) {
sslContextbBuilder.loadKeyMaterial(keyStore, "changeit".toCharArray());
}
final SSLContext sslContext = sslContextbBuilder.build();
String[] protocols = null;
if (enableHTTPClientSSLv3Only) {
protocols = new String[] { "SSLv3" };
} else {
protocols = new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" };
}
final SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, protocols, null, NoopHostnameVerifier.INSTANCE);
hcb.setSSLSocketFactory(sslsf);
}
hcb.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(60 * 1000).build());
return hcb.build();
}
protected Collection<Class<? extends Plugin>> asCollection(Class<? extends Plugin>... plugins) {
return Arrays.asList(plugins);
}
protected class TransportClientImpl extends TransportClient {
public TransportClientImpl(Settings settings, Collection<Class<? extends Plugin>> plugins) {
super(settings, plugins);
}
public TransportClientImpl(Settings settings, Settings defaultSettings, Collection<Class<? extends Plugin>> plugins) {
super(settings, defaultSettings, plugins, null);
}
}
}

View File

@ -0,0 +1,227 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.cert.CRL;
import java.security.cert.CertPathBuilderException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateRevokedException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ExceptionsHelper;
import org.junit.Assert;
import org.junit.Test;
import com.amazon.opendistroforelasticsearch.security.ssl.util.CertificateValidator;
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
public class CertificateValidatorTest {
public static final Date CRL_DATE = new Date(1525546426000L);
protected final Logger log = LogManager.getLogger(this.getClass());
@Test
public void testStaticCRL() throws Exception {
File staticCrl = getAbsoluteFilePathFromClassPath("crl/revoked.crl");
Collection<? extends CRL> crls = null;
try(FileInputStream crlin = new FileInputStream(staticCrl)) {
crls = CertificateFactory.getInstance("X.509").generateCRLs(crlin);
}
Assert.assertEquals(crls.size(), 1);
//trust chain incl intermediate certificates (root + intermediates)
Collection<? extends Certificate> rootCas;
final File trustedCas = getAbsoluteFilePathFromClassPath("chain-ca.pem");
try(FileInputStream trin = new FileInputStream(trustedCas)) {
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(rootCas.size(), 2);
//certificate chain to validate (client cert + intermediates but without root)
Collection<? extends Certificate> certsToValidate;
final File certs = getAbsoluteFilePathFromClassPath("crl/revoked.crt.pem");
try(FileInputStream trin = new FileInputStream(certs)) {
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(certsToValidate.size(), 2);
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), crls);
validator.setDate(CRL_DATE);
try {
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
Assert.fail();
} catch (CertificateException e) {
Assert.assertTrue(ExceptionUtils.getRootCause(e) instanceof CertificateRevokedException);
}
}
@Test
public void testStaticCRLOk() throws Exception {
File staticCrl = getAbsoluteFilePathFromClassPath("crl/revoked.crl");
Collection<? extends CRL> crls = null;
try(FileInputStream crlin = new FileInputStream(staticCrl)) {
crls = CertificateFactory.getInstance("X.509").generateCRLs(crlin);
}
Assert.assertEquals(crls.size(), 1);
//trust chain incl intermediate certificates (root + intermediates)
Collection<? extends Certificate> rootCas;
final File trustedCas = getAbsoluteFilePathFromClassPath("chain-ca.pem");
try(FileInputStream trin = new FileInputStream(trustedCas)) {
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(rootCas.size(), 2);
//certificate chain to validate (client cert + intermediates but without root)
Collection<? extends Certificate> certsToValidate;
final File certs = getAbsoluteFilePathFromClassPath("node-0.crt.pem");
try(FileInputStream trin = new FileInputStream(certs)) {
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(certsToValidate.size(), 3);
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), crls);
validator.setDate(CRL_DATE);
try {
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
} catch (CertificateException e) {
Assert.fail(ExceptionsHelper.stackTrace(ExceptionUtils.getRootCause(e)));
}
}
@Test
public void testNoValidationPossible() throws Exception {
//trust chain incl intermediate certificates (root + intermediates)
Collection<? extends Certificate> rootCas;
final File trustedCas = getAbsoluteFilePathFromClassPath("chain-ca.pem");
try(FileInputStream trin = new FileInputStream(trustedCas)) {
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(rootCas.size(), 2);
//certificate chain to validate (client cert + intermediates but without root)
Collection<? extends Certificate> certsToValidate;
final File certs = getAbsoluteFilePathFromClassPath("crl/revoked.crt.pem");
try(FileInputStream trin = new FileInputStream(certs)) {
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(certsToValidate.size(), 2);
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), Collections.emptyList());
validator.setDate(CRL_DATE);
try {
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
Assert.fail();
} catch (CertificateException e) {
Assert.assertTrue(e.getCause() instanceof CertPathBuilderException);
Assert.assertTrue(e.getCause().getMessage().contains("unable to find valid certification path to requested target"));
}
}
@Test
public void testCRLDP() throws Exception {
//trust chain incl intermediate certificates (root + intermediates)
Collection<? extends Certificate> rootCas;
final File trustedCas = getAbsoluteFilePathFromClassPath("root-ca.pem");
try(FileInputStream trin = new FileInputStream(trustedCas)) {
rootCas = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(rootCas.size(), 1);
//certificate chain to validate (client cert + intermediates but without root)
Collection<? extends Certificate> certsToValidate;
final File certs = getAbsoluteFilePathFromClassPath("crl/revoked.crt.pem");
//final File certs = getAbsoluteFilePathFromClassPath("node-0.crt.pem");
try(FileInputStream trin = new FileInputStream(certs)) {
certsToValidate = (Collection<? extends Certificate>) CertificateFactory.getInstance("X.509").generateCertificates(trin);
}
Assert.assertEquals(certsToValidate.size(), 2);
CertificateValidator validator = new CertificateValidator(rootCas.toArray(new X509Certificate[0]), Collections.emptyList());
validator.setEnableCRLDP(true);
validator.setEnableOCSP(true);
validator.setDate(CRL_DATE);
try {
validator.validate(certsToValidate.toArray(new X509Certificate[0]));
Assert.fail();
} catch (CertificateException e) {
Assert.assertTrue(ExceptionUtils.getRootCause(e) instanceof CertificateRevokedException);
}
}
public File getAbsoluteFilePathFromClassPath(final String fileNameFromClasspath) {
File file = null;
final URL fileUrl = AbstractUnitTest.class.getClassLoader().getResource(fileNameFromClasspath);
if (fileUrl != null) {
try {
file = new File(URLDecoder.decode(fileUrl.getFile(), "UTF-8"));
} catch (final UnsupportedEncodingException e) {
return null;
}
if (file.exists() && file.canRead()) {
return file;
} else {
log.error("Cannot read from {}, maybe the file does not exists? ", file.getAbsolutePath());
}
} else {
log.error("Failed to load " + fileNameFromClasspath);
}
return null;
}
}

View File

@ -0,0 +1,180 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import io.netty.handler.ssl.OpenSsl;
import java.util.HashSet;
import java.util.Set;
import org.elasticsearch.common.settings.Settings;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
public class OpenSSLTest extends SSLTest {
@Before
public void setup() {
allowOpenSSL = true;
}
@Test
public void testEnsureOpenSSLAvailability() {
//Assert.assertTrue("OpenSSL not available: "+String.valueOf(OpenSsl.unavailabilityCause()), OpenSsl.isAvailable());
final String openSSLOptional = System.getenv("OPENDISTRO_SECURITY_TEST_OPENSSL_OPT");
System.out.println("OPENDISTRO_SECURITY_TEST_OPENSSL_OPT "+openSSLOptional);
if(!Boolean.parseBoolean(openSSLOptional)) {
System.out.println("OpenSSL must be available");
Assert.assertTrue("OpenSSL not available: "+String.valueOf(OpenSsl.unavailabilityCause()), OpenSsl.isAvailable());
} else {
System.out.println("OpenSSL can be available");
}
}
@Override
@Test
public void testHttps() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttps();
}
@Override
@Test
public void testHttpsAndNodeSSL() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsAndNodeSSL();
}
@Override
@Test
public void testHttpPlainFail() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpPlainFail();
}
@Override
@Test
public void testHttpsNoEnforce() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsNoEnforce();
}
@Override
@Test
public void testHttpsV3Fail() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsV3Fail();
}
@Override
@Test(timeout=40000)
public void testTransportClientSSL() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testTransportClientSSL();
}
@Override
@Test(timeout=40000)
public void testNodeClientSSL() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testNodeClientSSL();
}
@Override
@Test(timeout=40000)
public void testTransportClientSSLFail() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testTransportClientSSLFail();
}
@Override
@Test
public void testHttpsOptionalAuth() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsOptionalAuth();
}
@Test
public void testAvailCiphersOpenSSL() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
// Set<String> openSSLAvailCiphers = new
// HashSet<>(OpenSsl.availableCipherSuites());
// System.out.println("OpenSSL available ciphers: "+openSSLAvailCiphers);
// ECDHE-RSA-AES256-SHA, ECDH-ECDSA-AES256-SHA, DH-DSS-DES-CBC-SHA,
// ADH-AES256-SHA256, ADH-CAMELLIA128-SHA
final Set<String> openSSLSecureCiphers = new HashSet<>();
for (final String secure : SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false)) {
if (OpenSsl.isCipherSuiteAvailable(secure)) {
openSSLSecureCiphers.add(secure);
}
}
System.out.println("OpenSSL secure ciphers: " + openSSLSecureCiphers);
Assert.assertTrue(openSSLSecureCiphers.size() > 0);
}
@Test
public void testHttpsEnforceFail() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsEnforceFail();
}
@Override
public void testCipherAndProtocols() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testCipherAndProtocols();
}
@Override
public void testHttpsAndNodeSSLFailedCipher() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsAndNodeSSLFailedCipher();
}
@Test
public void testHttpsAndNodeSSLPem() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsAndNodeSSLPem();
}
@Test
public void testHttpsAndNodeSSLPemEnc() throws Exception {
Assume.assumeTrue(OpenSsl.isAvailable());
super.testHttpsAndNodeSSLPemEnc();
}
}

View File

@ -0,0 +1,814 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import io.netty.util.internal.PlatformDependent;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.Security;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.TrustManagerFactory;
import org.apache.http.NoHttpResponseException;
import org.apache.lucene.util.Constants;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.PluginAwareNode;
import org.elasticsearch.transport.Netty4Plugin;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import com.amazon.opendistroforelasticsearch.security.ssl.DefaultOpenDistroSecurityKeyStore;
import com.amazon.opendistroforelasticsearch.security.ssl.ExternalOpenDistroSecurityKeyStore;
import com.amazon.opendistroforelasticsearch.security.ssl.OpenDistroSecuritySSLPlugin;
import com.amazon.opendistroforelasticsearch.security.ssl.util.ExceptionUtils;
import com.amazon.opendistroforelasticsearch.security.ssl.util.SSLConfigConstants;
@SuppressWarnings({"resource", "unchecked"})
public class SSLTest extends AbstractUnitTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
protected boolean allowOpenSSL = false;
@Test
public void testHttps() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
keystore = "node-untspec5-keystore.p12";
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put("opendistro_security.ssl.http.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_PROTOCOLS, "TLSv1.1","TLSv1.2")
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLED_CIPHERS, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256")
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, "TLSv1.1","TLSv1.2")
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.build();
startES(settings);
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true").contains("EMAILADDRESS=unt@tst.com"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=true").contains("local_certificates_list"));
Assert.assertFalse(executeSimpleRequest("_opendistro/_security/sslinfo?pretty&show_dn=false").contains("local_certificates_list"));
Assert.assertFalse(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("local_certificates_list"));
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
Assert.assertFalse(executeSimpleRequest("_nodes/settings?pretty").contains("\"opendistro_security\""));
Assert.assertFalse(executeSimpleRequest("_nodes/settings?pretty").contains("keystore_filepath"));
//Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
}
@Test
public void testCipherAndProtocols() throws Exception {
Security.setProperty("jdk.tls.disabledAlgorithms","");
System.out.println("Disabled algos: "+Security.getProperty("jdk.tls.disabledAlgorithms"));
System.out.println("allowOpenSSL: "+allowOpenSSL);
Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
//WEAK and insecure cipher, do NOT use this, its here for unittesting only!!!
.put("opendistro_security.ssl.http.enabled_ciphers","SSL_RSA_EXPORT_WITH_RC4_40_MD5")
//WEAK and insecure protocol, do NOT use this, its here for unittesting only!!!
.put("opendistro_security.ssl.http.enabled_protocols","SSLv3")
.put("client.type","node")
.put("path.home",".")
.build();
try {
String[] enabledCiphers = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createHTTPSSLEngine().getEnabledCipherSuites();
String[] enabledProtocols = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createHTTPSSLEngine().getEnabledProtocols();
if(allowOpenSSL) {
Assert.assertEquals(2, enabledProtocols.length); //SSLv2Hello is always enabled when using openssl
Assert.assertTrue("Check SSLv3", "SSLv3".equals(enabledProtocols[0]) || "SSLv3".equals(enabledProtocols[1]));
Assert.assertEquals(1, enabledCiphers.length);
Assert.assertEquals("TLS_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
} else {
Assert.assertEquals(1, enabledProtocols.length);
Assert.assertEquals("SSLv3", enabledProtocols[0]);
Assert.assertEquals(1, enabledCiphers.length);
Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
}
settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
//WEAK and insecure cipher, do NOT use this, its here for unittesting only!!!
.put("opendistro_security.ssl.transport.enabled_ciphers","SSL_RSA_EXPORT_WITH_RC4_40_MD5")
//WEAK and insecure protocol, do NOT use this, its here for unittesting only!!!
.put("opendistro_security.ssl.transport.enabled_protocols","SSLv3")
.put("client.type","node")
.put("path.home",".")
.build();
enabledCiphers = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createServerTransportSSLEngine().getEnabledCipherSuites();
enabledProtocols = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createServerTransportSSLEngine().getEnabledProtocols();
if(allowOpenSSL) {
Assert.assertEquals(2, enabledProtocols.length); //SSLv2Hello is always enabled when using openssl
Assert.assertTrue("Check SSLv3", "SSLv3".equals(enabledProtocols[0]) || "SSLv3".equals(enabledProtocols[1]));
Assert.assertEquals(1, enabledCiphers.length);
Assert.assertEquals("TLS_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
} else {
Assert.assertEquals(1, enabledProtocols.length);
Assert.assertEquals("SSLv3", enabledProtocols[0]);
Assert.assertEquals(1, enabledCiphers.length);
Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
}
enabledCiphers = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createClientTransportSSLEngine(null, -1).getEnabledCipherSuites();
enabledProtocols = new DefaultOpenDistroSecurityKeyStore(settings, Paths.get(".")).createClientTransportSSLEngine(null, -1).getEnabledProtocols();
if(allowOpenSSL) {
Assert.assertEquals(2, enabledProtocols.length); //SSLv2Hello is always enabled when using openssl
Assert.assertTrue("Check SSLv3","SSLv3".equals(enabledProtocols[0]) || "SSLv3".equals(enabledProtocols[1]));
Assert.assertEquals(1, enabledCiphers.length);
Assert.assertEquals("TLS_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
} else {
Assert.assertEquals(1, enabledProtocols.length);
Assert.assertEquals("SSLv3", enabledProtocols[0]);
Assert.assertEquals(1, enabledCiphers.length);
Assert.assertEquals("SSL_RSA_EXPORT_WITH_RC4_40_MD5",enabledCiphers[0]);
}
} catch (ElasticsearchSecurityException e) {
System.out.println("EXPECTED "+e.getClass().getSimpleName()+" for "+System.getProperty("java.specification.version")+": "+e.toString());
e.printStackTrace();
Assert.assertTrue("Check if error contains 'no valid cipher suites' -> "+e.toString(),e.toString().contains("no valid cipher suites")
|| e.toString().contains("failed to set cipher suite")
|| e.toString().contains("Unable to configure permitted SSL ciphers")
|| e.toString().contains("OPENSSL_internal:NO_CIPHER_MATCH")
);
Assert.assertTrue("Check if >= Java 8 and no openssl",allowOpenSSL?true:Constants.JRE_IS_MINIMUM_JAVA8 );
}
}
@Test
public void testHttpsOptionalAuth() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
startES(settings);
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
Assert.assertFalse(executeSimpleRequest("_nodes/settings?pretty").contains("\"opendistro_security\""));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
}
@Test
public void testHttpsAndNodeSSL() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.put("opendistro_security.ssl.http.enabled", true).put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.build();
startES(settings);
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_size_in_bytes\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_count\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_size_in_bytes\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_count\" : 0"));
}
@Test
public void testHttpsAndNodeSSLPem() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, "changeit")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, "changeit")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
.build();
startES(settings);
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
//Assert.assertTrue(!executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("null"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
}
@Test
public void testHttpsAndNodeSSLPemEnc() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.crt.pem"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.key"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, "changeit")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.crt.pem"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("pem/node-4.key"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, "changeit")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
.build();
startES(settings);
System.out.println(executeSimpleRequest("_opendistro/_security/sslinfo?pretty"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
//Assert.assertTrue(!executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("null"));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
}
@Test
public void testHttpsAndNodeSSLFailedCipher() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.put("opendistro_security.ssl.http.enabled", true).put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enabled_ciphers","INVALID_CIPHER")
.build();
try {
startES(settings);
Assert.fail();
} catch (Exception e1) {
Throwable e = ExceptionUtils.getRootCause(e1);
if(allowOpenSSL) {
Assert.assertTrue(e.toString(), e.toString().contains("no cipher match"));
} else {
Assert.assertTrue(e.toString(), e.toString().contains("no valid cipher"));
}
}
}
@Test
public void testHttpPlainFail() throws Exception {
thrown.expect(NoHttpResponseException.class);
enableHTTPClientSSL = false;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = false;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.clientauth_mode", "OPTIONAL")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
startES(settings);
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
}
@Test
public void testHttpsNoEnforce() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = false;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.clientauth_mode", "NONE")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
startES(settings);
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
Assert.assertFalse(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("CN=node-0.example.com,OU=SSL,O=Test,L=Test,C=DE"));
}
@Test
public void testHttpsEnforceFail() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = false;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
startES(settings);
try {
executeSimpleRequest("");
Assert.fail();
} catch (SocketException | SSLException e) {
//expected
System.out.println("Expected SSLHandshakeException "+e.toString());
} catch (Exception e) {
e.printStackTrace();
Assert.fail("Unexpected exception "+e.toString());
}
}
@Test
public void testHttpsV3Fail() throws Exception {
thrown.expect(SSLHandshakeException.class);
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = false;
enableHTTPClientSSLv3Only = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.clientauth_mode", "NONE")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
startES(settings);
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").length() > 0);
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
}
// transport
@Test
public void testTransportClientSSL() throws Exception {
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
startES(settings);
log.debug("Elasticsearch started");
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put(settings).build();
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
log.debug("TransportClient built, connect now to {}:{}", nodeHost, nodePort);
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
log.debug("TransportClient connected");
Assert.assertEquals("test", tc.index(new IndexRequest("test","test").setRefreshPolicy(RefreshPolicy.IMMEDIATE).source("{\"a\":5}", XContentType.JSON)).actionGet().getIndex());
log.debug("Index created");
Assert.assertEquals(1L, tc.search(new SearchRequest("test")).actionGet().getHits().getTotalHits());
log.debug("Search done");
Assert.assertEquals(3, tc.admin().cluster().health(new ClusterHealthRequest("test")).actionGet().getNumberOfNodes());
log.debug("ClusterHealth done");
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
log.debug("NodesInfoRequest asserted");
}
}
@Test
public void testTransportClientSSLExternalContext() throws Exception {
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
startES(settings);
log.debug("Elasticsearch started");
final Settings tcSettings = Settings.builder()
.put("cluster.name", clustername)
.put("path.home", ".")
.put("opendistro_security.ssl.client.external_context_id", "abcx")
.build();
final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory
.getDefaultAlgorithm());
final KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(this.getClass().getResourceAsStream("/truststore.jks"), "changeit".toCharArray());
tmf.init(trustStore);
final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
final KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(this.getClass().getResourceAsStream("/node-0-keystore.jks"), "changeit".toCharArray());
kmf.init(keyStore, "changeit".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
ExternalOpenDistroSecurityKeyStore.registerExternalSslContext("abcx", sslContext);
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
log.debug("TransportClient built, connect now to {}:{}", nodeHost, nodePort);
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
log.debug("TransportClient connected");
Assert.assertEquals("test", tc.index(new IndexRequest("test","test").setRefreshPolicy(RefreshPolicy.IMMEDIATE).source("{\"a\":5}", XContentType.JSON)).actionGet().getIndex());
log.debug("Index created");
Assert.assertEquals(1L, tc.search(new SearchRequest("test")).actionGet().getHits().getTotalHits());
log.debug("Search done");
Assert.assertEquals(3, tc.admin().cluster().health(new ClusterHealthRequest("test")).actionGet().getNumberOfNodes());
log.debug("ClusterHealth done");
//Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().length);
//log.debug("NodesInfoRequest asserted");
}
}
@Test
public void testNodeClientSSL() throws Exception {
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.build();
startES(settings);
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put("path.home", ".")
.put("node.name", "client_node_" + new Random().nextInt())
.put(settings)// -----
.build();
try (Node node = new PluginAwareNode(tcSettings, Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class).start()) {
ClusterHealthResponse res = node.client().admin().cluster().health(new ClusterHealthRequest().waitForNodes("4").timeout(TimeValue.timeValueSeconds(5))).actionGet();
Assert.assertFalse(res.isTimedOut());
Assert.assertEquals(4, res.getNumberOfNodes());
Assert.assertEquals(4, node.client().admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
}
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_size_in_bytes\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_count\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_size_in_bytes\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_count\" : 0"));
}
@Test
public void testTransportClientSSLFail() throws Exception {
thrown.expect(NoNodeAvailableException.class);
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
startES(settings);
final Settings tcSettings = Settings.builder().put("cluster.name", clustername)
.put("path.home", getAbsoluteFilePathFromClassPath("node-0-keystore.jks").getParent())
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore_fail.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false).build();
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
}
}
@Test
public void testAvailCiphers() throws Exception {
final SSLContext serverContext = SSLContext.getInstance("TLS");
serverContext.init(null, null, null);
final SSLEngine engine = serverContext.createSSLEngine();
final List<String> jdkSupportedCiphers = new ArrayList<>(Arrays.asList(engine.getSupportedCipherSuites()));
jdkSupportedCiphers.retainAll(SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false));
engine.setEnabledCipherSuites(jdkSupportedCiphers.toArray(new String[0]));
final List<String> jdkEnabledCiphers = Arrays.asList(engine.getEnabledCipherSuites());
// example
// TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
// TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA
System.out.println("JDK enabled ciphers: " + jdkEnabledCiphers);
Assert.assertTrue(jdkEnabledCiphers.size() > 0);
}
@Test
public void testUnmodifieableCipherProtocolConfig() throws Exception {
SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, false)[0] = "bogus";
Assert.assertEquals("TLSv1.3", SSLConfigConstants.getSecureSSLProtocols(Settings.EMPTY, false)[0]);
try {
SSLConfigConstants.getSecureSSLCiphers(Settings.EMPTY, false).set(0, "bogus");
Assert.fail();
} catch (UnsupportedOperationException e) {
//expected
}
}
@Test
public void testCustomPrincipalExtractor() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.put("opendistro_security.ssl.transport.principal_extractor_class", "com.amazon.opendistroforelasticsearch.security.ssl.TestPrincipalExtractor")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks")).build();
startES(settings);
log.debug("Elasticsearch started");
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put("path.home", ".").put(settings).build();
try (TransportClient tc = new TransportClientImpl(tcSettings, asCollection(OpenDistroSecuritySSLPlugin.class))) {
log.debug("TransportClient built, connect now to {}:{}", nodeHost, nodePort);
tc.addTransportAddress(new TransportAddress(new InetSocketAddress(nodeHost, nodePort)));
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
log.debug("TransportClient connected");
TestPrincipalExtractor.reset();
Assert.assertEquals("test", tc.index(new IndexRequest("test","test").setRefreshPolicy(RefreshPolicy.IMMEDIATE).source("{\"a\":5}", XContentType.JSON)).actionGet().getIndex());
log.debug("Index created");
Assert.assertEquals(1L, tc.search(new SearchRequest("test")).actionGet().getHits().getTotalHits());
log.debug("Search done");
Assert.assertEquals(3, tc.admin().cluster().health(new ClusterHealthRequest("test")).actionGet().getNumberOfNodes());
log.debug("ClusterHealth done");
Assert.assertEquals(3, tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
log.debug("NodesInfoRequest asserted");
}
executeSimpleRequest("_opendistro/_security/sslinfo?pretty");
//we need to test this in Security itself because in the SSL only plugin the info is not longer propagated
//Assert.assertTrue(TestPrincipalExtractor.getTransportCount() > 0);
Assert.assertTrue(TestPrincipalExtractor.getHttpCount() > 0);
}
@Test
public void testCRLPem() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMKEY_PASSWORD, "changeit")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("root-ca.pem"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.put("opendistro_security.ssl.http.enabled", true)
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMCERT_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.crt.pem"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_FILEPATH, getAbsoluteFilePathFromClassPath("node-0.key.pem"))
//.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMKEY_PASSWORD, "changeit")
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_PEMTRUSTEDCAS_FILEPATH, getAbsoluteFilePathFromClassPath("chain-ca.pem"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, CertificateValidatorTest.CRL_DATE.getTime())
.build();
startES(settings);
Assert.assertTrue(executeSimpleRequest("_opendistro/_security/sslinfo?pretty").contains("TLS"));
}
@Test
public void testCRL() throws Exception {
enableHTTPClientSSL = true;
trustHTTPServerCertificate = true;
sendHTTPClientCertificate = true;
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", false)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_KEYSTORE_ALIAS, "node-0").put("opendistro_security.ssl.http.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put("opendistro_security.ssl.http.clientauth_mode", "REQUIRE")
.put("opendistro_security.ssl.http.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.http.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATE, true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_FILE, getAbsoluteFilePathFromClassPath("crl/revoked.crl"))
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_CRL_VALIDATION_DATE, CertificateValidatorTest.CRL_DATE.getTime())
.build();
startES(settings);
Assert.assertTrue(executeSimpleRequest("_nodes/settings?pretty").contains(clustername));
}
@Test
public void testNodeClientSSLwithJavaTLSv13() throws Exception {
//Java TLS 1.3 is available since Java 11
Assume.assumeTrue(!allowOpenSSL && PlatformDependent.javaVersion() >= 11);
final Settings settings = Settings.builder().put("opendistro_security.ssl.transport.enabled", true)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_HTTP_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLE_OPENSSL_IF_AVAILABLE, allowOpenSSL)
.put(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_KEYSTORE_ALIAS, "node-0")
.put("opendistro_security.ssl.transport.keystore_filepath", getAbsoluteFilePathFromClassPath("node-0-keystore.jks"))
.put("opendistro_security.ssl.transport.truststore_filepath", getAbsoluteFilePathFromClassPath("truststore.jks"))
.put("opendistro_security.ssl.transport.enforce_hostname_verification", false)
.put("opendistro_security.ssl.transport.resolve_hostname", false)
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_PROTOCOLS, "TLSv1.3")
.putList(SSLConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_ENABLED_CIPHERS, "TLS_AES_128_GCM_SHA256")
.build();
startES(settings);
final Settings tcSettings = Settings.builder().put("cluster.name", clustername).put("path.home", ".")
.put("node.name", "client_node_" + new Random().nextInt())
.put(settings)// -----
.build();
try (Node node = new PluginAwareNode(tcSettings, Netty4Plugin.class, OpenDistroSecuritySSLPlugin.class).start()) {
ClusterHealthResponse res = node.client().admin().cluster().health(new ClusterHealthRequest().waitForNodes("4").timeout(TimeValue.timeValueSeconds(5))).actionGet();
Assert.assertFalse(res.isTimedOut());
Assert.assertEquals(4, res.getNumberOfNodes());
Assert.assertEquals(4, node.client().admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet().getNodes().size());
}
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_size_in_bytes\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_count\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"rx_size_in_bytes\" : 0"));
Assert.assertFalse(executeSimpleRequest("_nodes/stats?pretty").contains("\"tx_count\" : 0"));
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.amazon.opendistroforelasticsearch.security.ssl;
import java.security.cert.X509Certificate;
import com.amazon.opendistroforelasticsearch.security.ssl.transport.PrincipalExtractor;
public class TestPrincipalExtractor implements PrincipalExtractor {
private static int transportCount = 0;
private static int httpCount = 0;
public TestPrincipalExtractor() {
}
@Override
public String extractPrincipal(X509Certificate x509Certificate, Type type) {
if(type == Type.HTTP) {
httpCount++;
}
if(type == Type.TRANSPORT) {
transportCount++;
}
return "testdn";
}
public static int getTransportCount() {
return transportCount;
}
public static int getHttpCount() {
return httpCount;
}
public static void reset() {
httpCount = 0;
transportCount = 0;
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2015-2018 _floragunn_ GmbH
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Portions Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.elasticsearch.node;
import java.util.Arrays;
import org.elasticsearch.common.logging.LogConfigurator;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.Plugin;
public class PluginAwareNode extends Node {
@SafeVarargs
public PluginAwareNode(final Settings preparedSettings, final Class<? extends Plugin>... plugins) {
super(InternalSettingsPreparer.prepareEnvironment(preparedSettings, null), Arrays.asList(plugins), true);
}
@Override
protected void registerDerivedNodeNameWithLogger(String nodeName) {
System.out.println("nn "+nodeName);
LogConfigurator.setNodeName(nodeName);
}
}

View File

@ -0,0 +1,48 @@
-----BEGIN CERTIFICATE-----
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
pTIIfrQcZ1vrDg0lYzVgQ1iT
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
-----BEGIN X509 CRL-----
MIICJzCCAQ8CAQEwDQYJKoZIhvcNAQELBQAwgZUxEzARBgoJkiaJk/IsZAEZFgNj
b20xFzAVBgoJkiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENv
bSBJbmMuMSQwIgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAi
BgNVBAMMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQRcNMTgwNTA1MTQzNzEz
WhcNMTgwNjA0MTQzNzEzWjAUMBICAQQXDTE4MDUwNTE0MzcxM1qgLzAtMB8GA1Ud
IwQYMBaAFJR34pMxCz+258vljmpEpMTjBMHgMAoGA1UdFAQDAgECMA0GCSqGSIb3
DQEBCwUAA4IBAQBrfIw3gou9Rcrv5ih/Pm6Ghot8dZosJvpG+gMbU6+ZmBwldfMI
qNW5zEKm3pjKw6412MfjqhPV8ioKolxfHVBockH//a0fbo0VUH0H9K2C9lcKbHXV
h97x3ubrKkF/TqY9xKUTRbNJ5pUNGgq2SLnjaVHdI1dSQ17V6yIepJV6xk6s3jbl
bPf/rJAr7Ft4XLnw6LUuXSWN0vTxolQxHACTST8GBMsE57Vbs6TneCo3eOa6HwO6
Yolz3GTaVoF1wireUkNUAi+nf5T72HlgrMBEU24qbIuM2IcI0DuLMGISbFqp+BkK
74YjkYcDKqehftGJQPVqFTQTX/VnXOBWp0ww
-----END X509 CRL-----

View File

@ -0,0 +1,50 @@
-----BEGIN CERTIFICATE-----
MIIEczCCA1ugAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
NTE0MzcxM1oXDTI4MDUwMjE0MzcxM1owVzELMAkGA1UEBhMCREUxDTALBgNVBAcM
BFRlc3QxDTALBgNVBAoMBFRlc3QxDDAKBgNVBAsMA1NTTDEcMBoGA1UEAwwTcmV2
b2tlZC5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AKxwDZ7p6XYyfUSvaoBe8LzWYAm5QLcia/CVihP57OxZZoggIXNZjzmXQfgDR/Kq
OJeIBSJuNRmyZBqXZ1Hn5gTX7/JiZV3+vNGf3MhPjE6yhULRiASvi9S7oKyz6msW
r1fC8cXfhdnwtp2xcszBww+28MqCK+FVe4351H9/vjkaBgpG6bFg8TAtCGmhgZCZ
86o3e4+6GTIdDj8oWhNbz3VMxtNgMNmQX/JZYvq0SX6qbAQ2O9qSP41j2BnqDL8u
9iVK9S5lsciezROOa8ULKB1qsD/L8Giw23IZiSLLN+CsX9bKyc3kvXD/Po5mNcAb
5l08cm/u4WrPFiK1+CHoivMCAwEAAaOCAQkwggEFMA4GA1UdDwEB/wQEAwIFoDAJ
BgNVHRMEAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4E
FgQUy1zyrICC0otqxUy17nO6vHuCvBYwHwYDVR0jBBgwFoAUlHfikzELP7bny+WO
akSkxOMEweAwYgYDVR0fBFswWTBXoFWgU4ZRaHR0cHM6Ly9yYXcuZ2l0aHVidXNl
cmNvbnRlbnQuY29tL2Zsb3JhZ3VubmNvbS91bml0dGVzdC1hc3NldHMvbWFzdGVy
L3Jldm9rZWQuY3JsMCUGA1UdEQQeMByCE3Jldm9rZWQuZXhhbXBsZS5jb22IBSoD
BAUFMA0GCSqGSIb3DQEBCwUAA4IBAQDG6Ov5TMUdofGHKQgSjJDzka4XtQtMU7PP
rPvomrL6RsCEYv4hpbJwiZQuoMAPTQX14b9I+doQtN7kMb7nXK+UEOXff9LIUPi1
qS9OR6ViB3u1M9AV9vWIbUd3stqLr1Oceba+ISXxThW73eXpPnEFZXaA/1s84aqa
PrAIS7vsLrWI1TtsoyxZdzSVCjq5PjlAEW1hkrTw8GFe0ayIi1Vc4jWYlYJhCWn2
GRmpmARbV7yq1h+1Cp0bDs0LykUsAkTpiWN+E5YcS9Nt882ZRmQ59dkctvxxJzW8
+YMJisWjXv1Ssr1WokIMC+uVBcltzaIs+DY2guSmSOhBDHMKv8Jb
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
-----END CERTIFICATE-----

View File

@ -0,0 +1,29 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIE6TAbBgkqhkiG9w0BBQMwDgQIuBSRCrFlilwCAggABIIEyGvzG/HskxEPdjlB
UH23XevwHIWn2sf7mlsZipfBsgjm9v3kizTlbAlVrgHspuU2DK+Sd9pVoKGZ3HBA
nqt5RjPyXUtG9+RClGIF6KxErHCokF35iYb+7wGB4eZjGr1Pthl7Qffb62FT0Ecx
aP+4daY8ZHYujjNsFRAcrEvad72xRZh9+quZZWnOYYYh8wIpHBjBPvWOJdgnWA0C
hkFlqjBgqCFOkWFfSHO8TVwywU+QAH4/CW7RVWIpPUZmB7D5XhB7GHDunnA5sZZS
chHzJ+tyEQ2eryz4/raeFsOeRgdHMWxTJeLflLmJFBDglmsVg2ly0noobOaPtOOL
SxEzgVEC6pJ9hlWvwiAbTmnHaCdp8Oo8mVMemMrgxME7a7gPw8DfY9VJ9zc3JNk6
4eBYZMeG9HnBLLqG1LOsEt32QOIegHrEx729WpyEAXtYd7G+ZY0qT5LG5Vscy1vf
LGGPagcg1x6Bk8f8oxMRlMdMXHWPdYYvE9kQz+tiM2n/HAipUotgYGnC4jl/ux/Q
wvTK9qj2iHC7PTGdIeV08b01wvljfWWRLh5oMm3lQuxSTcHXx0+vw+OBuicEYwwb
KFyo/qPRqautDKLsHyNBUR1xbt43ZGP8ziwxLxJeNrSzmUed7gFsFZllg8czXlLk
54Wl3Ism6G9jkjb+K+QXKI2FKdb4RZmXmMXwrQnI8U77W1YT2g1p5W/e1w+/cVvE
vNQFcnIBTXvLKh3hM95X+QvFhIW4dXHHU4E+6GvNtp2IR27isfR+xc4BFicXsA4F
Ngz5qr8CJN5VT5XONGx9HuSF/oT3nu2S6LRVjkdLLo5ygCULLN9TdovtPrBrI0u9
oZALTXQVqGEBS+7YEO315EvWYk9RA1pAYqpho3lDGCUbO8y4RmuXjv1WsfM0qDl3
JF/aYgqJshF1lgMv5Dx8GTCUGawv3r53T2IWhI+MEbAzyrD/1Xs2+C4RCEsOE+bb
9pFvoDWWmLQzwagERsFdixdTvW4hBb/x/BJcD0FYoIN8FRp9/X8r8jclF3uIW5LY
9TikkjjPi25tAYKrlAkg+zcmDBnlL266UTa2BF5wtw34a8EbXb7bTSKWtjmS4f6G
gEaU7n3UwAE4yzJvY7h+OMbdoiCzf+Jlq+v8lEpGAmE1leSPd8OaWGcSsg20CjUc
0eCxFm4FGDFPn0OD4XiSFviFoyVngWx2H3ztSeP3tkCGKa7mYVf6slc8MNqa/emQ
NkzTmSr0Z+aGnCLfb2Y4B6F7kMk93+sYNXW1n2D1FECQbf84XgfjUB4D2FeGfPVT
L2MFVgUe42HBy7J3v0a4yAfb77LtAEild2PgWYQR5oKTnUndpiSj0Hxtwqy8gxac
K37V+SVbsi5JVCAjpu8r8bK7Dsw3937CjArOCKRj2iYYRf54rP58SG6EiIrZzQZh
DR8f9IZU7zEVzNfaH0canP0+ShqRUkoe5h2GyFRJnjDrZYRFoLRUFs4Bkqlhag9F
ws2N/eU9al8m6eursmBO6ZZnv2adIUF1A33Efk/vuKjy7Rd19HD/G45uji9U3tsJ
ygcKCS82yWsqbAcNAd7e2+MAyLnrh3ERyvW3ywr8am1Pk+nNbfDD/DK6kh+YOvol
Ax3JqWKlwZZ+pSls/A==
-----END ENCRYPTED PRIVATE KEY-----

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,30 @@
Bag Attributes
friendlyName: kirk
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 36 39 34 34
subject=/C=DE/L=Test/O=client/OU=client/CN=kirk
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
-----BEGIN CERTIFICATE-----
MIIEQDCCAyigAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
NTE0MzcxNloXDTI4MDUwMjE0MzcxNlowTTELMAkGA1UEBhMCREUxDTALBgNVBAcT
BFRlc3QxDzANBgNVBAoTBmNsaWVudDEPMA0GA1UECxMGY2xpZW50MQ0wCwYDVQQD
EwRraXJrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt7iBnBLbkmCK
MEkc9meRsLmtrYeKKbkPL/CNogjP5fhIH5vSWd2+vSzgENAXtaHkhLrDiqi6vnny
+r0KaluCsuYGZkisMMcPku3sODGtHakuWts4YYLqHtZWvsR4F8ioHJ1E+gdG+ACj
df4MvWR+MkG5tswceqwfltpZti0xzUOTCowFdtZ6NaCoWPMgmg85T3hjWGe7SSSI
gJDAWpJAETCb4RIKrSS26dlESdgU6zj4QowEV+/gKdLKO9pVo5mOKKuDNYLMzN6m
1Q7abUQFeTAgIq6MX9YSJ40Qj7fWWq2OB/hJNTHN9LfTra9/ZMKPt5ecyBCTRpr+
KmXlMEg+BwIDAQABo4HhMIHeMA4GA1UdDwEB/wQEAwIFoDAJBgNVHRMEAjAAMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUOXz2tftJLgWX
+hwbtJmItC0nJ8cwHwYDVR0jBBgwFoAUlHfikzELP7bny+WOakSkxOMEweAwYgYD
VR0fBFswWTBXoFWgU4ZRaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29t
L2Zsb3JhZ3VubmNvbS91bml0dGVzdC1hc3NldHMvbWFzdGVyL3Jldm9rZWQuY3Js
MA0GCSqGSIb3DQEBCwUAA4IBAQAORNkM6q4j1ELFStU3CVI0AJIepZQ4JoBPLOUN
K0tvnnzRuTEM57kaydg2PmbG1YUY6XS3S/IFyUZic95rPMxUUL8gGGCs1lJLq3i9
Kt7aN0oyrnL00N2h8EDgi1WFjTYF0l/L52zKrxIOc7fAo1M0HLOHiPUq21A6hCrS
VsBOeXB8GBgpKIqMLtx0wYDIwK3ItadGZ8B/rwH8rimMZHSSXvjd2RUQtaEHw5yj
7zSE+0CogoMWuBjiSWl5WzQ0RWHnYQVunzuCnMZVRTk04yO4L2ctPWqlRVUlXM7A
y/YZiBL/k1uu28QVRcP1XzH63XE4MAQMcShvTbAZAoSWAJkV
-----END CERTIFICATE-----

View File

@ -0,0 +1,9 @@
status = error
appender.console.type = Console
appender.console.name = console
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{ISO8601}][%-5p][%-25c{1.}] %marker%m%n
rootLogger.level = info
rootLogger.appenderRef.console.ref = console

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,88 @@
Bag Attributes
friendlyName: node-0
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 30 31 36 38
subject=/C=DE/L=Test/O=Test/OU=SSL/CN=node-0.example.com
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
-----BEGIN CERTIFICATE-----
MIIEgjCCA2qgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
NTE0MzcwOVoXDTI4MDUwMjE0MzcwOVowVjELMAkGA1UEBhMCREUxDTALBgNVBAcT
BFRlc3QxDTALBgNVBAoTBFRlc3QxDDAKBgNVBAsTA1NTTDEbMBkGA1UEAxMSbm9k
ZS0wLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
h5j6Dy0HqaP5MZe+KLkby42pUJn7OaQfZ7AYHJXs8XQ0aB+3eHfl57ubGDlsbxZc
9s88LuhPo1Y3Frgj7SbH/KVeD0nc04uSWDvhFlxbL27c+TopPg75YTC8KcXy4mK+
Bt1od28yxno6z18XroOoqBEf7086MY7MyDnduuLp/B1nwGijYM32k+KP9HJbRu9J
MMt16GQYmbQtGJEqo5E8WAP/doTiH1f/cASSSoaiAR4Lzjhjbf6BEvtEQK51BFvq
hG/qN229joyiOOexiLZb/bCdRdGebOOpOb9uBjqI1FlVc4TgIfyCKm/QATinZMLC
cSl6NcUTFgcJkUxZn9DaEwIDAQABo4IBGTCCARUwDgYDVR0PAQH/BAQDAgWgMAkG
A1UdEwQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW
BBR8XDrqpmWsEGpmnfP3sIdFTOZ7XDAfBgNVHSMEGDAWgBSUd+KTMQs/tufL5Y5q
RKTE4wTB4DBiBgNVHR8EWzBZMFegVaBThlFodHRwczovL3Jhdy5naXRodWJ1c2Vy
Y29udGVudC5jb20vZmxvcmFndW5uY29tL3VuaXR0ZXN0LWFzc2V0cy9tYXN0ZXIv
cmV2b2tlZC5jcmwwNQYDVR0RBC4wLIISbm9kZS0wLmV4YW1wbGUuY29tgglsb2Nh
bGhvc3SHBH8AAAGIBSoDBAUFMA0GCSqGSIb3DQEBCwUAA4IBAQBvrw8OxZfhRb6N
JtKTUN6L4Tof/PxrE6onKzNeB7H/YrWXx+ZN4eg4STLNY3jwV5sop8YqF9nF2QA/
+iC/xH6KA74qLD8t/epwOhkMt+w9q+N/j8KAesRyBOFiMKLgtQy/J2KvvT7hx2wY
NujerGbWW08UJgRohvbm0Ekm2FHx/yt/4jt1uNoEBgg1MI7dF99/M4sMm0pLgKab
5mn2PNsmQzF4FMPQ5vilmg4/sHe60ntR6YsfFxmkgLrEEiERs/DjUPTgSVMMPRmv
Cc+2hudY6sdLyrHV+NfGXqCcc18+ImpTVQ6QvngN/L9ZneXgooasFUAbs2Qgvl1+
aMsb6ZpV
-----END CERTIFICATE-----
Bag Attributes
friendlyName: CN=Example Com Inc. Signing CA,OU=Example Com Inc. Signing CA,O=Example Com Inc.,DC=example,DC=com
subject=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Root CA/CN=Example Com Inc. Root CA
-----BEGIN CERTIFICATE-----
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
-----END CERTIFICATE-----
Bag Attributes
friendlyName: CN=Example Com Inc. Root CA,OU=Example Com Inc. Root CA,O=Example Com Inc.,DC=example,DC=com
subject=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Root CA/CN=Example Com Inc. Root CA
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Root CA/CN=Example Com Inc. Root CA
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
pTIIfrQcZ1vrDg0lYzVgQ1iT
-----END CERTIFICATE-----

View File

@ -0,0 +1,32 @@
Bag Attributes
friendlyName: node-0
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 30 31 36 38
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHmPoPLQepo/kx
l74ouRvLjalQmfs5pB9nsBgclezxdDRoH7d4d+Xnu5sYOWxvFlz2zzwu6E+jVjcW
uCPtJsf8pV4PSdzTi5JYO+EWXFsvbtz5Oik+DvlhMLwpxfLiYr4G3Wh3bzLGejrP
Xxeug6ioER/vTzoxjszIOd264un8HWfAaKNgzfaT4o/0cltG70kwy3XoZBiZtC0Y
kSqjkTxYA/92hOIfV/9wBJJKhqIBHgvOOGNt/oES+0RArnUEW+qEb+o3bb2OjKI4
57GItlv9sJ1F0Z5s46k5v24GOojUWVVzhOAh/IIqb9ABOKdkwsJxKXo1xRMWBwmR
TFmf0NoTAgMBAAECggEARFPRrdQDCHiYGWVdbSfZ2biImRT+gw0wxg72F3F09Daa
Md3JlerU7vCaNpq5CUE7lyLWMMzfVG8dU1V2xQnFvImX3BxcKj0qgUurIJlpWX2D
3BJytdLV1yO3rVUSDwGyv8LR4V0nONxexiAkzsuJMSdv8Cb8K/zJNBv0nze4sFFd
9Mb3rlHTm+gVXk6Qa+2j5hQkfwCQ0HQnyyXnFb99YZIBVMaBkn6oUkdbbwn2BdH+
BxypwbDRgB/FoRhwMIah9CBLyuqZt26KiVKUnscemvuI/H3sH1H1veH2shpqWIeD
JcNWs2IbS8kbGW7wDc5lrzRpTLSiVs6g7gIk7KRQAQKBgQD1uIT8+3QnWZpr1i+1
coYJzgFWlghJVEj9SqVVFsC82aLDYaTd2S84anCYV9yDnO85se5qA7z+DE+jBF6S
uy1u5iFsUOyrEXeSXK46Os0sg8V93ez4mcCfDamrXTq95QZxWVeIcWjB9mwzoCj9
gLtFkd74tVHBgLhYqYE4x1a5yQKBgQCNRR9WG1rJanBw98e+LriBN7A97ti11j+W
geh30PsEMtmFtBHztUoO1BeXSy5L6ZQADjDKDEhPDLzzFt6iN2RqynG3nKf7ZzBV
YXTE0C0suzRFLE4B4IwOBLUa0I50teIOav67+o4t/KmCzx93T7M+YRLAATXuRQ1E
R8UHLjwi+wKBgDd/b3n8CSYCFOCaRbhDn4aDYsX9qO12/e1HeMQZGXsN5LcgTK5W
qVWipL+jyIhpX5a2W1TSd1Mh0LLO/9VANWjAzXe7Z1jT3x/NkwRP15tgP7DH+QfF
Ij5KRbIQon3VRnk/ZofIpZJ5Z8LZP6jR9HooEiY2PbroqbpMvoTmcO4RAoGAIW/y
8taWroXbB2IejQ1R7oPX21DlSmTjuCQXegSk5WGDyvnMJfsLBGd/DfhlhOJMfZbe
RXSSyOMi9ga7u3mQ8xXnxKX3vLG35v2iPdNoXeYRgS3zaM5VWBwVIburfERwtSju
EmBDtu7O0H9l2z+qFWG0pm2i7jq54Sd7oy92XHECgYEAs+ke0hR19C0bGPrcGr9U
o5JSsMIcqESYtrkJ3YR62k+guzDc6t3KRIFDzLv9I4s4Dpssn46QKnMYW/KUBxv7
pHkdZUtJagYPqeMIKPWR+UnwsmDDFJ9R/9U7Pf/9MMaQf7U64ffh3Qxdod/MEyI8
uUwbul3fmSa4OAjHhSNPoSk=
-----END PRIVATE KEY-----

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,50 @@
-----BEGIN CERTIFICATE-----
MIIEcTCCA1mgAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
NTE0MzcxNFoXDTI4MDUwMjE0MzcxNFowVjELMAkGA1UEBhMCREUxDTALBgNVBAcM
BFRlc3QxDTALBgNVBAoMBFRlc3QxDDAKBgNVBAsMA1NTTDEbMBkGA1UEAwwSbm9k
ZS00LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
1EjVHY9yVLJjWN7J5OU2pkZyrttRO674kUtIn1Z8lCNTD31DIfOnJ6iLlUDZ0HhC
9VumGOu4dc9HCSoxr4ck1GiDG0YrVdbZ6Hx4E3P+BY/RCxuQutGQeKi4BwgBm/bF
5yg9ro0+ia2808RB9pWuvLClypPjhSJSMfG+UUJ8+23jRYdxYRboWPScacbuV634
1AdOdlr7k7Rauw7nagehRi1k/DUEEOrSHbWqxyziiisJvU97Ey9FZhVya8st8srM
wgNst+Lr16458V1pLRm097PoBYQMU9/MgMVXIz0Rmm1oqRMCPW5CPg6x5SXiKoCf
9i1rwmt5abB58tYwxwJB8wIDAQABo4IBCDCCAQQwDgYDVR0PAQH/BAQDAgWgMAkG
A1UdEwQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW
BBSuaYlnZZNkm6DUGh5K4zLBBYvQMTAfBgNVHSMEGDAWgBSUd+KTMQs/tufL5Y5q
RKTE4wTB4DBiBgNVHR8EWzBZMFegVaBThlFodHRwczovL3Jhdy5naXRodWJ1c2Vy
Y29udGVudC5jb20vZmxvcmFndW5uY29tL3VuaXR0ZXN0LWFzc2V0cy9tYXN0ZXIv
cmV2b2tlZC5jcmwwJAYDVR0RBB0wG4ISbm9kZS00LmV4YW1wbGUuY29tiAUqAwQF
BTANBgkqhkiG9w0BAQsFAAOCAQEAlCP1gK4DkG5VwPAY68BeifMSmSFai/JOOVSA
URk7UiQ+nNkwo7Wuvf60aXqN+K440D3fvW3Bzk7+EnnKQFNXm4jief3ndM4Hvra0
WKh979iWfrBY2LUqWhpW9zsIEx6PQGJIBlAfNiaQSW+gU05DQ8sxcfOgPPou94XT
xrioFBg42JDMDLhiNhyLcMgMEwmdyfNw+N28HLrsoEJ223H9DWwfse1j/IgOKA8h
5/PWNWUE1OFUflWov9wmlMVH4RUDovJGjvzFqZ7e+mH5gALp3CNtIcwl8u5jT3Y7
206hdGScJoTWorKv5ujyhrGY/2Vp7AzY3pHHuP74HZL0HHvp4w==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEBzCCAu+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgZUxEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSQw
IgYDVQQLDBtFeGFtcGxlIENvbSBJbmMuIFNpZ25pbmcgQ0ExJDAiBgNVBAMMG0V4
YW1wbGUgQ29tIEluYy4gU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBANWsMh2EWiqH2eZmaiHreWG4NlhLZGcUbwzRIZT0HmeeBolQygGq
cJE1MpzCMYdezjTRaws/FVA2dkrtcox2xGT6YG7sKqr+4VlIt3Pd0Sah/5dEdRJv
RsN2mj8V8xNUZdduD6NnrIGW/wAoF4isDNJ3QlGFhPM0f0Of5TVFIyholgrevNLT
7D5rdUupIW192zQbOOuOxOmeXkunl8u35wq/VI/ZyJ4/mutCLR5sqd6/kOSDKQTU
gQ+xIrs7LiuF1xZbCtRT3/PWnnD/GJulUsuJ0xOeEHkQaJuwRwYzqFkyVrEea2Wf
U6XmSRZK9L0q5jy8TpCgzULlxb92POZd9ssCAwEAAaNmMGQwDgYDVR0PAQH/BAQD
AgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFJR34pMxCz+258vljmpE
pMTjBMHgMB8GA1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3
DQEBCwUAA4IBAQAY22ahhmYBdYUpPwQEyEUexyTWal29sbV+R44qVKM6FDEEd/8Q
cFe5cnguDqmLBwHDLey4eSsAHI5tBUtslPJMqobWbwzswxdZ9WCOaLBWlvZdK4XU
hkrq919wENMT6DVagNdpNRmDA47G4eRha4oD1ZO2YCFM0H8rEWDRSlaAHsGHLR59
cJ5AgPqAVrEMfP6WzxXW2ThY6HD1LsE69T20/CfR8/k826BkcYVHKR/MQ/YZOWXb
ccfb7D5o/oMop0E4+huCdF7ZDOt7/f5+BAfJZ08GCMLy5GSxU9gf8WiT/yNBYETS
DAj+BAKhzlzvsaC3E2lAeyUepIMN0B8YHjqV
-----END CERTIFICATE-----

View File

@ -0,0 +1,29 @@
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIE6TAbBgkqhkiG9w0BBQMwDgQIAUztzPE48tECAggABIIEyMq0nF+vkpgA9vs1
LrkGVinMLcl9kcnZ6sclulgUpar+agZ7yce3rtdFYrTFTRe9cLfOI/+nm3scsHaH
kf0j6ZVAAyyXupivEV9jnFw6QjMql14EEEpzSjdUJ0e+yO8IIXO5q8dx7tFpiUUg
WlSTaVqLS82OhuwD1VrDykR5XlmHp6COOhEJT7mVdvmNZFCwQ8VUg9k2hjAWB7vw
PhJPNBnhI4Tr5Gb0/qFvpPcPkV5muxSkSJ2VA+YgHHgvZKpC/8E46uq7t2m45owM
iCPOAVSy5nLigKcttP9Q8o7LY+l8iJdwkzTotu1gFjYfVp6+n1vHIKDf3kQz457v
wCpSTa9p7PEreAo+SNUsigG23SsNIWP9/uUpPiy3G4X2kuNlxWdmqY8KSmblttGq
6vmdIqpNwGOGDy6stfU9K7tgVdoEvRXfaNS1PwyF4V9ZVF9y6HEqmRcdpdjKIufW
H49nF7AcNPGsEGCeX36ILnAGborvWstCOMl0WFkBg45sbLiT2Q9gAfSo37+Rfh11
O+k6V8p5X30o6ftav3OR7j/dViKp/5j5dyAMjB/4tcDMkywHwm8Evyik8aWomQer
1u6KPpE9hYn2YOY2cZouiC3d8KNLZJMdkcOlqYRs23N9QNNeFW3CvGGb0203+uWb
185gjGHVX/lT8INlquPJyAt/3VT4EWTaSvIUS4pI75kDq/gzr56ak4/GgDEB4pK+
yH7npm3U1p/jyoriJ3/1jMXkRp7HN42XSL2/m/Kzk5fX9JaNNO4ANHpuxMqV6MU/
krWMa2bbC2shaVxZFOlx7LOUL7eHh7Vkk3T6/G28s57d9pW8qHBlwgNrYdegB8aC
wF8SNmo75c4xHkpShx+FmGG/Q7h0VYzzr2j9XQTs7GspbEJo9ugTSVoAEVLI2avL
sE6GS8AzKGTDKPNlzAru2+nzqQ4aG0RxYMpg9a+cPMQeoos7knjkkT1Twc1gcWQv
r9O3vsY87pLKMSsstDtkZRONqxwPqbfDIMyV2JOF/x1EZ3+V1NMQErwGgl/tqlW7
+PnW9JrIVFp+AEAzY666cta/RSJ2MNa7OrodIrgH5TtEwEy3qDH1YtVXUXG9A05W
AGjLMFCQKEtrTrN4EotqXEXLmY54JF9WvT7hvtjYYhxkS+QtquujJb6En+Pte+Lm
HN89dZToAY62LxhR4P1morg0jUwrAMssFa0YnMO3wN6ADQ8RSVT0cyOtGDM77DrI
ps/K1tY+lQi9OV1pflP+Q6SukTWs+6dm8MpRcySPiKI+OZLVwy0MYub8UlCaO7PK
QM+VcXVX3OyIKUe6BUiEE7KVnFh3V/I0KfNbYKInEM3gWPV06BWNSUo8TEXrxXWz
xNRGG9r8RKf99cMzotox7G2YUSBJdI3SAqUse5ubdOW7TRsSMtdzMpSr62hambZ8
BYLjtjYZm050vu3PHeYO6htCMj52m+w6IFrPGlmmKqwMsgnSC31Ns5zmMQP5Oeu9
spLrr+oGsURF3DRVdAXGBY1OlvWCDLsCSp0kOF2Vpj4y7v9zPEEku8w6eGMbRKcc
+Cg86Acrc1hOkDtzWtfpbDkkhXPkcYU8ic8c7gN3japCoH+RFLqoNhJow1vx6TW1
9vCq0aTqdksLCNZ1Bw==
-----END ENCRYPTED PRIVATE KEY-----

Binary file not shown.

View File

@ -0,0 +1,83 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: DC=com, DC=example, O=Example Com Inc., OU=Example Com Inc. Root CA, CN=Example Com Inc. Root CA
Validity
Not Before: May 5 14:37:08 2018 GMT
Not After : May 4 14:37:08 2028 GMT
Subject: DC=com, DC=example, O=Example Com Inc., OU=Example Com Inc. Root CA, CN=Example Com Inc. Root CA
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:a6:11:e1:5d:aa:74:36:e1:d8:43:32:37:14:2b:
5e:3e:2e:72:60:3b:6f:4e:7c:b3:5c:ea:88:dc:18:
41:84:66:42:e6:52:a7:68:42:98:d7:19:b8:e6:b6:
e3:2b:74:7d:71:d2:0c:b6:0d:0d:d5:4a:80:2d:0a:
f6:79:b6:e5:3c:b0:fd:9c:52:70:a7:62:1b:26:00:
9b:32:be:d2:68:5a:4f:98:19:b2:8b:e9:1c:c4:9c:
f2:d7:28:d7:4a:fa:7e:5a:31:0a:46:b3:2c:76:94:
80:20:05:bf:5b:9a:36:f2:0a:2b:cf:0a:28:78:d7:
9b:98:b4:34:f9:b1:ff:85:56:f4:89:09:b9:89:a2:
fc:40:9d:79:ae:51:ef:a2:c0:07:6d:62:87:c9:2b:
a1:52:34:79:18:47:07:55:73:6d:81:3d:8b:39:de:
30:9e:54:05:f2:c7:17:68:8c:47:f4:53:8a:58:2c:
e4:80:24:a5:d9:63:ea:0b:a1:0a:f4:89:b1:b3:a3:
d1:f9:a6:70:44:94:ac:fc:0a:00:47:e1:19:51:9f:
88:4e:db:d7:91:e8:e4:40:90:47:ac:a7:d4:20:e2:
ba:5a:4e:2e:6b:61:a7:bc:dc:67:68:f1:07:37:af:
b5:33:5e:5b:33:e8:9b:4d:b5:84:a1:b4:9e:bc:a8:
1f:95
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Key Identifier:
5B:C7:B9:B0:46:EE:FF:F6:42:E6:5E:E4:CF:12:F8:57:4C:6A:30:15
X509v3 Authority Key Identifier:
keyid:5B:C7:B9:B0:46:EE:FF:F6:42:E6:5E:E4:CF:12:F8:57:4C:6A:30:15
Signature Algorithm: sha256WithRSAEncryption
2a:5b:a0:b5:5c:a2:59:1f:a1:90:c9:d1:c5:71:44:e8:2e:99:
b8:61:2c:a9:a9:9b:c3:d1:67:f7:f5:d5:cd:ca:08:a1:f2:cc:
f2:76:dc:6d:28:46:23:16:2b:f1:3b:7a:0e:6b:8b:f7:27:fe:
76:cb:8a:0d:73:69:2c:17:28:57:44:02:61:28:41:39:f0:d1:
c3:1a:d6:fa:7a:a5:16:5a:df:64:d9:8a:e7:b2:f0:fc:93:48:
62:6e:3c:ed:4e:60:16:4d:8c:58:20:c7:45:fb:81:34:85:f3:
54:c6:41:66:5d:7b:53:84:ea:0c:85:d7:04:a9:46:15:5e:b5:
5d:ad:43:85:f6:d5:66:e3:d0:42:b1:0a:eb:0a:44:30:43:4b:
d6:be:04:da:8a:4d:2c:82:cc:f8:c9:a2:88:fa:23:91:b7:da:
85:ef:8f:d6:7f:b2:a3:2c:fa:59:47:73:a4:90:4d:6c:ad:f5:
a1:0a:cc:cd:cd:40:74:08:c0:f8:df:8b:fd:6c:84:56:b6:3c:
ef:55:04:c2:34:d9:bd:3d:a0:76:b4:c9:10:99:e2:be:8c:e4:
7b:cb:02:2d:3b:4f:a6:8a:3d:2f:0d:22:b7:6d:61:aa:4e:b7:
e0:01:75:27:a5:32:08:7e:b4:1c:67:5b:eb:0e:0d:25:63:35:
60:43:58:93
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
pTIIfrQcZ1vrDg0lYzVgQ1iT
-----END CERTIFICATE-----

View File

@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQsFADCBjzETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
MB8GA1UEAwwYRXhhbXBsZSBDb20gSW5jLiBSb290IENBMB4XDTE4MDUwNTE0Mzcw
OFoXDTI4MDUwNDE0MzcwOFowgY8xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAVBgoJ
kiaJk/IsZAEZFgdleGFtcGxlMRkwFwYDVQQKDBBFeGFtcGxlIENvbSBJbmMuMSEw
HwYDVQQLDBhFeGFtcGxlIENvbSBJbmMuIFJvb3QgQ0ExITAfBgNVBAMMGEV4YW1w
bGUgQ29tIEluYy4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKYR4V2qdDbh2EMyNxQrXj4ucmA7b058s1zqiNwYQYRmQuZSp2hCmNcZuOa2
4yt0fXHSDLYNDdVKgC0K9nm25Tyw/ZxScKdiGyYAmzK+0mhaT5gZsovpHMSc8tco
10r6floxCkazLHaUgCAFv1uaNvIKK88KKHjXm5i0NPmx/4VW9IkJuYmi/ECdea5R
76LAB21ih8kroVI0eRhHB1VzbYE9izneMJ5UBfLHF2iMR/RTilgs5IAkpdlj6guh
CvSJsbOj0fmmcESUrPwKAEfhGVGfiE7b15Ho5ECQR6yn1CDiulpOLmthp7zcZ2jx
BzevtTNeWzPom021hKG0nryoH5UCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFvHubBG7v/2QuZe5M8S+FdMajAVMB8G
A1UdIwQYMBaAFFvHubBG7v/2QuZe5M8S+FdMajAVMA0GCSqGSIb3DQEBCwUAA4IB
AQAqW6C1XKJZH6GQydHFcUToLpm4YSypqZvD0Wf39dXNygih8szydtxtKEYjFivx
O3oOa4v3J/52y4oNc2ksFyhXRAJhKEE58NHDGtb6eqUWWt9k2YrnsvD8k0hibjzt
TmAWTYxYIMdF+4E0hfNUxkFmXXtThOoMhdcEqUYVXrVdrUOF9tVm49BCsQrrCkQw
Q0vWvgTaik0sgsz4yaKI+iORt9qF74/Wf7KjLPpZR3OkkE1srfWhCszNzUB0CMD4
34v9bIRWtjzvVQTCNNm9PaB2tMkQmeK+jOR7ywItO0+mij0vDSK3bWGqTrfgAXUn
pTIIfrQcZ1vrDg0lYzVgQ1iT
-----END CERTIFICATE-----

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,30 @@
Bag Attributes
friendlyName: spock
localKeyID: 54 69 6D 65 20 31 35 32 35 35 33 31 30 33 35 36 38 39
subject=/C=DE/L=Test/O=client/OU=client/CN=spock
issuer=/DC=com/DC=example/O=Example Com Inc./OU=Example Com Inc. Signing CA/CN=Example Com Inc. Signing CA
-----BEGIN CERTIFICATE-----
MIIEQTCCAymgAwIBAgIBBzANBgkqhkiG9w0BAQsFADCBlTETMBEGCgmSJomT8ixk
ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
QTEkMCIGA1UEAwwbRXhhbXBsZSBDb20gSW5jLiBTaWduaW5nIENBMB4XDTE4MDUw
NTE0MzcxNVoXDTI4MDUwMjE0MzcxNVowTjELMAkGA1UEBhMCREUxDTALBgNVBAcT
BFRlc3QxDzANBgNVBAoTBmNsaWVudDEPMA0GA1UECxMGY2xpZW50MQ4wDAYDVQQD
EwVzcG9jazCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOtJCa7B8MJ3
5PjnZ6OQbXtwt8bWHQgHiGKoIEqKGKRHzZZeTLvA/u++ihuHWQlSSeGF5flRiLW3
5wZlSykcyabIC1rxV32SuJ/6ebxOHLnGhLagJ+ZS1+ehd9ksDu+y3bWQnJFLec6n
4dThQAdNT6blqDcq5m/p7p/q/tJfNFLt6YMSrvxhopn5kC1tc5k5t6MbyLraXe7b
u4ZaNNPsxho6ArJc5IktSwxgW1iqVxR2zC/5BghKFt3RKmZltVInX8IOZcWxSWvZ
zdhBJonw/RGvBnvsXFW3NQ7v4yfAce4gWnZwvzKW6kXg1BZAh5vWcPnNzTkkl48n
rMdfGP5tpF8CAwEAAaOB4TCB3jAOBgNVHQ8BAf8EBAMCBaAwCQYDVR0TBAIwADAd
BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFPUR3m9eT6lZ
4rz7qj8hhxVe2VibMB8GA1UdIwQYMBaAFJR34pMxCz+258vljmpEpMTjBMHgMGIG
A1UdHwRbMFkwV6BVoFOGUWh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNv
bS9mbG9yYWd1bm5jb20vdW5pdHRlc3QtYXNzZXRzL21hc3Rlci9yZXZva2VkLmNy
bDANBgkqhkiG9w0BAQsFAAOCAQEAL3COeHo9Dg1x78vhFmio0Nmfk46SmQz8n4vI
qxWp0e+OoKdIZXpbVPV7SU4TEoXRG0tzOTd37kvDcMv95YUiYCuXbM23c7Y44JL2
LHF0jIdUAuWFR/lchBB0rQiJshs6n0EqonAE/48zzSt7Vq6q+y8Q5sh4Eh1uyWMw
vgH85r4+iRVQdnadPc3dv3clSkFhDgbAqyYPr27z9z92leqsyoP3Um4C3vX3bNXP
/DxQE9YgT8E9AjAKoogyFGovG7RMZK9eh9FtnbwvGYGTBG6DE32l1xqrUfnMdSCs
OzXIwhyhXaB/vafIZrOpFxZWRkyAsmsqlhTVHNf/QJy3CaEG4w==
-----END CERTIFICATE-----

Binary file not shown.

Binary file not shown.