/* * Reference.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.utils.ConvertUtils; import es.uji.security.util.Base64; /** * Represents and XML-DSIG reference block that referrs to a particular piece of signed XML data and * contains it's hash code. * * @author Veiko Sinivee * @version 1.0 */ public class Reference implements Serializable { /** reference to parent SignedInfo object */ private SignedInfo m_sigInfo; /** URI to signed XML data */ private String m_uri; /** selected digest algorithm */ private String m_digestAlgorithm; /** digest data */ private byte[] m_digestValue; /** transform algorithm */ private String m_transformAlgorithm; /** * Creates new Reference. Initializes everything to null * * @param sigInfo * reference to parent SignedInfo object */ public Reference(SignedInfo sigInfo) { m_sigInfo = sigInfo; m_uri = null; m_digestAlgorithm = null; m_digestValue = null; m_transformAlgorithm = null; } /** * Creates new Reference * * @param sigInfo * reference to parent SignedInfo object * @param uri * reference uri pointing to signed XML data * @param algorithm * sigest algorithm identifier * @param digest * message digest data * @param transform * transform algorithm * @throws DigiDocException * for validation errors */ public Reference(SignedInfo sigInfo, String uri, String algorithm, byte[] digest, String transform) throws DigiDocException { m_sigInfo = sigInfo; setUri(uri); setDigestAlgorithm(algorithm); setDigestValue(digest); setTransformAlgorithm(transform); } /** * Creates new Reference and initializes it with default values from the DataFile * * @param sigInfo * reference to parent SignedInfo object * @param df * DataFile object * @throws DigiDocException * for validation errors */ public Reference(SignedInfo sigInfo, DataFile df) throws DigiDocException { m_sigInfo = sigInfo; setUri("#" + df.getId()); setDigestAlgorithm(SignedDoc.SHA1_DIGEST_ALGORITHM); setDigestValue(df.getDigest()); setTransformAlgorithm(df.getContentType().equals(DataFile.CONTENT_DETATCHED) ? SignedDoc.DIGIDOC_DETATCHED_TRANSFORM : null); } /** * Accessor for sigInfo attribute * * @return value of sigInfo attribute */ public SignedInfo getSignedInfo() { return m_sigInfo; } /** * Mutator for sigInfo attribute * * @param sigInfo * new value for sigInfo attribute */ public void setSignedInfo(SignedInfo sigInfo) { m_sigInfo = sigInfo; } /** * Creates new Reference and initializes it with default values from the SignedProperties * * @param sigInfo * reference to parent SignedInfo object * @param sp * SignedProperties object * @throws DigiDocException * for validation errors */ public Reference(SignedInfo sigInfo, SignedProperties sp) throws DigiDocException { m_sigInfo = sigInfo; setUri(sp.getTarget() + "-SignedProperties"); setDigestAlgorithm(SignedDoc.SHA1_DIGEST_ALGORITHM); setDigestValue(sp.calculateDigest()); setTransformAlgorithm(null); } /** * Accessor for uri attribute * * @return value of uri attribute */ public String getUri() { return m_uri; } /** * Mutator for uri attribute * * @param str * new value for uri attribute * @throws DigiDocException * for validation errors */ public void setUri(String str) throws DigiDocException { DigiDocException ex = validateUri(str); if (ex != null) throw ex; m_uri = str; } /** * Helper method to validate a uri * * @param str * input data * @return exception or null for ok */ private DigiDocException validateUri(String str) { DigiDocException ex = null; if (str == null) // check the uri somehow ??? ex = new DigiDocException(DigiDocException.ERR_REFERENCE_URI, "URI has to be in format #<DataFile-ID>", null); return ex; } /** * Accessor for digestAlgorithm attribute * * @return value of digestAlgorithm attribute */ public String getDigestAlgorithm() { return m_digestAlgorithm; } /** * Mutator for digestAlgorithm attribute * * @param str * new value for digestAlgorithm attribute * @throws DigiDocException * for validation errors */ public void setDigestAlgorithm(String str) throws DigiDocException { DigiDocException ex = validateDigestAlgorithm(str); if (ex != null) throw ex; m_digestAlgorithm = str; } /** * Helper method to validate a digest algorithm * * @param str * input data * @return exception or null for ok */ private DigiDocException validateDigestAlgorithm(String str) { DigiDocException ex = null; if (str == null || !str.equals(SignedDoc.SHA1_DIGEST_ALGORITHM)) ex = new DigiDocException(DigiDocException.ERR_DIGEST_ALGORITHM, "Currently supports only SHA1 digest algorithm", null); return ex; } /** * Accessor for digestValue attribute * * @return value of digestValue attribute */ public byte[] getDigestValue() { return m_digestValue; } /** * Mutator for digestValue attribute * * @param data * new value for digestValue attribute * @throws DigiDocException * for validation errors */ public void setDigestValue(byte[] data) throws DigiDocException { DigiDocException ex = validateDigestValue(data); if (ex != null) throw ex; m_digestValue = data; } /** * Helper method to validate a digest value * * @param data * input data * @return exception or null for ok */ private DigiDocException validateDigestValue(byte[] data) { DigiDocException ex = null; if (data == null || data.length != SignedDoc.SHA1_DIGEST_LENGTH) ex = new DigiDocException(DigiDocException.ERR_DIGEST_LENGTH, "SHA1 digest data is allways 20 bytes of length", null); return ex; } /** * Accessor for transformAlgorithm attribute * * @return value of transformAlgorithm attribute */ public String getTransformAlgorithm() { return m_transformAlgorithm; } /** * Mutator for transformAlgorithm attribute. Currently supports only one transform which has to * be digidoc detatched document transform or none at all. * * @param str * new value for transformAlgorithm attribute * @throws DigiDocException * for validation errors */ public void setTransformAlgorithm(String str) throws DigiDocException { DigiDocException ex = validateTransformAlgorithm(str); if (ex != null) throw ex; m_transformAlgorithm = str; } /** * Helper method to validate a transform algorithm * * @param str * input data * @return exception or null for ok */ private DigiDocException validateTransformAlgorithm(String str) { DigiDocException ex = null; if (str != null && !str.equals(SignedDoc.DIGIDOC_DETATCHED_TRANSFORM)) ex = new DigiDocException(DigiDocException.ERR_TRANSFORM_ALGORITHM, "Currently supports either no transforms or one detatched document transform", null); return ex; } /** * Helper method to validate the whole Reference object * * @return a possibly empty list of DigiDocException objects */ public ArrayList validate() { ArrayList errs = new ArrayList(); DigiDocException ex = validateUri(m_uri); if (ex != null) errs.add(ex); ex = validateDigestAlgorithm(m_digestAlgorithm); if (ex != null) errs.add(ex); ex = validateDigestValue(m_digestValue); if (ex != null) errs.add(ex); ex = validateTransformAlgorithm(m_transformAlgorithm); if (ex != null) errs.add(ex); return errs; } /** * Converts the Reference to XML form * * @return XML representation of Reference */ public byte[] toXML() throws DigiDocException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { /* * bos.write(ConvertUtils.str2data("<Reference URI=\"")); * bos.write(ConvertUtils.str2data(m_uri)); if(m_sigInfo.getSignature().getSignedDoc(). * getVersion().equals(SignedDoc.VERSION_1_2)) {bos.write(ConvertUtils.str2data( * "\" Type=\"http://uri.etsi.org/01903/v1.1.1#SignedProperties")); } */ // VS: rc11_02 bug fix on Type attribute bos.write(ConvertUtils.str2data("<Reference")); if ((m_sigInfo.getSignature().getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_2) || m_sigInfo .getSignature().getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_3)) && m_uri.indexOf("SignedProperties") != -1) { bos.write(ConvertUtils .str2data(" Type=\"http://uri.etsi.org/01903/v1.1.1#SignedProperties\"")); } bos.write(ConvertUtils.str2data(" URI=\"")); bos.write(ConvertUtils.str2data(m_uri)); bos.write(ConvertUtils.str2data("\">\n")); if (m_transformAlgorithm != null) { bos.write(ConvertUtils.str2data("<Transforms><Transform Algorithm=\"")); bos.write(ConvertUtils.str2data(m_transformAlgorithm)); bos.write(ConvertUtils.str2data("\"></Transform></Transforms>\n")); } bos.write(ConvertUtils.str2data("<DigestMethod Algorithm=\"")); bos.write(ConvertUtils.str2data(m_digestAlgorithm)); bos.write(ConvertUtils.str2data("\">\n</DigestMethod>\n")); bos.write(ConvertUtils.str2data("<DigestValue>")); bos.write(ConvertUtils.str2data(Base64.encodeBytes(m_digestValue))); bos.write(ConvertUtils.str2data("</DigestValue>\n")); bos.write(ConvertUtils.str2data("</Reference>")); } catch (IOException ex) { DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT); } return bos.toByteArray(); } /** * Returns the stringified form of Reference * * @return References string representation */ public String toString() { String str = null; try { str = new String(toXML()); } catch (Exception ex) { } return str; } }