Skip to content

Commit

Permalink
TLS Revocation config (#8425)
Browse files Browse the repository at this point in the history
TLS Revocation config

Signed-off-by: David Kral <david.k.kral@oracle.com>
  • Loading branch information
Verdent committed Mar 11, 2024
1 parent 083c1ba commit 7296040
Show file tree
Hide file tree
Showing 18 changed files with 740 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,28 @@

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertPathBuilder;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXRevocationChecker;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import javax.net.ssl.CertPathTrustManagerParameters;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -291,6 +299,48 @@ protected TrustManagerFactory createTmf(TlsConfig tlsConfig) {
}
}

/**
* Perform initialization of the {@link TrustManagerFactory} based on the provided TLS configuration.
*
* @param tmf trust manager factory to be initialized
* @param keyStore keystore
* @param tlsConfig tls configuration
*/
protected void initializeTmf(TrustManagerFactory tmf, KeyStore keyStore, TlsConfig tlsConfig) {
try {
if (tlsConfig.revocation().isPresent()) {
RevocationConfig revocationConfig = tlsConfig.revocation().get();
if (revocationConfig.enabled()) {
CertPathBuilder cpb = null;
cpb = CertPathBuilder.getInstance("PKIX");
PKIXRevocationChecker rc = (PKIXRevocationChecker) cpb.getRevocationChecker();
Set<PKIXRevocationChecker.Option> options = new HashSet<>();
if (revocationConfig.preferCrlOverOcsp()) {
options.add(PKIXRevocationChecker.Option.PREFER_CRLS);
}
if (revocationConfig.checkOnlyEndEntity()) {
options.add(PKIXRevocationChecker.Option.ONLY_END_ENTITY);
}
if (!revocationConfig.fallbackEnabled()) {
options.add(PKIXRevocationChecker.Option.NO_FALLBACK);
}
if (revocationConfig.softFailEnabled()) {
options.add(PKIXRevocationChecker.Option.SOFT_FAIL);
}
rc.setOptions(options);
revocationConfig.ocspResponderUri().ifPresent(rc::setOcspResponder);
PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(keyStore, new X509CertSelector());
pkixParams.addCertPathChecker(rc);
tmf.init(new CertPathTrustManagerParameters(pkixParams));
return;
}
}
tmf.init(keyStore);
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | KeyStoreException e) {
throw new IllegalArgumentException("Failed to initialize TrustManagerFactory", e);
}
}

/**
* Creates a trust all trust manager factory.
*
Expand All @@ -310,7 +360,7 @@ private TrustManagerFactory initTmf(TlsConfig tlsConfig) throws KeyStoreExceptio
i++;
}
TrustManagerFactory tmf = createTmf(tlsConfig);
tmf.init(ks);
initializeTmf(tmf, ks, tlsConfig);
return tmf;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.common.tls;

import java.net.URI;
import java.util.Optional;

import io.helidon.builder.api.Option;
import io.helidon.builder.api.Prototype;

/**
* Certificate revocation configuration.
* This configuration determines whether client certificate validation should include checking if
* it is still considered valid by the certificate authority.
* <br>
* Types of certificate validation checks:
* <ul>
* <li>CRL - shortcut name for Certificate Revocation List. It is a list of certificates that have
* been revoked by a certificate authority before their expiration date</li>
* <li>OCSP - shortcut name for Online Certificate Status Protocol. It is a real-time protocol used
* to check the status of a certificate, providing immediate verification of its validity</li>
* </ul>
*/
@Prototype.Blueprint
@Prototype.Configured
interface RevocationConfigBlueprint {

/**
* Flag indicating whether this revocation config is enabled.
*
* @return enabled flag
*/
@Option.Configured
@Option.DefaultBoolean(false)
boolean enabled();

/**
* Prefer CRL over OCSP.
* Default value is {@code false}. OCSP is preferred over the CRL by default.
*
* @return whether to prefer CRL over OCSP
*/
@Option.Configured
@Option.DefaultBoolean(false)
boolean preferCrlOverOcsp();

/**
* Only check the revocation status of end-entity certificates.
* Default value is {@code false}.
*
* @return whether to check only end-entity certificates
*/
@Option.Configured
@Option.DefaultBoolean(false)
boolean checkOnlyEndEntity();

/**
* Enable fallback to the less preferred checking option.
* <br>
* If the primary method for revocation checking fails to verify the revocation status of a certificate
* (such as using a CRL or OCSP), the checker will attempt alternative methods. This option ensures
* whether revocation checking is performed strictly according to the specified method, or should fallback
* to the one less preferred. OCSP is preferred over the CRL by default.
*
* @return whether to allow fallback to the less preferred checking option
*/
@Option.Configured
@Option.DefaultBoolean(true)
boolean fallbackEnabled();

/**
* Allow revocation check to succeed if the revocation status cannot be
* determined for one of the following reasons:
* <ul>
* <li>The CRL or OCSP response cannot be obtained because of a
* network error.
* <li>The OCSP responder returns one of the following errors
* specified in section 2.3 of RFC 2560: internalError or tryLater.
* </ul>
*
* @return whether soft fail is enabled
*/
@Option.Configured
@Option.DefaultBoolean(false)
boolean softFailEnabled();

/**
* The URI that identifies the location of the OCSP responder. This
* overrides the {@code ocsp.responderURL} security property and any
* responder specified in a certificate's Authority Information Access
* Extension, as defined in RFC 5280.
*
* @return OCSP responder URI
*/
@Option.Configured
Optional<URI> ocspResponderUri();

}
Original file line number Diff line number Diff line change
Expand Up @@ -291,4 +291,12 @@ static List<X509Certificate> createTrust(Keys config) {
@Option.Configured
Optional<String> internalKeystoreProvider();

/**
* Certificate revocation check configuration.
*
* @return certificate revocation configuration
*/
@Option.Configured
Optional<RevocationConfig> revocation();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2024 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

///////////////////////////////////////////////////////////////////////////////
ifndef::rootdir[:rootdir: {docdir}/..]
:description: Configuration of io.helidon.common.tls.RevocationConfig
:keywords: helidon, config, io.helidon.common.tls.RevocationConfig
:basic-table-intro: The table below lists the configuration keys that configure io.helidon.common.tls.RevocationConfig
include::{rootdir}/includes/attributes.adoc[]
= RevocationConfig (common.tls) Configuration
// tag::config[]
Type: link:{javadoc-base-url}/io.helidon.common.tls/io/helidon/common/tls/RevocationConfig.html[io.helidon.common.tls.RevocationConfig]
== Configuration options
.Optional configuration options
[cols="3,3a,2,5a"]
|===
|key |type |default value |description
|`check-only-end-entity` |boolean |`false` |Only check the revocation status of end-entity certificates.
Default value is `false`.
@return whether to check only end-entity certificates
|`enabled` |boolean |`false` |Flag indicating whether this revocation config is enabled.
@return enabled flag
|`fallback-enabled` |boolean |`true` |Enable fallback to the less preferred checking option.
@return whether to allow fallback to the less preferred checking option
|`ocsp-responder-uri` |URI |{nbsp} |The URI that identifies the location of the OCSP responder. This
overrides the `ocsp.responderURL` security property and any
responder specified in a certificate's Authority Information Access
Extension, as defined in RFC 5280.
@return OCSP responder URI
|`prefer-crl-over-ocsp` |boolean |`false` |Prefer CRL over OCSP.
Default value is `false`.
@return whether to prefer CRL over OCSP
|`soft-fail-enabled` |boolean |`false` |Allow revocation check to succeed if the revocation status cannot be
determined for one of the following reasons:
- The CRL or OCSP response cannot be obtained because of a
network error.
- The OCSP responder returns one of the following errors
specified in section 2.3 of RFC 2560: internalError or tryLater.
@return whether soft fail is enabled
|===
// end::config[]
5 changes: 4 additions & 1 deletion docs/src/main/asciidoc/config/io_helidon_common_tls_Tls.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
///////////////////////////////////////////////////////////////////////////////

Copyright (c) 2023 Oracle and/or its affiliates.
Copyright (c) 2024 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -85,6 +85,9 @@ Type: link:{javadoc-base-url}/io.helidon.common.tls/io/helidon/common/tls/Tls.ht
|`provider` |string |{nbsp} |Use explicit provider to obtain an instance of javax.net.ssl.SSLContext.
@return provider to use, defaults to none (only #protocol() is used by default)
|`revocation` |xref:{rootdir}/config/io_helidon_common_tls_RevocationConfig.adoc[RevocationConfig] |{nbsp} |Certificate revocation check configuration.
@return certificate revocation configuration
|`secure-random-algorithm` |string |{nbsp} |Algorithm to use when creating a new secure random.
@return algorithm to use, by default uses java.security.SecureRandom constructor
Expand Down
1 change: 1 addition & 0 deletions etc/copyright-exclude.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jaxb.index
.bin
.vm
.sql
.crl
src/main/proto/
src/test/resources/keystore/
etc/javadoc/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
* Copyright (c) 2023, 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -170,7 +170,7 @@ boolean loadContext(boolean initialLoad) {
tmf = createTmf(tlsConfig);
KeyStore keyStore = internalKeystore(tlsConfig);
keyStore.setCertificateEntry("trust-ca", ca);
tmf.init(keyStore);
initializeTmf(tmf, keyStore, tlsConfig);
}

Optional<X509KeyManager> keyManager = Arrays.stream(kmf.getKeyManagers())
Expand Down
1 change: 1 addition & 0 deletions tests/integration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
<module>security</module>
<module>vault</module>
<module>zipkin-mp-2.2</module>
<module>tls-revocation-config</module>
</modules>

<dependencyManagement>
Expand Down
Loading

0 comments on commit 7296040

Please sign in to comment.