<commit_before>/**
 * 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 java.util.List;

import org.w3c.dom.Element;

import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.DomUtils;
import eu.europa.esig.dss.SignatureLevel;
import eu.europa.esig.dss.XAdESNamespaces;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.CertificateVerifier;
import eu.europa.esig.dss.validation.DefaultAdvancedSignature;
import eu.europa.esig.dss.validation.SignatureCryptographicVerification;
import eu.europa.esig.dss.validation.ValidationContext;
import eu.europa.esig.dss.x509.RevocationToken;
import eu.europa.esig.dss.x509.crl.CRLToken;
import eu.europa.esig.dss.x509.ocsp.OCSPToken;

/**
 * LT profile of XAdES signature
 *
 */
public class XAdESLevelBaselineLT extends XAdESLevelBaselineT {

	/**
	 * The default constructor for XAdESLevelBaselineLT.
	 */
	public XAdESLevelBaselineLT(final CertificateVerifier certificateVerifier) {
		super(certificateVerifier);
	}

	/**
	 * Adds CertificateValues and RevocationValues segments to UnsignedSignatureProperties.<br>
	 * An XML electronic signature MAY contain at most one:<br>
	 * - CertificateValues element and<br>
	 * - RevocationValues element.
	 *
	 * @see XAdESLevelX#extendSignatureTag()
	 */
	@Override
	protected void extendSignatureTag() throws DSSException {

		assertExtendSignatureToLTPossible();
		super.extendSignatureTag();

		if (xadesSignature.hasLTAProfile()) {
			return;
		}

		// Timestamps can already be loaded in memory (force reload)
		xadesSignature.resetTimestamps();

		/**
		 * In all cases the -LT level need to be regenerated.
		 */
		checkSignatureIntegrity();

		final ValidationContext validationContext = xadesSignature.getSignatureValidationContext(certificateVerifier);

		removeOldCertificateValues();
		removeOldRevocationValues();

		incorporateCertificateValues(unsignedSignaturePropertiesDom, validationContext);
		incorporateRevocationValues(unsignedSignaturePropertiesDom, validationContext);

		/**
		 * Certificate(s), revocation data where added, XAdES signature certificate source must be reset.
		 */
		xadesSignature.resetCertificateSource();
		xadesSignature.resetRevocationSources();
	}

	/**
	 * This method checks the signature integrity and throws a {@code DSSException} if the signature is broken.
	 *
	 * @throws eu.europa.esig.dss.DSSException
	 */
	protected void checkSignatureIntegrity() throws DSSException {
		final SignatureCryptographicVerification signatureCryptographicVerification = xadesSignature.getSignatureCryptographicVerification();
		if (!signatureCryptographicVerification.isSignatureIntact()) {
			final String errorMessage = signatureCryptographicVerification.getErrorMessage();
			throw new DSSException("Cryptographic signature verification has failed" + (errorMessage.isEmpty() ? "." : (" / " + errorMessage)));
		}
	}

	/**
	 * This method removes old revocation values from the unsigned signature properties element.
	 */
	private void removeOldRevocationValues() {
		final Element toRemove = xadesSignature.getRevocationValues();
		if (toRemove != null) {
			unsignedSignaturePropertiesDom.removeChild(toRemove);
			xadesSignature.resetRevocationSources();
		}
	}

	/**
	 * This method removes old certificates values from the unsigned signature properties element.
	 */
	private void removeOldCertificateValues() {
		final Element toRemove = xadesSignature.getCertificateValues();
		if (toRemove != null) {
			unsignedSignaturePropertiesDom.removeChild(toRemove);
			xadesSignature.resetCertificateSource();
		}
	}

	/**
	 * This method incorporates revocation values.
	 * 
	 * <pre>
	 * 	{@code
	 * 		<xades:RevocationValues>
	 * 	}
	 * </pre>
	 *
	 * @param parentDom
	 *            the parent element
	 * @param validationContext
	 *            the validation context with the revocation data
	 */
	protected void incorporateRevocationValues(final Element parentDom, final ValidationContext validationContext) {
		final DefaultAdvancedSignature.RevocationDataForInclusion revocationsForInclusion = xadesSignature.getRevocationDataForInclusion(validationContext);
		if (!revocationsForInclusion.isEmpty()) {

			final Element revocationValuesDom = DomUtils.addElement(documentDom, parentDom, XAdESNamespaces.XAdES, "xades:RevocationValues");

			incorporateCrlTokens(revocationValuesDom, revocationsForInclusion.crlTokens);
			incorporateOcspTokens(revocationValuesDom, revocationsForInclusion.ocspTokens);
		}
	}

	/**
	 * This method incorporates the CRLValues :
	 * 
	 * <pre>
	 * 	{@code
	 * 		<xades:CRLValues>
	 * 			<xades:EncapsulatedCRLValue>...</xades:EncapsulatedCRLValue>
	 * 			...
	 * 		</xades:CRLValues>
	 * 	}
	 * </pre>
	 * 
	 * @param parentDom
	 *            the parent element<commit_msg>DSS-1693 : avoid duplicates revocation data<commit_after>/**
 * 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.bouncycastle.cert.ocsp.BasicOCSPResp;
import org.w3c.dom.Element;

import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.DomUtils;
import eu.europa.esig.dss.SignatureLevel;
import eu.europa.esig.dss.XAdESNamespaces;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.validation.CertificateVerifier;
import eu.europa.esig.dss.validation.DefaultAdvancedSignature;
import eu.europa.esig.dss.validation.SignatureCryptographicVerification;
import eu.europa.esig.dss.validation.ValidationContext;
import eu.europa.esig.dss.x509.RevocationToken;
import eu.europa.esig.dss.x509.crl.CRLToken;
import eu.europa.esig.dss.x509.ocsp.OCSPToken;

/**
 * LT profile of XAdES signature
 *
 */
public class XAdESLevelBaselineLT extends XAdESLevelBaselineT {

	/**
	 * The default constructor for XAdESLevelBaselineLT.
	 */
	public XAdESLevelBaselineLT(final CertificateVerifier certificateVerifier) {
		super(certificateVerifier);
	}

	/**
	 * Adds CertificateValues and RevocationValues segments to UnsignedSignatureProperties.<br>
	 * An XML electronic signature MAY contain at most one:<br>
	 * - CertificateValues element and<br>
	 * - RevocationValues element.
	 *
	 * @see XAdESLevelX#extendSignatureTag()
	 */
	@Override
	protected void extendSignatureTag() throws DSSException {

		assertExtendSignatureToLTPossible();
		super.extendSignatureTag();

		if (xadesSignature.hasLTAProfile()) {
			return;
		}

		// Timestamps can already be loaded in memory (force reload)
		xadesSignature.resetTimestamps();

		/**
		 * In all cases the -LT level need to be regenerated.
		 */
		checkSignatureIntegrity();

		final ValidationContext validationContext = xadesSignature.getSignatureValidationContext(certificateVerifier);

		removeOldCertificateValues();
		removeOldRevocationValues();

		incorporateCertificateValues(unsignedSignaturePropertiesDom, validationContext);
		incorporateRevocationValues(unsignedSignaturePropertiesDom, validationContext);

		/**
		 * Certificate(s), revocation data where added, XAdES signature certificate source must be reset.
		 */
		xadesSignature.resetCertificateSource();
		xadesSignature.resetRevocationSources();
	}

	/**
	 * This method checks the signature integrity and throws a {@code DSSException} if the signature is broken.
	 *
	 * @throws eu.europa.esig.dss.DSSException
	 */
	protected void checkSignatureIntegrity() throws DSSException {
		final SignatureCryptographicVerification signatureCryptographicVerification = xadesSignature.getSignatureCryptographicVerification();
		if (!signatureCryptographicVerification.isSignatureIntact()) {
			final String errorMessage = signatureCryptographicVerification.getErrorMessage();
			throw new DSSException("Cryptographic signature verification has failed" + (errorMessage.isEmpty() ? "." : (" / " + errorMessage)));
		}
	}

	/**
	 * This method removes old revocation values from the unsigned signature properties element.
	 */
	private void removeOldRevocationValues() {
		final Element toRemove = xadesSignature.getRevocationValues();
		if (toRemove != null) {
			unsignedSignaturePropertiesDom.removeChild(toRemove);
			xadesSignature.resetRevocationSources();
		}
	}

	/**
	 * This method removes old certificates values from the unsigned signature properties element.
	 */
	private void removeOldCertificateValues() {
		final Element toRemove = xadesSignature.getCertificateValues();
		if (toRemove != null) {
			unsignedSignaturePropertiesDom.removeChild(toRemove);
			xadesSignature.resetCertificateSource();
		}
	}

	/**
	 * This method incorporates revocation values.
	 * 
	 * <pre>
	 * 	{@code
	 * 		<xades:RevocationValues>
	 * 	}
	 * </pre>
	 *
	 * @param parentDom
	 *            the parent element
	 * @param validationContext
	 *            the validation context with the revocation data
	 */
	protected void incorporateRevocationValues(final Element parentDom, final ValidationContext validationContext) {
		final DefaultAdvancedSignature.RevocationDataForInclusion revocationsForInclusion = xadesSignature.getRevocationDataForInclusion(validationContext);
		if (!revocationsForInclusion.isEmpty()) {

			final Element revocationValuesDom = DomUtils.addElement(documentDom, parentDom, XAdESNamespaces.XAdES, "xades:RevocationValues");

			// Filter to avoid duplicate entries
			List<CRLToken> crlTokens = revocationsForInclusion.crlTokens;
			List<CRLToken> crlsToBeAdded = new ArrayList<CRLToken>();
			Collection<byte[]> containedX509CRLs = xadesSignature.getCRLSource().getContainedX509CRLs();
			for (CRLToken crlToken : crlTokens) {
				boolean found = false;
				byte[] expectedCrl = crlToken.getEncoded();
				for (byte[] byteArray : containedX509CRLs) {
					if (Arrays.equals(expectedCrl, byteArray)) {
						found = true;
						break;
					}
				}
				if (!found) {
					crlsToBeAdded.add(crlToken);
				}
			}

			List<OCSPToken> ocspTokens = revocationsForInclusion.ocspTokens;
			List<OCSPToken> ocspToBeAdded = new ArrayList<OCSPToken>();
			List<BasicOCSPResp> containedOCSPResponses = xadesSignature.getOCSPSource().getContainedOCSPResponses();
			for (OCSPToken ocspToken : ocspTokens) {
				BasicOCSPResp expectedBasicOCSP = ocspToken.getBasicOCSPResp();
				if (!containedOCSPResponses.contains(expectedBasicOCSP)) {
					ocspToBeAdded.add(ocspToken);
				}
			}

			incorporateCrlTokens(revocationValuesDom, crlsToBeAdded);
			incorporateOcspTokens(revocationValuesDom, ocspToBeAdded);
		}
	}

	/**
	 * This method incorporates the CRLValues :
	 * 
	 * <pre>
	 * 	{@code
	 * 		<xades:CRLValues>
	 * 			<xades:EncapsulatedCRLValue>...</xades:EncapsulatedCRLValue>
	 * 			...
	 * 		</xades:CRLValues>
	 * 	}
	 * </pre>
	 * 
	 * @param parentDom
	 *            the parent element
{'fraction_non_alphanumeric': 0.0898332009531374, 'fraction_numerical': 0.005321683876092137, 'mean_word_length': 4.600978647686833, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '833997', 'n_tokens_mistral': 4019, 'n_tokens_neox': 3548, 'n_words': 919}