All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.smpclient.security.TrustStoreBasedX509KeySelector Maven / Gradle / Ivy

There is a newer version: 9.6.0
Show newest version
/*
 * 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.smpclient.security;

import java.security.KeyStore;
import java.security.PublicKey;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXParameters;
import java.security.cert.X509Certificate;
import java.time.LocalDateTime;
import java.util.Date;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.X509Data;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.EPeppolCertificateCheckResult;
import com.helger.peppol.utils.PeppolCertificateChecker;
import com.helger.security.certificate.CertificateHelper;
import com.helger.security.keystore.ConstantKeySelectorResult;

/**
 * Finds and returns a key using the data contained in a {@link KeyInfo} object
 *
 * @author Philip Helger
 * @see 
 *      Programming with the Java XML Digital Signature API
 */
public final class TrustStoreBasedX509KeySelector extends KeySelector
{
  private static final Logger LOGGER = LoggerFactory.getLogger (TrustStoreBasedX509KeySelector.class);

  private final KeyStore m_aTrustStore;
  private LocalDateTime m_aValidationDateTime;

  /**
   * Constructor
   *
   * @param aTrustStore
   *        The trust store to use. May not be null.
   * @since 8.1.1
   */
  public TrustStoreBasedX509KeySelector (@Nonnull final KeyStore aTrustStore)
  {
    ValueEnforcer.notNull (aTrustStore, "TrustStore");
    m_aTrustStore = aTrustStore;
  }

  /**
   * @return The selected validation date and time to use. null
   *         means current date time.
   * @since 8.6.2
   */
  @Nullable
  public LocalDateTime getValidationDateTime ()
  {
    return m_aValidationDateTime;
  }

  /**
   * Set the date and time when the trust store entry should be valid.
   *
   * @param aValidationDateTime
   *        The date and time to use. May be null.
   * @return this for chaining
   * @since 8.6.2
   */
  @Nonnull
  public TrustStoreBasedX509KeySelector setValidationDateTime (@Nullable final LocalDateTime aValidationDateTime)
  {
    m_aValidationDateTime = aValidationDateTime;
    return this;
  }

  public static boolean algorithmEquals (@Nonnull final String sAlgURI, @Nonnull final String sAlgName)
  {
    if (sAlgName.equalsIgnoreCase ("DSA"))
    {
      if (sAlgURI.equalsIgnoreCase (SignatureMethod.DSA_SHA1) ||
          sAlgURI.equalsIgnoreCase ("http://www.w3.org/2009/xmldsig11#dsa-sha256"))
        return true;
    }
    else
      if (sAlgName.equalsIgnoreCase ("RSA"))
      {
        if (sAlgURI.equalsIgnoreCase (SignatureMethod.RSA_SHA1) ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha1-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha224") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha224-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha256-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha384-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha512-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha3-224-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha3-256-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha3-384-rsa-MGF1") ||
            sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#sha3-512-rsa-MGF1"))
          return true;
      }
      else
        if (sAlgName.equalsIgnoreCase ("EC"))
        {
          if (sAlgURI.equalsIgnoreCase ("http://www.w3.org/2007/05/xmldsig-more#ecdsa-ripemd160") ||
              sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1") ||
              sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224") ||
              sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256") ||
              sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384") ||
              sAlgURI.equalsIgnoreCase ("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"))
            return true;
        }

    LOGGER.warn ("Algorithm mismatch between JCA/JCE public key algorithm name ('" +
                 sAlgName +
                 "') and signature algorithm URI ('" +
                 sAlgURI +
                 "')");
    return false;
  }

  @Override
  public KeySelectorResult select (@Nonnull final KeyInfo aKeyInfo,
                                   final KeySelector.Purpose aPurpose,
                                   @Nonnull final AlgorithmMethod aMethod,
                                   final XMLCryptoContext aCryptoContext) throws KeySelectorException
  {
    // For all XMLStructure
    for (final XMLStructure aStructure : aKeyInfo.getContent ())
    {
      if (aStructure instanceof X509Data)
      {
        final X509Data aX509Data = (X509Data) aStructure;
        // For all content - can be many different types
        for (final Object aElement : aX509Data.getContent ())
        {
          if (aElement instanceof X509Certificate)
          {
            // We found a certificate
            // Now at Signature/KeyInfo/X509Data/X509Certificate
            final X509Certificate aCertificate = (X509Certificate) aElement;

            // Old version
            try
            {
              if (false)
              {
                // The SMP response must be signed with an SMP certificate
                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 ()));
                LOGGER.info ("SMP Client AP certificate check result: " + eCheckResult);
                if (eCheckResult.isInvalid ())
                  throw new KeySelectorException ("Failed to verify the contained AP certificate with code " +
                                                  eCheckResult);
              }
              else
              {
                final Date aCheckDate = m_aValidationDateTime != null ? PDTFactory.createDate (m_aValidationDateTime)
                                                                      : null;

                // Check if the certificate is expired or active.
                if (aCheckDate != null)
                  aCertificate.checkValidity (aCheckDate);
                else
                  aCertificate.checkValidity ();

                // Checks whether the certificate is in the trusted store.

                // The PKIXParameters constructor may fail because:
                // - the trustAnchorsParameter is empty
                final PKIXParameters aPKIXParams = new PKIXParameters (m_aTrustStore);
                aPKIXParams.setRevocationEnabled (false);
                aPKIXParams.setDate (aCheckDate);

                final CertificateFactory aCertificateFactory = CertificateHelper.getX509CertificateFactory ();
                final CertPath aCertPath = aCertificateFactory.generateCertPath (new CommonsArrayList <> (aCertificate));
                final CertPathValidator aPathValidator = CertPathValidator.getInstance ("PKIX");
                aPathValidator.validate (aCertPath, aPKIXParams);
              }

              final PublicKey aPublicKey = aCertificate.getPublicKey ();

              // Make sure the algorithm is compatible with the method.
              if (algorithmEquals (aMethod.getAlgorithm (), aPublicKey.getAlgorithm ()))
                return new ConstantKeySelectorResult (aPublicKey);
              // Else a warning was already emitted
            }
            catch (final KeySelectorException ex)
            {
              throw ex;
            }
            catch (final Exception ex)
            {
              throw new KeySelectorException ("Failed to select public key from certificate " + aCertificate, ex);
            }
          }
        }
      }
    }
    throw new KeySelectorException ("No public key found!");
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy