Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update "ssl-config" to support X-Pack features #74887

Merged

Conversation

tvernum
Copy link
Contributor

@tvernum tvernum commented Jul 5, 2021

This commit upgrades the existing SSPL licensed "ssl-config" library
to include additional features that are supported by the X-Pack SSL
library.

This commit does not make any changes to X-Pack to use these new
features - it introduces them in preparation for their future use by
X-Pack.

The reindex module is updated to reflect API changes in ssl-config

This commit upgrades the existing SSPL licensed "ssl-config" library
to include additional features that are supported by the X-Pack SSL
library.

This commit does not make any changes to X-Pack to use these new
features - it introduces them in preparation for their future use by
X-Pack.

The reindex module is updated to reflect API changes in ssl-config
@tvernum tvernum requested review from jkakavas and BigPandaToo July 5, 2021 01:44
@elasticmachine elasticmachine added the Team:Security Meta label for security team label Jul 5, 2021
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security (Team:Security)

@tvernum
Copy link
Contributor Author

tvernum commented Jul 5, 2021

I've labelled this as v8.0.0 only, because it's not needed in 7.x (it's only here to support migrating x-pack SSL onto this library).
We can talk about backporting it to 7.x if someone feels strongly, but I didn't make the changes with perfect BWC in mind, I'd need to do a review first.

/**
* A TrustConfiguration that merges trust anchors from a number of other trust configs to produce a single {@link X509ExtendedTrustManager}.
*/
public class CompositeTrustConfig implements SslTrustConfig {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In X-Pack, specifying a keystore, but no truststore gives you a set of trust anchors that support everything in your JDK trust, and all the trust anchors in your keystore.
This class was added so we can also support that behaviour from ssl-config.

@@ -51,6 +53,11 @@
this.trustStorePassword = trustStorePassword;
}

@Override
public boolean isSystemDefault() {
return true;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method needed for the PKI realm - it will not trust the JDK default issuers.

@@ -31,7 +31,7 @@
* Based on https://github.com/groovenauts/jmeter_oauth_plugin/blob/master/jmeter/src/
* main/java/org/apache/jmeter/protocol/oauth/sampler/PrivateKeyReader.java
*/
final class DerParser {
public final class DerParser {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RestrictedTrustConfig in X-Pack needs to be able to use this parser.


/**
* A variety of utility methods for working with or constructing {@link KeyStore} instances.
*/
final class KeyStoreUtil {
public final class KeyStoreUtil {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these methods have been made public because X-Pack will need to call them.

}

static Stream<KeyStoreEntry> stream(KeyStore keyStore,
Function<GeneralSecurityException, ? extends RuntimeException> exceptionHandler) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method and the class below were added to support stream-based iteration over keystore entires.

} catch (GeneralSecurityException e) {
throw new SslConfigException("cannot load ssl private key file [" + key.toAbsolutePath() + "]", e);
throw SslFileUtil.securityException(KEY_FILE_TYPE, List.of(path), e);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of exception handling has been unified. See comments in SslFileUtil

/**
* Utility methods for common file handling in SSL configuration
*/
final class SslFileUtil {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new class, mostly to handle generating exceptions for particular file related problems.

return ioException(fileType, paths, cause, null);
}

static SslConfigException ioException(String fileType, List<Path> paths, IOException cause, String detail) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the big things we did to try and make X-Pack SSL setup easier was write clear & explicit error messages for all the common problems that people run into:

  • File not found
  • File permissions wrong
  • File in wrong directory
  • Missing password
  • Wrong password

This class replicates those messages into ssl-config and centralises them.
Some of the messages already existed in this library, but the X-Pack ones are encountered more frequently, and have been better turned for readability.

That said, I did try and improve some of them along the way.

import java.util.Objects;
import java.util.stream.Collectors;

public abstract class SslKeystoreConfig implements SslKeyConfig {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a base class for PKCS#11 and File-Keystore (JKS, PKCS#12) support.
The X-Pack model of having 1 class that handled both was really fragile - we often wrote code that assume that the file was non-null.

* Information about a certificate that is locally stored.It includes a reference to the {@link X509Certificate} itself,
* as well as information about where it was loaded from.
*/
public class StoredCertificate {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used for the _ssl/certificates API.
That API uses a CertificateInfo which depends on ToXContent etc, which isn't available inside this library. So this class is a lightweight representation of the information needed for that API, and X-Pack will convert from this class to the X-Pack class.

@tvernum tvernum added the :Security/FIPS Running ES in FIPS 140-2 mode label Jul 5, 2021
@tvernum
Copy link
Contributor Author

tvernum commented Jul 13, 2021

@elasticmachine update branch

Copy link
Contributor

@BigPandaToo BigPandaToo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a couple of nit comments.
LGTM otherwise

@@ -91,9 +91,10 @@ static KeyStore buildKeyStore(Collection<Certificate> certificateChain, PrivateK

/**
* Construct an in-memory keystore with multiple trusted cert entries.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't say so.
Everything in that file has blank line between the method description & the parameters, so this format is consistent with the rest of the code.

Copy link
Member

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking the time to add comments for things that would most probably raise questions, that was very helpful. Added some suggestions and comments, mostly nits

* @param keyPassword Password for the private key (or empty is the key is not encrypted)
* @param configBasePath The base directory from which config files should be read (used for diagnostic exceptions)
*/
public PemKeyConfig(String certificate, String key, char[] keyPassword, Path configBasePath) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit for readability

Suggested change
public PemKeyConfig(String certificate, String key, char[] keyPassword, Path configBasePath) {
public PemKeyConfig(String certificatePath, String key, char[] keyPassword, Path configBasePath) {

boolean first = true;
for (Certificate cert : certificates) {
if (cert instanceof X509Certificate) {
info.add(new StoredCertificate((X509Certificate) cert, this.certificate, "PEM", null, first));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it safe to assume that certificate points to a file where if multiple certs are included, the leaf is always the first one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not - but that's what X-Pack currently does.

It should be - if the certificate path points to a PEM file with multiple certificates, then they should be a chain ordered from leaf to issuer to root - but there's no guarantee that it's true.

However, other things will break if it's not. When we build a keystore we will assume the certificates that we read form a valid chain, and Keystore.setKeyEntry will throw an exception if they're not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a test to show that createKeyManager fails if the chain is in the wrong order. I think that is sufficient for the assumption in this method.

We do have a "private key" for the leaf (first element) certificate. It might be the wrong key (none of the config classes check that in this method), but we have one.
And the core functionality of the config (building a key manager) will fail.

final Path trustStorePath = resolveSetting(TRUSTSTORE_PATH, basePath::resolve, null);
protected SslTrustConfig buildTrustConfig(Path basePath, SslVerificationMode verificationMode, SslKeyConfig keyConfig) {
final List<String> certificateAuthorities = resolveListSetting(CERTIFICATE_AUTHORITIES, Function.identity(), null);
final String trustStorePath = resolveSetting(TRUSTSTORE_PATH, Function.identity(), null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:+1

if (cause.getMessage() != null) {
message += " (" + cause.getMessage() + ")";
}
if (detail != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it worth adding the hint about UnrecoverableKeyException ? ( maybe only if detail is null )

/**
* @return A collection of {@link X509Certificate certificates} used by this config.
*/
Collection<? extends StoredCertificate> getConfiguredCertificates();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we foresee exteding StoredCertificate ? Can we make the return type non generic for now ?

List<Tuple<PrivateKey, X509Certificate>> getKeys();

/**
* @return A collection of {@link X509Certificate certificates} used by this config.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: update javadoc with corret return type

if (certificates.isEmpty()) {
return List.of();
}
final Certificate certificate = certificates.get(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rename certificate here for readability ( vs this.certificate)


if (cause.getCause() instanceof UnrecoverableKeyException) {
message += " - this is usually caused by an incorrect password";
} else if (cause != null && cause.getMessage() != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cause can't be null here, otherwise we'd have thrown an NPE in cause.getCause() above. We can check that cause is not null above and not go into this conditional at all

tvernum added 4 commits July 15, 2021 15:45
- Remove PKCS#11
- Improve exception messages
- Simplify return types
PemKeyConfig.getConfiguredCertificates relies on the certificate file
containing a chain from leaf -> issuer -> .. -> root

This commit adds a test to ensure that createKeyManager will fail if
that order is not correct, and therefore the assumption in
getConfiguredCertificates is acceptable
@tvernum tvernum requested a review from jkakavas July 15, 2021 06:46
Copy link
Member

@jkakavas jkakavas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tvernum tvernum merged commit 940a890 into elastic:master Jul 15, 2021
masseyke pushed a commit to masseyke/elasticsearch that referenced this pull request Jul 16, 2021
This commit upgrades the existing SSPL licensed "ssl-config" library
to include additional features that are supported by the X-Pack SSL
library.

This commit does not make any changes to X-Pack to use these new
features - it introduces them in preparation for their future use by
X-Pack.

The reindex module is updated to reflect API changes in ssl-config
ywangd pushed a commit to ywangd/elasticsearch that referenced this pull request Jul 30, 2021
This commit upgrades the existing SSPL licensed "ssl-config" library
to include additional features that are supported by the X-Pack SSL
library.

This commit does not make any changes to X-Pack to use these new
features - it introduces them in preparation for their future use by
X-Pack.

The reindex module is updated to reflect API changes in ssl-config
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>non-issue :Security/FIPS Running ES in FIPS 140-2 mode :Security/TLS SSL/TLS, Certificates Team:Security Meta label for security team v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants