001: package org.bouncycastle.tsp;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.ByteArrayOutputStream;
005: import java.io.InputStream;
006: import java.io.IOException;
007: import java.security.MessageDigest;
008:
009: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
010: import org.bouncycastle.asn1.tsp.TimeStampResp;
011: import org.bouncycastle.asn1.cmp.PKIFailureInfo;
012: import org.bouncycastle.asn1.cmp.PKIFreeText;
013: import org.bouncycastle.asn1.cmp.PKIStatus;
014: import org.bouncycastle.asn1.ASN1InputStream;
015: import org.bouncycastle.asn1.ASN1OutputStream;
016:
017: /**
018: * Base class for an RFC 3161 Time Stamp Response object.
019: */
020: public class TimeStampResponse {
021: TimeStampResp resp;
022: TimeStampToken timeStampToken;
023:
024: public TimeStampResponse(TimeStampResp resp) throws TSPException,
025: IOException {
026: this .resp = resp;
027:
028: if (resp.getTimeStampToken() != null) {
029: timeStampToken = new TimeStampToken(resp
030: .getTimeStampToken());
031: }
032: }
033:
034: /**
035: * Create a TimeStampResponse from a byte array containing an ASN.1 encoding.
036: *
037: * @param resp the byte array containing the encoded response.
038: * @throws TSPException if the response is malformed.
039: * @throws IOException if the byte array doesn't represent an ASN.1 encoding.
040: */
041: public TimeStampResponse(byte[] resp) throws TSPException,
042: IOException {
043: this (new ByteArrayInputStream(resp));
044: }
045:
046: /**
047: * Create a TimeStampResponse from an input stream containing an ASN.1 encoding.
048: *
049: * @param in the input stream containing the encoded response.
050: * @throws TSPException if the response is malformed.
051: * @throws IOException if the stream doesn't represent an ASN.1 encoding.
052: */
053: public TimeStampResponse(InputStream in) throws TSPException,
054: IOException {
055: this (readTimeStampResp(in));
056: }
057:
058: private static TimeStampResp readTimeStampResp(InputStream in)
059: throws IOException, TSPException {
060: try {
061: return TimeStampResp.getInstance(new ASN1InputStream(in)
062: .readObject());
063: } catch (IllegalArgumentException e) {
064: throw new TSPException(
065: "malformed timestamp response: " + e, e);
066: } catch (ClassCastException e) {
067: throw new TSPException(
068: "malformed timestamp response: " + e, e);
069: }
070: }
071:
072: public int getStatus() {
073: return resp.getStatus().getStatus().intValue();
074: }
075:
076: public String getStatusString() {
077: if (resp.getStatus().getStatusString() != null) {
078: StringBuffer statusStringBuf = new StringBuffer();
079: PKIFreeText text = resp.getStatus().getStatusString();
080: for (int i = 0; i != text.size(); i++) {
081: statusStringBuf.append(text.getStringAt(i).getString());
082: }
083: return statusStringBuf.toString();
084: } else {
085: return null;
086: }
087: }
088:
089: public PKIFailureInfo getFailInfo() {
090: if (resp.getStatus().getFailInfo() != null) {
091: return new PKIFailureInfo(resp.getStatus().getFailInfo());
092: }
093:
094: return null;
095: }
096:
097: public TimeStampToken getTimeStampToken() {
098: return timeStampToken;
099: }
100:
101: /**
102: * Check this response against to see if it a well formed response for
103: * the passed in request. Validation will include checking the time stamp
104: * token if the response status is GRANTED or GRANTED_WITH_MODS.
105: *
106: * @param request the request to be checked against
107: * @throws TSPException if the request can not match this response.
108: */
109: public void validate(TimeStampRequest request) throws TSPException {
110: TimeStampToken tok = this .getTimeStampToken();
111:
112: if (tok != null) {
113: TimeStampTokenInfo tstInfo = tok.getTimeStampInfo();
114:
115: if (request.getNonce() != null
116: && !request.getNonce().equals(tstInfo.getNonce())) {
117: throw new TSPValidationException(
118: "response contains wrong nonce value.");
119: }
120:
121: if (this .getStatus() != PKIStatus.GRANTED
122: && this .getStatus() != PKIStatus.GRANTED_WITH_MODS) {
123: throw new TSPValidationException(
124: "time stamp token found in failed request.");
125: }
126:
127: if (!MessageDigest.isEqual(request
128: .getMessageImprintDigest(), tstInfo
129: .getMessageImprintDigest())) {
130: throw new TSPValidationException(
131: "response for different message imprint digest.");
132: }
133:
134: if (!tstInfo.getMessageImprintAlgOID().equals(
135: request.getMessageImprintAlgOID())) {
136: throw new TSPValidationException(
137: "response for different message imprint algorithm.");
138: }
139:
140: if (tok.getSignedAttributes().get(
141: PKCSObjectIdentifiers.id_aa_signingCertificate) == null) {
142: throw new TSPValidationException(
143: "no signing certificate attribute present.");
144: }
145:
146: if (request.getReqPolicy() != null
147: && !request.getReqPolicy().equals(
148: tstInfo.getPolicy())) {
149: throw new TSPValidationException(
150: "TSA policy wrong for request.");
151: }
152: } else if (this .getStatus() == PKIStatus.GRANTED
153: || this .getStatus() == PKIStatus.GRANTED_WITH_MODS) {
154: throw new TSPValidationException(
155: "no time stamp token found and one expected.");
156: }
157: }
158:
159: /**
160: * return the ASN.1 encoded representation of this object.
161: */
162: public byte[] getEncoded() throws IOException {
163: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
164: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
165:
166: aOut.writeObject(resp);
167:
168: return bOut.toByteArray();
169: }
170: }
|