org.bouncycastle.tsp.TimeStampResponseGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.bouncycastle.tsp.TimeStampResponseGenerator.java

Source

package org.bouncycastle.tsp;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.DLSequence;
import org.bouncycastle.asn1.cmp.PKIFailureInfo;
import org.bouncycastle.asn1.cmp.PKIFreeText;
import org.bouncycastle.asn1.cmp.PKIStatus;
import org.bouncycastle.asn1.cmp.PKIStatusInfo;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.tsp.TimeStampResp;
import org.bouncycastle.asn1.x509.Extensions;

/**
 * Generator for RFC 3161 Time Stamp Responses.
 * <p>
 * New generate methods have been introduced to give people more control over what ends up in the message.
 * Unfortunately it turns out that in some cases fields like statusString must be left out otherwise a an
 * otherwise valid timestamp will be rejected.
 * </p>
 * If you're after the most control with generating a response use:
 * <pre>
 *    TimeStampResponse tsResp;
 *
 *    try
 *    {
 *       tsResp = tsRespGen.generateGrantedResponse(request, new BigInteger("23"), new Date());
 *    }
 *    catch (Exception e)
 *    {
 *        tsResp = tsRespGen.generateRejectedResponse(e);
 *    }
 * </pre>
 * The generate method does this, but provides a status string of "Operation Okay".
 * <p>
 * It should be pointed out that generateRejectedResponse() may also, on very rare occasions throw a TSPException.
 * In the event that happens, there's a serious internal problem with your responder.
 * </p>
 */
public class TimeStampResponseGenerator {
    int status;

    ASN1EncodableVector statusStrings;

    int failInfo;
    private TimeStampTokenGenerator tokenGenerator;
    private Set acceptedAlgorithms;
    private Set acceptedPolicies;
    private Set acceptedExtensions;

    /**
     *
     * @param tokenGenerator
     * @param acceptedAlgorithms a set of OIDs giving accepted algorithms.
     */
    public TimeStampResponseGenerator(TimeStampTokenGenerator tokenGenerator, Set acceptedAlgorithms) {
        this(tokenGenerator, acceptedAlgorithms, null, null);
    }

    /**
     *
     * @param tokenGenerator
     * @param acceptedAlgorithms a set of OIDs giving accepted algorithms.
     * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under.
     */
    public TimeStampResponseGenerator(TimeStampTokenGenerator tokenGenerator, Set acceptedAlgorithms,
            Set acceptedPolicies) {
        this(tokenGenerator, acceptedAlgorithms, acceptedPolicies, null);
    }

    /**
     *
     * @param tokenGenerator
     * @param acceptedAlgorithms a set of OIDs giving accepted algorithms.
     * @param acceptedPolicies if non-null a set of policies OIDs we are willing to sign under.
     * @param acceptedExtensions if non-null a set of extensions OIDs we are willing to accept.
     */
    public TimeStampResponseGenerator(TimeStampTokenGenerator tokenGenerator, Set acceptedAlgorithms,
            Set acceptedPolicies, Set acceptedExtensions) {
        this.tokenGenerator = tokenGenerator;
        this.acceptedAlgorithms = convert(acceptedAlgorithms);
        this.acceptedPolicies = convert(acceptedPolicies);
        this.acceptedExtensions = convert(acceptedExtensions);

        statusStrings = new ASN1EncodableVector();
    }

    private void addStatusString(String statusString) {
        statusStrings.add(new DERUTF8String(statusString));
    }

    private void setFailInfoField(int field) {
        failInfo = failInfo | field;
    }

    private PKIStatusInfo getPKIStatusInfo() {
        ASN1EncodableVector v = new ASN1EncodableVector();

        v.add(new ASN1Integer(status));

        if (statusStrings.size() > 0) {
            v.add(PKIFreeText.getInstance(new DERSequence(statusStrings)));
        }

        if (failInfo != 0) {
            DERBitString failInfoBitString = new FailInfo(failInfo);
            v.add(failInfoBitString);
        }

        return PKIStatusInfo.getInstance(new DERSequence(v));
    }

    /**
     * Return an appropriate TimeStampResponse.
     * <p>
     * If genTime is null a timeNotAvailable error response will be returned. Calling generate() is the
     * equivalent of:
     * <pre>
     *    TimeStampResponse tsResp;
     *
     *    try
     *    {
     *       tsResp = tsRespGen.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay");
     *    }
     *    catch (Exception e)
     *    {
     *        tsResp = tsRespGen.generateRejectedResponse(e);
     *    }
     * </pre>
     * @param request the request this response is for.
     * @param serialNumber serial number for the response token.
     * @param genTime generation time for the response token.
     * @return a TimeStampResponse.
     * @throws TSPException
     */
    public TimeStampResponse generate(TimeStampRequest request, BigInteger serialNumber, Date genTime)
            throws TSPException {
        try {
            return this.generateGrantedResponse(request, serialNumber, genTime, "Operation Okay");
        } catch (Exception e) {
            return this.generateRejectedResponse(e);
        }
    }

    /**
     * Return a granted response, if the passed in request passes validation.
     * <p>
     * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will
     * be thrown. The parent TSPException will only occur on some sort of system failure.
     * </p>
     * @param request the request this response is for.
     * @param serialNumber serial number for the response token.
     * @param genTime generation time for the response token.
     * @return  the TimeStampResponse with a status of  PKIStatus.GRANTED
     * @throws TSPException on validation exception or internal error.
     */
    public TimeStampResponse generateGrantedResponse(TimeStampRequest request, BigInteger serialNumber,
            Date genTime) throws TSPException {
        return generateGrantedResponse(request, serialNumber, genTime, null);
    }

    /**
     * Return a granted response, if the passed in request passes validation with the passed in status string.
     * <p>
     * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will
     * be thrown. The parent TSPException will only occur on some sort of system failure.
     * </p>
     * @param request the request this response is for.
     * @param serialNumber serial number for the response token.
     * @param genTime generation time for the response token.
     * @return  the TimeStampResponse with a status of  PKIStatus.GRANTED
     * @throws TSPException on validation exception or internal error.
     */
    public TimeStampResponse generateGrantedResponse(TimeStampRequest request, BigInteger serialNumber,
            Date genTime, String statusString) throws TSPException {
        return generateGrantedResponse(request, serialNumber, genTime, statusString, null);
    }

    /**
     * Return a granted response, if the passed in request passes validation with the passed in status string and extra extensions.
     * <p>
     * If genTime is null a timeNotAvailable or a validation exception occurs a TSPValidationException will
     * be thrown. The parent TSPException will only occur on some sort of system failure.
     * </p>
     * @param request the request this response is for.
     * @param serialNumber serial number for the response token.
     * @param genTime generation time for the response token.
     * @param additionalExtensions extra extensions to be added to the response token.
     * @return  the TimeStampResponse with a status of  PKIStatus.GRANTED
     * @throws TSPException on validation exception or internal error.
     */
    public TimeStampResponse generateGrantedResponse(TimeStampRequest request, BigInteger serialNumber,
            Date genTime, String statusString, Extensions additionalExtensions) throws TSPException {
        if (genTime == null) {
            throw new TSPValidationException("The time source is not available.", PKIFailureInfo.timeNotAvailable);
        }

        request.validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions);

        status = PKIStatus.GRANTED;
        statusStrings = new ASN1EncodableVector();

        if (statusString != null) {
            this.addStatusString(statusString);
        }

        PKIStatusInfo pkiStatusInfo = getPKIStatusInfo();

        ContentInfo tstTokenContentInfo;
        try {
            tstTokenContentInfo = tokenGenerator.generate(request, serialNumber, genTime, additionalExtensions)
                    .toCMSSignedData().toASN1Structure();
        } catch (TSPException e) {
            throw e;
        } catch (Exception e) {
            throw new TSPException("Timestamp token received cannot be converted to ContentInfo", e);
        }

        try {
            return new TimeStampResponse(new DLSequence(new ASN1Encodable[] { pkiStatusInfo.toASN1Primitive(),
                    tstTokenContentInfo.toASN1Primitive() }));
        } catch (IOException e) {
            throw new TSPException("created badly formatted response!");
        }
    }

    /**
     * Generate a generic rejection response based on a TSPValidationException or
     * an Exception. Exceptions which are not an instance of TSPValidationException
     * will be treated as systemFailure. The return value of exception.getMessage() will
     * be used as the status string for the response.
     *
     * @param exception the exception thrown on validating the request.
     * @return a TimeStampResponse.
     * @throws TSPException if a failure response cannot be generated.
     */
    public TimeStampResponse generateRejectedResponse(Exception exception) throws TSPException {
        if (exception instanceof TSPValidationException) {
            return generateFailResponse(PKIStatus.REJECTION, ((TSPValidationException) exception).getFailureCode(),
                    exception.getMessage());
        } else {
            return generateFailResponse(PKIStatus.REJECTION, PKIFailureInfo.systemFailure, exception.getMessage());
        }
    }

    /**
     * Generate a non-granted TimeStampResponse with chosen status and FailInfoField.
     * 
     * @param status the PKIStatus to set.
     * @param failInfoField the FailInfoField to set.
     * @param statusString an optional string describing the failure.
     * @return a TimeStampResponse with a failInfoField and optional statusString
     * @throws TSPException in case the response could not be created
     */
    public TimeStampResponse generateFailResponse(int status, int failInfoField, String statusString)
            throws TSPException {
        this.status = status;
        this.statusStrings = new ASN1EncodableVector();

        this.setFailInfoField(failInfoField);

        if (statusString != null) {
            this.addStatusString(statusString);
        }

        PKIStatusInfo pkiStatusInfo = getPKIStatusInfo();

        TimeStampResp resp = new TimeStampResp(pkiStatusInfo, null);

        try {
            return new TimeStampResponse(resp);
        } catch (IOException e) {
            throw new TSPException("created badly formatted response!");
        }
    }

    private Set convert(Set orig) {
        if (orig == null) {
            return orig;
        }

        Set con = new HashSet(orig.size());

        for (Iterator it = orig.iterator(); it.hasNext();) {
            Object o = it.next();

            if (o instanceof String) {
                con.add(new ASN1ObjectIdentifier((String) o));
            } else {
                con.add(o);
            }
        }

        return con;
    }

    class FailInfo extends DERBitString {
        FailInfo(int failInfoValue) {
            super(getBytes(failInfoValue), getPadBits(failInfoValue));
        }
    }
}