/** * Generates an OCSP request using BouncyCastle. * @param issuerCert certificate of the issues * @param serialNumber serial number * @return an OCSP request * @throws OCSPException * @throws IOException */ private static OCSPReq generateOCSPRequest(X509Certificate issuerCert, BigInteger serialNumber) throws OCSPException, IOException, OperatorException, CertificateEncodingException { //Add provider BC Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); JcaDigestCalculatorProviderBuilder digestCalculatorProviderBuilder = new JcaDigestCalculatorProviderBuilder(); DigestCalculatorProvider digestCalculatorProvider = digestCalculatorProviderBuilder.build(); DigestCalculator digestCalculator = digestCalculatorProvider.get(CertificateID.HASH_SHA1); // Generate the id for the certificate we are looking for CertificateID id = new CertificateID(digestCalculator, new JcaX509CertificateHolder(issuerCert), serialNumber); // basic request generation with nonce OCSPReqBuilder gen = new OCSPReqBuilder(); gen.addRequest(id); // create details for nonce extension Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(new DEROctetString(PdfEncryption.createDocumentId()).getEncoded())); gen.setRequestExtensions(new Extensions(new Extension[]{ext})); return gen.build(); }
public static OCSPReq GenOcspReq(X509Certificate nextCert, X509Certificate nextIssuer) throws OCSPException { OCSPReqGenerator ocspRequestGenerator = new OCSPReqGenerator(); CertificateID certId = new CertificateID(CertificateID.HASH_SHA1, nextIssuer, nextCert.getSerialNumber()); ocspRequestGenerator.addRequest(certId); BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis()); Vector<DERObjectIdentifier> oids = new Vector<DERObjectIdentifier>(); Vector<X509Extension> values = new Vector<X509Extension>(); oids.add(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); values.add(new X509Extension(false, new DEROctetString(nonce .toByteArray()))); ocspRequestGenerator.setRequestExtensions(new X509Extensions(oids, values)); return ocspRequestGenerator.generate(); }
public Object getResponseObject() throws OCSPException { ResponseBytes rb = this.resp.getResponseBytes(); if (rb == null) { return null; } if (rb.getResponseType().equals(OCSPObjectIdentifiers.id_pkix_ocsp_basic)) { try { ASN1Primitive obj = ASN1Primitive.fromByteArray(rb.getResponse().getOctets()); return new BasicOCSPResp(BasicOCSPResponse.getInstance(obj)); } catch (Exception e) { throw new OCSPException("problem decoding object: " + e, e); } } return rb.getResponse(); }
private OCSPReq generateOcspRequest(X509Certificate issuerCert, BigInteger serialNumber) throws OCSPException, CertificateEncodingException, OperatorCreationException, IOException { BcDigestCalculatorProvider util = new BcDigestCalculatorProvider(); // Generate the id for the certificate we are looking for CertificateID id = new CertificateID(util.get( CertificateID.HASH_SHA1), new X509CertificateHolder(issuerCert.getEncoded()), serialNumber); OCSPReqBuilder ocspGen = new OCSPReqBuilder(); ocspGen.addRequest(id); BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis()); Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, new DEROctetString(nonce.toByteArray())); ocspGen.setRequestExtensions(new Extensions(new Extension[] { ext })); return ocspGen.build(); }
private boolean isNonceMatch(final BasicOCSPResp basicOCSPResp, BigInteger expectedNonceValue) { Extension extension = basicOCSPResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); ASN1OctetString extnValue = extension.getExtnValue(); ASN1Primitive value; try { value = ASN1Primitive.fromByteArray(extnValue.getOctets()); } catch (IOException ex) { LOG.warn("Invalid encoding of nonce extension value in OCSP response", ex); return false; } if (value instanceof DEROctetString) { BigInteger receivedNonce = new BigInteger(((DEROctetString) value).getOctets()); return expectedNonceValue.equals(receivedNonce); } else { LOG.warn("Nonce extension value in OCSP response is not an OCTET STRING"); return false; } }
public OCSPResp build( int status, Object response) throws OCSPException { if (response == null) { return new OCSPResp(new OCSPResponse(new OCSPResponseStatus(status), null)); } if (response instanceof BasicOCSPResp) { BasicOCSPResp r = (BasicOCSPResp)response; ASN1OctetString octs; try { octs = new DEROctetString(r.getEncoded()); } catch (IOException e) { throw new OCSPException("can't encode object.", e); } ResponseBytes rb = new ResponseBytes( OCSPObjectIdentifiers.id_pkix_ocsp_basic, octs); return new OCSPResp(new OCSPResponse( new OCSPResponseStatus(status), rb)); } throw new OCSPException("unknown response object"); }
public static OCSPReq GenOcspReq(X509Certificate nextCert, X509Certificate nextIssuer) throws OCSPException, OperatorCreationException, CertificateEncodingException, IOException { OCSPReqBuilder ocspRequestGenerator = new OCSPReqBuilder(); DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build(); // CertificateID certId = new CertificateID( // CertificateID.HASH_SHA1, // nextIssuer, nextCert.getSerialNumber() // ); CertificateID certId = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), new X509CertificateHolder (nextIssuer.getEncoded()), nextCert.getSerialNumber()); // CertificateID id = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1), testCert, BigInteger.valueOf(1)); ocspRequestGenerator.addRequest(certId); BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis()); Extension ext = new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, false, new DEROctetString(nonce.toByteArray())); ocspRequestGenerator.setRequestExtensions(new Extensions(new Extension[]{ext})); return ocspRequestGenerator.build(); // Vector<DERObjectIdentifier> oids = new Vector<DERObjectIdentifier>(); // Vector<X509Extension> values = new Vector<X509Extension>(); // // oids.add(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); // values.add(new X509Extension(false, new DEROctetString(nonce // .toByteArray()))); // // ocspRequestGenerator.setRequestExtensions(new X509Extensions(oids, // values)); // return ocspRequestGenerator.generate(); }
private void addBasicOcspRespFrom_id_pkix_ocsp_basic(final List<BasicOCSPResp> basicOCSPResps) { final Store otherRevocationInfo = cmsSignedData.getOtherRevocationInfo(OCSPObjectIdentifiers.id_pkix_ocsp_basic); final Collection otherRevocationInfoMatches = otherRevocationInfo.getMatches(null); for (final Object object : otherRevocationInfoMatches) { if (object instanceof DERSequence) { final DERSequence otherRevocationInfoMatch = (DERSequence) object; final BasicOCSPResp basicOCSPResp = CMSUtils.getBasicOcspResp(otherRevocationInfoMatch); addBasicOcspResp(basicOCSPResps, basicOCSPResp); } else { LOG.warn("Unsupported object type for id_pkix_ocsp_basic (SHALL be DER encoding) : " + object.getClass().getSimpleName()); } } }
/** * Indicates if the revocation data should be checked for an OCSP signing certificate.<br> * http://www.ietf.org/rfc/rfc2560.txt?number=2560<br> * A CA may specify that an OCSP client can trust a responder for the lifetime of the responder's certificate. The * CA * does so by including the extension id-pkix-ocsp-nocheck. This SHOULD be a non-critical extension. The value of * the * extension should be NULL. * * @return */ public static boolean hasIdPkixOcspNoCheckExtension(CertificateToken token) { final byte[] extensionValue = token.getCertificate().getExtensionValue(OCSPObjectIdentifiers.id_pkix_ocsp_nocheck.getId()); if (extensionValue != null) { try { final ASN1Primitive derObject = toASN1Primitive(extensionValue); if (derObject instanceof DEROctetString) { return isDEROctetStringNull((DEROctetString) derObject); } } catch (Exception e) { LOG.debug("Exception when processing 'id_pkix_ocsp_no_check'", e); } } return false; }
private void extractArchiveCutOff() { Extension extension = basicOCSPResp.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_archive_cutoff); if (extension != null) { ASN1GeneralizedTime archiveCutOffAsn1 = (ASN1GeneralizedTime) extension.getParsedValue(); try { archiveCutOff = archiveCutOffAsn1.getDate(); } catch (ParseException e) { LOG.warn("Unable to extract id_pkix_ocsp_archive_cutoff : " + e.getMessage()); } } }
/** * Convert a BasicOCSPResp in OCSPResp (connection status is set to * SUCCESSFUL). * * @param basicOCSPResp * @return */ public static final OCSPResp fromBasicToResp(final byte[] basicOCSPResp) { final OCSPResponseStatus responseStatus = new OCSPResponseStatus(OCSPResponseStatus.SUCCESSFUL); final DEROctetString derBasicOCSPResp = new DEROctetString(basicOCSPResp); final ResponseBytes responseBytes = new ResponseBytes(OCSPObjectIdentifiers.id_pkix_ocsp_basic, derBasicOCSPResp); final OCSPResponse ocspResponse = new OCSPResponse(responseStatus, responseBytes); final OCSPResp ocspResp = new OCSPResp(ocspResponse); // !!! todo to be checked: System.out.println("===> RECREATED: " + // ocspResp.hashCode()); return ocspResp; }
/** * Processes the OCSP request from the client. * * According to <a href="https://tools.ietf.org/html/rfc6960">RFC 6960 </a> the responder * is tasked with the following checks and if any are not true, an error message is returned: * * 1. the message is well formed * 2. the responder is configured to provide the requested service * 3. the request contains the information needed by the responder. * * If we are at this point, number one is taken care of (we were able to parse it). * * This method will check the second and third conditions as well as do any additional * validation on the request before returning an OCSP response. * * @param ocspReq The OCSP request * @return The OCSP response */ private OCSPResp doProcessOCSPRequest(OCSPReq ocspReq) throws OCSPException { BasicOCSPRespBuilder responseBuilder = new BasicOCSPRespBuilder(responderID); checkForValidRequest(ocspReq); // Add appropriate extensions Collection<Extension> responseExtensions = new ArrayList<>(); //nonce Extension nonceExtension = ocspReq.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); if (nonceExtension != null) { responseExtensions.add(nonceExtension); } if (rejectUnknown) { responseExtensions.add( new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_extended_revoke, false, new byte[]{}) ); } Extension[] extensions = responseExtensions.toArray(new Extension[responseExtensions.size()]); responseBuilder.setResponseExtensions(new Extensions(extensions)); // Check that each request is valid and put the appropriate response in the builder Req[] requests = ocspReq.getRequestList(); for (Req request : requests) { addResponse(responseBuilder, request); } return buildAndSignResponse(responseBuilder); }
/** * Adds response for specific cert OCSP request * * @param responseBuilder The builder containing the full response * @param request The specific cert request */ private void addResponse(BasicOCSPRespBuilder responseBuilder, Req request) throws OCSPException{ CertificateID certificateID = request.getCertID(); // Build Extensions Extensions extensions = new Extensions(new Extension[]{}); Extensions requestExtensions = request.getSingleRequestExtensions(); if (requestExtensions != null) { Extension nonceExtension = requestExtensions.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); if (nonceExtension != null) { extensions = new Extensions(nonceExtension); } } // Check issuer boolean matchesIssuer = certificateID.matchesIssuer(issuingCertificate, digestCalculatorProvider); if (!matchesIssuer) { addResponseForCertificateRequest(responseBuilder, certificateID, new OCSPCertificateStatusWrapper(getUnknownStatus(), DateTime.now(), DateTime.now().plusSeconds(certificateManager.getRefreshSeconds())), extensions); } else { CertificateSummary certificateSummary = certificateManager.getSummary(certificateID.getSerialNumber()); addResponseForCertificateRequest(responseBuilder, request.getCertID(), getOCSPCertificateStatus(certificateSummary), extensions); } }
private Extension buildNonceExtension() { BigInteger nonce = BigInteger.valueOf(System.currentTimeMillis()); return new Extension( OCSPObjectIdentifiers.id_pkix_ocsp_nonce, true, new DEROctetString(nonce.toByteArray()) ); }
private boolean isOcspResponseValid(BasicOCSPResp latestOcspResponse) { Extension extension = latestOcspResponse.getExtension( new ASN1ObjectIdentifier(OCSPObjectIdentifiers.id_pkix_ocsp_nonce.getId())); if (extension == null) { logger.error("No valid OCSP extension found in signature: " + signature.getId()); return false; } return isOcspExtensionValid(extension); }
@Override Extension createNonce() { byte[] bytes = generateRandomNonce(); DEROctetString nonce = new DEROctetString(bytes); boolean critical = false; return new Extension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, critical, nonce); }
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); } }
@Test public void gettingOcspNonce() throws Exception { Configuration configuration = new Configuration(Configuration.Mode.TEST); BDocTSOcspSource ocspSource = new BDocTSOcspSource(configuration); Extension nonce = ocspSource.createNonce(); assertFalse(nonce.isCritical()); assertEquals(OCSPObjectIdentifiers.id_pkix_ocsp_nonce, nonce.getExtnId()); assertTrue(nonce.getExtnValue().toString().length() > 0); }
public OCSPResp generate( int status, Object response) throws OCSPException { if (response == null) { return new OCSPResp(new OCSPResponse(new OCSPResponseStatus(status),null)); } if (response instanceof BasicOCSPResp) { BasicOCSPResp r = (BasicOCSPResp)response; ASN1OctetString octs; try { octs = new DEROctetString(r.getEncoded()); } catch (IOException e) { throw new OCSPException("can't encode object.", e); } ResponseBytes rb = new ResponseBytes( OCSPObjectIdentifiers.id_pkix_ocsp_basic, octs); return new OCSPResp(new OCSPResponse( new OCSPResponseStatus(status), rb)); } throw new OCSPException("unknown response object"); }
private void validateSuccessfulResponse(OCSPResp ocspResp, OCSPReq ocspReq, CertificateSummary... summaries) throws Exception { assertThat(summaries).isNotEmpty(); assertThat(ocspResp.getStatus()).isEqualTo(OCSPRespBuilder.SUCCESSFUL); assertThat(ocspResp.getResponseObject()).isExactlyInstanceOf(BasicOCSPResp.class); BasicOCSPResp basicResponse = (BasicOCSPResp)ocspResp.getResponseObject(); assertThat(basicResponse.getProducedAt()).isAfterOrEqualsTo(NOW.toDate()); // check signature boolean validSignature = basicResponse.isSignatureValid( new JcaContentVerifierProviderBuilder().setProvider("BC").build(signingCertificate.getPublicKey())); assertThat(validSignature).isTrue().withFailMessage("Signature was invalid"); assertThat(basicResponse.getSignatureAlgorithmID()).isEqualTo( new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256withRSA") ); // check extensions List<ASN1ObjectIdentifier> extensionOIDs = Lists.transform( (List<?>) basicResponse.getExtensionOIDs(), input -> (ASN1ObjectIdentifier) input // just casting here ); assertThat(extensionOIDs).containsExactly(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); Extension reqNonce = ocspReq.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); Extension respNonce = basicResponse.getExtension(OCSPObjectIdentifiers.id_pkix_ocsp_nonce); assertThat(respNonce).isEqualTo(reqNonce); SingleResp[] singleResponses = basicResponse.getResponses(); Req[] singleRequests = ocspReq.getRequestList(); assertThat(singleResponses).hasSameSizeAs(singleRequests); for (int i = 0; i < singleRequests.length; i++) { Req request = singleRequests[i]; SingleResp response = singleResponses[i]; assertThat(response.getCertID()).isEqualTo(request.getCertID()); ASN1ObjectIdentifier[] requestExtensions = request.getSingleRequestExtensions().getExtensionOIDs(); for (ASN1ObjectIdentifier extensionOID : requestExtensions) { Extension extension = response.getExtension(extensionOID); assertThat(extension).isNotNull(); assertThat(extension).isEqualTo(request.getSingleRequestExtensions().getExtension(extensionOID)); } assertThat(response.getCertID().getSerialNumber()).isEqualTo(summaries[i].getSerialNumber()); org.bouncycastle.cert.ocsp.CertificateStatus ocspCertificateStatus = getOCSPCertificateStatus(summaries[i]).getCertificateStatus(); if (ocspCertificateStatus == GOOD) { assertThat(response.getCertStatus()).isEqualTo(GOOD); // They implemented GOOD as null ... really? ..... } else { assertThat(response.getCertStatus()).isEqualToComparingFieldByField(ocspCertificateStatus); } assertThat(response.getThisUpdate()).isEqualToIgnoringMillis(summaries[i].getThisUpdateTime().toDate()); assertThat(response.getNextUpdate()) .hasSecond((summaries[i].getThisUpdateTime().getSecondOfMinute() + REFRESH_TIME) % 60); } }