/* * Copyright (c) 1990-2012 kopiLeft Development SARL, Bizerte, Tunisia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ package org.kopi.ebics.xml; import java.io.ByteArrayInputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.apache.xml.security.c14n.Canonicalizer; import org.apache.xml.security.transforms.TransformationException; import org.apache.xml.security.utils.IgnoreAllErrorHandler; import org.apache.xpath.XPathAPI; import org.kopi.ebics.exception.EbicsException; import org.kopi.ebics.interfaces.EbicsUser; import org.kopi.ebics.schema.xmldsig.CanonicalizationMethodType; import org.kopi.ebics.schema.xmldsig.DigestMethodType; import org.kopi.ebics.schema.xmldsig.ReferenceType; import org.kopi.ebics.schema.xmldsig.SignatureMethodType; import org.kopi.ebics.schema.xmldsig.SignatureType; import org.kopi.ebics.schema.xmldsig.SignedInfoType; import org.kopi.ebics.schema.xmldsig.TransformType; import org.kopi.ebics.schema.xmldsig.TransformsType; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * A representation of the SignedInfo element * performing signature for signed ebics requests * * @author hachani * */ public class SignedInfo extends DefaultEbicsRootElement { /** * Constructs a new <code>SignedInfo</code> element * @param digest the digest value */ public SignedInfo(EbicsUser user, byte[] digest) { this.user = user; this.digest = digest; } @Override public void build() throws EbicsException { CanonicalizationMethodType canonicalizationMethod; SignatureMethodType signatureMethod; ReferenceType reference; TransformsType transforms; DigestMethodType digestMethod; TransformType transform; SignedInfoType signedInfo; if (digest == null) { throw new EbicsException("digest value cannot be null"); } transform = EbicsXmlFactory.createTransformType(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); digestMethod = EbicsXmlFactory.createDigestMethodType("http://www.w3.org/2001/04/xmlenc#sha256"); transforms = EbicsXmlFactory.createTransformsType(new TransformType[] {transform}); reference = EbicsXmlFactory.createReferenceType("#xpointer(//*[@authenticate='true'])", transforms, digestMethod, digest); signatureMethod = EbicsXmlFactory.createSignatureMethodType("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"); canonicalizationMethod = EbicsXmlFactory.createCanonicalizationMethodType(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); signedInfo = EbicsXmlFactory.createSignedInfoType(canonicalizationMethod, signatureMethod, new ReferenceType[] {reference}); document = EbicsXmlFactory.createSignatureType(signedInfo); } /** * Returns the digest value. * @return the digest value. */ public byte[] getDigest() { return digest; } /** * Returns the signed info element as an <code>XmlObject</code> * @return he signed info element * @throws EbicsException user Signature and Canonicalization errors */ public SignatureType getSignatureType() { return ((SignatureType)document); } /** * Canonizes and signs a given input with the authentication private key. * of the EBICS user. * * <p>The given input to be signed is first Canonized using the * http://www.w3.org/TR/2001/REC-xml-c14n-20010315 algorithm. * * <p>The element to be canonized is only the SignedInfo element that should be * contained in the request to be signed. Otherwise, a {@link TransformationException} * is thrown. * * <p> The namespace of the SignedInfo element should be named <b>ds</b> as specified in * the EBICS specification for common namespaces nomination. * * <p> The signature is ensured using the user X002 private key. This step is done in * {@link EbicsUser#authenticate(byte[]) authenticate}. * * @param toSign the input to sign * @return the signed input * @throws EbicsException signature fails. */ public byte[] sign(byte[] toSign) throws EbicsException { try { DocumentBuilderFactory factory; DocumentBuilder builder; Document document; Node node; Canonicalizer canonicalizer; factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); factory.setValidating(true); builder = factory.newDocumentBuilder(); builder.setErrorHandler(new IgnoreAllErrorHandler()); document = builder.parse(new ByteArrayInputStream(toSign)); node = XPathAPI.selectSingleNode(document, "//ds:SignedInfo"); canonicalizer = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); return user.authenticate(canonicalizer.canonicalizeSubtree(node)); } catch(Exception e) { throw new EbicsException(e.getMessage()); } } @Override public byte[] toByteArray() { addNamespaceDecl("", "http://www.ebics.org/H003"); setSaveSuggestedPrefixes("http://www.w3.org/2000/09/xmldsig#", "ds"); return super.toByteArray(); } @Override public String getName() { return "SignedInfo.xml"; } // -------------------------------------------------------------------- // DATA MEMBERS // -------------------------------------------------------------------- private byte[] digest; private EbicsUser user; private static final long serialVersionUID = 4194924578678778580L; }