mirror of https://github.com/apache/cassandra
Add support for PEM based key material for SSL
patch by Maulin Vasavada; reviewed by Jon Meredith and Stefan Miklosovic for CASSANDRA-17031
This commit is contained in:
parent
72302adec8
commit
3655b26adf
|
|
@ -66,7 +66,7 @@ target/
|
|||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
/.ant-targets-build.xml
|
||||
**/.ant-targets-build.xml
|
||||
.ant_targets
|
||||
|
||||
# Generated files from the documentation
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
4.1
|
||||
* Add support for PEM based key material for SSL (CASSANDRA-17031)
|
||||
* Standardize storage configuration parameters' names. Support unit suffixes. (CASSANDRA-15234)
|
||||
* Remove support for Windows (CASSANDRA-16956)
|
||||
* Runtime-configurable YAML option to prohibit USE statements (CASSANDRA-17318)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Licensed to the Apache Software Foundation (ASF) under one
|
||||
~ or more contributor license agreements. See the NOTICE file
|
||||
|
|
@ -51,6 +51,7 @@
|
|||
</fileset>
|
||||
<path refid="build.classpath"/>
|
||||
<path location="${build.dir}/${final.name}.jar"/>
|
||||
<pathelement location="${build.classes}"/>
|
||||
<pathelement location="${test.build.classes}"/>
|
||||
<pathelement location="${test.build.conf}"/>
|
||||
</path>
|
||||
|
|
@ -73,9 +74,11 @@
|
|||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="buildTests" depends="init">
|
||||
<deltree dir="${test.build.dir}/conf"/>
|
||||
<copydir src="test/conf" dest="${test.build.dir}/conf"/>
|
||||
<target name="buildTests" depends="build">
|
||||
<delete dir="${test.build.dir}/conf"/>
|
||||
<copy todir="${test.build.dir}/conf">
|
||||
<fileset dir="test/conf" includes="**"/>
|
||||
</copy>
|
||||
<javac destdir="${test.build.classes}" debug="true" includeantruntime="false">
|
||||
<src path="${test.src}" />
|
||||
<src path="${test.build.dir}/conf" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import java.util.Map;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Custom {@link ISslContextFactory} implementation based on Kubernetes Secrets. It allows the keystore and
|
||||
* truststore paths to be configured from the K8 secrets via volumeMount and passwords via K8 secrets environment
|
||||
* variables. The official Kubernetes Secret Spec can be found <a href="https://kubernetes.io/docs/concepts/configuration/secret/ ">here</a>.
|
||||
* <p>
|
||||
* When keystore or truststore is updated, this implementation can detect that based on updated K8 secrets
|
||||
* at the mounted paths ({@code KEYSTORE_UPDATED_TIMESTAMP_PATH} for the keystore and {@code
|
||||
* TRUSTSTORE_UPDATED_TIMESTAMP_PATH} for the truststore. The values in those paths are expected to be numeric values.
|
||||
* The most obvious choice might be to just use the time in nano/milli-seconds precision but any other strategy would work
|
||||
* as well, as far as the comparison of those values can be done in a consistent/predictable manner. Again, those
|
||||
* values do not have to necessarily reflect actual file's update timestamps, using the actual file's timestamps is
|
||||
* just one of the valid options to signal updates.
|
||||
* <p>
|
||||
* Defaults:
|
||||
* <pre>
|
||||
* private key password = cassandra
|
||||
* keystore updated timestamp path = /etc/my-ssl-store/keystore-last-updatedtime
|
||||
* truststore updated timestamp path = /etc/my-ssl-store/truststore-last-updatedtime
|
||||
* </pre>
|
||||
* <p>
|
||||
* Customization: In order to customize the K8s secret configuration, override appropriate values in the below Cassandra
|
||||
* configuration. The similar configuration can be applied to {@code client_encryption_options}.
|
||||
* <pre>
|
||||
* server_encryption_options:
|
||||
* internode_encryption: none
|
||||
* ssl_context_factory:
|
||||
* class_name: org.apache.cassandra.security.KubernetesSecretsPEMSslContextFactory
|
||||
* parameters:
|
||||
* PRIVATE_KEY_ENV_VAR: PRIVATE_KEY
|
||||
* PRIVATE_KEY_PASSWORD_ENV_VAR: PRIVATE_KEY_PASSWORD
|
||||
* KEYSTORE_UPDATED_TIMESTAMP_PATH: /etc/my-ssl-store/keystore-last-updatedtime
|
||||
* TRUSTED_CERTIFICATES_ENV_VAR: TRUSTED_CERTIFICATES
|
||||
* TRUSTSTORE_UPDATED_TIMESTAMP_PATH: /etc/my-ssl-store/truststore-last-updatedtime
|
||||
* </pre>
|
||||
* <p>
|
||||
* Below is the corresponding sample YAML configuration for K8 env.
|
||||
* <pre>
|
||||
* apiVersion: v1
|
||||
* kind: Pod
|
||||
* metadata:
|
||||
* name: my-pod
|
||||
* labels:
|
||||
* app: my-app
|
||||
* spec:
|
||||
* containers:
|
||||
* - name: my-app
|
||||
* image: my-app:latest
|
||||
* imagePullPolicy: Always
|
||||
* env:
|
||||
* - name: PRIVATE_KEY
|
||||
* valueFrom:
|
||||
* secretKeyRef:
|
||||
* name: my-ssl-store
|
||||
* key: private-key
|
||||
* - name: PRIVATE_KEY_PASSWORD
|
||||
* valueFrom:
|
||||
* secretKeyRef:
|
||||
* name: my-ssl-store
|
||||
* key: private-key-password
|
||||
* - name: TRUSTED_CERTIFICATES
|
||||
* valueFrom:
|
||||
* secretKeyRef:
|
||||
* name: my-ssl-store
|
||||
* key: trusted-certificates
|
||||
* volumeMounts:
|
||||
* - name: my-ssl-store
|
||||
* mountPath: "/etc/my-ssl-store"
|
||||
* readOnly: true
|
||||
* volumes:
|
||||
* - name: my-ssl-store
|
||||
* secret:
|
||||
* secretName: my-ssl-store
|
||||
* items:
|
||||
* - key: keystore-last-updatedtime
|
||||
* path: keystore-last-updatedtime
|
||||
* - key: truststore-last-updatedtime
|
||||
* path: truststore-last-updatedtime
|
||||
* </pre>
|
||||
*/
|
||||
public class KubernetesSecretsPEMSslContextFactory extends KubernetesSecretsSslContextFactory
|
||||
{
|
||||
public static final String DEFAULT_PRIVATE_KEY = "";
|
||||
public static final String DEFAULT_PRIVATE_KEY_PASSWORD = "";
|
||||
public static final String DEFAULT_TRUSTED_CERTIFICATES = "";
|
||||
|
||||
@VisibleForTesting
|
||||
static final String DEFAULT_PRIVATE_KEY_ENV_VAR_NAME = "PRIVATE_KEY";
|
||||
@VisibleForTesting
|
||||
static final String DEFAULT_PRIVATE_KEY_PASSWORD_ENV_VAR_NAME = "PRIVATE_KEY_PASSWORD";
|
||||
@VisibleForTesting
|
||||
static final String DEFAULT_TRUSTED_CERTIFICATES_ENV_VAR_NAME = "TRUSTED_CERTIFICATES";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(KubernetesSecretsPEMSslContextFactory.class);
|
||||
private String pemEncodedKey;
|
||||
private String keyPassword;
|
||||
private String pemEncodedCertificates;
|
||||
private PEMBasedSslContextFactory pemBasedSslContextFactory;
|
||||
|
||||
public KubernetesSecretsPEMSslContextFactory()
|
||||
{
|
||||
pemBasedSslContextFactory = new PEMBasedSslContextFactory();
|
||||
}
|
||||
|
||||
public KubernetesSecretsPEMSslContextFactory(Map<String, Object> parameters)
|
||||
{
|
||||
super(parameters);
|
||||
|
||||
pemEncodedKey = getValueFromEnv(getString(PEMConfigKey.PRIVATE_KEY_ENV_VAR, DEFAULT_PRIVATE_KEY_ENV_VAR_NAME),
|
||||
DEFAULT_PRIVATE_KEY);
|
||||
keyPassword = getValueFromEnv(getString(PEMConfigKey.PRIVATE_KEY_PASSWORD_ENV_VAR,
|
||||
DEFAULT_PRIVATE_KEY_PASSWORD_ENV_VAR_NAME),
|
||||
DEFAULT_PRIVATE_KEY_PASSWORD);
|
||||
pemEncodedCertificates = getValueFromEnv(getString(PEMConfigKey.TRUSTED_CERTIFICATE_ENV_VAR, DEFAULT_TRUSTED_CERTIFICATES_ENV_VAR_NAME),
|
||||
DEFAULT_TRUSTED_CERTIFICATES);
|
||||
|
||||
parameters.put(PEMBasedSslContextFactory.ConfigKey.ENCODED_KEY.getKeyName(), pemEncodedKey);
|
||||
parameters.put(PEMBasedSslContextFactory.ConfigKey.KEY_PASSWORD.getKeyName(), keyPassword);
|
||||
parameters.put(PEMBasedSslContextFactory.ConfigKey.ENCODED_CERTIFICATES.getKeyName(), pemEncodedCertificates);
|
||||
|
||||
pemBasedSslContextFactory = new PEMBasedSslContextFactory(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void initHotReloading()
|
||||
{
|
||||
// No-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKeystore()
|
||||
{
|
||||
return pemBasedSslContextFactory.hasKeystore();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected KeyManagerFactory buildKeyManagerFactory() throws SSLException
|
||||
{
|
||||
KeyManagerFactory kmf = pemBasedSslContextFactory.buildKeyManagerFactory();
|
||||
checkedExpiry = pemBasedSslContextFactory.checkedExpiry;
|
||||
return kmf;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TrustManagerFactory buildTrustManagerFactory() throws SSLException
|
||||
{
|
||||
return pemBasedSslContextFactory.buildTrustManagerFactory();
|
||||
}
|
||||
|
||||
public interface PEMConfigKey
|
||||
{
|
||||
String PRIVATE_KEY_ENV_VAR = "PRIVATE_KEY_ENV_VAR";
|
||||
String PRIVATE_KEY_PASSWORD_ENV_VAR = "PRIVATE_KEY_PASSWORD_ENV_VAR";
|
||||
String TRUSTED_CERTIFICATE_ENV_VAR = "TRUSTED_CERTIFICATE_ENV_VAR";
|
||||
}
|
||||
}
|
||||
|
|
@ -186,8 +186,8 @@ public class KubernetesSecretsSslContextFactory extends FileBasedSslContextFacto
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks environment variables for {@code K8_SECRET_KEYSTORE_UPDATED_TIMESTAMP_ENV_VAR} and {@code K8_SECRET_TRUSTSTORE_UPDATED_TIMESTAMP_ENV_VAR}
|
||||
* and compares the values for those variables with the current timestamps. In case the environment variables are
|
||||
* Checks mounted paths for {@code KEYSTORE_UPDATED_TIMESTAMP_PATH} and {@code TRUSTSTORE_UPDATED_TIMESTAMP_PATH}
|
||||
* and compares the values for those variables with the current timestamps. In case the mounted paths are
|
||||
* not valid (either they are not initialized yet, got removed or got corrupted in-flight), this method considers
|
||||
* that nothing has changed.
|
||||
* @return {@code true} if either of the timestamps (keystore or truststore) got updated;{@code false} otherwise
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
|
||||
g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
|
||||
xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
|
||||
L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
|
||||
sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
|
||||
f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
|
||||
RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
|
||||
0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
|
||||
evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
|
||||
tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
|
||||
wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
|
||||
K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
|
||||
zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
|
||||
mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
|
||||
WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
|
||||
jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
|
||||
eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
|
||||
DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
|
||||
AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
|
||||
Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
|
||||
Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
|
||||
ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
|
||||
bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
|
||||
hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
|
||||
RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
|
||||
pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
|
||||
FujZhqbKUDbYAcqTkoQ=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6TAbBgkqhkiG9w0BBQMwDgQI4QuRiKYzf88CAggABIIEyPRVmPp38SIFr8H3
|
||||
wi+oc6b+HJH7SPflXO6XZe4Tignw/aSyBTsLm2dWrzojRAYMIRd1xC7yQ2ffYrvx
|
||||
uoYbtOQeAminNqvwXdRTnwu6oC0rxdBT8RQ9NK7xL2tQyD/shmOeTJG/glXxaeqS
|
||||
rT0CZ5P5GJh6xdIWLEu3lEa3NSWVFE2YacUphmxBoaWjBjsJfWTgkF665SgP+2lh
|
||||
8R2WTcHrHjD8jR4jHB03wlup0LOmOwzplUmqHB9TyuA4wF6tlJajwBcPa0PNI6ny
|
||||
e9YcdcRr7Y0IxnPQr7PhQNV5AQb9TivwX4WaZxR+BXtwMglp+mz0ohjwLS3z6pqr
|
||||
tLrFhv2qcacSl+CKukFb9umV/QBkUk/iu+jwLcNJKPC965GWdieNbO0akBQpQsUN
|
||||
mqaF9DYHogW5lRnybl8WWPIR8tXmSCbSUIgzw4lRK+o15I4vaMI0NfkwFD/2y1sn
|
||||
t3m9LnVBukkpx3g/CPKd9PbZZeWpOTrnRJQfOu9Fj2lmkpGp0peCBqLJpO0pieVl
|
||||
87EQ0ZCErtAGLGIAhWnDUqRK0MaWZ+DMQNKYn5klF4YTVBkfRc9tQbIgBaa77wvz
|
||||
gvVWBuJtTFpCt9c8jByTH1gLbchC4bhLsy1nO7moevypMmNW4rqw9x5f0EIR3zCU
|
||||
L5/buoIh91TG5JB7BaIbVHtbB/Y2siARRXJibuw3ChBjqPOfzQ66j//NCMqhfTwT
|
||||
x2wn7L1BB4xyLJgVW9803FUTzaaL3EvJjzpdvrGC7vzcB6Jd0La9cjHhWSAPOKro
|
||||
nD9XPCbgLs10vW9g1Tc8drnZklhw6f7xrIQhWFg6VlwmVpvCQhEpX48rCCo2PH9X
|
||||
uzeJA+oqFEH3zfDp0r+q6jbAl+5TkkbBBgC2GCoI1vTYSKaWjeKKHkgzGG0QQLAz
|
||||
YXWMXvWKOME4wVPkeVxJv80RqDv0JsoOrnVoaFAzAHJMWa7UZQnjkrbVz/y8ZbV4
|
||||
oLJjQjvuOnU2PoXXs6SXbzOs1xx5zbX1UUH3Wc7/CCaUec2hemQJ5m6b1XJciyrY
|
||||
GHpMKWtXky9Mo1ruTP7ZH1nk03b4PTObKSx2gQD5AZ/ASuTeahMqMb/2PJkDkpHA
|
||||
sy8b1zOn2YTbf4K6NWVNIOkiaApmKhhX0Af6Lg8Wr2ymRTXdp/Um8f+SQLADpB/F
|
||||
xOydEN622wmihKDge9DrUFqPG/bdIiRGLXLg8efNboC6/cn/i/sheO7/YlrvcUNo
|
||||
qxDa/Bb1N/DgmtgAQ1ZP+AKjk6FKkwZRF1X/VZkZ6auscDlaPetF7razPeIJUrKN
|
||||
z/x4AD2txGYKmeYztYR577hPXBw+PPKdggRhIugb6z5Tk89C2pDEwfnByA/wcGJr
|
||||
w5avxrubosPrp0QtJpZMzouOvcD52VUiZzDfu9dqI/hpinyt5rETj5E19qxBjIZt
|
||||
X3Nq5lY2ktbyqVIo8Z8w4EUU+3XHZKqDwjyYvjxCxv5lVVnqvQrH9h3kENBMrPYQ
|
||||
4XonQHpUGG7g7pA3ylmHi+nEedr0H5qKHzyFZlRdI7CLVNoAtBSdwvmtGd2cVVXU
|
||||
EaToKNbHPXXYYPX/oVAWZYwD7PHXIRJkiEZnrFARNhLypicU7yjvejUPXcVy5HMh
|
||||
XqEbrODPp4VXfbYhVg==
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXjCCAkYCAhI0MA0GCSqGSIb3DQEBBAUAMHcxCzAJBgNVBAYTAlVTMRMwEQYD
|
||||
VQQIDApDYWxpZm9ybmlhMREwDwYDVQQHDAhTYW4gSm9zZTEXMBUGA1UECgwOUGVy
|
||||
c29uYWwsIEluYy4xEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDG15ZG9tYWlu
|
||||
LmNvbTAeFw0yMTExMjIyMjQ5MzlaFw0yMjExMjIyMjQ5MzlaMHIxCzAJBgNVBAYT
|
||||
AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQHDAhTYW4gSm9zZTEXMBUG
|
||||
A1UECgwOUGVyc29uYWwsIEluYy4xCzAJBgNVBAsMAklUMRUwEwYDVQQDDAxteWRv
|
||||
bWFpbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5fdA7wwD9
|
||||
9e5RcdLscvGB+hqJUEHuNC53SYKg5X4Sf0H4ExQUbsy8UaoWzWHhgGbCtTvUVavl
|
||||
72xsO74ei0EblopW7QknF0kaTO8Vi3mxhUAdtZFLG/o0NS9J16HdGDGojJwuqU9+
|
||||
sMQt1w0HCTMlriELnxaUFKP7M9b0uK5VODEKJ38QKNGXUDt66D7BVYeT/6hz2cXK
|
||||
QWDoHk/JadALSzW5ES8KIHfxCLnl2TcKxQhJ4CnL8qeGvc8N3VyTh2AXajaJW5RB
|
||||
8Oy4CVoYxcdmP1IapxCD+yNcmNt9XpUTD+6eM5gnvtbye+MSfwPz2MW+fWEDZXOv
|
||||
3VxhJyTRFNVTAgMBAAEwDQYJKoZIhvcNAQEEBQADggEBADYK/pn6QG7bvUL0Xnnw
|
||||
1KPf1nx36gfJE2V0bNk4uyNNeYufMKS8gPLzC+a3RigCEDc+hIZFE5BJexHd7DXA
|
||||
CWgHZJtdjM/Xlgoxbf1yfGV3DWeIZlNFSFZujBIpbm1Ug2BAeV31YRWODPZlUSEZ
|
||||
0jv8NEs8/oEz9bM4jwRdn09lo4D9hE6o8qDnrzmN2LBZP5dDIJ6g/M+mq/SJFnho
|
||||
qBrfUABZhbgk2+tkZ89OI2xpASCLo6X/vqua2iho6km3x+cz6EI9BbvVr6xOOdVK
|
||||
m6gs/Bi4MGTh35jdmvyXoyBUOd1w3yBBj86qbEt2ZHYqreRTxntQYx06598Q9Dsi
|
||||
xdg=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDajCCAlICCQD/7mxPcMTPIDANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJV
|
||||
UzETMBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UEBwwIU2FuIEpvc2UxFzAVBgNV
|
||||
BAoMDlBlcnNvbmFsLCBJbmMuMRAwDgYDVQQLDAdSb290IENBMRUwEwYDVQQDDAxt
|
||||
eWRvbWFpbi5jb20wHhcNMjExMTIyMjExODAwWhcNNDkwNDA5MjExODAwWjB3MQsw
|
||||
CQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UEBwwIU2FuIEpv
|
||||
c2UxFzAVBgNVBAoMDlBlcnNvbmFsLCBJbmMuMRAwDgYDVQQLDAdSb290IENBMRUw
|
||||
EwYDVQQDDAxteWRvbWFpbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQCkIwuNGv3ckew/o2UwaDlYgXH9bh1jap4ZCb6qpjvR3tq9nCerY6XMli0Z
|
||||
Xxg0wMHDNUr/jmVYIdQjbz0DVNz/l6ZBJHzHCEgqR40pNM3NgC5sDyuNhF3WLNvj
|
||||
WgHEwYosfb/9kFRjKUPqqtJ0ccj87OP3XrE/4epCTdJdmugroAQSpXt1ZZfwwPO4
|
||||
K27DzMD9W01EmeLcUhMfrpUnKGCfL22c0sZZm/6Khk4BExC3pSILP/NREKeUEAHw
|
||||
+rxhNqbUyD/e4/DutdtJ5zONA+GVVGYCpu1Iy0W78Jve4MD2/TFPcEzf5omiWpPz
|
||||
WjpOWayD43ur0SZnYJ5haUlZ+bSLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABqN
|
||||
/eb+mKEw2zklPZuzy5uhOc7ImG2LP/ha3oc2ntwkqZQ2LmVA/2ZNVfcNrRRngIfn
|
||||
Ir9Kual7djmKmIQvanpnSyXOKOlIiuN0VOrewgzlBZZwlFJL/AH1l7K9uZfBbV5h
|
||||
oFfaR9wc+vRGsg3nqO9+hEuk6xbp0jk8QCt26EVhEPlijxzbxTQYiNPNSLuf/kPW
|
||||
C9xtIKSWIDT4N6DtH7BtHGQKQdRJ2b4SSUF4joEmBe6jcrLBeDybmuFtKqlVJKUk
|
||||
tzBd9CPseqMML1c518KzxlSkXNxTCa7PWEnuN5atLZ+pGGjxtGcDKkrZ9Cgi09G8
|
||||
MzB8b4C/goypyhBNlyI=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOSZVf8dLj1xLw
|
||||
efqjbogbAwhwRXd3tmEfQY1zHyudJF3XR1T0Xp26BKNvAYUxxZRDNg16M3prPRZv
|
||||
wkhDJdE9NaN+BpZPJUavRsZOfGDq/CHN8j/2PPKrn3G/b065JjV3GZjfV/Sln047
|
||||
DeZptaSyOg7ZN7F8qjGqxEcnw+szV/wTzhnjGjZMlcbOm4jFGQAn6xUOooQCGsoB
|
||||
9FgxKB0nvNG3xVe/2eCNfbS4DabT3Y1wfQqZ62hOa5ZS0rwT+pw3tQs3zFFY1Sfi
|
||||
G7qYbqZrKTheWIZGojVVm6mqH4yA2ofOe5N3RsBitCwU/D0dpnaG9Wcl98nmXueM
|
||||
B6Rk04v7AgMBAAECggEAYnxIKjrFz/JkJ5MmiszM5HV698r9YB0aqHnFIHPoykIL
|
||||
uiCjiumantDrFsCkosixULwvI/BRwbxstTpyrheU9psT6P1CONICVPvV8ylgJAYU
|
||||
l+ofn56cEXKxVuICSWFLDH7pM1479g+IJJQAchbKQpqxAGTuMu3SpvJolfuj5srt
|
||||
bM7/RYhJFLwDuvHNA3ivlogMneItP03+C25aaxstM+lBuBf68+n78zMgSvt6J/6Y
|
||||
G2TOMKnxveMlG2qu9l2lAw/2i8daG/qre08nTH7wpRx0gZLZqNpe45exkrzticzF
|
||||
FgWYjG2K2brX21jqHroFgMhdXF7zhhRgLoIeC0BrIQKBgQDCfGfWrJESKBbVai5u
|
||||
7wqD9nlzjv6N6FXfTDOPXO1vz5frdvtLVWbs0SMPy+NglkaZK0iqHvb9mf2of8eC
|
||||
0D5cmewjn7WCDBQMypIMYgT912ak/BBVuGXcxb6UgD+xARfSARo2C8NG1hfprw1W
|
||||
ad14CjS5xhFMs44HpVYhI7iPYwKBgQC7SqVG/b37vZ7CINemdvoMujLvvYXDJJM8
|
||||
N21LqNJfVXdukdH3T0xuLnh9Z/wPHjJDMF/9+1foxSEPHijtyz5P19EilNEC/3qw
|
||||
fI19+VZoY0mdhPtXSGzy+rbTE2v71QgwFLizSos14Gr+eNiIjF7FYccK05++K/zk
|
||||
cd8ZA3bwiQKBgQCl+HTFBs9mpz+VMOAfW2+l3hkXPNiPUc62mNkHZ05ZNNd44jjh
|
||||
uSf0wSUiveR08MmevQlt5K7zDQ8jVKh2QjB15gVXAVxsdtJFeDnax2trFP9LnLBz
|
||||
9sE2/qn9INU5wK0LUlWD+dXUBbCyg+jl7cJKRqtoPldVFYYHkFlIPqup8QKBgHXv
|
||||
hyuw1FUVDkdHzwOvn70r8q8sNHKxMVWVwWkHIZGOi+pAQGrusD4hXRX6yKnsZdIR
|
||||
QCD6iFy25R5T64nxlYdJaxPPid3NakB/7ckJnPOWseBSwMIxhQlr/nvjmve1Kba9
|
||||
FaEwq4B9lGIxToiNe4/nBiM3JzvlDxX67nUdzWOhAoGAdFvriyvjshSJ4JHgIY9K
|
||||
37BVB0VKMcFV2P8fLVWO5oyRtE1bJhU4QVpQmauABU4RGSojJ3NPIVH1wxmJeYtj
|
||||
Q3b7EZaqI6ovna2eK2qtUx4WwxhRaXTT8xueBI2lgL6sBSTGG+K69ZOzGQzG/Mfr
|
||||
RXKInnLInFD9JD94VqmMozo=
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.apache.cassandra.security.KubernetesSecretsPEMSslContextFactory.DEFAULT_PRIVATE_KEY_ENV_VAR_NAME;
|
||||
import static org.apache.cassandra.security.KubernetesSecretsPEMSslContextFactory.DEFAULT_PRIVATE_KEY_PASSWORD_ENV_VAR_NAME;
|
||||
import static org.apache.cassandra.security.KubernetesSecretsPEMSslContextFactory.PEMConfigKey.PRIVATE_KEY_PASSWORD_ENV_VAR;
|
||||
import static org.apache.cassandra.security.KubernetesSecretsPEMSslContextFactory.PEMConfigKey.TRUSTED_CERTIFICATE_ENV_VAR;
|
||||
import static org.apache.cassandra.security.KubernetesSecretsSslContextFactory.ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH;
|
||||
import static org.apache.cassandra.security.KubernetesSecretsSslContextFactory.ConfigKeys.TRUSTSTORE_UPDATED_TIMESTAMP_PATH;
|
||||
|
||||
public class KubernetesSecretsPEMSslContextFactoryTest
|
||||
{
|
||||
private static final Logger logger = LoggerFactory.getLogger(KubernetesSecretsPEMSslContextFactoryTest.class);
|
||||
|
||||
private static final String ENCRYPTED_PRIVATE_KEY_FILEPATH = "build/test/conf/cassandra_encrypted_private_key.pem";
|
||||
private static final String ENCRYPTED_PRIVATE_KEY_WITH_MULTIPLE_CERTS_IN_CERTCHAIN_FILEPATH = "build/test/conf" +
|
||||
"/cassandra_encrypted_private_key_multiplecerts.pem";
|
||||
private static final String UNENCRYPTED_PRIVATE_KEY_FILEPATH = "build/test/conf/cassandra_unencrypted_private_key.pem";
|
||||
private static final String TRUSTED_CERTIFICATES_FILEPATH = "build/test/conf/cassandra_trusted_certificates.pem";
|
||||
private final static String TRUSTSTORE_UPDATED_TIMESTAMP_FILEPATH = "build/test/conf/cassandra_truststore_last_updatedtime";
|
||||
private final static String KEYSTORE_UPDATED_TIMESTAMP_FILEPATH = "build/test/conf/cassandra_keystore_last_updatedtime";
|
||||
|
||||
private static String private_key;
|
||||
private static String unencrypted_private_key;
|
||||
private static String trusted_certificates;
|
||||
|
||||
private final Map<String, Object> commonConfig = new HashMap<>();
|
||||
|
||||
@BeforeClass
|
||||
public static void prepare()
|
||||
{
|
||||
deleteFileIfExists(TRUSTSTORE_UPDATED_TIMESTAMP_FILEPATH);
|
||||
deleteFileIfExists(KEYSTORE_UPDATED_TIMESTAMP_FILEPATH);
|
||||
private_key = readFile(ENCRYPTED_PRIVATE_KEY_FILEPATH);
|
||||
unencrypted_private_key = readFile(UNENCRYPTED_PRIVATE_KEY_FILEPATH);
|
||||
trusted_certificates = readFile(TRUSTED_CERTIFICATES_FILEPATH);
|
||||
}
|
||||
|
||||
private static void deleteFileIfExists(String filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
logger.info("Deleting the file {} to prepare for the tests", new File(filePath).getAbsolutePath());
|
||||
File file = new File(filePath);
|
||||
if (file.exists())
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.warn("File {} could not be deleted.", filePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String readFile(String file)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new String(Files.readAllBytes(Paths.get(file)));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.error("Unable to read the file {}. Without this tests in this file would fail.", file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setup()
|
||||
{
|
||||
commonConfig.put(TRUSTED_CERTIFICATE_ENV_VAR,
|
||||
"MY_TRUSTED_CERTIFICATES");
|
||||
commonConfig.put("MY_TRUSTED_CERTIFICATES", trusted_certificates);
|
||||
commonConfig.put(TRUSTSTORE_UPDATED_TIMESTAMP_PATH, TRUSTSTORE_UPDATED_TIMESTAMP_FILEPATH);
|
||||
/*
|
||||
* In order to test with real 'env' variables comment out this line and set appropriate env variable. This is
|
||||
* done to avoid having a dependency on env in the unit test.
|
||||
*/
|
||||
commonConfig.put("require_client_auth", Boolean.FALSE);
|
||||
commonConfig.put("cipher_suites", Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA"));
|
||||
}
|
||||
|
||||
private void addKeystoreOptions(Map<String, Object> config)
|
||||
{
|
||||
config.put(DEFAULT_PRIVATE_KEY_ENV_VAR_NAME, private_key);
|
||||
config.put(PRIVATE_KEY_PASSWORD_ENV_VAR, "MY_KEY_PASSWORD");
|
||||
config.put(KEYSTORE_UPDATED_TIMESTAMP_PATH, KEYSTORE_UPDATED_TIMESTAMP_FILEPATH);
|
||||
/*
|
||||
* In order to test with real 'env' variables comment out this line and set appropriate env variable. This is
|
||||
* done to avoid having a dependency on env in the unit test.
|
||||
*/
|
||||
config.put("MY_KEY_PASSWORD", "cassandra");
|
||||
}
|
||||
|
||||
private void addUnencryptedKeystoreOptions(Map<String, Object> config)
|
||||
{
|
||||
config.put(DEFAULT_PRIVATE_KEY_ENV_VAR_NAME, unencrypted_private_key);
|
||||
config.put(KEYSTORE_UPDATED_TIMESTAMP_PATH, KEYSTORE_UPDATED_TIMESTAMP_FILEPATH);
|
||||
config.remove(DEFAULT_PRIVATE_KEY_PASSWORD_ENV_VAR_NAME);
|
||||
config.remove(PRIVATE_KEY_PASSWORD_ENV_VAR);
|
||||
}
|
||||
|
||||
@Test(expected = SSLException.class)
|
||||
public void buildTrustManagerFactoryWithInvalidTrustedCertificates() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
config.put("MY_TRUSTED_CERTIFICATES", trusted_certificates.replaceAll("\\s", String.valueOf(System.nanoTime())));
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory =
|
||||
new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
kubernetesSecretsSslContextFactory.checkedExpiry = false;
|
||||
kubernetesSecretsSslContextFactory.buildTrustManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildTrustManagerFactoryHappyPath() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
kubernetesSecretsSslContextFactory.checkedExpiry = false;
|
||||
TrustManagerFactory trustManagerFactory = kubernetesSecretsSslContextFactory.buildTrustManagerFactory();
|
||||
Assert.assertNotNull(trustManagerFactory);
|
||||
}
|
||||
|
||||
@Test(expected = SSLException.class)
|
||||
public void buildKeyManagerFactoryWithInvalidPrivateKey() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
config.put(DEFAULT_PRIVATE_KEY_ENV_VAR_NAME, private_key.replaceAll("\\s", String.valueOf(System.nanoTime())));
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory =
|
||||
new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
kubernetesSecretsSslContextFactory.checkedExpiry = false;
|
||||
kubernetesSecretsSslContextFactory.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void buildKeyManagerFactoryWithBadPassword() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
config.put(DEFAULT_PRIVATE_KEY_ENV_VAR_NAME, private_key);
|
||||
config.put(DEFAULT_PRIVATE_KEY_PASSWORD_ENV_VAR_NAME, "HomeOfBadPasswords");
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory =
|
||||
new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
kubernetesSecretsSslContextFactory.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildKeyManagerFactoryHappyPath() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory1 = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
// Make sure the exiry check didn't happen so far for the private key
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory1.checkedExpiry);
|
||||
|
||||
addKeystoreOptions(config);
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory2 = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
// Trigger the private key loading. That will also check for expired private key
|
||||
kubernetesSecretsSslContextFactory2.buildKeyManagerFactory();
|
||||
// Now we should have checked the private key's expiry
|
||||
Assert.assertTrue(kubernetesSecretsSslContextFactory2.checkedExpiry);
|
||||
|
||||
// Make sure that new factory object preforms the fresh private key expiry check
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory3 =
|
||||
new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory3.checkedExpiry);
|
||||
kubernetesSecretsSslContextFactory3.buildKeyManagerFactory();
|
||||
Assert.assertTrue(kubernetesSecretsSslContextFactory3.checkedExpiry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildKeyManagerFactoryWithMultipleCertsInCertChain() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addKeystoreOptions(config);
|
||||
config.put(DEFAULT_PRIVATE_KEY_ENV_VAR_NAME, readFile(ENCRYPTED_PRIVATE_KEY_WITH_MULTIPLE_CERTS_IN_CERTCHAIN_FILEPATH));
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory2 = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
// Trigger the private key loading. That will also check for expired private key
|
||||
kubernetesSecretsSslContextFactory2.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildKeyManagerFactoryHappyPathForUnencryptedKey() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory1 = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
// Make sure the exiry check didn't happen so far for the private key
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory1.checkedExpiry);
|
||||
|
||||
addUnencryptedKeystoreOptions(config);
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory2 = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
// Trigger the private key loading. That will also check for expired private key
|
||||
kubernetesSecretsSslContextFactory2.buildKeyManagerFactory();
|
||||
// Now we should have checked the private key's expiry
|
||||
Assert.assertTrue(kubernetesSecretsSslContextFactory2.checkedExpiry);
|
||||
|
||||
// Make sure that new factory object preforms the fresh private key expiry check
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory3 =
|
||||
new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory3.checkedExpiry);
|
||||
kubernetesSecretsSslContextFactory3.buildKeyManagerFactory();
|
||||
Assert.assertTrue(kubernetesSecretsSslContextFactory3.checkedExpiry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkTruststoreUpdateReloading() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addKeystoreOptions(config);
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
kubernetesSecretsSslContextFactory.checkedExpiry = false;
|
||||
TrustManagerFactory trustManagerFactory = kubernetesSecretsSslContextFactory.buildTrustManagerFactory();
|
||||
Assert.assertNotNull(trustManagerFactory);
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory.shouldReload());
|
||||
|
||||
updateTimestampFile(config, TRUSTSTORE_UPDATED_TIMESTAMP_PATH);
|
||||
Assert.assertTrue(kubernetesSecretsSslContextFactory.shouldReload());
|
||||
|
||||
config.remove(TRUSTSTORE_UPDATED_TIMESTAMP_PATH);
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory.shouldReload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkKeystoreUpdateReloading() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addKeystoreOptions(config);
|
||||
|
||||
KubernetesSecretsPEMSslContextFactory kubernetesSecretsSslContextFactory = new KubernetesSecretsPEMSslContextFactoryForTestOnly(config);
|
||||
kubernetesSecretsSslContextFactory.checkedExpiry = false;
|
||||
KeyManagerFactory keyManagerFactory = kubernetesSecretsSslContextFactory.buildKeyManagerFactory();
|
||||
Assert.assertNotNull(keyManagerFactory);
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory.shouldReload());
|
||||
|
||||
updateTimestampFile(config, KEYSTORE_UPDATED_TIMESTAMP_PATH);
|
||||
Assert.assertTrue(kubernetesSecretsSslContextFactory.shouldReload());
|
||||
|
||||
config.remove(KEYSTORE_UPDATED_TIMESTAMP_PATH);
|
||||
Assert.assertFalse(kubernetesSecretsSslContextFactory.shouldReload());
|
||||
}
|
||||
|
||||
private void updateTimestampFile(Map<String, Object> config, String filePathKey)
|
||||
{
|
||||
String filePath = config.containsKey(filePathKey) ? config.get(filePathKey).toString() : null;
|
||||
try (OutputStream os = Files.newOutputStream(Paths.get(filePath)))
|
||||
{
|
||||
String timestamp = String.valueOf(System.nanoTime());
|
||||
os.write(timestamp.getBytes());
|
||||
logger.info("Successfully wrote to file {}", filePath);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.warn("Failed to write to filePath {} from the mounted volume", filePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class KubernetesSecretsPEMSslContextFactoryForTestOnly extends KubernetesSecretsPEMSslContextFactory
|
||||
{
|
||||
|
||||
public KubernetesSecretsPEMSslContextFactoryForTestOnly()
|
||||
{
|
||||
}
|
||||
|
||||
public KubernetesSecretsPEMSslContextFactoryForTestOnly(Map<String, Object> config)
|
||||
{
|
||||
super(config);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is overriden to first give priority to the input map configuration since we should not be setting env
|
||||
* variables from the unit tests. However, if the input map configuration doesn't have the value for the
|
||||
* given key then fallback to loading from the real environment variables.
|
||||
*/
|
||||
@Override
|
||||
String getValueFromEnv(String envVarName, String defaultValue)
|
||||
{
|
||||
String envVarValue = parameters.get(envVarName) != null ? parameters.get(envVarName).toString() : null;
|
||||
if (StringUtils.isEmpty(envVarValue))
|
||||
{
|
||||
logger.info("Configuration doesn't have env variable {}. Will use parent's implementation", envVarName);
|
||||
return super.getValueFromEnv(envVarName, defaultValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("Configuration has environment variable {} with value {}. Will use that.",
|
||||
envVarName, envVarValue);
|
||||
return envVarValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -38,6 +38,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.config.EncryptionOptions;
|
||||
import org.apache.cassandra.io.util.PathUtils;
|
||||
|
||||
import static org.apache.cassandra.security.KubernetesSecretsSslContextFactory.ConfigKeys.KEYSTORE_PASSWORD_ENV_VAR;
|
||||
import static org.apache.cassandra.security.KubernetesSecretsSslContextFactory.ConfigKeys.KEYSTORE_UPDATED_TIMESTAMP_PATH;
|
||||
|
|
@ -49,45 +50,9 @@ public class KubernetesSecretsSslContextFactoryTest
|
|||
private static final Logger logger = LoggerFactory.getLogger(KubernetesSecretsSslContextFactoryTest.class);
|
||||
private static final String TRUSTSTORE_PATH = EncryptionOptions.ConfigKey.TRUSTSTORE.toString();
|
||||
private static final String KEYSTORE_PATH = EncryptionOptions.ConfigKey.KEYSTORE.toString();
|
||||
|
||||
private Map<String, Object> commonConfig = new HashMap<>();
|
||||
private final static String truststoreUpdatedTimestampFilepath = "build/test/conf/cassandra_truststore_last_updatedtime";
|
||||
private final static String keystoreUpdatedTimestampFilepath = "build/test/conf/cassandra_keystore_last_updatedtime";
|
||||
|
||||
private static class KubernetesSecretsSslContextFactoryForTestOnly extends KubernetesSecretsSslContextFactory
|
||||
{
|
||||
|
||||
public KubernetesSecretsSslContextFactoryForTestOnly()
|
||||
{
|
||||
}
|
||||
|
||||
public KubernetesSecretsSslContextFactoryForTestOnly(Map<String, Object> config)
|
||||
{
|
||||
super(config);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is overriden to first give priority to the input map configuration since we should not be setting env
|
||||
* variables from the unit tests. However, if the input map configuration doesn't have the value for the
|
||||
* given key then fallback to loading from the real environment variables.
|
||||
*/
|
||||
@Override
|
||||
String getValueFromEnv(String envVarName, String defaultValue)
|
||||
{
|
||||
String envVarValue = parameters.get(envVarName) != null ? parameters.get(envVarName).toString() : null;
|
||||
if (StringUtils.isEmpty(envVarValue))
|
||||
{
|
||||
logger.info("Configuration doesn't have env variable {}. Will use parent's implementation", envVarName);
|
||||
return super.getValueFromEnv(envVarName, defaultValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("Configuration has env variable {} with value {}. Will use that.",
|
||||
envVarName, envVarValue);
|
||||
return envVarValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
private final Map<String, Object> commonConfig = new HashMap<>();
|
||||
|
||||
@BeforeClass
|
||||
public static void prepare()
|
||||
|
|
@ -96,20 +61,13 @@ public class KubernetesSecretsSslContextFactoryTest
|
|||
deleteFileIfExists(keystoreUpdatedTimestampFilepath);
|
||||
}
|
||||
|
||||
private static void deleteFileIfExists(String filePath)
|
||||
private static void deleteFileIfExists(String file)
|
||||
{
|
||||
try
|
||||
Path filePath = Paths.get(file);
|
||||
boolean deleted = PathUtils.tryDelete(filePath);
|
||||
if (!deleted)
|
||||
{
|
||||
logger.info("Deleting the file {} to prepare for the tests", new File(filePath).getAbsolutePath());
|
||||
File file = new File(filePath);
|
||||
if (file.exists())
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.warn("File {} could not be deleted.", filePath, e);
|
||||
logger.warn("File {} could not be deleted.", filePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -293,4 +251,39 @@ public class KubernetesSecretsSslContextFactoryTest
|
|||
logger.warn("Failed to write to filePath {} from the mounted volume", filePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class KubernetesSecretsSslContextFactoryForTestOnly extends KubernetesSecretsSslContextFactory
|
||||
{
|
||||
|
||||
public KubernetesSecretsSslContextFactoryForTestOnly()
|
||||
{
|
||||
}
|
||||
|
||||
public KubernetesSecretsSslContextFactoryForTestOnly(Map<String, Object> config)
|
||||
{
|
||||
super(config);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is overriden to first give priority to the input map configuration since we should not be setting env
|
||||
* variables from the unit tests. However, if the input map configuration doesn't have the value for the
|
||||
* given key then fallback to loading from the real environment variables.
|
||||
*/
|
||||
@Override
|
||||
String getValueFromEnv(String envVarName, String defaultValue)
|
||||
{
|
||||
String envVarValue = parameters.get(envVarName) != null ? parameters.get(envVarName).toString() : null;
|
||||
if (StringUtils.isEmpty(envVarValue))
|
||||
{
|
||||
logger.info("Configuration doesn't have env variable {}. Will use parent's implementation", envVarName);
|
||||
return super.getValueFromEnv(envVarName, defaultValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.info("Configuration has env variable {} with value {}. Will use that.",
|
||||
envVarName, envVarValue);
|
||||
return envVarValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.io.InputStream;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
|
@ -37,6 +38,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.io.util.File;
|
||||
import org.apache.cassandra.utils.Clock;
|
||||
|
||||
/**
|
||||
* Abstract implementation for {@link ISslContextFactory} using file based, standard keystore format with the ability
|
||||
|
|
@ -124,26 +126,19 @@ abstract public class FileBasedSslContextFactory extends AbstractSslContextFacto
|
|||
* @return KeyManagerFactory built from the file based keystore.
|
||||
* @throws SSLException if any issues encountered during the build process
|
||||
*/
|
||||
@Override
|
||||
protected KeyManagerFactory buildKeyManagerFactory() throws SSLException
|
||||
{
|
||||
|
||||
try (InputStream ksf = Files.newInputStream(Paths.get(keystore)))
|
||||
{
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
|
||||
algorithm == null ? KeyManagerFactory.getDefaultAlgorithm() : algorithm);
|
||||
final String algorithm = this.algorithm == null ? KeyManagerFactory.getDefaultAlgorithm() : this.algorithm;
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
|
||||
KeyStore ks = KeyStore.getInstance(store_type);
|
||||
ks.load(ksf, keystore_password.toCharArray());
|
||||
if (!checkedExpiry)
|
||||
{
|
||||
for (Enumeration<String> aliases = ks.aliases(); aliases.hasMoreElements(); )
|
||||
{
|
||||
String alias = aliases.nextElement();
|
||||
if (ks.getCertificate(alias).getType().equals("X.509"))
|
||||
{
|
||||
Date expires = ((X509Certificate) ks.getCertificate(alias)).getNotAfter();
|
||||
if (expires.before(new Date()))
|
||||
logger.warn("Certificate for {} expired on {}", alias, expires);
|
||||
}
|
||||
}
|
||||
checkExpiredCerts(ks);
|
||||
checkedExpiry = true;
|
||||
}
|
||||
kmf.init(ks, keystore_password.toCharArray());
|
||||
|
|
@ -161,12 +156,13 @@ abstract public class FileBasedSslContextFactory extends AbstractSslContextFacto
|
|||
* @return TrustManagerFactory from the file based truststore
|
||||
* @throws SSLException if any issues encountered during the build process
|
||||
*/
|
||||
@Override
|
||||
protected TrustManagerFactory buildTrustManagerFactory() throws SSLException
|
||||
{
|
||||
try (InputStream tsf = Files.newInputStream(Paths.get(truststore)))
|
||||
{
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
|
||||
algorithm == null ? TrustManagerFactory.getDefaultAlgorithm() : algorithm);
|
||||
final String algorithm = this.algorithm == null ? TrustManagerFactory.getDefaultAlgorithm() : this.algorithm;
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
|
||||
KeyStore ts = KeyStore.getInstance(store_type);
|
||||
ts.load(tsf, truststore_password.toCharArray());
|
||||
tmf.init(ts);
|
||||
|
|
@ -178,10 +174,30 @@ abstract public class FileBasedSslContextFactory extends AbstractSslContextFacto
|
|||
}
|
||||
}
|
||||
|
||||
protected boolean checkExpiredCerts(KeyStore ks) throws KeyStoreException
|
||||
{
|
||||
boolean hasExpiredCerts = false;
|
||||
final Date now = new Date(Clock.Global.currentTimeMillis());
|
||||
for (Enumeration<String> aliases = ks.aliases(); aliases.hasMoreElements(); )
|
||||
{
|
||||
String alias = aliases.nextElement();
|
||||
if (ks.getCertificate(alias).getType().equals("X.509"))
|
||||
{
|
||||
Date expires = ((X509Certificate) ks.getCertificate(alias)).getNotAfter();
|
||||
if (expires.before(now))
|
||||
{
|
||||
hasExpiredCerts = true;
|
||||
logger.warn("Certificate for {} expired on {}", alias, expires);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasExpiredCerts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for hot reloading SSL Contexts
|
||||
*/
|
||||
private static class HotReloadableFile
|
||||
protected static class HotReloadableFile
|
||||
{
|
||||
private final File file;
|
||||
private volatile long lastModTime;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.io.util.File;
|
||||
|
||||
|
||||
/**
|
||||
* SslContextFactory for the <a href="">PEM standard</a> encoded PKCS#8 private keys and X509 certificates/public-keys.
|
||||
* It parses the key material based on the standard defined in the <a href="https://datatracker.ietf.org/doc/html/rfc7468">RFC 7468</a>.
|
||||
* It creates <a href="https://datatracker.ietf.org/doc/html/rfc5208">PKCS# 8</a> based private key and X509 certificate(s)
|
||||
* for the public key to build the required keystore and the truststore managers that are used for the SSL context creation.
|
||||
* Internally it builds Java {@link KeyStore} with <a href="https://datatracker.ietf.org/doc/html/rfc7292">PKCS# 12</a> <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#keystore-types">store type</a>
|
||||
* to be used for keystore and the truststore managers.
|
||||
* <p>
|
||||
* This factory also supports 'hot reloading' of the key material, the same way as defined by {@link FileBasedSslContextFactory},
|
||||
* <b>if it is file based</b>. This factory ignores the existing 'store_type' configuration used for other file based store
|
||||
* types like JKS.
|
||||
* <p>
|
||||
* You can configure this factory with either inline PEM data or with the files having the required PEM data as shown
|
||||
* below,
|
||||
*
|
||||
* <b>Configuration: PEM keys/certs defined inline (mind the spaces in the YAML!)</b>
|
||||
* <pre>
|
||||
* client/server_encryption_options:
|
||||
* ssl_context_factory:
|
||||
* class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
|
||||
* parameters:
|
||||
* private_key: |
|
||||
* -----BEGIN ENCRYPTED PRIVATE KEY----- OR -----BEGIN PRIVATE KEY-----
|
||||
* <your base64 encoded private key>
|
||||
* -----END ENCRYPTED PRIVATE KEY----- OR -----END PRIVATE KEY-----
|
||||
* -----BEGIN CERTIFICATE-----
|
||||
* <your base64 encoded certificate chain>
|
||||
* -----END CERTIFICATE-----
|
||||
*
|
||||
* private_key_password: "<your password if the private key is encrypted with a password>"
|
||||
*
|
||||
* trusted_certificates: |
|
||||
* -----BEGIN CERTIFICATE-----
|
||||
* <your base64 encoded certificate>
|
||||
* -----END CERTIFICATE-----
|
||||
* </pre>
|
||||
*
|
||||
* <b>Configuration: PEM keys/certs defined in files</b>
|
||||
* <pre>
|
||||
* client/server_encryption_options:
|
||||
* ssl_context_factory:
|
||||
* class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
|
||||
* keystore: <file path to the keystore file in the PEM format with the private key and the certificate chain>
|
||||
* keystore_password: "<your password if the private key is encrypted with a password>"
|
||||
* truststore: <file path to the truststore file in the PEM format>
|
||||
* </pre>
|
||||
*/
|
||||
public final class PEMBasedSslContextFactory extends FileBasedSslContextFactory
|
||||
{
|
||||
public static final String DEFAULT_TARGET_STORETYPE = "PKCS12";
|
||||
private static final Logger logger = LoggerFactory.getLogger(PEMBasedSslContextFactory.class);
|
||||
private String pemEncodedKey;
|
||||
private String keyPassword;
|
||||
private String pemEncodedCertificates;
|
||||
private boolean maybeFileBasedPrivateKey;
|
||||
private boolean maybeFileBasedTrustedCertificates;
|
||||
|
||||
public PEMBasedSslContextFactory()
|
||||
{
|
||||
}
|
||||
|
||||
public PEMBasedSslContextFactory(Map<String, Object> parameters)
|
||||
{
|
||||
super(parameters);
|
||||
pemEncodedKey = getString(ConfigKey.ENCODED_KEY.getKeyName());
|
||||
keyPassword = getString(ConfigKey.KEY_PASSWORD.getKeyName());
|
||||
if (StringUtils.isEmpty(keyPassword))
|
||||
{
|
||||
keyPassword = keystore_password;
|
||||
}
|
||||
else if (!StringUtils.isEmpty(keystore_password) && !keyPassword.equals(keystore_password))
|
||||
{
|
||||
throw new IllegalArgumentException("'keystore_password' and 'key_password' both configurations are given and the " +
|
||||
"values do not match");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("'keystore_password' and 'key_password' both are configured but since the values match it's " +
|
||||
"okay. Ideally you should only specify one of them.");
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(truststore_password))
|
||||
{
|
||||
logger.warn("PEM based truststore should not be using password. Ignoring the given value in " +
|
||||
"'truststore_password' configuration.");
|
||||
}
|
||||
|
||||
pemEncodedCertificates = getString(ConfigKey.ENCODED_CERTIFICATES.getKeyName());
|
||||
|
||||
maybeFileBasedPrivateKey = StringUtils.isEmpty(pemEncodedKey);
|
||||
maybeFileBasedTrustedCertificates = StringUtils.isEmpty(pemEncodedCertificates);
|
||||
|
||||
enforceSinglePrivateKeySource();
|
||||
enforceSingleTurstedCertificatesSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides if this factory has a keystore defined - key material specified in files or inline to the configuration.
|
||||
*
|
||||
* @return {@code true} if there is a keystore defined; {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean hasKeystore()
|
||||
{
|
||||
return maybeFileBasedPrivateKey ? keystoreFileExists() :
|
||||
!StringUtils.isEmpty(pemEncodedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the keystore file exists.
|
||||
*
|
||||
* @return {@code true} if keystore file exists; {@code false} otherwise
|
||||
*/
|
||||
private boolean keystoreFileExists()
|
||||
{
|
||||
return keystore != null && new File(keystore).exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides if this factory has a truststore defined - key material specified in files or inline to the
|
||||
* configuration.
|
||||
*
|
||||
* @return {@code true} if there is a truststore defined; {@code false} otherwise
|
||||
*/
|
||||
private boolean hasTruststore()
|
||||
{
|
||||
return maybeFileBasedTrustedCertificates ? truststoreFileExists() :
|
||||
!StringUtils.isEmpty(pemEncodedCertificates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the truststore file exists.
|
||||
*
|
||||
* @return {@code true} if truststore file exists; {@code false} otherwise
|
||||
*/
|
||||
private boolean truststoreFileExists()
|
||||
{
|
||||
return truststore != null && new File(truststore).exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* This enables 'hot' reloading of the key/trust stores based on the last updated timestamps if they are file based.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void initHotReloading()
|
||||
{
|
||||
List<HotReloadableFile> fileList = new ArrayList<>();
|
||||
if (maybeFileBasedPrivateKey && hasKeystore())
|
||||
{
|
||||
fileList.add(new HotReloadableFile(keystore));
|
||||
}
|
||||
if (maybeFileBasedTrustedCertificates && hasTruststore())
|
||||
{
|
||||
fileList.add(new HotReloadableFile(truststore));
|
||||
}
|
||||
if (!fileList.isEmpty())
|
||||
{
|
||||
hotReloadableFiles = fileList;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds required KeyManagerFactory from the PEM based keystore. It also checks for the PrivateKey's certificate's
|
||||
* expiry and logs {@code warning} for each expired PrivateKey's certitificate.
|
||||
*
|
||||
* @return KeyManagerFactory built from the PEM based keystore.
|
||||
* @throws SSLException if any issues encountered during the build process
|
||||
*/
|
||||
@Override
|
||||
protected KeyManagerFactory buildKeyManagerFactory() throws SSLException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (hasKeystore())
|
||||
{
|
||||
if (maybeFileBasedPrivateKey)
|
||||
{
|
||||
pemEncodedKey = readPEMFile(keystore); // read PEM from the file
|
||||
}
|
||||
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
|
||||
algorithm == null ? KeyManagerFactory.getDefaultAlgorithm() : algorithm);
|
||||
KeyStore ks = buildKeyStore();
|
||||
if (!checkedExpiry)
|
||||
{
|
||||
checkExpiredCerts(ks);
|
||||
checkedExpiry = true;
|
||||
}
|
||||
kmf.init(ks, keyPassword != null ? keyPassword.toCharArray() : null);
|
||||
return kmf;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new SSLException("Must provide keystore or private_key in configuration for PEMBasedSSlContextFactory");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SSLException("Failed to build key manager store for secure connections", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds TrustManagerFactory from the PEM based truststore.
|
||||
*
|
||||
* @return TrustManagerFactory from the PEM based truststore
|
||||
* @throws SSLException if any issues encountered during the build process
|
||||
*/
|
||||
@Override
|
||||
protected TrustManagerFactory buildTrustManagerFactory() throws SSLException
|
||||
{
|
||||
try
|
||||
{
|
||||
if (hasTruststore())
|
||||
{
|
||||
if (maybeFileBasedTrustedCertificates)
|
||||
{
|
||||
pemEncodedCertificates = readPEMFile(truststore); // read PEM from the file
|
||||
}
|
||||
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
|
||||
algorithm == null ? TrustManagerFactory.getDefaultAlgorithm() : algorithm);
|
||||
KeyStore ts = buildTrustStore();
|
||||
tmf.init(ts);
|
||||
return tmf;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new SSLException("Must provide truststore or trusted_certificates in configuration for " +
|
||||
"PEMBasedSSlContextFactory");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new SSLException("Failed to build trust manager store for secure connections", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String readPEMFile(String file) throws IOException
|
||||
{
|
||||
return new String(Files.readAllBytes(Paths.get(file)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds KeyStore object given the {@link #DEFAULT_TARGET_STORETYPE} out of the PEM formatted private key material.
|
||||
* It uses {@code cassandra-ssl-keystore} as the alias for the created key-entry.
|
||||
*/
|
||||
private KeyStore buildKeyStore() throws GeneralSecurityException, IOException
|
||||
{
|
||||
char[] keyPasswordArray = keyPassword != null ? keyPassword.toCharArray() : null;
|
||||
PrivateKey privateKey = PEMReader.extractPrivateKey(pemEncodedKey, keyPassword);
|
||||
Certificate[] certChainArray = PEMReader.extractCertificates(pemEncodedKey);
|
||||
if (certChainArray == null || certChainArray.length == 0)
|
||||
{
|
||||
throw new SSLException("Could not read any certificates for the certChain for the private key");
|
||||
}
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance(DEFAULT_TARGET_STORETYPE);
|
||||
keyStore.load(null, null);
|
||||
keyStore.setKeyEntry("cassandra-ssl-keystore", privateKey, keyPasswordArray, certChainArray);
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds KeyStore object given the {@link #DEFAULT_TARGET_STORETYPE} out of the PEM formatted certificates/public-key
|
||||
* material.
|
||||
* <p>
|
||||
* It uses {@code cassandra-ssl-trusted-cert-<numeric-id>} as the alias for the created certificate-entry.
|
||||
*/
|
||||
private KeyStore buildTrustStore() throws GeneralSecurityException, IOException
|
||||
{
|
||||
Certificate[] certChainArray = PEMReader.extractCertificates(pemEncodedCertificates);
|
||||
if (certChainArray == null || certChainArray.length == 0)
|
||||
{
|
||||
throw new SSLException("Could not read any certificates from the given PEM");
|
||||
}
|
||||
|
||||
KeyStore keyStore = KeyStore.getInstance(DEFAULT_TARGET_STORETYPE);
|
||||
keyStore.load(null, null);
|
||||
for (int i = 0; i < certChainArray.length; i++)
|
||||
{
|
||||
keyStore.setCertificateEntry("cassandra-ssl-trusted-cert-" + (i + 1), certChainArray[i]);
|
||||
}
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces that the configuration specified a sole source of loading private keys - either {@code keystore} (the
|
||||
* actual file must exist) or {@code private_key}, not both.
|
||||
*/
|
||||
private void enforceSinglePrivateKeySource()
|
||||
{
|
||||
if (keystoreFileExists() && !StringUtils.isEmpty(pemEncodedKey))
|
||||
{
|
||||
throw new IllegalArgumentException("Configuration must specify value for either keystore or private_key, " +
|
||||
"not both for PEMBasedSSlContextFactory");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces that the configuration specified a sole source of loading trusted certificates - either {@code
|
||||
* truststore} (actual file must exist) or {@code trusted_certificates}, not both.
|
||||
*/
|
||||
private void enforceSingleTurstedCertificatesSource()
|
||||
{
|
||||
if (truststoreFileExists() && !StringUtils.isEmpty(pemEncodedCertificates))
|
||||
{
|
||||
throw new IllegalArgumentException("Configuration must specify value for either truststore or " +
|
||||
"trusted_certificates, not both for PEMBasedSSlContextFactory");
|
||||
}
|
||||
}
|
||||
|
||||
public enum ConfigKey
|
||||
{
|
||||
ENCODED_KEY("private_key"),
|
||||
KEY_PASSWORD("private_key_password"),
|
||||
ENCODED_CERTIFICATES("trusted_certificates");
|
||||
|
||||
final String keyName;
|
||||
|
||||
ConfigKey(String keyName)
|
||||
{
|
||||
this.keyName = keyName;
|
||||
}
|
||||
|
||||
String getKeyName()
|
||||
{
|
||||
return keyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.AlgorithmParameters;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.EncryptedPrivateKeyInfo;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static java.util.regex.Pattern.CASE_INSENSITIVE;
|
||||
|
||||
/**
|
||||
* This is a helper class to read private keys and X509 certifificates encoded based on <a href="https://datatracker.ietf.org/doc/html/rfc1421">PEM (RFC 1421)</a>
|
||||
* format. It can read Password Based Encrypted (PBE henceforth) private keys as well as non-encrypted private keys
|
||||
* along with the X509 certificates/cert-chain based on the textual encoding defined in the <a href="https://datatracker.ietf.org/doc/html/rfc7468">RFC 7468</a>
|
||||
* <p>
|
||||
* The input private key must be in PKCS#8 format.
|
||||
* <p>
|
||||
* It returns PKCS#8 formatted private key and X509 certificates.
|
||||
*/
|
||||
public final class PEMReader
|
||||
{
|
||||
/**
|
||||
* The private key can be with any of these algorithms in order for this read to successfully parse it.
|
||||
* Currently, supported algorithms are,
|
||||
* <pre>
|
||||
* RSA, DSA or EC
|
||||
* </pre>
|
||||
* The first one to be evaluated is RSA, being the most common for private keys.
|
||||
*/
|
||||
public static final Set<String> SUPPORTED_PRIVATE_KEY_ALGORITHMS = ImmutableSet.of("RSA", "DSA", "EC");
|
||||
private static final Logger logger = LoggerFactory.getLogger(PEMReader.class);
|
||||
private static final Pattern CERT_PATTERN = Pattern.compile("-+BEGIN\\s+.*CERTIFICATE[^-]*-+(?:\\s|\\r|\\n)+([a-z0-9+/=\\r\\n]+)-+END\\s+.*CERTIFICATE[^-]*-+", CASE_INSENSITIVE);
|
||||
private static final Pattern KEY_PATTERN = Pattern.compile("-+BEGIN\\s+.*PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n)+([a-z0-9+/=\\r\\n]+)-+END\\s+.*PRIVATE\\s+KEY[^-]*-+", CASE_INSENSITIVE);
|
||||
|
||||
/**
|
||||
* Extracts private key from the PEM content for the private key, assuming its not PBE.
|
||||
*
|
||||
* @param unencryptedPEMKey private key stored as PEM content
|
||||
* @return {@link PrivateKey} upon successful reading of the private key
|
||||
* @throws IOException in case PEM reading fails
|
||||
* @throws GeneralSecurityException in case any issue encountered while reading the private key
|
||||
*/
|
||||
public static PrivateKey extractPrivateKey(String unencryptedPEMKey) throws IOException, GeneralSecurityException
|
||||
{
|
||||
return extractPrivateKey(unencryptedPEMKey, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts private key from the Password Based Encrypted PEM content for the private key.
|
||||
*
|
||||
* @param pemKey PBE private key stored as PEM content
|
||||
* @param keyPassword password to be used for the private key decryption
|
||||
* @return {@link PrivateKey} upon successful reading of the private key
|
||||
* @throws IOException in case PEM reading fails
|
||||
* @throws GeneralSecurityException in case any issue encountered while reading the private key
|
||||
*/
|
||||
public static PrivateKey extractPrivateKey(String pemKey, String keyPassword) throws IOException,
|
||||
GeneralSecurityException
|
||||
{
|
||||
PKCS8EncodedKeySpec keySpec;
|
||||
String base64EncodedKey = extractBase64EncodedKey(pemKey);
|
||||
byte[] derKeyBytes = decodeBase64(base64EncodedKey);
|
||||
|
||||
if (keyPassword != null)
|
||||
{
|
||||
logger.debug("Encrypted key's length: {}, key's password length: {}",
|
||||
derKeyBytes.length, keyPassword.length());
|
||||
|
||||
EncryptedPrivateKeyInfo epki = new EncryptedPrivateKeyInfo(derKeyBytes);
|
||||
logger.debug("Encrypted private key info's algorithm name: {}", epki.getAlgName());
|
||||
|
||||
AlgorithmParameters params = epki.getAlgParameters();
|
||||
PBEKeySpec pbeKeySpec = new PBEKeySpec(keyPassword.toCharArray());
|
||||
Key encryptionKey = SecretKeyFactory.getInstance(epki.getAlgName()).generateSecret(pbeKeySpec);
|
||||
pbeKeySpec.clearPassword();
|
||||
logger.debug("Key algorithm: {}, key format: {}", encryptionKey.getAlgorithm(), encryptionKey.getFormat());
|
||||
|
||||
Cipher cipher = Cipher.getInstance(epki.getAlgName());
|
||||
cipher.init(Cipher.DECRYPT_MODE, encryptionKey, params);
|
||||
byte[] rawKeyBytes;
|
||||
try
|
||||
{
|
||||
rawKeyBytes = cipher.doFinal(epki.getEncryptedData());
|
||||
}
|
||||
catch (BadPaddingException e)
|
||||
{
|
||||
throw new GeneralSecurityException("Failed to decrypt the private key data. Either the password " +
|
||||
"provided for the key is wrong or the private key data is " +
|
||||
"corrupted. msg=" + e.getMessage(), e);
|
||||
}
|
||||
logger.debug("Decrypted private key's length: {}", rawKeyBytes.length);
|
||||
|
||||
keySpec = new PKCS8EncodedKeySpec(rawKeyBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("Key length: {}", derKeyBytes.length);
|
||||
keySpec = new PKCS8EncodedKeySpec(derKeyBytes);
|
||||
}
|
||||
|
||||
PrivateKey privateKey = null;
|
||||
|
||||
/*
|
||||
* Ideally we can inspect the OID (Object Identifier) from the private key with ASN.1 parser and identify the
|
||||
* actual algorithm of the private key. For doing that, we have to use some special library like BouncyCastle.
|
||||
* However in the absence of that, below brute-force approach can work- that is to try out all the supported
|
||||
* private key algorithms given that there are only three major algorithms to verify against.
|
||||
*/
|
||||
for (String privateKeyAlgorithm : SUPPORTED_PRIVATE_KEY_ALGORITHMS)
|
||||
{
|
||||
try
|
||||
{
|
||||
privateKey = KeyFactory.getInstance(privateKeyAlgorithm).generatePrivate(keySpec);
|
||||
logger.info("Parsing for the private key finished with {} algorithm.", privateKeyAlgorithm);
|
||||
return privateKey;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.debug("Failed to parse the private key with {} algorithm. Will try the other supported " +
|
||||
"algorithms.", privateKeyAlgorithm);
|
||||
}
|
||||
}
|
||||
throw new GeneralSecurityException("The given private key could not be parsed with any of the supported " +
|
||||
"algorithms. Please see PEMReader#SUPPORTED_PRIVATE_KEY_ALGORITHMS.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the certificates/cert-chain from the PEM content.
|
||||
*
|
||||
* @param pemCerts certificates/cert-chain stored as PEM content
|
||||
* @return X509 certiificate list
|
||||
* @throws GeneralSecurityException in case any issue encountered while reading the certificates
|
||||
*/
|
||||
public static Certificate[] extractCertificates(String pemCerts) throws GeneralSecurityException
|
||||
{
|
||||
List<Certificate> certificateList = new ArrayList<>();
|
||||
List<String> base64EncodedCerts = extractBase64EncodedCerts(pemCerts);
|
||||
for (String base64EncodedCertificate : base64EncodedCerts)
|
||||
{
|
||||
certificateList.add(generateCertificate(base64EncodedCertificate));
|
||||
}
|
||||
Certificate[] certificates = certificateList.toArray(new Certificate[0]);
|
||||
return certificates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the X509 certificate object given the base64 encoded PEM content.
|
||||
*
|
||||
* @param base64Certificate base64 encoded PEM content for the certificate
|
||||
* @return X509 certificate
|
||||
* @throws GeneralSecurityException in case any issue encountered while reading the certificate
|
||||
*/
|
||||
private static Certificate generateCertificate(String base64Certificate) throws GeneralSecurityException
|
||||
{
|
||||
byte[] decodedCertificateBytes = decodeBase64(base64Certificate);
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
|
||||
X509Certificate certificate =
|
||||
(X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(decodedCertificateBytes));
|
||||
logCertificateDetails(certificate);
|
||||
return certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs X509 certificate details for the debugging purpose with {@code INFO} level log.
|
||||
* Namely, it prints - Subject DN, Issuer DN, Certificate serial number and the certificate expiry date which
|
||||
* could be very valuable for debugging any certificate related issues.
|
||||
*
|
||||
* @param certificate certificate to log
|
||||
*/
|
||||
private static void logCertificateDetails(X509Certificate certificate)
|
||||
{
|
||||
assert certificate != null;
|
||||
logger.info("*********** Certificate Details *****************");
|
||||
logger.info("Subject DN: {}", certificate.getSubjectDN());
|
||||
logger.info("Issuer DN: {}", certificate.getIssuerDN());
|
||||
logger.info("Serial Number: {}", certificate.getSerialNumber());
|
||||
logger.info("Expiry: {}", certificate.getNotAfter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the PEM formatted private key based on the standard pattern specified by the <a href="https://datatracker.ietf.org/doc/html/rfc7468#section-11">RFC 7468</a>.
|
||||
*
|
||||
* @param pemKey private key stored as PEM content
|
||||
* @return base64 string contained within the defined encapsulation boundaries by the above RFC
|
||||
* @throws GeneralSecurityException in case any issue encountered while parsing the key
|
||||
*/
|
||||
private static String extractBase64EncodedKey(String pemKey) throws GeneralSecurityException
|
||||
{
|
||||
Matcher matcher = KEY_PATTERN.matcher(pemKey);
|
||||
if (matcher.find())
|
||||
{
|
||||
return matcher.group(1).replaceAll("\\s", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new GeneralSecurityException("Invalid private key format");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the PEM formatted certificate/public-key based on the standard pattern specified by the
|
||||
* <a href="https://datatracker.ietf.org/doc/html/rfc7468#section-13">RFC 7468</a>.
|
||||
*
|
||||
* @param pemCerts certificate/public-key stored as PEM content
|
||||
* @return list of base64 encoded certificates within the defined encapsulation boundaries by the above RFC
|
||||
* @throws GeneralSecurityException in case any issue encountered parsing the certificate
|
||||
*/
|
||||
private static List<String> extractBase64EncodedCerts(String pemCerts) throws GeneralSecurityException
|
||||
{
|
||||
List<String> certificateList = new ArrayList<>();
|
||||
Matcher matcher = CERT_PATTERN.matcher(pemCerts);
|
||||
if (!matcher.find())
|
||||
{
|
||||
throw new GeneralSecurityException("Invalid certificate format");
|
||||
}
|
||||
|
||||
for (int start = 0; matcher.find(start); start = matcher.end())
|
||||
{
|
||||
String certificate = matcher.group(1).replaceAll("\\s", "");
|
||||
certificateList.add(certificate);
|
||||
}
|
||||
return certificateList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes given input in Base64 format.
|
||||
*
|
||||
* @param base64Input input to be decoded
|
||||
* @return byte[] containing decoded bytes
|
||||
* @throws GeneralSecurityException in case it fails to decode the given base64 input
|
||||
*/
|
||||
private static byte[] decodeBase64(String base64Input) throws GeneralSecurityException
|
||||
{
|
||||
try
|
||||
{
|
||||
return Base64.getDecoder().decode(base64Input);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
throw new GeneralSecurityException("Failed to decode given base64 input. msg=" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Testing for pluggable ssl_context_factory option for client and server encryption options with a valid and a missing
|
||||
# implementation classes.
|
||||
#
|
||||
cluster_name: Test Cluster
|
||||
# memtable_allocation_type: heap_buffers
|
||||
memtable_allocation_type: offheap_objects
|
||||
commitlog_sync: batch
|
||||
commitlog_segment_size: 5MiB
|
||||
commitlog_directory: build/test/cassandra/commitlog
|
||||
# commitlog_compression:
|
||||
# - class_name: LZ4Compressor
|
||||
cdc_raw_directory: build/test/cassandra/cdc_raw
|
||||
cdc_enabled: false
|
||||
hints_directory: build/test/cassandra/hints
|
||||
partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
|
||||
listen_address: 127.0.0.1
|
||||
storage_port: 7012
|
||||
ssl_storage_port: 17012
|
||||
start_native_transport: true
|
||||
native_transport_port: 9042
|
||||
column_index_size: 4KiB
|
||||
saved_caches_directory: build/test/cassandra/saved_caches
|
||||
data_file_directories:
|
||||
- build/test/cassandra/data
|
||||
disk_access_mode: mmap
|
||||
seed_provider:
|
||||
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
|
||||
parameters:
|
||||
- seeds: "127.0.0.1:7012"
|
||||
endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
|
||||
dynamic_snitch: true
|
||||
client_encryption_options:
|
||||
ssl_context_factory:
|
||||
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
|
||||
parameters:
|
||||
private_key: |
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
|
||||
g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
|
||||
xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
|
||||
L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
|
||||
sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
|
||||
f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
|
||||
RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
|
||||
0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
|
||||
evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
|
||||
tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
|
||||
wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
|
||||
K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
|
||||
zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
|
||||
mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
|
||||
WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
|
||||
jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
|
||||
eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
|
||||
DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
|
||||
AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
|
||||
Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
|
||||
Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
|
||||
ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
|
||||
bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
|
||||
hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
|
||||
RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
|
||||
pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
|
||||
FujZhqbKUDbYAcqTkoQ=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
private_key_password: "cassandra"
|
||||
trusted_certificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
server_encryption_options:
|
||||
internode_encryption: none
|
||||
keystore: test/conf/cassandra_ssl_test.keystore
|
||||
keystore_password: cassandra
|
||||
truststore: test/conf/cassandra_ssl_test.truststore
|
||||
truststore_password: cassandra
|
||||
incremental_backups: true
|
||||
concurrent_compactors: 4
|
||||
compaction_throughput: 0MiB/s
|
||||
row_cache_class_name: org.apache.cassandra.cache.OHCProvider
|
||||
row_cache_size: 16MiB
|
||||
user_defined_functions_enabled: true
|
||||
scripted_user_defined_functions_enabled: true
|
||||
prepared_statements_cache_size: 1MiB
|
||||
corrupted_tombstone_strategy: exception
|
||||
stream_entire_sstables: true
|
||||
stream_throughput_outbound: 24MiB/s
|
||||
sasi_indexes_enabled: true
|
||||
materialized_views_enabled: true
|
||||
file_cache_enabled: true
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Testing for pluggable ssl_context_factory option for client and server encryption options with a valid and a missing
|
||||
# implementation classes.
|
||||
#
|
||||
cluster_name: Test Cluster
|
||||
# memtable_allocation_type: heap_buffers
|
||||
memtable_allocation_type: offheap_objects
|
||||
commitlog_sync: batch
|
||||
commitlog_segment_size: 5MiB
|
||||
commitlog_directory: build/test/cassandra/commitlog
|
||||
# commitlog_compression:
|
||||
# - class_name: LZ4Compressor
|
||||
cdc_raw_directory: build/test/cassandra/cdc_raw
|
||||
cdc_enabled: false
|
||||
hints_directory: build/test/cassandra/hints
|
||||
partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
|
||||
listen_address: 127.0.0.1
|
||||
storage_port: 7012
|
||||
ssl_storage_port: 17012
|
||||
start_native_transport: true
|
||||
native_transport_port: 9042
|
||||
column_index_size: 4KiB
|
||||
saved_caches_directory: build/test/cassandra/saved_caches
|
||||
data_file_directories:
|
||||
- build/test/cassandra/data
|
||||
disk_access_mode: mmap
|
||||
seed_provider:
|
||||
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
|
||||
parameters:
|
||||
- seeds: "127.0.0.1:7012"
|
||||
endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
|
||||
dynamic_snitch: true
|
||||
client_encryption_options:
|
||||
ssl_context_factory:
|
||||
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
|
||||
parameters:
|
||||
private_key: |
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
|
||||
g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
|
||||
xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
|
||||
L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
|
||||
sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
|
||||
f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
|
||||
RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
|
||||
0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
|
||||
evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
|
||||
tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
|
||||
wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
|
||||
K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
|
||||
zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
|
||||
mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
|
||||
WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
|
||||
jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
|
||||
eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
|
||||
DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
|
||||
AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
|
||||
Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
|
||||
Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
|
||||
ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
|
||||
bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
|
||||
hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
|
||||
RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
|
||||
pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
|
||||
FujZhqbKUDbYAcqTkoQ=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
private_key_password: "cassandra"
|
||||
trusted_certificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
keystore: test/conf/cassandra_ssl_test.keystore.pem
|
||||
keystore_password: cassandra
|
||||
truststore: test/conf/cassandra_ssl_test.truststore.pem
|
||||
incremental_backups: true
|
||||
concurrent_compactors: 4
|
||||
compaction_throughput: 0MiB/s
|
||||
row_cache_class_name: org.apache.cassandra.cache.OHCProvider
|
||||
row_cache_size: 16MiB
|
||||
user_defined_functions_enabled: true
|
||||
scripted_user_defined_functions_enabled: true
|
||||
prepared_statements_cache_size: 1MiB
|
||||
corrupted_tombstone_strategy: exception
|
||||
stream_entire_sstables: true
|
||||
stream_throughput_outbound: 24MiB/s
|
||||
sasi_indexes_enabled: true
|
||||
materialized_views_enabled: true
|
||||
file_cache_enabled: true
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Testing for pluggable ssl_context_factory option for client and server encryption options with a valid and a missing
|
||||
# implementation classes.
|
||||
#
|
||||
cluster_name: Test Cluster
|
||||
# memtable_allocation_type: heap_buffers
|
||||
memtable_allocation_type: offheap_objects
|
||||
commitlog_sync: batch
|
||||
commitlog_segment_size: 5MiB
|
||||
commitlog_directory: build/test/cassandra/commitlog
|
||||
# commitlog_compression:
|
||||
# - class_name: LZ4Compressor
|
||||
cdc_raw_directory: build/test/cassandra/cdc_raw
|
||||
cdc_enabled: false
|
||||
hints_directory: build/test/cassandra/hints
|
||||
partitioner: org.apache.cassandra.dht.ByteOrderedPartitioner
|
||||
listen_address: 127.0.0.1
|
||||
storage_port: 7012
|
||||
ssl_storage_port: 17012
|
||||
start_native_transport: true
|
||||
native_transport_port: 9042
|
||||
column_index_size: 4KiB
|
||||
saved_caches_directory: build/test/cassandra/saved_caches
|
||||
data_file_directories:
|
||||
- build/test/cassandra/data
|
||||
disk_access_mode: mmap
|
||||
seed_provider:
|
||||
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
|
||||
parameters:
|
||||
- seeds: "127.0.0.1:7012"
|
||||
endpoint_snitch: org.apache.cassandra.locator.SimpleSnitch
|
||||
dynamic_snitch: true
|
||||
client_encryption_options:
|
||||
ssl_context_factory:
|
||||
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
|
||||
parameters:
|
||||
private_key: |
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
|
||||
g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
|
||||
xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
|
||||
L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
|
||||
sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
|
||||
f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
|
||||
RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
|
||||
0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
|
||||
evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
|
||||
tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
|
||||
wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
|
||||
K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
|
||||
zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
|
||||
mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
|
||||
WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
|
||||
jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
|
||||
eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
|
||||
DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
|
||||
AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
|
||||
Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
|
||||
Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
|
||||
ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
|
||||
bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
|
||||
hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
|
||||
RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
|
||||
pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
|
||||
FujZhqbKUDbYAcqTkoQ=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
private_key_password: "cassandra"
|
||||
trusted_certificates: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
server_encryption_options:
|
||||
ssl_context_factory:
|
||||
class_name: org.apache.cassandra.security.PEMBasedSslContextFactory
|
||||
internode_encryption: none
|
||||
keystore: test/conf/cassandra_ssl_test.keystore.pem
|
||||
keystore_password: cassandra
|
||||
truststore: test/conf/cassandra_ssl_test.truststore.pem
|
||||
incremental_backups: true
|
||||
concurrent_compactors: 4
|
||||
compaction_throughput: 0MiB/s
|
||||
row_cache_class_name: org.apache.cassandra.cache.OHCProvider
|
||||
row_cache_size: 16MiB
|
||||
user_defined_functions_enabled: true
|
||||
scripted_user_defined_functions_enabled: true
|
||||
prepared_statements_cache_size: 1MiB
|
||||
corrupted_tombstone_strategy: exception
|
||||
stream_entire_sstables: true
|
||||
stream_throughput_outbound: 24MiB/s
|
||||
sasi_indexes_enabled: true
|
||||
materialized_views_enabled: true
|
||||
file_cache_enabled: true
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/
|
||||
g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl
|
||||
xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29
|
||||
L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V
|
||||
sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/
|
||||
f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8
|
||||
RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR
|
||||
0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs
|
||||
evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU
|
||||
tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6
|
||||
wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN
|
||||
K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv
|
||||
zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5
|
||||
mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo
|
||||
WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ
|
||||
jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6
|
||||
eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny
|
||||
DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn
|
||||
AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY
|
||||
Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow
|
||||
Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut
|
||||
ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr
|
||||
bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH
|
||||
hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI
|
||||
RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw
|
||||
pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP
|
||||
FujZhqbKUDbYAcqTkoQ=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOSZVf8dLj1xLw
|
||||
efqjbogbAwhwRXd3tmEfQY1zHyudJF3XR1T0Xp26BKNvAYUxxZRDNg16M3prPRZv
|
||||
wkhDJdE9NaN+BpZPJUavRsZOfGDq/CHN8j/2PPKrn3G/b065JjV3GZjfV/Sln047
|
||||
DeZptaSyOg7ZN7F8qjGqxEcnw+szV/wTzhnjGjZMlcbOm4jFGQAn6xUOooQCGsoB
|
||||
9FgxKB0nvNG3xVe/2eCNfbS4DabT3Y1wfQqZ62hOa5ZS0rwT+pw3tQs3zFFY1Sfi
|
||||
G7qYbqZrKTheWIZGojVVm6mqH4yA2ofOe5N3RsBitCwU/D0dpnaG9Wcl98nmXueM
|
||||
B6Rk04v7AgMBAAECggEAYnxIKjrFz/JkJ5MmiszM5HV698r9YB0aqHnFIHPoykIL
|
||||
uiCjiumantDrFsCkosixULwvI/BRwbxstTpyrheU9psT6P1CONICVPvV8ylgJAYU
|
||||
l+ofn56cEXKxVuICSWFLDH7pM1479g+IJJQAchbKQpqxAGTuMu3SpvJolfuj5srt
|
||||
bM7/RYhJFLwDuvHNA3ivlogMneItP03+C25aaxstM+lBuBf68+n78zMgSvt6J/6Y
|
||||
G2TOMKnxveMlG2qu9l2lAw/2i8daG/qre08nTH7wpRx0gZLZqNpe45exkrzticzF
|
||||
FgWYjG2K2brX21jqHroFgMhdXF7zhhRgLoIeC0BrIQKBgQDCfGfWrJESKBbVai5u
|
||||
7wqD9nlzjv6N6FXfTDOPXO1vz5frdvtLVWbs0SMPy+NglkaZK0iqHvb9mf2of8eC
|
||||
0D5cmewjn7WCDBQMypIMYgT912ak/BBVuGXcxb6UgD+xARfSARo2C8NG1hfprw1W
|
||||
ad14CjS5xhFMs44HpVYhI7iPYwKBgQC7SqVG/b37vZ7CINemdvoMujLvvYXDJJM8
|
||||
N21LqNJfVXdukdH3T0xuLnh9Z/wPHjJDMF/9+1foxSEPHijtyz5P19EilNEC/3qw
|
||||
fI19+VZoY0mdhPtXSGzy+rbTE2v71QgwFLizSos14Gr+eNiIjF7FYccK05++K/zk
|
||||
cd8ZA3bwiQKBgQCl+HTFBs9mpz+VMOAfW2+l3hkXPNiPUc62mNkHZ05ZNNd44jjh
|
||||
uSf0wSUiveR08MmevQlt5K7zDQ8jVKh2QjB15gVXAVxsdtJFeDnax2trFP9LnLBz
|
||||
9sE2/qn9INU5wK0LUlWD+dXUBbCyg+jl7cJKRqtoPldVFYYHkFlIPqup8QKBgHXv
|
||||
hyuw1FUVDkdHzwOvn70r8q8sNHKxMVWVwWkHIZGOi+pAQGrusD4hXRX6yKnsZdIR
|
||||
QCD6iFy25R5T64nxlYdJaxPPid3NakB/7ckJnPOWseBSwMIxhQlr/nvjmve1Kba9
|
||||
FaEwq4B9lGIxToiNe4/nBiM3JzvlDxX67nUdzWOhAoGAdFvriyvjshSJ4JHgIY9K
|
||||
37BVB0VKMcFV2P8fLVWO5oyRtE1bJhU4QVpQmauABU4RGSojJ3NPIVH1wxmJeYtj
|
||||
Q3b7EZaqI6ovna2eK2qtUx4WwxhRaXTT8xueBI2lgL6sBSTGG+K69ZOzGQzG/Mfr
|
||||
RXKInnLInFD9JD94VqmMozo=
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV
|
||||
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
|
||||
VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh
|
||||
Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx
|
||||
EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu
|
||||
a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw
|
||||
FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d
|
||||
ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy
|
||||
q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2
|
||||
TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto
|
||||
TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA
|
||||
YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD
|
||||
N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v
|
||||
iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh
|
||||
IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv
|
||||
6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG
|
||||
qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa
|
||||
HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru
|
||||
n3MVF9w=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.config.Config;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
|
||||
public class PEMBasedSslContextFactoryConfigTest
|
||||
{
|
||||
@BeforeClass
|
||||
public static void setupDatabaseDescriptor()
|
||||
{
|
||||
System.setProperty("cassandra.config", "cassandra-pem-sslcontextfactory.yaml");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownDatabaseDescriptor()
|
||||
{
|
||||
System.clearProperty("cassandra.config");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHappyPathInlinePEM() throws SSLException
|
||||
{
|
||||
|
||||
Config config = DatabaseDescriptor.loadConfig();
|
||||
config.client_encryption_options.applyConfig();
|
||||
|
||||
Assert.assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
|
||||
config.client_encryption_options.ssl_context_factory.class_name);
|
||||
Assert.assertEquals(config.client_encryption_options.ssl_context_factory.class_name,
|
||||
config.client_encryption_options.sslContextFactoryInstance.getClass().getName());
|
||||
PEMBasedSslContextFactory sslContextFactory =
|
||||
(PEMBasedSslContextFactory) config.client_encryption_options.sslContextFactoryInstance;
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
sslContextFactory.buildTrustManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHappyPathFileBasedPEM() throws SSLException
|
||||
{
|
||||
|
||||
Config config = DatabaseDescriptor.loadConfig();
|
||||
config.server_encryption_options.applyConfig();
|
||||
|
||||
Assert.assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
|
||||
config.server_encryption_options.ssl_context_factory.class_name);
|
||||
Assert.assertEquals(config.server_encryption_options.ssl_context_factory.class_name,
|
||||
config.server_encryption_options.sslContextFactoryInstance.getClass().getName());
|
||||
PEMBasedSslContextFactory sslContextFactory =
|
||||
(PEMBasedSslContextFactory) config.server_encryption_options.sslContextFactoryInstance;
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
sslContextFactory.buildTrustManagerFactory();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.config.Config;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
|
||||
public class PEMBasedSslContextFactoryInvalidConfigTest
|
||||
{
|
||||
@BeforeClass
|
||||
public static void setupDatabaseDescriptor()
|
||||
{
|
||||
System.setProperty("cassandra.config", "cassandra-pem-sslcontextfactory-invalidconfiguration.yaml");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownDatabaseDescriptor()
|
||||
{
|
||||
System.clearProperty("cassandra.config");
|
||||
}
|
||||
|
||||
@Test(expected = ConfigurationException.class)
|
||||
public void testFileBasedAndInlinePEMConfiguration() throws SSLException
|
||||
{
|
||||
|
||||
Config config = DatabaseDescriptor.loadConfig();
|
||||
config.client_encryption_options.applyConfig();
|
||||
|
||||
Assert.assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
|
||||
config.client_encryption_options.ssl_context_factory.class_name);
|
||||
Assert.assertEquals(config.client_encryption_options.ssl_context_factory.class_name,
|
||||
config.client_encryption_options.sslContextFactoryInstance.getClass().getName());
|
||||
PEMBasedSslContextFactory sslContextFactory =
|
||||
(PEMBasedSslContextFactory) config.client_encryption_options.sslContextFactoryInstance;
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
sslContextFactory.buildTrustManagerFactory();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,449 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import io.netty.handler.ssl.OpenSsl;
|
||||
import io.netty.handler.ssl.OpenSslContext;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
import org.apache.cassandra.config.EncryptionOptions;
|
||||
import org.apache.cassandra.config.ParameterizedClass;
|
||||
|
||||
import static org.apache.cassandra.security.PEMBasedSslContextFactory.ConfigKey.ENCODED_CERTIFICATES;
|
||||
import static org.apache.cassandra.security.PEMBasedSslContextFactory.ConfigKey.ENCODED_KEY;
|
||||
import static org.apache.cassandra.security.PEMBasedSslContextFactory.ConfigKey.KEY_PASSWORD;
|
||||
|
||||
public class PEMBasedSslContextFactoryTest
|
||||
{
|
||||
private static final String private_key =
|
||||
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/\n" +
|
||||
"g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl\n" +
|
||||
"xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29\n" +
|
||||
"L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V\n" +
|
||||
"sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/\n" +
|
||||
"f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8\n" +
|
||||
"RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR\n" +
|
||||
"0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs\n" +
|
||||
"evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU\n" +
|
||||
"tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6\n" +
|
||||
"wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN\n" +
|
||||
"K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv\n" +
|
||||
"zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5\n" +
|
||||
"mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo\n" +
|
||||
"WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ\n" +
|
||||
"jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6\n" +
|
||||
"eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny\n" +
|
||||
"DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn\n" +
|
||||
"AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY\n" +
|
||||
"Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow\n" +
|
||||
"Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut\n" +
|
||||
"ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr\n" +
|
||||
"bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH\n" +
|
||||
"hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI\n" +
|
||||
"RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw\n" +
|
||||
"pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP\n" +
|
||||
"FujZhqbKUDbYAcqTkoQ=\n" +
|
||||
"-----END ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV\n" +
|
||||
"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n" +
|
||||
"VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh\n" +
|
||||
"Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx\n" +
|
||||
"EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu\n" +
|
||||
"a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw\n" +
|
||||
"FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
|
||||
"MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d\n" +
|
||||
"ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy\n" +
|
||||
"q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2\n" +
|
||||
"TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto\n" +
|
||||
"TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA\n" +
|
||||
"YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD\n" +
|
||||
"N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v\n" +
|
||||
"iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh\n" +
|
||||
"IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv\n" +
|
||||
"6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG\n" +
|
||||
"qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa\n" +
|
||||
"HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru\n" +
|
||||
"n3MVF9w=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
private static final String unencrypted_private_key =
|
||||
"-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOSZVf8dLj1xLw\n" +
|
||||
"efqjbogbAwhwRXd3tmEfQY1zHyudJF3XR1T0Xp26BKNvAYUxxZRDNg16M3prPRZv\n" +
|
||||
"wkhDJdE9NaN+BpZPJUavRsZOfGDq/CHN8j/2PPKrn3G/b065JjV3GZjfV/Sln047\n" +
|
||||
"DeZptaSyOg7ZN7F8qjGqxEcnw+szV/wTzhnjGjZMlcbOm4jFGQAn6xUOooQCGsoB\n" +
|
||||
"9FgxKB0nvNG3xVe/2eCNfbS4DabT3Y1wfQqZ62hOa5ZS0rwT+pw3tQs3zFFY1Sfi\n" +
|
||||
"G7qYbqZrKTheWIZGojVVm6mqH4yA2ofOe5N3RsBitCwU/D0dpnaG9Wcl98nmXueM\n" +
|
||||
"B6Rk04v7AgMBAAECggEAYnxIKjrFz/JkJ5MmiszM5HV698r9YB0aqHnFIHPoykIL\n" +
|
||||
"uiCjiumantDrFsCkosixULwvI/BRwbxstTpyrheU9psT6P1CONICVPvV8ylgJAYU\n" +
|
||||
"l+ofn56cEXKxVuICSWFLDH7pM1479g+IJJQAchbKQpqxAGTuMu3SpvJolfuj5srt\n" +
|
||||
"bM7/RYhJFLwDuvHNA3ivlogMneItP03+C25aaxstM+lBuBf68+n78zMgSvt6J/6Y\n" +
|
||||
"G2TOMKnxveMlG2qu9l2lAw/2i8daG/qre08nTH7wpRx0gZLZqNpe45exkrzticzF\n" +
|
||||
"FgWYjG2K2brX21jqHroFgMhdXF7zhhRgLoIeC0BrIQKBgQDCfGfWrJESKBbVai5u\n" +
|
||||
"7wqD9nlzjv6N6FXfTDOPXO1vz5frdvtLVWbs0SMPy+NglkaZK0iqHvb9mf2of8eC\n" +
|
||||
"0D5cmewjn7WCDBQMypIMYgT912ak/BBVuGXcxb6UgD+xARfSARo2C8NG1hfprw1W\n" +
|
||||
"ad14CjS5xhFMs44HpVYhI7iPYwKBgQC7SqVG/b37vZ7CINemdvoMujLvvYXDJJM8\n" +
|
||||
"N21LqNJfVXdukdH3T0xuLnh9Z/wPHjJDMF/9+1foxSEPHijtyz5P19EilNEC/3qw\n" +
|
||||
"fI19+VZoY0mdhPtXSGzy+rbTE2v71QgwFLizSos14Gr+eNiIjF7FYccK05++K/zk\n" +
|
||||
"cd8ZA3bwiQKBgQCl+HTFBs9mpz+VMOAfW2+l3hkXPNiPUc62mNkHZ05ZNNd44jjh\n" +
|
||||
"uSf0wSUiveR08MmevQlt5K7zDQ8jVKh2QjB15gVXAVxsdtJFeDnax2trFP9LnLBz\n" +
|
||||
"9sE2/qn9INU5wK0LUlWD+dXUBbCyg+jl7cJKRqtoPldVFYYHkFlIPqup8QKBgHXv\n" +
|
||||
"hyuw1FUVDkdHzwOvn70r8q8sNHKxMVWVwWkHIZGOi+pAQGrusD4hXRX6yKnsZdIR\n" +
|
||||
"QCD6iFy25R5T64nxlYdJaxPPid3NakB/7ckJnPOWseBSwMIxhQlr/nvjmve1Kba9\n" +
|
||||
"FaEwq4B9lGIxToiNe4/nBiM3JzvlDxX67nUdzWOhAoGAdFvriyvjshSJ4JHgIY9K\n" +
|
||||
"37BVB0VKMcFV2P8fLVWO5oyRtE1bJhU4QVpQmauABU4RGSojJ3NPIVH1wxmJeYtj\n" +
|
||||
"Q3b7EZaqI6ovna2eK2qtUx4WwxhRaXTT8xueBI2lgL6sBSTGG+K69ZOzGQzG/Mfr\n" +
|
||||
"RXKInnLInFD9JD94VqmMozo=\n" +
|
||||
"-----END PRIVATE KEY-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV\n" +
|
||||
"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n" +
|
||||
"VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh\n" +
|
||||
"Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx\n" +
|
||||
"EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu\n" +
|
||||
"a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw\n" +
|
||||
"FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
|
||||
"MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d\n" +
|
||||
"ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy\n" +
|
||||
"q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2\n" +
|
||||
"TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto\n" +
|
||||
"TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA\n" +
|
||||
"YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD\n" +
|
||||
"N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v\n" +
|
||||
"iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh\n" +
|
||||
"IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv\n" +
|
||||
"6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG\n" +
|
||||
"qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa\n" +
|
||||
"HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru\n" +
|
||||
"n3MVF9w=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
private static final String trusted_certificates =
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV\n" +
|
||||
"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n" +
|
||||
"VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh\n" +
|
||||
"Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx\n" +
|
||||
"EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu\n" +
|
||||
"a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw\n" +
|
||||
"FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
|
||||
"MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d\n" +
|
||||
"ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy\n" +
|
||||
"q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2\n" +
|
||||
"TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto\n" +
|
||||
"TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA\n" +
|
||||
"YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD\n" +
|
||||
"N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v\n" +
|
||||
"iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh\n" +
|
||||
"IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv\n" +
|
||||
"6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG\n" +
|
||||
"qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa\n" +
|
||||
"HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru\n" +
|
||||
"n3MVF9w=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
private final Map<String, Object> commonConfig = new HashMap<>();
|
||||
|
||||
@Before
|
||||
public void setup()
|
||||
{
|
||||
commonConfig.put(ENCODED_CERTIFICATES.getKeyName(), trusted_certificates);
|
||||
commonConfig.put("require_client_auth", Boolean.FALSE);
|
||||
commonConfig.put("cipher_suites", Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA"));
|
||||
}
|
||||
|
||||
private void addKeyStoreOptions(Map<String, Object> config)
|
||||
{
|
||||
config.put(ENCODED_KEY.getKeyName(), private_key);
|
||||
config.put(KEY_PASSWORD.getKeyName(), "cassandra");
|
||||
}
|
||||
|
||||
private void addUnencryptedKeyStoreOptions(Map<String, Object> config)
|
||||
{
|
||||
config.put(ENCODED_KEY.getKeyName(), unencrypted_private_key);
|
||||
}
|
||||
|
||||
private void addFileBaseTrustStoreOptions(Map<String, Object> config)
|
||||
{
|
||||
config.put("truststore", "test/conf/cassandra_ssl_test.truststore.pem");
|
||||
}
|
||||
|
||||
private void addFileBaseKeyStoreOptions(Map<String, Object> config)
|
||||
{
|
||||
config.put("keystore", "test/conf/cassandra_ssl_test.keystore.pem");
|
||||
config.put("keystore_password", "cassandra");
|
||||
}
|
||||
|
||||
private void addFileBaseUnencryptedKeyStoreOptions(Map<String, Object> config)
|
||||
{
|
||||
config.put("keystore", "test/conf/cassandra_ssl_test.unencrypted_keystore.pem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSslContextOpenSSL() throws IOException
|
||||
{
|
||||
ParameterizedClass sslContextFactory = new ParameterizedClass(PEMBasedSslContextFactory.class.getSimpleName()
|
||||
, new HashMap<>());
|
||||
EncryptionOptions options = new EncryptionOptions().withTrustStore("test/conf/cassandra_ssl_test.truststore.pem")
|
||||
.withKeyStore("test/conf/cassandra_ssl_test.keystore.pem")
|
||||
.withKeyStorePassword("cassandra")
|
||||
.withRequireClientAuth(false)
|
||||
.withCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA")
|
||||
.withSslContextFactory(sslContextFactory);
|
||||
SslContext sslContext = SSLFactory.getOrCreateSslContext(options, true, ISslContextFactory.SocketType.CLIENT);
|
||||
Assert.assertNotNull(sslContext);
|
||||
if (OpenSsl.isAvailable())
|
||||
Assert.assertTrue(sslContext instanceof OpenSslContext);
|
||||
else
|
||||
Assert.assertTrue(sslContext instanceof SslContext);
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void buildTrustManagerFactoryWithInvalidTruststoreFile() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
config.remove("encoded_certificates");
|
||||
config.put("truststore", "/this/is/probably/not/a/file/on/your/test/machine");
|
||||
|
||||
DefaultSslContextFactory defaultSslContextFactoryImpl = new DefaultSslContextFactory(config);
|
||||
defaultSslContextFactoryImpl.checkedExpiry = false;
|
||||
defaultSslContextFactoryImpl.buildTrustManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildTrustManagerFactoryHappyPath() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
sslContextFactory.checkedExpiry = false;
|
||||
TrustManagerFactory trustManagerFactory = sslContextFactory.buildTrustManagerFactory();
|
||||
Assert.assertNotNull(trustManagerFactory);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildFileBasedTrustManagerFactoryHappyPath() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
config.remove(ENCODED_CERTIFICATES.getKeyName());
|
||||
addFileBaseTrustStoreOptions(config);
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
sslContextFactory.checkedExpiry = false;
|
||||
TrustManagerFactory trustManagerFactory = sslContextFactory.buildTrustManagerFactory();
|
||||
Assert.assertNotNull(trustManagerFactory);
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void buildKeyManagerFactoryWithInvalidKeystoreFile() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
config.put("keystore", "/this/is/probably/not/a/file/on/your/test/machine");
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
sslContextFactory.checkedExpiry = false;
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void buildKeyManagerFactoryWithBadPassword() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addKeyStoreOptions(config);
|
||||
config.put("keystore_password", "HomeOfBadPasswords");
|
||||
|
||||
DefaultSslContextFactory defaultSslContextFactoryImpl = new DefaultSslContextFactory(config);
|
||||
defaultSslContextFactoryImpl.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildKeyManagerFactoryHappyPath() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory1 = new PEMBasedSslContextFactory(config);
|
||||
// Make sure the exiry check didn't happen so far for the private key
|
||||
Assert.assertFalse(sslContextFactory1.checkedExpiry);
|
||||
|
||||
addKeyStoreOptions(config);
|
||||
PEMBasedSslContextFactory sslContextFactory2 = new PEMBasedSslContextFactory(config);
|
||||
// Trigger the private key loading. That will also check for expired private key
|
||||
sslContextFactory2.buildKeyManagerFactory();
|
||||
// Now we should have checked the private key's expiry
|
||||
Assert.assertTrue(sslContextFactory2.checkedExpiry);
|
||||
|
||||
// Make sure that new factory object preforms the fresh private key expiry check
|
||||
PEMBasedSslContextFactory sslContextFactory3 = new PEMBasedSslContextFactory(config);
|
||||
Assert.assertFalse(sslContextFactory3.checkedExpiry);
|
||||
sslContextFactory3.buildKeyManagerFactory();
|
||||
Assert.assertTrue(sslContextFactory3.checkedExpiry);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void buildKeyManagerFactoryWithConflictingPasswordConfigs() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addKeyStoreOptions(config);
|
||||
config.put("keystore_password", config.get("keyPassword") + "-conflict");
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildKeyManagerFactoryWithMatchingPasswordConfigs() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addKeyStoreOptions(config);
|
||||
config.put("keystore_password", config.get("keyPassword"));
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildFileBasedKeyManagerFactoryHappyPath() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory1 = new PEMBasedSslContextFactory(config);
|
||||
// Make sure the expiry check didn't happen so far for the private key
|
||||
Assert.assertFalse(sslContextFactory1.checkedExpiry);
|
||||
|
||||
addFileBaseKeyStoreOptions(config);
|
||||
PEMBasedSslContextFactory sslContextFactory2 = new PEMBasedSslContextFactory(config);
|
||||
// Trigger the private key loading. That will also check for expired private key
|
||||
sslContextFactory2.buildKeyManagerFactory();
|
||||
// Now we should have checked the private key's expiry
|
||||
Assert.assertTrue(sslContextFactory2.checkedExpiry);
|
||||
|
||||
// Make sure that new factory object preforms the fresh private key expiry check
|
||||
PEMBasedSslContextFactory sslContextFactory3 = new PEMBasedSslContextFactory(config);
|
||||
Assert.assertFalse(sslContextFactory3.checkedExpiry);
|
||||
sslContextFactory3.buildKeyManagerFactory();
|
||||
Assert.assertTrue(sslContextFactory3.checkedExpiry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildKeyManagerFactoryWithUnencryptedKey() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addUnencryptedKeyStoreOptions(config);
|
||||
|
||||
Assert.assertTrue("Unencrypted Key test must not specify a key password",
|
||||
StringUtils.isEmpty((String) config.get(KEY_PASSWORD.getKeyName())));
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildKeyManagerFactoryWithFileBasedUnencryptedKey() throws IOException
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addFileBaseUnencryptedKeyStoreOptions(config);
|
||||
|
||||
Assert.assertTrue("Unencrypted Key test must not specify a key password",
|
||||
StringUtils.isEmpty((String) config.get(KEY_PASSWORD.getKeyName())));
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
sslContextFactory.buildKeyManagerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableOpenSslForInJvmDtests()
|
||||
{
|
||||
// The configuration name below is hard-coded intentionally to make sure we don't break the contract without
|
||||
// changing the documentation appropriately
|
||||
System.setProperty("cassandra.disable_tcactive_openssl", "true");
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
PEMBasedSslContextFactory sslContextFactory = new PEMBasedSslContextFactory(config);
|
||||
Assert.assertEquals(SslProvider.JDK, sslContextFactory.getSslProvider());
|
||||
System.clearProperty("cassandra.disable_tcactive_openssl");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMultiplePrivateKeySources()
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addUnencryptedKeyStoreOptions(config);
|
||||
|
||||
// Check with a valid file path for the keystore
|
||||
addFileBaseUnencryptedKeyStoreOptions(config);
|
||||
new PEMBasedSslContextFactory(config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiplePrivateKeySourcesWithInvalidKeystorePath()
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
addUnencryptedKeyStoreOptions(config);
|
||||
|
||||
// Check with an invalid file path for the keystore
|
||||
config.put("keystore", "/path/to/nowhere");
|
||||
new PEMBasedSslContextFactory(config);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMultipleTrustedCertificatesSources()
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
// Check with a valid file path for the truststore
|
||||
addFileBaseTrustStoreOptions(config);
|
||||
new PEMBasedSslContextFactory(config);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleTrustedCertificatesSourcesWithInvalidTruststorePath()
|
||||
{
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.putAll(commonConfig);
|
||||
|
||||
// Check with an invalid file path for the truststore
|
||||
config.put("truststore", "/path/to/nowhere");
|
||||
new PEMBasedSslContextFactory(config);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.config.Config;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
|
||||
public class PEMJKSSslContextFactoryConfigTest
|
||||
{
|
||||
@BeforeClass
|
||||
public static void setupDatabaseDescriptor()
|
||||
{
|
||||
System.setProperty("cassandra.config", "cassandra-pem-jks-sslcontextfactory.yaml");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownDatabaseDescriptor() {
|
||||
System.clearProperty("cassandra.config");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPEMAndJKSCombination() throws SSLException
|
||||
{
|
||||
|
||||
Config config = DatabaseDescriptor.loadConfig();
|
||||
config.client_encryption_options.applyConfig();
|
||||
|
||||
Assert.assertEquals("org.apache.cassandra.security.PEMBasedSslContextFactory",
|
||||
config.client_encryption_options.ssl_context_factory.class_name);
|
||||
Assert.assertEquals(config.client_encryption_options.ssl_context_factory.class_name,
|
||||
config.client_encryption_options.sslContextFactoryInstance.getClass().getName());
|
||||
PEMBasedSslContextFactory clientSslContextFactory =
|
||||
(PEMBasedSslContextFactory)config.client_encryption_options.sslContextFactoryInstance;
|
||||
clientSslContextFactory.buildKeyManagerFactory();
|
||||
clientSslContextFactory.buildTrustManagerFactory();
|
||||
|
||||
config.server_encryption_options.applyConfig();
|
||||
|
||||
Assert.assertEquals("org.apache.cassandra.security.DefaultSslContextFactory",
|
||||
config.server_encryption_options.ssl_context_factory.class_name);
|
||||
Assert.assertEquals(config.server_encryption_options.ssl_context_factory.class_name,
|
||||
config.server_encryption_options.sslContextFactoryInstance.getClass().getName());
|
||||
DefaultSslContextFactory serverSslContextFactory =
|
||||
(DefaultSslContextFactory)config.server_encryption_options.sslContextFactoryInstance;
|
||||
serverSslContextFactory.buildKeyManagerFactory();
|
||||
serverSslContextFactory.buildTrustManagerFactory();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,454 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.security;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PEMReaderTest
|
||||
{
|
||||
private static final String encoded_encrypted_key =
|
||||
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"MIIE6jAcBgoqhkiG9w0BDAEDMA4ECOWqSzq5PBIdAgIFxQSCBMjXsCK30J0aT3J/\n" +
|
||||
"g5kcbmevTOY1pIhJGbf5QYYrMUPiuDK2ydxIbiPzoTE4/S+OkCeHhlqwn/YydpBl\n" +
|
||||
"xgjZZ1Z5rLJHO27d2biuESqanDiBVXYuVmHmaifRnFy0uUTFkStB5mjVZEiJgO29\n" +
|
||||
"L83hL60uWru71EVuVriC2WCfmZ/EXp6wyYszOqCFQ8Quk/rDO6XuaBl467MJbx5V\n" +
|
||||
"sucGT6E9XKNd9hB14/Izb2jtVM5kqKxoiHpz1na6yhEYJiE5D1uOonznWjBnjwB/\n" +
|
||||
"f0x+acpDfVDoJKTlRdz+DEcbOF7mb9lBVVjP6P/AAsmQzz6JKwHjvCrjYfQmyyN8\n" +
|
||||
"RI4KRQnWgm4L3dtByLqY8HFU4ogisCMCgI+hZQ+OKMz/hoRO540YGiPcTRY3EOUR\n" +
|
||||
"0bd5JxU6tCJDMTqKP9aSL2KmLoiLowdMkSPz7TCzLsZ2bGJemuCfpAs4XT1vXCHs\n" +
|
||||
"evrUbOnh8et1IA8mZ9auThfqsZtNagJLEXA6hWIKp1FfVL3Q49wvMKZt4eTn/zwU\n" +
|
||||
"tLL0m5yPo6/HAaOA3hbm/oghZS0dseshXl7PZrmZQtvYnIvjyoxEL7ducYDQCDP6\n" +
|
||||
"wZ7Nzyh1QZAauSS15hl3vLFRZCA9hWAVgwQAviTvhB342O0i9qI7TQkcHk+qcTPN\n" +
|
||||
"K+iGNbFZ8ma1izXNKSJ2PgI/QqFNIeJWvZrb9PhJRmaZVsTJ9fERm1ewpebZqkVv\n" +
|
||||
"zMqMhlKgx9ggAaSKgnGZkwXwB6GrSbbzUrwRCKm3FieD1QE4VVYevaadVUU75GG5\n" +
|
||||
"mrFKorJEH7kFZlic8OTjDksYnHbcgU36XZrGEXa2+ldVeGKL3CsXWciaQRcJg8yo\n" +
|
||||
"WQDjZpcutGI0eMJWCqUkv8pYZC2/wZU4htCve5nVJUU4t9uuo9ex7lnwlLWPvheQ\n" +
|
||||
"jUBMgzSRsZ+zwaIusvufAAxiKK/cJm4ubZSZPIjBbfd4U7VPxtirP4Accydu7EK6\n" +
|
||||
"eG/MZwtAMFNJxfxUR+/aYzJU/q1ePw7fWVHrpt58t/22CX2SJBEiUGmSmuyER4Ny\n" +
|
||||
"DPw6d6mhvPUS1jRhIZ9A81ht8MOX7VL5uVp307rt7o5vRpV1mo0iPiRHzGscMpJn\n" +
|
||||
"AP36klEAUNTf0uLTKZa7KHiwhn5iPmsCrENHkOKJjxhRrqHjD2wy3YHs3ow2voyY\n" +
|
||||
"Ua4Cids+c1hvRkNEDGNHm4+rKGFOGOsG/ZU7uj/6gflO4JXxNGiyTLflqMdWBvow\n" +
|
||||
"Zd7hk1zCaGAAn8nZ0hPweGxQ4Q30I9IBZrimGxB0vjiUqNio9+qMf33dCHFJEuut\n" +
|
||||
"ZGJMaUGVaPhXQcTy4uD5hzsPZV5xcsU4H3vBYyBcZgrusJ6OOgkuZQaU7p8rWQWr\n" +
|
||||
"bUEVbXuZdwEmxsCe7H/vEVv5+aA4sF4kWnMMFL7/LIYaiEzkTqdJlRv/KyJJgcAH\n" +
|
||||
"hg2BvR3XTAq8wiX0C98CdmTbsx2eyQdj5tCU606rEohFLKUxWkJYAKxCiUbxGGpI\n" +
|
||||
"RheVmxkef9ErxJiq7hsAsGrSJvMtJuDKIasnD14SOEwD/7jRAq6WdL9VLpxtzlOw\n" +
|
||||
"pWnIl8kUCO3WoaG9Jf+ZTIv2hnxJhaSzYrdXzGPNnaWKhBlwnXJRvQEdrIxZOimP\n" +
|
||||
"FujZhqbKUDbYAcqTkoQ=\n" +
|
||||
"-----END ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV\n" +
|
||||
"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n" +
|
||||
"VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh\n" +
|
||||
"Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx\n" +
|
||||
"EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu\n" +
|
||||
"a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw\n" +
|
||||
"FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
|
||||
"MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d\n" +
|
||||
"ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy\n" +
|
||||
"q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2\n" +
|
||||
"TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto\n" +
|
||||
"TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA\n" +
|
||||
"YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD\n" +
|
||||
"N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v\n" +
|
||||
"iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh\n" +
|
||||
"IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv\n" +
|
||||
"6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG\n" +
|
||||
"qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa\n" +
|
||||
"HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru\n" +
|
||||
"n3MVF9w=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
private static final String encoded_certificates =
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV\n" +
|
||||
"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n" +
|
||||
"VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh\n" +
|
||||
"Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx\n" +
|
||||
"EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu\n" +
|
||||
"a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw\n" +
|
||||
"FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
|
||||
"MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d\n" +
|
||||
"ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy\n" +
|
||||
"q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2\n" +
|
||||
"TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto\n" +
|
||||
"TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA\n" +
|
||||
"YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD\n" +
|
||||
"N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v\n" +
|
||||
"iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh\n" +
|
||||
"IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv\n" +
|
||||
"6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG\n" +
|
||||
"qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa\n" +
|
||||
"HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru\n" +
|
||||
"n3MVF9w=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
private static final String encoded_key =
|
||||
"-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOSZVf8dLj1xLw\n" +
|
||||
"efqjbogbAwhwRXd3tmEfQY1zHyudJF3XR1T0Xp26BKNvAYUxxZRDNg16M3prPRZv\n" +
|
||||
"wkhDJdE9NaN+BpZPJUavRsZOfGDq/CHN8j/2PPKrn3G/b065JjV3GZjfV/Sln047\n" +
|
||||
"DeZptaSyOg7ZN7F8qjGqxEcnw+szV/wTzhnjGjZMlcbOm4jFGQAn6xUOooQCGsoB\n" +
|
||||
"9FgxKB0nvNG3xVe/2eCNfbS4DabT3Y1wfQqZ62hOa5ZS0rwT+pw3tQs3zFFY1Sfi\n" +
|
||||
"G7qYbqZrKTheWIZGojVVm6mqH4yA2ofOe5N3RsBitCwU/D0dpnaG9Wcl98nmXueM\n" +
|
||||
"B6Rk04v7AgMBAAECggEAYnxIKjrFz/JkJ5MmiszM5HV698r9YB0aqHnFIHPoykIL\n" +
|
||||
"uiCjiumantDrFsCkosixULwvI/BRwbxstTpyrheU9psT6P1CONICVPvV8ylgJAYU\n" +
|
||||
"l+ofn56cEXKxVuICSWFLDH7pM1479g+IJJQAchbKQpqxAGTuMu3SpvJolfuj5srt\n" +
|
||||
"bM7/RYhJFLwDuvHNA3ivlogMneItP03+C25aaxstM+lBuBf68+n78zMgSvt6J/6Y\n" +
|
||||
"G2TOMKnxveMlG2qu9l2lAw/2i8daG/qre08nTH7wpRx0gZLZqNpe45exkrzticzF\n" +
|
||||
"FgWYjG2K2brX21jqHroFgMhdXF7zhhRgLoIeC0BrIQKBgQDCfGfWrJESKBbVai5u\n" +
|
||||
"7wqD9nlzjv6N6FXfTDOPXO1vz5frdvtLVWbs0SMPy+NglkaZK0iqHvb9mf2of8eC\n" +
|
||||
"0D5cmewjn7WCDBQMypIMYgT912ak/BBVuGXcxb6UgD+xARfSARo2C8NG1hfprw1W\n" +
|
||||
"ad14CjS5xhFMs44HpVYhI7iPYwKBgQC7SqVG/b37vZ7CINemdvoMujLvvYXDJJM8\n" +
|
||||
"N21LqNJfVXdukdH3T0xuLnh9Z/wPHjJDMF/9+1foxSEPHijtyz5P19EilNEC/3qw\n" +
|
||||
"fI19+VZoY0mdhPtXSGzy+rbTE2v71QgwFLizSos14Gr+eNiIjF7FYccK05++K/zk\n" +
|
||||
"cd8ZA3bwiQKBgQCl+HTFBs9mpz+VMOAfW2+l3hkXPNiPUc62mNkHZ05ZNNd44jjh\n" +
|
||||
"uSf0wSUiveR08MmevQlt5K7zDQ8jVKh2QjB15gVXAVxsdtJFeDnax2trFP9LnLBz\n" +
|
||||
"9sE2/qn9INU5wK0LUlWD+dXUBbCyg+jl7cJKRqtoPldVFYYHkFlIPqup8QKBgHXv\n" +
|
||||
"hyuw1FUVDkdHzwOvn70r8q8sNHKxMVWVwWkHIZGOi+pAQGrusD4hXRX6yKnsZdIR\n" +
|
||||
"QCD6iFy25R5T64nxlYdJaxPPid3NakB/7ckJnPOWseBSwMIxhQlr/nvjmve1Kba9\n" +
|
||||
"FaEwq4B9lGIxToiNe4/nBiM3JzvlDxX67nUdzWOhAoGAdFvriyvjshSJ4JHgIY9K\n" +
|
||||
"37BVB0VKMcFV2P8fLVWO5oyRtE1bJhU4QVpQmauABU4RGSojJ3NPIVH1wxmJeYtj\n" +
|
||||
"Q3b7EZaqI6ovna2eK2qtUx4WwxhRaXTT8xueBI2lgL6sBSTGG+K69ZOzGQzG/Mfr\n" +
|
||||
"RXKInnLInFD9JD94VqmMozo=\n" +
|
||||
"-----END PRIVATE KEY-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV\n" +
|
||||
"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n" +
|
||||
"VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh\n" +
|
||||
"Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx\n" +
|
||||
"EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu\n" +
|
||||
"a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw\n" +
|
||||
"FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
|
||||
"MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d\n" +
|
||||
"ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy\n" +
|
||||
"q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2\n" +
|
||||
"TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto\n" +
|
||||
"TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA\n" +
|
||||
"YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD\n" +
|
||||
"N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v\n" +
|
||||
"iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh\n" +
|
||||
"IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv\n" +
|
||||
"6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG\n" +
|
||||
"qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa\n" +
|
||||
"HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru\n" +
|
||||
"n3MVF9w=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
private static final String encoded_unencrypted_ec_private_key =
|
||||
"-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgMLP6H2Wdl28J5PHU\n" +
|
||||
"gMLApCsjONhbyMd5br0byJaQpXShRANCAASmX26IPehdE1wdLW2fVndT9QbjURro\n" +
|
||||
"h74aMnzlmq8GIBWnRzpd+JVJlHgeWLZIDwapthGCYUGivtH27wiO3g7d\n" +
|
||||
"-----END PRIVATE KEY-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIBizCCATACCQCtgEKhNta70DAKBggqhkjOPQQDAjBNMQswCQYDVQQGEwJVUzEL\n" +
|
||||
"MAkGA1UECAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMREwDwYDVQQKDAhQZXJzb25h\n" +
|
||||
"bDELMAkGA1UECwwCSVQwHhcNMjExMDE5MDAzMDU4WhcNMjIxMDE0MDAzMDU4WjBN\n" +
|
||||
"MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCFNhbiBKb3NlMREw\n" +
|
||||
"DwYDVQQKDAhQZXJzb25hbDELMAkGA1UECwwCSVQwWTATBgcqhkjOPQIBBggqhkjO\n" +
|
||||
"PQMBBwNCAASmX26IPehdE1wdLW2fVndT9QbjURroh74aMnzlmq8GIBWnRzpd+JVJ\n" +
|
||||
"lHgeWLZIDwapthGCYUGivtH27wiO3g7dMAoGCCqGSM49BAMCA0kAMEYCIQDsNMGL\n" +
|
||||
"b4+BEhgNXaXyHWkezUO/3hCmLDw2gUdwMXG+JQIhAIAm8wALKbb9jJDgFQTHyqGJ\n" +
|
||||
"AVAkzYOwmRMYC9BHKjNs\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
private static final String encoded_encrypted_key_with_multiplecerts_in_chain =
|
||||
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"MIIE6TAbBgkqhkiG9w0BBQMwDgQI4QuRiKYzf88CAggABIIEyPRVmPp38SIFr8H3\n" +
|
||||
"wi+oc6b+HJH7SPflXO6XZe4Tignw/aSyBTsLm2dWrzojRAYMIRd1xC7yQ2ffYrvx\n" +
|
||||
"uoYbtOQeAminNqvwXdRTnwu6oC0rxdBT8RQ9NK7xL2tQyD/shmOeTJG/glXxaeqS\n" +
|
||||
"rT0CZ5P5GJh6xdIWLEu3lEa3NSWVFE2YacUphmxBoaWjBjsJfWTgkF665SgP+2lh\n" +
|
||||
"8R2WTcHrHjD8jR4jHB03wlup0LOmOwzplUmqHB9TyuA4wF6tlJajwBcPa0PNI6ny\n" +
|
||||
"e9YcdcRr7Y0IxnPQr7PhQNV5AQb9TivwX4WaZxR+BXtwMglp+mz0ohjwLS3z6pqr\n" +
|
||||
"tLrFhv2qcacSl+CKukFb9umV/QBkUk/iu+jwLcNJKPC965GWdieNbO0akBQpQsUN\n" +
|
||||
"mqaF9DYHogW5lRnybl8WWPIR8tXmSCbSUIgzw4lRK+o15I4vaMI0NfkwFD/2y1sn\n" +
|
||||
"t3m9LnVBukkpx3g/CPKd9PbZZeWpOTrnRJQfOu9Fj2lmkpGp0peCBqLJpO0pieVl\n" +
|
||||
"87EQ0ZCErtAGLGIAhWnDUqRK0MaWZ+DMQNKYn5klF4YTVBkfRc9tQbIgBaa77wvz\n" +
|
||||
"gvVWBuJtTFpCt9c8jByTH1gLbchC4bhLsy1nO7moevypMmNW4rqw9x5f0EIR3zCU\n" +
|
||||
"L5/buoIh91TG5JB7BaIbVHtbB/Y2siARRXJibuw3ChBjqPOfzQ66j//NCMqhfTwT\n" +
|
||||
"x2wn7L1BB4xyLJgVW9803FUTzaaL3EvJjzpdvrGC7vzcB6Jd0La9cjHhWSAPOKro\n" +
|
||||
"nD9XPCbgLs10vW9g1Tc8drnZklhw6f7xrIQhWFg6VlwmVpvCQhEpX48rCCo2PH9X\n" +
|
||||
"uzeJA+oqFEH3zfDp0r+q6jbAl+5TkkbBBgC2GCoI1vTYSKaWjeKKHkgzGG0QQLAz\n" +
|
||||
"YXWMXvWKOME4wVPkeVxJv80RqDv0JsoOrnVoaFAzAHJMWa7UZQnjkrbVz/y8ZbV4\n" +
|
||||
"oLJjQjvuOnU2PoXXs6SXbzOs1xx5zbX1UUH3Wc7/CCaUec2hemQJ5m6b1XJciyrY\n" +
|
||||
"GHpMKWtXky9Mo1ruTP7ZH1nk03b4PTObKSx2gQD5AZ/ASuTeahMqMb/2PJkDkpHA\n" +
|
||||
"sy8b1zOn2YTbf4K6NWVNIOkiaApmKhhX0Af6Lg8Wr2ymRTXdp/Um8f+SQLADpB/F\n" +
|
||||
"xOydEN622wmihKDge9DrUFqPG/bdIiRGLXLg8efNboC6/cn/i/sheO7/YlrvcUNo\n" +
|
||||
"qxDa/Bb1N/DgmtgAQ1ZP+AKjk6FKkwZRF1X/VZkZ6auscDlaPetF7razPeIJUrKN\n" +
|
||||
"z/x4AD2txGYKmeYztYR577hPXBw+PPKdggRhIugb6z5Tk89C2pDEwfnByA/wcGJr\n" +
|
||||
"w5avxrubosPrp0QtJpZMzouOvcD52VUiZzDfu9dqI/hpinyt5rETj5E19qxBjIZt\n" +
|
||||
"X3Nq5lY2ktbyqVIo8Z8w4EUU+3XHZKqDwjyYvjxCxv5lVVnqvQrH9h3kENBMrPYQ\n" +
|
||||
"4XonQHpUGG7g7pA3ylmHi+nEedr0H5qKHzyFZlRdI7CLVNoAtBSdwvmtGd2cVVXU\n" +
|
||||
"EaToKNbHPXXYYPX/oVAWZYwD7PHXIRJkiEZnrFARNhLypicU7yjvejUPXcVy5HMh\n" +
|
||||
"XqEbrODPp4VXfbYhVg==\n" +
|
||||
"-----END ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDXjCCAkYCAhI0MA0GCSqGSIb3DQEBBAUAMHcxCzAJBgNVBAYTAlVTMRMwEQYD\n" +
|
||||
"VQQIDApDYWxpZm9ybmlhMREwDwYDVQQHDAhTYW4gSm9zZTEXMBUGA1UECgwOUGVy\n" +
|
||||
"c29uYWwsIEluYy4xEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDG15ZG9tYWlu\n" +
|
||||
"LmNvbTAeFw0yMTExMjIyMjQ5MzlaFw0yMjExMjIyMjQ5MzlaMHIxCzAJBgNVBAYT\n" +
|
||||
"AlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQHDAhTYW4gSm9zZTEXMBUG\n" +
|
||||
"A1UECgwOUGVyc29uYWwsIEluYy4xCzAJBgNVBAsMAklUMRUwEwYDVQQDDAxteWRv\n" +
|
||||
"bWFpbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5fdA7wwD9\n" +
|
||||
"9e5RcdLscvGB+hqJUEHuNC53SYKg5X4Sf0H4ExQUbsy8UaoWzWHhgGbCtTvUVavl\n" +
|
||||
"72xsO74ei0EblopW7QknF0kaTO8Vi3mxhUAdtZFLG/o0NS9J16HdGDGojJwuqU9+\n" +
|
||||
"sMQt1w0HCTMlriELnxaUFKP7M9b0uK5VODEKJ38QKNGXUDt66D7BVYeT/6hz2cXK\n" +
|
||||
"QWDoHk/JadALSzW5ES8KIHfxCLnl2TcKxQhJ4CnL8qeGvc8N3VyTh2AXajaJW5RB\n" +
|
||||
"8Oy4CVoYxcdmP1IapxCD+yNcmNt9XpUTD+6eM5gnvtbye+MSfwPz2MW+fWEDZXOv\n" +
|
||||
"3VxhJyTRFNVTAgMBAAEwDQYJKoZIhvcNAQEEBQADggEBADYK/pn6QG7bvUL0Xnnw\n" +
|
||||
"1KPf1nx36gfJE2V0bNk4uyNNeYufMKS8gPLzC+a3RigCEDc+hIZFE5BJexHd7DXA\n" +
|
||||
"CWgHZJtdjM/Xlgoxbf1yfGV3DWeIZlNFSFZujBIpbm1Ug2BAeV31YRWODPZlUSEZ\n" +
|
||||
"0jv8NEs8/oEz9bM4jwRdn09lo4D9hE6o8qDnrzmN2LBZP5dDIJ6g/M+mq/SJFnho\n" +
|
||||
"qBrfUABZhbgk2+tkZ89OI2xpASCLo6X/vqua2iho6km3x+cz6EI9BbvVr6xOOdVK\n" +
|
||||
"m6gs/Bi4MGTh35jdmvyXoyBUOd1w3yBBj86qbEt2ZHYqreRTxntQYx06598Q9Dsi\n" +
|
||||
"xdg=\n" +
|
||||
"-----END CERTIFICATE-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDajCCAlICCQD/7mxPcMTPIDANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJV\n" +
|
||||
"UzETMBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UEBwwIU2FuIEpvc2UxFzAVBgNV\n" +
|
||||
"BAoMDlBlcnNvbmFsLCBJbmMuMRAwDgYDVQQLDAdSb290IENBMRUwEwYDVQQDDAxt\n" +
|
||||
"eWRvbWFpbi5jb20wHhcNMjExMTIyMjExODAwWhcNNDkwNDA5MjExODAwWjB3MQsw\n" +
|
||||
"CQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UEBwwIU2FuIEpv\n" +
|
||||
"c2UxFzAVBgNVBAoMDlBlcnNvbmFsLCBJbmMuMRAwDgYDVQQLDAdSb290IENBMRUw\n" +
|
||||
"EwYDVQQDDAxteWRvbWFpbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" +
|
||||
"AoIBAQCkIwuNGv3ckew/o2UwaDlYgXH9bh1jap4ZCb6qpjvR3tq9nCerY6XMli0Z\n" +
|
||||
"Xxg0wMHDNUr/jmVYIdQjbz0DVNz/l6ZBJHzHCEgqR40pNM3NgC5sDyuNhF3WLNvj\n" +
|
||||
"WgHEwYosfb/9kFRjKUPqqtJ0ccj87OP3XrE/4epCTdJdmugroAQSpXt1ZZfwwPO4\n" +
|
||||
"K27DzMD9W01EmeLcUhMfrpUnKGCfL22c0sZZm/6Khk4BExC3pSILP/NREKeUEAHw\n" +
|
||||
"+rxhNqbUyD/e4/DutdtJ5zONA+GVVGYCpu1Iy0W78Jve4MD2/TFPcEzf5omiWpPz\n" +
|
||||
"WjpOWayD43ur0SZnYJ5haUlZ+bSLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABqN\n" +
|
||||
"/eb+mKEw2zklPZuzy5uhOc7ImG2LP/ha3oc2ntwkqZQ2LmVA/2ZNVfcNrRRngIfn\n" +
|
||||
"Ir9Kual7djmKmIQvanpnSyXOKOlIiuN0VOrewgzlBZZwlFJL/AH1l7K9uZfBbV5h\n" +
|
||||
"oFfaR9wc+vRGsg3nqO9+hEuk6xbp0jk8QCt26EVhEPlijxzbxTQYiNPNSLuf/kPW\n" +
|
||||
"C9xtIKSWIDT4N6DtH7BtHGQKQdRJ2b4SSUF4joEmBe6jcrLBeDybmuFtKqlVJKUk\n" +
|
||||
"tzBd9CPseqMML1c518KzxlSkXNxTCa7PWEnuN5atLZ+pGGjxtGcDKkrZ9Cgi09G8\n" +
|
||||
"MzB8b4C/goypyhBNlyI=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
private static final String encoded_encrypted_dsa_key =
|
||||
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"MIICkTAbBgkqhkiG9w0BBQMwDgQIL1GiUDca2x0CAggABIICcCrSiNBy5kZNC7RK\n" +
|
||||
"fVF3IZ9Ecl00OYIjvBhlWGkaiNt9ZAeWPpYx57HSQAygzJ8ba+3jtz1dV8Bhz5D5\n" +
|
||||
"4kggzolC820I/QLPxClH5R6ZPzDHGu/JFuNNZWASq2JHZfolEP+itdnz0F6VvQx9\n" +
|
||||
"imngOGIJMkRWIzvwuCnq8xpNSEJHJcs8kyLBP/3qT+kUiEwJ5KrmJ8DQsHluwpyo\n" +
|
||||
"GoiGEtiA+MNUSzc/DkuLxhC45k7K4afe4QzpWl9eR/z91F9Q06jdc5mnUWke8qCg\n" +
|
||||
"ZopBVWbSI6fMZVlqLxKeSFljDZ+moW+2/Lh8cjEvNMccVTwWQE7JH9RLnVogqixV\n" +
|
||||
"HIpN58wrlHd4uMVH47wD18A11AGEbghO1MEShX4SCEJIdZsr67bNx8mIkhSWjqAx\n" +
|
||||
"BT9OmITzdbnR9sHi4CyEWhGMAMDp7YBySwpt+U7Y6DvRwWJbXUaF8zYJUlrp2IbH\n" +
|
||||
"qdSE+oJPKxGB1s2B5KGrJUA0JkElkBUYm6ghXZlTI32w8HoV9fDOhjx1ATu7SdZY\n" +
|
||||
"8DX0mwVVdc88Msr5RPxdeB3V4yN2iFJs4i3usicPkB0N+29LJ/lKQlm/pia0yl9j\n" +
|
||||
"yDNN3R0RiCJdYHme4t1PqRqeTfjMauz05ObennQmkzMxD8mlBZ0zhaKL5I4TuQod\n" +
|
||||
"PITFgYihTR9OYfa8lryvHQNCIi5iZ6M9myLUxbjPoeVBdp8pSlMAjmekEHo47vn3\n" +
|
||||
"7IGF7AfnKVNymc/1Kim3WQx8D7nryCb8EUyb7BuNA7izGKq+NW51l39J8RGVcFSx\n" +
|
||||
"sVkpFUbqGXusUgLWWwi21EJHCJceFnOWJRgsoeqNeCt5VCUSag==\n" +
|
||||
"-----END ENCRYPTED PRIVATE KEY-----\n" +
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIEeDCCBB4CCQD9UojL1A7cmzAJBgcqhkjOOAQDME0xCzAJBgNVBAYTAlVTMQsw\n" +
|
||||
"CQYDVQQIDAJDQTERMA8GA1UEBwwIU2FuIEpvc2UxETAPBgNVBAoMCFBlcnNvbmFs\n" +
|
||||
"MQswCQYDVQQLDAJJVDAeFw0yMTEwMTgyMzU0MjRaFw0yMjEwMTgyMzU0MjRaME0x\n" +
|
||||
"CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIU2FuIEpvc2UxETAP\n" +
|
||||
"BgNVBAoMCFBlcnNvbmFsMQswCQYDVQQLDAJJVDCCA0YwggI5BgcqhkjOOAQBMIIC\n" +
|
||||
"LAKCAQEAzxMsktQYQ06q71pwqWAa9YvDIkF34RJgQT5tqCZdzwtP7HXyrwaZBgLK\n" +
|
||||
"oC4grIPKyUlPmIbm+oucucbTzDCYCx2d09VMVR471vqJi7vRCYnBIqMTTOSvbTGw\n" +
|
||||
"8VuwA2prSt4TiqFYeqYM0Afv/KrI2MLNTP+z8RFfiLkijZIxZ9CzyHmTOEqHxOft\n" +
|
||||
"Ln145NNcuPy3U7Bmh5k7i+RR+5jYweuLzOfTK4bTUnG111mjAhAeo+ST14ydfiuQ\n" +
|
||||
"2e85UwLucVheh4REqm+n7g0k0B/+nG+9Os1nxfQVRVKHP4/iTrNLpf35EoPeh9XT\n" +
|
||||
"D0BtV9lqQuttCB1aPLH66TKl9v4FowIhAMXhJ3LooBT7ypUWMtN07FvpPpoLERBr\n" +
|
||||
"Pk9MeGwQnBPFAoIBAAcVYJ+RH1i8JFyD8MUwwOKgkmVzbRvc28B5F17oek76R6fi\n" +
|
||||
"yyqyhHrkxmjwxktXuwRlWQBJqCTqpmMstLplqsVjcETHo7KRaHgDpT9tHf14PZvP\n" +
|
||||
"qpoxYNpa5z4wPpOFhZ3K6VVaFUSlqSSHhaS1HqVzZC0FefFFd3TDKu0EWHDDkLM8\n" +
|
||||
"luOxDUMydKpRtrVba+iF4kx9NcCyXjSMhFAOw3cWhGvoq6R3h4UkRJO67pzYtqK4\n" +
|
||||
"yAETPsQKT0c8NUM+VUiPAHL/+f1EqaVtzatk9G0OHWZXgDxuhx2CAM6QfELew+ys\n" +
|
||||
"D/QUUT0tXHQRxRCKmYE+uacwyQx5G0DeCHN0c9gDggEFAAKCAQBFGXF7flzfRH/8\n" +
|
||||
"r/qDuNC+9y3fRtDWXaados+XQkzujizBBK9dkkAd/j/pgP5p7/bRvoeR507Oyrge\n" +
|
||||
"6xBbfE7SlRu0cx08Ihlw7a6mCowMnP0psFBwW7npKJRYPXxRDpu9oUuuJHi1WYp7\n" +
|
||||
"8/Ekg6hG21zAYO0JLGyU6aH5Rvuls754R+rxqveVqLiig5NTnfw7ymLb2kF1z8g7\n" +
|
||||
"fDvX6OS242ceQIQHvq97cGnysEVSlavuHfbh3PKXklh91ip/BYuzanQjiEb97YIU\n" +
|
||||
"DhMQyPGvk+iDdhD0PwgwOZB0P0mL7Xszw6p+lfzUc+g8jETjrnzksnVEg8On6q3Q\n" +
|
||||
"RDJG9VnuMAkGByqGSM44BAMDSQAwRgIhAIay5hyZrwHslGXmTAx498903l7CQsdi\n" +
|
||||
"fUrmGkxbPiZXAiEAitS8+gyG64c0jV7V/u8Z1NEL8MI47K2P9Jbn3cqzz3k=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
private static final String invalid_encoded_private_key =
|
||||
"-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOSZVf8dLj1xLw\n" +
|
||||
"efqjbogbAwhwRXd3tmEfQY1zHyudJF3XR1T0Xp26BKNvAYUxxZRDNg16M3prPRZv\n" +
|
||||
"wkhDJdE9NaN+BpZPJUavRsZOfGDq/CHN8j/2PPKrn3G/b065JjV3GZjfV/Sln047\n" +
|
||||
"DeZptaSyOg7ZN7F8qjGqxEcnw+szV/wTzhnjGjZMlcbOm4jFGQAn6xUOooQCGsoB\n" +
|
||||
"9FgxKB0nvNG3xVe/2eCNfbS4DabT3Y1wfQqZ62hOa5ZS0rwT+pw3tQs3zFFY1Sfi\n" +
|
||||
"G7qYbqZrKTheWIZGojVVm6mqH4yA2ofOe5N3RsBitCwU/D0dpnaG9Wcl98nmXueM\n" +
|
||||
"B6Rk04v7AgMBAAECggEAYnxIKjrFz/JkJ5MmiszM5HV698r9YB0aqHnFIHPoykIL\n" +
|
||||
"uiCjiumantDrFsCkosixULwvI/BRwbxstTpyrheU9psT6P1CONICVPvV8ylgJAYU\n" +
|
||||
"l+ofn56cEXKxVuICSWFLDH7pM1479g+IJJQAchbKQpqxAGTuMu3SpvJolfuj5srt\n" +
|
||||
"bM7/RYhJFLwDuvHNA3ivlogMneItP03+C25aaxstM+lBuBf68+n78zMgSvt6J/6Y\n" +
|
||||
"G2TOMKnxveMlG2qu9l2lAw/2i8daG/qre08nTH7wpRx0gZLZqNpe45exkrzticzF\n" +
|
||||
"FgWYjG2K2brX21jqHroFgMhdXF7zhhRgLoIeC0BrIQKBgQDCfGfWrJESKBbVai5u\n" +
|
||||
"7wqD9nlzjv6N6FXfTDOPXO1vz5frdvtLVWbs0SMPy+NglkaZK0iqHvb9mf2of8eC\n" +
|
||||
"0D5cmewjn7WCDBQMypIMYgT912ak/BBVuGXcxb6UgD+xARfSARo2C8NG1hfprw1W\n" +
|
||||
"ad14CjS5xhFMs44HpVYhI7iPYwKBgQC7SqVG/b37vZ7CINemdvoMujLvvYXDJJM8\n" +
|
||||
"N21LqNJfVXdukdH3T0xuLnh9Z/wPHjJDMF/9+1foxSEPHijtyz5P19EilNEC/3qw\n" +
|
||||
"fI19+VZoY0mdhPtXSGzy+rbTE2v71QgwFLizSos14Gr+eNiIjF7FYccK05++K/zk\n" +
|
||||
"cd8ZA3bwiQKBgQCl+HTFBs9mpz+VMOAfW2+l3hkXPNiPUc62mNkHZ05ZNNd44jjh\n" +
|
||||
"uSf0wSUiveR08MmevQlt5K7zDQ8jVKh2QjB15gVXAVxsdtJFeDnax2trFP9LnLBz\n" +
|
||||
"9sE2/qn9INU5wK0LUlWD+dXUBbCyg+jl7cJKRqtoPldVFYYHkFlIPqup8QKBgHXv\n" +
|
||||
"hyuw1FUVDkdHzwOvn70r8q8sNHKxMVWVwWkHIZGOi+pAQGrusD4hXRX6yKnsZdIR\n" +
|
||||
"QCD6iFy25R5T64nxlYdJaxPPid3NakB/7ckJnPOWseBSwMIxhQlr/nvjmve1Kba9\n" +
|
||||
"FaEwq4B9lGIxToiNe4/nBiM3JzvlDxX67nUdzWOhAoGAdFvriyvjshSJ4JHgIY9K\n" +
|
||||
"37BVB0VKMcFV2P8fLVWO5oyRtE1bJhU4QVpQmauABU4RGSojJ3NPIVH1wxmJeYtj\n" +
|
||||
"Q3b7EZaqI6ovna2eK2qtUx4WwxhRaXTT8xueBI2lgL6sBSTGG+K69ZOzGQzG/Mfr\n" +
|
||||
"RXKInnLInFD9JD94VqmMozoInvalidData=\n" +
|
||||
"-----END PRIVATE KEY-----\n";
|
||||
private static final String invalid_encoded_certificate =
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIIDkTCCAnmgAwIBAgIETxH5JDANBgkqhkiG9w0BAQsFADB5MRAwDgYDVQQGEwdV\n" +
|
||||
"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\n" +
|
||||
"VQQKEwdVbmtub3duMRQwEgYDVQQLDAtzc2xfdGVzdGluZzEZMBcGA1UEAxMQQXBh\n" +
|
||||
"Y2hlIENhc3NhbmRyYTAeFw0xNjAzMTgyMTI4MDJaFw0xNjA2MTYyMTI4MDJaMHkx\n" +
|
||||
"EDAOBgNVBAYTB1Vua25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vu\n" +
|
||||
"a25vd24xEDAOBgNVBAoTB1Vua25vd24xFDASBgNVBAsMC3NzbF90ZXN0aW5nMRkw\n" +
|
||||
"FwYDVQQDExBBcGFjaGUgQ2Fzc2FuZHJhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
|
||||
"MIIBCgKCAQEAjkmVX/HS49cS8Hn6o26IGwMIcEV3d7ZhH0GNcx8rnSRd10dU9F6d\n" +
|
||||
"ugSjbwGFMcWUQzYNejN6az0Wb8JIQyXRPTWjfgaWTyVGr0bGTnxg6vwhzfI/9jzy\n" +
|
||||
"q59xv29OuSY1dxmY31f0pZ9OOw3mabWksjoO2TexfKoxqsRHJ8PrM1f8E84Z4xo2\n" +
|
||||
"TJXGzpuIxRkAJ+sVDqKEAhrKAfRYMSgdJ7zRt8VXv9ngjX20uA2m092NcH0Kmeto\n" +
|
||||
"TmuWUtK8E/qcN7ULN8xRWNUn4hu6mG6mayk4XliGRqI1VZupqh+MgNqHznuTd0bA\n" +
|
||||
"YrQsFPw9HaZ2hvVnJffJ5l7njAekZNOL+wIDAQABoyEwHzAdBgNVHQ4EFgQUcdiD\n" +
|
||||
"N6aylI91kAd34Hl2AzWY51QwDQYJKoZIhvcNAQELBQADggEBAG9q29ilUgCWQP5v\n" +
|
||||
"iHkZHj10gXGEoMkdfrPBf8grC7dpUcaw1Qfku/DJ7kPvMALeEsmFDk/t78roeNbh\n" +
|
||||
"IYBLJlzI1HZN6VPtpWQGsqxltAy5XN9Xw9mQM/tu70ShgsodGmE1UoW6eE5+/GMv\n" +
|
||||
"6Fg+zLuICPvs2cFNmWUvukN5LW146tJSYCv0Q/rCPB3m9dNQ9pBxrzPUHXw4glwG\n" +
|
||||
"qGnGddXmOC+tSW5lDLLG1BRbKv4zxv3UlrtIjqlJtZb/sQMT6WtG2ihAz7SKOBHa\n" +
|
||||
"HOWUwuPTetWIuJCKP7P4mWWtmSmjLy+BFX5seNEngn3RzJ2L8uuTJQ/88OsqgGru\n" +
|
||||
"n3MVF9wInvalidData=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
@Test
|
||||
public void readEncryptedKey() throws IOException, GeneralSecurityException
|
||||
{
|
||||
PrivateKey privateKey = PEMReader.extractPrivateKey(encoded_encrypted_key, "cassandra");
|
||||
Assert.assertNotNull(privateKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readEncryptedDSAKey() throws IOException, GeneralSecurityException
|
||||
{
|
||||
PrivateKey privateKey = PEMReader.extractPrivateKey(encoded_encrypted_dsa_key, "mytest");
|
||||
Assert.assertNotNull(privateKey);
|
||||
}
|
||||
|
||||
@Test(expected = GeneralSecurityException.class)
|
||||
public void readEncryptedDSAKeyWithBadPassword() throws IOException, GeneralSecurityException
|
||||
{
|
||||
try
|
||||
{
|
||||
PEMReader.extractPrivateKey(encoded_encrypted_dsa_key, "bad-password");
|
||||
} catch(GeneralSecurityException e) {
|
||||
Assert.assertTrue(e.getMessage().startsWith("Failed to decrypt the private key data. Either the password " +
|
||||
"provided for the key is wrong or the private key data is " +
|
||||
"corrupted. msg="));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = GeneralSecurityException.class)
|
||||
public void readInvalidEncryptedKey() throws IOException, GeneralSecurityException
|
||||
{
|
||||
// Test by injecting junk data in the given key and making it invalid
|
||||
PrivateKey privateKey = PEMReader.extractPrivateKey(encoded_encrypted_key.replaceAll("\\s",
|
||||
String.valueOf(System.nanoTime())),
|
||||
"cassandra");
|
||||
Assert.assertNotNull(privateKey);
|
||||
}
|
||||
|
||||
@Test(expected = GeneralSecurityException.class)
|
||||
public void readInvalidBase64PrivateKey() throws IOException, GeneralSecurityException
|
||||
{
|
||||
PEMReader.extractPrivateKey(invalid_encoded_private_key);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readUnencryptedKey() throws IOException, GeneralSecurityException
|
||||
{
|
||||
PrivateKey privateKey = PEMReader.extractPrivateKey(encoded_key);
|
||||
Assert.assertNotNull(privateKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readUnencryptedECKey() throws IOException, GeneralSecurityException
|
||||
{
|
||||
PrivateKey privateKey = PEMReader.extractPrivateKey(encoded_unencrypted_ec_private_key);
|
||||
Assert.assertNotNull(privateKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readCertChain() throws GeneralSecurityException
|
||||
{
|
||||
Certificate[] certificates = PEMReader.extractCertificates(encoded_encrypted_key);
|
||||
Assert.assertNotNull("CertChain must not be null", certificates);
|
||||
Assert.assertTrue("CertChain must have only one certificate", certificates.length == 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readCertChainWithMoreThanOneCerts() throws GeneralSecurityException
|
||||
{
|
||||
Certificate[] certificates = PEMReader.extractCertificates(encoded_encrypted_key_with_multiplecerts_in_chain);
|
||||
Assert.assertNotNull("CertChain must not be null", certificates);
|
||||
}
|
||||
|
||||
@Test(expected = GeneralSecurityException.class)
|
||||
public void readInvalidCertificate() throws GeneralSecurityException
|
||||
{
|
||||
// Test by injecting junk data in the given key and making it invalid
|
||||
Certificate[] certificates = PEMReader.extractCertificates(encoded_encrypted_key.replaceAll("\\s",
|
||||
String.valueOf(System.nanoTime())));
|
||||
Assert.assertNotNull("CertChain must not be null", certificates);
|
||||
Assert.assertTrue("CertChain must have only one certificate", certificates.length == 1);
|
||||
}
|
||||
|
||||
@Test(expected = GeneralSecurityException.class)
|
||||
public void readInvalidBase64Certificate() throws GeneralSecurityException
|
||||
{
|
||||
PEMReader.extractCertificates(invalid_encoded_certificate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readTrustedCertificates() throws GeneralSecurityException
|
||||
{
|
||||
Certificate[] certificates = PEMReader.extractCertificates(encoded_certificates);
|
||||
Assert.assertNotNull("Trusted certificate list must not be null", certificates);
|
||||
Assert.assertTrue("Trusted certificate list must have only one certificate", certificates.length == 1);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void tamperSupportedAlgorithms() throws GeneralSecurityException
|
||||
{
|
||||
Set<String> original = PEMReader.SUPPORTED_PRIVATE_KEY_ALGORITHMS;
|
||||
for (int i = 0; i < original.size(); i++)
|
||||
{
|
||||
original.remove("RSA");
|
||||
original.remove("DSA");
|
||||
original.remove("EC");
|
||||
original.add("TAMPERED");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +74,16 @@ public class SSLFactoryTest
|
|||
.withKeyStorePassword("cassandra");
|
||||
}
|
||||
|
||||
private ServerEncryptionOptions addPEMKeystoreOptions(ServerEncryptionOptions options)
|
||||
{
|
||||
ParameterizedClass sslContextFactoryClass = new ParameterizedClass("org.apache.cassandra.security.PEMBasedSslContextFactory",
|
||||
new HashMap<>());
|
||||
return options.withSslContextFactory(sslContextFactoryClass)
|
||||
.withKeyStore("test/conf/cassandra_ssl_test.keystore.pem")
|
||||
.withKeyStorePassword("cassandra")
|
||||
.withTrustStore("test/conf/cassandra_ssl_test.truststore.pem");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSslContextReload_HappyPath() throws IOException, InterruptedException
|
||||
{
|
||||
|
|
@ -106,6 +116,38 @@ public class SSLFactoryTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPEMSslContextReload_HappyPath() throws IOException, InterruptedException
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerEncryptionOptions options = addPEMKeystoreOptions(encryptionOptions)
|
||||
.withInternodeEncryption(ServerEncryptionOptions.InternodeEncryption.all);
|
||||
|
||||
SSLFactory.initHotReloading(options, options, true);
|
||||
|
||||
SslContext oldCtx = SSLFactory.getOrCreateSslContext(options, true, ISslContextFactory.SocketType.CLIENT);
|
||||
File keystoreFile = new File(options.keystore);
|
||||
|
||||
SSLFactory.checkCertFilesForHotReloading(options, options);
|
||||
|
||||
keystoreFile.trySetLastModified(System.currentTimeMillis() + 15000);
|
||||
|
||||
SSLFactory.checkCertFilesForHotReloading(options, options);
|
||||
SslContext newCtx = SSLFactory.getOrCreateSslContext(options, true, ISslContextFactory.SocketType.CLIENT);
|
||||
|
||||
Assert.assertNotSame(oldCtx, newCtx);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
DatabaseDescriptor.loadConfig();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
public void testSslFactorySslInit_BadPassword_ThrowsException() throws IOException
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue