/** * method for JSP to create valid TimeStampRequest * * @param file * @param tsr * @return */ public TimeStampRequest createCorrespondingTSQ(byte[] file, TimeStampResponse tsr) { // get hash algorithm ASN1ObjectIdentifier algID = tsr.getTimeStampToken().getTimeStampInfo().getMessageImprintAlgOID(); GeneralDigest digestAlgorithm = getDigestAlg(algID); logger.info( "The timestamp's algorithm was recognized as {}.", digestAlgorithm.getAlgorithmName()); // create new hashed request byte[] digest = calculateMessageDigest(file, digestAlgorithm); TimeStampRequest tsq = getTSRequest(digest, algID); return tsq; }
/** * prints details of received TimeStamp * * @param tsr {@link TimeStampResponse} */ private void logResponse(final TimeStampResponse tsr) { logger.info("Timestamp: {}", tsr.getTimeStampToken().getTimeStampInfo().getGenTime()); logger.info("TSA: {}", tsr.getTimeStampToken().getTimeStampInfo().getTsa()); logger.info("Serial number: {}", tsr.getTimeStampToken().getTimeStampInfo().getSerialNumber()); logger.info("Policy: {}", tsr.getTimeStampToken().getTimeStampInfo().getPolicy()); }
public byte[] getTimeStampToken(byte[] digest) throws NoSuchAlgorithmException, UnsupportedEncodingException, TSPException { TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator(); tsqGenerator.setCertReq(true); if (tsaOid != null) tsqGenerator.setReqPolicy(tsaOid); TimeStampRequest tsReq = tsqGenerator.generate(TSPAlgorithms.SHA1, digest, BigInteger.valueOf(100)); byte[] respBytes; try { byte[] requestBytes = tsReq.getEncoded(); URL url = new URL(tsaURL); HttpsURLConnection tsaConnection = (HttpsURLConnection) url.openConnection(); String user_pass = Base64.encodeToString((tsaUsername + ":" + tsaPassword).getBytes(), 0); tsaConnection.setRequestProperty("Authorization", "Basic " + user_pass); tsaConnection.setDoInput(true); tsaConnection.setDoOutput(true); tsaConnection.setUseCaches(false); tsaConnection.setRequestProperty("Content-Type", "application/timestamp-query"); tsaConnection.setRequestProperty("Content-Transfer-Encoding", "binary"); OutputStream out = tsaConnection.getOutputStream(); out.write(requestBytes); out.close(); InputStream inp = tsaConnection.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = inp.read(buffer, 0, buffer.length)) >= 0) { baos.write(buffer, 0, bytesRead); } respBytes = baos.toByteArray(); String encoding = tsaConnection.getContentEncoding(); if (encoding != null && encoding.equalsIgnoreCase("base64")) { respBytes = Base64.decode(new String(respBytes), 0); } if (respBytes == null) { String error = "Error: Impossible to get TSA response"; Log.e(TAG, error); } TimeStampResponse tsRes = new TimeStampResponse(respBytes); tsRes.validate(tsReq); PKIFailureInfo failure = tsRes.getFailInfo(); int value = (failure == null) ? 0 : failure.intValue(); if (value != 0) { String error = "Error: Invalid TSA response (" + tsRes.getStatusString() + ")"; Log.e(TAG, error); return null; } TimeStampToken myTSToken = tsRes.getTimeStampToken(); if (myTSToken == null) { String error = "Error: Invalid TSA response (NULL)"; Log.e(TAG, error); return null; } return myTSToken.getEncoded(); } catch (IOException | TSPException e) { Log.e(TAG, e.getMessage()); } return null; }
/** * Main method for validating files with stamps. It serves as an example of whole process in one * go. * * @param originalFile * @param timeStamp * @throws IOException * @throws TSPException * @throws CertificateException * @throws CertificateEncodingException * @throws OperatorCreationException */ public void verify(InputStream originalFile, InputStream timeStamp) throws IOException, TSPException, CertificateException, CertificateEncodingException, OperatorCreationException { logger.entry(); // open files byte[] file = getBytesFromInputStream(originalFile); TimeStampResponse tsr = parseTSR(timeStamp); logger.info("The timestamp was sucessfully opened."); logResponse(tsr); // get hash algorithm ASN1ObjectIdentifier algID = tsr.getTimeStampToken().getTimeStampInfo().getMessageImprintAlgOID(); GeneralDigest digestAlgorithm = getDigestAlg(algID); logger.info( "The timestamp's algorithm was recognized as {}.", digestAlgorithm.getAlgorithmName()); // create new hashed request byte[] digest = calculateMessageDigest(file, digestAlgorithm); TimeStampRequest tsq = getTSRequest(digest, algID); logger.info( "The timestamp fits the file (the file was not changed), now verifying certificates.."); InputStream is = null; if (is == null) { throw new UnsupportedOperationException( "Timestamp fits the file (the file was not changed), certificate not implemented yet."); } // <editor-fold defaultstate="collapsed" desc="varianta 1 - ze souboru"> CertificateFactory factory; X509Certificate cert; try { factory = CertificateFactory.getInstance("X.509"); cert = (X509Certificate) factory.generateCertificate(null); // TODO: get inputstream } catch (CertificateException e) { logger.catching(e); throw e; } // RSA Signature processing with BC X509CertificateHolder holder; SignerInformationVerifier siv; try { holder = new X509CertificateHolder(cert.getEncoded()); siv = new BcRSASignerInfoVerifierBuilder( new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), new DefaultDigestAlgorithmIdentifierFinder(), new BcDigestCalculatorProvider()) .build(holder); } catch (CertificateEncodingException | OperatorCreationException e) { logger.catching(e); throw e; } // Signature processing with JCA and other provider // X509CertificateHolder holderJca = new JcaX509CertificateHolder(cert); // SignerInformationVerifier sivJca = new // JcaSimpleSignerInfoVerifierBuilder().setProvider("anotherprovider").build(holderJca); try { tsr.getTimeStampToken().validate(siv); } catch (TSPException e) { logger.catching(e); throw e; } /* konec varianty 1 */ // </editor-fold> // <editor-fold defaultstate="collapsed" desc="varianta 2 - z razitka"> /*/ get certificates CollectionStore certs = (CollectionStore) tst.getCertificates(); SignerInformationStore signers = tst.toCMSSignedData().getSignerInfos(); int certsCount = 0; for (Iterator it = certs.iterator(); it.hasNext();) { certsCount++; // stupid hack to get actual number of certificates } if (certsCount < 1) { logger.error("No certificate found."); return; } for (SignerInformation signer : signers) { Collection<X509Certificate> col = certs.getMatches(signer.getSID()); X509Certificate[] signerCerts = new X509Certificate[0]; col.toArray(signerCerts); if (signerCerts.length != 1) { logger.error("Expected only one certificate per signer."); return; } try { signerCerts[0].checkValidity(); } catch (CertificateExpiredException | CertificateNotYetValidException ex) { java.util.logging.Logger.getLogger(TSAConnector.class.getName()).log(Level.SEVERE, null, ex); } // signer.verify(signerCerts[0]); // should verify that the timestamp is signed correctly } /* konec varianty 2 */ // </editor-fold> logger.info("All certificates successfully verified, the timestamp is trusted."); logger.exit(); }
public byte[] timeStamp(byte[] data, RevocationData revocationData) throws Exception { // digest the message MessageDigest messageDigest = MessageDigest.getInstance(this.digestAlgo); byte[] digest = messageDigest.digest(data); // generate the TSP request BigInteger nonce = new BigInteger(128, new SecureRandom()); TimeStampRequestGenerator requestGenerator = new TimeStampRequestGenerator(); requestGenerator.setCertReq(true); if (null != this.requestPolicy) { requestGenerator.setReqPolicy(this.requestPolicy); } TimeStampRequest request = requestGenerator.generate(this.digestAlgoOid, digest, nonce); byte[] encodedRequest = request.getEncoded(); // create the HTTP client HttpClient httpClient = new HttpClient(); if (null != this.username) { Credentials credentials = new UsernamePasswordCredentials(this.username, this.password); httpClient.getState().setCredentials(AuthScope.ANY, credentials); } if (null != this.proxyHost) { httpClient.getHostConfiguration().setProxy(this.proxyHost, this.proxyPort); } // create the HTTP POST request PostMethod postMethod = new PostMethod(this.tspServiceUrl); RequestEntity requestEntity = new ByteArrayRequestEntity(encodedRequest, "application/timestamp-query"); postMethod.addRequestHeader("User-Agent", this.userAgent); postMethod.setRequestEntity(requestEntity); // invoke TSP service int statusCode = httpClient.executeMethod(postMethod); if (HttpStatus.SC_OK != statusCode) { LOG.error("Error contacting TSP server " + this.tspServiceUrl); throw new Exception("Error contacting TSP server " + this.tspServiceUrl); } // HTTP input validation Header responseContentTypeHeader = postMethod.getResponseHeader("Content-Type"); if (null == responseContentTypeHeader) { throw new RuntimeException("missing Content-Type header"); } String contentType = responseContentTypeHeader.getValue(); if (!contentType.startsWith("application/timestamp-reply")) { LOG.debug("response content: " + postMethod.getResponseBodyAsString()); throw new RuntimeException("invalid Content-Type: " + contentType); } if (0 == postMethod.getResponseContentLength()) { throw new RuntimeException("Content-Length is zero"); } // TSP response parsing and validation InputStream inputStream = postMethod.getResponseBodyAsStream(); TimeStampResponse timeStampResponse = new TimeStampResponse(inputStream); timeStampResponse.validate(request); if (0 != timeStampResponse.getStatus()) { LOG.debug("status: " + timeStampResponse.getStatus()); LOG.debug("status string: " + timeStampResponse.getStatusString()); PKIFailureInfo failInfo = timeStampResponse.getFailInfo(); if (null != failInfo) { LOG.debug("fail info int value: " + failInfo.intValue()); if (PKIFailureInfo.unacceptedPolicy == failInfo.intValue()) { LOG.debug("unaccepted policy"); } } throw new RuntimeException( "timestamp response status != 0: " + timeStampResponse.getStatus()); } TimeStampToken timeStampToken = timeStampResponse.getTimeStampToken(); SignerId signerId = timeStampToken.getSID(); BigInteger signerCertSerialNumber = signerId.getSerialNumber(); X500Principal signerCertIssuer = signerId.getIssuer(); LOG.debug("signer cert serial number: " + signerCertSerialNumber); LOG.debug("signer cert issuer: " + signerCertIssuer); // TSP signer certificates retrieval CertStore certStore = timeStampToken.getCertificatesAndCRLs("Collection", BouncyCastleProvider.PROVIDER_NAME); Collection<? extends Certificate> certificates = certStore.getCertificates(null); X509Certificate signerCert = null; Map<String, X509Certificate> certificateMap = new HashMap<String, X509Certificate>(); for (Certificate certificate : certificates) { X509Certificate x509Certificate = (X509Certificate) certificate; if (signerCertIssuer.equals(x509Certificate.getIssuerX500Principal()) && signerCertSerialNumber.equals(x509Certificate.getSerialNumber())) { signerCert = x509Certificate; } String ski = Hex.encodeHexString(getSubjectKeyId(x509Certificate)); certificateMap.put(ski, x509Certificate); LOG.debug( "embedded certificate: " + x509Certificate.getSubjectX500Principal() + "; SKI=" + ski); } // TSP signer cert path building if (null == signerCert) { throw new RuntimeException("TSP response token has no signer certificate"); } List<X509Certificate> tspCertificateChain = new LinkedList<X509Certificate>(); X509Certificate certificate = signerCert; do { LOG.debug("adding to certificate chain: " + certificate.getSubjectX500Principal()); tspCertificateChain.add(certificate); if (certificate.getSubjectX500Principal().equals(certificate.getIssuerX500Principal())) { break; } String aki = Hex.encodeHexString(getAuthorityKeyId(certificate)); certificate = certificateMap.get(aki); } while (null != certificate); // verify TSP signer signature timeStampToken.validate(tspCertificateChain.get(0), BouncyCastleProvider.PROVIDER_NAME); // verify TSP signer certificate this.validator.validate(tspCertificateChain, revocationData); LOG.debug("time-stamp token time: " + timeStampToken.getTimeStampInfo().getGenTime()); byte[] timestamp = timeStampToken.getEncoded(); return timestamp; }