List of usage examples for org.bouncycastle.cert.ocsp OCSPRespBuilder MALFORMED_REQUEST
int MALFORMED_REQUEST
To view the source code for org.bouncycastle.cert.ocsp OCSPRespBuilder MALFORMED_REQUEST.
Click Source Link
From source file:org.apache.nifi.web.security.x509.ocsp.OcspCertificateValidator.java
License:Apache License
/** * Gets the OCSP status for the specified subject and issuer certificates. * * @param ocspStatusKey status key// w w w. j av a 2 s .c om * @return ocsp status */ private OcspStatus getOcspStatus(final OcspRequest ocspStatusKey) { final X509Certificate subjectCertificate = ocspStatusKey.getSubjectCertificate(); final X509Certificate issuerCertificate = ocspStatusKey.getIssuerCertificate(); // initialize the default status final OcspStatus ocspStatus = new OcspStatus(); ocspStatus.setVerificationStatus(VerificationStatus.Unknown); ocspStatus.setValidationStatus(ValidationStatus.Unknown); try { // prepare the request final BigInteger subjectSerialNumber = subjectCertificate.getSerialNumber(); final DigestCalculatorProvider calculatorProviderBuilder = new JcaDigestCalculatorProviderBuilder() .setProvider("BC").build(); final CertificateID certificateId = new CertificateID( calculatorProviderBuilder.get(CertificateID.HASH_SHA1), new X509CertificateHolder(issuerCertificate.getEncoded()), subjectSerialNumber); // generate the request final OCSPReqBuilder requestGenerator = new OCSPReqBuilder(); requestGenerator.addRequest(certificateId); // Create a nonce to avoid replay attack BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis()); Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, new DEROctetString(nonce.toByteArray())); requestGenerator.setRequestExtensions(new Extensions(new Extension[] { ext })); final OCSPReq ocspRequest = requestGenerator.build(); // perform the request final Response response = getClientResponse(ocspRequest); // ensure the request was completed successfully if (Response.Status.OK.getStatusCode() != response.getStatusInfo().getStatusCode()) { logger.warn(String.format("OCSP request was unsuccessful (%s).", response.getStatus())); return ocspStatus; } // interpret the response OCSPResp ocspResponse = new OCSPResp(response.readEntity(InputStream.class)); // verify the response status switch (ocspResponse.getStatus()) { case OCSPRespBuilder.SUCCESSFUL: ocspStatus.setResponseStatus(OcspStatus.ResponseStatus.Successful); break; case OCSPRespBuilder.INTERNAL_ERROR: ocspStatus.setResponseStatus(OcspStatus.ResponseStatus.InternalError); break; case OCSPRespBuilder.MALFORMED_REQUEST: ocspStatus.setResponseStatus(OcspStatus.ResponseStatus.MalformedRequest); break; case OCSPRespBuilder.SIG_REQUIRED: ocspStatus.setResponseStatus(OcspStatus.ResponseStatus.SignatureRequired); break; case OCSPRespBuilder.TRY_LATER: ocspStatus.setResponseStatus(OcspStatus.ResponseStatus.TryLater); break; case OCSPRespBuilder.UNAUTHORIZED: ocspStatus.setResponseStatus(OcspStatus.ResponseStatus.Unauthorized); break; default: ocspStatus.setResponseStatus(OcspStatus.ResponseStatus.Unknown); break; } // only proceed if the response was successful if (ocspResponse.getStatus() != OCSPRespBuilder.SUCCESSFUL) { logger.warn(String.format("OCSP request was unsuccessful (%s).", ocspStatus.getResponseStatus().toString())); return ocspStatus; } // ensure the appropriate response object final Object ocspResponseObject = ocspResponse.getResponseObject(); if (ocspResponseObject == null || !(ocspResponseObject instanceof BasicOCSPResp)) { logger.warn(String.format("Unexpected OCSP response object: %s", ocspResponseObject)); return ocspStatus; } // get the response object final BasicOCSPResp basicOcspResponse = (BasicOCSPResp) ocspResponse.getResponseObject(); // attempt to locate the responder certificate final X509CertificateHolder[] responderCertificates = basicOcspResponse.getCerts(); if (responderCertificates.length != 1) { logger.warn(String.format("Unexpected number of OCSP responder certificates: %s", responderCertificates.length)); return ocspStatus; } // get the responder certificate final X509Certificate trustedResponderCertificate = getTrustedResponderCertificate( responderCertificates[0], issuerCertificate); if (trustedResponderCertificate != null) { // verify the response if (basicOcspResponse.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("BC") .build(trustedResponderCertificate.getPublicKey()))) { ocspStatus.setVerificationStatus(VerificationStatus.Verified); } else { ocspStatus.setVerificationStatus(VerificationStatus.Unverified); } } else { ocspStatus.setVerificationStatus(VerificationStatus.Unverified); } // validate the response final SingleResp[] responses = basicOcspResponse.getResponses(); for (SingleResp singleResponse : responses) { final CertificateID responseCertificateId = singleResponse.getCertID(); final BigInteger responseSerialNumber = responseCertificateId.getSerialNumber(); if (responseSerialNumber.equals(subjectSerialNumber)) { Object certStatus = singleResponse.getCertStatus(); // interpret the certificate status if (CertificateStatus.GOOD == certStatus) { ocspStatus.setValidationStatus(ValidationStatus.Good); } else if (certStatus instanceof RevokedStatus) { ocspStatus.setValidationStatus(ValidationStatus.Revoked); } else { ocspStatus.setValidationStatus(ValidationStatus.Unknown); } } } } catch (final OCSPException | IOException | ProcessingException | OperatorCreationException e) { logger.error(e.getMessage(), e); } catch (CertificateException e) { e.printStackTrace(); } return ocspStatus; }
From source file:org.cesecore.certificates.ocsp.OcspResponseGeneratorSessionBean.java
License:Open Source License
@Override public OcspResponseInformation getOcspResponse(final byte[] request, final X509Certificate[] requestCertificates, String remoteAddress, String remoteHost, StringBuffer requestUrl, final AuditLogger auditLogger, final TransactionLogger transactionLogger) throws MalformedRequestException, OCSPException { //Check parameters if (auditLogger == null) { throw new InvalidParameterException( "Illegal to pass a null audit logger to OcspResponseSession.getOcspResponse"); }//from www. j a va2 s. c o m if (transactionLogger == null) { throw new InvalidParameterException( "Illegal to pass a null transaction logger to OcspResponseSession.getOcspResponse"); } // Validate byte array. if (request.length > MAX_REQUEST_SIZE) { final String msg = intres.getLocalizedMessage("request.toolarge", MAX_REQUEST_SIZE, request.length); throw new MalformedRequestException(msg); } byte[] respBytes = null; final Date startTime = new Date(); OCSPResp ocspResponse = null; // Start logging process time after we have received the request if (transactionLogger.isEnabled()) { transactionLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); } if (auditLogger.isEnabled()) { auditLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); auditLogger.paramPut(AuditLogger.OCSPREQUEST, new String(Hex.encode(request))); } OCSPReq req; long maxAge = OcspConfiguration.getMaxAge(CertificateProfileConstants.CERTPROFILE_NO_PROFILE); OCSPRespBuilder responseGenerator = new OCSPRespBuilder(); try { req = translateRequestFromByteArray(request, remoteAddress, transactionLogger); // Get the certificate status requests that are inside this OCSP req Req[] ocspRequests = req.getRequestList(); if (ocspRequests.length <= 0) { String infoMsg = intres.getLocalizedMessage("ocsp.errornoreqentities"); log.info(infoMsg); throw new MalformedRequestException(infoMsg); } final int maxRequests = 100; if (ocspRequests.length > maxRequests) { String infoMsg = intres.getLocalizedMessage("ocsp.errortoomanyreqentities", maxRequests); log.info(infoMsg); throw new MalformedRequestException(infoMsg); } if (log.isDebugEnabled()) { log.debug("The OCSP request contains " + ocspRequests.length + " simpleRequests."); } if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.NUM_CERT_ID, ocspRequests.length); transactionLogger.paramPut(TransactionLogger.STATUS, OCSPRespBuilder.SUCCESSFUL); } if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.STATUS, OCSPRespBuilder.SUCCESSFUL); } OcspSigningCacheEntry ocspSigningCacheEntry = null; long nextUpdate = OcspConfiguration .getUntilNextUpdate(CertificateProfileConstants.CERTPROFILE_NO_PROFILE); // Add standard response extensions Map<ASN1ObjectIdentifier, Extension> responseExtensions = getStandardResponseExtensions(req); // Look for extension OIDs final Collection<String> extensionOids = OcspConfiguration.getExtensionOids(); // Look over the status requests List<OCSPResponseItem> responseList = new ArrayList<OCSPResponseItem>(); boolean addExtendedRevokedExtension = false; Date producedAt = null; for (Req ocspRequest : ocspRequests) { CertificateID certId = ocspRequest.getCertID(); ASN1ObjectIdentifier certIdhash = certId.getHashAlgOID(); if (!OIWObjectIdentifiers.idSHA1.equals(certIdhash) && !NISTObjectIdentifiers.id_sha256.equals(certIdhash)) { throw new InvalidAlgorithmException( "CertID with SHA1 and SHA256 are supported, not: " + certIdhash.getId()); } if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.SERIAL_NOHEX, certId.getSerialNumber().toByteArray()); transactionLogger.paramPut(TransactionLogger.DIGEST_ALGOR, certId.getHashAlgOID().toString()); transactionLogger.paramPut(TransactionLogger.ISSUER_NAME_HASH, certId.getIssuerNameHash()); transactionLogger.paramPut(TransactionLogger.ISSUER_KEY, certId.getIssuerKeyHash()); } if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.ISSUER_KEY, certId.getIssuerKeyHash()); auditLogger.paramPut(AuditLogger.SERIAL_NOHEX, certId.getSerialNumber().toByteArray()); auditLogger.paramPut(AuditLogger.ISSUER_NAME_HASH, certId.getIssuerNameHash()); } byte[] hashbytes = certId.getIssuerNameHash(); String hash = null; if (hashbytes != null) { hash = new String(Hex.encode(hashbytes)); } String infoMsg = intres.getLocalizedMessage("ocsp.inforeceivedrequest", certId.getSerialNumber().toString(16), hash, remoteAddress); log.info(infoMsg); // Locate the CA which gave out the certificate ocspSigningCacheEntry = OcspSigningCache.INSTANCE.getEntry(certId); if (ocspSigningCacheEntry == null) { //Could it be that we haven't updated the OCSP Signing Cache? ocspSigningCacheEntry = findAndAddMissingCacheEntry(certId); } if (ocspSigningCacheEntry != null) { if (transactionLogger.isEnabled()) { // This will be the issuer DN of the signing certificate, whether an OCSP responder or an internal CA String issuerNameDn = CertTools .getIssuerDN(ocspSigningCacheEntry.getFullCertificateChain().get(0)); transactionLogger.paramPut(TransactionLogger.ISSUER_NAME_DN, issuerNameDn); } } else { /* * if the certId was issued by an unknown CA * * The algorithm here: * We will sign the response with the CA that issued the last certificate(certId) in the request. If the issuing CA is not available on * this server, we sign the response with the default responderId (from params in web.xml). We have to look up the ca-certificate for * each certId in the request though, as we will check for revocation on the ca-cert as well when checking for revocation on the certId. */ // We could not find certificate for this request so get certificate for default responder ocspSigningCacheEntry = OcspSigningCache.INSTANCE.getDefaultEntry(); if (ocspSigningCacheEntry != null) { String errMsg = intres.getLocalizedMessage("ocsp.errorfindcacertusedefault", new String(Hex.encode(certId.getIssuerNameHash()))); log.info(errMsg); // If we can not find the CA, answer UnknowStatus responseList.add(new OCSPResponseItem(certId, new UnknownStatus(), nextUpdate)); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.CERT_STATUS, OCSPResponseItem.OCSP_UNKNOWN); transactionLogger.writeln(); } continue; } else { GlobalOcspConfiguration ocspConfiguration = (GlobalOcspConfiguration) globalConfigurationSession .getCachedConfiguration(GlobalOcspConfiguration.OCSP_CONFIGURATION_ID); String defaultResponder = ocspConfiguration.getOcspDefaultResponderReference(); String errMsg = intres.getLocalizedMessage("ocsp.errorfindcacert", new String(Hex.encode(certId.getIssuerNameHash())), defaultResponder); log.error(errMsg); // If we are responding to multiple requests, the last found ocspSigningCacheEntry will be used in the end // so even if there are not any one now, it might be later when it is time to sign the responses. // Since we only will sign the entire response once if there is at least one valid ocspSigningCacheEntry // we might as well include the unknown requests. responseList.add(new OCSPResponseItem(certId, new UnknownStatus(), nextUpdate)); continue; } } final org.bouncycastle.cert.ocsp.CertificateStatus certStatus; // Check if the cacert (or the default responderid) is revoked X509Certificate caCertificate = ocspSigningCacheEntry.getIssuerCaCertificate(); final CertificateStatus signerIssuerCertStatus = ocspSigningCacheEntry .getIssuerCaCertificateStatus(); final String caCertificateSubjectDn = CertTools.getSubjectDN(caCertificate); CertificateStatusHolder certificateStatusHolder = null; if (signerIssuerCertStatus.equals(CertificateStatus.REVOKED)) { /* * According to chapter 2.7 in RFC2560: * * 2.7 CA Key Compromise If an OCSP responder knows that a particular CA's private key has been compromised, it MAY return the revoked * state for all certificates issued by that CA. */ // If we've ended up here it's because the signer issuer certificate was revoked. certStatus = new RevokedStatus( new RevokedInfo(new ASN1GeneralizedTime(signerIssuerCertStatus.revocationDate), CRLReason.lookup(signerIssuerCertStatus.revocationReason))); infoMsg = intres.getLocalizedMessage("ocsp.signcertissuerrevoked", CertTools.getSerialNumberAsString(caCertificate), CertTools.getSubjectDN(caCertificate)); log.info(infoMsg); responseList.add(new OCSPResponseItem(certId, certStatus, nextUpdate)); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.CERT_STATUS, OCSPResponseItem.OCSP_REVOKED); transactionLogger.writeln(); } } else { /** * Here is the actual check for the status of the sought certificate (easy to miss). Here we grab just the status if there aren't * any OIDs defined (default case), but if there are we'll probably need the certificate as well. If that's the case, we'll grab * the certificate in the same transaction. */ final CertificateStatus status; if (extensionOids.isEmpty()) { status = certificateStoreSession.getStatus(caCertificateSubjectDn, certId.getSerialNumber()); } else { certificateStatusHolder = certificateStoreSession .getCertificateAndStatus(caCertificateSubjectDn, certId.getSerialNumber()); status = certificateStatusHolder.getCertificateStatus(); } // If we have an OcspKeyBinding configured for this request, we override the default value if (ocspSigningCacheEntry.isUsingSeparateOcspSigningCertificate()) { nextUpdate = ocspSigningCacheEntry.getOcspKeyBinding().getUntilNextUpdate() * 1000L; } // If we have an explicit value configured for this certificate profile, we override the the current value with this value if (status.certificateProfileId != CertificateProfileConstants.CERTPROFILE_NO_PROFILE && OcspConfiguration.isUntilNextUpdateConfigured(status.certificateProfileId)) { nextUpdate = OcspConfiguration.getUntilNextUpdate(status.certificateProfileId); } // If we have an OcspKeyBinding configured for this request, we override the default value if (ocspSigningCacheEntry.isUsingSeparateOcspSigningCertificate()) { maxAge = ocspSigningCacheEntry.getOcspKeyBinding().getMaxAge() * 1000L; } // If we have an explicit value configured for this certificate profile, we override the the current value with this value if (status.certificateProfileId != CertificateProfileConstants.CERTPROFILE_NO_PROFILE && OcspConfiguration.isMaxAgeConfigured(status.certificateProfileId)) { maxAge = OcspConfiguration.getMaxAge(status.certificateProfileId); } final String sStatus; boolean addArchiveCutoff = false; if (status.equals(CertificateStatus.NOT_AVAILABLE)) { // No revocation info available for this cert, handle it if (log.isDebugEnabled()) { log.debug("Unable to find revocation information for certificate with serial '" + certId.getSerialNumber().toString(16) + "'" + " from issuer '" + caCertificateSubjectDn + "'"); } /* * If we do not treat non existing certificates as good or revoked * OR * we don't actually handle requests for the CA issuing the certificate asked about * then we return unknown * */ if (OcspConfigurationCache.INSTANCE.isNonExistingGood(requestUrl, ocspSigningCacheEntry.getOcspKeyBinding()) && OcspSigningCache.INSTANCE.getEntry(certId) != null) { sStatus = "good"; certStatus = null; // null means "good" in OCSP if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.CERT_STATUS, OCSPResponseItem.OCSP_GOOD); } } else if (OcspConfigurationCache.INSTANCE.isNonExistingRevoked(requestUrl, ocspSigningCacheEntry.getOcspKeyBinding()) && OcspSigningCache.INSTANCE.getEntry(certId) != null) { sStatus = "revoked"; certStatus = new RevokedStatus(new RevokedInfo(new ASN1GeneralizedTime(new Date(0)), CRLReason.lookup(CRLReason.certificateHold))); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.CERT_STATUS, OCSPResponseItem.OCSP_REVOKED); } addExtendedRevokedExtension = true; } else { sStatus = "unknown"; certStatus = new UnknownStatus(); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.CERT_STATUS, OCSPResponseItem.OCSP_UNKNOWN); } } } else if (status.equals(CertificateStatus.REVOKED)) { // Revocation info available for this cert, handle it sStatus = "revoked"; certStatus = new RevokedStatus( new RevokedInfo(new ASN1GeneralizedTime(status.revocationDate), CRLReason.lookup(status.revocationReason))); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.CERT_STATUS, OCSPResponseItem.OCSP_REVOKED); } // If we have an explicit value configured for this certificate profile, we override the the current value with this value if (status.certificateProfileId != CertificateProfileConstants.CERTPROFILE_NO_PROFILE && OcspConfiguration .isRevokedUntilNextUpdateConfigured(status.certificateProfileId)) { nextUpdate = OcspConfiguration.getRevokedUntilNextUpdate(status.certificateProfileId); } // If we have an explicit value configured for this certificate profile, we override the the current value with this value if (status.certificateProfileId != CertificateProfileConstants.CERTPROFILE_NO_PROFILE && OcspConfiguration.isRevokedMaxAgeConfigured(status.certificateProfileId)) { maxAge = OcspConfiguration.getRevokedMaxAge(status.certificateProfileId); } } else { sStatus = "good"; certStatus = null; if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.CERT_STATUS, OCSPResponseItem.OCSP_GOOD); } addArchiveCutoff = checkAddArchiveCuttoff(caCertificateSubjectDn, certId); } if (log.isDebugEnabled()) { log.debug("Set nextUpdate=" + nextUpdate + ", and maxAge=" + maxAge + " for certificateProfileId=" + status.certificateProfileId); } infoMsg = intres.getLocalizedMessage("ocsp.infoaddedstatusinfo", sStatus, certId.getSerialNumber().toString(16), caCertificateSubjectDn); log.info(infoMsg); OCSPResponseItem respItem = new OCSPResponseItem(certId, certStatus, nextUpdate); if (addArchiveCutoff) { addArchiveCutoff(respItem); producedAt = new Date(); } responseList.add(respItem); if (transactionLogger.isEnabled()) { transactionLogger.writeln(); } } for (String oidstr : extensionOids) { boolean useAlways = false; if (oidstr.startsWith("*")) { oidstr = oidstr.substring(1, oidstr.length()); useAlways = true; } ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(oidstr); Extension extension = null; if (!useAlways) { // Only check if extension exists if we are not already bound to use it if (req.hasExtensions()) { extension = req.getExtension(oid); } } //If found, or if it should be used anyway if (useAlways || extension != null) { // We found an extension, call the extension class if (log.isDebugEnabled()) { log.debug("Found OCSP extension oid: " + oidstr); } OCSPExtension extObj = OcspExtensionsCache.INSTANCE.getExtensions().get(oidstr); if (extObj != null) { // Find the certificate from the certId if (certificateStatusHolder != null && certificateStatusHolder.getCertificate() != null) { X509Certificate cert = (X509Certificate) certificateStatusHolder.getCertificate(); // Call the OCSP extension Map<ASN1ObjectIdentifier, Extension> retext = extObj.process(requestCertificates, remoteAddress, remoteHost, cert, certStatus); if (retext != null) { // Add the returned X509Extensions to the responseExtension we will add to the basic OCSP response responseExtensions.putAll(retext); } else { String errMsg = intres.getLocalizedMessage("ocsp.errorprocessextension", extObj.getClass().getName(), Integer.valueOf(extObj.getLastErrorCode())); log.error(errMsg); } } } } } } if (addExtendedRevokedExtension) { // id-pkix-ocsp-extended-revoke OBJECT IDENTIFIER ::= {id-pkix-ocsp 9} final ASN1ObjectIdentifier extendedRevokedOID = new ASN1ObjectIdentifier( OCSPObjectIdentifiers.id_pkix_ocsp + ".9"); try { responseExtensions.put(extendedRevokedOID, new Extension(extendedRevokedOID, false, DERNull.INSTANCE.getEncoded())); } catch (IOException e) { throw new IllegalStateException("Could not get encodig from DERNull.", e); } } if (ocspSigningCacheEntry != null) { // Add responseExtensions Extensions exts = new Extensions(responseExtensions.values().toArray(new Extension[0])); // generate the signed response object BasicOCSPResp basicresp = signOcspResponse(req, responseList, exts, ocspSigningCacheEntry, producedAt); ocspResponse = responseGenerator.build(OCSPRespBuilder.SUCCESSFUL, basicresp); if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.STATUS, OCSPRespBuilder.SUCCESSFUL); } if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.STATUS, OCSPRespBuilder.SUCCESSFUL); } } else { // Only unknown CAs in requests and no default responder's cert, return an unsigned response if (log.isDebugEnabled()) { log.debug(intres.getLocalizedMessage("ocsp.errornocacreateresp")); } ocspResponse = responseGenerator.build(OCSPRespBuilder.UNAUTHORIZED, null); if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.STATUS, OCSPRespBuilder.UNAUTHORIZED); } if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.STATUS, OCSPRespBuilder.UNAUTHORIZED); } } } catch (SignRequestException e) { if (transactionLogger.isEnabled()) { transactionLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); } if (auditLogger.isEnabled()) { auditLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); } String errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq", e.getMessage()); log.info(errMsg); // No need to log the full exception here // RFC 2560: responseBytes are not set on error. ocspResponse = responseGenerator.build(OCSPRespBuilder.SIG_REQUIRED, null); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.STATUS, OCSPRespBuilder.SIG_REQUIRED); transactionLogger.writeln(); } if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.STATUS, OCSPRespBuilder.SIG_REQUIRED); } } catch (SignRequestSignatureException e) { if (transactionLogger.isEnabled()) { transactionLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); } if (auditLogger.isEnabled()) { auditLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); } String errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq", e.getMessage()); log.info(errMsg); // No need to log the full exception here // RFC 2560: responseBytes are not set on error. ocspResponse = responseGenerator.build(OCSPRespBuilder.UNAUTHORIZED, null); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.STATUS, OCSPRespBuilder.UNAUTHORIZED); transactionLogger.writeln(); } if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.STATUS, OCSPRespBuilder.UNAUTHORIZED); } } catch (InvalidAlgorithmException e) { if (transactionLogger.isEnabled()) { transactionLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); } if (auditLogger.isEnabled()) { auditLogger.paramPut(PatternLogger.PROCESS_TIME, PatternLogger.PROCESS_TIME); } String errMsg = intres.getLocalizedMessage("ocsp.errorprocessreq", e.getMessage()); log.info(errMsg); // No need to log the full exception here // RFC 2560: responseBytes are not set on error. ocspResponse = responseGenerator.build(OCSPRespBuilder.MALFORMED_REQUEST, null); if (transactionLogger.isEnabled()) { transactionLogger.paramPut(TransactionLogger.STATUS, OCSPRespBuilder.MALFORMED_REQUEST); transactionLogger.writeln(); } if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.STATUS, OCSPRespBuilder.MALFORMED_REQUEST); } } catch (NoSuchAlgorithmException e) { ocspResponse = processDefaultError(responseGenerator, transactionLogger, auditLogger, e); } catch (CertificateException e) { ocspResponse = processDefaultError(responseGenerator, transactionLogger, auditLogger, e); } catch (CryptoTokenOfflineException e) { ocspResponse = processDefaultError(responseGenerator, transactionLogger, auditLogger, e); } try { respBytes = ocspResponse.getEncoded(); if (auditLogger.isEnabled()) { auditLogger.paramPut(AuditLogger.OCSPRESPONSE, new String(Hex.encode(respBytes))); auditLogger.writeln(); auditLogger.flush(); } if (transactionLogger.isEnabled()) { transactionLogger.flush(); } if (OcspConfiguration.getLogSafer()) { // See if the Errorhandler has found any problems if (hasErrorHandlerFailedSince(startTime)) { log.info("ProbableErrorhandler reported error, cannot answer request"); // RFC 2560: responseBytes are not set on error. ocspResponse = responseGenerator.build(OCSPRespBuilder.INTERNAL_ERROR, null); } // See if the Appender has reported any problems if (!CanLogCache.INSTANCE.canLog()) { log.info("SaferDailyRollingFileAppender reported error, cannot answer request"); // RFC 2560: responseBytes are not set on error. ocspResponse = responseGenerator.build(OCSPRespBuilder.INTERNAL_ERROR, null); } } } catch (IOException e) { log.error("Unexpected IOException caught.", e); if (transactionLogger.isEnabled()) { transactionLogger.flush(); } if (auditLogger.isEnabled()) { auditLogger.flush(); } } return new OcspResponseInformation(ocspResponse, maxAge); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspHttpStandaloneTest.java
License:Open Source License
/** * Just verify that a both escaped and non-encoded GET requests work. *//*w ww . j ava 2 s . com*/ @Test public void test13GetRequests() throws Exception { super.test13GetRequests(); // See if the OCSP Servlet can also read escaped requests final String urlEncReq = httpReqPath + '/' + resourceOcsp + '/' + "MGwwajBFMEMwQTAJBgUrDgMCGgUABBRBRfilzPB%2BAevx0i1AoeKTkrHgLgQUFJw5gwk9BaEgsX3pzsRF9iso29ICCCzdx5N0v9XwoiEwHzAdBgkrBgEFBQcwAQIEECrZswo%2Fa7YW%2Bhyi5Sn85fs%3D"; URL url = new URL(urlEncReq); log.info(url.toString()); // Dump the exact string we use for access HttpURLConnection con = (HttpURLConnection) url.openConnection(); assertEquals( "Response code did not match. (Make sure you allow encoded slashes in your appserver.. add -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true in Tomcat)", 200, con.getResponseCode()); 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); assertTrue("Should not be concidered malformed.", OCSPRespBuilder.MALFORMED_REQUEST != response.getStatus()); final String dubbleSlashEncReq = httpReqPath + '/' + resourceOcsp + '/' + "MGwwajBFMEMwQTAJBgUrDgMCGgUABBRBRfilzPB%2BAevx0i1AoeKTkrHgLgQUFJw5gwk9BaEgsX3pzsRF9iso29ICCAvB%2F%2FHJyKqpoiEwHzAdBgkrBgEFBQcwAQIEEOTzT2gv3JpVva22Vj8cuKo%3D"; url = new URL(dubbleSlashEncReq); log.info(url.toString()); // Dump the exact string we use for access con = (HttpURLConnection) url.openConnection(); assertEquals("Response code did not match. ", 200, con.getResponseCode()); assertNotNull(con.getContentType()); assertTrue(con.getContentType().startsWith("application/ocsp-response")); response = new OCSPResp(IOUtils.toByteArray(con.getInputStream())); assertNotNull("Response should not be null.", response); assertTrue("Should not be concidered malformed.", OCSPRespBuilder.MALFORMED_REQUEST != response.getStatus()); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspHttpTest.java
License:Open Source License
/** * Just verify that a simple GET works.//from ww w . ja v a 2 s . co m */ @Test public void test13GetRequests() throws Exception { // See if the OCSP Servlet can read non-encoded requests final String plainReq = httpReqPath + '/' + resourceOcsp + '/' + "MGwwajBFMEMwQTAJBgUrDgMCGgUABBRBRfilzPB+Aevx0i1AoeKTkrHgLgQUFJw5gwk9BaEgsX3pzsRF9iso29ICCCzdx5N0v9XwoiEwHzAdBgkrBgEFBQcwAQIEECrZswo/a7YW+hyi5Sn85fs="; URL url = new URL(plainReq); log.info(url.toString()); // Dump the exact string we use for access HttpURLConnection con = (HttpURLConnection) url.openConnection(); assertEquals("Response code did not match. ", 200, con.getResponseCode()); 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); assertTrue("Should not be considered malformed.", OCSPRespBuilder.MALFORMED_REQUEST != response.getStatus()); final String dubbleSlashNonEncReq = httpReqPath + '/' + resourceOcsp + '/' + "MGwwajBFMEMwQTAJBgUrDgMCGgUABBRBRfilzPB%2BAevx0i1AoeKTkrHgLgQUFJw5gwk9BaEgsX3pzsRF9iso29ICCAvB//HJyKqpoiEwHzAdBgkrBgEFBQcwAQIEEOTzT2gv3JpVva22Vj8cuKo%3D"; url = new URL(dubbleSlashNonEncReq); log.info(url.toString()); // Dump the exact string we use for access con = (HttpURLConnection) url.openConnection(); assertEquals("Response code did not match. ", 200, con.getResponseCode()); assertNotNull(con.getContentType()); assertTrue(con.getContentType().startsWith("application/ocsp-response")); response = new OCSPResp(IOUtils.toByteArray(con.getInputStream())); assertNotNull("Response should not be null.", response); assertTrue("Should not be concidered malformed.", OCSPRespBuilder.MALFORMED_REQUEST != response.getStatus()); // An OCSP request, ocspTestCert is already created in earlier tests loadUserCert(this.caid); this.helper.reloadKeys(); this.helper.verifyStatusGood(this.caid, this.cacert, this.ocspTestCert.getSerialNumber()); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspHttpTest.java
License:Open Source License
/** * Verify OCSP response for a malicious request. Uses nonsense payload. * * HTTP Content-length: 200000 byte ASN1 sequence length: 9996 byte Payload * size: 200000 byte (not including HTTP header) *///from ww w .ja va 2s . com @Test public void test19MaliciousOcspRequest() throws Exception { log.trace(">test19MaliciousOcspRequest"); int i = 0; // Construct the fake data. byte data[] = new byte[LimitLengthASN1Reader.MAX_REQUEST_SIZE * 2]; // The first byte indicate that this is a sequence. Necessary to past // the first test as an accepted OCSP object. data[0] = (byte) BERTags.SEQUENCE; // The second byte indicates the number of the following bytes are more // than can be represented by one byte and will be represented by 2 // bytes instead. data[1] = (byte) 0x82; // The third through the forth bytes are the number of the following // bytes. (0x270C = 9996) data[2] = (byte) 0x27; // MSB data[3] = (byte) 0x0C; // LSB // Fill the rest of the array with some fake data. for (i = 4; i < data.length; i++) { data[i] = (byte) i; } // Create the HTTP header String path = "/ejbca/" + resourceOcsp; String headers = "POST " + path + " HTTP/1.1\r\n" + "Host: " + httpHost + "\r\n" + "Content-Type: application/ocsp-request\r\n" + "Content-Length: 200000\r\n" + "\r\n"; // Merge the HTTP headers and the raw data into one package. byte input[] = concatByteArrays(headers.getBytes(), data); // Create the socket. Socket socket = new Socket(InetAddress.getByName(httpHost), Integer.parseInt(httpPort)); // Send data byte for byte. OutputStream os = socket.getOutputStream(); try { os.write(input); } catch (IOException e) { log.info("Socket threw an IOException.", e); } // Reading the response. InputStream ins = socket.getInputStream(); byte ret[] = new byte[1024]; ins.read(ret); socket.close(); // Removing the HTTP headers. The HTTP headers end at the last // occurrence of "\r\n". for (i = ret.length - 1; i > 0; i--) { if ((ret[i] == 0x0A) && (ret[i - 1] == 0x0D)) { break; } } int start = i + 1; byte respa[] = new byte[ret.length - start]; for (i = start; i < ret.length; i++) { respa[i - start] = ret[i]; } log.info("response contains: " + respa.length + " bytes."); // Reading the response as a OCSPResp. OCSPResp response = new OCSPResp(respa); assertEquals("Incorrect response status.", OCSPRespBuilder.MALFORMED_REQUEST, response.getStatus()); log.trace("<test19MaliciousOcspRequest"); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspHttpTest.java
License:Open Source License
/** * Verify OCSP response for a malicious request where the POST data starts * with a proper OCSP request.//from w w w. j av a 2s.c om */ @Test public void test20MaliciousOcspRequest() throws Exception { log.trace(">test20MaliciousOcspRequest"); // Start by sending a valid OCSP requests so we know the helpers work byte validOcspReq[] = getValidOcspRequest(); OCSPResp response = sendRawRequestToOcsp(validOcspReq.length, validOcspReq, false); assertEquals("Incorrect response status.", OCSPRespBuilder.SUCCESSFUL, response.getStatus()); // Try sending a valid request and then keep sending some more data. byte[] buf = new byte[LimitLengthASN1Reader.MAX_REQUEST_SIZE * 2]; Arrays.fill(buf, (byte) 123); buf = concatByteArrays(validOcspReq, buf); // This should return an error because we only allow content length of 100000 bytes response = sendRawRequestToOcsp(buf.length, buf, false); assertEquals("Incorrect response status.", OCSPRespBuilder.MALFORMED_REQUEST, response.getStatus()); // Now try with a fake HTTP content-length header try { response = sendRawRequestToOcsp(validOcspReq.length, buf, false); // When sending a large request body with a too short content-length the serves sees this as two streaming // requests. The first request will be read and processed by EJBCA normally and sent back, but the // second one will not be a valid request so the server will send back an error. // Glassfish actually sends back a "400 Bad request". Our reading code in sendRawRequestToOcsp // does not handle multiple streaming responses so it will barf on the second one. // This is different for JBoss and Glassfish though, with JBoss we will get a IOException trying // to read the response, while for Glassfish we will get the response with 0 bytes from the 400 response // Only glassfish will come here, with a non-null response, but of length 2(/r/n?). JBoss (4, 5, 6) will go to the // IOException below try { byte[] encoded = response.getEncoded(); if ((encoded != null) && (encoded.length > 2)) { // Actually this error message is wrong, since it is our client that does not handle streaming responses // where the first response should be good. fail("Was able to send a lot of data with a fake HTTP Content-length without any error."); } } catch (NullPointerException npe) { // NOPMD // the response.getEncoded() can give NPE, in some versions of BC, if it was not created with correct input } } catch (IOException e) { } // Try sneaking through a payload that is just under the limit. The // responder will answer politely, but log a warning. buf = new byte[LimitLengthASN1Reader.MAX_REQUEST_SIZE - validOcspReq.length]; Arrays.fill(buf, (byte) 123); buf = concatByteArrays(validOcspReq, buf); response = sendRawRequestToOcsp(buf.length, buf, false); assertEquals("Server accepted malicious request. (This might be a good thing!)", OCSPRespBuilder.SUCCESSFUL, response.getStatus()); log.trace("<test20MaliciousOcspRequest"); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspTestBase.java
License:Open Source License
/** * In compliance with RFC 2560 on/* ww w. ja v a 2 s . com*/ * "ASN.1 Specification of the OCSP Response": If the value of * responseStatus is one of the error conditions, responseBytes are not set. * * OCSPResponse ::= SEQUENCE { responseStatus OCSPResponseStatus, * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL } */ protected void test11MalformedRequest() throws Exception { // NOPMD, this is not a test class itself loadUserCert(this.caid); OCSPReqBuilder gen = new OCSPReqBuilder(); // Add 101 OCSP requests.. the Servlet will consider a request with more // than 100 malformed.. // This does not mean that we only should allow 100 in the future, just // that we if so need to find // another way make the Servlet return // OCSPRespBuilder.MALFORMED_REQUEST for (int i = 0; i < 101; i++) { gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert, ocspTestCert.getSerialNumber())); } Extension[] extensions = new Extension[1]; extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString("123456789".getBytes())); gen.setRequestExtensions(new Extensions(extensions)); OCSPReq req = gen.build(); // Send the request and receive null SingleResp[] singleResps = helper.sendOCSPPost(req.getEncoded(), "123456789", OCSPRespBuilder.MALFORMED_REQUEST, 200); assertNull("No SingleResps should be returned.", singleResps); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspTestBase.java
License:Open Source License
protected void test12CorruptRequests() throws Exception { // NOPMD, this is not a test class itself log.trace(">test12CorruptRequests()"); loadUserCert(this.caid); // An OCSP request, ocspTestCert is already created in earlier tests OCSPReqBuilder gen = new OCSPReqBuilder(); gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert, ocspTestCert.getSerialNumber())); Extension[] extensions = new Extension[1]; extensions[0] = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString("123456789".getBytes())); gen.setRequestExtensions(new Extensions(extensions)); OCSPReq req = gen.build();// w ww . j a va2s .c o m // Request 1 // // Send the request and receive a singleResponse byte[] orgbytes = req.getEncoded(); // Save original bytes, so we can // make different strange values byte[] bytes = req.getEncoded(); // Switch the first byte, now it's a really corrupted request bytes[0] = 0x44; SingleResp[] singleResps = helper.sendOCSPPost(bytes, "123456789", OCSPRespBuilder.MALFORMED_REQUEST, 200); // error // code // 1 // means // malformed // request assertNull("SingleResps should be null.", singleResps); // Request 2 // // Remove the last byte, should still be quite corrupted // bytes = Arrays.copyOf(orgbytes, orgbytes.length-1); only works in // Java 6 bytes = ArrayUtils.remove(orgbytes, orgbytes.length - 1); singleResps = helper.sendOCSPPost(bytes, "123456789", OCSPRespBuilder.MALFORMED_REQUEST, 200); // error // code // 1 // means // malformed // request assertNull("SingleResps should be null.", singleResps); // Request 3 // // more than 1 million bytes // bytes = Arrays.copyOf(orgbytes, 1000010); only works in Java 6 bytes = ArrayUtils.addAll(orgbytes, new byte[1000010]); singleResps = helper.sendOCSPPost(bytes, "123456789", OCSPRespBuilder.MALFORMED_REQUEST, 200); // // // error // code // 1 // means // malformed // request assertNull("SingleResps should be null.", singleResps); // Request 4 // // // A completely empty request with no question in it gen = new OCSPReqBuilder(); req = gen.build(); bytes = req.getEncoded(); singleResps = helper.sendOCSPPost(bytes, "123456789", 1, 200); // assertNull("SingleResps should be null.", singleResps); log.trace("<test12CorruptRequests()"); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspTestBase.java
License:Open Source License
/** * Just verify that a simple GET works./*from w w w. j a v a 2 s .c o m*/ */ protected void test13GetRequests() throws Exception { // NOPMD, this is not a test class itself loadUserCert(this.caid); // See if the OCSP Servlet can read non-encoded requests final String plainReq = httpReqPath + '/' + resourceOcsp + '/' + "MGwwajBFMEMwQTAJBgUrDgMCGgUABBRBRfilzPB+Aevx0i1AoeKTkrHgLgQUFJw5gwk9BaEgsX3pzsRF9iso29ICCCzdx5N0v9XwoiEwHzAdBgkrBgEFBQcwAQIEECrZswo/a7YW+hyi5Sn85fs="; URL url = new URL(plainReq); log.info(url.toString()); // Dump the exact string we use for access HttpURLConnection con = (HttpURLConnection) url.openConnection(); assertEquals("Response code did not match. ", 200, con.getResponseCode()); 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); assertTrue("Should not be concidered malformed.", OCSPRespBuilder.MALFORMED_REQUEST != response.getStatus()); final String dubbleSlashNonEncReq = httpReqPath + '/' + resourceOcsp + '/' + "MGwwajBFMEMwQTAJBgUrDgMCGgUABBRBRfilzPB%2BAevx0i1AoeKTkrHgLgQUFJw5gwk9BaEgsX3pzsRF9iso29ICCAvB//HJyKqpoiEwHzAdBgkrBgEFBQcwAQIEEOTzT2gv3JpVva22Vj8cuKo%3D"; url = new URL(dubbleSlashNonEncReq); log.info(url.toString()); // Dump the exact string we use for access con = (HttpURLConnection) url.openConnection(); assertEquals("Response code did not match. ", 200, con.getResponseCode()); assertNotNull(con.getContentType()); assertTrue(con.getContentType().startsWith("application/ocsp-response")); response = new OCSPResp(IOUtils.toByteArray(con.getInputStream())); assertNotNull("Response should not be null.", response); assertTrue("Should not be concidered malformed.", OCSPRespBuilder.MALFORMED_REQUEST != response.getStatus()); // An OCSP request, ocspTestCert is already created in earlier tests OCSPReqBuilder gen = new OCSPReqBuilder(); loadUserCert(this.caid); gen.addRequest(new JcaCertificateID(SHA1DigestCalculator.buildSha1Instance(), cacert, ocspTestCert.getSerialNumber())); OCSPReq req = gen.build(); BasicOCSPResp brep = helper.sendOCSPGet(req.getEncoded(), null, OCSPRespBuilder.SUCCESSFUL, 200); SingleResp[] singleResps = brep.getResponses(); assertNotNull("SingleResps should not be null.", singleResps); CertificateID certId = singleResps[0].getCertID(); assertEquals("Serno in response does not match serno in request.", certId.getSerialNumber(), ocspTestCert.getSerialNumber()); Object status = singleResps[0].getCertStatus(); assertEquals("Status is not null (null is 'good')", null, status); }
From source file:org.ejbca.core.protocol.ocsp.ProtocolOcspTestBase.java
License:Open Source License
/** * Send a bunch of faulty requests/*from ww w. j a v a 2 s . com*/ */ protected void test14CorruptGetRequests() throws Exception { // NOPMD, this is not a test class itself // An array of zeros cannot be right.. // A GET request larger than 2048 works on JBoss but not on Glassfish, // GF only gives "unexpected end of file", i.e. it closes the connection helper.sendOCSPGet(new byte[2048], null, OCSPRespBuilder.MALFORMED_REQUEST, 200); // Send an empty GET request: .../ocsp/{nothing} helper.sendOCSPGet(new byte[0], null, OCSPRespBuilder.MALFORMED_REQUEST, 200); // Test too large requests /* * try { // When we use an URL of length ~ 8100 chars on JBoss we get a * "Connection reset", // JBoss 5 considers this a bad request (400) // * so we cannot test the real Malformed response we want here * helper.sendOCSPGet(new byte[6020], null, * OCSPRespBuilder.MALFORMED_REQUEST, 200); } catch (IOException e) { * log.info(e.getMessage()); } try { // When we use an URL of length ~ > * 500000 chars on JBoss we get a "Error writing to server", // so we * cannot test the real Malformed response we want here caused by to * large requests helper.sendOCSPGet(new byte[1000001], null, * OCSPRespBuilder.MALFORMED_REQUEST, 200); } catch (IOException e) { * log.info(e.getMessage()); } */ }