Example usage for org.bouncycastle.asn1.isismtt.ocsp CertHash CertHash

List of usage examples for org.bouncycastle.asn1.isismtt.ocsp CertHash CertHash

Introduction

In this page you can find the example usage for org.bouncycastle.asn1.isismtt.ocsp CertHash CertHash.

Prototype

public CertHash(AlgorithmIdentifier hashAlgorithm, byte[] certificateHash) 

Source Link

Document

Constructor from a given details.

Usage

From source file:org.ejbca.core.protocol.ocsp.extension.certhash.OcspCertHashExtension.java

License:Open Source License

@Override
public Map<ASN1ObjectIdentifier, Extension> process(X509Certificate[] requestCertificates, String remoteAddress,
        String remoteHost, X509Certificate cert, org.bouncycastle.cert.ocsp.CertificateStatus status) {
    MessageDigest md = null;//w  w w  . ja  v  a 2 s  .  c  o  m
    try {
        md = MessageDigest.getInstance("SHA256");
    } catch (NoSuchAlgorithmException e) {
        //This state can't be handled, shouldn't return null 
        log.error("Could not create MessageDigest with algorithm SHA256", e);
        throw new IllegalStateException("Could not create MessageDigest with algorithm SHA256", e);
    }
    CertHash certHash;
    try {
        certHash = new CertHash(new AlgorithmIdentifier(SHA256), md.digest(cert.getEncoded()));
    } catch (CertificateEncodingException e) {
        //This state can't be handled, shouldn't return null 
        log.error("Could not encode certificate " + cert, e);
        throw new IllegalStateException("Could not encode certificate " + cert, e);
    }
    HashMap<ASN1ObjectIdentifier, Extension> result = new HashMap<ASN1ObjectIdentifier, Extension>();
    try {
        result.put(new ASN1ObjectIdentifier(CERT_HASH_OID),
                new Extension(new ASN1ObjectIdentifier(CERT_HASH_OID), false, new DEROctetString(certHash)));
    } catch (IOException e) {
        throw new IllegalStateException("Could not construct an ASN.1Primitive.", e);
    }
    return result;
}

From source file:org.xipki.ocsp.server.impl.OcspServer.java

License:Open Source License

public OcspRespWithCacheInfo answer(final Responder responder, final OCSPReq request,
        final AuditEvent auditEvent, final boolean viaGet) {
    ResponderOption responderOption = responder.getResponderOption();
    RequestOption requestOption = responder.getRequestOption();
    ResponseOption responseOption = responder.getResponseOption();
    ResponderSigner signer = responder.getSigner();
    AuditOption auditOption = responder.getAuditOption();
    CertprofileOption certprofileOption = responder.getCertprofileOption();

    int version = request.getVersionNumber();
    if (requestOption.isVersionAllowed(version) == false) {
        String message = "invalid request version " + version;
        LOG.warn(message);//from www .  j a  v  a2 s. c om
        if (auditEvent != null) {
            fillAuditEvent(auditEvent, AuditLevel.INFO, AuditStatus.FAILED, message);
        }
        return createUnsuccessfullOCSPResp(OcspResponseStatus.malformedRequest);
    }

    try {
        OcspRespWithCacheInfo resp = checkSignature(request, requestOption, auditEvent);
        if (resp != null) {
            return resp;
        }

        boolean couldCacheInfo = viaGet;

        List<Extension> responseExtensions = new ArrayList<>(2);

        Req[] requestList = request.getRequestList();
        int n = requestList.length;

        Set<ASN1ObjectIdentifier> criticalExtensionOIDs = new HashSet<>();
        Set<?> tmp = request.getCriticalExtensionOIDs();
        if (tmp != null) {
            for (Object oid : tmp) {
                criticalExtensionOIDs.add((ASN1ObjectIdentifier) oid);
            }
        }

        RespID respID = new RespID(signer.getResponderId());
        BasicOCSPRespBuilder basicOcspBuilder = new BasicOCSPRespBuilder(respID);
        ASN1ObjectIdentifier extensionType = OCSPObjectIdentifiers.id_pkix_ocsp_nonce;
        criticalExtensionOIDs.remove(extensionType);
        Extension nonceExtn = request.getExtension(extensionType);
        if (nonceExtn != null) {
            byte[] nonce = nonceExtn.getExtnValue().getOctets();
            int len = nonce.length;
            int min = requestOption.getNonceMinLen();
            int max = requestOption.getNonceMaxLen();

            if (len < min || len > max) {
                LOG.warn("length of nonce {} not within [{},{}]", new Object[] { len, min, max });
                if (auditEvent != null) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("length of nonce ").append(len);
                    sb.append(" not within [").append(min).append(", ").append(max);
                    fillAuditEvent(auditEvent, AuditLevel.INFO, AuditStatus.FAILED, sb.toString());
                }
                return createUnsuccessfullOCSPResp(OcspResponseStatus.malformedRequest);
            }

            couldCacheInfo = false;
            responseExtensions.add(nonceExtn);
        } else if (requestOption.isNonceRequired()) {
            String message = "nonce required, but is not present in the request";
            LOG.warn(message);
            if (auditEvent != null) {
                fillAuditEvent(auditEvent, AuditLevel.INFO, AuditStatus.FAILED, message);
            }
            return createUnsuccessfullOCSPResp(OcspResponseStatus.malformedRequest);
        }

        boolean includeExtendedRevokeExtension = false;

        long cacheThisUpdate = 0;
        long cacheNextUpdate = Long.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            AuditChildEvent childAuditEvent = null;
            if (auditEvent != null) {
                childAuditEvent = new AuditChildEvent();
                auditEvent.addChildAuditEvent(childAuditEvent);
            }

            Req req = requestList[i];
            CertificateID certID = req.getCertID();
            String certIdHashAlgo = certID.getHashAlgOID().getId();
            HashAlgoType reqHashAlgo = HashAlgoType.getHashAlgoType(certIdHashAlgo);
            if (reqHashAlgo == null) {
                LOG.warn("unknown CertID.hashAlgorithm {}", certIdHashAlgo);
                if (childAuditEvent != null) {
                    fillAuditEvent(childAuditEvent, AuditLevel.INFO, AuditStatus.FAILED,
                            "unknown CertID.hashAlgorithm " + certIdHashAlgo);
                }
                return createUnsuccessfullOCSPResp(OcspResponseStatus.malformedRequest);
            } else if (requestOption.allows(reqHashAlgo) == false) {
                LOG.warn("CertID.hashAlgorithm {} not allowed", certIdHashAlgo);
                if (childAuditEvent != null) {
                    fillAuditEvent(childAuditEvent, AuditLevel.INFO, AuditStatus.FAILED,
                            "CertID.hashAlgorithm " + certIdHashAlgo + " not allowed");
                }
                return createUnsuccessfullOCSPResp(OcspResponseStatus.malformedRequest);
            }

            CertStatusInfo certStatusInfo = null;
            CertStatusStore answeredStore = null;
            boolean exceptionOccurs = false;

            for (CertStatusStore store : responder.getStores()) {
                try {
                    certStatusInfo = store.getCertStatus(reqHashAlgo, certID.getIssuerNameHash(),
                            certID.getIssuerKeyHash(), certID.getSerialNumber(),
                            responseOption.isIncludeCerthash(), responseOption.getCertHashAlgo(),
                            certprofileOption);
                    if (certStatusInfo.getCertStatus() != CertStatus.ISSUER_UNKNOWN) {
                        answeredStore = store;
                        break;
                    }
                } catch (CertStatusStoreException e) {
                    exceptionOccurs = true;
                    final String message = "getCertStatus() of CertStatusStore " + store.getName();
                    if (LOG.isErrorEnabled()) {
                        LOG.error(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(),
                                e.getMessage());
                    }
                    LOG.debug(message, e);
                }
            }

            if (certStatusInfo == null) {
                if (childAuditEvent != null) {
                    fillAuditEvent(childAuditEvent, AuditLevel.ERROR, AuditStatus.FAILED,
                            "no CertStatusStore can answer the request");
                }
                if (exceptionOccurs) {
                    return createUnsuccessfullOCSPResp(OcspResponseStatus.tryLater);
                } else {
                    certStatusInfo = CertStatusInfo.getIssuerUnknownCertStatusInfo(new Date(), null);
                }
            } else if (answeredStore != null) {
                if (responderOption.isInheritCaRevocation()) {
                    CertRevocationInfo caRevInfo = answeredStore.getCARevocationInfo(reqHashAlgo,
                            certID.getIssuerNameHash(), certID.getIssuerKeyHash());
                    if (caRevInfo != null) {
                        CertStatus certStatus = certStatusInfo.getCertStatus();
                        boolean replaced = false;
                        if (certStatus == CertStatus.GOOD || certStatus == CertStatus.UNKNOWN) {
                            replaced = true;
                        } else if (certStatus == CertStatus.REVOKED) {
                            if (certStatusInfo.getRevocationInfo().getRevocationTime()
                                    .after(caRevInfo.getRevocationTime())) {
                                replaced = true;
                            }
                        }

                        if (replaced) {
                            CertRevocationInfo newRevInfo;
                            if (caRevInfo.getReason() == CRLReason.CA_COMPROMISE) {
                                newRevInfo = caRevInfo;
                            } else {
                                newRevInfo = new CertRevocationInfo(CRLReason.CA_COMPROMISE,
                                        caRevInfo.getRevocationTime(), caRevInfo.getInvalidityTime());
                            }
                            certStatusInfo = CertStatusInfo.getRevokedCertStatusInfo(newRevInfo,
                                    certStatusInfo.getCertHashAlgo(), certStatusInfo.getCertHash(),
                                    certStatusInfo.getThisUpdate(), certStatusInfo.getNextUpdate(),
                                    certStatusInfo.getCertprofile());
                        }
                    }
                }
            }

            if (childAuditEvent != null) {
                String certprofile = certStatusInfo.getCertprofile();
                String auditCertType;
                if (certprofile != null) {
                    auditCertType = auditOption.getCertprofileMapping().get(certprofile);
                    if (auditCertType == null) {
                        auditCertType = certprofile;
                    }
                } else {
                    auditCertType = "UNKNOWN";
                }

                childAuditEvent.addEventData(new AuditEventData("certType", auditCertType));
            }

            // certStatusInfo could not be null in any case, since at least one store is configured
            Date thisUpdate = certStatusInfo.getThisUpdate();
            if (thisUpdate == null) {
                thisUpdate = new Date();
            }
            Date nextUpdate = certStatusInfo.getNextUpdate();

            List<Extension> extensions = new LinkedList<>();
            boolean unknownAsRevoked = false;
            CertificateStatus bcCertStatus = null;
            switch (certStatusInfo.getCertStatus()) {
            case GOOD:
                bcCertStatus = null;
                break;

            case ISSUER_UNKNOWN:
                couldCacheInfo = false;
                bcCertStatus = new UnknownStatus();
                break;

            case UNKNOWN:
            case IGNORE:
                couldCacheInfo = false;
                if (responderOption.getMode() == OCSPMode.RFC2560) {
                    bcCertStatus = new UnknownStatus();
                } else// (ocspMode == OCSPMode.RFC6960)
                {
                    unknownAsRevoked = true;
                    includeExtendedRevokeExtension = true;
                    bcCertStatus = new RevokedStatus(new Date(0L), CRLReason.CERTIFICATE_HOLD.getCode());
                }
                break;
            case REVOKED:
                CertRevocationInfo revInfo = certStatusInfo.getRevocationInfo();
                ASN1GeneralizedTime revTime = new ASN1GeneralizedTime(revInfo.getRevocationTime());
                org.bouncycastle.asn1.x509.CRLReason _reason = null;
                if (responseOption.isIncludeRevReason()) {
                    _reason = org.bouncycastle.asn1.x509.CRLReason.lookup(revInfo.getReason().getCode());
                }
                RevokedInfo _revInfo = new RevokedInfo(revTime, _reason);
                bcCertStatus = new RevokedStatus(_revInfo);

                Date invalidityDate = revInfo.getInvalidityTime();
                if (responseOption.isIncludeInvalidityDate() && invalidityDate != null
                        && invalidityDate.equals(revTime) == false) {
                    Extension extension = new Extension(Extension.invalidityDate, false,
                            new ASN1GeneralizedTime(invalidityDate).getEncoded());
                    extensions.add(extension);
                }
                break;
            }

            byte[] certHash = certStatusInfo.getCertHash();
            if (certHash != null) {
                ASN1ObjectIdentifier hashAlgoOid = new ASN1ObjectIdentifier(
                        certStatusInfo.getCertHashAlgo().getOid());
                AlgorithmIdentifier aId = new AlgorithmIdentifier(hashAlgoOid, DERNull.INSTANCE);
                CertHash bcCertHash = new CertHash(aId, certHash);

                byte[] encodedCertHash;
                try {
                    encodedCertHash = bcCertHash.getEncoded();
                } catch (IOException e) {
                    final String message = "answer() bcCertHash.getEncoded";
                    if (LOG.isErrorEnabled()) {
                        LOG.error(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(),
                                e.getMessage());
                    }
                    LOG.debug(message, e);
                    if (childAuditEvent != null) {
                        fillAuditEvent(childAuditEvent, AuditLevel.ERROR, AuditStatus.FAILED,
                                "CertHash.getEncoded() with IOException");
                    }
                    return createUnsuccessfullOCSPResp(OcspResponseStatus.internalError);
                }

                Extension extension = new Extension(ISISMTTObjectIdentifiers.id_isismtt_at_certHash, false,
                        encodedCertHash);

                extensions.add(extension);
            }

            if (certStatusInfo.getArchiveCutOff() != null) {
                Extension extension = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_archive_cutoff, false,
                        new ASN1GeneralizedTime(certStatusInfo.getArchiveCutOff()).getEncoded());
                extensions.add(extension);
            }

            String certStatusText;
            if (bcCertStatus instanceof UnknownStatus) {
                certStatusText = "unknown";
            } else if (bcCertStatus instanceof RevokedStatus) {
                certStatusText = unknownAsRevoked ? "unknown_as_revoked" : "revoked";
            } else if (bcCertStatus == null) {
                certStatusText = "good";
            } else {
                certStatusText = "should-not-happen";
            }

            if (childAuditEvent != null) {
                childAuditEvent.setLevel(AuditLevel.INFO);
                childAuditEvent.setStatus(AuditStatus.SUCCESSFUL);
                childAuditEvent.addEventData(new AuditEventData("certStatus", certStatusText));
            }

            if (LOG.isDebugEnabled()) {
                StringBuilder sb = new StringBuilder();
                sb.append("certHashAlgo: ").append(certID.getHashAlgOID().getId()).append(", ");

                String hexCertHash = null;
                if (certHash != null) {
                    hexCertHash = Hex.toHexString(certHash).toUpperCase();
                }

                sb.append("issuerKeyHash: ").append(Hex.toHexString(certID.getIssuerKeyHash()).toUpperCase())
                        .append(", ");
                sb.append("issuerNameHash: ").append(Hex.toHexString(certID.getIssuerNameHash()).toUpperCase())
                        .append(", ");
                sb.append("serialNumber: ").append(certID.getSerialNumber()).append(", ");
                sb.append("certStatus: ").append(certStatusText).append(", ");
                sb.append("thisUpdate: ").append(thisUpdate).append(", ");
                sb.append("nextUpdate: ").append(nextUpdate).append(", ");
                sb.append("certHash: ").append(hexCertHash);
                LOG.debug(sb.toString());
            }

            basicOcspBuilder.addResponse(certID, bcCertStatus, thisUpdate, nextUpdate,
                    CollectionUtil.isEmpty(extensions) ? null
                            : new Extensions(extensions.toArray(new Extension[0])));
            cacheThisUpdate = Math.max(cacheThisUpdate, thisUpdate.getTime());
            if (nextUpdate != null) {
                cacheNextUpdate = Math.min(cacheNextUpdate, nextUpdate.getTime());
            }
        }

        if (includeExtendedRevokeExtension) {
            responseExtensions.add(new Extension(ObjectIdentifiers.id_pkix_ocsp_extendedRevoke, true,
                    DERNull.INSTANCE.getEncoded()));
        }

        if (CollectionUtil.isNotEmpty(responseExtensions)) {
            basicOcspBuilder
                    .setResponseExtensions(new Extensions(responseExtensions.toArray(new Extension[0])));
        }

        ConcurrentContentSigner concurrentSigner = null;
        if (responderOption.getMode() != OCSPMode.RFC2560) {
            extensionType = ObjectIdentifiers.id_pkix_ocsp_prefSigAlgs;
            criticalExtensionOIDs.remove(extensionType);
            Extension ext = request.getExtension(extensionType);
            if (ext != null) {
                ASN1Sequence preferredSigAlgs = ASN1Sequence.getInstance(ext.getParsedValue());
                concurrentSigner = signer.getSignerForPreferredSigAlgs(preferredSigAlgs);
            }
        }

        if (CollectionUtil.isNotEmpty(criticalExtensionOIDs)) {
            return createUnsuccessfullOCSPResp(OcspResponseStatus.malformedRequest);
        }

        if (concurrentSigner == null) {
            concurrentSigner = signer.getFirstSigner();
        }

        ContentSigner singleSigner;
        try {
            singleSigner = concurrentSigner.borrowContentSigner();
        } catch (NoIdleSignerException e) {
            return createUnsuccessfullOCSPResp(OcspResponseStatus.tryLater);
        }

        X509CertificateHolder[] certsInResp;
        EmbedCertsMode certsMode = responseOption.getEmbedCertsMode();
        if (certsMode == null || certsMode == EmbedCertsMode.SIGNER) {
            certsInResp = new X509CertificateHolder[] { signer.getBcCertificate() };
        } else if (certsMode == EmbedCertsMode.SIGNER_AND_CA) {
            certsInResp = signer.getBcCertificateChain();
        } else {
            // NONE
            certsInResp = null;
        }

        BasicOCSPResp basicOcspResp;
        try {
            basicOcspResp = basicOcspBuilder.build(singleSigner, certsInResp, new Date());
        } catch (OCSPException e) {
            final String message = "answer() basicOcspBuilder.build";
            if (LOG.isErrorEnabled()) {
                LOG.error(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage());
            }
            LOG.debug(message, e);
            if (auditEvent != null) {
                fillAuditEvent(auditEvent, AuditLevel.ERROR, AuditStatus.FAILED,
                        "BasicOCSPRespBuilder.build() with OCSPException");
            }
            return createUnsuccessfullOCSPResp(OcspResponseStatus.internalError);
        } finally {
            concurrentSigner.returnContentSigner(singleSigner);
        }

        OCSPRespBuilder ocspRespBuilder = new OCSPRespBuilder();
        try {
            OCSPResp ocspResp = ocspRespBuilder.build(OcspResponseStatus.successfull.getStatus(),
                    basicOcspResp);

            if (couldCacheInfo) {
                ResponseCacheInfo cacheInfo = new ResponseCacheInfo(cacheThisUpdate);
                if (cacheNextUpdate != Long.MAX_VALUE) {
                    cacheInfo.setNextUpdate(cacheNextUpdate);
                }
                return new OcspRespWithCacheInfo(ocspResp, cacheInfo);
            } else {
                return new OcspRespWithCacheInfo(ocspResp, null);
            }
        } catch (OCSPException e) {
            final String message = "answer() ocspRespBuilder.build";
            if (LOG.isErrorEnabled()) {
                LOG.error(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage());
            }
            LOG.debug(message, e);
            if (auditEvent != null) {
                fillAuditEvent(auditEvent, AuditLevel.ERROR, AuditStatus.FAILED,
                        "OCSPRespBuilder.build() with OCSPException");
            }
            return createUnsuccessfullOCSPResp(OcspResponseStatus.internalError);
        }

    } catch (Throwable t) {
        final String message = "Throwable";
        if (LOG.isErrorEnabled()) {
            LOG.error(LogUtil.buildExceptionLogFormat(message), t.getClass().getName(), t.getMessage());
        }
        LOG.debug(message, t);

        if (auditEvent != null) {
            fillAuditEvent(auditEvent, AuditLevel.ERROR, AuditStatus.FAILED, "internal error");
        }

        return createUnsuccessfullOCSPResp(OcspResponseStatus.internalError);
    }
}

From source file:org.xipki.pki.ocsp.server.impl.OcspServer.java

License:Open Source License

private OcspRespWithCacheInfo processCertReq(Req req, BasicOCSPRespBuilder builder, Responder responder,
        RequestOption reqOpt, ResponseOption repOpt, OcspRespControl repControl, AuditEvent event)
        throws IOException {
    CertificateID certId = req.getCertID();
    String certIdHashAlgo = certId.getHashAlgOID().getId();
    HashAlgoType reqHashAlgo = HashAlgoType.getHashAlgoType(certIdHashAlgo);
    if (reqHashAlgo == null) {
        LOG.warn("unknown CertID.hashAlgorithm {}", certIdHashAlgo);
        if (event != null) {
            fillAuditEvent(event, AuditLevel.INFO, AuditStatus.FAILED,
                    "unknown CertID.hashAlgorithm " + certIdHashAlgo);
        }//from  w w w  . java 2 s  . c  o  m
        return createUnsuccessfulOcspResp(OcspResponseStatus.malformedRequest);
    } else if (!reqOpt.allows(reqHashAlgo)) {
        LOG.warn("CertID.hashAlgorithm {} not allowed", certIdHashAlgo);
        if (event != null) {
            fillAuditEvent(event, AuditLevel.INFO, AuditStatus.FAILED,
                    "not allowed CertID.hashAlgorithm " + certIdHashAlgo);
        }
        return createUnsuccessfulOcspResp(OcspResponseStatus.malformedRequest);
    }

    if (event != null) {
        event.addEventData(OcspAuditConstants.NAME_serial, certId.getSerialNumber());
    }

    CertStatusInfo certStatusInfo = null;
    OcspStore answeredStore = null;
    boolean exceptionOccurs = false;

    Date now = new Date();
    for (OcspStore store : responder.getStores()) {
        try {
            certStatusInfo = store.getCertStatus(now, reqHashAlgo, certId.getIssuerNameHash(),
                    certId.getIssuerKeyHash(), certId.getSerialNumber(), repOpt.isIncludeCerthash(),
                    repOpt.getCertHashAlgo(), responder.getCertprofileOption());
            if (certStatusInfo != null && certStatusInfo.getCertStatus() != CertStatus.ISSUER_UNKNOWN) {
                answeredStore = store;
                break;
            }
        } catch (OcspStoreException ex) {
            exceptionOccurs = true;
            LogUtil.error(LOG, ex, "getCertStatus() of CertStatusStore " + store.getName());
        } // end try
    } // end for

    if (certStatusInfo == null) {
        if (exceptionOccurs) {
            fillAuditEvent(event, AuditLevel.INFO, AuditStatus.FAILED,
                    "no CertStatusStore can answer the request");
            return createUnsuccessfulOcspResp(OcspResponseStatus.tryLater);
        } else {
            certStatusInfo = CertStatusInfo.getIssuerUnknownCertStatusInfo(new Date(), null);
        }
    } else if (answeredStore != null && responder.getResponderOption().isInheritCaRevocation()) {
        CertRevocationInfo caRevInfo = answeredStore.getCaRevocationInfo(reqHashAlgo,
                certId.getIssuerNameHash(), certId.getIssuerKeyHash());
        if (caRevInfo != null) {
            CertStatus certStatus = certStatusInfo.getCertStatus();
            boolean replaced = false;
            if (certStatus == CertStatus.GOOD || certStatus == CertStatus.UNKNOWN) {
                replaced = true;
            } else if (certStatus == CertStatus.REVOKED) {
                if (certStatusInfo.getRevocationInfo().getRevocationTime()
                        .after(caRevInfo.getRevocationTime())) {
                    replaced = true;
                }
            }

            if (replaced) {
                CertRevocationInfo newRevInfo;
                if (caRevInfo.getReason() == CrlReason.CA_COMPROMISE) {
                    newRevInfo = caRevInfo;
                } else {
                    newRevInfo = new CertRevocationInfo(CrlReason.CA_COMPROMISE, caRevInfo.getRevocationTime(),
                            caRevInfo.getInvalidityTime());
                }
                certStatusInfo = CertStatusInfo.getRevokedCertStatusInfo(newRevInfo,
                        certStatusInfo.getCertHashAlgo(), certStatusInfo.getCertHash(),
                        certStatusInfo.getThisUpdate(), certStatusInfo.getNextUpdate(),
                        certStatusInfo.getCertprofile());
            } // end if(replaced)
        } // end if
    } // end if

    if (event != null) {
        String certprofile = certStatusInfo.getCertprofile();
        String auditCertType;
        if (certprofile != null) {
            auditCertType = responder.getAuditOption().getCertprofileMapping().get(certprofile);
            if (auditCertType == null) {
                auditCertType = certprofile;
            }
        } else {
            auditCertType = "UNKNOWN";
        }

        event.addEventData(OcspAuditConstants.NAME_type, auditCertType);
    }

    // certStatusInfo must not be null in any case, since at least one store
    // is configured
    Date thisUpdate = certStatusInfo.getThisUpdate();
    if (thisUpdate == null) {
        thisUpdate = new Date();
    }
    Date nextUpdate = certStatusInfo.getNextUpdate();

    List<Extension> extensions = new LinkedList<>();
    boolean unknownAsRevoked = false;
    CertificateStatus bcCertStatus;
    switch (certStatusInfo.getCertStatus()) {
    case GOOD:
        bcCertStatus = null;
        break;

    case ISSUER_UNKNOWN:
        repControl.couldCacheInfo = false;
        bcCertStatus = new UnknownStatus();
        break;

    case UNKNOWN:
    case IGNORE:
        repControl.couldCacheInfo = false;
        if (responder.getResponderOption().getMode() == OcspMode.RFC2560) {
            bcCertStatus = new UnknownStatus();
        } else { // (ocspMode == OCSPMode.RFC6960)
            unknownAsRevoked = true;
            repControl.includeExtendedRevokeExtension = true;
            bcCertStatus = new RevokedStatus(new Date(0L), CrlReason.CERTIFICATE_HOLD.getCode());
        }
        break;
    case REVOKED:
        CertRevocationInfo revInfo = certStatusInfo.getRevocationInfo();
        ASN1GeneralizedTime revTime = new ASN1GeneralizedTime(revInfo.getRevocationTime());
        org.bouncycastle.asn1.x509.CRLReason tmpReason = null;
        if (repOpt.isIncludeRevReason()) {
            tmpReason = org.bouncycastle.asn1.x509.CRLReason.lookup(revInfo.getReason().getCode());
        }
        RevokedInfo tmpRevInfo = new RevokedInfo(revTime, tmpReason);
        bcCertStatus = new RevokedStatus(tmpRevInfo);

        Date invalidityDate = revInfo.getInvalidityTime();
        if (repOpt.isIncludeInvalidityDate() && invalidityDate != null
                && !invalidityDate.equals(revInfo.getRevocationTime())) {
            Extension extension = new Extension(Extension.invalidityDate, false,
                    new ASN1GeneralizedTime(invalidityDate).getEncoded());
            extensions.add(extension);
        }
        break;
    default:
        throw new RuntimeException("unknown CertificateStatus:" + certStatusInfo.getCertStatus());
    } // end switch

    byte[] certHash = certStatusInfo.getCertHash();
    if (certHash != null) {
        ASN1ObjectIdentifier hashAlgOid = certStatusInfo.getCertHashAlgo().getOid();
        AlgorithmIdentifier hashAlgId = new AlgorithmIdentifier(hashAlgOid, DERNull.INSTANCE);
        CertHash bcCertHash = new CertHash(hashAlgId, certHash);

        byte[] encodedCertHash;
        try {
            encodedCertHash = bcCertHash.getEncoded();
        } catch (IOException ex) {
            LogUtil.error(LOG, ex, "answer() bcCertHash.getEncoded");
            if (event != null) {
                fillAuditEvent(event, AuditLevel.ERROR, AuditStatus.FAILED,
                        "CertHash.getEncoded() with IOException");
            }
            return createUnsuccessfulOcspResp(OcspResponseStatus.internalError);
        }

        Extension extension = new Extension(ISISMTTObjectIdentifiers.id_isismtt_at_certHash, false,
                encodedCertHash);

        extensions.add(extension);
    } // end if(certHash != null)

    if (certStatusInfo.getArchiveCutOff() != null) {
        Extension extension = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_archive_cutoff, false,
                new ASN1GeneralizedTime(certStatusInfo.getArchiveCutOff()).getEncoded());
        extensions.add(extension);
    }

    String certStatusText;
    if (bcCertStatus instanceof UnknownStatus) {
        certStatusText = "unknown";
    } else if (bcCertStatus instanceof RevokedStatus) {
        certStatusText = unknownAsRevoked ? "unknown_as_revoked" : "revoked";
    } else if (bcCertStatus == null) {
        certStatusText = "good";
    } else {
        certStatusText = "should-not-happen";
    }

    if (event != null) {
        event.setLevel(AuditLevel.INFO);
        event.setStatus(AuditStatus.SUCCESSFUL);
        event.addEventData(OcspAuditConstants.NAME_status, certStatusText);
    }

    if (LOG.isDebugEnabled()) {
        StringBuilder sb = new StringBuilder(250);
        sb.append("certHashAlgo: ").append(certId.getHashAlgOID().getId()).append(", ");
        sb.append("issuerNameHash: ").append(Hex.toHexString(certId.getIssuerNameHash()).toUpperCase())
                .append(", ");
        sb.append("issuerKeyHash: ").append(Hex.toHexString(certId.getIssuerKeyHash()).toUpperCase())
                .append(", ");
        sb.append("serialNumber: ").append(LogUtil.formatCsn(certId.getSerialNumber())).append(", ");
        sb.append("certStatus: ").append(certStatusText).append(", ");
        sb.append("thisUpdate: ").append(thisUpdate).append(", ");
        sb.append("nextUpdate: ").append(nextUpdate);
        if (certHash != null) {
            sb.append(", certHash: ").append(Hex.toHexString(certHash).toUpperCase());
        }
        LOG.debug(sb.toString());
    }

    Extensions extns = null;
    if (CollectionUtil.isNonEmpty(extensions)) {
        extns = new Extensions(extensions.toArray(new Extension[0]));
    }

    builder.addResponse(certId, bcCertStatus, thisUpdate, nextUpdate, extns);
    repControl.cacheThisUpdate = Math.max(repControl.cacheThisUpdate, thisUpdate.getTime());
    if (nextUpdate != null) {
        repControl.cacheNextUpdate = Math.min(repControl.cacheNextUpdate, nextUpdate.getTime());
    }

    return null;
}