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

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

Introduction

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

Prototype

public AlgorithmIdentifier getHashAlgorithm() 

Source Link

Usage

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

License:Open Source License

/**
 * This test runs a vanilla run through of the process method of OcspCertHashExtension, and simply verifies that 
 * the certHash is correctly produced (i.e fingerprint by SHA256)
 * @throws CertificateException //from  ww  w.  jav  a  2  s.c  om
 * @throws OperatorCreationException 
 * 
 */
@Test
public void testProcess() throws InvalidKeyException, NoSuchAlgorithmException, SignatureException,
        IllegalStateException, NoSuchProviderException, InvalidAlgorithmParameterException, IOException,
        OperatorCreationException, CertificateException {
    OcspCertHashExtension ocspCertHashExtension = new OcspCertHashExtension();
    KeyPair keys = KeyTools.genKeys("512", AlgorithmConstants.KEYALGORITHM_RSA);
    X509Certificate cert = CertTools.genSelfCert("CN=CertHashTest", 365, null, keys.getPrivate(),
            keys.getPublic(), AlgorithmConstants.SIGALG_SHA1_WITH_RSA, false);
    Map<ASN1ObjectIdentifier, Extension> result = ocspCertHashExtension.process(null, null, null, cert, null);
    Extension extension = result.get(new ASN1ObjectIdentifier(OcspCertHashExtension.CERT_HASH_OID));
    ASN1Encodable derSequence = extension.getParsedValue();
    CertHash certHash = CertHash.getInstance(derSequence);
    assertEquals("Algorithm was not extracted correctly from CertHash", OcspCertHashExtension.SHA256,
            certHash.getHashAlgorithm().getAlgorithm());
    MessageDigest md = MessageDigest.getInstance("SHA256");
    String fingerprint = new String(Hex.encode(md.digest(cert.getEncoded())));
    String certificateHashAsString = new String(Hex.encode(certHash.getCertificateHash()));
    assertEquals("Fingerprint (certificate hash) was not extracted correctly", fingerprint,
            certificateHashAsString);
}

From source file:org.xipki.ocsp.client.shell.OCSPStatusCommand.java

License:Open Source License

@Override
protected Object processResponse(final OCSPResp response, final X509Certificate respIssuer,
        final X509Certificate issuer, final List<BigInteger> serialNumbers,
        final Map<BigInteger, byte[]> encodedCerts) throws Exception {
    BasicOCSPResp basicResp = OCSPUtils.extractBasicOCSPResp(response);

    boolean extendedRevoke = basicResp.getExtension(OCSPRequestor.id_pkix_ocsp_extendedRevoke) != null;

    SingleResp[] singleResponses = basicResp.getResponses();

    int n = singleResponses == null ? 0 : singleResponses.length;
    if (n == 0) {
        throw new CmdFailure("received no status from server");
    }//w w w .ja v a2  s  .  co  m

    if (n != serialNumbers.size()) {
        throw new CmdFailure("received status with " + n + " single responses from server, but "
                + serialNumbers.size() + " were requested");
    }

    Date[] thisUpdates = new Date[n];
    for (int i = 0; i < n; i++) {
        thisUpdates[i] = singleResponses[i].getThisUpdate();
    }

    // check the signature if available
    if (null == basicResp.getSignature()) {
        out("response is not signed");
    } else {
        X509CertificateHolder[] responderCerts = basicResp.getCerts();
        if (responderCerts == null || responderCerts.length < 1) {
            throw new CmdFailure("no responder certificate is contained in the response");
        }

        X509CertificateHolder respSigner = responderCerts[0];
        boolean validOn = true;
        for (Date thisUpdate : thisUpdates) {
            validOn = respSigner.isValidOn(thisUpdate);
            if (validOn == false) {
                throw new CmdFailure("responder certificate is not valid on " + thisUpdate);
            }
        }

        if (validOn) {
            PublicKey responderPubKey = KeyUtil.generatePublicKey(respSigner.getSubjectPublicKeyInfo());
            ContentVerifierProvider cvp = KeyUtil.getContentVerifierProvider(responderPubKey);
            boolean sigValid = basicResp.isSignatureValid(cvp);

            if (sigValid == false) {
                throw new CmdFailure("response is equipped with invalid signature");
            }

            // verify the OCSPResponse signer
            if (respIssuer != null) {
                boolean certValid = true;
                X509Certificate jceRespSigner = new X509CertificateObject(respSigner.toASN1Structure());
                if (X509Util.issues(respIssuer, jceRespSigner)) {
                    try {
                        jceRespSigner.verify(respIssuer.getPublicKey());
                    } catch (SignatureException e) {
                        certValid = false;
                    }
                }

                if (certValid == false) {
                    throw new CmdFailure(
                            "response is equipped with valid signature but the OCSP signer is not trusted");
                }
            } else {
                out("response is equipped with valid signature");
            }
        }

        if (verbose.booleanValue()) {
            out("responder is " + X509Util.getRFC4519Name(responderCerts[0].getSubject()));
        }
    }

    for (int i = 0; i < n; i++) {
        if (n > 1) {
            out("---------------------------- " + i + " ----------------------------");
        }
        SingleResp singleResp = singleResponses[i];
        BigInteger serialNumber = singleResp.getCertID().getSerialNumber();

        CertificateStatus singleCertStatus = singleResp.getCertStatus();

        String status;
        if (singleCertStatus == null) {
            status = "good";
        } else if (singleCertStatus instanceof RevokedStatus) {
            RevokedStatus revStatus = (RevokedStatus) singleCertStatus;
            Date revTime = revStatus.getRevocationTime();
            Date invTime = null;
            Extension ext = singleResp.getExtension(Extension.invalidityDate);
            if (ext != null) {
                invTime = ASN1GeneralizedTime.getInstance(ext.getParsedValue()).getDate();
            }

            if (revStatus.hasRevocationReason()) {
                int reason = revStatus.getRevocationReason();
                if (extendedRevoke && reason == CRLReason.CERTIFICATE_HOLD.getCode()
                        && revTime.getTime() == 0) {
                    status = "unknown (RFC6960)";
                } else {
                    StringBuilder sb = new StringBuilder("revoked, reason = ");
                    sb.append(CRLReason.forReasonCode(reason).getDescription());
                    sb.append(", revocationTime = ");
                    sb.append(revTime);
                    if (invTime != null) {
                        sb.append(", invalidityTime = ");
                        sb.append(invTime);
                    }
                    status = sb.toString();
                }
            } else {
                status = "revoked, no reason, revocationTime = " + revTime;
            }
        } else if (singleCertStatus instanceof UnknownStatus) {
            status = "unknown (RFC2560)";
        } else {
            status = "ERROR";
        }

        StringBuilder msg = new StringBuilder();
        msg.append("serialNumber: ").append(serialNumber);
        msg.append("\nCertificate status: ").append(status);

        if (verbose.booleanValue()) {
            msg.append("\nthisUpdate: " + singleResp.getThisUpdate());
            msg.append("\nnextUpdate: " + singleResp.getNextUpdate());

            Extension extension = singleResp.getExtension(ISISMTTObjectIdentifiers.id_isismtt_at_certHash);
            if (extension != null) {
                msg.append("\nCertHash is provided:\n");
                ASN1Encodable extensionValue = extension.getParsedValue();
                CertHash certHash = CertHash.getInstance(extensionValue);
                ASN1ObjectIdentifier hashAlgOid = certHash.getHashAlgorithm().getAlgorithm();
                byte[] hashValue = certHash.getCertificateHash();

                msg.append("\tHash algo : ").append(hashAlgOid.getId()).append("\n");
                msg.append("\tHash value: ").append(Hex.toHexString(hashValue)).append("\n");

                if (encodedCerts != null) {
                    byte[] encodedCert = encodedCerts.get(serialNumber);
                    MessageDigest md = MessageDigest.getInstance(hashAlgOid.getId());
                    byte[] expectedHashValue = md.digest(encodedCert);
                    if (Arrays.equals(expectedHashValue, hashValue)) {
                        msg.append("\tThis matches the requested certificate");
                    } else {
                        msg.append("\tThis differs from the requested certificate");
                    }
                }
            }

            extension = singleResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_archive_cutoff);
            if (extension != null) {
                ASN1Encodable extensionValue = extension.getParsedValue();
                ASN1GeneralizedTime time = ASN1GeneralizedTime.getInstance(extensionValue);
                msg.append("\nArchive-CutOff: ");
                msg.append(time.getTimeString());
            }

            AlgorithmIdentifier sigAlg = basicResp.getSignatureAlgorithmID();
            if (sigAlg == null) {
                msg.append(("\nresponse is not signed"));
            } else {
                String sigAlgName = AlgorithmUtil.getSignatureAlgoName(sigAlg);
                if (sigAlgName == null) {
                    sigAlgName = "unknown";
                }
                msg.append("\nresponse is signed with ").append(sigAlgName);
            }

            // extensions
            msg.append("\nExtensions: ");

            List<?> extensionOIDs = basicResp.getExtensionOIDs();
            if (extensionOIDs == null || extensionOIDs.size() == 0) {
                msg.append("-");
            } else {
                int size = extensionOIDs.size();
                for (int j = 0; j < size; j++) {
                    ASN1ObjectIdentifier extensionOID = (ASN1ObjectIdentifier) extensionOIDs.get(j);
                    String name = extensionOidNameMap.get(extensionOID);
                    msg.append(name == null ? extensionOID.getId() : name);
                    if (j != size - 1) {
                        msg.append(", ");
                    }
                }
            }
        }

        out(msg.toString());
    }
    out("");

    return null;
}

From source file:org.xipki.ocsp.qa.impl.OcspQAImpl.java

License:Open Source License

private List<ValidationIssue> checkSingleCert(final int index, final SingleResp singleResp,
        final OcspCertStatus expectedStatus, final byte[] encodedCert, final boolean extendedRevoke,
        final Occurrence nextupdateOccurrence, final Occurrence certhashOccurrence,
        final ASN1ObjectIdentifier certhashAlg) {
    List<ValidationIssue> issues = new LinkedList<>();
    {//from  www .j a  v  a  2  s.  com
        // status
        ValidationIssue issue = new ValidationIssue("OCSP.RESPONSE." + index + ".STATUS", "certificate status");
        issues.add(issue);

        CertificateStatus singleCertStatus = singleResp.getCertStatus();

        OcspCertStatus status = null;
        if (singleCertStatus == null) {
            status = OcspCertStatus.good;
        } else if (singleCertStatus instanceof RevokedStatus) {
            RevokedStatus revStatus = (RevokedStatus) singleCertStatus;
            Date revTime = revStatus.getRevocationTime();

            if (revStatus.hasRevocationReason()) {
                int reason = revStatus.getRevocationReason();
                if (extendedRevoke && reason == CRLReason.CERTIFICATE_HOLD.getCode()
                        && revTime.getTime() == 0) {
                    status = OcspCertStatus.unknown;
                } else {
                    CRLReason revocationReason = CRLReason.forReasonCode(reason);
                    switch (revocationReason) {
                    case UNSPECIFIED:
                        status = OcspCertStatus.unspecified;
                        break;
                    case KEY_COMPROMISE:
                        status = OcspCertStatus.keyCompromise;
                        break;
                    case CA_COMPROMISE:
                        status = OcspCertStatus.cACompromise;
                        break;
                    case AFFILIATION_CHANGED:
                        status = OcspCertStatus.affiliationChanged;
                        break;
                    case SUPERSEDED:
                        status = OcspCertStatus.superseded;
                        break;
                    case CERTIFICATE_HOLD:
                        status = OcspCertStatus.certificateHold;
                        break;
                    case REMOVE_FROM_CRL:
                        status = OcspCertStatus.removeFromCRL;
                        break;
                    case PRIVILEGE_WITHDRAWN:
                        status = OcspCertStatus.privilegeWithdrawn;
                        break;
                    case AA_COMPROMISE:
                        status = OcspCertStatus.aACompromise;
                        break;
                    default:
                        issue.setFailureMessage("should not reach here, unknwon CRLReason " + revocationReason);
                        break;
                    }
                }
            } else {
                status = OcspCertStatus.rev_noreason;
            }
        } else if (singleCertStatus instanceof UnknownStatus) {
            status = OcspCertStatus.issuerUnknown;
        } else {
            issue.setFailureMessage("unknown certstatus: " + singleCertStatus.getClass().getName());
        }

        if (issue.isFailed() == false && expectedStatus != status) {
            issue.setFailureMessage("is='" + status + "', but expected='" + expectedStatus + "'");
        }
    }

    {
        // nextUpdate
        Date nextUpdate = singleResp.getNextUpdate();
        checkOccurrence("OCSP.RESPONSE." + index + ".NEXTUPDATE", nextUpdate, nextupdateOccurrence);
    }

    Extension extension = singleResp.getExtension(ISISMTTObjectIdentifiers.id_isismtt_at_certHash);
    {
        checkOccurrence("OCSP.RESPONSE." + index + ".CERTHASh", extension, certhashOccurrence);
    }

    if (extension != null) {
        ASN1Encodable extensionValue = extension.getParsedValue();
        CertHash certHash = CertHash.getInstance(extensionValue);
        ASN1ObjectIdentifier hashAlgOid = certHash.getHashAlgorithm().getAlgorithm();
        if (certhashAlg != null) {
            // certHash algorithm
            ValidationIssue issue = new ValidationIssue("OCSP.RESPONSE." + index + ".CERTHASH.ALG",
                    "certhash algorithm");
            issues.add(issue);

            ASN1ObjectIdentifier is = certHash.getHashAlgorithm().getAlgorithm();
            if (certhashAlg.equals(is) == false) {
                issue.setFailureMessage("is '" + is.getId() + "', but expected '" + certhashAlg.getId() + "'");
            }
        }

        byte[] hashValue = certHash.getCertificateHash();
        if (encodedCert != null) {
            ValidationIssue issue = new ValidationIssue("OCSP.RESPONSE." + index + ".CERTHASH.VALIDITY",
                    "certhash validity");
            issues.add(issue);

            try {
                MessageDigest md = MessageDigest.getInstance(hashAlgOid.getId());
                byte[] expectedHashValue = md.digest(encodedCert);
                if (Arrays.equals(expectedHashValue, hashValue) == false) {
                    issue.setFailureMessage("certHash does not match the requested certificate");
                }
            } catch (NoSuchAlgorithmException e) {
                issue.setFailureMessage("NoSuchAlgorithm " + hashAlgOid.getId());
            }
        }
    }

    return issues;
}

From source file:org.xipki.pki.ocsp.client.shell.OcspStatusCmd.java

License:Open Source License

@Override
protected Object processResponse(final OCSPResp response, final X509Certificate respIssuer,
        final IssuerHash issuerHash, final List<BigInteger> serialNumbers,
        final Map<BigInteger, byte[]> encodedCerts) throws Exception {
    ParamUtil.requireNonNull("response", response);
    ParamUtil.requireNonNull("issuerHash", issuerHash);
    ParamUtil.requireNonNull("serialNumbers", serialNumbers);

    BasicOCSPResp basicResp = OcspUtils.extractBasicOcspResp(response);

    boolean extendedRevoke = basicResp.getExtension(ObjectIdentifiers.id_pkix_ocsp_extendedRevoke) != null;

    SingleResp[] singleResponses = basicResp.getResponses();

    if (singleResponses == null || singleResponses.length == 0) {
        throw new CmdFailure("received no status from server");
    }// w  w w.  j  a v a2  s  .c  o m

    final int n = singleResponses.length;
    if (n != serialNumbers.size()) {
        throw new CmdFailure("received status with " + n + " single responses from server, but "
                + serialNumbers.size() + " were requested");
    }

    Date[] thisUpdates = new Date[n];
    for (int i = 0; i < n; i++) {
        thisUpdates[i] = singleResponses[i].getThisUpdate();
    }

    // check the signature if available
    if (null == basicResp.getSignature()) {
        println("response is not signed");
    } else {
        X509CertificateHolder[] responderCerts = basicResp.getCerts();
        if (responderCerts == null || responderCerts.length < 1) {
            throw new CmdFailure("no responder certificate is contained in the response");
        }

        ResponderID respId = basicResp.getResponderId().toASN1Primitive();
        X500Name respIdByName = respId.getName();
        byte[] respIdByKey = respId.getKeyHash();

        X509CertificateHolder respSigner = null;
        for (X509CertificateHolder cert : responderCerts) {
            if (respIdByName != null) {
                if (cert.getSubject().equals(respIdByName)) {
                    respSigner = cert;
                }
            } else {
                byte[] spkiSha1 = HashAlgoType.SHA1
                        .hash(cert.getSubjectPublicKeyInfo().getPublicKeyData().getBytes());
                if (Arrays.equals(respIdByKey, spkiSha1)) {
                    respSigner = cert;
                }
            }

            if (respSigner != null) {
                break;
            }
        }

        if (respSigner == null) {
            throw new CmdFailure("no responder certificate match the ResponderId");
        }

        boolean validOn = true;
        for (Date thisUpdate : thisUpdates) {
            validOn = respSigner.isValidOn(thisUpdate);
            if (!validOn) {
                throw new CmdFailure("responder certificate is not valid on " + thisUpdate);
            }
        }

        if (validOn) {
            PublicKey responderPubKey = KeyUtil.generatePublicKey(respSigner.getSubjectPublicKeyInfo());
            ContentVerifierProvider cvp = securityFactory.getContentVerifierProvider(responderPubKey);
            boolean sigValid = basicResp.isSignatureValid(cvp);

            if (!sigValid) {
                throw new CmdFailure("response is equipped with invalid signature");
            }

            // verify the OCSPResponse signer
            if (respIssuer != null) {
                boolean certValid = true;
                X509Certificate jceRespSigner = X509Util.toX509Cert(respSigner.toASN1Structure());
                if (X509Util.issues(respIssuer, jceRespSigner)) {
                    try {
                        jceRespSigner.verify(respIssuer.getPublicKey());
                    } catch (SignatureException ex) {
                        certValid = false;
                    }
                }

                if (!certValid) {
                    throw new CmdFailure("response is equipped with valid signature but the"
                            + " OCSP signer is not trusted");
                }
            } else {
                println("response is equipped with valid signature");
            } // end if(respIssuer)
        } // end if(validOn)

        if (verbose.booleanValue()) {
            println("responder is " + X509Util.getRfc4519Name(responderCerts[0].getSubject()));
        }
    } // end if

    for (int i = 0; i < n; i++) {
        if (n > 1) {
            println("---------------------------- " + i + "----------------------------");
        }
        SingleResp singleResp = singleResponses[i];
        CertificateStatus singleCertStatus = singleResp.getCertStatus();

        String status;
        if (singleCertStatus == null) {
            status = "good";
        } else if (singleCertStatus instanceof RevokedStatus) {
            RevokedStatus revStatus = (RevokedStatus) singleCertStatus;
            Date revTime = revStatus.getRevocationTime();
            Date invTime = null;
            Extension ext = singleResp.getExtension(Extension.invalidityDate);
            if (ext != null) {
                invTime = ASN1GeneralizedTime.getInstance(ext.getParsedValue()).getDate();
            }

            if (revStatus.hasRevocationReason()) {
                int reason = revStatus.getRevocationReason();
                if (extendedRevoke && reason == CrlReason.CERTIFICATE_HOLD.getCode()
                        && revTime.getTime() == 0) {
                    status = "unknown (RFC6960)";
                } else {
                    StringBuilder sb = new StringBuilder("revoked, reason = ");
                    sb.append(CrlReason.forReasonCode(reason).getDescription());
                    sb.append(", revocationTime = ").append(revTime);
                    if (invTime != null) {
                        sb.append(", invalidityTime = ").append(invTime);
                    }
                    status = sb.toString();
                }
            } else {
                status = "revoked, no reason, revocationTime = " + revTime;
            }
        } else if (singleCertStatus instanceof UnknownStatus) {
            status = "unknown (RFC2560)";
        } else {
            status = "ERROR";
        }

        StringBuilder msg = new StringBuilder();

        CertificateID certId = singleResp.getCertID();
        HashAlgoType hashAlgo = HashAlgoType.getNonNullHashAlgoType(certId.getHashAlgOID());
        boolean issuerMatch = issuerHash.match(hashAlgo, certId.getIssuerNameHash(), certId.getIssuerKeyHash());
        BigInteger serialNumber = certId.getSerialNumber();

        msg.append("issuer matched: ").append(issuerMatch);
        msg.append("\nserialNumber: ").append(LogUtil.formatCsn(serialNumber));
        msg.append("\nCertificate status: ").append(status);

        if (verbose.booleanValue()) {
            msg.append("\nthisUpdate: ").append(singleResp.getThisUpdate());
            msg.append("\nnextUpdate: ").append(singleResp.getNextUpdate());

            Extension extension = singleResp.getExtension(ISISMTTObjectIdentifiers.id_isismtt_at_certHash);
            if (extension != null) {
                msg.append("\nCertHash is provided:\n");
                ASN1Encodable extensionValue = extension.getParsedValue();
                CertHash certHash = CertHash.getInstance(extensionValue);
                ASN1ObjectIdentifier hashAlgOid = certHash.getHashAlgorithm().getAlgorithm();
                byte[] hashValue = certHash.getCertificateHash();

                msg.append("\tHash algo : ").append(hashAlgOid.getId()).append("\n");
                msg.append("\tHash value: ").append(Hex.toHexString(hashValue)).append("\n");

                if (encodedCerts != null) {
                    byte[] encodedCert = encodedCerts.get(serialNumber);
                    MessageDigest md = MessageDigest.getInstance(hashAlgOid.getId());
                    byte[] expectedHashValue = md.digest(encodedCert);
                    if (Arrays.equals(expectedHashValue, hashValue)) {
                        msg.append("\tThis matches the requested certificate");
                    } else {
                        msg.append("\tThis differs from the requested certificate");
                    }
                }
            } // end if (extension != null)

            extension = singleResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_archive_cutoff);
            if (extension != null) {
                ASN1Encodable extensionValue = extension.getParsedValue();
                ASN1GeneralizedTime time = ASN1GeneralizedTime.getInstance(extensionValue);
                msg.append("\nArchive-CutOff: ");
                msg.append(time.getTimeString());
            }

            AlgorithmIdentifier sigAlg = basicResp.getSignatureAlgorithmID();
            if (sigAlg == null) {
                msg.append(("\nresponse is not signed"));
            } else {
                String sigAlgName = AlgorithmUtil.getSignatureAlgoName(sigAlg);
                if (sigAlgName == null) {
                    sigAlgName = "unknown";
                }
                msg.append("\nresponse is signed with ").append(sigAlgName);
            }

            // extensions
            msg.append("\nExtensions: ");

            List<?> extensionOids = basicResp.getExtensionOIDs();
            if (extensionOids == null || extensionOids.size() == 0) {
                msg.append("-");
            } else {
                int size = extensionOids.size();
                for (int j = 0; j < size; j++) {
                    ASN1ObjectIdentifier extensionOid = (ASN1ObjectIdentifier) extensionOids.get(j);
                    String name = EXTENSION_OIDNAME_MAP.get(extensionOid);
                    if (name == null) {
                        msg.append(extensionOid.getId());
                    } else {
                        msg.append(name);
                    }
                    if (j != size - 1) {
                        msg.append(", ");
                    }
                }
            }
        } // end if (verbose.booleanValue())

        println(msg.toString());
    } // end for
    println("");

    return null;
}

From source file:org.xipki.pki.ocsp.qa.OcspQa.java

License:Open Source License

private List<ValidationIssue> checkSingleCert(final int index, final SingleResp singleResp,
        final IssuerHash issuerHash, final OcspCertStatus expectedStatus, final byte[] encodedCert,
        final boolean extendedRevoke, final Occurrence nextupdateOccurrence,
        final Occurrence certhashOccurrence, final ASN1ObjectIdentifier certhashAlg) {
    List<ValidationIssue> issues = new LinkedList<>();

    // issuer hash
    ValidationIssue issue = new ValidationIssue("OCSP.RESPONSE." + index + ".ISSUER", "certificate issuer");
    issues.add(issue);// ww  w. ja v a2s.c  o  m

    CertificateID certId = singleResp.getCertID();
    HashAlgoType hashAlgo = HashAlgoType.getHashAlgoType(certId.getHashAlgOID());
    if (hashAlgo == null) {
        issue.setFailureMessage("unknown hash algorithm " + certId.getHashAlgOID().getId());
    } else {
        if (!issuerHash.match(hashAlgo, certId.getIssuerNameHash(), certId.getIssuerKeyHash())) {
            issue.setFailureMessage("issuer not match");
        }
    }

    // status
    issue = new ValidationIssue("OCSP.RESPONSE." + index + ".STATUS", "certificate status");
    issues.add(issue);

    CertificateStatus singleCertStatus = singleResp.getCertStatus();

    OcspCertStatus status = null;
    if (singleCertStatus == null) {
        status = OcspCertStatus.good;
    } else if (singleCertStatus instanceof RevokedStatus) {
        RevokedStatus revStatus = (RevokedStatus) singleCertStatus;
        Date revTime = revStatus.getRevocationTime();

        if (revStatus.hasRevocationReason()) {
            int reason = revStatus.getRevocationReason();
            if (extendedRevoke && reason == CrlReason.CERTIFICATE_HOLD.getCode() && revTime.getTime() == 0) {
                status = OcspCertStatus.unknown;
            } else {
                CrlReason revocationReason = CrlReason.forReasonCode(reason);
                switch (revocationReason) {
                case UNSPECIFIED:
                    status = OcspCertStatus.unspecified;
                    break;
                case KEY_COMPROMISE:
                    status = OcspCertStatus.keyCompromise;
                    break;
                case CA_COMPROMISE:
                    status = OcspCertStatus.cACompromise;
                    break;
                case AFFILIATION_CHANGED:
                    status = OcspCertStatus.affiliationChanged;
                    break;
                case SUPERSEDED:
                    status = OcspCertStatus.superseded;
                    break;
                case CERTIFICATE_HOLD:
                    status = OcspCertStatus.certificateHold;
                    break;
                case REMOVE_FROM_CRL:
                    status = OcspCertStatus.removeFromCRL;
                    break;
                case PRIVILEGE_WITHDRAWN:
                    status = OcspCertStatus.privilegeWithdrawn;
                    break;
                case AA_COMPROMISE:
                    status = OcspCertStatus.aACompromise;
                    break;
                default:
                    issue.setFailureMessage("should not reach here, unknown CRLReason " + revocationReason);
                    break;
                }
            } // end if
        } else {
            status = OcspCertStatus.rev_noreason;
        } // end if (revStatus.hasRevocationReason())
    } else if (singleCertStatus instanceof UnknownStatus) {
        status = OcspCertStatus.issuerUnknown;
    } else {
        issue.setFailureMessage("unknown certstatus: " + singleCertStatus.getClass().getName());
    }

    if (!issue.isFailed() && expectedStatus != status) {
        issue.setFailureMessage("is='" + status + "', but expected='" + expectedStatus + "'");
    }

    // nextUpdate
    Date nextUpdate = singleResp.getNextUpdate();
    checkOccurrence("OCSP.RESPONSE." + index + ".NEXTUPDATE", nextUpdate, nextupdateOccurrence);

    Extension extension = singleResp.getExtension(ISISMTTObjectIdentifiers.id_isismtt_at_certHash);
    checkOccurrence("OCSP.RESPONSE." + index + ".CERTHASH", extension, certhashOccurrence);

    if (extension != null) {
        ASN1Encodable extensionValue = extension.getParsedValue();
        CertHash certHash = CertHash.getInstance(extensionValue);
        ASN1ObjectIdentifier hashAlgOid = certHash.getHashAlgorithm().getAlgorithm();
        if (certhashAlg != null) {
            // certHash algorithm
            issue = new ValidationIssue("OCSP.RESPONSE." + index + ".CHASH.ALG", "certhash algorithm");
            issues.add(issue);

            ASN1ObjectIdentifier is = certHash.getHashAlgorithm().getAlgorithm();
            if (!certhashAlg.equals(is)) {
                issue.setFailureMessage("is '" + is.getId() + "', but expected '" + certhashAlg.getId() + "'");
            }
        }

        byte[] hashValue = certHash.getCertificateHash();
        if (encodedCert != null) {
            issue = new ValidationIssue("OCSP.RESPONSE." + index + ".CHASH.VALIDITY", "certhash validity");
            issues.add(issue);

            try {
                MessageDigest md = MessageDigest.getInstance(hashAlgOid.getId());
                byte[] expectedHashValue = md.digest(encodedCert);
                if (!Arrays.equals(expectedHashValue, hashValue)) {
                    issue.setFailureMessage("certhash does not match the requested certificate");
                }
            } catch (NoSuchAlgorithmException ex) {
                issue.setFailureMessage("NoSuchAlgorithm " + hashAlgOid.getId());
            }
        } // end if(encodedCert != null)
    } // end if (extension != null)

    return issues;
}