/*
* SignedInfo.java
* PROJECT: JDigiDoc
* DESCRIPTION: Digi Doc functions for creating
* and reading signed documents.
* 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.io.Serializable;
import java.util.ArrayList;
import es.uji.security.crypto.openxades.digidoc.factory.CanonicalizationFactory;
import es.uji.security.crypto.openxades.digidoc.factory.FactoryManager;
/**
* Represents an XML-DSIG SignedInfo block
*
* @author Veiko Sinivee
* @version 1.0
*/
public class SignedInfo implements Serializable
{
/** reference to parent Signature object */
private Signature m_signature;
/** selected signature method */
private String m_signatureMethod;
/** selected canonicalization method */
private String m_canonicalizationMethod;
/** array of references */
private ArrayList m_references;
/** digest over the original bytes read from XML file */
private byte[] m_origDigest;
/**
* Creates new SignedInfo. Initializes everything to null.
*
* @param sig
* parent Signature reference
*/
public SignedInfo(Signature sig)
{
m_signature = sig;
m_signatureMethod = null;
m_canonicalizationMethod = null;
m_references = null;
m_origDigest = null;
}
/**
* Creates new SignedInfo
*
* @param sig
* parent Signature reference
* @param signatureMethod
* signature method uri
* @param canonicalizationMethod
* xml canonicalization method uri throws DigiDocException
*/
public SignedInfo(Signature sig, String signatureMethod, String canonicalizationMethod)
throws DigiDocException
{
m_signature = sig;
setSignatureMethod(signatureMethod);
setCanonicalizationMethod(canonicalizationMethod);
m_references = null;
m_origDigest = null;
}
/**
* Accessor for signature attribute
*
* @return value of signature attribute
*/
public Signature getSignature()
{
return m_signature;
}
/**
* Mutator for signature attribute
*
* @param sig
* new value for signature attribute
*/
public void setSignature(Signature sig)
{
m_signature = sig;
}
/**
* Accessor for origDigest attribute
*
* @return value of origDigest attribute
*/
public byte[] getOrigDigest()
{
return m_origDigest;
}
/**
* Mutator for origDigest attribute
*
* @param str
* new value for origDigest attribute
*/
public void setOrigDigest(byte[] data)
{
m_origDigest = data;
}
/**
* Accessor for signatureMethod attribute
*
* @return value of signatureMethod attribute
*/
public String getSignatureMethod()
{
return m_signatureMethod;
}
/**
* Mutator for signatureMethod attribute
*
* @param str
* new value for signatureMethod attribute
* @throws DigiDocException
* for validation errors
*/
public void setSignatureMethod(String str) throws DigiDocException
{
DigiDocException ex = validateSignatureMethod(str);
if (ex != null)
throw ex;
m_signatureMethod = str;
}
/**
* Helper method to validate a signature method
*
* @param str
* input data
* @return exception or null for ok
*/
private DigiDocException validateSignatureMethod(String str)
{
DigiDocException ex = null;
if (str == null || !str.equals(SignedDoc.RSA_SHA1_SIGNATURE_METHOD))
ex = new DigiDocException(DigiDocException.ERR_SIGNATURE_METHOD,
"Currently supports only RSA-SHA1 signatures", null);
return ex;
}
/**
* Accessor for canonicalizationMethod attribute
*
* @return value of canonicalizationMethod attribute
*/
public String getCanonicalizationMethod()
{
return m_canonicalizationMethod;
}
/**
* Mutator for canonicalizationMethod attribute
*
* @param str
* new value for canonicalizationMethod attribute
* @throws DigiDocException
* for validation errors
*/
public void setCanonicalizationMethod(String str) throws DigiDocException
{
DigiDocException ex = validateCanonicalizationMethod(str);
if (ex != null)
throw ex;
m_canonicalizationMethod = str;
}
/**
* Helper method to validate a signature method
*
* @param str
* input data
* @return exception or null for ok
*/
private DigiDocException validateCanonicalizationMethod(String str)
{
DigiDocException ex = null;
if (str == null || !str.equals(SignedDoc.CANONICALIZATION_METHOD_20010315))
ex = new DigiDocException(DigiDocException.ERR_CANONICALIZATION_METHOD,
"Currently supports only Canonical XML 1.0", null);
return ex;
}
/**
* Returns the count of Reference objects
*
* @return count of Reference objects
*/
public int countReferences()
{
return ((m_references == null) ? 0 : m_references.size());
}
/**
* Adds a new reference object
*
* @param ref
* Reference object to add
*/
public void addReference(Reference ref)
{
if (m_references == null)
m_references = new ArrayList();
m_references.add(ref);
}
/**
* Returns the desired Reference object
*
* @param idx
* index of the Reference object
* @return desired Reference object
*/
public Reference getReference(int idx)
{
return (Reference) m_references.get(idx);
}
/**
* Returns the desired Reference object
*
* @param df
* DataFile whose digest we are searching
* @return desired Reference object
*/
public Reference getReferenceForDataFile(DataFile df)
{
Reference ref = null;
for (int i = 0; (m_references != null) && (i < m_references.size()); i++)
{
Reference r1 = (Reference) m_references.get(i);
if (r1.getUri().equals("#" + df.getId()))
{
ref = r1;
break;
}
}
return ref;
}
/**
* Returns the desired Reference object
*
* @param sp
* SignedProperties whose digest we are searching
* @return desired Reference object
*/
public Reference getReferenceForSignedProperties(SignedProperties sp)
{
Reference ref = null;
for (int i = 0; (m_references != null) && (i < m_references.size()); i++)
{
Reference r1 = (Reference) m_references.get(i);
if (r1.getUri().equals("#" + sp.getId()))
{
ref = r1;
break;
}
}
return ref;
}
/**
* Returns the last Reference object
*
* @return desired Reference object
*/
public Reference getLastReference()
{
return (Reference) m_references.get(m_references.size() - 1);
}
/**
* Helper method to validate references
*
* @return exception or null for ok
*/
private ArrayList validateReferences()
{
ArrayList errs = new ArrayList();
if (countReferences() < 2)
{
errs.add(new DigiDocException(DigiDocException.ERR_NO_REFERENCES,
"At least 2 References are required!", null));
}
else
{
for (int i = 0; i < countReferences(); i++)
{
Reference ref = getReference(i);
ArrayList e = ref.validate();
if (!e.isEmpty())
errs.addAll(e);
}
}
return errs;
}
/**
* Helper method to validate the whole SignedInfo object
*
* @return a possibly empty list of DigiDocException objects
*/
public ArrayList validate()
{
ArrayList errs = new ArrayList();
DigiDocException ex = validateSignatureMethod(m_signatureMethod);
if (ex != null)
errs.add(ex);
ex = validateCanonicalizationMethod(m_canonicalizationMethod);
if (ex != null)
errs.add(ex);
ArrayList e = validateReferences();
if (!e.isEmpty())
errs.addAll(e);
return errs;
}
/**
* Calculates the digest of SignedInfo block If the user has set origDigest attribute which is
* allways done when reading the XML file, then this digest is returned otherwise a new digest
* is calculated.
*
* @return SignedInfo block digest
*/
public byte[] calculateDigest() throws DigiDocException
{
if (m_origDigest == null)
{
CanonicalizationFactory canFac = FactoryManager.getCanonicalizationFactory();
byte[] tmp = canFac.canonicalize(toXML(), SignedDoc.CANONICALIZATION_METHOD_20010315);
return SignedDoc.digest(tmp);
}
else
return m_origDigest;
}
/**
* Clauer-UJI Modification Returns the SignedInfo block itself. This block is the one that
* should be digested and cyphered to get the signature.
*
* @return SignedInfo block
* */
public byte[] getSignedContent() throws DigiDocException
{
CanonicalizationFactory canFac = FactoryManager.getCanonicalizationFactory();
byte[] tmp = canFac.canonicalize(toXML(), SignedDoc.CANONICALIZATION_METHOD_20010315);
return tmp;
}
/**
* Converts the SignedInfo to XML form
*
* @return XML representation of SignedInfo
*/
public byte[] toXML() throws DigiDocException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try
{
bos.write("<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n".getBytes());
bos.write("<CanonicalizationMethod Algorithm=\"".getBytes());
bos.write(m_canonicalizationMethod.getBytes());
bos.write("\">\n</CanonicalizationMethod>\n".getBytes());
bos.write("<SignatureMethod Algorithm=\"".getBytes());
bos.write(m_signatureMethod.getBytes());
bos.write("\">\n</SignatureMethod>\n".getBytes());
for (int i = 0; (m_references != null) && (i < m_references.size()); i++)
{
Reference ref = (Reference) m_references.get(i);
bos.write(ref.toXML());
bos.write("\n".getBytes());
}
bos.write("</SignedInfo>".getBytes());
}
catch (IOException ex)
{
DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT);
}
return bos.toByteArray();
}
/**
* Returns the stringified form of SignedInfo
*
* @return SignedInfo string representation
*/
public String toString()
{
String str = null;
try
{
str = new String(toXML());
}
catch (Exception ex)
{
}
return str;
}
}