Example usage for org.bouncycastle.cert.ocsp BasicOCSPResp getExtension

List of usage examples for org.bouncycastle.cert.ocsp BasicOCSPResp getExtension

Introduction

In this page you can find the example usage for org.bouncycastle.cert.ocsp BasicOCSPResp getExtension.

Prototype

public Extension getExtension(ASN1ObjectIdentifier oid) 

Source Link

Usage

From source file:eu.europa.ec.markt.dss.validation102853.ocsp.OnlineOCSPSource.java

License:Open Source License

@Override
public BasicOCSPResp getOCSPResponse(final X509Certificate x509Certificate,
        final X509Certificate issuerX509Certificate) {

    if (dataLoader == null) {

        throw new DSSNullException(DataLoader.class);
    }//from www  . ja  v a  2s .  com
    try {

        final String ocspUri = getAccessLocation(x509Certificate);
        if (LOG.isDebugEnabled()) {
            LOG.debug("OCSP URI: " + ocspUri);
        }
        if (ocspUri == null) {

            return null;
        }
        final byte[] content = buildOCSPRequest(x509Certificate, issuerX509Certificate);

        final byte[] ocspRespBytes = dataLoader.post(ocspUri, content);

        final OCSPResp ocspResp = new OCSPResp(ocspRespBytes);
        /*
                    final int status = ocspResp.getStatus();
                    System.out.println(status);
        */
        try {

            final BasicOCSPResp responseObject = (BasicOCSPResp) ocspResp.getResponseObject();
            if (ADD_NONCE) {

                final Extension extension = responseObject
                        .getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
                final DEROctetString receivedNonce = (DEROctetString) extension.getExtnValue();
                if (!receivedNonce.equals(nonce)) {

                    throw new DSSException("The OCSP request was the victim of replay attack: nonce[sent:"
                            + nonce + ", received:" + receivedNonce);
                }
            }
            return responseObject;
        } catch (NullPointerException e) {

            LOG.error(
                    "OCSP error: Encountered a case when the OCSPResp is initialised with a null OCSP response... (and there are no nullity checks in the OCSPResp implementation)",
                    e);
        }
    } catch (OCSPException e) {

        LOG.error("OCSP error: " + e.getMessage(), e);
    } catch (IOException e) {

        throw new DSSException(e);
    }
    return null;
}

From source file:eu.europa.ec.markt.dss.validation102853.ocsp.SKOnlineOCSPSource.java

License:GNU General Public License

protected void checkNonce(BasicOCSPResp basicOCSPResp, Extension expectedNonceExtension) {
    final Extension extension = basicOCSPResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
    final DEROctetString expectedNonce = (DEROctetString) expectedNonceExtension.getExtnValue();
    final DEROctetString receivedNonce = (DEROctetString) extension.getExtnValue();
    if (!receivedNonce.equals(expectedNonce)) {
        throw new DigiDoc4JException("The OCSP request was the victim of replay attack: nonce[sent:"
                + expectedNonce + "," + " received:" + receivedNonce);
    }/* w ww.  j  a va  2  s  . com*/
}

From source file:eu.europa.esig.dss.client.ocsp.OnlineOCSPSource.java

License:Open Source License

private boolean isNonceMatch(final BasicOCSPResp basicOCSPResp) {
    Extension extension = basicOCSPResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce);
    DEROctetString derReceivedNonce = (DEROctetString) extension.getExtnValue();
    BigInteger receivedNonce = new BigInteger(derReceivedNonce.getOctets());
    return receivedNonce.equals(nonceSource.getNonce());
}

From source file:net.maritimecloud.pki.ocsp.OCSPClient.java

License:Open Source License

public CertStatus getCertificateStatus() throws OCSPValidationException {
    try {/*from w w  w. j a v  a  2 s  .c o  m*/
        if (null == url) {
            throw new OCSPValidationException("Certificate not validated by OCSP");
        }

        byte[] encodedOcspRequest = generateOCSPRequest(issuer, certificate.getSerialNumber()).getEncoded();

        HttpURLConnection httpConnection;
        httpConnection = (HttpURLConnection) url.openConnection();
        httpConnection.setRequestProperty("Content-Type", "application/ocsp-request");
        httpConnection.setRequestProperty("Accept", "application/ocsp-response");
        httpConnection.setDoOutput(true);

        try (DataOutputStream dataOut = new DataOutputStream(
                new BufferedOutputStream(httpConnection.getOutputStream()))) {
            dataOut.write(encodedOcspRequest);
            dataOut.flush();
        }

        InputStream in = (InputStream) httpConnection.getContent();

        if (httpConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
            throw new OCSPValidationException(
                    "Received HTTP code != 200 [" + httpConnection.getResponseCode() + "]");
        }

        OCSPResp ocspResponse = new OCSPResp(in);
        BasicOCSPResp basicResponse = (BasicOCSPResp) ocspResponse.getResponseObject();

        byte[] receivedNonce = basicResponse.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce).getExtnId()
                .getEncoded();
        if (!Arrays.equals(receivedNonce, sentNonce)) {
            throw new OCSPValidationException("Nonce in ocsp response does not match nonce of ocsp request");
        }

        X509CertificateHolder certHolder = basicResponse.getCerts()[0];
        if (!basicResponse
                .isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("BC").build(issuer))) {
            if (!certHolder.isValidOn(Date.from(Instant.now()))) {
                throw new OCSPValidationException("Certificate is not valid today!");
            }
            // Certificate must have a Key Purpose ID for authorized responders
            if (!ExtendedKeyUsage.fromExtensions(certHolder.getExtensions())
                    .hasKeyPurposeId(KeyPurposeId.id_kp_OCSPSigning)) {
                throw new OCSPValidationException(
                        "Certificate does not contain required extension (id_kp_OCSPSigning)");
            }
            // Certificate must be issued by the same CA of the certificate that we are verifying
            if (!certHolder.isSignatureValid(
                    new JcaContentVerifierProviderBuilder().setProvider("BC").build(issuer))) {
                throw new OCSPValidationException("Certificate is not signed by the same issuer");
            }
            // Validate signature in OCSP response
            if (!basicResponse.isSignatureValid(
                    new JcaContentVerifierProviderBuilder().setProvider("BC").build(certHolder))) {
                throw new OCSPValidationException("Could not validate OCSP response!");
            }
        } else {
            if (!certHolder.isValidOn(Date.from(Instant.now()))) {
                throw new OCSPValidationException("Certificate is not valid today!");
            }
        }

        // SCEE Certificate Policy (?)
        /*if (null == certHolder.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nocheck) || null == certHolder.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nocheck).getExtnId()) {
        throw new OCSPValidationException("Extension id_pkix_ocsp_nocheck not found in certificate");
        }*/

        SingleResp[] responses = basicResponse.getResponses();
        if (responses[0].getCertID().getSerialNumber().equals(certificate.getSerialNumber())) {
            CertificateStatus status = responses[0].getCertStatus();
            if (status == CertificateStatus.GOOD) {
                return CertStatus.GOOD;
            } else {

                if (status instanceof RevokedStatus) {
                    revokedStatus = (RevokedStatus) status;
                    return CertStatus.REVOKED;
                } else {
                    return CertStatus.UNKNOWN;
                }
            }
        } else {
            throw new OCSPValidationException(
                    "Serial number of certificate in response ocsp does not match certificate serial number");
        }
    } catch (CertificateEncodingException | OperatorCreationException | OCSPException | IOException ex) {
        throw new OCSPValidationException("Unable to perform validation through OCSP ("
                + certificate.getSubjectX500Principal().getName() + ")", ex);
    } catch (CertException | CertificateException ex) {
        throw new OCSPValidationException("Unable to perform validation through OCSP ("
                + certificate.getSubjectX500Principal().getName() + ")", ex);
    }
}

From source file:org.cesecore.certificates.ocsp.OcspResponseInformation.java

License:Open Source License

public OcspResponseInformation(OCSPResp ocspResponse, long maxAge) throws OCSPException {
    try {/*from   ww  w  .java2  s . c  om*/
        this.ocspResponse = ocspResponse.getEncoded();
    } catch (IOException e) {
        throw new IllegalStateException("Unexpected IOException caught when encoding ocsp response.", e);
    }
    this.maxAge = maxAge;
    /*
     * This may seem like a somewhat odd place to perform the below operations (instead of in the end servlet which demanded 
     * this object), but BouncyCastle (up to 1.47) is  a bit shy about making their classes serializable. This means that 
     * OCSPResp can't be transmitted, neither can many of the objects it contains such as SingleResp. Luckily we only need 
     * these classes for the diagnostic operations performed below, so we can sum up the result in the boolean member 
     * addCacheHeaders.  If BC choose to change their policy, the below code can med moved to a more logical location. 
     *  -mikek
     */
    if (ocspResponse.getResponseObject() == null) {
        if (log.isDebugEnabled()) {
            log.debug("Will not add cache headers for response to bad request.");
        }
        addCacheHeaders = false;
    } else {
        final BasicOCSPResp basicOCSPResp = (BasicOCSPResp) ocspResponse.getResponseObject();
        final SingleResp[] singleRespones = basicOCSPResp.getResponses();
        if (singleRespones.length != 1) {
            if (log.isDebugEnabled()) {
                log.debug("Will not add RFC 5019 cache headers: reponse contains multiple embedded responses.");
            }
            addCacheHeaders = false;
        } else if (singleRespones[0].getNextUpdate() == null) {
            if (log.isDebugEnabled()) {
                log.debug("Will not add RFC 5019 cache headers: nextUpdate isn't set.");
            }
            addCacheHeaders = false;
        } else if (basicOCSPResp.hasExtensions()
                && basicOCSPResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce) != null) {
            if (log.isDebugEnabled()) {
                log.debug("Will not add RFC 5019 cache headers: response contains a nonce.");
            }
            addCacheHeaders = false;
        } else {
            nextUpdate = singleRespones[0].getNextUpdate().getTime();
            thisUpdate = singleRespones[0].getThisUpdate().getTime();
            try {
                responseHeader = new String(Hex.encode(MessageDigest
                        .getInstance("SHA-1", BouncyCastleProvider.PROVIDER_NAME).digest(this.ocspResponse)));
            } catch (NoSuchProviderException e) {
                throw new OcspFailureException("Bouncycastle was not available as a provider", e);
            } catch (NoSuchAlgorithmException e) {
                throw new OcspFailureException("SHA-1 was not an available algorithm for MessageDigester", e);
            }
        }
        if (addCacheHeaders && singleRespones[0].getCertStatus() instanceof UnknownStatus) {
            explicitNoCache = true;
        }
    }
}

From source file:org.cesecore.util.PKIXCertRevocationStatusChecker.java

License:Open Source License

/**
 * Sends an OCSP request, gets a response and verifies the response as much as possible before returning it to the caller.
 * //w w  w.  j  a v  a  2 s  .c om
 * @return The OCSP response, or null of no correct response could be obtained.
 */
private SingleResp getOCSPResponse(final String ocspurl, final OCSPReq ocspRequest, final Certificate cert,
        final byte[] nonce, int expectedOcspRespCode, int expectedHttpRespCode) {
    if (log.isDebugEnabled()) {
        log.debug("Sending OCSP request to " + ocspurl + " regarding certificate with SubjectDN: "
                + CertTools.getSubjectDN(cert) + " - IssuerDN: " + CertTools.getIssuerDN(cert));
    }

    //----------------------- Open connection and send the request --------------//
    OCSPResp response = null;
    HttpURLConnection con = null;
    try {
        final URL url = new URL(ocspurl);
        con = (HttpURLConnection) url.openConnection();
        // we are going to do a POST
        con.setDoOutput(true);
        con.setRequestMethod("POST");

        // POST it
        con.setRequestProperty("Content-Type", "application/ocsp-request");
        OutputStream os = con.getOutputStream();
        os.write(ocspRequest.getEncoded());
        os.close();

        final int httpRespCode = ((HttpURLConnection) con).getResponseCode();
        if (httpRespCode != expectedHttpRespCode) {
            log.info("HTTP response from OCSP request was " + httpRespCode + ". Expected "
                    + expectedHttpRespCode);
            handleContentOfErrorStream(con.getErrorStream());
            return null; // if it is an http error code we don't need to test any more
        }

        InputStream is = con.getInputStream();
        response = new OCSPResp(IOUtils.toByteArray(is));
        is.close();

    } catch (IOException e) {
        log.info("Unable to get an OCSP response. " + e.getLocalizedMessage());
        if (con != null) {
            handleContentOfErrorStream(con.getErrorStream());
        }
        return null;
    }

    // ------------ Verify the response signature --------------//
    BasicOCSPResp brep = null;
    try {
        brep = (BasicOCSPResp) response.getResponseObject();

        if ((expectedOcspRespCode != OCSPRespBuilder.SUCCESSFUL) && (brep != null)) {
            log.warn("According to RFC 2560, responseBytes are not set on error, but we got some.");
            return null; // it messes up testing of invalid signatures... but is needed for the unsuccessful responses
        }

        if (brep == null) {
            log.warn("Cannot extract OCSP response object. OCSP response status: " + response.getStatus());
            return null;
        }

        X509CertificateHolder[] chain = brep.getCerts();
        boolean verify = brep.isSignatureValid(new JcaContentVerifierProviderBuilder()
                .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(chain[0]));
        if (!verify) {
            log.warn("OCSP response signature was not valid");
            return null;
        }
    } catch (OCSPException | OperatorCreationException | CertificateException e) {
        if (log.isDebugEnabled()) {
            log.debug("Failed to obtain or verify OCSP response. " + e.getLocalizedMessage());
        }
        return null;
    }

    // ------------- Verify the nonce ---------------//
    byte[] noncerep;
    try {
        noncerep = brep.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce).getExtnValue().getEncoded();
    } catch (IOException e) {
        if (log.isDebugEnabled()) {
            log.debug("Failed to read extension from OCSP response. " + e.getLocalizedMessage());
        }
        return null;
    }
    if (noncerep == null) {
        log.warn("Sent an OCSP request containing a nonce, but the OCSP response does not contain a nonce");
        return null;
    }

    try {
        ASN1InputStream ain = new ASN1InputStream(noncerep);
        ASN1OctetString oct = ASN1OctetString.getInstance(ain.readObject());
        ain.close();
        if (!Arrays.equals(nonce, oct.getOctets())) {
            log.warn("The nonce in the OCSP request and the OCSP response do not match");
            return null;
        }
    } catch (IOException e) {
        if (log.isDebugEnabled()) {
            log.debug("Failed to read extension from OCSP response. " + e.getLocalizedMessage());
        }
        return null;
    }

    // ------------ Extract the single response and verify that it concerns a cert with the right serialnumber ----//
    SingleResp[] singleResps = brep.getResponses();
    if ((singleResps == null) || (singleResps.length == 0)) {
        if (log.isDebugEnabled()) {
            log.debug("The OCSP response object contained no responses.");
        }
        return null;
    }

    SingleResp singleResponse = singleResps[0];
    CertificateID certId = singleResponse.getCertID();
    if (!certId.getSerialNumber().equals(CertTools.getSerialNumber(cert))) {
        if (log.isDebugEnabled()) {
            log.debug(
                    "Certificate serialnumber in response does not match certificate serialnumber in request.");
        }
        return null;
    }

    // ------------ Return the single response ---------------//
    return singleResponse;
}

From source file:org.digidoc4j.impl.bdoc.OcspNonceValidator.java

License:GNU General Public License

private boolean isOcspResponseValid(BasicOCSPResp latestOcspResponse) {
    Extension extension = latestOcspResponse.getExtension(new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.2"));
    if (extension == null) {
        logger.error("No valid OCSP extension found in signature: " + signature.getId());
        return false;
    }//from w  w  w.j  a va  2 s  .c om
    return isOcspExtensionValid(extension);
}

From source file:org.ejbca.core.protocol.ocsp.OcspJunitHelper.java

License:Open Source License

/**
 *
 * @param ocspPackage/*  w  ww  . j  a va2  s  .  c  o  m*/
 * @param nonce
 * @param respCode expected response code, OK = 0, if not 0, response checking will not continue after response code is checked.
 * @param httpCode, normally 200 for OK or OCSP error. Can be 400 is more than 1 million bytes is sent for example
 * @return a SingleResp or null if respCode != 0
 * @throws IOException
 * @throws OCSPException
 * @throws NoSuchProviderException
 * @throws CertificateException on parsing errors.
 * @throws OperatorCreationException 
 */
protected SingleResp[] sendOCSPPost(byte[] ocspPackage, String nonce, int respCode, int httpCode)
        throws IOException, OCSPException, NoSuchProviderException, OperatorCreationException,
        CertificateException {
    // POST the OCSP request
    URL url = new URL(this.sBaseURL + this.urlEnding);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    // we are going to do a POST
    con.setDoOutput(true);
    con.setRequestMethod("POST");

    // POST it
    con.setRequestProperty("Content-Type", "application/ocsp-request");
    OutputStream os = con.getOutputStream();
    os.write(ocspPackage);
    os.close();
    assertEquals("Response code", httpCode, con.getResponseCode());
    if (con.getResponseCode() != 200) {
        return null; // if it is an http error code we don't need to test any more
    }
    // Some appserver (Weblogic) responds with "application/ocsp-response; charset=UTF-8"
    assertNotNull("No Content-Type in reply.", con.getContentType());
    assertTrue(con.getContentType().startsWith("application/ocsp-response"));
    OCSPResp response = new OCSPResp(IOUtils.toByteArray(con.getInputStream()));
    assertEquals("Response status not the expected.", respCode, response.getStatus());
    if (respCode != 0) {
        assertNull("According to RFC 2560, responseBytes are not set on error.", response.getResponseObject());
        return null; // it messes up testing of invalid signatures... but is needed for the unsuccessful responses
    }
    BasicOCSPResp brep = (BasicOCSPResp) response.getResponseObject();
    X509CertificateHolder[] chain = brep.getCerts();
    assertNotNull(
            "No certificate chain returned in response (chain == null), is ocsp.includesignercert=false in ocsp.properties?. It should be set to default value for test to run.",
            chain);
    boolean verify = brep.isSignatureValid(new JcaContentVerifierProviderBuilder().build(chain[0]));
    assertTrue("Response failed to verify.", verify);
    // Check nonce (if we sent one)
    if (nonce != null) {
        byte[] noncerep = brep.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce).getExtnValue()
                .getEncoded();
        assertNotNull(noncerep);
        ASN1InputStream ain = new ASN1InputStream(noncerep);
        ASN1OctetString oct = ASN1OctetString.getInstance(ain.readObject());
        ain.close();
        assertEquals(nonce, new String(oct.getOctets()));
    }
    SingleResp[] singleResps = brep.getResponses();
    return singleResps;
}

From source file:org.ejbca.core.protocol.ocsp.OcspJunitHelper.java

License:Open Source License

/**
 *
 * @param ocspPackage//  ww w . j av  a2 s.co  m
 * @param nonce
 * @param respCode expected response code, OK = 0, if not 0, response checking will not continue after response code is checked.
 * @param httpCode, normally 200 for OK or OCSP error. Can be 400 is more than 1 million bytes is sent for example
 * @return a BasicOCSPResp or null if not found
 * @throws IOException
 * @throws OCSPException
 * @throws NoSuchProviderException
 * @throws NoSuchAlgorithmException
 * @throws CertificateException on parsing errors.
 * @throws OperatorCreationException 
 */
protected BasicOCSPResp sendOCSPGet(byte[] ocspPackage, String nonce, int respCode, int httpCode,
        boolean shouldIncludeSignCert, X509Certificate signCert) throws IOException, OCSPException,
        NoSuchProviderException, NoSuchAlgorithmException, OperatorCreationException, CertificateException {
    // GET the OCSP request
    String b64 = new String(Base64.encode(ocspPackage, false));
    //String urls = URLEncoder.encode(b64, "UTF-8");   // JBoss/Tomcat will not accept escaped '/'-characters by default
    URL url = new URL(this.sBaseURL + '/' + b64 + this.urlEnding);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    if (con.getResponseCode() != httpCode) {
        log.info("URL when request gave unexpected result: " + url.toString() + " Message was: "
                + con.getResponseMessage());
    }
    assertEquals("Response code did not match. ", httpCode, con.getResponseCode());
    if (con.getResponseCode() != 200) {
        return null; // if it is an http error code we don't need to test any more
    }
    // Some appserver (Weblogic) responds with "application/ocsp-response; charset=UTF-8"
    assertNotNull(con.getContentType());
    assertTrue(con.getContentType().startsWith("application/ocsp-response"));
    OCSPResp response = new OCSPResp(IOUtils.toByteArray(con.getInputStream()));
    assertNotNull("Response should not be null.", response);
    assertEquals("Response status not the expected.", respCode, response.getStatus());
    if (respCode != 0) {
        assertNull("According to RFC 2560, responseBytes are not set on error.", response.getResponseObject());
        return null; // it messes up testing of invalid signatures... but is needed for the unsuccessful responses
    }
    BasicOCSPResp brep = (BasicOCSPResp) response.getResponseObject();

    final X509CertificateHolder signCertHolder;
    if (!shouldIncludeSignCert) {
        assertEquals("The signing certificate should not be included in the OCSP response ", 0,
                brep.getCerts().length);
        signCertHolder = new JcaX509CertificateHolder(signCert);
    } else {
        X509CertificateHolder[] chain = brep.getCerts();
        signCertHolder = chain[0];
    }
    boolean verify = brep.isSignatureValid(new JcaContentVerifierProviderBuilder().build(signCertHolder));

    assertTrue("Response failed to verify.", verify);
    // Check nonce (if we sent one)
    if (nonce != null) {
        byte[] noncerep = brep.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce).getExtnValue()
                .getEncoded();
        assertNotNull(noncerep);
        ASN1InputStream ain = new ASN1InputStream(noncerep);
        ASN1OctetString oct = ASN1OctetString.getInstance(ain.readObject());
        ain.close();
        assertEquals(nonce, new String(oct.getOctets()));
    }
    return brep;
}

From source file:org.ejbca.core.protocol.ocsp.OCSPUnidClient.java

License:Open Source License

private OCSPUnidResponse sendOCSPRequest(byte[] ocspPackage, X509Certificate knownTrustAnchor, boolean useGet)
        throws IOException, OCSPException, OperatorCreationException, CertificateException,
        UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
    final HttpURLConnection con;
    if (useGet) {
        String b64 = new String(Base64.encode(ocspPackage, false));
        URL url = new URL(httpReqPath + '/' + b64);
        con = (HttpURLConnection) url.openConnection();
    } else {/*from ww w  .j  a va 2s.c o  m*/
        // POST the OCSP request
        URL url = new URL(httpReqPath);
        con = (HttpURLConnection) getUrlConnection(url);
        // we are going to do a POST
        con.setDoOutput(true);
        con.setRequestMethod("POST");
        // POST it
        con.setRequestProperty("Content-Type", "application/ocsp-request");
        OutputStream os = null;
        try {
            os = con.getOutputStream();
            os.write(ocspPackage);
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }
    final OCSPUnidResponse ret = new OCSPUnidResponse();
    ret.setHttpReturnCode(con.getResponseCode());
    if (ret.getHttpReturnCode() != 200) {
        if (ret.getHttpReturnCode() == 401) {
            ret.setErrorCode(OCSPUnidResponse.ERROR_UNAUTHORIZED);
        } else {
            ret.setErrorCode(OCSPUnidResponse.ERROR_UNKNOWN);
        }
        return ret;
    }
    final OCSPResp response;
    {
        final InputStream in = con.getInputStream();
        if (in != null) {
            try {
                response = new OCSPResp(IOUtils.toByteArray(in));
            } finally {
                in.close();
            }
        } else {
            response = null;
        }
    }
    if (response == null) {
        ret.setErrorCode(OCSPUnidResponse.ERROR_NO_RESPONSE);
        return ret;
    }
    ret.setResp(response);
    final BasicOCSPResp brep = (BasicOCSPResp) response.getResponseObject();
    if (brep == null) {
        ret.setErrorCode(OCSPUnidResponse.ERROR_NO_RESPONSE);
        return ret;
    }
    // Compare nonces to see if the server sent the same nonce as we sent
    final byte[] noncerep = brep.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce).getExtnValue()
            .getEncoded();
    if (noncerep != null) {
        ASN1InputStream ain = new ASN1InputStream(noncerep);
        ASN1OctetString oct = ASN1OctetString.getInstance(ain.readObject());
        ain.close();
        boolean eq = ArrayUtils.isEquals(this.nonce, oct.getOctets());
        if (!eq) {
            ret.setErrorCode(OCSPUnidResponse.ERROR_INVALID_NONCE);
            return ret;
        }
    }

    final RespID id = brep.getResponderId();
    final DERTaggedObject to = (DERTaggedObject) id.toASN1Object().toASN1Primitive();
    final RespID respId;
    final X509CertificateHolder[] chain = brep.getCerts();
    JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
    X509Certificate signerCertificate = converter.getCertificate(chain[0]);
    final PublicKey signerPub = signerCertificate.getPublicKey();
    if (to.getTagNo() == 1) {
        // This is Name
        respId = new JcaRespID(signerCertificate.getSubjectX500Principal());
    } else {
        // This is KeyHash
        respId = new JcaRespID(signerPub, SHA1DigestCalculator.buildSha1Instance());
    }
    if (!id.equals(respId)) {
        // Response responderId does not match signer certificate responderId!
        ret.setErrorCode(OCSPUnidResponse.ERROR_INVALID_SIGNERID);
    }
    if (!brep.isSignatureValid(new JcaContentVerifierProviderBuilder().build(signerPub))) {
        ret.setErrorCode(OCSPUnidResponse.ERROR_INVALID_SIGNATURE);
        return ret;
    }

    /* 
     * Okay, at this point we have three different variables and six different possible valid use cases. These
     * variables are:
     *          1. If the OCSP reply is from a CA (integrated) or an OCSP responder (standalone) 
     *          2. If it was from a CA, then if that CA is self signed or a subCA
     *          3. If the server (in the integrated case) or keybinding (standalone case) was set to include the certificate chain
     */

    //If we have a chain, verify it
    if (chain.length > 1) {
        // end at one shortof chain.length, because the root certificate is (usually) not included in the OCSP response
        // TODO: improve this when we can pass in the root cert from parameter to properly validate the whole chain
        for (int i = 0; i + 1 < chain.length; i++) {
            final X509Certificate cert1 = converter.getCertificate(chain[i]);
            final X509Certificate cert2 = converter.getCertificate(chain[Math.min(i + 1, chain.length - 1)]);
            try {
                cert1.verify(cert2.getPublicKey());
            } catch (GeneralSecurityException e) {
                m_log.info("Verifying problem with", e);
                m_log.info("Certificate to be verified: " + cert1);
                m_log.info("Verifying certificate: " + cert2);
                ret.setErrorCode(OCSPUnidResponse.ERROR_INVALID_SIGNERCERT);
                return ret;
            }
        }
    }

    if (CertTools.isCA(signerCertificate)) {
        //Verify that the signer certificate was the same as the trust anchor
        if (!signerCertificate.getSerialNumber().equals(knownTrustAnchor.getSerialNumber())) {
            m_log.info("Signing certificate for integrated OCSP was not the provided trust anchor.");
            ret.setErrorCode(OCSPUnidResponse.ERROR_INVALID_SIGNERCERT);
            return ret;
        }
    } else if (CertTools.isOCSPCert(signerCertificate)) {
        //If an OCSP certificate was used to sign
        try {
            signerCertificate.verify(knownTrustAnchor.getPublicKey());
        } catch (GeneralSecurityException e) {
            m_log.info("Signing certificate was not signed by known trust anchor.");
            ret.setErrorCode(OCSPUnidResponse.ERROR_INVALID_SIGNERCERT);
            return ret;
        }
    } else {
        m_log.info("Signing certificate was not an OCSP certificate.");
        ret.setErrorCode(OCSPUnidResponse.ERROR_INVALID_SIGNERCERT);
        return ret;
    }

    String fnr = getFnr(brep);
    if (fnr != null) {
        ret.setFnr(fnr);
    }
    return ret;
}