All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ee.sk.digidoc.SignedInfo Maven / Gradle / Ivy

/*
 * 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 ee.sk.digidoc;
import java.io.Serializable;
import java.util.ArrayList;
//import ee.sk.utils.ConvertUtils;
import ee.sk.utils.ConfigManager;
import ee.sk.digidoc.factory.CanonicalizationFactory;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import ee.sk.digidoc.factory.DigiDocXmlGenFactory;


/**
 * Represents an XML-DSIG SignedInfo block
 * @author  Veiko Sinivee
 * @version 1.0
 */
public class SignedInfo implements Serializable
{
	private static final long serialVersionUID = 1L;
	/** Id atribute value if set */
    private String m_id;
    /** 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, m_origXml;
    
    /** 
     * Creates new SignedInfo. Initializes everything to null.
     * @param sig parent Signature reference
     */
    public SignedInfo(Signature sig) 
    {
    	m_id = null;
        m_signature = sig;
        m_signatureMethod = null;
        m_canonicalizationMethod = null;
        m_references = null;
        m_origDigest = null;
        m_origXml = 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_id = null;
        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 Id attribute
     * @return value of Id attribute
     */
    public String getId() {
        return m_id;
    }
    
    /**
     * Mutator for Id attribute
     * @param str new value for Id attribute
     */    
    public void setId(String str) 
    {
        m_id = str;
    }
    
    /**
     * 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 origXml attribute
     * @return value of origXml attribute
     */
    public byte[] getOrigXml() {
        return m_origXml;
    }
    
    /**
     * Mutator for origXml attribute
     * @param s new value for origXml attribute
     */    
    public void setOrigXml(byte[] b) 
    {
    	m_origXml = b;
    }
    
    /**
     * 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) &&
        	!str.equals(SignedDoc.RSA_SHA224_SIGNATURE_METHOD) &&
        	!str.equals(SignedDoc.RSA_SHA256_SIGNATURE_METHOD) &&
        	!str.equals(SignedDoc.RSA_SHA512_SIGNATURE_METHOD) &&
        	!str.equals(SignedDoc.ECDSA_SHA1_SIGNATURE_METHOD) &&
        	!str.equals(SignedDoc.ECDSA_SHA224_SIGNATURE_METHOD) &&
        	!str.equals(SignedDoc.ECDSA_SHA256_SIGNATURE_METHOD) &&
        	!str.equals(SignedDoc.ECDSA_SHA512_SIGNATURE_METHOD) ))
            ex = new DigiDocException(DigiDocException.ERR_SIGNATURE_METHOD, 
                "Currently supports only RSA-SHA1, RSA-SHA224, RSA-SHA256, RSA-SHA512, ECDSA-SHA1, ECDSA-SHA224, ECDSA-SHA256 and ECDSA-SHA512 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) && 
           !str.equals(SignedDoc.CANONICALIZATION_METHOD_1_1) &&
           !str.equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC)))
            ex= new DigiDocException(DigiDocException.ERR_CANONICALIZATION_METHOD, 
                "Currently supports only Canonical XML 1.0, 1.1 and exc", 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;
        String fName = null;
        if(df.getFileName() != null) {
        	File fT = new File(df.getFileName());
        	fName = fT.getName(); // get not-absolute file-name
        }
        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;
            }
            if(r1.getUri().equals(df.getId()) || r1.getUri().equals(df.getFileName()) || r1.getUri().equals(fName)) {
            	ref = r1;
                break;
            }
            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 desired Reference object
     * @param dof DataObjectFormat whose digest we are searching
     * @return desired Reference object
     */
    public Reference getReferenceForDataObjectFormat(DataObjectFormat dof) {
        Reference ref = null;
        String sUri = dof.getObjectReference();
        if(sUri.startsWith("#")) sUri = sUri.substring(1);
        for(int i = 0; (m_references != null) && (i < m_references.size()); i++) {
            Reference r1 = (Reference)m_references.get(i);
            if(r1.getId().equals(sUri)) {
                ref = r1;
                break;
            }
        }
        return ref;
    }
    
    /**
     * Finds data-object-format for given reference
     * @param ref Reference object
     * @return DataObjectFormat
     */
    public DataObjectFormat getDataObjectFormatForReference(Reference ref)
    {
    	if(getSignature().getSignedProperties() != null &&
    		getSignature().getSignedProperties().getSignedDataObjectProperties() != null) {
    		for(int i = 0; i < getSignature().getSignedProperties().getSignedDataObjectProperties().countDataObjectFormats(); i++) {
    			DataObjectFormat dof = getSignature().getSignedProperties().getSignedDataObjectProperties().getDataObjectFormat(i);
    			if(dof.getObjectReference().equals("#" + ref.getId()))
    				return dof;
    		}
    	}
    	return null;
    }

    /**
     * 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 = ConfigManager.
                    instance().getCanonicalizationFactory();
        	DigiDocXmlGenFactory genFac = new DigiDocXmlGenFactory(m_signature.getSignedDoc());
        	byte[] xml = genFac.signedInfoToXML(m_signature, this);
        	byte[] tmp = canFac.canonicalize(xml, m_canonicalizationMethod);
        	byte[] hash = null;
        	if(m_signatureMethod.equals(SignedDoc.RSA_SHA1_SIGNATURE_METHOD) ||
        			m_signatureMethod.equals(SignedDoc.ECDSA_SHA1_SIGNATURE_METHOD))
        		hash = SignedDoc.digestOfType(tmp, SignedDoc.SHA1_DIGEST_TYPE);
        	if(m_signatureMethod.equals(SignedDoc.RSA_SHA256_SIGNATURE_METHOD) ||
        			m_signatureMethod.equals(SignedDoc.ECDSA_SHA256_SIGNATURE_METHOD))
        		hash = SignedDoc.digestOfType(tmp, SignedDoc.SHA256_DIGEST_TYPE);
        	if(m_signatureMethod.equals(SignedDoc.RSA_SHA224_SIGNATURE_METHOD) ||
        			m_signatureMethod.equals(SignedDoc.ECDSA_SHA224_SIGNATURE_METHOD))
        		hash = SignedDoc.digestOfType(tmp, SignedDoc.SHA224_DIGEST_TYPE);
        	if(m_signatureMethod.equals(SignedDoc.RSA_SHA384_SIGNATURE_METHOD) ||
        			m_signatureMethod.equals(SignedDoc.ECDSA_SHA384_SIGNATURE_METHOD))
        		hash = SignedDoc.digestOfType(tmp, SignedDoc.SHA384_DIGEST_TYPE);
        	if(m_signatureMethod.equals(SignedDoc.RSA_SHA512_SIGNATURE_METHOD) ||
        			m_signatureMethod.equals(SignedDoc.ECDSA_SHA512_SIGNATURE_METHOD))
        		hash = SignedDoc.digestOfType(tmp, SignedDoc.SHA512_DIGEST_TYPE);
        	return hash;
    	}
    	else
    		return m_origDigest;
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy