blob: 8095d53c3a3e475cd0b281f0f807aad210356d65 [file] [log] [blame]
package org.bouncycastle.asn1.tsp;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.cms.Attributes;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.SignedData;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
/**
* Implementation of the Archive Timestamp type defined in RFC4998.
* {@see <a href="https://tools.ietf.org/html/rfc4998">RFC 4998</a>}
* <p>
* ASN.1 Archive Timestamp
* <p>
* ArchiveTimeStamp ::= SEQUENCE {
* digestAlgorithm [Ø] AlgorithmIdentifier OPTIONAL,
* attributes [1] Attributes OPTIONAL,
* reducedHashtree [2] SEQUENCE OF PartialHashtree OPTIONAL,
* timeStamp ContentInfo}
* <p>
* PartialHashtree ::= SEQUENCE OF OCTET STRING
* <p>
* Attributes ::= SET SIZE (1..MAX) OF Attribute
*/
public class ArchiveTimeStamp
extends ASN1Object
{
private AlgorithmIdentifier digestAlgorithm;
private Attributes attributes;
private ASN1Sequence reducedHashTree;
private ContentInfo timeStamp;
/**
* Return an ArchiveTimestamp from the given object.
*
* @param obj the object we want converted.
* @return an ArchiveTimestamp instance, or null.
* @throws IllegalArgumentException if the object cannot be converted.
*/
public static ArchiveTimeStamp getInstance(final Object obj)
{
if (obj instanceof ArchiveTimeStamp)
{
return (ArchiveTimeStamp)obj;
}
else if (obj != null)
{
return new ArchiveTimeStamp(ASN1Sequence.getInstance(obj));
}
return null;
}
public ArchiveTimeStamp(
AlgorithmIdentifier digestAlgorithm,
PartialHashtree[] reducedHashTree,
ContentInfo timeStamp)
{
this.digestAlgorithm = digestAlgorithm;
this.reducedHashTree = new DERSequence(reducedHashTree);
this.timeStamp = timeStamp;
}
public ArchiveTimeStamp(
AlgorithmIdentifier digestAlgorithm,
Attributes attributes,
PartialHashtree[] reducedHashTree,
ContentInfo timeStamp)
{
this.digestAlgorithm = digestAlgorithm;
this.attributes = attributes;
this.reducedHashTree = new DERSequence(reducedHashTree);
this.timeStamp = timeStamp;
}
public ArchiveTimeStamp(
ContentInfo timeStamp)
{
this.timeStamp = timeStamp;
}
private ArchiveTimeStamp(final ASN1Sequence sequence)
{
if (sequence.size() < 1 || sequence.size() > 4)
{
throw new IllegalArgumentException("wrong sequence size in constructor: " + sequence.size());
}
for (int i = 0; i < sequence.size() - 1; i++)
{
Object obj = sequence.getObjectAt(i);
if (obj instanceof ASN1TaggedObject)
{
ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(obj);
switch (taggedObject.getTagNo())
{
case 0:
digestAlgorithm = AlgorithmIdentifier.getInstance(taggedObject, false);
break;
case 1:
attributes = Attributes.getInstance(taggedObject, false);
break;
case 2:
reducedHashTree = ASN1Sequence.getInstance(taggedObject, false);
break;
default:
throw new IllegalArgumentException("invalid tag no in constructor: "
+ taggedObject.getTagNo());
}
}
}
timeStamp = ContentInfo.getInstance(sequence.getObjectAt(sequence.size() - 1));
}
public AlgorithmIdentifier getDigestAlgorithmIdentifier()
{
if (digestAlgorithm != null)
{
return digestAlgorithm;
}
else
{
if (timeStamp.getContentType().equals(CMSObjectIdentifiers.signedData))
{
SignedData tsData = SignedData.getInstance(timeStamp.getContent());
if (tsData.getEncapContentInfo().getContentType().equals(PKCSObjectIdentifiers.id_ct_TSTInfo))
{
TSTInfo tstData = TSTInfo.getInstance(tsData.getEncapContentInfo());
return tstData.getMessageImprint().getHashAlgorithm();
}
else
{
throw new IllegalStateException("cannot parse time stamp");
}
}
else
{
throw new IllegalStateException("cannot identify algorithm identifier for digest");
}
}
}
/**
* Return the contents of the digestAlgorithm field - null if not set.
*
* @return the contents of the digestAlgorithm field, or null if not set.
*/
public AlgorithmIdentifier getDigestAlgorithm()
{
return digestAlgorithm;
}
public PartialHashtree[] getReducedHashTree()
{
if (reducedHashTree == null)
{
return null;
}
PartialHashtree[] rv = new PartialHashtree[reducedHashTree.size()];
for (int i = 0; i != rv.length; i++)
{
rv[i] = PartialHashtree.getInstance(reducedHashTree.getObjectAt(i));
}
return rv;
}
public ContentInfo getTimeStamp()
{
return timeStamp;
}
public ASN1Primitive toASN1Primitive()
{
ASN1EncodableVector v = new ASN1EncodableVector();
if (digestAlgorithm != null)
{
v.add(new DERTaggedObject(false, 0, digestAlgorithm));
}
if (attributes != null)
{
v.add(new DERTaggedObject(false, 1, attributes));
}
if (reducedHashTree != null)
{
v.add(new DERTaggedObject(false, 2, reducedHashTree));
}
v.add(timeStamp);
return new DERSequence(v);
}
}