/*
* TimestampInfo.java
* PROJECT: JDigiDoc
* DESCRIPTION: Holds data about timestamp source.
* AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
*==================================================
* Copyright (C) AS Sertifitseerimiskeskus
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* GNU Lesser General Public Licence is available at
* http://www.gnu.org/copyleft/lesser.html
*==================================================
*/
package es.uji.security.crypto.openxades.digidoc;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import es.uji.security.crypto.openxades.digidoc.utils.ConvertUtils;
import es.uji.security.crypto.timestamp.TSResponse;
import es.uji.security.crypto.timestamp.TimestampToken;
import es.uji.security.util.Base64;
//import org.bouncycastle.cms.SignerId;
//import org.bouncycastle.cms.CMSSignedData;
/**
* Models the ETSI timestamp element(s) Holds timestamp info and TS_RESP response.
*
* @author Veiko Sinivee
* @version 1.0
*/
public class TimestampInfo
{
/** elements Id atribute */
private String m_id;
/** parent object - Signature ref */
private Signature m_signature;
/** timestamp type */
private int m_type;
/** Include sublements */
private ArrayList m_includes;
/** timestamp response */
private TSResponse m_tsResp;
/** real hash calculated over the corresponding xml block */
private byte[] m_hash;
/** possible values for type atribute */
public static final int TIMESTAMP_TYPE_UNKNOWN = 0;
public static final int TIMESTAMP_TYPE_ALL_DATA_OBJECTS = 1;
public static final int TIMESTAMP_TYPE_INDIVIDUAL_DATA_OBJECTS = 2;
public static final int TIMESTAMP_TYPE_SIGNATURE = 3;
public static final int TIMESTAMP_TYPE_SIG_AND_REFS = 4;
public static final int TIMESTAMP_TYPE_REFS_ONLY = 5;
public static final int TIMESTAMP_TYPE_ARCHIVE = 6;
/**
* Creates new TimestampInfo and initializes everything to null
*/
public TimestampInfo()
{
m_id = null;
m_signature = null;
m_includes = null;
m_tsResp = null;
m_hash = null;
m_type = TIMESTAMP_TYPE_UNKNOWN;
}
/**
* Accessor for Signature attribute
*
* @return value of Signature attribute
*/
public Signature getSignature()
{
return m_signature;
}
/**
* Mutator for Signature attribute
*
* @param uprops
* value of Signature attribute
*/
public void setSignature(Signature sig)
{
m_signature = sig;
}
/**
* Creates new TimestampInfo
*
* @param id
* Id atribute value
* @param type
* timestamp type
* @throws DigiDocException
* for validation errors
*/
public TimestampInfo(String id, int type) throws DigiDocException
{
setId(id);
setType(type);
m_includes = null;
}
/**
* Accessor for Hash attribute
*
* @return value of Hash attribute
*/
public byte[] getHash()
{
return m_hash;
}
/**
* Mutator for Hash attribute
*
* @param str
* new value for Hash attribute
*/
public void setHash(byte[] b)
{
m_hash = b;
}
/**
* Accessor for Id attribute
*
* @return value of Id attribute
*/
public String getId()
{
return m_id;
}
/**
* Mutator for Id attribute
*
* @param str
* new value for Id attribute
* @throws DigiDocException
* for validation errors
*/
public void setId(String str) throws DigiDocException
{
DigiDocException ex = validateId(str);
if (ex != null)
throw ex;
m_id = str;
}
/**
* Helper method to validate Id
*
* @param str
* input data
* @return exception or null for ok
*/
private DigiDocException validateId(String str)
{
DigiDocException ex = null;
if (str == null)
ex = new DigiDocException(DigiDocException.ERR_TIMESTAMP_ID,
"Id atribute cannot be empty", null);
return ex;
}
/**
* Accessor for Type attribute
*
* @return value of Type attribute
*/
public int getType()
{
return m_type;
}
/**
* Mutator for Type attribute
*
* @param n
* new value for Type attribute
* @throws DigiDocException
* for validation errors
*/
public void setType(int n) throws DigiDocException
{
DigiDocException ex = validateType(n);
if (ex != null)
throw ex;
m_type = n;
}
/**
* Helper method to validate Type
*
* @param n
* input data
* @return exception or null for ok
*/
private DigiDocException validateType(int n)
{
DigiDocException ex = null;
if (n < TIMESTAMP_TYPE_ALL_DATA_OBJECTS || n > TIMESTAMP_TYPE_ARCHIVE)
ex = new DigiDocException(DigiDocException.ERR_TIMESTAMP_TYPE,
"Invalid timestamp type", null);
return ex;
}
/**
* Accessor for TimeStampResponse attribute
*
* @return value of TimeStampResponse attribute
*/
public TSResponse getTimeStampResponse()
{
return m_tsResp;
}
/**
* Mutator for TimeStampResponse attribute
*
* @param tsr
* new value for TimeStampResponse attribute
* @throws DigiDocException
* for validation errors
*/
public void setTimeStampResponse(TSResponse tsr) throws DigiDocException
{
DigiDocException ex = validateTimeStampResponse(tsr);
if (ex != null)
throw ex;
m_tsResp = tsr;
}
/**
* Helper method to validate TimeStampResponse
*
* @param tsr
* input data
* @return exception or null for ok
*/
private DigiDocException validateTimeStampResponse(TSResponse tsr)
{
DigiDocException ex = null;
if (tsr == null)
ex = new DigiDocException(DigiDocException.ERR_TIMESTAMP_RESP,
"timestamp cannot be null", null);
return ex;
}
/**
* return the count of IncludeInfo objects
*
* @return count of IncludeInfo objects
*/
public int countIncludeInfos()
{
return ((m_includes == null) ? 0 : m_includes.size());
}
/**
* Adds a new IncludeInfo object
*
* @param inc
* new object to be added
*/
public void addIncludeInfo(IncludeInfo inc)
{
if (m_includes == null)
m_includes = new ArrayList();
inc.setTimestampInfo(this);
m_includes.add(inc);
}
/**
* Retrieves IncludeInfo element with the desired index
*
* @param idx
* IncludeInfo index
* @return IncludeInfo element or null if not found
*/
public IncludeInfo getIncludeInfo(int idx)
{
if (m_includes != null && idx < m_includes.size())
{
return (IncludeInfo) m_includes.get(idx);
}
else
return null; // not found
}
/**
* Retrieves the last IncludeInfo element
*
* @return IncludeInfo element or null if not found
*/
public IncludeInfo getLastIncludeInfo()
{
if (m_includes != null && m_includes.size() > 0)
{
return (IncludeInfo) m_includes.get(m_includes.size() - 1);
}
else
return null; // not found
}
// /**
// * Retrieves timestamp responses signature algorithm OID.
// *
// * @return responses signature algorithm OID
// */
// public String getAlgorithmOid()
// {
// String oid = null;
// if (m_tsResp != null)
// {
// oid = m_tsResp.getTimeStampToken().getTimeStampInfo().getMessageImprintAlgOID();
// }
// return oid;
// }
//
// /**
// * Retrieves timestamp responses policy
// *
// * @return responses policy
// */
// public String getPolicy()
// {
// String oid = null;
// if (m_tsResp != null)
// {
// oid = m_tsResp.getTimeStampToken().getTimeStampInfo().getPolicy();
// }
// return oid;
// }
/**
* Retrieves timestamp issuing time
*
* @return timestamp issuing time
* @throws IOException
*/
public Date getTime()
{
Date d = null;
if (m_tsResp != null)
{
try
{
TimestampToken timestampToken = new TimestampToken(this.m_tsResp.getToken().getContentInfo().getData());
d = timestampToken.getDate();
}
catch (IOException e)
{
}
}
return d;
}
// /**
// * Retrieves timestamp msg-imprint digest
// *
// * @return timestamp msg-imprint digest
// */
// public byte[] getMessageImprint()
// {
// byte[] b = null;
// if (m_tsResp != null)
// {
// b = m_tsResp.getTimeStampToken().getTimeStampInfo().getMessageImprintDigest();
// }
// return b;
// }
//
// /**
// * Retrieves timestamp nonce
// *
// * @return timestamp nonce
// */
// public BigInteger getNonce()
// {
// BigInteger b = null;
// if (m_tsResp != null)
// {
// b = m_tsResp.getTimeStampToken().getTimeStampInfo().getNonce();
// }
// return b;
// }
/**
* Retrieves timestamp serial number
*
* @return timestamp serial number
*/
public BigInteger getSerialNumber()
{
BigInteger b = null;
if (m_tsResp != null)
{
try
{
b = m_tsResp.getToken().getContentInfo().getContent().getBigInteger();
}
catch (IOException e)
{
}
}
return b;
}
// /**
// * Retrieves timestamp is-ordered atribute
// *
// * @return timestamp is-ordered atribute
// */
// public boolean isOrdered()
// {
// boolean b = false;
// if (m_tsResp != null)
// {
// b = m_tsResp.getTimeStampToken().getTimeStampInfo().isOrdered();
// }
// return b;
// }
/**
* Retrieves timestamp is-ordered atribute
*
* @return timestamp is-ordered atribute
*/
public String getSignerCN()
{
String s = null;
if (m_tsResp != null)
{
// SignerId = m_tsResp.getTimeStampToken().getSignedAttributes()
// org.bouncycastle.cms.CMSSignedData cms = m_tsResp.getTimeStampToken().
}
return s;
}
/**
* Helper method to validate the whole TimestampInfo object
*
* @return a possibly empty list of DigiDocException objects
*/
public ArrayList validate()
{
ArrayList errs = new ArrayList();
DigiDocException ex = validateId(m_id);
if (ex != null)
errs.add(ex);
ex = validateType(m_type);
if (ex != null)
errs.add(ex);
return errs;
}
/**
* Converts the TimestampInfo to XML form
*
* @return XML representation of TimestampInfo
*/
public byte[] toXML() throws DigiDocException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try
{
switch (m_type)
{
case TIMESTAMP_TYPE_ALL_DATA_OBJECTS:
bos.write(ConvertUtils.str2data("<AllDataObjectsTimeStamp Id=\""));
break;
case TIMESTAMP_TYPE_INDIVIDUAL_DATA_OBJECTS:
bos.write(ConvertUtils.str2data("<IndividualDataObjectsTimeStamp Id=\""));
break;
case TIMESTAMP_TYPE_SIGNATURE:
bos.write(ConvertUtils.str2data("<SignatureTimeStamp Id=\""));
break;
case TIMESTAMP_TYPE_SIG_AND_REFS:
bos.write(ConvertUtils.str2data("<SigAndRefsStamp Id=\""));
break;
case TIMESTAMP_TYPE_REFS_ONLY:
bos.write(ConvertUtils.str2data("<RefsOnlyTimeStamp Id=\""));
break;
case TIMESTAMP_TYPE_ARCHIVE:
bos.write(ConvertUtils.str2data("<ArchiveTimeStamp Id=\""));
break;
}
bos.write(ConvertUtils.str2data(m_id));
bos.write(ConvertUtils.str2data("\">"));
for (int i = 0; i < countIncludeInfos(); i++)
{
IncludeInfo inc = getIncludeInfo(i);
bos.write(inc.toXML());
}
bos.write(ConvertUtils.str2data("<EncapsulatedTimeStamp>"));
if (m_tsResp != null){
// Moved to TSResponse.getEncodedToken
// byte[] resp= m_tsResp.getEncodedToken();
// byte[] status= {0x30, (byte)0x82, 0x03, (byte)0xA7, 0x30, 0x03, 0x02, 0x01, 0x00};
// byte[] completeEncodedToken= new byte[resp.length + status.length];
//
// System.arraycopy(status, 0, completeEncodedToken, 0, status.length);
// System.arraycopy(resp, 0, completeEncodedToken, status.length, resp.length);
bos.write(ConvertUtils.str2data(Base64.encodeBytes(m_tsResp.getEncodedToken())));
}
bos.write(ConvertUtils.str2data("</EncapsulatedTimeStamp>"));
switch (m_type)
{
case TIMESTAMP_TYPE_ALL_DATA_OBJECTS:
bos.write(ConvertUtils.str2data("</AllDataObjectsTimeStamp>"));
break;
case TIMESTAMP_TYPE_INDIVIDUAL_DATA_OBJECTS:
bos.write(ConvertUtils.str2data("</IndividualDataObjectsTimeStamp>"));
break;
case TIMESTAMP_TYPE_SIGNATURE:
bos.write(ConvertUtils.str2data("</SignatureTimeStamp>"));
break;
case TIMESTAMP_TYPE_SIG_AND_REFS:
bos.write(ConvertUtils.str2data("</SigAndRefsStamp>"));
break;
case TIMESTAMP_TYPE_REFS_ONLY:
bos.write(ConvertUtils.str2data("</RefsOnlyTimeStamp>"));
break;
case TIMESTAMP_TYPE_ARCHIVE:
bos.write(ConvertUtils.str2data("</ArchiveTimeStamp>"));
break;
}
}
catch (IOException ex)
{
DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT);
}
return bos.toByteArray();
}
/**
* Returns the stringified form of CompleteCertificateRefs
*
* @return CompleteCertificateRefs string representation
*/
public String toString()
{
String str = null;
try
{
str = new String(toXML());
}
catch (Exception ex)
{
}
return str;
}
}