Remove BouncyCastle dependency from runtime (#32193)

* Remove BouncyCastle dependency from runtime

This commit introduces a new gradle  project that contains
 the classes that have a dependency on BouncyCastle. For 
the default distribution, It builds  a jar from those and
 in puts it in a subdirectory of lib
 (/tools/security-cli) along with the BouncyCastle jars. 
This directory is then passed in the
ES_ADDITIONAL_CLASSPATH_DIRECTORIES of the CLI tools 
that use these classes.

BouncyCastle is removed as a runtime dependency (remains
as a compileOnly one) from x-pack core and x-pack security.
This commit is contained in:
Ioannis Kakavas 2018-07-21 00:03:58 +03:00 committed by GitHub
parent 7aa8a0a927
commit aaa8f842d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 294 additions and 172 deletions

View File

@ -49,7 +49,7 @@ CopySpec archiveFiles(CopySpec modulesFiles, String distributionType, boolean os
return copySpec {
into("elasticsearch-${version}") {
into('lib') {
with libFiles
with libFiles(oss)
}
into('config') {
dirMode 0750

View File

@ -227,16 +227,24 @@ configure(subprojects.findAll { ['archives', 'packages'].contains(it.name) }) {
/*****************************************************************************
* Common files in all distributions *
*****************************************************************************/
libFiles = copySpec {
// delay by using closures, since they have not yet been configured, so no jar task exists yet
from { project(':server').jar }
from { project(':server').configurations.runtime }
from { project(':libs:plugin-classloader').jar }
from { project(':distribution:tools:java-version-checker').jar }
from { project(':distribution:tools:launchers').jar }
into('tools/plugin-cli') {
from { project(':distribution:tools:plugin-cli').jar }
from { project(':distribution:tools:plugin-cli').configurations.runtime }
libFiles = { oss ->
copySpec {
// delay by using closures, since they have not yet been configured, so no jar task exists yet
from { project(':server').jar }
from { project(':server').configurations.runtime }
from { project(':libs:plugin-classloader').jar }
from { project(':distribution:tools:java-version-checker').jar }
from { project(':distribution:tools:launchers').jar }
into('tools/plugin-cli') {
from { project(':distribution:tools:plugin-cli').jar }
from { project(':distribution:tools:plugin-cli').configurations.runtime }
}
if (oss == false) {
into('tools/security-cli') {
from { project(':x-pack:plugin:security:cli').jar }
from { project(':x-pack:plugin:security:cli').configurations.compile }
}
}
}
}

View File

@ -126,7 +126,7 @@ Closure commonPackageConfig(String type, boolean oss) {
}
into('lib') {
with copySpec {
with libFiles
with libFiles(oss)
// we need to specify every intermediate directory so we iterate through the parents; duplicate calls with the same part are fine
eachFile { FileCopyDetails fcp ->
String[] segments = fcp.relativePath.segments

View File

@ -57,6 +57,7 @@ import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.isEmptyString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeThat;
import static org.junit.Assume.assumeTrue;
@ -302,5 +303,26 @@ public abstract class ArchiveTestCase extends PackagingTestCase {
}
}
public void test90SecurityCliPackaging() {
assumeThat(installation, is(notNullValue()));
final Installation.Executables bin = installation.executables();
final Shell sh = new Shell();
if (distribution().equals(Distribution.DEFAULT_TAR) || distribution().equals(Distribution.DEFAULT_ZIP)) {
assertTrue(Files.exists(installation.lib.resolve("tools").resolve("security-cli")));
Platforms.onLinux(() -> {
final Result result = sh.run(bin.elasticsearchCertutil + " help");
assertThat(result.stdout, containsString("Simplifies certificate creation for use with the Elastic Stack"));
});
Platforms.onWindows(() -> {
final Result result = sh.run(bin.elasticsearchCertutil + " help");
assertThat(result.stdout, containsString("Simplifies certificate creation for use with the Elastic Stack"));
});
} else if (distribution().equals(Distribution.OSS_TAR) || distribution().equals(Distribution.OSS_ZIP)) {
assertFalse(Files.exists(installation.lib.resolve("tools").resolve("security-cli")));
}
}
}

View File

@ -101,6 +101,7 @@ public class Installation {
public final Path elasticsearchPlugin = platformExecutable("elasticsearch-plugin");
public final Path elasticsearchKeystore = platformExecutable("elasticsearch-keystore");
public final Path elasticsearchTranslog = platformExecutable("elasticsearch-translog");
public final Path elasticsearchCertutil = platformExecutable("elasticsearch-certutil");
private Path platformExecutable(String name) {
final String platformExecutableName = Platforms.WINDOWS

View File

@ -20,7 +20,6 @@ esplugin {
}
dependencyLicenses {
mapping from: /bc.*/, to: 'bouncycastle'
mapping from: /http.*/, to: 'httpclient' // pulled in by rest client
mapping from: /commons-.*/, to: 'commons' // pulled in by rest client
}
@ -38,8 +37,6 @@ dependencies {
// security deps
compile 'com.unboundid:unboundid-ldapsdk:3.2.0'
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
compile 'org.bouncycastle:bcpkix-jdk15on:1.59'
compile project(path: ':modules:transport-netty4', configuration: 'runtime')
testCompile 'org.elasticsearch:securemock:1.2'
@ -116,6 +113,7 @@ task testJar(type: Jar) {
appendix 'test'
from sourceSets.test.output
}
artifacts {
// normal es plugins do not publish the jar but we need to since users need it for Transport Clients and extensions
archives jar

View File

@ -63,7 +63,7 @@ public class CertParsingUtils {
return PathUtils.get(path).normalize();
}
static KeyStore readKeyStore(Path path, String type, char[] password)
public static KeyStore readKeyStore(Path path, String type, char[] password)
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
try (InputStream in = Files.newInputStream(path)) {
KeyStore store = KeyStore.getInstance(type);
@ -108,7 +108,7 @@ public class CertParsingUtils {
return certificates.toArray(new X509Certificate[0]);
}
static List<Certificate> readCertificates(InputStream input) throws CertificateException, IOException {
public static List<Certificate> readCertificates(InputStream input) throws CertificateException, IOException {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
Collection<Certificate> certificates = (Collection<Certificate>) certFactory.generateCertificates(input);
return new ArrayList<>(certificates);
@ -140,7 +140,7 @@ public class CertParsingUtils {
/**
* Creates a {@link KeyStore} from a PEM encoded certificate and key file
*/
static KeyStore getKeyStoreFromPEM(Path certificatePath, Path keyPath, char[] keyPassword)
public static KeyStore getKeyStoreFromPEM(Path certificatePath, Path keyPath, char[] keyPassword)
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
final PrivateKey key = PemUtils.readPrivateKey(keyPath, () -> keyPassword);
final Certificate[] certificates = readCertificates(Collections.singletonList(certificatePath));
@ -168,7 +168,7 @@ public class CertParsingUtils {
/**
* Returns a {@link X509ExtendedKeyManager} that is built from the provided keystore
*/
static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm)
public static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm)
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
kmf.init(keyStore, password);
@ -271,7 +271,7 @@ public class CertParsingUtils {
/**
* Creates a {@link X509ExtendedTrustManager} based on the trust material in the provided {@link KeyStore}
*/
static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm)
public static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm)
throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(keyStore);

View File

@ -22,8 +22,8 @@ dependencies {
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
compile 'com.unboundid:unboundid-ldapsdk:3.2.0'
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
compile 'org.bouncycastle:bcpkix-jdk15on:1.59'
compileOnly 'org.bouncycastle:bcprov-jdk15on:1.59'
compileOnly 'org.bouncycastle:bcpkix-jdk15on:1.59'
// the following are all SAML dependencies - might as well download the whole internet
compile "org.opensaml:opensaml-core:3.3.0"
@ -79,7 +79,6 @@ sourceSets.test.resources {
srcDir '../core/src/test/resources'
}
dependencyLicenses {
mapping from: /bc.*/, to: 'bouncycastle'
mapping from: /java-support|opensaml-.*/, to: 'shibboleth'
mapping from: /http.*/, to: 'httpclient'
}

View File

@ -0,0 +1,20 @@
apply plugin: 'elasticsearch.build'
archivesBaseName = 'elasticsearch-security-cli'
dependencies {
compileOnly "org.elasticsearch:elasticsearch:${version}"
compileOnly xpackProject('plugin:core')
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
compile 'org.bouncycastle:bcpkix-jdk15on:1.59'
testImplementation 'com.google.jimfs:jimfs:1.1'
testCompile "junit:junit:${versions.junit}"
testCompile "org.hamcrest:hamcrest-all:${versions.hamcrest}"
testCompile 'org.elasticsearch:securemock:1.2'
testCompile "org.elasticsearch.test:framework:${version}"
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
}
dependencyLicenses {
mapping from: /bc.*/, to: 'bouncycastle'
}

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ssl;
package org.elasticsearch.xpack.security.cli;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@ -78,7 +78,7 @@ public class CertGenUtils {
* Generates a CA certificate
*/
public static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair, int days)
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true, days, null);
}
@ -100,7 +100,7 @@ public class CertGenUtils {
*/
public static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
X509Certificate caCert, PrivateKey caPrivKey, int days)
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false, days, null);
}
@ -125,7 +125,7 @@ public class CertGenUtils {
public static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
X509Certificate caCert, PrivateKey caPrivKey,
int days, String signatureAlgorithm)
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false, days, signatureAlgorithm);
}
@ -150,7 +150,7 @@ public class CertGenUtils {
private static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
X509Certificate caCert, PrivateKey caPrivKey, boolean isCa,
int days, String signatureAlgorithm)
throws NoSuchAlgorithmException, CertificateException, CertIOException, OperatorCreationException {
throws NoSuchAlgorithmException, CertificateException, CertIOException, OperatorCreationException {
Objects.requireNonNull(keyPair, "Key-Pair must not be null");
final DateTime notBefore = new DateTime(DateTimeZone.UTC);
if (days < 1) {
@ -175,8 +175,8 @@ public class CertGenUtils {
}
JcaX509v3CertificateBuilder builder =
new JcaX509v3CertificateBuilder(issuer, serial,
new Time(notBefore.toDate(), Locale.ROOT), new Time(notAfter.toDate(), Locale.ROOT), subject, keyPair.getPublic());
new JcaX509v3CertificateBuilder(issuer, serial,
new Time(notBefore.toDate(), Locale.ROOT), new Time(notAfter.toDate(), Locale.ROOT), subject, keyPair.getPublic());
builder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
builder.addExtension(Extension.authorityKeyIdentifier, false, authorityKeyIdentifier);
@ -187,8 +187,8 @@ public class CertGenUtils {
PrivateKey signingKey = caPrivKey != null ? caPrivKey : keyPair.getPrivate();
ContentSigner signer = new JcaContentSignerBuilder(
(Strings.isNullOrEmpty(signatureAlgorithm)) ? getDefaultSignatureAlgorithm(signingKey) : signatureAlgorithm)
.setProvider(CertGenUtils.BC_PROV).build(signingKey);
(Strings.isNullOrEmpty(signatureAlgorithm)) ? getDefaultSignatureAlgorithm(signingKey) : signatureAlgorithm)
.setProvider(CertGenUtils.BC_PROV).build(signingKey);
X509CertificateHolder certificateHolder = builder.build(signer);
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
}
@ -214,7 +214,7 @@ public class CertGenUtils {
break;
default:
throw new IllegalArgumentException("Unsupported algorithm : " + key.getAlgorithm()
+ " for signature, allowed values for private key algorithm are [RSA, DSA, EC]");
+ " for signature, allowed values for private key algorithm are [RSA, DSA, EC]");
}
return signatureAlgorithm;
}
@ -229,7 +229,7 @@ public class CertGenUtils {
* @return a certificate signing request
*/
static PKCS10CertificationRequest generateCSR(KeyPair keyPair, X500Principal principal, GeneralNames sanList)
throws IOException, OperatorCreationException {
throws IOException, OperatorCreationException {
Objects.requireNonNull(keyPair, "Key-Pair must not be null");
Objects.requireNonNull(keyPair.getPublic(), "Public-Key must not be null");
Objects.requireNonNull(principal, "Principal must not be null");

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ssl;
package org.elasticsearch.xpack.security.cli;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionSet;
@ -34,6 +34,8 @@ import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.PemUtils;
import javax.security.auth.x500.X500Principal;
@ -68,6 +70,7 @@ import java.util.zip.ZipOutputStream;
/**
* CLI tool to make generation of certificates or certificate requests easier for users
*
* @deprecated Replaced by {@link CertificateTool}
*/
@Deprecated
@ -81,7 +84,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
private static final int FILE_EXTENSION_LENGTH = 4;
static final int MAX_FILENAME_LENGTH = 255 - FILE_EXTENSION_LENGTH;
private static final Pattern ALLOWED_FILENAME_CHAR_PATTERN =
Pattern.compile("[a-zA-Z0-9!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1," + MAX_FILENAME_LENGTH + "}");
Pattern.compile("[a-zA-Z0-9!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1," + MAX_FILENAME_LENGTH + "}");
private static final int DEFAULT_KEY_SIZE = 2048;
private static final BouncyCastleProvider BC_PROV = new BouncyCastleProvider();
@ -96,11 +99,11 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
// of the parser in this class so that we can defer initialization until after logging has been initialized
static {
@SuppressWarnings("unchecked") final ConstructingObjectParser<CertificateInformation, Void> instanceParser =
new ConstructingObjectParser<>(
"instances",
a -> new CertificateInformation(
(String) a[0], (String) (a[1] == null ? a[0] : a[1]),
(List<String>) a[2], (List<String>) a[3], (List<String>) a[4]));
new ConstructingObjectParser<>(
"instances",
a -> new CertificateInformation(
(String) a[0], (String) (a[1] == null ? a[0] : a[1]),
(List<String>) a[2], (List<String>) a[3], (List<String>) a[4]));
instanceParser.declareString(ConstructingObjectParser.constructorArg(), new ParseField("name"));
instanceParser.declareString(ConstructingObjectParser.optionalConstructorArg(), new ParseField("filename"));
instanceParser.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), new ParseField("ip"));
@ -125,29 +128,29 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
CertificateGenerateTool() {
super(DESCRIPTION);
outputPathSpec = parser.accepts("out", "path of the zip file that the output should be written to")
.withRequiredArg();
.withRequiredArg();
csrSpec = parser.accepts("csr", "only generate certificate signing requests");
caCertPathSpec = parser.accepts("cert", "path to an existing ca certificate").availableUnless(csrSpec).withRequiredArg();
caKeyPathSpec = parser.accepts("key", "path to an existing ca private key")
.availableIf(caCertPathSpec)
.requiredIf(caCertPathSpec)
.withRequiredArg();
.availableIf(caCertPathSpec)
.requiredIf(caCertPathSpec)
.withRequiredArg();
caPasswordSpec = parser.accepts("pass", "password for an existing ca private key or the generated ca private key")
.availableUnless(csrSpec)
.withOptionalArg();
.availableUnless(csrSpec)
.withOptionalArg();
caDnSpec = parser.accepts("dn", "distinguished name to use for the generated ca. defaults to " + AUTO_GEN_CA_DN)
.availableUnless(caCertPathSpec)
.availableUnless(csrSpec)
.withRequiredArg();
.availableUnless(caCertPathSpec)
.availableUnless(csrSpec)
.withRequiredArg();
keysizeSpec = parser.accepts("keysize", "size in bits of RSA keys").withRequiredArg().ofType(Integer.class);
inputFileSpec = parser.accepts("in", "file containing details of the instances in yaml format").withRequiredArg();
daysSpec = parser.accepts("days", "number of days that the generated certificates are valid")
.availableUnless(csrSpec)
.withRequiredArg()
.ofType(Integer.class);
.availableUnless(csrSpec)
.withRequiredArg()
.ofType(Integer.class);
p12Spec = parser.accepts("p12", "output a p12 (PKCS#12) version for each certificate/key pair, with optional password")
.availableUnless(csrSpec)
.withOptionalArg();
.availableUnless(csrSpec)
.withOptionalArg();
}
public static void main(String[] args) throws Exception {
@ -178,7 +181,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
p12Password = null;
}
CAInfo caInfo = getCAInfo(terminal, dn, caCertPathSpec.value(options), caKeyPathSpec.value(options), keyPass, prompt, env,
keysize, days);
keysize, days);
Collection<CertificateInformation> certificateInformations = getCertificateInformationList(terminal, inputFile);
generateAndWriteSignedCertificates(outputFile, certificateInformations, caInfo, keysize, days, p12Password);
}
@ -197,7 +200,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
/**
* Checks for output file in the user specified options or prompts the user for the output file
*
* @param terminal terminal to communicate with a user
* @param terminal terminal to communicate with a user
* @param outputPath user specified output file, may be {@code null}
* @return a {@link Path} to the output file
*/
@ -223,12 +226,13 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
/**
* This method handles the collection of information about each instance that is necessary to generate a certificate. The user may
* be prompted or the information can be gathered from a file
* @param terminal the terminal to use for user interaction
*
* @param terminal the terminal to use for user interaction
* @param inputFile an optional file that will be used to load the instance information
* @return a {@link Collection} of {@link CertificateInformation} that represents each instance
*/
static Collection<CertificateInformation> getCertificateInformationList(Terminal terminal, String inputFile)
throws Exception {
throws Exception {
if (inputFile != null) {
return parseAndValidateFile(terminal, resolvePath(inputFile).toAbsolutePath());
}
@ -239,7 +243,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
if (name.isEmpty() == false) {
final boolean isNameValidFilename = Name.isValidFilename(name);
String filename = terminal.readText("Enter name for directories and files " + (isNameValidFilename ? "[" + name + "]" : "")
+ ": " );
+ ": ");
if (filename.isEmpty() && isNameValidFilename) {
filename = name;
}
@ -267,7 +271,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
}
String exit = terminal.readText("Would you like to specify another instance? Press 'y' to continue entering instance " +
"information: ");
"information: ");
if ("y".equals(exit) == false) {
done = true;
}
@ -283,7 +287,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
if (errors.size() > 0) {
hasError = true;
terminal.println(Terminal.Verbosity.SILENT, "Configuration for instance " + certInfo.name.originalName
+ " has invalid details");
+ " has invalid details");
for (String message : errors) {
terminal.println(Terminal.Verbosity.SILENT, " * " + message);
}
@ -298,6 +302,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
/**
* Parses the input file to retrieve the certificate information
*
* @param file the file to parse
* @return a collection of certificate information
*/
@ -305,22 +310,23 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
try (Reader reader = Files.newBufferedReader(file)) {
// EMPTY is safe here because we never use namedObject
XContentParser xContentParser = XContentType.YAML.xContent()
.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, reader);
.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, reader);
return InputFileParser.PARSER.parse(xContentParser, new ArrayList<>(), null);
}
}
/**
* Generates certificate signing requests and writes them out to the specified file in zip format
*
* @param outputFile the file to write the output to. This file must not already exist
* @param certInfo the details to use in the certificate signing requests
* @param certInfo the details to use in the certificate signing requests
*/
static void generateAndWriteCsrs(Path outputFile, Collection<CertificateInformation> certInfo, int keysize) throws Exception {
fullyWriteFile(outputFile, (outputStream, pemWriter) -> {
for (CertificateInformation certificateInformation : certInfo) {
KeyPair keyPair = CertGenUtils.generateKeyPair(keysize);
GeneralNames sanList = getSubjectAlternativeNamesValue(certificateInformation.ipAddresses, certificateInformation.dnsNames,
certificateInformation.commonNames);
certificateInformation.commonNames);
PKCS10CertificationRequest csr = CertGenUtils.generateCSR(keyPair, certificateInformation.name.x500Principal, sanList);
final String dirName = certificateInformation.name.filename + "/";
@ -347,15 +353,15 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
* Returns the CA certificate and private key that will be used to sign certificates. These may be specified by the user or
* automatically generated
*
* @param terminal the terminal to use for prompting the user
* @param dn the distinguished name to use for the CA
* @param terminal the terminal to use for prompting the user
* @param dn the distinguished name to use for the CA
* @param caCertPath the path to the CA certificate or {@code null} if not provided
* @param caKeyPath the path to the CA private key or {@code null} if not provided
* @param prompt whether we should prompt the user for a password
* @param keyPass the password to the private key. If not present and the key is encrypted the user will be prompted
* @param env the environment for this tool to resolve files with
* @param keysize the size of the key in bits
* @param days the number of days that the certificate should be valid for
* @param caKeyPath the path to the CA private key or {@code null} if not provided
* @param prompt whether we should prompt the user for a password
* @param keyPass the password to the private key. If not present and the key is encrypted the user will be prompted
* @param env the environment for this tool to resolve files with
* @param keysize the size of the key in bits
* @param days the number of days that the certificate should be valid for
* @return CA cert and private key
*/
static CAInfo getCAInfo(Terminal terminal, String dn, String caCertPath, String caKeyPath, char[] keyPass, boolean prompt,
@ -366,7 +372,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
Certificate[] certificates = CertParsingUtils.readCertificates(Collections.singletonList(resolvedCaCertPath), env);
if (certificates.length != 1) {
throw new IllegalArgumentException("expected a single certificate in file [" + caCertPath + "] but found [" +
certificates.length + "]");
certificates.length + "]");
}
Certificate caCert = certificates[0];
PrivateKey privateKey = readPrivateKey(caKeyPath, keyPass, terminal, prompt);
@ -388,11 +394,12 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
/**
* Generates signed certificates in PEM format stored in a zip file
* @param outputFile the file that the certificates will be written to. This file must not exist
*
* @param outputFile the file that the certificates will be written to. This file must not exist
* @param certificateInformations details for creation of the certificates
* @param caInfo the CA information to sign the certificates with
* @param keysize the size of the key in bits
* @param days the number of days that the certificate should be valid for
* @param caInfo the CA information to sign the certificates with
* @param keysize the size of the key in bits
* @param days the number of days that the certificate should be valid for
*/
static void generateAndWriteSignedCertificates(Path outputFile, Collection<CertificateInformation> certificateInformations,
CAInfo caInfo, int keysize, int days, char[] pkcs12Password) throws Exception {
@ -403,9 +410,9 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
for (CertificateInformation certificateInformation : certificateInformations) {
KeyPair keyPair = CertGenUtils.generateKeyPair(keysize);
Certificate certificate = CertGenUtils.generateSignedCertificate(certificateInformation.name.x500Principal,
getSubjectAlternativeNamesValue(certificateInformation.ipAddresses, certificateInformation.dnsNames,
certificateInformation.commonNames),
keyPair, caInfo.caCert, caInfo.privateKey, days);
getSubjectAlternativeNamesValue(certificateInformation.ipAddresses, certificateInformation.dnsNames,
certificateInformation.commonNames),
keyPair, caInfo.caCert, caInfo.privateKey, days);
final String dirName = certificateInformation.name.filename + "/";
ZipEntry zipEntry = new ZipEntry(dirName);
@ -429,7 +436,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
final KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
pkcs12.load(null);
pkcs12.setKeyEntry(certificateInformation.name.originalName, keyPair.getPrivate(), pkcs12Password,
new Certificate[]{certificate});
new Certificate[]{certificate});
outputStream.putNextEntry(new ZipEntry(entryBase + ".p12"));
pkcs12.store(outputStream, pkcs12Password);
@ -441,7 +448,8 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
/**
* This method handles the deletion of a file in the case of a partial write
* @param file the file that is being written to
*
* @param file the file that is being written to
* @param writer writes the contents of the file
*/
private static void fullyWriteFile(Path file, Writer writer) throws Exception {
@ -468,9 +476,10 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
/**
* This method handles writing out the certificate authority cert and private key if the certificate authority was generated by
* this invocation of the tool
*
* @param outputStream the output stream to write to
* @param pemWriter the writer for PEM objects
* @param info the certificate authority information
* @param pemWriter the writer for PEM objects
* @param info the certificate authority information
*/
private static void writeCAInfoIfGenerated(ZipOutputStream outputStream, JcaPEMWriter pemWriter, CAInfo info) throws Exception {
if (info.generated) {
@ -577,14 +586,15 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
/**
* Helper method to read a private key and support prompting of user for a key. To avoid passwords being placed as an argument we
* can prompt the user for their password if we encounter an encrypted key.
* @param path the path to the private key
*
* @param path the path to the private key
* @param password the password provided by the user or {@code null}
* @param terminal the terminal to use for user interaction
* @param prompt whether to prompt the user or not
* @param prompt whether to prompt the user or not
* @return the {@link PrivateKey} that was read from the file
*/
private static PrivateKey readPrivateKey(String path, char[] password, Terminal terminal, boolean prompt)
throws Exception {
throws Exception {
AtomicReference<char[]> passwordReference = new AtomicReference<>(password);
try {
return PemUtils.readPrivateKey(resolvePath(path), () -> {
@ -682,7 +692,7 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
}
} catch (IllegalArgumentException e) {
String error = "[" + name + "] could not be converted to a valid DN\n" + e.getMessage() + "\n"
+ ExceptionsHelper.stackTrace(e);
+ ExceptionsHelper.stackTrace(e);
return new Name(name, null, null, error);
}
@ -695,15 +705,15 @@ public class CertificateGenerateTool extends EnvironmentAwareCommand {
static boolean isValidFilename(String name) {
return ALLOWED_FILENAME_CHAR_PATTERN.matcher(name).matches()
&& ALLOWED_FILENAME_CHAR_PATTERN.matcher(resolvePath(name).toString()).matches()
&& name.startsWith(".") == false;
&& ALLOWED_FILENAME_CHAR_PATTERN.matcher(resolvePath(name).toString()).matches()
&& name.startsWith(".") == false;
}
@Override
public String toString() {
return getClass().getSimpleName()
+ "{original=[" + originalName + "] principal=[" + x500Principal
+ "] file=[" + filename + "] err=[" + error + "]}";
+ "{original=[" + originalName + "] principal=[" + x500Principal
+ "] file=[" + filename + "] err=[" + error + "]}";
}
}

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ssl;
package org.elasticsearch.xpack.security.cli;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
@ -39,6 +39,8 @@ import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.PemUtils;
import javax.security.auth.x500.X500Principal;
@ -101,7 +103,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
private static final int FILE_EXTENSION_LENGTH = 4;
static final int MAX_FILENAME_LENGTH = 255 - FILE_EXTENSION_LENGTH;
private static final Pattern ALLOWED_FILENAME_CHAR_PATTERN =
Pattern.compile("[a-zA-Z0-9!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1," + MAX_FILENAME_LENGTH + "}");
Pattern.compile("[a-zA-Z0-9!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1," + MAX_FILENAME_LENGTH + "}");
private static final int DEFAULT_KEY_SIZE = 2048;
/**
@ -115,11 +117,11 @@ public class CertificateTool extends LoggingAwareMultiCommand {
// of the parser in this class so that we can defer initialization until after logging has been initialized
static {
@SuppressWarnings("unchecked") final ConstructingObjectParser<CertificateInformation, Void> instanceParser =
new ConstructingObjectParser<>(
"instances",
a -> new CertificateInformation(
(String) a[0], (String) (a[1] == null ? a[0] : a[1]),
(List<String>) a[2], (List<String>) a[3], (List<String>) a[4]));
new ConstructingObjectParser<>(
"instances",
a -> new CertificateInformation(
(String) a[0], (String) (a[1] == null ? a[0] : a[1]),
(List<String>) a[2], (List<String>) a[3], (List<String>) a[4]));
instanceParser.declareString(ConstructingObjectParser.constructorArg(), new ParseField("name"));
instanceParser.declareString(ConstructingObjectParser.optionalConstructorArg(), new ParseField("filename"));
instanceParser.declareStringArray(ConstructingObjectParser.optionalConstructorArg(), new ParseField("ip"));
@ -144,28 +146,28 @@ public class CertificateTool extends LoggingAwareMultiCommand {
static final String INTRO_TEXT = "This tool assists you in the generation of X.509 certificates and certificate\n" +
"signing requests for use with SSL/TLS in the Elastic stack.";
"signing requests for use with SSL/TLS in the Elastic stack.";
static final String INSTANCE_EXPLANATION =
" * An instance is any piece of the Elastic Stack that requires a SSL certificate.\n" +
" Depending on your configuration, Elasticsearch, Logstash, Kibana, and Beats\n" +
" may all require a certificate and private key.\n" +
" * The minimum required value for each instance is a name. This can simply be the\n" +
" hostname, which will be used as the Common Name of the certificate. A full\n" +
" distinguished name may also be used.\n" +
" * A filename value may be required for each instance. This is necessary when the\n" +
" name would result in an invalid file or directory name. The name provided here\n" +
" is used as the directory name (within the zip) and the prefix for the key and\n" +
" certificate files. The filename is required if you are prompted and the name\n" +
" is not displayed in the prompt.\n" +
" * IP addresses and DNS names are optional. Multiple values can be specified as a\n" +
" comma separated string. If no IP addresses or DNS names are provided, you may\n" +
" disable hostname verification in your SSL configuration.";
" * An instance is any piece of the Elastic Stack that requires a SSL certificate.\n" +
" Depending on your configuration, Elasticsearch, Logstash, Kibana, and Beats\n" +
" may all require a certificate and private key.\n" +
" * The minimum required value for each instance is a name. This can simply be the\n" +
" hostname, which will be used as the Common Name of the certificate. A full\n" +
" distinguished name may also be used.\n" +
" * A filename value may be required for each instance. This is necessary when the\n" +
" name would result in an invalid file or directory name. The name provided here\n" +
" is used as the directory name (within the zip) and the prefix for the key and\n" +
" certificate files. The filename is required if you are prompted and the name\n" +
" is not displayed in the prompt.\n" +
" * IP addresses and DNS names are optional. Multiple values can be specified as a\n" +
" comma separated string. If no IP addresses or DNS names are provided, you may\n" +
" disable hostname verification in your SSL configuration.";
static final String CA_EXPLANATION =
" * All certificates generated by this tool will be signed by a certificate authority (CA).\n" +
" * The tool can automatically generate a new CA for you, or you can provide your own with the\n" +
" -ca or -ca-cert command line options.";
" * All certificates generated by this tool will be signed by a certificate authority (CA).\n" +
" * The tool can automatically generate a new CA for you, or you can provide your own with the\n" +
" -ca or -ca-cert command line options.";
abstract static class CertificateCommand extends EnvironmentAwareCommand {
@ -202,32 +204,32 @@ public class CertificateTool extends LoggingAwareMultiCommand {
final void acceptCertificateGenerationOptions() {
pemFormatSpec = parser.accepts("pem", "output certificates and keys in PEM format instead of PKCS#12");
daysSpec = parser.accepts("days", "number of days that the generated certificates are valid")
.withRequiredArg().ofType(Integer.class);
.withRequiredArg().ofType(Integer.class);
}
final void acceptsCertificateAuthority() {
caPkcs12PathSpec = parser.accepts("ca", "path to an existing ca key pair (in PKCS#12 format)").withRequiredArg();
caCertPathSpec = parser.accepts("ca-cert", "path to an existing ca certificate")
.availableUnless(caPkcs12PathSpec)
.withRequiredArg();
.availableUnless(caPkcs12PathSpec)
.withRequiredArg();
caKeyPathSpec = parser.accepts("ca-key", "path to an existing ca private key")
.availableIf(caCertPathSpec)
.requiredIf(caCertPathSpec)
.withRequiredArg();
.availableIf(caCertPathSpec)
.requiredIf(caCertPathSpec)
.withRequiredArg();
keepCaKeySpec = parser.accepts("keep-ca-key", "retain the CA private key for future use")
.availableUnless(caPkcs12PathSpec)
.availableUnless(caCertPathSpec);
.availableUnless(caPkcs12PathSpec)
.availableUnless(caCertPathSpec);
caPasswordSpec = parser.accepts("ca-pass", "password for an existing ca private key or the generated ca private key")
.withOptionalArg();
.withOptionalArg();
acceptsCertificateAuthorityName();
}
void acceptsCertificateAuthorityName() {
OptionSpecBuilder builder = parser.accepts("ca-dn",
"distinguished name to use for the generated ca. defaults to " + AUTO_GEN_CA_DN);
"distinguished name to use for the generated ca. defaults to " + AUTO_GEN_CA_DN);
if (caPkcs12PathSpec != null) {
builder = builder.availableUnless(caPkcs12PathSpec);
}
@ -336,11 +338,11 @@ public class CertificateTool extends LoggingAwareMultiCommand {
char[] passwordOption = getChars(caPasswordSpec.value(options));
Map<Certificate, Key> keys = withPassword("CA (" + path + ")", passwordOption,
terminal, password -> CertParsingUtils.readPkcs12KeyPairs(path, password, a -> password));
terminal, password -> CertParsingUtils.readPkcs12KeyPairs(path, password, a -> password));
if (keys.size() != 1) {
throw new IllegalArgumentException("expected a single key in file [" + path.toAbsolutePath() + "] but found [" +
keys.size() + "]");
keys.size() + "]");
}
final Map.Entry<Certificate, Key> pair = keys.entrySet().iterator().next();
return new CAInfo((X509Certificate) pair.getKey(), (PrivateKey) pair.getValue());
@ -358,7 +360,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
Certificate[] certificates = CertParsingUtils.readCertificates(Collections.singletonList(resolvedCaCertPath), env);
if (certificates.length != 1) {
throw new IllegalArgumentException("expected a single certificate in file [" + resolvedCaCertPath + "] but found [" +
certificates.length + "]");
certificates.length + "]");
}
X509Certificate caCert = (X509Certificate) certificates[0];
PrivateKey privateKey = readPrivateKey(key, getChars(password), terminal);
@ -391,7 +393,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
* @return a {@link Collection} of {@link CertificateInformation} that represents each instance
*/
Collection<CertificateInformation> getCertificateInformationList(Terminal terminal, OptionSet options)
throws Exception {
throws Exception {
final Path input = resolvePath(options, inputFileSpec);
if (input != null) {
return parseAndValidateFile(terminal, input.toAbsolutePath());
@ -456,7 +458,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
}
String exit = terminal.readText("Would you like to specify another instance? Press 'y' to continue entering instance " +
"information: ");
"information: ");
if ("y".equals(exit) == false) {
done = true;
}
@ -468,7 +470,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
final boolean isNameValidFilename = Name.isValidFilename(certName);
while (true) {
String filename = terminal.readText("Enter name for directories and files of " + certName +
(isNameValidFilename ? " [" + certName + "]" : "") + ": ");
(isNameValidFilename ? " [" + certName + "]" : "") + ": ");
if (filename.isEmpty() && isNameValidFilename) {
return certName;
}
@ -490,7 +492,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
* @param includeKey if true, write the CA key in PEM format
*/
static void writeCAInfo(ZipOutputStream outputStream, JcaPEMWriter pemWriter, CAInfo info, boolean includeKey)
throws Exception {
throws Exception {
final String caDirName = createCaDirectory(outputStream);
outputStream.putNextEntry(new ZipEntry(caDirName + "ca.crt"));
pemWriter.writeObject(info.certAndKey.cert);
@ -546,7 +548,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
pkcs12.load(null);
withPassword(fileName, password, terminal, p12Password -> {
if (isAscii(p12Password)) {
pkcs12.setKeyEntry(alias, pair.key, p12Password, new Certificate[] { pair.cert });
pkcs12.setKeyEntry(alias, pair.key, p12Password, new Certificate[]{pair.cert});
if (caCert != null) {
pkcs12.setCertificateEntry("ca", caCert);
}
@ -574,7 +576,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
terminal.println("The 'csr' mode generates certificate signing requests that can be sent to");
terminal.println("a trusted certificate authority");
terminal.println(" * By default, this generates a single CSR for a single instance.");
terminal.println(" * You can use the '-multiple' option to generate CSRs for multiple" );
terminal.println(" * You can use the '-multiple' option to generate CSRs for multiple");
terminal.println(" instances, each with their own private key.");
terminal.println(" * The '-in' option allows for the CSR generation to be automated");
terminal.println(" by describing the details of each instance in a YAML file");
@ -616,7 +618,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
for (CertificateInformation certificateInformation : certInfo) {
KeyPair keyPair = CertGenUtils.generateKeyPair(keySize);
GeneralNames sanList = getSubjectAlternativeNamesValue(certificateInformation.ipAddresses,
certificateInformation.dnsNames, certificateInformation.commonNames);
certificateInformation.dnsNames, certificateInformation.commonNames);
PKCS10CertificationRequest csr = CertGenUtils.generateCSR(keyPair, certificateInformation.name.x500Principal, sanList);
final String dirName = certificateInformation.name.filename + "/";
@ -750,7 +752,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
*/
void generateAndWriteSignedCertificates(Path output, boolean writeZipFile, OptionSet options,
Collection<CertificateInformation> certs, CAInfo caInfo, Terminal terminal)
throws Exception {
throws Exception {
checkDirectory(output, terminal);
@ -805,7 +807,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
final String fileName = entryBase + ".p12";
outputStream.putNextEntry(new ZipEntry(fileName));
writePkcs12(fileName, outputStream, certificateInformation.name.originalName, pair, caInfo.certAndKey.cert,
outputPassword, terminal);
outputPassword, terminal);
outputStream.closeEntry();
}
}
@ -815,7 +817,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
CertificateInformation certificateInformation = certs.iterator().next();
CertificateAndKey pair = generateCertificateAndKey(certificateInformation, caInfo, keySize, days);
fullyWriteFile(output, stream -> writePkcs12(output.getFileName().toString(), stream,
certificateInformation.name.originalName, pair, caInfo.certAndKey.cert, outputPassword, terminal));
certificateInformation.name.originalName, pair, caInfo.certAndKey.cert, outputPassword, terminal));
}
}
@ -823,9 +825,9 @@ public class CertificateTool extends LoggingAwareMultiCommand {
int keySize, int days) throws Exception {
KeyPair keyPair = CertGenUtils.generateKeyPair(keySize);
Certificate certificate = CertGenUtils.generateSignedCertificate(certificateInformation.name.x500Principal,
getSubjectAlternativeNamesValue(certificateInformation.ipAddresses, certificateInformation.dnsNames,
certificateInformation.commonNames),
keyPair, caInfo.certAndKey.cert, caInfo.certAndKey.key, days);
getSubjectAlternativeNamesValue(certificateInformation.ipAddresses, certificateInformation.dnsNames,
certificateInformation.commonNames),
keyPair, caInfo.certAndKey.cert, caInfo.certAndKey.key, days);
return new CertificateAndKey((X509Certificate) certificate, keyPair.getPrivate());
}
@ -872,7 +874,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
} else {
final String fileName = output.getFileName().toString();
fullyWriteFile(output, outputStream ->
writePkcs12(fileName, outputStream, "ca", caInfo.certAndKey, null, caInfo.password, terminal));
writePkcs12(fileName, outputStream, "ca", caInfo.certAndKey, null, caInfo.password, terminal));
}
}
}
@ -912,7 +914,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
try (Reader reader = Files.newBufferedReader(file)) {
// EMPTY is safe here because we never use namedObject
XContentParser xContentParser = XContentType.YAML.xContent()
.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, reader);
.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, reader);
return CertificateToolParser.PARSER.parse(xContentParser, new ArrayList<>(), null);
}
}
@ -1015,7 +1017,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
* @return the {@link PrivateKey} that was read from the file
*/
private static PrivateKey readPrivateKey(Path path, char[] password, Terminal terminal)
throws Exception {
throws Exception {
AtomicReference<char[]> passwordReference = new AtomicReference<>(password);
try {
return PemUtils.readPrivateKey(path, () -> {
@ -1125,7 +1127,7 @@ public class CertificateTool extends LoggingAwareMultiCommand {
}
} catch (IllegalArgumentException e) {
String error = "[" + name + "] could not be converted to a valid DN\n" + e.getMessage() + "\n"
+ ExceptionsHelper.stackTrace(e);
+ ExceptionsHelper.stackTrace(e);
return new Name(name, null, null, error);
}
@ -1138,15 +1140,15 @@ public class CertificateTool extends LoggingAwareMultiCommand {
static boolean isValidFilename(String name) {
return ALLOWED_FILENAME_CHAR_PATTERN.matcher(name).matches()
&& ALLOWED_FILENAME_CHAR_PATTERN.matcher(resolvePath(name).toString()).matches()
&& name.startsWith(".") == false;
&& ALLOWED_FILENAME_CHAR_PATTERN.matcher(resolvePath(name).toString()).matches()
&& name.startsWith(".") == false;
}
@Override
public String toString() {
return getClass().getSimpleName()
+ "{original=[" + originalName + "] principal=[" + x500Principal
+ "] file=[" + filename + "] err=[" + error + "]}";
+ "{original=[" + originalName + "] principal=[" + x500Principal
+ "] file=[" + filename + "] err=[" + error + "]}";
}
}

View File

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ssl;
package org.elasticsearch.xpack.security.cli;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
@ -12,6 +12,7 @@ import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.security.cli.CertGenUtils;
import org.junit.BeforeClass;
import java.math.BigInteger;

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ssl;
package org.elasticsearch.xpack.security.cli;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
@ -33,9 +33,11 @@ import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.SecuritySettingsSourceField;
import org.elasticsearch.xpack.core.ssl.CertificateGenerateTool.CAInfo;
import org.elasticsearch.xpack.core.ssl.CertificateGenerateTool.CertificateInformation;
import org.elasticsearch.xpack.core.ssl.CertificateGenerateTool.Name;
import org.elasticsearch.xpack.security.cli.CertificateGenerateTool.CAInfo;
import org.elasticsearch.xpack.security.cli.CertificateGenerateTool.CertificateInformation;
import org.elasticsearch.xpack.security.cli.CertificateGenerateTool.Name;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.PemUtils;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.BeforeClass;
@ -359,8 +361,8 @@ public class CertificateGenerateToolTests extends ESTestCase {
public void testGetCAInfo() throws Exception {
Environment env = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
Path testNodeCertPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt");
Path testNodeKeyPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem");
Path testNodeCertPath = getDataPath("/org/elasticsearch/xpack/security/cli/testnode.crt");
Path testNodeKeyPath = getDataPath("/org/elasticsearch/xpack/security/cli/testnode.pem");
final boolean passwordPrompt = randomBoolean();
MockTerminal terminal = new MockTerminal();
if (passwordPrompt) {

View File

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.ssl;
package org.elasticsearch.xpack.security.cli;
import com.google.common.jimfs.Configuration;
import com.google.common.jimfs.Jimfs;
@ -39,12 +39,14 @@ import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.SecuritySettingsSourceField;
import org.elasticsearch.test.TestMatchers;
import org.elasticsearch.xpack.core.ssl.CertificateTool.CAInfo;
import org.elasticsearch.xpack.core.ssl.CertificateTool.CertificateAuthorityCommand;
import org.elasticsearch.xpack.core.ssl.CertificateTool.CertificateCommand;
import org.elasticsearch.xpack.core.ssl.CertificateTool.CertificateInformation;
import org.elasticsearch.xpack.core.ssl.CertificateTool.GenerateCertificateCommand;
import org.elasticsearch.xpack.core.ssl.CertificateTool.Name;
import org.elasticsearch.xpack.security.cli.CertificateTool.CAInfo;
import org.elasticsearch.xpack.security.cli.CertificateTool.CertificateAuthorityCommand;
import org.elasticsearch.xpack.security.cli.CertificateTool.CertificateCommand;
import org.elasticsearch.xpack.security.cli.CertificateTool.CertificateInformation;
import org.elasticsearch.xpack.security.cli.CertificateTool.GenerateCertificateCommand;
import org.elasticsearch.xpack.security.cli.CertificateTool.Name;
import org.elasticsearch.xpack.core.ssl.CertParsingUtils;
import org.elasticsearch.xpack.core.ssl.PemUtils;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.BeforeClass;
@ -387,8 +389,8 @@ public class CertificateToolTests extends ESTestCase {
public void testGetCAInfo() throws Exception {
Environment env = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
Path testNodeCertPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt");
Path testNodeKeyPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem");
Path testNodeCertPath = getDataPath("/org/elasticsearch/xpack/security/cli/testnode.crt");
Path testNodeKeyPath = getDataPath("/org/elasticsearch/xpack/security/cli/testnode.pem");
final boolean passwordPrompt = randomBoolean();
MockTerminal terminal = new MockTerminal();
if (passwordPrompt) {

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID0zCCArugAwIBAgIJALi5bDfjMszLMA0GCSqGSIb3DQEBCwUAMEgxDDAKBgNV
BAoTA29yZzEWMBQGA1UECxMNZWxhc3RpY3NlYXJjaDEgMB4GA1UEAxMXRWxhc3Rp
Y3NlYXJjaCBUZXN0IE5vZGUwHhcNMTUwOTIzMTg1MjU3WhcNMTkwOTIyMTg1MjU3
WjBIMQwwCgYDVQQKEwNvcmcxFjAUBgNVBAsTDWVsYXN0aWNzZWFyY2gxIDAeBgNV
BAMTF0VsYXN0aWNzZWFyY2ggVGVzdCBOb2RlMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA3rGZ1QbsW0+MuyrSLmMfDFKtLBkIFW8V0gRuurFg1PUKKNR1
Mq2tMVwjjYETAU/UY0iKZOzjgvYPKhDTYBTte/WHR1ZK4CYVv7TQX/gtFQG/ge/c
7u0sLch9p7fbd+/HZiLS/rBEZDIohvgUvzvnA8+OIYnw4kuxKo/5iboAIS41klMg
/lATm8V71LMY68inht71/ZkQoAHKgcR9z4yNYvQ1WqKG8DG8KROXltll3sTrKbl5
zJhn660es/1ZnR6nvwt6xnSTl/mNHMjkfv1bs4rJ/py3qPxicdoSIn/KyojUcgHV
F38fuAy2CQTdjVG5fWj9iz+mQvLm3+qsIYQdFwIDAQABo4G/MIG8MAkGA1UdEwQC
MAAwHQYDVR0OBBYEFEMMWLWQi/g83PzlHYqAVnty5L7HMIGPBgNVHREEgYcwgYSC
CWxvY2FsaG9zdIIVbG9jYWxob3N0LmxvY2FsZG9tYWluggpsb2NhbGhvc3Q0ghds
b2NhbGhvc3Q0LmxvY2FsZG9tYWluNIIKbG9jYWxob3N0NoIXbG9jYWxob3N0Ni5s
b2NhbGRvbWFpbjaHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQEL
BQADggEBAMjGGXT8Nt1tbl2GkiKtmiuGE2Ej66YuZ37WSJViaRNDVHLlg87TCcHe
k2rdO+6sFqQbbzEfwQ05T7xGmVu7tm54HwKMRugoQ3wct0bQC5wEWYN+oMDvSyO6
M28mZwWb4VtR2IRyWP+ve5DHwTM9mxWa6rBlGzsQqH6YkJpZojzqk/mQTug+Y8aE
mVoqRIPMHq9ob+S9qd5lp09+MtYpwPfTPx/NN+xMEooXWW/ARfpGhWPkg/FuCu4z
1tFmCqHgNcWirzMm3dQpF78muE9ng6OB2MXQwL4VgnVkxmlZNHbkR2v/t8MyZJxC
y4g6cTMM3S/UMt5/+aIB2JAuMKyuD+A=
-----END CERTIFICATE-----

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,9D867F7E0C94D013
dVoVCjPeg1wgS7rVtOvGfQcrZyLkx393aWRnFq45tbjKBVuITtJ9vI7o4QXOV/15
Gnb6WhXGIdWrzsxEAd46K6hIuNSISd4Emsx6c2Q5hTqWXXfexbOZBNfTtXtdJPnJ
1jAaikhtztLo3JSLTKNY5sNxd+XbaQyYVUWvueK6zOaIIMETvB+VPVFd9i1ROibk
Sgdtyj01KjkoalifqK/tA0CIYNKL0S6/eoK3UhAlpIprlpV+cnXa940C6bjLeJPt
PMAGGp5RrplxSgrSerw3I9DOWkHGtpqzIka3XneNUXJP8k4HUJ+aZkGH2ZILKS8d
4KMIb+KZSpHEGn+6uGccWLtZZmAjWJrDw56JbQtSHdRYLBRSOjLbTvQoPu/2Hpli
7HOxbotlvjptMunncq5aqK57SHA1dh0cwF7J3LUmGFJ67eoz+VV3b5qMn4MopSeI
mS16Ydd3nGpjSrln/elM0CQxqWfcOAXRZpDpFUQoXcBrLVzvz2DBl/0CrTRLhgzi
CO+5/IVcBWRlYpRNGgjjP7q0j6URID3jk5J06fYQXmBiwQT5j+GZqqzpMCJ9mIy2
1O9SN1hebJnIcEU+E0njn/MGjlYdPywhaCy8pqElp6Q8TUEJpwLRFO/owCoBet/n
ZmCXUjfCGhc1pWHufFcDEQ6xMgEWWY/tdwCZeSU7EhErTjCbfupg+55A5fpDml0m
3wH4CFcuRjlqyx6Ywixm1ATeitDtJl5HQTw6b8OtEXwSgRmZ0eSqSRVk9QbVS7gu
IpQe09/Zimb5HzjZqZ3fdqHlcW4xax8hyJeyIvF5ZJ57eY8CBvu/wP2GDn26QnvF
xQqdfDbq1H4JmpwUHpbFwBoQK4Q6WFd1z4EA9bRQeo3H9PoqoOwMDjzajwLRF7b7
q6tYH/n9PyHwdf1c4fFwgSmL1toXGfKlA9hjIaLsRSDD6srT5EdUk78bsnddwI51
tu7C7P4JG+h1VdRNMNTlqtileWsIE7Nn2A1OkcUxZdF5mamENpDpJcHePLto6c8q
FKiwyFMsxhgsj6HK2HqO+UA4sX5Ni4oHwiPmb//EZLn045M5i1AN26KosJmb8++D
sgR5reWRy+UqJCTYblVg+7Dx++ggUnfxVyQEsWmw5r5f4KU5wXBkvoVMGtPNa9DE
n/uLtObD1qkNL38pRsr2OGRchYCgEoKGqEISBP4knfGXLOlWiW/246j9QzI97r1u
tvy7fKg28G7AUz9l6bpewsPHefBUeRQeieP9eJINaEpxkF/w2RpKDLpQjWxwDDOM
s+D0mrBMJve17AmJ8rMw6dIQPZYNZ88/jz1uQuUwQ2YlbmtZbCG81k9YMFGEU9XS
cyhJxj8hvYnt2PR5Z9/cJPyWOs0m/ufOeeQQ8SnU/lzmrQnpzUd2Z6p5i/B7LdRP
n1kX+l1qynuPnjvBz4nJQE0p6nzW8RyCDSniC9mtYtZmhgC8icqxgbvS7uEOBIYJ
NbK+0bEETTO34iY/JVTIqLOw3iQZYMeUpxpj6Phgx/oooxMTquMecPKNgeVtaBst
qjTNPX0ti1/HYpZqzYi8SV8YjHSJWCVMsZjKPr3W/HIcCKqYoIfgzi83Ha2KMQx6
-----END RSA PRIVATE KEY-----

View File

@ -4,7 +4,8 @@
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
ES_MAIN_CLASS=org.elasticsearch.xpack.core.ssl.CertificateGenerateTool \
ES_MAIN_CLASS=org.elasticsearch.xpack.security.cli.CertificateGenerateTool \
ES_ADDITIONAL_SOURCES="x-pack-env;x-pack-security-env" \
ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli \
"`dirname "$0"`"/elasticsearch-cli \
"$@"

View File

@ -7,8 +7,9 @@ rem you may not use this file except in compliance with the Elastic License.
setlocal enabledelayedexpansion
setlocal enableextensions
set ES_MAIN_CLASS=org.elasticsearch.xpack.core.ssl.CertificateGenerateTool
set ES_MAIN_CLASS=org.elasticsearch.xpack.security.cli.CertificateGenerateTool
set ES_ADDITIONAL_SOURCES=x-pack-env;x-pack-security-env
set ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli
call "%~dp0elasticsearch-cli.bat" ^
%%* ^
|| exit /b 1

View File

@ -4,7 +4,8 @@
# or more contributor license agreements. Licensed under the Elastic License;
# you may not use this file except in compliance with the Elastic License.
ES_MAIN_CLASS=org.elasticsearch.xpack.core.ssl.CertificateTool \
ES_MAIN_CLASS=org.elasticsearch.xpack.security.cli.CertificateTool \
ES_ADDITIONAL_SOURCES="x-pack-env;x-pack-security-env" \
ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli \
"`dirname "$0"`"/elasticsearch-cli \
"$@"

View File

@ -7,8 +7,9 @@ rem you may not use this file except in compliance with the Elastic License.
setlocal enabledelayedexpansion
setlocal enableextensions
set ES_MAIN_CLASS=org.elasticsearch.xpack.core.ssl.CertificateTool
set ES_MAIN_CLASS=org.elasticsearch.xpack.security.cli.CertificateTool
set ES_ADDITIONAL_SOURCES=x-pack-env;x-pack-security-env
set ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli
call "%~dp0elasticsearch-cli.bat" ^
%%* ^
|| exit /b 1