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

org.cesecore.certificates.ocsp.cache.OcspSigningCacheEntry Maven / Gradle / Ivy

/*************************************************************************
 *                                                                       *
 *  CESeCore: CE Security Core                                           *
 *                                                                       *
 *  This software is free software; you can redistribute it and/or       *
 *  modify it under the terms of the GNU Lesser General Public           *
 *  License as published by the Free Software Foundation; either         *
 *  version 2.1 of the License, or any later version.                    *
 *                                                                       *
 *  See terms of license at gnu.org.                                     *
 *                                                                       *
 *************************************************************************/
package org.cesecore.certificates.ocsp.cache;

import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.RespID;
import org.bouncycastle.cert.ocsp.jcajce.JcaRespID;
import org.cesecore.certificates.certificate.CertificateStatus;
import org.cesecore.certificates.ocsp.SHA1DigestCalculator;
import org.cesecore.config.OcspConfiguration;
import org.cesecore.keybind.impl.OcspKeyBinding;
import org.cesecore.util.CertTools;

/**
 * Hold information needed for creating an OCSP response without database lookups.
 * 
 * @version $Id: OcspSigningCacheEntry.java 28643 2018-04-06 08:53:57Z samuellb $
 */
public class OcspSigningCacheEntry {

    private static final Logger log = Logger.getLogger(OcspSigningCacheEntry.class);
    
    private final List certificateID;
    private final List caCertificateChain;
    private final X509Certificate ocspSigningCertificate;
    private final List fullCertificateChain;
    private final X509Certificate signingCertificate;
    private final String signingCertificateIssuerDn;
    private final String signingCertificateIssuerDnRaw;
    private final transient PrivateKey privateKey;
    private final String signatureProviderName;
    private final OcspKeyBinding ocspKeyBinding;
    private final X509Certificate issuerCaCertificate;
    private final CertificateStatus issuerCaCertificateStatus;
    private boolean responseSignatureVerified = false;
    private final OcspKeyBinding.ResponderIdType responderIdType;
    private RespID respId;
    private final X509Certificate[] responseCertChain;
    private final boolean signingCertificateForOcspSigning;

    public OcspSigningCacheEntry(X509Certificate issuerCaCertificate, CertificateStatus issuerCaCertificateStatus,
            List signingCaCertificateChain, X509Certificate ocspSigningCertificate, PrivateKey privateKey,
            String signatureProviderName, OcspKeyBinding ocspKeyBinding, OcspKeyBinding.ResponderIdType responderIdType) {
        this.caCertificateChain = signingCaCertificateChain;
        this.ocspSigningCertificate = ocspSigningCertificate;
        if (ocspSigningCertificate == null) {
            // We will sign with a CA key
            fullCertificateChain = signingCaCertificateChain;
        } else {
            // We will sign with an OCSP Key Binding
            fullCertificateChain = new ArrayList();
            fullCertificateChain.add(ocspSigningCertificate);
            fullCertificateChain.addAll(signingCaCertificateChain);
        }
        if (fullCertificateChain==null) {
            // This is just a placeholder cache entry
            signingCertificate = null;
        } else {
            // Get the certificate that corresponds to the private key
            signingCertificate = fullCertificateChain.get(0);
        }
        this.privateKey = privateKey;
        this.signatureProviderName = signatureProviderName;
        this.ocspKeyBinding = ocspKeyBinding;
        this.issuerCaCertificate = issuerCaCertificate;
        this.certificateID = OcspSigningCache.getCertificateIDFromCertificate(issuerCaCertificate);
        this.issuerCaCertificateStatus = issuerCaCertificateStatus;
        this.responderIdType = responderIdType;
        if (signingCertificate==null) {
            // This is just a placeholder cache entry
            respId = null;
            signingCertificateForOcspSigning = true;
            signingCertificateIssuerDn = null;
            signingCertificateIssuerDnRaw = null;
        } else {
            // Pre-calculate the Responder ID
            if (OcspKeyBinding.ResponderIdType.NAME.equals(responderIdType)) {
                respId = new JcaRespID(signingCertificate.getSubjectX500Principal());
            } else {
                try {
                    respId = new JcaRespID(signingCertificate.getPublicKey(), SHA1DigestCalculator.buildSha1Instance());
                } catch (OCSPException e) {
                    log.warn("Unable to contruct responder Id of type 'hash', falling back to using 'name' as responder Id.", e);
                    respId = new JcaRespID(signingCertificate.getSubjectX500Principal());
                }
            }
            if (ocspSigningCertificate==null) {
                signingCertificateForOcspSigning = true;    // CA cert
            } else {
                signingCertificateForOcspSigning = CertTools.isOCSPCert(signingCertificate);
            }
            signingCertificateIssuerDn = CertTools.getIssuerDN(signingCertificate);
            signingCertificateIssuerDnRaw = signingCertificate.getIssuerDN().getName();
        }
        if (fullCertificateChain==null) {
            responseCertChain = null;
        } else {
            responseCertChain = getResponseCertChain(fullCertificateChain.toArray(new X509Certificate[0]));
        }
    }

    /** @return certificate of the CA that we want to respond for */
    public X509Certificate getIssuerCaCertificate() { return issuerCaCertificate; }

    /** @return certificate ID of the CA that we want to respond for */
    public List getCertificateID() { return certificateID; }

    /** @return the certificate revocation status for the CA that we want to respond for at the time of cache reload */
    public CertificateStatus getIssuerCaCertificateStatus() { return issuerCaCertificateStatus; }

    /** @return the chain of all CA certificates */
    public List getCaCertificateChain() { return caCertificateChain; }

    /** @return a OCSP signing certificate or null if this cache entry will use a CA key to sign the response */
    public X509Certificate getOcspSigningCertificate() { return ocspSigningCertificate; }

    /** @return the full certificate chain that will be used to sign the OCSP response. The first position is either an OCSP signing certificate or a CA certificate. */
    public List getFullCertificateChain() { return fullCertificateChain; }

    /** @return the certificate that will be used to sign the OCSP response. This is either an OCSP signing certificate or a CA certificate. */
    public X509Certificate getSigningCertificate() { return signingCertificate; }

    /** @return the Issuer DN of the certificate that will be used to sign the OCSP response. BC normalized. */
    public String getSigningCertificateIssuerDn() { return signingCertificateIssuerDn; }

    /** @return the Issuer DN of the certificate that will be used to sign the OCSP response. Not normalized. */
    public String getSigningCertificateIssuerDnRaw() { return signingCertificateIssuerDnRaw; }

    /** @return the private key that will be used to sign the OCSP response. */
    public PrivateKey getPrivateKey() { return privateKey; }

    /** @return the signature provider that should be used with this cache entries private key. */
    public String getSignatureProviderName() { return signatureProviderName; }

    /** @return the OCSP key binding mapped by this entry or null if the private key belongs to a CA. */
    public OcspKeyBinding getOcspKeyBinding() { return ocspKeyBinding; }

    /** @return one of the OcspConfiguration.RESPONDERIDTYPE_* values used by this cache entry */
    public OcspKeyBinding.ResponderIdType getResponderIdType() { return responderIdType; }

    /** @return the actual responder type ASN1 object used by this cache entry */
    public RespID getRespId() { return respId; }

    /** @return the part of the full certificate chain that has been configured to be included in the response. */
    public X509Certificate[] getResponseCertChain() { return responseCertChain; }
    /**
     * Checks if the entry has a OCSP signing certificate separate from the certificate chain.
     * Only entries with a keybinding can have a separate certificate.
     */
    public boolean isUsingSeparateOcspSigningCertificate() { return ocspSigningCertificate != null; }

    /** @return false when we are using a non-CA signing certificate and the certificate lacks the OCSP signing EKU */
    public boolean isSigningCertificateForOcspSigning() { return signingCertificateForOcspSigning; }

    /** @return true if this entry is just a temporary placeholder that should be replaced with the default responder when rebuilding the cache. */
    public boolean isPlaceholder() { return privateKey == null; }

    /** @return false for the first thread that invokes this method (a caller that gets a false return value should verify the response signature) */
    public boolean checkResponseSignatureVerified() {
        // There is a small race condition here, so multiple callers might get a "false" return value, but since this
        // is a hot-path we don't want the overhead of synchronization for a large majority of the invocations
        if (responseSignatureVerified) {
            return true;
        }
        responseSignatureVerified = true;
        return false;
    }

    /**
     * This method construct the certificate chain that will be included in the OCSP response according to the following rules:
     * - If includeSignCert && includeChain --> include entire chain except for the root CA certificate
     * - If includeSignCert && !includeChain --> include only the signing certificate whatever it is (even if it was a root CA cert)
     * - If !includingSignCert --> not including any certificate or chain no matter what value includeChain has. The value of the 
     *   certificate chain  will then be an empty array.
     *   
     * @param certChain
     * @return the certificate chain that will be included in the OCSP response
     */
    private X509Certificate[] getResponseCertChain(X509Certificate[] certChain) {
        X509Certificate[] chain;
        boolean includeSignCert = OcspConfiguration.getIncludeSignCert();
        boolean includeChain = OcspConfiguration.getIncludeCertChain();
        // If we have an OcspKeyBinding we use this configuration to override the default
        if (isUsingSeparateOcspSigningCertificate()) {
            includeSignCert = getOcspKeyBinding().getIncludeSignCert();
            includeChain = getOcspKeyBinding().getIncludeCertChain();
        }
        if (log.isDebugEnabled()) {
            log.debug("Include signing cert: " + includeSignCert);
            log.debug("Include chain: " + includeChain);
        }
        if (includeSignCert) {
            if (includeChain) {
                if (certChain.length > 1) { // certChain contained more than the root cert
                    //create a new array containing all the certs in certChain except for the root cert
                    chain = new X509Certificate[certChain.length-1];
                    for(int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy