Java tutorial
/** * DSS - Digital Signature Services * Copyright (C) 2015 European Commission, provided under the CEF programme * * This file is part of the "DSS - Digital Signature Services" project. * * 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. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package eu.europa.esig.dss.xades.signature; import static eu.europa.esig.dss.XAdESNamespaces.XAdES; import static javax.xml.crypto.dsig.XMLSignature.XMLNS; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.xml.datatype.XMLGregorianCalendar; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text; import eu.europa.esig.dss.ChainCertificate; import eu.europa.esig.dss.DSSDocument; import eu.europa.esig.dss.DSSException; import eu.europa.esig.dss.DSSUtils; import eu.europa.esig.dss.DSSXMLUtils; import eu.europa.esig.dss.DigestAlgorithm; import eu.europa.esig.dss.EncryptionAlgorithm; import eu.europa.esig.dss.InMemoryDocument; import eu.europa.esig.dss.MimeType; import eu.europa.esig.dss.Policy; import eu.europa.esig.dss.SignatureAlgorithm; import eu.europa.esig.dss.SignerLocation; import eu.europa.esig.dss.XAdESNamespaces; import eu.europa.esig.dss.validation.CertificateVerifier; import eu.europa.esig.dss.validation.TimestampInclude; import eu.europa.esig.dss.validation.TimestampToken; import eu.europa.esig.dss.x509.CertificatePool; import eu.europa.esig.dss.x509.CertificateToken; import eu.europa.esig.dss.x509.TimestampType; import eu.europa.esig.dss.xades.DSSReference; import eu.europa.esig.dss.xades.DSSTransform; import eu.europa.esig.dss.xades.SignatureBuilder; import eu.europa.esig.dss.xades.XAdESSignatureParameters; /** * This class implements all the necessary mechanisms to build each form of the XML signature. * */ public abstract class XAdESSignatureBuilder extends XAdESBuilder implements SignatureBuilder { /** * Indicates if the signature was already built. (Two steps building) */ protected boolean built = false; /** * This is the reference to the original document to sign */ protected DSSDocument detachedDocument; protected String signedInfoCanonicalizationMethod; protected String signedPropertiesCanonicalizationMethod; protected String deterministicId; /* * This variable represents the current DOM signature object. */ protected Element signatureDom; protected Element signedInfoDom; protected Element signatureValueDom; protected Element qualifyingPropertiesDom; protected Element signedPropertiesDom; protected Element signedSignaturePropertiesDom; protected Element signedDataObjectPropertiesDom; protected Element unsignedSignaturePropertiesDom; /** * Creates the signature according to the packaging * * @param params The set of parameters relating to the structure and process of the creation or extension of the electronic signature. * @param document The original document to sign. * @param certificateVerifier * @return */ public static XAdESSignatureBuilder getSignatureBuilder(final XAdESSignatureParameters params, final DSSDocument document, final CertificateVerifier certificateVerifier) { switch (params.getSignaturePackaging()) { case ENVELOPED: return new EnvelopedSignatureBuilder(params, document, certificateVerifier); case ENVELOPING: return new EnvelopingSignatureBuilder(params, document, certificateVerifier); case DETACHED: return new DetachedSignatureBuilder(params, document, certificateVerifier); default: throw new DSSException("Unsupported packaging " + params.getSignaturePackaging()); } } /** * The default constructor for SignatureBuilder. * * @param params The set of parameters relating to the structure and process of the creation or extension of the electronic signature. * @param detachedDocument The original document to sign. * @param certificateVerifier */ public XAdESSignatureBuilder(final XAdESSignatureParameters params, final DSSDocument detachedDocument, final CertificateVerifier certificateVerifier) { super(certificateVerifier); this.params = params; this.detachedDocument = detachedDocument; } protected void setCanonicalizationMethods(final XAdESSignatureParameters params, final String canonicalizationMethod) { final String signedInfoCanonicalizationMethod_ = params.getSignedInfoCanonicalizationMethod(); if (StringUtils.isNotBlank(signedInfoCanonicalizationMethod_)) { signedInfoCanonicalizationMethod = signedInfoCanonicalizationMethod_; } else { signedInfoCanonicalizationMethod = canonicalizationMethod; } final String signedPropertiesCanonicalizationMethod_ = params.getSignedPropertiesCanonicalizationMethod(); if (StringUtils.isNotBlank(signedPropertiesCanonicalizationMethod_)) { signedPropertiesCanonicalizationMethod = signedPropertiesCanonicalizationMethod_; } else { signedPropertiesCanonicalizationMethod = canonicalizationMethod; } } /** * This is the main method which is called to build the XML signature * * @return A byte array is returned with XML that represents the canonicalized <ds:SignedInfo> segment of signature. This data are used to define the <ds:SignatureValue> * element. * @throws DSSException */ public byte[] build() throws DSSException { documentDom = buildRootDocumentDom(); deterministicId = params.getDeterministicId(); final List<DSSReference> references = params.getReferences(); if (CollectionUtils.isEmpty(references)) { final List<DSSReference> defaultReferences = createDefaultReferences(); // The SignatureParameters object is updated with the default references. params.setReferences(defaultReferences); } incorporateSignatureDom(); incorporateSignedInfo(); incorporateSignatureValue(); incorporateKeyInfo(); incorporateObject(); /** * We create <ds:Reference> segment only now, because we need first to define the SignedProperties segment to * calculate the digest of references. */ incorporateReferences(); incorporateReferenceSignedProperties(); // Preparation of SignedInfo byte[] canonicalizedSignedInfo = DSSXMLUtils.canonicalizeSubtree(signedInfoCanonicalizationMethod, signedInfoDom); if (LOG.isTraceEnabled()) { LOG.trace("Canonicalized SignedInfo --> {}", new String(canonicalizedSignedInfo)); final byte[] digest = DSSUtils.digest(DigestAlgorithm.SHA256, canonicalizedSignedInfo); LOG.trace("Canonicalized SignedInfo SHA256 --> {}", Base64.encodeBase64String(digest)); } built = true; return canonicalizedSignedInfo; } protected Document buildRootDocumentDom() { return DSSXMLUtils.buildDOM(); } /** * This method creates a new instance of Signature element. */ public void incorporateSignatureDom() { signatureDom = documentDom.createElementNS(XMLNS, DS_SIGNATURE); signatureDom.setAttribute(XMLNS_DS, XMLNS); signatureDom.setAttribute(ID, deterministicId); final Node parentNodeOfSignature = getParentNodeOfSignature(); parentNodeOfSignature.appendChild(signatureDom); } protected Node getParentNodeOfSignature() { return documentDom; } public void incorporateSignedInfo() { // <ds:SignedInfo> signedInfoDom = DSSXMLUtils.addElement(documentDom, signatureDom, XMLNS, DS_SIGNED_INFO); incorporateCanonicalizationMethod(signedInfoDom, signedInfoCanonicalizationMethod); //<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> final Element signatureMethod = DSSXMLUtils.addElement(documentDom, signedInfoDom, XMLNS, DS_SIGNATURE_METHOD); final EncryptionAlgorithm encryptionAlgorithm = params.getEncryptionAlgorithm(); final DigestAlgorithm digestAlgorithm = params.getDigestAlgorithm(); final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.getAlgorithm(encryptionAlgorithm, digestAlgorithm); final String signatureAlgorithmXMLId = signatureAlgorithm.getXMLId(); signatureMethod.setAttribute(ALGORITHM, signatureAlgorithmXMLId); } private void incorporateCanonicalizationMethod(final Element parentDom, final String signedInfoCanonicalizationMethod) { //<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> final Element canonicalizationMethodDom = DSSXMLUtils.addElement(documentDom, parentDom, XMLNS, DS_CANONICALIZATION_METHOD); canonicalizationMethodDom.setAttribute(ALGORITHM, signedInfoCanonicalizationMethod); } /** * This method incorporates the references other than the one concerning "http://uri.etsi.org/01903#SignedProperties". * * @throws DSSException */ protected abstract void incorporateReferences() throws DSSException; /** * Creates KeyInfoType JAXB object. * NOTE: when trust anchor baseline profile policy is defined only the certificates previous to the trust anchor are included. * * @throws DSSException */ protected void incorporateKeyInfo() throws DSSException { // <ds:KeyInfo> final Element keyInfoDom = DSSXMLUtils.addElement(documentDom, signatureDom, XMLNS, DS_KEY_INFO); // <ds:X509Data> final Element x509DataDom = DSSXMLUtils.addElement(documentDom, keyInfoDom, XMLNS, DS_X509_DATA); final boolean trustAnchorBPPolicy = params.bLevel().isTrustAnchorBPPolicy(); final CertificatePool certificatePool = getCertificatePool(); boolean firstCertificate = true; // The signing certificate can be directly in the TSL for (final ChainCertificate chainCertificate : params.getCertificateChain()) { final CertificateToken x509Certificate = chainCertificate.getX509Certificate(); if (trustAnchorBPPolicy && (certificatePool != null)) { if (!certificatePool.get(x509Certificate.getSubjectX500Principal()).isEmpty()) { if (firstCertificate) { addCertificate(x509DataDom, x509Certificate); } break; } firstCertificate = false; } addCertificate(x509DataDom, x509Certificate); } } private void addCertificate(final Element x509DataDom, final CertificateToken x509Certificate) { final byte[] encoded = x509Certificate.getEncoded(); final String base64Encoded = Base64.encodeBase64String(encoded); // <ds:X509Certificate>...</ds:X509Certificate> DSSXMLUtils.addTextElement(documentDom, x509DataDom, XMLNS, DS_X509_CERTIFICATE, base64Encoded); } /** * @throws DSSException */ protected void incorporateObject() throws DSSException { // <ds:Object> final Element objectDom = DSSXMLUtils.addElement(documentDom, signatureDom, XMLNS, DS_OBJECT); // <QualifyingProperties xmlns="http://uri.etsi.org/01903/v1.3.2#" Target="#sigId-ide5c549340079fe19f3f90f03354a5965"> qualifyingPropertiesDom = DSSXMLUtils.addElement(documentDom, objectDom, XAdES, XADES_QUALIFYING_PROPERTIES); qualifyingPropertiesDom.setAttribute(XMLNS_XADES, XAdES); qualifyingPropertiesDom.setAttribute(TARGET, "#" + deterministicId); incorporateSignedProperties(); } /** * @throws DSSException */ protected void incorporateReferenceSignedProperties() throws DSSException { // <ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xades-ide5c549340079fe19f3f90f03354a5965"> final Element reference = DSSXMLUtils.addElement(documentDom, signedInfoDom, XMLNS, DS_REFERENCE); reference.setAttribute(TYPE, xPathQueryHolder.XADES_SIGNED_PROPERTIES); reference.setAttribute(URI, "#xades-" + deterministicId); // <ds:Transforms> final Element transforms = DSSXMLUtils.addElement(documentDom, reference, XMLNS, DS_TRANSFORMS); // <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> final Element transform = DSSXMLUtils.addElement(documentDom, transforms, XMLNS, DS_TRANSFORM); transform.setAttribute(ALGORITHM, signedPropertiesCanonicalizationMethod); // </ds:Transforms> // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> final DigestAlgorithm digestAlgorithm = params.getDigestAlgorithm(); incorporateDigestMethod(reference, digestAlgorithm); // <ds:DigestValue>b/JEDQH2S1Nfe4Z3GSVtObN34aVB1kMrEbVQZswThfQ=</ds:DigestValue> final byte[] canonicalizedBytes = DSSXMLUtils.canonicalizeSubtree(signedPropertiesCanonicalizationMethod, signedPropertiesDom); if (LOG.isTraceEnabled()) { LOG.trace("Canonicalization method --> {}", signedPropertiesCanonicalizationMethod); LOG.trace("Canonicalised REF_2 --> {}", new String(canonicalizedBytes)); } incorporateDigestValue(reference, digestAlgorithm, new InMemoryDocument(canonicalizedBytes)); } /** * This method incorporates a reference within the signedInfoDom * * @param dssReference {@code DSSReference} * @throws DSSException */ protected void incorporateReference(final DSSReference dssReference) throws DSSException { final Element referenceDom = DSSXMLUtils.addElement(documentDom, signedInfoDom, XMLNS, DS_REFERENCE); referenceDom.setAttribute(ID, dssReference.getId()); final String uri = dssReference.getUri(); referenceDom.setAttribute(URI, uri); referenceDom.setAttribute(TYPE, dssReference.getType()); final List<DSSTransform> dssTransforms = dssReference.getTransforms(); if (dssTransforms != null) { // Detached signature may not have transformations final Element transformsDom = DSSXMLUtils.addElement(documentDom, referenceDom, XMLNS, DS_TRANSFORMS); for (final DSSTransform dssTransform : dssTransforms) { final Element transformDom = DSSXMLUtils.addElement(documentDom, transformsDom, XMLNS, DS_TRANSFORM); createTransform(documentDom, dssTransform, transformDom); } } // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> final DigestAlgorithm digestAlgorithm = dssReference.getDigestMethodAlgorithm(); incorporateDigestMethod(referenceDom, digestAlgorithm); final DSSDocument canonicalizedDocument = transformReference(dssReference); if (LOG.isTraceEnabled()) { LOG.trace("Reference canonicalization method -->" + signedInfoCanonicalizationMethod); } incorporateDigestValue(referenceDom, digestAlgorithm, canonicalizedDocument); } static void createTransform(final Document document, final DSSTransform dssTransform, final Element transformDom) { transformDom.setAttribute(ALGORITHM, dssTransform.getAlgorithm()); final String elementName = dssTransform.getElementName(); final String textContent = dssTransform.getTextContent(); if (StringUtils.isNotBlank(elementName)) { final String namespace = dssTransform.getNamespace(); DSSXMLUtils.addTextElement(document, transformDom, namespace, elementName, textContent); } else if (StringUtils.isNotBlank(textContent)) { final Document transformContentDoc = DSSXMLUtils.buildDOM(textContent); final Element contextDocumentElement = transformContentDoc.getDocumentElement(); document.adoptNode(contextDocumentElement); transformDom.appendChild(contextDocumentElement); } } /** * When the user does not want to create its own references (only when signing one contents) the default one are created. * * @return {@code List} of {@code DSSReference} */ protected abstract List<DSSReference> createDefaultReferences(); /** * This method performs the reference transformation. Note that for the time being (4.3.0-RC) only two types of transformation are implemented: canonicalization & {@code * Transforms.TRANSFORM_XPATH} and can be applied only for {@code SignaturePackaging.ENVELOPED}. * * @param reference {@code DSSReference} to be transformed * @return {@code DSSDocument} containing transformed reference's data */ protected abstract DSSDocument transformReference(final DSSReference reference); /** * This method incorporates the signature value. */ protected void incorporateSignatureValue() { signatureValueDom = DSSXMLUtils.addElement(documentDom, signatureDom, XMLNS, DS_SIGNATURE_VALUE); signatureValueDom.setAttribute(ID, "value-" + deterministicId); } /** * Creates the SignedProperties DOM object element. * * @throws DSSException */ protected void incorporateSignedProperties() throws DSSException { // <SignedProperties Id="xades-ide5c549340079fe19f3f90f03354a5965"> signedPropertiesDom = DSSXMLUtils.addElement(documentDom, qualifyingPropertiesDom, XAdES, XADES_SIGNED_PROPERTIES); signedPropertiesDom.setAttribute(ID, "xades-" + deterministicId); incorporateSignedSignatureProperties(); } /** * Creates the SignedSignatureProperties DOM object element. * */ protected void incorporateSignedSignatureProperties() { // <SignedSignatureProperties> signedSignaturePropertiesDom = DSSXMLUtils.addElement(documentDom, signedPropertiesDom, XAdES, XADES_SIGNED_SIGNATURE_PROPERTIES); incorporateSigningTime(); incorporateSigningCertificate(); incorporateSignedDataObjectProperties(); incorporatePolicy(); incorporateSignatureProductionPlace(); incorporateSignerRole(); incorporateCommitmentTypeIndications(); } private void incorporatePolicy() { final Policy signaturePolicy = params.bLevel().getSignaturePolicy(); if ((signaturePolicy != null)) {// && (signaturePolicy.getId() != null)) { final Element signaturePolicyIdentifierDom = DSSXMLUtils.addElement(documentDom, signedSignaturePropertiesDom, XAdES, XADES_SIGNATURE_POLICY_IDENTIFIER); String signaturePolicyId = signaturePolicy.getId(); if (StringUtils.isEmpty(signaturePolicyId)) { // implicit DSSXMLUtils.addElement(documentDom, signaturePolicyIdentifierDom, XAdES, XADES_SIGNATURE_POLICY_IMPLIED); } else { // explicit final Element signaturePolicyIdDom = DSSXMLUtils.addElement(documentDom, signaturePolicyIdentifierDom, XAdES, XADES_SIGNATURE_POLICY_ID); final Element sigPolicyIdDom = DSSXMLUtils.addElement(documentDom, signaturePolicyIdDom, XAdES, XADES_SIG_POLICY_ID); DSSXMLUtils.addTextElement(documentDom, sigPolicyIdDom, XAdES, XADES_IDENTIFIER, signaturePolicyId); String description = signaturePolicy.getDescription(); if (StringUtils.isNotEmpty(description)) { DSSXMLUtils.addTextElement(documentDom, sigPolicyIdDom, XAdES, XADES_DESCRIPTION, description); } if ((signaturePolicy.getDigestAlgorithm() != null) && (signaturePolicy.getDigestValue() != null)) { final Element sigPolicyHashDom = DSSXMLUtils.addElement(documentDom, signaturePolicyIdDom, XAdES, XADES_SIG_POLICY_HASH); // <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> final DigestAlgorithm digestAlgorithm = signaturePolicy.getDigestAlgorithm(); incorporateDigestMethod(sigPolicyHashDom, digestAlgorithm); final byte[] hashValue = signaturePolicy.getDigestValue(); final String bas64EncodedHashValue = Base64.encodeBase64String(hashValue); DSSXMLUtils.addTextElement(documentDom, sigPolicyHashDom, XMLNS, DS_DIGEST_VALUE, bas64EncodedHashValue); } String spuri = signaturePolicy.getSpuri(); if (StringUtils.isNotEmpty(spuri)) { Element sigPolicyQualifiers = DSSXMLUtils.addElement(documentDom, signaturePolicyIdDom, XAdES, XADES_SIGNATURE_POLICY_QUALIFIERS); Element sigPolicyQualifier = DSSXMLUtils.addElement(documentDom, sigPolicyQualifiers, XAdES, XADES_SIGNATURE_POLICY_QUALIFIER); DSSXMLUtils.addTextElement(documentDom, sigPolicyQualifier, XAdES, XADES_SPURI, spuri); } } } } /** * Creates SigningTime DOM object element. */ private void incorporateSigningTime() { final Date signingDate = params.bLevel().getSigningDate(); final XMLGregorianCalendar xmlGregorianCalendar = DSSXMLUtils.createXMLGregorianCalendar(signingDate); final String xmlSigningTime = xmlGregorianCalendar.toXMLFormat(); // <SigningTime>2013-11-23T11:22:52Z</SigningTime> final Element signingTimeDom = documentDom.createElementNS(XAdES, XADES_SIGNING_TIME); signedSignaturePropertiesDom.appendChild(signingTimeDom); final Text textNode = documentDom.createTextNode(xmlSigningTime); signingTimeDom.appendChild(textNode); } /** * Creates SigningCertificate building block DOM object: * * <SigningCertificate> <Cert> <CertDigest> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> <ds:DigestValue>fj8SJujSXU4fi342bdtiKVbglA0=</ds:DigestValue> * </CertDigest> <IssuerSerial> <ds:X509IssuerName>CN=ICA A,O=DSS,C=AA</ds:X509IssuerName> <ds:X509SerialNumber>4</ds:X509SerialNumber> </IssuerSerial> </Cert> * </SigningCertificate> */ private void incorporateSigningCertificate() { String signingCertificate = XAdESNamespaces.getXADES_SIGNING_CERTIFICATE(); if (params.isEn319132()) { signingCertificate = XAdESNamespaces.getXADES_SIGNING_CERTIFICATE_V2(); } final Element signingCertificateDom = DSSXMLUtils.addElement(documentDom, signedSignaturePropertiesDom, XAdES, signingCertificate); final List<CertificateToken> certificates = new ArrayList<CertificateToken>(); final List<ChainCertificate> certificateChain = params.getCertificateChain(); for (final ChainCertificate chainCertificate : certificateChain) { if (chainCertificate.isSignedAttribute()) { certificates.add(chainCertificate.getX509Certificate()); } } incorporateCertificateRef(signingCertificateDom, certificates); } /** * This method incorporates the SignedDataObjectProperties DOM element <SignedDataObjectProperties> ...<DataObjectFormat ObjectReference="#detached-ref-id"> * ......<MimeType>text/plain</MimeType> ...</DataObjectFormat> </SignedDataObjectProperties> */ private void incorporateSignedDataObjectProperties() { signedDataObjectPropertiesDom = DSSXMLUtils.addElement(documentDom, signedPropertiesDom, XAdES, XADES_SIGNED_DATA_OBJECT_PROPERTIES); final List<DSSReference> references = params.getReferences(); for (final DSSReference reference : references) { final String dataObjectFormatObjectReference = "#" + reference.getId(); final Element dataObjectFormatDom = DSSXMLUtils.addElement(documentDom, signedDataObjectPropertiesDom, XAdES, XADES_DATA_OBJECT_FORMAT); dataObjectFormatDom.setAttribute(OBJECT_REFERENCE, dataObjectFormatObjectReference); final Element mimeTypeDom = DSSXMLUtils.addElement(documentDom, dataObjectFormatDom, XAdES, XADES_MIME_TYPE); MimeType dataObjectFormatMimeType = getReferenceMimeType(reference); DSSXMLUtils.setTextNode(documentDom, mimeTypeDom, dataObjectFormatMimeType.getMimeTypeString()); } incorporateContentTimestamps(); } /** * @param reference the reference to compute * @return the {@code MimeType} of the reference or the default value {@code MimeType.BINARY} */ protected MimeType getReferenceMimeType(final DSSReference reference) { MimeType dataObjectFormatMimeType = reference.getContents().getMimeType(); if (dataObjectFormatMimeType == null) { dataObjectFormatMimeType = MimeType.BINARY; } return dataObjectFormatMimeType; } /** * This method incorporate the content-timestamps within the signature being created. */ private void incorporateContentTimestamps() { final List<TimestampToken> contentTimestamps = params.getContentTimestamps(); if (contentTimestamps == null) { return; } Element allDataObjectsTimestampDom = null; Element individualDataObjectsTimestampDom = null; for (final TimestampToken contentTimestamp : contentTimestamps) { final TimestampType timeStampType = contentTimestamp.getTimeStampType(); if (TimestampType.ALL_DATA_OBJECTS_TIMESTAMP.equals(timeStampType)) { if (allDataObjectsTimestampDom == null) { allDataObjectsTimestampDom = DSSXMLUtils.addElement(documentDom, signedDataObjectPropertiesDom, XAdES, XADES_ALL_DATA_OBJECTS_TIME_STAMP); } addTimestamp(allDataObjectsTimestampDom, contentTimestamp); } else if (TimestampType.INDIVIDUAL_DATA_OBJECTS_TIMESTAMP.equals(timeStampType)) { if (individualDataObjectsTimestampDom == null) { individualDataObjectsTimestampDom = DSSXMLUtils.addElement(documentDom, signedDataObjectPropertiesDom, XAdES, XADES_INDIVIDUAL_DATA_OBJECTS_TIME_STAMP); } addTimestamp(individualDataObjectsTimestampDom, contentTimestamp); } } } /** * This method incorporates the signer claimed roleType into signed signature properties. */ private void incorporateSignerRole() { final List<String> claimedSignerRoles = params.bLevel().getClaimedSignerRoles(); final List<String> certifiedSignerRoles = params.bLevel().getCertifiedSignerRoles(); if ((claimedSignerRoles != null) || (certifiedSignerRoles != null)) { final Element signerRoleDom; if (params.isEn319132()) { signerRoleDom = DSSXMLUtils.addElement(documentDom, signedSignaturePropertiesDom, XAdES, XADES_SIGNER_ROLE_V2); } else { signerRoleDom = DSSXMLUtils.addElement(documentDom, signedSignaturePropertiesDom, XAdES, XADES_SIGNER_ROLE); } if (CollectionUtils.isNotEmpty(claimedSignerRoles)) { final Element claimedRolesDom = DSSXMLUtils.addElement(documentDom, signerRoleDom, XAdES, XADES_CLAIMED_ROLES); addRoles(claimedSignerRoles, claimedRolesDom, XADES_CLAIMED_ROLE); } if (CollectionUtils.isNotEmpty(certifiedSignerRoles)) { final Element certifiedRolesDom; if (params.isEn319132()) { certifiedRolesDom = DSSXMLUtils.addElement(documentDom, signerRoleDom, XAdES, XADES_CERTIFIED_ROLES_V2); } else { certifiedRolesDom = DSSXMLUtils.addElement(documentDom, signerRoleDom, XAdES, XADES_CERTIFIED_ROLES); } addRoles(certifiedSignerRoles, certifiedRolesDom, XADES_CERTIFIED_ROLE); } } } private void addRoles(final List<String> signerRoles, final Element rolesDom, final String roleType) { for (final String signerRole : signerRoles) { final Element roleDom = DSSXMLUtils.addElement(documentDom, rolesDom, XAdES, roleType); DSSXMLUtils.setTextNode(documentDom, roleDom, signerRole); } } private void incorporateSignatureProductionPlace() { final SignerLocation signatureProductionPlace = params.bLevel().getSignerLocation(); if (signatureProductionPlace != null) { final Element signatureProductionPlaceDom; if (params.isEn319132()) { signatureProductionPlaceDom = DSSXMLUtils.addElement(documentDom, signedSignaturePropertiesDom, XAdES, XADES_SIGNATURE_PRODUCTION_PLACE_V2); } else { signatureProductionPlaceDom = DSSXMLUtils.addElement(documentDom, signedSignaturePropertiesDom, XAdES, XADES_SIGNATURE_PRODUCTION_PLACE); } final String city = signatureProductionPlace.getLocality(); if (city != null) { DSSXMLUtils.addTextElement(documentDom, signatureProductionPlaceDom, XAdES, XADES_CITY, city); } if (params.isEn319132()) { final String streetAddress = signatureProductionPlace.getStreet(); if (streetAddress != null) { DSSXMLUtils.addTextElement(documentDom, signatureProductionPlaceDom, XAdES, XADES_STREET_ADDRESS, streetAddress); } } final String postalCode = signatureProductionPlace.getPostalCode(); if (postalCode != null) { DSSXMLUtils.addTextElement(documentDom, signatureProductionPlaceDom, XAdES, XADES_POSTAL_CODE, postalCode); } final String stateOrProvince = signatureProductionPlace.getStateOrProvince(); if (stateOrProvince != null) { DSSXMLUtils.addTextElement(documentDom, signatureProductionPlaceDom, XAdES, XADES_STATE_OR_PROVINCE, stateOrProvince); } final String country = signatureProductionPlace.getCountry(); if (country != null) { DSSXMLUtils.addTextElement(documentDom, signatureProductionPlaceDom, XAdES, XADES_COUNTRY_NAME, country); } } } /** * Below follows the schema definition for this element. <xsd:element name="CommitmentTypeIndication" type="CommitmentTypeIndicationType"/> * * <xsd:complexType name="CommitmentTypeIndicationType"> ...<xsd:sequence> ......<xsd:element name="CommitmentTypeId" type="ObjectIdentifierType"/> ......<xsd:choice> * .........<xsd:element name="ObjectReference" type="xsd:anyURI" maxOccurs="unbounded"/> .........< xsd:element name="AllSignedDataObjects"/> ......</xsd:choice> * ......<xsd:element name="CommitmentTypeQualifiers" type="CommitmentTypeQualifiersListType" minOccurs="0"/> ...</xsd:sequence> </xsd:complexType> <xsd:complexType * name="CommitmentTypeQualifiersListType"> ...<xsd:sequence> ......<xsd:element name="CommitmentTypeQualifier" type="AnyType" minOccurs="0" maxOccurs="unbounded"/> * ...</xsd:sequence> </xsd:complexType> */ private void incorporateCommitmentTypeIndications() { final List<String> commitmentTypeIndications = params.bLevel().getCommitmentTypeIndications(); if (commitmentTypeIndications != null) { final Element commitmentTypeIndicationDom = DSSXMLUtils.addElement(documentDom, signedDataObjectPropertiesDom, XAdES, XADES_COMMITMENT_TYPE_INDICATION); final Element commitmentTypeIdDom = DSSXMLUtils.addElement(documentDom, commitmentTypeIndicationDom, XAdES, XADES_COMMITMENT_TYPE_ID); for (final String commitmentTypeIndication : commitmentTypeIndications) { DSSXMLUtils.addTextElement(documentDom, commitmentTypeIdDom, XAdES, XADES_IDENTIFIER, commitmentTypeIndication); } //final Element objectReferenceDom = DSSXMLUtils.addElement(documentDom, commitmentTypeIndicationDom, XADES, "ObjectReference"); // or DSSXMLUtils.addElement(documentDom, commitmentTypeIndicationDom, XAdES, XADES_ALL_SIGNED_DATA_OBJECTS); //final Element commitmentTypeQualifiersDom = DSSXMLUtils.addElement(documentDom, commitmentTypeIndicationDom, XADES, "CommitmentTypeQualifiers"); } } /** * Adds signature value to the signature and returns XML signature (InMemoryDocument) * * @param signatureValue * @return * @throws DSSException */ @Override public DSSDocument signDocument(final byte[] signatureValue) throws DSSException { if (!built) { build(); } final EncryptionAlgorithm encryptionAlgorithm = params.getEncryptionAlgorithm(); final byte[] signatureValueBytes = DSSSignatureUtils.convertToXmlDSig(encryptionAlgorithm, signatureValue); final String signatureValueBase64Encoded = Base64.encodeBase64String(signatureValueBytes); final Text signatureValueNode = documentDom.createTextNode(signatureValueBase64Encoded); signatureValueDom.appendChild(signatureValueNode); byte[] documentBytes = DSSXMLUtils.transformDomToByteArray(documentDom); final InMemoryDocument inMemoryDocument = new InMemoryDocument(documentBytes); inMemoryDocument.setMimeType(MimeType.XML); return inMemoryDocument; } /** * Adds the content of a timestamp into a given timestamp element * * @param timestampElement */ protected void addTimestamp(final Element timestampElement, final TimestampToken token) { //List<TimestampInclude> includes, String canonicalizationMethod, TimestampToken encapsulatedTimestamp) { //add includes: URI + referencedData = "true" //add canonicalizationMethod: Algorithm //add encapsulatedTimestamp: Encoding, Id, while its textContent is the base64 encoding of the data to digest final List<TimestampInclude> includes = token.getTimestampIncludes(); if (includes != null) { for (final TimestampInclude include : includes) { final Element timestampIncludeElement = documentDom.createElementNS(XAdES, XADES_INCLUDE); timestampIncludeElement.setAttribute(URI, "#" + include.getURI()); timestampIncludeElement.setAttribute(REFERENCED_DATA, "true"); timestampElement.appendChild(timestampIncludeElement); } } final Element canonicalizationMethodElement = documentDom.createElementNS(XMLNS, DS_CANONICALIZATION_METHOD); canonicalizationMethodElement.setAttribute(ALGORITHM, token.getCanonicalizationMethod()); timestampElement.appendChild(canonicalizationMethodElement); Element encapsulatedTimestampElement = documentDom.createElementNS(XAdES, XADES_ENCAPSULATED_TIME_STAMP); encapsulatedTimestampElement.setTextContent(Base64.encodeBase64String(token.getEncoded())); timestampElement.appendChild(encapsulatedTimestampElement); } }