From 486128c45aa76b64543cf590dca637362a177e0e Mon Sep 17 00:00:00 2001 From: Philip Helger Date: Sun, 10 Nov 2024 20:51:57 +0100 Subject: [PATCH] Reworked Certificate checking to be more flexible and streamlined --- README.md | 5 + .../utils/AbstractRevocationCheckBuilder.java | 57 ++- ...CertificateRevocationCheckerDefaults.java} | 49 ++- .../helger/peppol/utils/PeppolCAChecker.java | 136 +++++++ .../utils/PeppolCertificateChecker.java | 341 ++++++------------ .../peppol/utils/PeppolRevocationCache.java | 5 +- .../peppol/utils/RevocationCheckBuilder.java | 30 ++ .../peppol/utils/TrustedCACertificates.java | 41 +-- .../utils/PeppolCertificateCheckerTest.java | 85 +++-- .../utils/PeppolCertificateHelperTest.java | 12 +- .../TrustStoreBasedX509KeySelector.java | 20 +- .../peppol/SMPClientReadOnlyTest.java | 13 +- 12 files changed, 436 insertions(+), 358 deletions(-) rename peppol-commons/src/main/java/com/helger/peppol/utils/{CertificateRevocationChecker.java => CertificateRevocationCheckerDefaults.java} (85%) create mode 100644 peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCAChecker.java create mode 100644 peppol-commons/src/main/java/com/helger/peppol/utils/RevocationCheckBuilder.java diff --git a/README.md b/README.md index ac5ee33d..c646f212 100644 --- a/README.md +++ b/README.md @@ -310,6 +310,11 @@ They depend on several other libraries so I suggest you are going for the Maven * Moved method `PeppolCertificateHelper.getAllTrustedCertificates` to class `PeppolKeyStoreHelper` * Added new methods to support Peppol Policy for use of Identifiers 4.3.0 * Added new annotations `@Pfuoi420` and `@Pfuoi430` to hint methods that are specification specific + * Added support for eB2B AP Pilot Trust Store as a predefined truststore + * Renamed class `CertificateRevocationChecker` to `CertificateRevocationCheckerDefaults` + * Made class `RevocationCheckBuilder` a top-level class + * Totally reworked class `PeppolCertificateChecker` to add flexibility and support multiple Peppol CAs + * Added new class `PeppolCAChecker` to support in the verification of Peppol certificates * v9.5.1 - 2024-08-11 * Make sure that wildcard lookups including a "*" in the Customization ID will always fail * Added additional `SMPClientReadOnly.getWildcardServiceMetadataOrNull` overload diff --git a/peppol-commons/src/main/java/com/helger/peppol/utils/AbstractRevocationCheckBuilder.java b/peppol-commons/src/main/java/com/helger/peppol/utils/AbstractRevocationCheckBuilder.java index 6f205290..a95875f1 100644 --- a/peppol-commons/src/main/java/com/helger/peppol/utils/AbstractRevocationCheckBuilder.java +++ b/peppol-commons/src/main/java/com/helger/peppol/utils/AbstractRevocationCheckBuilder.java @@ -88,7 +88,7 @@ public abstract class AbstractRevocationCheckBuilder > m_aSoftFailExceptionHdl; private ETriState m_eExecuteInSynchronizedBlock = ETriState.UNDEFINED; private Duration m_aExecutionDurationWarn = DEFAULT_EXECUTION_WARN_DURATION; - private CRLCache m_aCRLCache = CertificateRevocationChecker.getDefaultCRLCache (); + private CRLCache m_aCRLCache = CertificateRevocationCheckerDefaults.getDefaultCRLCache (); public AbstractRevocationCheckBuilder () {} @@ -146,6 +146,22 @@ public final IMPLTYPE validCAs (@Nullable final Iterable null. + * @return this for chaining + */ + @Nonnull + public final IMPLTYPE validCAs (@Nullable final X509Certificate... a) + { + m_aValidCAs.setAll (a); + return thisAsT (); + } + /** * Set the valid CAs to be checked against from the provided trust store. All * previous trusted CAs are removed. @@ -191,6 +207,21 @@ public final IMPLTYPE addValidCAs (@Nullable final Iterable null. + * @return this for chaining + */ + @Nonnull + public final IMPLTYPE addValidCAs (@Nullable final X509Certificate... a) + { + m_aValidCAs.addAll (a); + return thisAsT (); + } + /** * Add the valid CAs to be checked against from the provided trust store. All * previously contained valid CAs are kept. @@ -370,7 +401,7 @@ public final IMPLTYPE softFailExceptionHandler (@Nullable final Consumer true to enable it, false to disable it. * @return this for chaining - * @see CertificateRevocationChecker#isExecuteInSynchronizedBlock() + * @see CertificateRevocationCheckerDefaults#isExecuteInSynchronizedBlock() */ @Nonnull public final IMPLTYPE executeInSynchronizedBlock (final boolean b) @@ -438,15 +469,15 @@ public final IMPLTYPE crlCache (@Nonnull final CRLCache a) * performed: * */ @Nonnull @@ -454,15 +485,15 @@ public ERevoked build () { // Fallback to global settings where possible final ERevocationCheckMode eRealCheckMode = m_eCheckMode != null ? m_eCheckMode - : CertificateRevocationChecker.getRevocationCheckMode (); + : CertificateRevocationCheckerDefaults.getRevocationCheckMode (); final Consumer aRealExceptionHdl = m_aExceptionHdl != null ? m_aExceptionHdl - : CertificateRevocationChecker.getExceptionHdl (); + : CertificateRevocationCheckerDefaults.getExceptionHdl (); final boolean bAllowSoftFail = m_eAllowSoftFail.isDefined () ? m_eAllowSoftFail.getAsBooleanValue () - : CertificateRevocationChecker.isAllowSoftFail (); + : CertificateRevocationCheckerDefaults.isAllowSoftFail (); final Consumer > aRealSoftFailExceptionHdl = m_aSoftFailExceptionHdl != null ? m_aSoftFailExceptionHdl - : CertificateRevocationChecker.getSoftFailExceptionHdl (); + : CertificateRevocationCheckerDefaults.getSoftFailExceptionHdl (); final boolean bExecuteSync = m_eExecuteInSynchronizedBlock.isDefined () ? m_eExecuteInSynchronizedBlock.getAsBooleanValue () - : CertificateRevocationChecker.isExecuteInSynchronizedBlock (); + : CertificateRevocationCheckerDefaults.isExecuteInSynchronizedBlock (); // Consistency checks if (m_aCert == null) @@ -606,7 +637,7 @@ public ERevoked build () if (bExecuteSync) { // Synchronize because the change of the Security.property is global - synchronized (CertificateRevocationChecker.class) + synchronized (CertificateRevocationCheckerDefaults.class) { aPerformer.run (); } diff --git a/peppol-commons/src/main/java/com/helger/peppol/utils/CertificateRevocationChecker.java b/peppol-commons/src/main/java/com/helger/peppol/utils/CertificateRevocationCheckerDefaults.java similarity index 85% rename from peppol-commons/src/main/java/com/helger/peppol/utils/CertificateRevocationChecker.java rename to peppol-commons/src/main/java/com/helger/peppol/utils/CertificateRevocationCheckerDefaults.java index 46a916eb..0777d3f2 100644 --- a/peppol-commons/src/main/java/com/helger/peppol/utils/CertificateRevocationChecker.java +++ b/peppol-commons/src/main/java/com/helger/peppol/utils/CertificateRevocationCheckerDefaults.java @@ -18,13 +18,13 @@ import java.security.GeneralSecurityException; import java.security.cert.CertPathValidatorException; +import java.time.Duration; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.ThreadSafe; import org.slf4j.Logger; @@ -34,21 +34,25 @@ import com.helger.commons.concurrent.SimpleReadWriteLock; /** - * A generic class to check certificates against OCSP and CRL servers. + * A helper class with certificate revocation check defaults. Name prior to + * v9.6.0 was CertificateRevocationChecker * * @author Philip Helger * @since 8.5.2 */ @ThreadSafe -public final class CertificateRevocationChecker +public final class CertificateRevocationCheckerDefaults { // By default only CRL is used // https://github.com/phax/phase4/issues/124 public static final ERevocationCheckMode DEFAULT_REVOCATION_CHECK_MODE = ERevocationCheckMode.CRL; public static final boolean DEFAULT_ALLOW_SOFT_FAIL = false; public static final boolean DEFAULT_ALLOW_EXEC_SYNC = true; + public static final boolean DEFAULT_CACHE_REVOCATION_CHECK_RESULTS = true; - private static final Logger LOGGER = LoggerFactory.getLogger (CertificateRevocationChecker.class); + public static final Duration DEFAULT_REVOCATION_CHECK_CACHING_DURATION = Duration.ofHours (6); + + private static final Logger LOGGER = LoggerFactory.getLogger (CertificateRevocationCheckerDefaults.class); private static final SimpleReadWriteLock RW_LOCK = new SimpleReadWriteLock (); @GuardedBy ("RW_LOCK") @@ -63,8 +67,10 @@ public final class CertificateRevocationChecker private static final AtomicBoolean ALLOW_EXEC_SYNC = new AtomicBoolean (DEFAULT_ALLOW_EXEC_SYNC); @GuardedBy ("RW_LOCK") private static CRLCache s_aDefaultCRLCache = CRLCache.createDefault (); + // Revocation checking stuff + private static final AtomicBoolean CACHE_REVOCATION_RESULTS = new AtomicBoolean (DEFAULT_CACHE_REVOCATION_CHECK_RESULTS); - private CertificateRevocationChecker () + private CertificateRevocationCheckerDefaults () {} /** @@ -221,19 +227,36 @@ public static void setDefaultCRLCache (@Nonnull final CRLCache aCRLCache) } /** - * @return A new {@link RevocationCheckBuilder} instance. + * @return true if OSCP results may be cached, false + * if not. The default is + * {@value #DEFAULT_CACHE_REVOCATION_CHECK_RESULTS}. + * @since 9.6.0 */ - public static RevocationCheckBuilder revocationCheck () + public static boolean isCacheRevocationCheckResults () { - return new RevocationCheckBuilder (); + return CACHE_REVOCATION_RESULTS.get (); } /** - * A generic revocation check builder that works with arbitrary certificates. + * Enable or disable caching of OSCP results. * - * @author Philip Helger + * @param bCache + * true to enable caching, false to disable + * it. + * @since 9.6.0 */ - @NotThreadSafe - public static class RevocationCheckBuilder extends AbstractRevocationCheckBuilder - {} + public static void setCacheRevocationCheckResults (final boolean bCache) + { + CACHE_REVOCATION_RESULTS.set (bCache); + LOGGER.info ("Global cache revocation check results enabled: " + bCache); + } + + /** + * @return A new {@link RevocationCheckBuilder} instance. + */ + @Deprecated (forRemoval = true, since = "9.6.0") + public static RevocationCheckBuilder revocationCheck () + { + return new RevocationCheckBuilder (); + } } diff --git a/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCAChecker.java b/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCAChecker.java new file mode 100644 index 00000000..82045492 --- /dev/null +++ b/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCAChecker.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2015-2024 Philip Helger + * philip[at]helger[dot]com + * + * 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 com.helger.peppol.utils; + +import java.security.cert.X509Certificate; +import java.time.OffsetDateTime; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.helger.commons.ValueEnforcer; +import com.helger.commons.datetime.PDTFactory; +import com.helger.commons.state.EChange; +import com.helger.commons.state.ETriState; + +/** + * This is a specific helper class to check the validity of Peppol certificates + * for a specific PA. See {@link PeppolCertificateChecker} for predefined + * instances of this class. + * + * @author Philip Helger + * @since 9.6.0 + */ +public final class PeppolCAChecker +{ + private final TrustedCACertificates m_aTrustedCAs = new TrustedCACertificates (); + private final PeppolRevocationCache m_aRevocationCache; + + /** + * Constructor + * + * @param aCACerts + * The trusted CA certificates to be used. May neither be + * null nor empty. + */ + public PeppolCAChecker (@Nonnull final X509Certificate... aCACerts) + { + ValueEnforcer.notNullNoNullValue (aCACerts, "CACerts"); + for (final X509Certificate aCACert : aCACerts) + m_aTrustedCAs.addTrustedCACertificate (aCACert); + // The cache always uses "now" as the checking date and time + m_aRevocationCache = new PeppolRevocationCache (aCert -> new RevocationCheckBuilder ().certificate (aCert) + .validCAs (aCACerts) + .checkMode (CertificateRevocationCheckerDefaults.getRevocationCheckMode ()) + .build (), + CertificateRevocationCheckerDefaults.DEFAULT_REVOCATION_CHECK_CACHING_DURATION); + } + + /** + * Check if the provided certificate is a valid Peppol certificate according + * to the configured CA. + * + * @param aCert + * The certificate to be checked. May be null. + * @return {@link EPeppolCertificateCheckResult} and never null. + */ + @Nonnull + public EPeppolCertificateCheckResult checkCertificate (@Nullable final X509Certificate aCert) + { + return checkCertificate (aCert, PDTFactory.getCurrentOffsetDateTime ()); + } + + /** + * Check if the provided certificate is a valid Peppol certificate according + * to the configured CA. + * + * @param aCert + * The certificate to be checked. May be null. + * @param aCheckDT + * The check date and time to use. May be null which means + * "now". + * @return {@link EPeppolCertificateCheckResult} and never null. + */ + @Nonnull + public EPeppolCertificateCheckResult checkCertificate (@Nullable final X509Certificate aCert, + @Nullable final OffsetDateTime aCheckDT) + { + return checkCertificate (aCert, aCheckDT, ETriState.UNDEFINED, null); + } + + /** + * Check if the provided certificate is a valid Peppol certificate according + * to the configured CA. + * + * @param aCert + * The certificate to be checked. May be null. + * @param aCheckDT + * The check date and time to use. May be null which means + * "now". + * @param eCacheRevocationCheckResult + * Define whether to cache the revocation check results or not. Use + * {@link ETriState#UNDEFINED} to solely use the default. + * @param eCheckMode + * Possibility to override the revocation checking mode for each check. + * May be null to use the global state from + * {@link CertificateRevocationCheckerDefaults#getRevocationCheckMode()}. + * @return {@link EPeppolCertificateCheckResult} and never null. + */ + @Nonnull + public EPeppolCertificateCheckResult checkCertificate (@Nullable final X509Certificate aCert, + @Nullable final OffsetDateTime aCheckDT, + @Nonnull final ETriState eCacheRevocationCheckResult, + @Nullable final ERevocationCheckMode eCheckMode) + { + final boolean bUseRevocationCache = eCacheRevocationCheckResult.isUndefined () ? CertificateRevocationCheckerDefaults.isCacheRevocationCheckResults () + : eCacheRevocationCheckResult.isTrue (); + + return PeppolCertificateChecker.checkCertificate (m_aTrustedCAs.getAllTrustedCAIssuers (), + bUseRevocationCache && aCheckDT == null ? m_aRevocationCache + : null, + new RevocationCheckBuilder ().certificate (aCert) + .checkDate (aCheckDT) + .validCAs (m_aTrustedCAs.getAllTrustedCACertificates ()) + .checkMode (eCheckMode)); + } + + @Nonnull + public EChange clearRevocationCache () + { + return m_aRevocationCache.clearCache (); + } +} diff --git a/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCertificateChecker.java b/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCertificateChecker.java index 81e8e86e..3fe476e0 100644 --- a/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCertificateChecker.java +++ b/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolCertificateChecker.java @@ -21,11 +21,9 @@ import java.security.cert.X509Certificate; import java.time.OffsetDateTime; import java.util.Date; -import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.ThreadSafe; import javax.security.auth.x500.X500Principal; @@ -33,10 +31,7 @@ import org.slf4j.LoggerFactory; import com.helger.commons.ValueEnforcer; -import com.helger.commons.annotation.Nonempty; -import com.helger.commons.annotation.ReturnsMutableCopy; -import com.helger.commons.annotation.ReturnsMutableObject; -import com.helger.commons.collection.impl.ICommonsList; +import com.helger.commons.collection.impl.ICommonsSet; import com.helger.commons.state.ETriState; /** @@ -48,285 +43,169 @@ @ThreadSafe public final class PeppolCertificateChecker { - public static final boolean DEFAULT_CACHE_OSCP_RESULTS = true; + /** + * @deprecated Use + * {@link CertificateRevocationCheckerDefaults#DEFAULT_CACHE_REVOCATION_CHECK_RESULTS} + * instead + */ + @Deprecated (forRemoval = true, since = "9.6.0") + public static final boolean DEFAULT_CACHE_OSCP_RESULTS = CertificateRevocationCheckerDefaults.DEFAULT_CACHE_REVOCATION_CHECK_RESULTS; private static final Logger LOGGER = LoggerFactory.getLogger (PeppolCertificateChecker.class); - // Revocation checking stuff - private static final AtomicBoolean CACHE_OCSP_RESULTS = new AtomicBoolean (DEFAULT_CACHE_OSCP_RESULTS); - - /** Peppol Access Point (AP) stuff */ - private static final TrustedCACertificates PEPPOL_AP_TRUSTED = new TrustedCACertificates (); + private static final PeppolCAChecker PILOT_AP = new PeppolCAChecker (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP); + private static final PeppolCAChecker PROD_AP = new PeppolCAChecker (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PRODUCTION_AP); + private static final PeppolCAChecker ALL_AP = new PeppolCAChecker (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP, + PeppolKeyStoreHelper.Config2018.CERTIFICATE_PRODUCTION_AP); - /** Peppol Service Metadata Publisher (SMP) stuff */ - private static final TrustedCACertificates PEPPOL_SMP_TRUSTED = new TrustedCACertificates (); + private static final PeppolCAChecker PILOT_SMP = new PeppolCAChecker (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_SMP); + private static final PeppolCAChecker PROD_SMP = new PeppolCAChecker (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PRODUCTION_SMP); + private static final PeppolCAChecker ALL_SMP = new PeppolCAChecker (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_SMP, + PeppolKeyStoreHelper.Config2018.CERTIFICATE_PRODUCTION_SMP); - static - { - // PKI v3 (recursive) - PEPPOL_AP_TRUSTED.addTrustedCACertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP); - PEPPOL_AP_TRUSTED.addTrustedCACertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PRODUCTION_AP); - - PEPPOL_SMP_TRUSTED.addTrustedCACertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_SMP); - PEPPOL_SMP_TRUSTED.addTrustedCACertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PRODUCTION_SMP); - } - - // Caches don't consider the checking date - private static final PeppolRevocationCache REVOCATION_CACHE_AP = new PeppolRevocationCache (aCert -> peppolRevocationCheck ().certificate (aCert) - .validCAsPeppolAP () - .build (), - PeppolRevocationCache.DEFAULT_CACHING_DURATION); - private static final PeppolRevocationCache REVOCATION_CACHE_SMP = new PeppolRevocationCache (aCert -> peppolRevocationCheck ().certificate (aCert) - .validCAsPeppolSMP () - .build (), - PeppolRevocationCache.DEFAULT_CACHING_DURATION); + private static final PeppolCAChecker PILOT_EB2B_AP = new PeppolCAChecker (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_EB2B_AP); private PeppolCertificateChecker () {} /** - * @return true if OSCP results may be cached, false - * if not. The default is {@value #DEFAULT_CACHE_OSCP_RESULTS}. - */ - public static boolean isCacheOCSPResults () - { - return CACHE_OCSP_RESULTS.get (); - } - - /** - * Enable or disable caching of OSCP results. - * - * @param bCache - * true to enable caching, false to disable - * it. + * @return The Peppol CA checker for Pilot AP certificates. + * @since 9.6.0 */ - public static void setCacheOCSPResults (final boolean bCache) + @Nonnull + public static PeppolCAChecker peppolPilotAP () { - CACHE_OCSP_RESULTS.set (bCache); - LOGGER.info ("Global PeppolCertificateChecker OCSP cache enabled: " + bCache); + return PILOT_AP; } /** - * Remove all entries from the OSCP cache. + * @return The Peppol CA checker for Production AP certificates. + * @since 9.6.0 */ - public static void clearOCSPCache () - { - REVOCATION_CACHE_AP.clearCache (); - REVOCATION_CACHE_SMP.clearCache (); - LOGGER.info ("The PeppolCertificateChecker OCSP cache was cleared"); - } - - @Nonnull - @ReturnsMutableObject - public static PeppolRevocationCache getRevocationCacheAP () - { - return REVOCATION_CACHE_AP; - } - @Nonnull - @ReturnsMutableObject - public static PeppolRevocationCache getRevocationCacheSMP () + public static PeppolCAChecker peppolProductionAP () { - return REVOCATION_CACHE_SMP; + return PROD_AP; } /** - * @return The list of trusted Peppol AP certificates. Never - * null. - * @since 9.4.0 + * @return The Peppol CA checker for Pilot and Production AP certificates. + * @since 9.6.0 */ @Nonnull - @ReturnsMutableObject - public static TrustedCACertificates getTrustedCertificatesAP () + public static PeppolCAChecker peppolAllAP () { - return PEPPOL_AP_TRUSTED; + return ALL_AP; } /** - * @return The list of trusted Peppol SMP certificates. Never - * null. - * @since 9.4.0 + * @return The Peppol CA checker for Pilot SMP certificates. + * @since 9.6.0 */ @Nonnull - @ReturnsMutableObject - public static TrustedCACertificates getTrustedCertificatesSMP () + public static PeppolCAChecker peppolPilotSMP () { - return PEPPOL_SMP_TRUSTED; + return PILOT_SMP; } /** - * Register a trusted Peppol AP CA Certificate - * - * @param aCert - * The CA certificate to be added. May not be null. - * @throws IllegalArgumentException - * If the provided certificate is already trusted - * @since 9.0.4 - * @deprecated Use - * getTrustedCertificatesAP ().addTrustedCACertificate - * instead + * @return The Peppol CA checker for Production SMP certificates. + * @since 9.6.0 */ - @Deprecated (forRemoval = true, since = "9.4.0") - public static void addTrustedPeppolAPCACertificate (@Nonnull final X509Certificate aCert) + @Nonnull + public static PeppolCAChecker peppolProductionSMP () { - getTrustedCertificatesAP ().addTrustedCACertificate (aCert); + return PROD_SMP; } /** - * Explicitly remove all known trusted Peppol AP CA certificates so that - * different ones can be added. Handle this with care! - * - * @since 9.0.4 - * @deprecated Use - * getTrustedCertificatesAP ().clearTrustedCACertificates - * instead + * @return The Peppol CA checker for Pilot and Production SMP certificates. + * @since 9.6.0 */ - @Deprecated (forRemoval = true, since = "9.4.0") - public static void clearTrustedPeppolAPCACertificates () + @Nonnull + public static PeppolCAChecker peppolAllSMP () { - getTrustedCertificatesAP ().clearTrustedCACertificates (); + return ALL_SMP; } /** - * @return All the Peppol AP CA certificates currently valid. Neither - * null nor empty. - * @since 8.2.7 - * @deprecated Use - * getTrustedCertificatesAP ().getAllTrustedCACertificates - * instead + * @return The Peppol CA checker for Pilot eB2B AP certificates. + * @since 9.6.0 */ @Nonnull - @Nonempty - @ReturnsMutableCopy - @Deprecated (forRemoval = true, since = "9.4.0") - public static ICommonsList getAllPeppolAPCACertificates () + public static PeppolCAChecker peppolPilotEb2bAP () { - return getTrustedCertificatesAP ().getAllTrustedCACertificates (); + return PILOT_EB2B_AP; } /** - * @return All the Peppol AP CA issuers currently valid. Neither - * null nor empty. - * @since 8.2.7 + * @return true if OSCP results may be cached, false + * if not. The default is + * {@value CertificateRevocationCheckerDefaults#DEFAULT_CACHE_REVOCATION_CHECK_RESULTS}. * @deprecated Use - * getTrustedCertificatesAP ().getAllTrustedCAIssuers + * {@link CertificateRevocationCheckerDefaults#isCacheRevocationCheckResults()} * instead */ - @Nonnull - @Nonempty - @ReturnsMutableCopy - @Deprecated (forRemoval = true, since = "9.4.0") - public static ICommonsList getAllPeppolAPCAIssuers () + @Deprecated (forRemoval = true, since = "9.6.0") + public static boolean isCacheOCSPResults () { - return getTrustedCertificatesAP ().getAllTrustedCAIssuers (); + return CertificateRevocationCheckerDefaults.isCacheRevocationCheckResults (); } /** - * Register a trusted Peppol SMP CA Certificate + * Enable or disable caching of OSCP results. * - * @param aCert - * The CA certificate to be added. May not be null. - * @throws IllegalArgumentException - * If the provided certificate is already trusted - * @since 9.0.4 + * @param bCache + * true to enable caching, false to disable + * it. * @deprecated Use - * getTrustedCertificatesSMP ().addTrustedCACertificate + * {@link CertificateRevocationCheckerDefaults#setCacheRevocationCheckResults(boolean)} * instead */ - @Deprecated (forRemoval = true, since = "9.4.0") - public static void addTrustedPeppolSMPCACertificate (@Nonnull final X509Certificate aCert) + @Deprecated (forRemoval = true, since = "9.6.0") + public static void setCacheOCSPResults (final boolean bCache) { - getTrustedCertificatesSMP ().addTrustedCACertificate (aCert); + CertificateRevocationCheckerDefaults.setCacheRevocationCheckResults (bCache); } /** - * Explicitly remove all known trusted Peppol SMP CA certificates so that - * different ones can be added. Handle this with care! + * Remove all entries from the OSCP cache. * - * @since 9.0.4 - * @deprecated Use - * getTrustedCertificatesSMP ().clearTrustedCACertificates - * instead + * @deprecated Use {@link #clearRevocationCheckCache()} instead */ - @Deprecated (forRemoval = true, since = "9.4.0") - public static void clearTrustedPeppolSMPCACertificates () + @Deprecated (forRemoval = true, since = "9.6.0") + public static void clearOCSPCache () { - getTrustedCertificatesSMP ().clearTrustedCACertificates (); + clearRevocationCheckCache (); } /** - * @return All the Peppol SMP CA certificates currently valid. Neither - * null nor empty. - * @since 8.2.7 - * @deprecated Use - * getTrustedCertificatesSMP ().getAllTrustedCACertificates - * instead + * Remove all entries from the OSCP cache. */ - @Nonnull - @Nonempty - @ReturnsMutableCopy - @Deprecated (forRemoval = true, since = "9.4.0") - public static ICommonsList getAllPeppolSMPCACertificates () + public static void clearRevocationCheckCache () { - return getTrustedCertificatesSMP ().getAllTrustedCACertificates (); - } + PILOT_AP.clearRevocationCache (); + PROD_AP.clearRevocationCache (); + ALL_AP.clearRevocationCache (); - /** - * @return All the Peppol SMP CA issuers currently valid. Neither - * null nor empty. - * @since 8.2.7 - * @deprecated Use - * getTrustedCertificatesSMP ().getAllTrustedCAIssuers - * instead - */ - @Nonnull - @Nonempty - @ReturnsMutableCopy - @Deprecated (forRemoval = true, since = "9.4.0") - public static ICommonsList getAllPeppolSMPCAIssuers () - { - return getTrustedCertificatesSMP ().getAllTrustedCAIssuers (); - } + PILOT_SMP.clearRevocationCache (); + PROD_SMP.clearRevocationCache (); + ALL_SMP.clearRevocationCache (); - /** - * @return A new {@link PeppolRevocationCheckBuilder} instance. - * @since 8.5.2 - */ - public static PeppolRevocationCheckBuilder peppolRevocationCheck () - { - return new PeppolRevocationCheckBuilder (); + PILOT_EB2B_AP.clearRevocationCache (); + + LOGGER.info ("The PeppolCertificateChecker revocation cache was cleared"); } /** - * A special revocation check builder that has specific support for Peppol - * requirements. - * - * @author Philip Helger + * @return A new {@link RevocationCheckBuilder} instance. + * @since 8.5.2 + * @deprecated Instantiate the class directly. No Peppol specifics remaining. */ - @NotThreadSafe - public static class PeppolRevocationCheckBuilder extends AbstractRevocationCheckBuilder + @Deprecated (forRemoval = true, since = "9.6.0") + public static RevocationCheckBuilder peppolRevocationCheck () { - /** - * Use the Peppol AP CA certificates as valid ones. - * - * @return this for chaining - */ - @Nonnull - public PeppolRevocationCheckBuilder validCAsPeppolAP () - { - return validCAs (getTrustedCertificatesAP ().getAllTrustedCACertificates ()); - } - - /** - * Use only the Peppol SMP CA certificates as valid ones. - * - * @return this for chaining - */ - @Nonnull - public PeppolRevocationCheckBuilder validCAsPeppolSMP () - { - return validCAs (getTrustedCertificatesSMP ().getAllTrustedCACertificates ()); - } + return new RevocationCheckBuilder (); } /** @@ -342,7 +221,7 @@ public PeppolRevocationCheckBuilder validCAsPeppolSMP () * @param aIssuers * The list of valid certificate issuers to check against. May be * null to not perform this check. - * @param aCache + * @param aRevocationCache * The cache. May be null to disable caching. * @param aRevocationChecker * The revocation checker builder with all necessary parameters already @@ -351,8 +230,8 @@ public PeppolRevocationCheckBuilder validCAsPeppolSMP () * @since 8.5.2 */ @Nonnull - public static EPeppolCertificateCheckResult checkCertificate (@Nullable final ICommonsList aIssuers, - @Nullable final PeppolRevocationCache aCache, + public static EPeppolCertificateCheckResult checkCertificate (@Nullable final ICommonsSet aIssuers, + @Nullable final PeppolRevocationCache aRevocationCache, @Nonnull final AbstractRevocationCheckBuilder aRevocationChecker) { ValueEnforcer.notNull (aRevocationChecker, "RevocationChecker"); @@ -360,7 +239,7 @@ public static EPeppolCertificateCheckResult checkCertificate (@Nullable final IC if (LOGGER.isDebugEnabled ()) LOGGER.debug ("Running Peppol Certificate Check" + (aIssuers != null ? " against a list of " + aIssuers.size () + " certificate issuers" : "") + - (aCache != null ? "; a cache is provided" : "; not using a cache")); + (aRevocationCache != null ? "; a cache is provided" : "; not using a cache")); // Get the certificate to be validated final X509Certificate aCert = aRevocationChecker.certificate (); @@ -422,13 +301,13 @@ public static EPeppolCertificateCheckResult checkCertificate (@Nullable final IC } // Check revocation OCSP/CLR - if (aCache != null) + if (aRevocationCache != null) { // Caching is enabled if (LOGGER.isDebugEnabled ()) LOGGER.debug ("Testing if the Peppol Certificate is revoked, using a cache"); - final boolean bRevoked = aCache.isRevoked (aCert); + final boolean bRevoked = aRevocationCache.isRevoked (aCert); if (bRevoked) { LOGGER.warn ("The Peppol Certificate is revoked [caching used]"); @@ -463,29 +342,28 @@ public static EPeppolCertificateCheckResult checkCertificate (@Nullable final IC * @param aCheckDT * The check date and time to use. May be null which means * "now". - * @param eCacheOSCResult + * @param eCacheRevocationCheckResult * Possibility to override the usage of OSCP caching flag on a per * query basis. Use {@link ETriState#UNDEFINED} to solely use the * global flag. * @param eCheckMode * Possibility to override the OSCP checking flag on a per query basis. * May be null to use the global flag from - * {@link CertificateRevocationChecker#getRevocationCheckMode()}. + * {@link CertificateRevocationCheckerDefaults#getRevocationCheckMode()}. * @return {@link EPeppolCertificateCheckResult} and never null. + * @deprecated Use {@link #peppolAllAP()}, {@link #peppolPilotAP()} or + * {@link #peppolProductionAP()} with + * {@link PeppolCAChecker#checkCertificate(X509Certificate, OffsetDateTime, ETriState, ERevocationCheckMode)} + * instead */ @Nonnull + @Deprecated (forRemoval = true, since = "9.6.0") public static EPeppolCertificateCheckResult checkPeppolAPCertificate (@Nullable final X509Certificate aCert, @Nullable final OffsetDateTime aCheckDT, - @Nonnull final ETriState eCacheOSCResult, + @Nonnull final ETriState eCacheRevocationCheckResult, @Nullable final ERevocationCheckMode eCheckMode) { - final boolean bRevocationCache = eCacheOSCResult.isUndefined () ? isCacheOCSPResults () : eCacheOSCResult.isTrue (); - return checkCertificate (getTrustedCertificatesAP ().getAllTrustedCAIssuers (), - bRevocationCache ? getRevocationCacheAP () : null, - peppolRevocationCheck ().certificate (aCert) - .checkDate (aCheckDT) - .validCAsPeppolAP () - .checkMode (eCheckMode)); + return peppolAllAP ().checkCertificate (aCert, aCheckDT, eCacheRevocationCheckResult, eCheckMode); } /** @@ -496,28 +374,27 @@ public static EPeppolCertificateCheckResult checkPeppolAPCertificate (@Nullable * @param aCheckDT * The check date and time to use. May be null which means * "now". - * @param eCacheOSCResult + * @param eCacheRevocationCheckResult * Possibility to override the usage of OSCP caching flag on a per * query basis. Use {@link ETriState#UNDEFINED} to solely use the * global flag. * @param eCheckMode * Possibility to override the OSCP checking flag on a per query basis. * May be null to use the global flag from - * {@link CertificateRevocationChecker#getRevocationCheckMode()}. + * {@link CertificateRevocationCheckerDefaults#getRevocationCheckMode()}. * @return {@link EPeppolCertificateCheckResult} and never null. + * @deprecated Use {@link #peppolAllSMP()}, {@link #peppolPilotSMP()} or + * {@link #peppolProductionSMP()} with + * {@link PeppolCAChecker#checkCertificate(X509Certificate, OffsetDateTime, ETriState, ERevocationCheckMode)} + * instead */ @Nonnull + @Deprecated (forRemoval = true, since = "9.6.0") public static EPeppolCertificateCheckResult checkPeppolSMPCertificate (@Nullable final X509Certificate aCert, @Nullable final OffsetDateTime aCheckDT, - @Nonnull final ETriState eCacheOSCResult, + @Nonnull final ETriState eCacheRevocationCheckResult, @Nullable final ERevocationCheckMode eCheckMode) { - final boolean bRevocationCache = eCacheOSCResult.isUndefined () ? isCacheOCSPResults () : eCacheOSCResult.isTrue (); - return checkCertificate (getTrustedCertificatesSMP ().getAllTrustedCAIssuers (), - bRevocationCache ? getRevocationCacheSMP () : null, - peppolRevocationCheck ().certificate (aCert) - .checkDate (aCheckDT) - .validCAsPeppolSMP () - .checkMode (eCheckMode)); + return peppolAllSMP ().checkCertificate (aCert, aCheckDT, eCacheRevocationCheckResult, eCheckMode); } } diff --git a/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolRevocationCache.java b/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolRevocationCache.java index af57af71..0c8369ae 100644 --- a/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolRevocationCache.java +++ b/peppol-commons/src/main/java/com/helger/peppol/utils/PeppolRevocationCache.java @@ -31,14 +31,15 @@ /** * An revocation cache that checks the revocation status of each certificate and - * keeps the status for up to 6 hours. + * keeps the status for a provided duration. * * @author Philip Helger */ @ThreadSafe public final class PeppolRevocationCache extends MappedCache > { - public static final Duration DEFAULT_CACHING_DURATION = Duration.ofHours (6); + @Deprecated (forRemoval = true, since = "9.6.0") + public static final Duration DEFAULT_CACHING_DURATION = CertificateRevocationCheckerDefaults.DEFAULT_REVOCATION_CHECK_CACHING_DURATION; private static final Logger LOGGER = LoggerFactory.getLogger (PeppolRevocationCache.class); diff --git a/peppol-commons/src/main/java/com/helger/peppol/utils/RevocationCheckBuilder.java b/peppol-commons/src/main/java/com/helger/peppol/utils/RevocationCheckBuilder.java new file mode 100644 index 00000000..d7a0008a --- /dev/null +++ b/peppol-commons/src/main/java/com/helger/peppol/utils/RevocationCheckBuilder.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015-2024 Philip Helger + * philip[at]helger[dot]com + * + * 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 com.helger.peppol.utils; + +import javax.annotation.concurrent.NotThreadSafe; + +/** + * A generic revocation check builder that works with arbitrary certificates. + * Contains no specific pre-configuration. + * + * @author Philip Helger + * @since 9.6.0 a top-level class + */ +@NotThreadSafe +public class RevocationCheckBuilder extends AbstractRevocationCheckBuilder +{} diff --git a/peppol-commons/src/main/java/com/helger/peppol/utils/TrustedCACertificates.java b/peppol-commons/src/main/java/com/helger/peppol/utils/TrustedCACertificates.java index 8870456c..f069b227 100644 --- a/peppol-commons/src/main/java/com/helger/peppol/utils/TrustedCACertificates.java +++ b/peppol-commons/src/main/java/com/helger/peppol/utils/TrustedCACertificates.java @@ -16,17 +16,11 @@ */ package com.helger.peppol.utils; -import java.io.IOException; import java.security.cert.X509Certificate; import javax.annotation.Nonnull; import javax.security.auth.x500.X500Principal; -import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.x509.BasicConstraints; -import org.bouncycastle.asn1.x509.Extension; -import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,8 +28,11 @@ import com.helger.commons.annotation.Nonempty; import com.helger.commons.annotation.ReturnsMutableCopy; import com.helger.commons.collection.impl.CommonsArrayList; +import com.helger.commons.collection.impl.CommonsHashSet; import com.helger.commons.collection.impl.ICommonsList; +import com.helger.commons.collection.impl.ICommonsSet; import com.helger.commons.string.ToStringGenerator; +import com.helger.security.certificate.CertificateHelper; /** * Manages a list of trusted CA certificates. @@ -48,37 +45,11 @@ public class TrustedCACertificates private static final Logger LOGGER = LoggerFactory.getLogger (TrustedCACertificates.class); private final ICommonsList m_aCerts = new CommonsArrayList <> (); - private final ICommonsList m_aIssuers = new CommonsArrayList <> (); + private final ICommonsSet m_aIssuers = new CommonsHashSet <> (); public TrustedCACertificates () {} - // TODO ph-commons > 11.1.6 - replace with CertificateHelper method - private static boolean _isCA (@Nonnull final X509Certificate aCert) - { - final byte [] aBCBytes = aCert.getExtensionValue (Extension.basicConstraints.getId ()); - if (aBCBytes != null) - { - try - { - final ASN1Encodable aBCDecoded = JcaX509ExtensionUtils.parseExtensionValue (aBCBytes); - if (aBCDecoded instanceof ASN1Sequence) - { - final ASN1Sequence aBCSequence = (ASN1Sequence) aBCDecoded; - final BasicConstraints aBasicConstraints = BasicConstraints.getInstance (aBCSequence); - if (aBasicConstraints != null) - return aBasicConstraints.isCA (); - } - } - catch (final IOException e) - { - // Fall through - } - } - // Defaults to "no" - return false; - } - /** * Register a trusted CA Certificate * @@ -91,7 +62,7 @@ public void addTrustedCACertificate (@Nonnull final X509Certificate aCert) { ValueEnforcer.notNull (aCert, "Certificate"); - if (!_isCA (aCert)) + if (!CertificateHelper.isCA (aCert)) throw new IllegalArgumentException ("The provided certificate does not seem to be a CA: " + aCert); if (m_aCerts.contains (aCert)) @@ -134,7 +105,7 @@ public ICommonsList getAllTrustedCACertificates () @Nonnull @Nonempty @ReturnsMutableCopy - public ICommonsList getAllTrustedCAIssuers () + public ICommonsSet getAllTrustedCAIssuers () { return m_aIssuers.getClone (); } diff --git a/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateCheckerTest.java b/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateCheckerTest.java index 1b4d1a83..02042062 100644 --- a/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateCheckerTest.java +++ b/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateCheckerTest.java @@ -45,29 +45,22 @@ public class PeppolCertificateCheckerTest @Test public void testBasic () { - EPeppolCertificateCheckResult e = PeppolCertificateChecker.checkPeppolAPCertificate (null, - null, - ETriState.UNDEFINED, - null); + EPeppolCertificateCheckResult e = PeppolCertificateChecker.peppolPilotAP ().checkCertificate (null, null); assertEquals (EPeppolCertificateCheckResult.NO_CERTIFICATE_PROVIDED, e); - e = PeppolCertificateChecker.checkPeppolAPCertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP, - PDTFactory.createOffsetDateTime (2000, Month.JANUARY, 1), - ETriState.UNDEFINED, - null); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP, + PDTFactory.createOffsetDateTime (2000, Month.JANUARY, 1)); assertEquals (EPeppolCertificateCheckResult.NOT_YET_VALID, e); - e = PeppolCertificateChecker.checkPeppolAPCertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP, - PDTFactory.createOffsetDateTime (2099, Month.JANUARY, 1), - ETriState.UNDEFINED, - null); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP, + PDTFactory.createOffsetDateTime (2099, Month.JANUARY, 1)); assertEquals (EPeppolCertificateCheckResult.EXPIRED, e); // It's the same certificate, but we need one issued by the pilot AP - e = PeppolCertificateChecker.checkPeppolAPCertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP, - null, - ETriState.UNDEFINED, - null); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (PeppolKeyStoreHelper.Config2018.CERTIFICATE_PILOT_AP, null); assertEquals (EPeppolCertificateCheckResult.UNSUPPORTED_ISSUER, e); } @@ -93,34 +86,40 @@ public void testRealAPCert () throws Exception EPeppolCertificateCheckResult e; LOGGER.info ("Checking with OCSP_BEFORE_CRL"); - e = PeppolCertificateChecker.checkPeppolAPCertificate (aCert, - null, - ETriState.FALSE, - ERevocationCheckMode.OCSP_BEFORE_CRL); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aCert, + null, + ETriState.FALSE, + ERevocationCheckMode.OCSP_BEFORE_CRL); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with OCSP"); - e = PeppolCertificateChecker.checkPeppolAPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.OCSP); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.OCSP); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with CRL_BEFORE_OCSP"); - e = PeppolCertificateChecker.checkPeppolAPCertificate (aCert, - null, - ETriState.FALSE, - ERevocationCheckMode.CRL_BEFORE_OCSP); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aCert, + null, + ETriState.FALSE, + ERevocationCheckMode.CRL_BEFORE_OCSP); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with CRL"); - e = PeppolCertificateChecker.checkPeppolAPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); assertEquals (EPeppolCertificateCheckResult.VALID, e); // Try again with CRL only to ensure it's not downloaded again LOGGER.info ("Checking with CRL"); - e = PeppolCertificateChecker.checkPeppolAPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with NONE"); - e = PeppolCertificateChecker.checkPeppolAPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.NONE); + e = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.NONE); assertEquals (EPeppolCertificateCheckResult.VALID, e); } else @@ -149,34 +148,40 @@ public void testRealSMPCert () throws Exception EPeppolCertificateCheckResult e; LOGGER.info ("Checking with OCSP_BEFORE_CRL"); - e = PeppolCertificateChecker.checkPeppolSMPCertificate (aCert, - null, - ETriState.FALSE, - ERevocationCheckMode.OCSP_BEFORE_CRL); + e = PeppolCertificateChecker.peppolPilotSMP () + .checkCertificate (aCert, + null, + ETriState.FALSE, + ERevocationCheckMode.OCSP_BEFORE_CRL); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with OCSP"); - e = PeppolCertificateChecker.checkPeppolSMPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.OCSP); + e = PeppolCertificateChecker.peppolPilotSMP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.OCSP); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with CRL_BEFORE_OCSP"); - e = PeppolCertificateChecker.checkPeppolSMPCertificate (aCert, - null, - ETriState.FALSE, - ERevocationCheckMode.CRL_BEFORE_OCSP); + e = PeppolCertificateChecker.peppolPilotSMP () + .checkCertificate (aCert, + null, + ETriState.FALSE, + ERevocationCheckMode.CRL_BEFORE_OCSP); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with CRL"); - e = PeppolCertificateChecker.checkPeppolSMPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); + e = PeppolCertificateChecker.peppolPilotSMP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); assertEquals (EPeppolCertificateCheckResult.VALID, e); // Try again with CRL only to ensure it's not downloaded again LOGGER.info ("Checking with CRL"); - e = PeppolCertificateChecker.checkPeppolSMPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); + e = PeppolCertificateChecker.peppolPilotSMP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.CRL); assertEquals (EPeppolCertificateCheckResult.VALID, e); LOGGER.info ("Checking with NONE"); - e = PeppolCertificateChecker.checkPeppolSMPCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.NONE); + e = PeppolCertificateChecker.peppolPilotSMP () + .checkCertificate (aCert, null, ETriState.FALSE, ERevocationCheckMode.NONE); assertEquals (EPeppolCertificateCheckResult.VALID, e); } else diff --git a/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateHelperTest.java b/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateHelperTest.java index d7f2b4a6..1429ed43 100644 --- a/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateHelperTest.java +++ b/peppol-commons/src/test/java/com/helger/peppol/utils/PeppolCertificateHelperTest.java @@ -35,7 +35,6 @@ import com.helger.commons.datetime.PDTFactory; import com.helger.commons.io.resource.ClassPathResource; import com.helger.commons.io.stream.StreamHelper; -import com.helger.commons.state.ETriState; import com.helger.security.certificate.CertificateHelper; /** @@ -75,12 +74,11 @@ public void testCheckRevoked () throws CertificateException StandardCharsets.UTF_8)); assertNotNull (aCert); // Check at a specific date, as the certificate - final EPeppolCertificateCheckResult eCertCheckResult = PeppolCertificateChecker.checkPeppolAPCertificate (aCert, - PDTFactory.createOffsetDateTime (2024, - Month.JANUARY, - 1), - ETriState.UNDEFINED, - CertificateRevocationChecker.getRevocationCheckMode ()); + final EPeppolCertificateCheckResult eCertCheckResult = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aCert, + PDTFactory.createOffsetDateTime (2024, + Month.JANUARY, + 1)); assertSame (EPeppolCertificateCheckResult.REVOKED, eCertCheckResult); } } diff --git a/peppol-smp-client/src/main/java/com/helger/smpclient/security/TrustStoreBasedX509KeySelector.java b/peppol-smp-client/src/main/java/com/helger/smpclient/security/TrustStoreBasedX509KeySelector.java index 8496cc15..754f33ba 100644 --- a/peppol-smp-client/src/main/java/com/helger/smpclient/security/TrustStoreBasedX509KeySelector.java +++ b/peppol-smp-client/src/main/java/com/helger/smpclient/security/TrustStoreBasedX509KeySelector.java @@ -44,9 +44,11 @@ import com.helger.commons.ValueEnforcer; import com.helger.commons.collection.impl.CommonsArrayList; import com.helger.commons.datetime.PDTFactory; -import com.helger.peppol.utils.CertificateRevocationChecker; +import com.helger.peppol.utils.CertificateRevocationCheckerDefaults; import com.helger.peppol.utils.EPeppolCertificateCheckResult; import com.helger.peppol.utils.PeppolCertificateChecker; +import com.helger.peppol.utils.PeppolKeyStoreHelper; +import com.helger.peppol.utils.RevocationCheckBuilder; import com.helger.security.certificate.CertificateHelper; import com.helger.security.keystore.ConstantKeySelectorResult; @@ -182,15 +184,13 @@ public KeySelectorResult select (@Nonnull final KeyInfo aKeyInfo, final EPeppolCertificateCheckResult eCheckResult; // No cache because it uses the default issuer check and trust // store - eCheckResult = PeppolCertificateChecker.checkCertificate (PeppolCertificateChecker.getTrustedCertificatesSMP () - .getAllTrustedCAIssuers (), - true ? null - : PeppolCertificateChecker.getRevocationCacheSMP (), - PeppolCertificateChecker.peppolRevocationCheck () - .certificate (aCertificate) - .checkDate (m_aValidationDateTime) - .validCAs (m_aTrustStore) - .checkMode (CertificateRevocationChecker.getRevocationCheckMode ())); + eCheckResult = PeppolCertificateChecker.checkCertificate (PeppolKeyStoreHelper.getAllTrustedCertificates (m_aTrustStore) + .getAllMapped (X509Certificate::getSubjectX500Principal), + null, + new RevocationCheckBuilder ().certificate (aCertificate) + .checkDate (m_aValidationDateTime) + .validCAs (m_aTrustStore) + .checkMode (CertificateRevocationCheckerDefaults.getRevocationCheckMode ())); LOGGER.info ("SMP Client AP certificate check result: " + eCheckResult); if (eCheckResult.isInvalid ()) throw new KeySelectorException ("Failed to verify the contained AP certificate with code " + diff --git a/peppol-smp-client/src/test/java/com/helger/smpclient/peppol/SMPClientReadOnlyTest.java b/peppol-smp-client/src/test/java/com/helger/smpclient/peppol/SMPClientReadOnlyTest.java index c2470870..ab10f94f 100644 --- a/peppol-smp-client/src/test/java/com/helger/smpclient/peppol/SMPClientReadOnlyTest.java +++ b/peppol-smp-client/src/test/java/com/helger/smpclient/peppol/SMPClientReadOnlyTest.java @@ -530,12 +530,13 @@ public void testReceiverHasRevokedAPCert () throws Exception assertNotNull (aAPCert); // Check at a specific date, as the certificate - final EPeppolCertificateCheckResult eCertCheckResult = PeppolCertificateChecker.checkPeppolAPCertificate (aAPCert, - PDTFactory.createOffsetDateTime (2024, - Month.JUNE, - 1), - ETriState.UNDEFINED, - ERevocationCheckMode.CRL_BEFORE_OCSP); + final EPeppolCertificateCheckResult eCertCheckResult = PeppolCertificateChecker.peppolPilotAP () + .checkCertificate (aAPCert, + PDTFactory.createOffsetDateTime (2024, + Month.JUNE, + 1), + ETriState.UNDEFINED, + ERevocationCheckMode.CRL_BEFORE_OCSP); assertSame (EPeppolCertificateCheckResult.REVOKED, eCertCheckResult); }