
com.gc.iotools.fmt.decoders.TimeStampedDataParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wazformat Show documentation
Show all versions of wazformat Show documentation
Format identification utilities
The newest version!
package com.gc.iotools.fmt.decoders;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1SequenceParser;
import org.bouncycastle.asn1.ASN1StreamParser;
import org.bouncycastle.asn1.BEROctetStringParser;
import org.bouncycastle.asn1.BERSequenceParser;
import org.bouncycastle.asn1.BERTaggedObjectParser;
import org.bouncycastle.asn1.BERTags;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DEROctetStringParser;
import org.bouncycastle.asn1.DERSequenceParser;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.ContentInfoParser;
import org.bouncycastle.asn1.cms.Evidence;
import org.bouncycastle.asn1.cms.MetaData;
import org.bouncycastle.asn1.cms.TimeStampAndCRL;
import org.bouncycastle.asn1.cms.TimeStampTokenEvidence;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.tsp.TimeStampToken;
/**
* Stream processing of a {@link org.bouncycastle.asn1.cms.TimeStampedData} object.
*
* @author Giacomo Boccardo ([email protected])
*
* See RFC 5544.
*
*
* ContentInfo ::= SEQUENCE {
* contentType ContentType,
* content [0] EXPLICIT ANY DEFINED BY contentType
* }
*
* ContentType ::= OBJECT IDENTIFIER
*
* id-ct-timestampedData OBJECT IDENTIFIER ::= {
* iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
* pkcs9(9) id-smime(16) id-ct(1) 31 }
*
* TimeStampedData ::= SEQUENCE {
* version INTEGER { v1(1) },
* dataUri IA5String OPTIONAL,
* metaData MetaData OPTIONAL,
* content OCTET STRING OPTIONAL,
* temporalEvidence Evidence
* }
*
* MetaData ::= SEQUENCE {
* hashProtected BOOLEAN,
* fileName UTF8String OPTIONAL,
* mediaType IA5String OPTIONAL,
* otherMetaData Attributes OPTIONAL
* }
*
* Attributes ::=
* SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
*
* Evidence ::= CHOICE {
* tstEvidence [0] TimeStampTokenEvidence, -- see RFC 3161
* ersEvidence [1] EvidenceRecord, -- see RFC 4998
* otherEvidence [2] OtherEvidence
* }
*
* TimeStampTokenEvidence ::=
* SEQUENCE SIZE(1..MAX) OF TimeStampAndCRL
*
* TimeStampAndCRL ::= SEQUENCE {
* timeStamp TimeStampToken, -- according to RFC 3161
* crl CertificateList OPTIONAL -- according to RFC 5280
* }
*
*
*/
public final class TimeStampedDataParser {
private ASN1SequenceParser tsdSeq;
private ASN1ObjectIdentifier contentType;
private ASN1Integer version;
private DERIA5String dataUri;
private MetaData metaData;
private InputStream contentAsIS;
private boolean contentISRead = false;
/**
* Instantiate a {@link TimeStampedDataParser} in order to stream process a TSD timestamp.
*
*
* Note: since it's a stream processing, the order in which the methods of this class are called is essential.
* In detail, you should follow these steps:
*
* - instantiate a {@link TimeStampedDataParser} object passing the {@link InputStream} of the TSD;
* - get the {@link InputStream} of the content using the method {@link #getContentAsIS()} and consume it
* completely (or you'll lose it after the following step);
* - get the array of the timestamps as {@link TimeStampToken} objects using the method
* {@link #getTimeStampTokens()}.
*
*
*
* @param tsdIS
* The {@link InputStream} of a {@link org.bouncycastle.asn1.cms.TimeStampedData} object.
* @throws IOException
* @throws TSPException
*/
public TimeStampedDataParser(final InputStream tsdIS) throws IOException {
final ASN1StreamParser asn1SP = new ASN1StreamParser(tsdIS);
try {
// ContentInfo
final ASN1SequenceParser contentInfoSeq = (ASN1SequenceParser) asn1SP.readObject();
final ContentInfoParser contentInfoParser = new ContentInfoParser(contentInfoSeq);
// ContentType
contentType = contentInfoParser.getContentType();
// Content (SEQUENCE) = TimeStampedData
final ASN1SequenceParser tsDataSeq = (ASN1SequenceParser) contentInfoParser.getContent(BERTags.SEQUENCE);
// TimeStampedData#version
version = (ASN1Integer) tsDataSeq.readObject();
// TimeStampedData#{dataUri, metaData, content}
ASN1Encodable o;
while ((o = tsDataSeq.readObject()) != null) {
if (o instanceof DERIA5String) {
dataUri = (DERIA5String) o;
} else if (o instanceof BERSequenceParser) {
metaData = MetaData.getInstance(((BERSequenceParser) o).toASN1Primitive());
} else if (o instanceof DERSequenceParser) {
metaData = MetaData.getInstance(((DERSequenceParser) o).toASN1Primitive());
} else if (o instanceof BEROctetStringParser) {
final InputStream contentIS = ((BEROctetStringParser) o).getOctetStream();
contentAsIS = contentIS;
// The Evidence field can't be read until the InputStream of
// the content is completely consumed.
break;
} else if (o instanceof DEROctetStringParser) {
final InputStream contentIS = ((DEROctetStringParser) o).getOctetStream();
contentAsIS = contentIS;
// The Evidence field can't be read until the InputStream of
// the content is completely consumed.
break;
} else if (o instanceof BERTaggedObjectParser) {
// TODO
// If we are here, there's no content and we are reading the
// Evidence field.
// The content could be retrieved using the URI in the field
// dataUri, if present.
throw new UnsupportedOperationException("Content field not present, retrieve it using the dataUri");
} else {
throw new IOException("The TimeStampedData object is malformed: [" + o + "]");
}
}
tsdSeq = tsDataSeq;
} catch (final IOException e) {
tsdSeq = null;
throw new IOException("The TSD can't be recognized", e);
}
}
public InputStream getContentAsIS() {
if (hasContentBeenRead()) {
throw new IllegalStateException("The stream processing doesn't allow to read the "
+ " content after the TimeStampToken(s) " + "(Evidence(s)) have been read");
}
return contentAsIS;
}
public ASN1ObjectIdentifier getContentType() {
return contentType;
}
public DERIA5String getDataUri() {
return dataUri;
}
public MetaData getMetaData() {
return metaData;
}
/**
* Retrieves the {@link TimeStampToken}s from the {@link TimeStampTokenEvidence}.
*
* Note: the stream processing requires to read the content field of the TSD before the {@link Evidence} field.
*
*
* @return the {@link TimeStampToken[]} contained in the {@link Evidence} field.
* @throws IOException
* @throws TSPException
*/
public TimeStampToken[] getTimeStampTokens() throws IOException, TSPException {
// Note: before reading the Evidence field the InputStream of the
// content must be completely consumed.
IOUtils.copy(contentAsIS, new NullOutputStream());
contentISRead = true;
// TimeStampedData#temporalEvidence
final ASN1Encodable o = tsdSeq.readObject();
final ASN1Encodable temporalEvidenceDER = ((BERTaggedObjectParser) o).toASN1Primitive();
if (temporalEvidenceDER == null) {
throw new TSPException("The Evidence field must me present.");
}
final Evidence temporalEvidence = Evidence.getInstance(temporalEvidenceDER);
if (temporalEvidence == null) {
throw new IOException("The Evidence field is malformed.");
}
// TimeStampTokenEvidence
final TimeStampTokenEvidence tstEvidence = temporalEvidence.getTstEvidence();
if (tstEvidence == null) {
throw new TSPException("The Evidence field must contain a " + "TimeStampTokenEvidence.");
}
// TimeStampTokenEvidence#TimeStampAndCRL[]
final TimeStampAndCRL[] timeStampAndCRLArray = tstEvidence.toTimeStampAndCRLArray();
if (timeStampAndCRLArray.length == 0) {
throw new IOException("The TimeStampTokenEvidence must contain " + " at least a TimeStampAndCRL object.");
}
final ArrayList tstArr = new ArrayList();
for (final TimeStampAndCRL tsAndCRL : timeStampAndCRLArray) {
// TimeStampAndCRL#TimeStampToken
final ContentInfo timeStamp = tsAndCRL.getTimeStampToken();
if (timeStamp == null) {
throw new IOException("The TimeStampAndCRL must contain a" + " ContentInfo object.");
}
TimeStampToken timeStampToken = null;
try {
timeStampToken = new TimeStampToken(timeStamp);
} catch (final Exception e) {
throw new IOException("The TimeStampToken object is malformed: " + e, e);
}
tstArr.add(timeStampToken);
}
return tstArr.toArray(new TimeStampToken[tstArr.size()]);
}
public ASN1Integer getVersion() {
return version;
}
public boolean hasContentBeenRead() {
return contentISRead;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy