Skip to content

Commit aaa8f84

Browse files
authored
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.
1 parent 7aa8a0a commit aaa8f84

File tree

25 files changed

+294
-172
lines changed

25 files changed

+294
-172
lines changed

distribution/archives/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ CopySpec archiveFiles(CopySpec modulesFiles, String distributionType, boolean os
4949
return copySpec {
5050
into("elasticsearch-${version}") {
5151
into('lib') {
52-
with libFiles
52+
with libFiles(oss)
5353
}
5454
into('config') {
5555
dirMode 0750

distribution/build.gradle

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -227,16 +227,24 @@ configure(subprojects.findAll { ['archives', 'packages'].contains(it.name) }) {
227227
/*****************************************************************************
228228
* Common files in all distributions *
229229
*****************************************************************************/
230-
libFiles = copySpec {
231-
// delay by using closures, since they have not yet been configured, so no jar task exists yet
232-
from { project(':server').jar }
233-
from { project(':server').configurations.runtime }
234-
from { project(':libs:plugin-classloader').jar }
235-
from { project(':distribution:tools:java-version-checker').jar }
236-
from { project(':distribution:tools:launchers').jar }
237-
into('tools/plugin-cli') {
238-
from { project(':distribution:tools:plugin-cli').jar }
239-
from { project(':distribution:tools:plugin-cli').configurations.runtime }
230+
libFiles = { oss ->
231+
copySpec {
232+
// delay by using closures, since they have not yet been configured, so no jar task exists yet
233+
from { project(':server').jar }
234+
from { project(':server').configurations.runtime }
235+
from { project(':libs:plugin-classloader').jar }
236+
from { project(':distribution:tools:java-version-checker').jar }
237+
from { project(':distribution:tools:launchers').jar }
238+
into('tools/plugin-cli') {
239+
from { project(':distribution:tools:plugin-cli').jar }
240+
from { project(':distribution:tools:plugin-cli').configurations.runtime }
241+
}
242+
if (oss == false) {
243+
into('tools/security-cli') {
244+
from { project(':x-pack:plugin:security:cli').jar }
245+
from { project(':x-pack:plugin:security:cli').configurations.compile }
246+
}
247+
}
240248
}
241249
}
242250

distribution/packages/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ Closure commonPackageConfig(String type, boolean oss) {
126126
}
127127
into('lib') {
128128
with copySpec {
129-
with libFiles
129+
with libFiles(oss)
130130
// we need to specify every intermediate directory so we iterate through the parents; duplicate calls with the same part are fine
131131
eachFile { FileCopyDetails fcp ->
132132
String[] segments = fcp.relativePath.segments

qa/vagrant/src/main/java/org/elasticsearch/packaging/test/ArchiveTestCase.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import static org.hamcrest.CoreMatchers.notNullValue;
5858
import static org.hamcrest.MatcherAssert.assertThat;
5959
import static org.hamcrest.Matchers.isEmptyString;
60+
import static org.junit.Assert.assertFalse;
6061
import static org.junit.Assert.assertTrue;
6162
import static org.junit.Assume.assumeThat;
6263
import static org.junit.Assume.assumeTrue;
@@ -302,5 +303,26 @@ public void test80RelativePathConf() throws IOException {
302303
}
303304
}
304305

306+
public void test90SecurityCliPackaging() {
307+
assumeThat(installation, is(notNullValue()));
308+
309+
final Installation.Executables bin = installation.executables();
310+
final Shell sh = new Shell();
311+
312+
if (distribution().equals(Distribution.DEFAULT_TAR) || distribution().equals(Distribution.DEFAULT_ZIP)) {
313+
assertTrue(Files.exists(installation.lib.resolve("tools").resolve("security-cli")));
314+
Platforms.onLinux(() -> {
315+
final Result result = sh.run(bin.elasticsearchCertutil + " help");
316+
assertThat(result.stdout, containsString("Simplifies certificate creation for use with the Elastic Stack"));
317+
});
318+
319+
Platforms.onWindows(() -> {
320+
final Result result = sh.run(bin.elasticsearchCertutil + " help");
321+
assertThat(result.stdout, containsString("Simplifies certificate creation for use with the Elastic Stack"));
322+
});
323+
} else if (distribution().equals(Distribution.OSS_TAR) || distribution().equals(Distribution.OSS_ZIP)) {
324+
assertFalse(Files.exists(installation.lib.resolve("tools").resolve("security-cli")));
325+
}
326+
}
305327

306328
}

qa/vagrant/src/main/java/org/elasticsearch/packaging/util/Installation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public class Executables {
101101
public final Path elasticsearchPlugin = platformExecutable("elasticsearch-plugin");
102102
public final Path elasticsearchKeystore = platformExecutable("elasticsearch-keystore");
103103
public final Path elasticsearchTranslog = platformExecutable("elasticsearch-translog");
104+
public final Path elasticsearchCertutil = platformExecutable("elasticsearch-certutil");
104105

105106
private Path platformExecutable(String name) {
106107
final String platformExecutableName = Platforms.WINDOWS

x-pack/plugin/core/build.gradle

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ esplugin {
2020
}
2121

2222
dependencyLicenses {
23-
mapping from: /bc.*/, to: 'bouncycastle'
2423
mapping from: /http.*/, to: 'httpclient' // pulled in by rest client
2524
mapping from: /commons-.*/, to: 'commons' // pulled in by rest client
2625
}
@@ -38,8 +37,6 @@ dependencies {
3837

3938
// security deps
4039
compile 'com.unboundid:unboundid-ldapsdk:3.2.0'
41-
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
42-
compile 'org.bouncycastle:bcpkix-jdk15on:1.59'
4340
compile project(path: ':modules:transport-netty4', configuration: 'runtime')
4441

4542
testCompile 'org.elasticsearch:securemock:1.2'
@@ -116,6 +113,7 @@ task testJar(type: Jar) {
116113
appendix 'test'
117114
from sourceSets.test.output
118115
}
116+
119117
artifacts {
120118
// normal es plugins do not publish the jar but we need to since users need it for Transport Clients and extensions
121119
archives jar

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/CertParsingUtils.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static Path resolvePath(String path, @Nullable Environment environment) {
6363
return PathUtils.get(path).normalize();
6464
}
6565

66-
static KeyStore readKeyStore(Path path, String type, char[] password)
66+
public static KeyStore readKeyStore(Path path, String type, char[] password)
6767
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException {
6868
try (InputStream in = Files.newInputStream(path)) {
6969
KeyStore store = KeyStore.getInstance(type);
@@ -108,7 +108,7 @@ public static X509Certificate[] readX509Certificates(List<Path> certPaths) throw
108108
return certificates.toArray(new X509Certificate[0]);
109109
}
110110

111-
static List<Certificate> readCertificates(InputStream input) throws CertificateException, IOException {
111+
public static List<Certificate> readCertificates(InputStream input) throws CertificateException, IOException {
112112
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
113113
Collection<Certificate> certificates = (Collection<Certificate>) certFactory.generateCertificates(input);
114114
return new ArrayList<>(certificates);
@@ -140,7 +140,7 @@ public static Map<Certificate, Key> readPkcs12KeyPairs(Path path, char[] passwor
140140
/**
141141
* Creates a {@link KeyStore} from a PEM encoded certificate and key file
142142
*/
143-
static KeyStore getKeyStoreFromPEM(Path certificatePath, Path keyPath, char[] keyPassword)
143+
public static KeyStore getKeyStoreFromPEM(Path certificatePath, Path keyPath, char[] keyPassword)
144144
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
145145
final PrivateKey key = PemUtils.readPrivateKey(keyPath, () -> keyPassword);
146146
final Certificate[] certificates = readCertificates(Collections.singletonList(certificatePath));
@@ -168,7 +168,7 @@ private static KeyStore getKeyStore(Certificate[] certificateChain, PrivateKey p
168168
/**
169169
* Returns a {@link X509ExtendedKeyManager} that is built from the provided keystore
170170
*/
171-
static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm)
171+
public static X509ExtendedKeyManager keyManager(KeyStore keyStore, char[] password, String algorithm)
172172
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
173173
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
174174
kmf.init(keyStore, password);
@@ -271,7 +271,7 @@ public static X509ExtendedTrustManager trustManager(String trustStorePath, Strin
271271
/**
272272
* Creates a {@link X509ExtendedTrustManager} based on the trust material in the provided {@link KeyStore}
273273
*/
274-
static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm)
274+
public static X509ExtendedTrustManager trustManager(KeyStore keyStore, String algorithm)
275275
throws NoSuchAlgorithmException, KeyStoreException {
276276
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
277277
tmf.init(keyStore);

x-pack/plugin/security/build.gradle

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ dependencies {
2222
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
2323

2424
compile 'com.unboundid:unboundid-ldapsdk:3.2.0'
25-
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
26-
compile 'org.bouncycastle:bcpkix-jdk15on:1.59'
25+
compileOnly 'org.bouncycastle:bcprov-jdk15on:1.59'
26+
compileOnly 'org.bouncycastle:bcpkix-jdk15on:1.59'
2727

2828
// the following are all SAML dependencies - might as well download the whole internet
2929
compile "org.opensaml:opensaml-core:3.3.0"
@@ -79,7 +79,6 @@ sourceSets.test.resources {
7979
srcDir '../core/src/test/resources'
8080
}
8181
dependencyLicenses {
82-
mapping from: /bc.*/, to: 'bouncycastle'
8382
mapping from: /java-support|opensaml-.*/, to: 'shibboleth'
8483
mapping from: /http.*/, to: 'httpclient'
8584
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apply plugin: 'elasticsearch.build'
2+
3+
archivesBaseName = 'elasticsearch-security-cli'
4+
5+
dependencies {
6+
compileOnly "org.elasticsearch:elasticsearch:${version}"
7+
compileOnly xpackProject('plugin:core')
8+
compile 'org.bouncycastle:bcprov-jdk15on:1.59'
9+
compile 'org.bouncycastle:bcpkix-jdk15on:1.59'
10+
testImplementation 'com.google.jimfs:jimfs:1.1'
11+
testCompile "junit:junit:${versions.junit}"
12+
testCompile "org.hamcrest:hamcrest-all:${versions.hamcrest}"
13+
testCompile 'org.elasticsearch:securemock:1.2'
14+
testCompile "org.elasticsearch.test:framework:${version}"
15+
testCompile project(path: xpackModule('core'), configuration: 'testArtifacts')
16+
}
17+
18+
dependencyLicenses {
19+
mapping from: /bc.*/, to: 'bouncycastle'
20+
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/CertGenUtils.java renamed to x-pack/plugin/security/cli/src/main/java/org/elasticsearch/xpack/security/cli/CertGenUtils.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* or more contributor license agreements. Licensed under the Elastic License;
44
* you may not use this file except in compliance with the Elastic License.
55
*/
6-
package org.elasticsearch.xpack.core.ssl;
6+
package org.elasticsearch.xpack.security.cli;
77

88
import org.bouncycastle.asn1.ASN1Encodable;
99
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -78,7 +78,7 @@ private CertGenUtils() {
7878
* Generates a CA certificate
7979
*/
8080
public static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair, int days)
81-
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
81+
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
8282
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true, days, null);
8383
}
8484

@@ -100,7 +100,7 @@ public static X509Certificate generateCACertificate(X500Principal x500Principal,
100100
*/
101101
public static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
102102
X509Certificate caCert, PrivateKey caPrivKey, int days)
103-
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
103+
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
104104
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false, days, null);
105105
}
106106

@@ -125,7 +125,7 @@ public static X509Certificate generateSignedCertificate(X500Principal principal,
125125
public static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
126126
X509Certificate caCert, PrivateKey caPrivKey,
127127
int days, String signatureAlgorithm)
128-
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
128+
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
129129
return generateSignedCertificate(principal, subjectAltNames, keyPair, caCert, caPrivKey, false, days, signatureAlgorithm);
130130
}
131131

@@ -150,7 +150,7 @@ public static X509Certificate generateSignedCertificate(X500Principal principal,
150150
private static X509Certificate generateSignedCertificate(X500Principal principal, GeneralNames subjectAltNames, KeyPair keyPair,
151151
X509Certificate caCert, PrivateKey caPrivKey, boolean isCa,
152152
int days, String signatureAlgorithm)
153-
throws NoSuchAlgorithmException, CertificateException, CertIOException, OperatorCreationException {
153+
throws NoSuchAlgorithmException, CertificateException, CertIOException, OperatorCreationException {
154154
Objects.requireNonNull(keyPair, "Key-Pair must not be null");
155155
final DateTime notBefore = new DateTime(DateTimeZone.UTC);
156156
if (days < 1) {
@@ -175,8 +175,8 @@ private static X509Certificate generateSignedCertificate(X500Principal principal
175175
}
176176

177177
JcaX509v3CertificateBuilder builder =
178-
new JcaX509v3CertificateBuilder(issuer, serial,
179-
new Time(notBefore.toDate(), Locale.ROOT), new Time(notAfter.toDate(), Locale.ROOT), subject, keyPair.getPublic());
178+
new JcaX509v3CertificateBuilder(issuer, serial,
179+
new Time(notBefore.toDate(), Locale.ROOT), new Time(notAfter.toDate(), Locale.ROOT), subject, keyPair.getPublic());
180180

181181
builder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
182182
builder.addExtension(Extension.authorityKeyIdentifier, false, authorityKeyIdentifier);
@@ -187,8 +187,8 @@ private static X509Certificate generateSignedCertificate(X500Principal principal
187187

188188
PrivateKey signingKey = caPrivKey != null ? caPrivKey : keyPair.getPrivate();
189189
ContentSigner signer = new JcaContentSignerBuilder(
190-
(Strings.isNullOrEmpty(signatureAlgorithm)) ? getDefaultSignatureAlgorithm(signingKey) : signatureAlgorithm)
191-
.setProvider(CertGenUtils.BC_PROV).build(signingKey);
190+
(Strings.isNullOrEmpty(signatureAlgorithm)) ? getDefaultSignatureAlgorithm(signingKey) : signatureAlgorithm)
191+
.setProvider(CertGenUtils.BC_PROV).build(signingKey);
192192
X509CertificateHolder certificateHolder = builder.build(signer);
193193
return new JcaX509CertificateConverter().getCertificate(certificateHolder);
194194
}
@@ -214,7 +214,7 @@ private static String getDefaultSignatureAlgorithm(PrivateKey key) {
214214
break;
215215
default:
216216
throw new IllegalArgumentException("Unsupported algorithm : " + key.getAlgorithm()
217-
+ " for signature, allowed values for private key algorithm are [RSA, DSA, EC]");
217+
+ " for signature, allowed values for private key algorithm are [RSA, DSA, EC]");
218218
}
219219
return signatureAlgorithm;
220220
}
@@ -229,7 +229,7 @@ private static String getDefaultSignatureAlgorithm(PrivateKey key) {
229229
* @return a certificate signing request
230230
*/
231231
static PKCS10CertificationRequest generateCSR(KeyPair keyPair, X500Principal principal, GeneralNames sanList)
232-
throws IOException, OperatorCreationException {
232+
throws IOException, OperatorCreationException {
233233
Objects.requireNonNull(keyPair, "Key-Pair must not be null");
234234
Objects.requireNonNull(keyPair.getPublic(), "Public-Key must not be null");
235235
Objects.requireNonNull(principal, "Principal must not be null");

0 commit comments

Comments
 (0)