/** * Gets OCSP responses from the Document Security Store. * * @return a list of BasicOCSPResp objects * @throws IOException * @throws GeneralSecurityException */ public List<BasicOCSPResp> getOCSPResponsesFromDSS() throws IOException, GeneralSecurityException { List<BasicOCSPResp> ocsps = new ArrayList<BasicOCSPResp>(); if (dss == null) return ocsps; PdfArray ocsparray = dss.getAsArray(PdfName.OCSPS); if (ocsparray == null) return ocsps; for (int i = 0; i < ocsparray.size(); i++) { PRStream stream = (PRStream) ocsparray.getAsStream(i); OCSPResp ocspResponse = new OCSPResp(PdfReader.getStreamBytes(stream)); if (ocspResponse.getStatus() == 0) try { ocsps.add((BasicOCSPResp) ocspResponse.getResponseObject()); } catch (OCSPException e) { throw new GeneralSecurityException(e); } } return ocsps; }
/** * This method returns the {@code BasicOCSPResp} from a {@code OCSPResp}. * * @param ocspResp {@code OCSPResp} to analysed * @return */ public static BasicOCSPResp getBasicOCSPResp(final OCSPResp ocspResp) { BasicOCSPResp basicOCSPResp = null; try { final Object responseObject = ocspResp.getResponseObject(); if (responseObject instanceof BasicOCSPResp) { basicOCSPResp = (BasicOCSPResp) responseObject; } else { LOG.warn("Unknown OCSP response type: {}", responseObject.getClass()); } } catch (OCSPException e) { LOG.error("Impossible to process OCSPResp!", e); } return basicOCSPResp; }
public void performTest() throws Exception { String signDN = "O=Bouncy Castle, C=AU"; KeyPair signKP = OCSPTestUtil.makeKeyPair(); X509CertificateHolder testCert = new JcaX509CertificateHolder(OCSPTestUtil.makeCertificate(signKP, signDN, signKP, signDN)); String origDN = "CN=Eric H. Echidna, [email protected], O=Bouncy Castle, C=AU"; GeneralName origName = new GeneralName(new X509Name(origDN)); DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(); // // general id value for our test issuer cert and a serial number. // CertificateID id = new CertificateID( digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)); // // basic request generation // OCSPReqBuilder gen = new OCSPReqBuilder(); gen.addRequest( new CertificateID( digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1))); OCSPReq req = gen.build(); if (req.isSigned()) { fail("signed but shouldn't be"); } X509CertificateHolder[] certs = req.getCerts(); if (certs.length != 0) { fail("0 certs expected, but not found"); } Req[] requests = req.getRequestList(); if (!requests[0].getCertID().equals(id)) { fail("Failed isFor test"); } // // request generation with signing // X509CertificateHolder[] chain = new X509CertificateHolder[1]; gen = new OCSPReqBuilder(); gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred"))); gen.addRequest( new CertificateID( digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1))); chain[0] = testCert; req = gen.build( new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate()), chain); if (!req.isSigned()) { fail("not signed but should be"); } if (!req.isSignatureValid( new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic()))) { fail("signature failed to verify"); } requests = req.getRequestList(); if (!requests[0].getCertID().equals(id)) { fail("Failed isFor test"); } certs = req.getCerts(); if (certs == null) { fail("null certs found"); } if (certs.length != 1 || !certs[0].equals(testCert)) { fail("incorrect certs found in request"); } // // encoding test // byte[] reqEnc = req.getEncoded(); OCSPReq newReq = new OCSPReq(reqEnc); if (!newReq.isSignatureValid( new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic()))) { fail("newReq signature failed to verify"); } // // request generation with signing and nonce // chain = new X509CertificateHolder[1]; gen = new OCSPReqBuilder(); Vector oids = new Vector(); Vector values = new Vector(); byte[] sampleNonce = new byte[16]; Random rand = new Random(); rand.nextBytes(sampleNonce); gen.setRequestorName(new GeneralName(GeneralName.directoryName, new X509Principal("CN=fred"))); oids.addElement(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); values.addElement( new X509Extension(false, new DEROctetString(new DEROctetString(sampleNonce)))); gen.setRequestExtensions(new X509Extensions(oids, values)); gen.addRequest( new CertificateID( digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1))); chain[0] = testCert; req = gen.build( new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(signKP.getPrivate()), chain); if (!req.isSigned()) { fail("not signed but should be"); } if (!req.isSignatureValid( new JcaContentVerifierProviderBuilder().setProvider(BC).build(signKP.getPublic()))) { fail("signature failed to verify"); } // // extension check. // Set extOids = req.getCriticalExtensionOIDs(); if (extOids.size() != 0) { fail("wrong number of critical extensions in OCSP request."); } extOids = req.getNonCriticalExtensionOIDs(); if (extOids.size() != 1) { fail("wrong number of non-critical extensions in OCSP request."); } X509Extension ext = req.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); ASN1Encodable extObj = ext.getParsedValue(); if (!(extObj instanceof ASN1OctetString)) { fail("wrong extension type found."); } if (!areEqual(((ASN1OctetString) extObj).getOctets(), sampleNonce)) { fail("wrong extension value found."); } // // request list check // requests = req.getRequestList(); if (!requests[0].getCertID().equals(id)) { fail("Failed isFor test"); } // // response parsing - test 1 // OCSPResp response = new OCSPResp(testResp1); if (response.getStatus() != 0) { fail("response status not zero."); } BasicOCSPResp brep = (BasicOCSPResp) response.getResponseObject(); chain = brep.getCerts(); if (!brep.isSignatureValid( new JcaContentVerifierProviderBuilder().setProvider(BC).build(chain[0]))) { fail("response 1 failed to verify."); } // // test 2 // SingleResp[] singleResp = brep.getResponses(); response = new OCSPResp(testResp2); if (response.getStatus() != 0) { fail("response status not zero."); } brep = (BasicOCSPResp) response.getResponseObject(); chain = brep.getCerts(); if (!brep.isSignatureValid( new JcaContentVerifierProviderBuilder().setProvider(BC).build(chain[0]))) { fail("response 2 failed to verify."); } singleResp = brep.getResponses(); // // simple response generation // OCSPRespBuilder respGen = new OCSPRespBuilder(); OCSPResp resp = respGen.build(OCSPRespBuilder.SUCCESSFUL, response.getResponseObject()); if (!resp.getResponseObject().equals(response.getResponseObject())) { fail("response fails to match"); } testECDSA(); testRSA(); testIrregularVersionReq(); }
private void processRequest( final HttpServletRequest request, final HttpServletResponse response, final ResponderAndRelativeUri r, final boolean getMethod) throws ServletException, IOException { Responder responder = r.getResponder(); AuditEvent auditEvent = null; AuditLevel auditLevel = AuditLevel.INFO; AuditStatus auditStatus = AuditStatus.SUCCESSFUL; String auditMessage = null; long start = 0; AuditService auditService = (auditServiceRegister == null) ? null : auditServiceRegister.getAuditService(); if (auditService != null && responder.getAuditOption() != null) { start = System.currentTimeMillis(); auditEvent = new AuditEvent(new Date()); auditEvent.setApplicationName("OCSP"); auditEvent.setName("PERF"); } try { if (server == null) { String message = "responder in servlet not configured"; LOG.error(message); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentLength(0); auditLevel = AuditLevel.ERROR; auditStatus = AuditStatus.FAILED; auditMessage = message; return; } InputStream requestStream; if (getMethod) { String relativeUri = r.getRelativeUri(); // RFC2560 A.1.1 specifies that request longer than 255 bytes SHOULD be sent by // POST, we support GET for longer requests anyway. if (relativeUri.length() > responder.getRequestOption().getMaxRequestSize()) { response.setContentLength(0); response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE); auditStatus = AuditStatus.FAILED; auditMessage = "request too large"; return; } requestStream = new ByteArrayInputStream(Base64.decode(relativeUri)); } else { // accept only "application/ocsp-request" as content type if (!CT_REQUEST.equalsIgnoreCase(request.getContentType())) { response.setContentLength(0); response.setStatus(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); auditStatus = AuditStatus.FAILED; auditMessage = "unsupporte media type " + request.getContentType(); return; } // request too long if (request.getContentLength() > responder.getRequestOption().getMaxRequestSize()) { response.setContentLength(0); response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE); auditStatus = AuditStatus.FAILED; auditMessage = "request too large"; return; } // if (CT_REQUEST) requestStream = request.getInputStream(); } // end if (getMethod) OCSPRequest ocspRequest; try { ASN1StreamParser parser = new ASN1StreamParser(requestStream); ocspRequest = OCSPRequest.getInstance(parser.readObject()); } catch (Exception e) { response.setContentLength(0); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); auditStatus = AuditStatus.FAILED; auditMessage = "bad request"; final String message = "could not parse the request (OCSPRequest)"; if (LOG.isErrorEnabled()) { LOG.error( LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage()); } LOG.debug(message, e); return; } OCSPReq ocspReq = new OCSPReq(ocspRequest); response.setContentType(HttpOcspServlet.CT_RESPONSE); OcspRespWithCacheInfo ocspRespWithCacheInfo = server.answer(responder, ocspReq, auditEvent, getMethod); if (ocspRespWithCacheInfo == null) { auditMessage = "processRequest returned null, this should not happen"; LOG.error(auditMessage); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentLength(0); auditLevel = AuditLevel.ERROR; auditStatus = AuditStatus.FAILED; } else { OCSPResp resp = ocspRespWithCacheInfo.getResponse(); byte[] encodedOcspResp = null; response.setStatus(HttpServletResponse.SC_OK); ResponseCacheInfo cacheInfo = ocspRespWithCacheInfo.getCacheInfo(); if (getMethod && cacheInfo != null) { encodedOcspResp = resp.getEncoded(); long now = System.currentTimeMillis(); // RFC 5019 6.2: Date: The date and time at which the OCSP server generated // the HTTP response. response.setDateHeader("Date", now); // RFC 5019 6.2: Last-Modified: date and time at which the OCSP responder // last modified the response. response.setDateHeader("Last-Modified", cacheInfo.getThisUpdate()); // RFC 5019 6.2: Expires: This date and time will be the same as the // nextUpdate time-stamp in the OCSP // response itself. // This is overridden by max-age on HTTP/1.1 compatible components if (cacheInfo.getNextUpdate() != null) { response.setDateHeader("Expires", cacheInfo.getNextUpdate()); } // RFC 5019 6.2: This profile RECOMMENDS that the ETag value be the ASCII // HEX representation of the SHA1 hash of the OCSPResponse structure. response.setHeader( "ETag", new StringBuilder(42) .append('\\') .append(HashCalculator.hexSha1(encodedOcspResp)) .append('\\') .toString()); // Max age must be in seconds in the cache-control header long maxAge; if (responder.getResponseOption().getCacheMaxAge() != null) { maxAge = responder.getResponseOption().getCacheMaxAge().longValue(); } else { maxAge = OcspServer.defaultCacheMaxAge; } if (cacheInfo.getNextUpdate() != null) { maxAge = Math.min(maxAge, (cacheInfo.getNextUpdate() - cacheInfo.getThisUpdate()) / 1000); } response.setHeader( "Cache-Control", new StringBuilder(55) .append("max-age=") .append(maxAge) .append(",public,no-transform,must-revalidate") .toString()); } // end if (getMethod && cacheInfo != null) if (encodedOcspResp != null) { response.getOutputStream().write(encodedOcspResp); } else { ASN1OutputStream asn1Out = new ASN1OutputStream(response.getOutputStream()); asn1Out.writeObject(resp.toASN1Structure()); asn1Out.flush(); } } // end if (ocspRespWithCacheInfo) } catch (EOFException e) { final String message = "Connection reset by peer"; if (LOG.isErrorEnabled()) { LOG.warn(LogUtil.buildExceptionLogFormat(message), e.getClass().getName(), e.getMessage()); } LOG.debug(message, e); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentLength(0); } catch (Throwable t) { final String message = "Throwable thrown, this should not happen!"; LOG.error(message, t); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.setContentLength(0); auditLevel = AuditLevel.ERROR; auditStatus = AuditStatus.FAILED; auditMessage = "internal error"; } finally { try { response.flushBuffer(); } finally { if (auditEvent != null) { if (auditLevel != null) { auditEvent.setLevel(auditLevel); } if (auditStatus != null) { auditEvent.setStatus(auditStatus); } if (auditMessage != null) { auditEvent.addEventData(new AuditEventData("message", auditMessage)); } auditEvent.setDuration(System.currentTimeMillis() - start); if (!auditEvent.containsChildAuditEvents()) { auditService.logEvent(auditEvent); } else { List<AuditEvent> expandedAuditEvents = auditEvent.expandAuditEvents(); for (AuditEvent event : expandedAuditEvents) { auditService.logEvent(event); } } } // end if (auditEvent != null) } // end inner try } // end external try } // method processRequest