com.github.beat.signer.pdf_signer.TSAClient.java Source code

Java tutorial

Introduction

Here is the source code for com.github.beat.signer.pdf_signer.TSAClient.java

Source

package com.github.beat.signer.pdf_signer;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.URLConnection;
import java.security.MessageDigest;
import java.security.SecureRandom;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.jcajce.provider.util.DigestFactory;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;

/**
 * Time Stamping Authority (TSA) Client [RFC 3161].
 * 
 * @author Vakhtang Koroghlishvili
 * @author John HewsonF
 */
public class TSAClient {
    private static final int CONNECT_TIMEOUT = 3000;

    private static final Log LOGGER = LogFactory.getLog(TSAClient.class);

    private final MessageDigest digest;

    private final TSAInformation tsaInfo;

    public TSAClient(TSAInformation tsaInfo, MessageDigest digest) {
        this.tsaInfo = tsaInfo;
        this.digest = digest;
    }

    /**
     *
     * @param messageImprint
     *            imprint of message contents
     * @return the encoded time stamp token
     * @throws IOException
     *             if there was an error with the connection or data from the
     *             TSA server, or if the time stamp response could not be
     *             validated
     */
    public byte[] getTimeStampToken(byte[] messageImprint) throws IOException {
        digest.reset();
        byte[] hash = digest.digest(messageImprint);

        // 32-bit cryptographic nonce
        // FIXME sicher??
        SecureRandom random = new SecureRandom();
        int nonce = random.nextInt();

        // generate TSA request
        TimeStampRequestGenerator tsaGenerator = new TimeStampRequestGenerator();
        tsaGenerator.setCertReq(true);
        ASN1ObjectIdentifier oid = getHashObjectIdentifier(digest.getAlgorithm());
        TimeStampRequest request = tsaGenerator.generate(oid, hash, BigInteger.valueOf(nonce));

        // get TSA response
        byte[] tsaResponse = getTSAResponse(request.getEncoded());

        TimeStampResponse response;
        try {
            response = new TimeStampResponse(tsaResponse);
            response.validate(request);
        } catch (TSPException e) {
            throw new IOException(e);
        }

        TimeStampToken token = response.getTimeStampToken();
        if (token == null) {
            throw new IOException("Response does not have a time stamp token");
        }

        return token.getEncoded();
    }

    // gets response data for the given encoded TimeStampRequest data
    // throws IOException if a connection to the TSA cannot be established
    private byte[] getTSAResponse(byte[] request) throws IOException {
        LOGGER.debug("Opening connection to TSA server");

        // FIXME: support proxy servers
        URLConnection connection = tsaInfo.getTsaUrl().openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setReadTimeout(CONNECT_TIMEOUT);
        connection.setConnectTimeout(CONNECT_TIMEOUT);
        connection.setRequestProperty("Content-Type", "application/timestamp-query");

        // TODO set accept header

        LOGGER.debug("Established connection to TSA server");

        String username = tsaInfo.getUsername();
        char[] password = tsaInfo.getPassword();
        if (StringUtils.isNotBlank(username) && password != null) {
            // FIXME this most likely wrong, e.g. set correct request property!
            // connection.setRequestProperty(username, password);
        }

        // read response
        sendRequest(request, connection);

        LOGGER.debug("Waiting for response from TSA server");

        byte[] response = getResponse(connection);

        LOGGER.debug("Received response from TSA server");

        return response;
    }

    private void sendRequest(byte[] request, URLConnection connection) throws IOException {
        OutputStream output = null;
        try {
            output = connection.getOutputStream();
            output.write(request);
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    private byte[] getResponse(URLConnection connection) throws IOException {
        InputStream input = null;
        try {
            input = connection.getInputStream();
            return IOUtils.toByteArray(input);
        } finally {
            IOUtils.closeQuietly(input);
        }
    }

    // returns the ASN.1 OID of the given hash algorithm
    private ASN1ObjectIdentifier getHashObjectIdentifier(String algorithm) {
        return DigestFactory.getOID(algorithm);
    }
}