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

eu.europa.esig.dss.cades.validation.CAdESSignature Maven / Gradle / Ivy

Go to download

DSS CAdES contains the code for the creation and validation of CAdES signatures.

There is a newer version: 6.2.RC1
Show newest version
/**
 * 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.cades.validation;

import eu.europa.esig.dss.cades.CMSUtils;
import eu.europa.esig.dss.cades.SignedAssertion;
import eu.europa.esig.dss.cades.SignedAssertions;
import eu.europa.esig.dss.cades.SignerAttributeV2;
import eu.europa.esig.dss.cades.validation.scope.CAdESSignatureScopeFinder;
import eu.europa.esig.dss.cades.validation.timestamp.CAdESTimestampSource;
import eu.europa.esig.dss.enumerations.DigestAlgorithm;
import eu.europa.esig.dss.enumerations.DigestMatcherType;
import eu.europa.esig.dss.enumerations.EncryptionAlgorithm;
import eu.europa.esig.dss.enumerations.EndorsementType;
import eu.europa.esig.dss.enumerations.MaskGenerationFunction;
import eu.europa.esig.dss.enumerations.SignatureAlgorithm;
import eu.europa.esig.dss.enumerations.SignatureForm;
import eu.europa.esig.dss.enumerations.SignatureLevel;
import eu.europa.esig.dss.model.DSSDocument;
import eu.europa.esig.dss.model.DSSException;
import eu.europa.esig.dss.model.Digest;
import eu.europa.esig.dss.model.DigestDocument;
import eu.europa.esig.dss.model.InMemoryDocument;
import eu.europa.esig.dss.model.ManifestEntry;
import eu.europa.esig.dss.model.ReferenceValidation;
import eu.europa.esig.dss.model.SignaturePolicyStore;
import eu.europa.esig.dss.model.SpDocSpecification;
import eu.europa.esig.dss.model.UserNotice;
import eu.europa.esig.dss.model.scope.SignatureScope;
import eu.europa.esig.dss.model.signature.CommitmentTypeIndication;
import eu.europa.esig.dss.model.signature.SignatureCryptographicVerification;
import eu.europa.esig.dss.model.signature.SignatureDigestReference;
import eu.europa.esig.dss.model.signature.SignaturePolicy;
import eu.europa.esig.dss.model.signature.SignatureProductionPlace;
import eu.europa.esig.dss.model.signature.SignerRole;
import eu.europa.esig.dss.spi.DSSASN1Utils;
import eu.europa.esig.dss.spi.DSSUtils;
import eu.europa.esig.dss.spi.OID;
import eu.europa.esig.dss.spi.SignatureCertificateSource;
import eu.europa.esig.dss.spi.signature.AdvancedSignature;
import eu.europa.esig.dss.spi.x509.CandidatesForSigningCertificate;
import eu.europa.esig.dss.spi.x509.CertificateValidity;
import eu.europa.esig.dss.spi.x509.SignatureIntegrityValidator;
import eu.europa.esig.dss.spi.x509.SignerIdentifier;
import eu.europa.esig.dss.spi.x509.revocation.crl.OfflineCRLSource;
import eu.europa.esig.dss.spi.x509.revocation.ocsp.OfflineOCSPSource;
import eu.europa.esig.dss.spi.x509.tsp.TimestampToken;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.spi.validation.CertificateVerifier;
import eu.europa.esig.dss.spi.signature.DefaultAdvancedSignature;
import eu.europa.esig.dss.spi.signature.identifier.SignatureIdentifierBuilder;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1IA5String;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.esf.OtherHashAlgAndValue;
import org.bouncycastle.asn1.esf.SPUserNotice;
import org.bouncycastle.asn1.esf.SigPolicyQualifierInfo;
import org.bouncycastle.asn1.esf.SigPolicyQualifiers;
import org.bouncycastle.asn1.esf.SignaturePolicyId;
import org.bouncycastle.asn1.esf.SignerAttribute;
import org.bouncycastle.asn1.esf.SignerLocation;
import org.bouncycastle.asn1.ess.ContentHints;
import org.bouncycastle.asn1.ess.ContentIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x500.DirectoryString;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.AttCertValidityPeriod;
import org.bouncycastle.asn1.x509.AttributeCertificate;
import org.bouncycastle.asn1.x509.AttributeCertificateInfo;
import org.bouncycastle.asn1.x509.DisplayText;
import org.bouncycastle.asn1.x509.NoticeReference;
import org.bouncycastle.asn1.x509.RoleSyntax;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataParser;
import org.bouncycastle.cms.CMSTypedStream;
import org.bouncycastle.cms.SignerId;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static eu.europa.esig.dss.spi.OID.id_aa_ets_sigPolicyStore;

/**
 * CAdES Signature class helper
 */
public class CAdESSignature extends DefaultAdvancedSignature {

	private static final long serialVersionUID = 8449504364217200965L;

	private static final Logger LOG = LoggerFactory.getLogger(CAdESSignature.class);

	/** The CMSSignedData of the signature */
	private final CMSSignedData cmsSignedData;

	/** The corresponding SignerInformation to the signature */
	private final SignerInformation signerInformation;

	/**
	 * NOTE: The value shall be cached in order to properly compute a unique
	 * identifier for counter signatures
	 */
	private SignerInformationStore counterSignaturesStore;

	/**
	 * The default constructor for CAdESSignature.
	 *
	 * @param cmsSignedData
	 *            CMSSignedData
	 * @param signerInformation
	 *            an expanded SignerInfo block from a CMS Signed message
	 */
	public CAdESSignature(final CMSSignedData cmsSignedData, final SignerInformation signerInformation) {
		Objects.requireNonNull(cmsSignedData, "CMSSignedData cannot be null!");
		Objects.requireNonNull(signerInformation, "SignerInformation must be provided!");
		this.cmsSignedData = cmsSignedData;
		this.signerInformation = signerInformation;
	}

	@Override
	public SignatureForm getSignatureForm() {
		return SignatureForm.CAdES;
	}

	@Override
	public SignatureCertificateSource getCertificateSource() {
		if (offlineCertificateSource == null) {
			offlineCertificateSource = new CAdESCertificateSource(cmsSignedData, signerInformation);
		}
		return offlineCertificateSource;
	}

	@Override
	public OfflineCRLSource getCRLSource() {
		if (signatureCRLSource == null) {
			try {
				signatureCRLSource = new CAdESCRLSource(cmsSignedData, signerInformation.getUnsignedAttributes());
			} catch (Exception e) {
				// When error in computing or in format of the algorithm: just
				// continues (will try to get online information)
				LOG.warn("Error in computing or in format of the algorithm: just continue...", e);
			}
		}
		return signatureCRLSource;
	}

	@Override
	public OfflineOCSPSource getOCSPSource() {
		if (signatureOCSPSource == null) {
			signatureOCSPSource = new CAdESOCSPSource(cmsSignedData, signerInformation.getUnsignedAttributes());
		}
		return signatureOCSPSource;
	}
	
	@Override
	public CAdESTimestampSource getTimestampSource() {
		if (signatureTimestampSource == null) {
			signatureTimestampSource = new CAdESTimestampSource(this);
		}
		return (CAdESTimestampSource) signatureTimestampSource;
	}
	
	/**
	 * Returns {@code SignerId} of the related to the signature {@code signerInformation}
	 *
	 * @return {@link SignerId}
	 */
	public SignerId getSignerId() {
		return signerInformation.getSID();
	}

	@Override
	protected List findSignatureScopes() {
		return new CAdESSignatureScopeFinder().findSignatureScope(this);
	}

	@Override
	protected SignaturePolicy buildSignaturePolicy() {
		final Attribute attribute = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.id_aa_ets_sigPolicyId);
		if (attribute == null) {
			return null;
		}

		final ASN1Encodable attrValue = attribute.getAttrValues().getObjectAt(0);
		if (attrValue instanceof DERNull) {
			signaturePolicy = new SignaturePolicy();
			return signaturePolicy;
		}

		final SignaturePolicyId sigPolicy = SignaturePolicyId.getInstance(attrValue);
		if (sigPolicy == null) {
			return null;
		}

		final String policyId = sigPolicy.getSigPolicyId().getId();

		signaturePolicy = new SignaturePolicy(policyId);

		final OtherHashAlgAndValue hashAlgAndValue = sigPolicy.getSigPolicyHash();
		final ASN1OctetString digestValue = hashAlgAndValue.getHashValue();
		final byte[] digestValueBytes = digestValue.getOctets();
		boolean zeroHash = isZeroHash(digestValueBytes);
		signaturePolicy.setZeroHash(zeroHash);

		if (!zeroHash) {
			final AlgorithmIdentifier digestAlgorithmIdentifier = hashAlgAndValue.getHashAlgorithm();
			final String digestAlgorithmOID = digestAlgorithmIdentifier.getAlgorithm().getId();
			final DigestAlgorithm digestAlgorithm = DigestAlgorithm.forOID(digestAlgorithmOID);

			signaturePolicy.setDigest(new Digest(digestAlgorithm, digestValueBytes));
		}

		final SigPolicyQualifiers sigPolicyQualifiers = sigPolicy.getSigPolicyQualifiers();
		if (sigPolicyQualifiers != null) {
			for (int ii = 0; ii < sigPolicyQualifiers.size(); ii++) {
				try {
					final SigPolicyQualifierInfo policyQualifierInfo = sigPolicyQualifiers.getInfoAt(ii);
					final ASN1ObjectIdentifier policyQualifierInfoId = policyQualifierInfo.getSigPolicyQualifierId();
					final String policyQualifierInfoValue = policyQualifierInfo.getSigQualifier().toString();

					if (PKCSObjectIdentifiers.id_spq_ets_uri.equals(policyQualifierInfoId)) {
						signaturePolicy.setUri(policyQualifierInfoValue);

					} else if (PKCSObjectIdentifiers.id_spq_ets_unotice.equals(policyQualifierInfoId)) {
						final SPUserNotice spUserNotice = SPUserNotice.getInstance(policyQualifierInfo.getSigQualifier());
						signaturePolicy.setUserNotice(buildSPUserNoticeString(spUserNotice));

					} else if (OID.id_sp_doc_specification.equals(policyQualifierInfoId)) {
						final SpDocSpecification spDocSpecification = new SpDocSpecification();
						spDocSpecification.setId(policyQualifierInfoValue);
						signaturePolicy.setDocSpecification(spDocSpecification);

					} else {
						LOG.warn("Unknown signature policy qualifier id: {} with value: {}", policyQualifierInfoId,
								policyQualifierInfoValue);
					}

				} catch (Exception e) {
					LOG.warn("Unable to read SigPolicyQualifierInfo {} : {}", ii, e.getMessage());
				}
			}
		}
		
		return signaturePolicy;
	}

	private UserNotice buildSPUserNoticeString(SPUserNotice spUserNotice) {
		final UserNotice userNotice = new UserNotice();

		final NoticeReference noticeRef = spUserNotice.getNoticeRef();
		if (noticeRef != null) {
			final DisplayText organization = noticeRef.getOrganization();
			if (organization != null) {
				userNotice.setOrganization(organization.getString());
			}
			final ASN1Integer[] noticeNumbers = noticeRef.getNoticeNumbers();
			if (noticeNumbers != null && noticeNumbers.length != 0) {
				int[] noticeNumbersArray = new int[noticeNumbers.length];
				for (int i = 0; i < noticeNumbers.length ; i++) {
					noticeNumbersArray[i] = noticeNumbers[i].intValueExact();
				}
				userNotice.setNoticeNumbers(noticeNumbersArray);
			}
		}
		final DisplayText explicitText = spUserNotice.getExplicitText();
		if (explicitText != null) {
			userNotice.setExplicitText(explicitText.getString());
		}

		return userNotice;
	}
	
	@Override
	public SignaturePolicyStore getSignaturePolicyStore() {
		final Attribute sigPolicyStore = CMSUtils.getUnsignedAttribute(signerInformation, id_aa_ets_sigPolicyStore);
		if (sigPolicyStore != null && sigPolicyStore.getAttrValues().size() > 0) {
			SignaturePolicyStore signaturePolicyStore = new SignaturePolicyStore();
			SpDocSpecification spDocSpecification = new SpDocSpecification();
			
			ASN1Sequence sequence = ASN1Sequence.getInstance(sigPolicyStore.getAttrValues().getObjectAt(0));
			
			if (sequence.size() == 2) {
				ASN1Encodable spDocSpec = sequence.getObjectAt(0);
				spDocSpecification.setId(spDocSpec.toString());

				ASN1Encodable spDocument = sequence.getObjectAt(1);
				if (spDocument instanceof ASN1OctetString) {
					ASN1OctetString sigPolicyEncoded = ASN1OctetString.getInstance(spDocument);
					signaturePolicyStore.setSignaturePolicyContent(new InMemoryDocument(sigPolicyEncoded.getOctets()));

				} else if (spDocument instanceof ASN1IA5String) {
					ASN1String sigPolicyLocalURI = ASN1IA5String.getInstance(spDocument);
					signaturePolicyStore.setSigPolDocLocalURI(sigPolicyLocalURI.getString());

				} else {
					LOG.warn("Unable to extract a signature-policy-store spDocument. " +
							"One of 'sigPolicyEncoded' or 'sigPolicyLocalURI' is expected!");
				}
				signaturePolicyStore.setSpDocSpecification(spDocSpecification);
				return signaturePolicyStore;

			} else {
				LOG.warn("Unable to extract a signature-policy-store. The element shall contain two attributes.");
			}
		}
		return null;
	}

	private boolean isZeroHash(byte[] hashValue) {
		// The hashValue within the sigPolicyHash may be set to zero or be empty to indicate that
		// the policy hash value is not known.
		return isZeroHashEmpty(hashValue) || doesZeroHashContainSigneZeroByte(hashValue);
	}
	
	private boolean isZeroHashEmpty(byte[] hashValue) {
		return (hashValue != null) && (hashValue.length == 0);
	}
	
	private boolean doesZeroHashContainSigneZeroByte(byte[] hashValue) {
		return (hashValue != null) && (hashValue.length == 1) && ((hashValue[0] == '0') || (hashValue[0] == 0x00));
	}

	@Override
	public Date getSigningTime() {
		final Attribute attr = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.pkcs_9_at_signingTime);
		if (attr == null) {
			return null;
		}
		final ASN1Set attrValues = attr.getAttrValues();
		final ASN1Encodable attrValue = attrValues.getObjectAt(0);
		return CMSUtils.readSigningDate(attrValue);
	}

	/**
	 * Gets CMSSignedData
	 *
	 * @return {@link CMSSignedData} the cmsSignedData
	 */
	public CMSSignedData getCmsSignedData() {
		return cmsSignedData;
	}

	@Override
	public SignatureProductionPlace getSignatureProductionPlace() {
		Attribute signatureProductionPlaceAttr = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.id_aa_ets_signerLocation);
		if (signatureProductionPlaceAttr == null) {
			return null;
		}

		final ASN1Encodable asn1Encodable = signatureProductionPlaceAttr.getAttrValues().getObjectAt(0);
		SignerLocation signerLocation = null;
		try {
			signerLocation = SignerLocation.getInstance(asn1Encodable);
		} catch (Exception e) {
			String errorMessage = "Unable to build a SignerLocation instance. Reason : {}";
			if (LOG.isDebugEnabled()) {
				LOG.warn(errorMessage, e.getMessage(), e);
			} else {
				LOG.warn(errorMessage, e.getMessage());
			}
		}
		if (signerLocation == null) {
			return null;
		}

		final SignatureProductionPlace signatureProductionPlace = new SignatureProductionPlace();

		final DirectoryString countryName = signerLocation.getCountry();
		if (countryName != null) {
			signatureProductionPlace.setCountryName(countryName.getString());
		}

		final DirectoryString localityName = signerLocation.getLocality();
		if (localityName != null) {
			signatureProductionPlace.setCity(localityName.getString());
		}

		final ASN1Sequence seq = signerLocation.getPostalAddress();
		if (seq != null) {
			for (int ii = 0; ii < seq.size(); ii++) {
				String postalAddress = DSSASN1Utils.getDirectoryStringValue(seq.getObjectAt(ii));
				if (Utils.isStringNotEmpty(postalAddress)) {
					signatureProductionPlace.getPostalAddress().add(postalAddress);
				}
			}
		}

		return signatureProductionPlace;
	}

	@Override
	public List getCommitmentTypeIndications() {
		final Attribute commitmentTypeIndicationAttribute = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.id_aa_ets_commitmentType);
		if (commitmentTypeIndicationAttribute == null) {
			return Collections.emptyList();
		}

		try {
			List commitmentTypeIndications = null;
			final ASN1Set attrValues = commitmentTypeIndicationAttribute.getAttrValues();
			final int size = attrValues.size();
			if (size > 0) {
				commitmentTypeIndications = new ArrayList<>();
				for (int ii = 0; ii < size; ii++) {
					if (attrValues.getObjectAt(ii) instanceof ASN1Sequence) {
						final ASN1Sequence sequence = (ASN1Sequence) attrValues.getObjectAt(ii);
						final org.bouncycastle.asn1.esf.CommitmentTypeIndication commitmentTypeIndication =
								org.bouncycastle.asn1.esf.CommitmentTypeIndication.getInstance(sequence);
						final ASN1ObjectIdentifier commitmentTypeId = commitmentTypeIndication.getCommitmentTypeId();
						commitmentTypeIndications.add(new eu.europa.esig.dss.model.signature.CommitmentTypeIndication(commitmentTypeId.getId()));
					} else {
						LOG.warn("Unsupported type for CommitmentType : {}", attrValues.getObjectAt(ii).getClass());
					}
				}
			}
			return commitmentTypeIndications;
		} catch (Exception e) {
			LOG.warn("An error while extracting CommitmentTypeIndication. Reason : {}", e.getMessage(), e);
			return Collections.emptyList();
		}
	}

	@Override
	public List getSignedAssertions() {
		List result = new ArrayList<>();
		final SignerAttributeV2 signerAttrV2 = getSignerAttributeV2();
		if (signerAttrV2 != null) {
		    for (final Object signerAttrValue : signerAttrV2.getValues()) {
			    if (signerAttrValue instanceof SignedAssertions) {
				    List assertions = ((SignedAssertions) signerAttrValue).getAssertions();
				    for (SignedAssertion sa: assertions) {
						result.add(new SignerRole(sa.toString(), EndorsementType.SIGNED));
				    }
			    }
		    }
		}
		return result;
	}

	@Override
	public List getClaimedSignerRoles() {
		final SignerAttribute signerAttr = getSignerAttributeV1();
		final SignerAttributeV2 signerAttrV2 = getSignerAttributeV2();

		Object[] signerAttrValues = null;
		try {

			if (signerAttr != null) {
				signerAttrValues = signerAttr.getValues();
			} else if (signerAttrV2 != null) {
				signerAttrValues = signerAttrV2.getValues();
			}
			if (signerAttrValues == null) {
				return Collections.emptyList();
			}

			final List claimedRoles = new ArrayList<>();
			for (final Object signerAttrValue : signerAttrValues) {
				if (!(signerAttrValue instanceof org.bouncycastle.asn1.x509.Attribute[])) {
					continue;
				}
				final org.bouncycastle.asn1.x509.Attribute[] signerAttrValueArray = (org.bouncycastle.asn1.x509.Attribute[]) signerAttrValue;
				for (final org.bouncycastle.asn1.x509.Attribute claimedRole : signerAttrValueArray) {
					claimedRoles.addAll(getClaimedSignerRoles(claimedRole));
				}
			}
			return claimedRoles;
		} catch (Exception e) {
			LOG.warn("Error when dealing with claimed signer roles : {}", signerAttrValues, e);
			return Collections.emptyList();
		}
	}

	private List getClaimedSignerRoles(final org.bouncycastle.asn1.x509.Attribute claimedRole) {
		final List claimedRoles = new ArrayList<>();
		final ASN1Encodable[] attrValues1 = claimedRole.getAttrValues().toArray();
		for (final ASN1Encodable asn1Encodable : attrValues1) {
			if (asn1Encodable instanceof ASN1String) {
				ASN1String asn1String = (ASN1String) asn1Encodable;
				final String role = asn1String.getString();
				claimedRoles.add(new SignerRole(role, EndorsementType.CLAIMED));
			}
		}
		return claimedRoles;
	}

	@Override
	public List getCertifiedSignerRoles() {
		final SignerAttribute signerAttr = getSignerAttributeV1();
		final SignerAttributeV2 signerAttrV2 = getSignerAttributeV2();

		Object[] signerAttrValues = null;
		try {
			if (signerAttr != null) {
				signerAttrValues = signerAttr.getValues();
			} else if (signerAttrV2 != null) {
				signerAttrValues = signerAttrV2.getValues();
			}
			if (signerAttrValues == null) {
				return Collections.emptyList();
			}
			List roles = new ArrayList<>();
			for (final Object signerAttrValue : signerAttrValues) {
				if (signerAttrValue instanceof AttributeCertificate) {
					roles.addAll(getCertifiedSignerRoles((AttributeCertificate) signerAttrValue));
				}
			}
			return roles;
		} catch (Exception e) {
			LOG.warn("Error when dealing with certified signer roles : {}", signerAttrValues, e);
			return Collections.emptyList();
		}
	}

	private List getCertifiedSignerRoles(final AttributeCertificate attributeCertificate) {
		List roles = new ArrayList<>();
		final AttributeCertificateInfo acInfo = attributeCertificate.getAcinfo();
		final AttCertValidityPeriod attrCertValidityPeriod = acInfo.getAttrCertValidityPeriod();
		final ASN1Sequence attributes = acInfo.getAttributes();
		for (int ii = 0; ii < attributes.size(); ii++) {

			final ASN1Encodable objectAt = attributes.getObjectAt(ii);
			final org.bouncycastle.asn1.x509.Attribute attribute = org.bouncycastle.asn1.x509.Attribute.getInstance(objectAt);
			final ASN1Set attrValues1 = attribute.getAttrValues();
			ASN1Encodable firstItem = attrValues1.getObjectAt(0);
			if (firstItem instanceof ASN1Sequence) {
				ASN1Sequence sequence = (ASN1Sequence) firstItem;
				RoleSyntax roleSyntax = RoleSyntax.getInstance(sequence);
				SignerRole certifiedRole = new SignerRole(roleSyntax.getRoleNameAsString(), EndorsementType.CERTIFIED);
				certifiedRole.setNotBefore(DSSASN1Utils.toDate(attrCertValidityPeriod.getNotBeforeTime()));
				certifiedRole.setNotAfter(DSSASN1Utils.toDate(attrCertValidityPeriod.getNotAfterTime()));
				roles.add(certifiedRole);
			} else {
				LOG.warn("Unsupported type for RoleSyntax : {}", firstItem == null ? null : firstItem.getClass().getSimpleName());
			}
		}
		return roles;
	}

	private SignerAttribute getSignerAttributeV1() {
		final Attribute idAaEtsSignerAttr = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.id_aa_ets_signerAttr);
		if (idAaEtsSignerAttr != null) {
			final ASN1Set attrValues = idAaEtsSignerAttr.getAttrValues();
			final ASN1Encodable attrValue = attrValues.getObjectAt(0);
			try {
				return SignerAttribute.getInstance(attrValue);
			} catch (Exception e) {
				String warningMessage = "Unable to parse signerAttr - [{}]. Reason : {}";
				if (LOG.isDebugEnabled()) {
					LOG.warn(warningMessage, Utils.toBase64(DSSASN1Utils.getDEREncoded(attrValue)), e.getMessage(), e);
				} else {
					LOG.warn(warningMessage, Utils.toBase64(DSSASN1Utils.getDEREncoded(attrValue)), e.getMessage());
				}
			}
		}
		return null;
	}

	private SignerAttributeV2 getSignerAttributeV2() {
		final Attribute idAaEtsSignerAttrV2 = CMSUtils.getSignedAttribute(signerInformation, OID.id_aa_ets_signerAttrV2);
		if (idAaEtsSignerAttrV2 != null) {
			final ASN1Set attrValues = idAaEtsSignerAttrV2.getAttrValues();
			final ASN1Encodable attrValue = attrValues.getObjectAt(0);
			try {
				return SignerAttributeV2.getInstance(attrValue);
			} catch (Exception e) {
				LOG.warn("Unable to parse signerAttrV2 : {}", Utils.toBase64(DSSASN1Utils.getDEREncoded(attrValue)), e);
			}
		}
		return null;
	}

	@Override
	public EncryptionAlgorithm getEncryptionAlgorithm() {

		String oid = signerInformation.getEncryptionAlgOID();
		try {
			return EncryptionAlgorithm.forOID(oid);
		} catch (IllegalArgumentException e) {
			// purposely empty
		}

		try {
			// fallback to identify via signature algorithm
			final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.forOID(oid);
			return signatureAlgorithm.getEncryptionAlgorithm();
		} catch (IllegalArgumentException e) {
			LOG.warn("Unable to identify encryption algorithm for OID '{}'. Reason : {}", oid, e.getMessage());
		}

		return null;
	}

	@Override
	public DigestAlgorithm getDigestAlgorithm() {
		final SignatureAlgorithm signatureAlgorithm = getEncryptedDigestAlgo();
		if (signatureAlgorithm != null) {
			if (EncryptionAlgorithm.RSASSA_PSS.equals(signatureAlgorithm.getEncryptionAlgorithm())) {
				return getPSSHashAlgorithm();
			}
			return signatureAlgorithm.getDigestAlgorithm();

		} else {
			final String digestAlgOID = signerInformation.getDigestAlgOID();
			try {
				return DigestAlgorithm.forOID(digestAlgOID);
			} catch (IllegalArgumentException e) {
				LOG.warn("Unable to identify DigestAlgorithm for OID '{}'. Reason : {}", digestAlgOID, e.getMessage());
				return null;
			}
		}
	}

	private SignatureAlgorithm getEncryptedDigestAlgo() {
		try {
			// RFC 3852 states that's a "signature algorithm" (encryption + digest algorithms) and gives as examples :
			// RSA, DSA and ECDSA (encryption algorithm only)
			return SignatureAlgorithm.forOID(signerInformation.getEncryptionAlgOID());
		} catch (RuntimeException e) {
			// purposely empty
			return null;
		}
	}

	private DigestAlgorithm getPSSHashAlgorithm() {
		try {
			byte[] encryptionAlgParams = signerInformation.getEncryptionAlgParams();
			if (Utils.isArrayNotEmpty(encryptionAlgParams) && !Arrays.equals(DERNull.INSTANCE.getEncoded(), encryptionAlgParams)) {
				RSASSAPSSparams param = RSASSAPSSparams.getInstance(encryptionAlgParams);
				AlgorithmIdentifier pssHashAlgo = param.getHashAlgorithm();
				return DigestAlgorithm.forOID(pssHashAlgo.getAlgorithm().getId());
			}
		} catch (IOException e) {
			LOG.warn("Unable to analyze EncryptionAlgParams", e);
		}
		return null;
	}

	@Override
	@Deprecated
	public MaskGenerationFunction getMaskGenerationFunction() {
		EncryptionAlgorithm encryptionAlgorithm = getEncryptionAlgorithm();
		if (EncryptionAlgorithm.RSASSA_PSS == encryptionAlgorithm) {
			return MaskGenerationFunction.MGF1;
		}
		return null;
	}

	@Override
	public SignatureAlgorithm getSignatureAlgorithm() {
		return SignatureAlgorithm.getAlgorithm(getEncryptionAlgorithm(), getDigestAlgorithm());
	}

	@Override
	public void checkSignatureIntegrity() {
		if (signatureCryptographicVerification != null) {
			return;
		}
		signatureCryptographicVerification = new SignatureCryptographicVerification();
		try {
			
			boolean detachedSignature = CMSUtils.isDetachedSignature(cmsSignedData);
			SignerInformation signerInformationToCheck = null;
			if (detachedSignature && !isCounterSignature()) {
				if (Utils.isCollectionEmpty(detachedContents)) {
					signatureCryptographicVerification.setErrorMessage("Detached file not found!");
					getReferenceValidations(signerInformationToCheck);
					return;
				}
				signerInformationToCheck = recreateSignerInformation();
			} else {
				signerInformationToCheck = signerInformation;
			}
			
			CandidatesForSigningCertificate candidatesForSigningCertificate = getCandidatesForSigningCertificate();
			
			SignatureIntegrityValidator signingCertificateValidator = new CAdESSignatureIntegrityValidator(signerInformationToCheck);
			CertificateValidity certificateValidity = signingCertificateValidator.validate(candidatesForSigningCertificate);
			if (certificateValidity != null) {
				candidatesForSigningCertificate.setTheCertificateValidity(certificateValidity);
			}
			
			List errorMessages = signingCertificateValidator.getErrorMessages();
			signatureCryptographicVerification.setErrorMessages(errorMessages);
			signatureCryptographicVerification.setSignatureIntact(certificateValidity != null);

			boolean referenceDataFound = true;
			boolean referenceDataIntact = true;
			List refValidations = getReferenceValidations(signerInformationToCheck);
			for (ReferenceValidation referenceValidation : refValidations) {
				referenceDataFound = referenceDataFound && referenceValidation.isFound();
				referenceDataIntact = referenceDataIntact && referenceValidation.isIntact();
			}
			signatureCryptographicVerification.setReferenceDataFound(referenceDataFound);
			signatureCryptographicVerification.setReferenceDataIntact(referenceDataIntact);
			
		} catch (CMSException | IOException e) {
			LOG.warn(e.getMessage(), e);
			signatureCryptographicVerification.setErrorMessage(e.getMessage());
		}
		LOG.debug(" - RESULT: {}", signatureCryptographicVerification);
	}

	/**
	 * Returns the reference validation
	 *
	 * @param signerInformationToCheck {@link SignerInformation}
	 * @return a list of {@link ReferenceValidation}s
	 */
	public List getReferenceValidations(SignerInformation signerInformationToCheck) {
		if (referenceValidations == null) {
			referenceValidations = new ArrayList<>();

			DSSDocument originalDocument = null;
			try {
				originalDocument = getSignerDocumentContent();
			} catch (DSSException e) {
				LOG.warn("Original document not found");
			}

			ReferenceValidation validation;
			final byte[] messageDigestValue = getMessageDigestValue();
			if (messageDigestValue != null) {
				validation = getMessageDigestReferenceValidation(originalDocument, messageDigestValue);
			} else {
				LOG.warn("message-digest is not present in SignedData! Extracting digests from content SignatureValue...");
				validation = getContentReferenceValidation(originalDocument, signerInformationToCheck);
			}

			referenceValidations.add(validation);

		}
		return referenceValidations;
	}

	/**
	 * This method extracts a document content that was signed
	 *
	 * NOTE: Some differences are possible with PAdES
	 *
	 * @return {@link DSSDocument}
	 */
	protected DSSDocument getSignerDocumentContent() {
		return getOriginalDocument();
	}

	private boolean verifyDigestAlgorithm(DSSDocument originalDocument, Set messageDigestAlgorithms,
			Digest messageDigest) {
		if (Utils.isCollectionNotEmpty(messageDigestAlgorithms)) {
			// try to match with found digest algorithm(s)
			for (DigestAlgorithm digestAlgorithm : messageDigestAlgorithms) {
				byte[] base64Digest = originalDocument.getDigestValue(digestAlgorithm);
				if (Arrays.equals(messageDigest.getValue(), base64Digest)) {
					messageDigest.setAlgorithm(digestAlgorithm);
					return true;
				}
			}
		} else {
			LOG.warn("Message DigestAlgorithms not found in SignedData! Reference validation is not possible.");
		}

		return false;
	}
	
	private List getManifestEntryValidation() {
		List manifestEntryValidations = new ArrayList<>();
		if (manifestFile == null) {
			if (LOG.isDebugEnabled()) {
				LOG.debug("No related manifest file found for a signature with name [{}]", getSignatureFilename());
			}
			return manifestEntryValidations;
		}
		for (ManifestEntry entry : manifestFile.getEntries()) {
			ReferenceValidation entryValidation = new ReferenceValidation();
			entryValidation.setType(DigestMatcherType.MANIFEST_ENTRY);
			entryValidation.setUri(entry.getUri());
			entryValidation.setDocumentName(entry.getDocumentName());
			entryValidation.setDigest(entry.getDigest());
			entryValidation.setFound(entry.isFound());
			entryValidation.setIntact(entry.isIntact());
			manifestEntryValidations.add(entryValidation);
		}
		
		return manifestEntryValidations;
	}

	@Override
	public List getReferenceValidations() {
		checkSignatureIntegrity();
		return referenceValidations;
	}
	
	/**
	 * Verifies a message-digest of a CMSSignedData, when applicable
	 *
	 * @param originalDocument {@link DSSDocument} the signed original document
	 * @param messageDigestValue message-digest byte array content
	 * @return {@link ReferenceValidation}
	 */
	private ReferenceValidation getMessageDigestReferenceValidation(DSSDocument originalDocument, byte[] messageDigestValue) {
		ReferenceValidation messageDigestValidation = new ReferenceValidation();
		messageDigestValidation.setType(DigestMatcherType.MESSAGE_DIGEST);
		
		Digest messageDigest = new Digest();
		messageDigest.setValue(messageDigestValue);
		messageDigestValidation.setDigest(messageDigest);

		Set digestAlgorithmCandidates = new HashSet<>();
		DigestAlgorithm signerInformationDigestAlgorithm = getDigestAlgorithm();
		if (signerInformationDigestAlgorithm != null) {
			digestAlgorithmCandidates.add(signerInformationDigestAlgorithm);
		}
		digestAlgorithmCandidates.addAll(getMessageDigestAlgorithms());
		
		if (Utils.collectionSize(digestAlgorithmCandidates) == 1) {
			messageDigest.setAlgorithm(digestAlgorithmCandidates.iterator().next());
		}

		if (originalDocument != null) {
			messageDigestValidation.setDocumentName(originalDocument.getName());
			messageDigestValidation.setFound(true);
			messageDigestValidation.setIntact(verifyDigestAlgorithm(originalDocument, digestAlgorithmCandidates, messageDigest));

			if (manifestFile != null && 
					Arrays.equals(messageDigest.getValue(), manifestFile.getDigestValue(messageDigest.getAlgorithm()))) {
				// get references to documents contained in the manifest file (for ASiC-E container)
				messageDigestValidation.getDependentValidations()
						.addAll(getManifestEntryValidation());
			}
		} else {
			LOG.warn("The original document is not found or cannot be extracted. Reference validation is not possible.");
		}
		return messageDigestValidation;
	}
	
	/**
	 * Verifies a content digest, when applicable
	 *
	 * @param originalDocument {@link DSSDocument} the signed original document
	 * @param signerInformation {@link SignerInformation}
	 * @return {@link ReferenceValidation}
	 */
	private ReferenceValidation getContentReferenceValidation(DSSDocument originalDocument, SignerInformation signerInformation) {
		ReferenceValidation contentValidation = new ReferenceValidation();
		contentValidation.setType(DigestMatcherType.CONTENT_DIGEST);
		if (signerInformation != null) {
			DigestAlgorithm digestAlgorithm = getDigestAlgorithmForOID(signerInformation.getDigestAlgOID());
			if (originalDocument != null && digestAlgorithm != null) {
				byte[] contentDigest = signerInformation.getContentDigest();
				if (Utils.isArrayNotEmpty(contentDigest)) {
					contentValidation.setFound(true);
					contentValidation.setDigest(new Digest(digestAlgorithm, contentDigest));
					if (Arrays.equals(contentDigest, originalDocument.getDigestValue(digestAlgorithm))) {
						contentValidation.setIntact(true);
					}
				}
			}
		}
		return contentValidation;
	}
	
	/**
	 * TS 119 442 - V1.1.1 - Electronic Signatures and Infrastructures (ESI), ch. 5.1.4.2.1.3 XML component:
	 * 
	 * In case of CAdES signatures, the input to the digest value computation shall be one of the DER-encoded
	 * instances of SignedInfo type present within the CMS structure. 
	 */
	@Override
	public SignatureDigestReference getSignatureDigestReference(DigestAlgorithm digestAlgorithm) {
		byte[] derEncodedSignerInfo = DSSASN1Utils.getDEREncoded(signerInformation.toASN1Structure());
		byte[] digestValue = DSSUtils.digest(digestAlgorithm, derEncodedSignerInfo);
		return new SignatureDigestReference(new Digest(digestAlgorithm, digestValue));
	}
	
	@Override
	public Digest getDataToBeSignedRepresentation() {
		List referenceValidations = getReferenceValidations();
		ReferenceValidation referenceValidation = referenceValidations.iterator().next(); // only one is allowed for CMS
		switch (referenceValidation.getType()) {
			case MESSAGE_DIGEST:
				DigestAlgorithm digestAlgorithm = getDigestAlgorithm();
				if (digestAlgorithm != null) {
					AttributeTable signedAttributes = CMSUtils.getSignedAttributes(signerInformation);
					byte[] derEncoded = DSSASN1Utils.getDEREncoded(signedAttributes.toASN1Structure());
					return new Digest(digestAlgorithm, DSSUtils.digest(digestAlgorithm, derEncoded));
				}
				return null;
			case CONTENT_DIGEST:
				return referenceValidation.getDigest();
			default:
				throw new DSSException(String.format("The found referenceValidation type '%s' is not supported! "
						+ "Unable to compute DTBSR.", referenceValidation.getType()));
		}
	}

	/**
	 * This method recreates a {@code SignerInformation} with the content using
	 * a {@code CMSSignedDataParser}.
	 *
	 * @return {@link SignerInformation}
	 * @throws CMSException if CMS exception occurs
	 * @throws IOException if IOException occurs
	 */
	private SignerInformation recreateSignerInformation() throws CMSException, IOException {

		final DSSDocument dssDocument = detachedContents.get(0); // only one element for CAdES Signature
		CMSSignedDataParser cmsSignedDataParser;
		if (dssDocument instanceof DigestDocument) {
			cmsSignedDataParser = new CMSSignedDataParser(new PrecomputedDigestCalculatorProvider((DigestDocument) dssDocument), cmsSignedData.getEncoded());
		} else {
			try (InputStream inputStream = dssDocument.openStream()) {
				final CMSTypedStream signedContent = new CMSTypedStream(inputStream);
				cmsSignedDataParser = new CMSSignedDataParser(new BcDigestCalculatorProvider(), signedContent, cmsSignedData.getEncoded());
				cmsSignedDataParser.getSignedContent().drain(); // Closes the stream
			}
		}

		final SignerId signerId = getSignerId();
		return cmsSignedDataParser.getSignerInfos().get(signerId);
	}

	/**
	 * Returns a set of used {@link DigestAlgorithm}s incorporated into the CMSSignedData
	 *
	 * @return a set of {@link DigestAlgorithm}s
	 */
	public Set getMessageDigestAlgorithms() {
		Set result = new HashSet<>();
		Set digestAlgorithmIDs = cmsSignedData.getDigestAlgorithmIDs();
		for (AlgorithmIdentifier algorithmIdentifier : digestAlgorithmIDs) {
			String oid = algorithmIdentifier.getAlgorithm().getId();
			DigestAlgorithm digestAlgorithm = getDigestAlgorithmForOID(oid);
			if (digestAlgorithm != null) {
				result.add(digestAlgorithm);
			}
		}
		return result;
	}
	
	private DigestAlgorithm getDigestAlgorithmForOID(String oid) {
		try {
			return DigestAlgorithm.forOID(oid);
		} catch (IllegalArgumentException e) {
			LOG.warn("Not a digest algorithm {} : {}", oid, e.getMessage());
			return null;
		}
	}

	/**
	 * Returns a digest value incorporated in an attribute "message-digest" in CMS
	 * Signed Data
	 * 
	 * @return a byte array representing a signed content digest value
	 */
	public byte[] getMessageDigestValue() {
		final Attribute messageDigestAttribute = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.pkcs_9_at_messageDigest);
		if (messageDigestAttribute == null) {
			return null;
		}
		final ASN1OctetString asn1OctetString = (ASN1OctetString) messageDigestAttribute.getAttrValues().getObjectAt(0);
		return asn1OctetString.getOctets();
	}

	@Override
	public String getContentType() {
		final Attribute contentTypeAttribute = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.pkcs_9_at_contentType);
		if (contentTypeAttribute == null) {
			return null;
		}
		final ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) contentTypeAttribute.getAttrValues().getObjectAt(0);
		return oid.getId();
	}

	@Override
	public String getMimeType() {
		final Attribute mimeTypeAttribute = CMSUtils.getSignedAttribute(signerInformation, OID.id_aa_ets_mimeType);
		if (mimeTypeAttribute == null) {
			return null;
		}
		return DSSASN1Utils.getString(mimeTypeAttribute.getAttrValues().getObjectAt(0));
	}

	/**
	 * Gets ContentIdentifier String
	 *
	 * @return content identifier as {@code String}
	 */
	public String getContentIdentifier() {
		final Attribute contentIdentifierAttribute = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.id_aa_contentIdentifier);
		if (contentIdentifierAttribute == null) {
			return null;
		}
		final ASN1Encodable asn1Encodable = contentIdentifierAttribute.getAttrValues().getObjectAt(0);
		final ContentIdentifier contentIdentifier = ContentIdentifier.getInstance(asn1Encodable);
		return DSSASN1Utils.toString(contentIdentifier.getValue());
	}

	/**
	 * Gets Content Hints
	 *
	 * @return content hints as {@code String}
	 */
	public String getContentHints() {
		final Attribute contentHintAttribute = CMSUtils.getSignedAttribute(signerInformation, PKCSObjectIdentifiers.id_aa_contentHint);
		if (contentHintAttribute == null) {
			return null;
		}
		final ASN1Encodable asn1Encodable = contentHintAttribute.getAttrValues().getObjectAt(0);
		String contentHint = null;
		try {
			final ContentHints contentHints = ContentHints.getInstance(asn1Encodable);
			if (contentHints != null) {
				// content-type is mandatory
				contentHint = contentHints.getContentType().toString();
				// content-description is optional
				if (contentHints.getContentDescriptionUTF8() != null) {
					contentHint += " [" + contentHints.getContentDescriptionUTF8().toString() + "]";
				}
			}
		} catch (Exception e) {
			String warningMessage = "Unable to parse ContentHints - [{}]. Reason : {}";
			if (LOG.isDebugEnabled()) {
				LOG.warn(warningMessage, Utils.toBase64(DSSASN1Utils.getDEREncoded(asn1Encodable)), e.getMessage(), e);
			} else {
				LOG.warn(warningMessage, Utils.toBase64(DSSASN1Utils.getDEREncoded(asn1Encodable)), e.getMessage());
			}
		}

		return contentHint;
	}

	/**
	 * Gets a SignedInformation
	 *
	 * @return {@link SignerInformation} the signerInformation
	 */
	public SignerInformation getSignerInformation() {
		return signerInformation;
	}
	
	@Override
	public byte[] getSignatureValue() {
		return signerInformation.getSignature();
	}
	
	@Override
	public boolean isCounterSignature() {
		return signerInformation.isCounterSignature();
	}

	@Override
	public List getCounterSignatures() {
		if (counterSignatures != null) {
			return counterSignatures;
		}
		
		counterSignatures = new ArrayList<>();
		for (final SignerInformation counterSignerInformation : getCounterSignatureStore()) {
			final CAdESSignature counterSignature = new CAdESSignature(cmsSignedData, counterSignerInformation);
			counterSignature.setSignatureFilename(getSignatureFilename());
			counterSignature.setMasterSignature(this);
			counterSignatures.add(counterSignature);
		}
		return counterSignatures;
	}
	
	/**
	 * Returns a SignerInformationStore containing counter signatures
	 * 
	 * @return {@link SignerInformationStore}
	 */
	protected SignerInformationStore getCounterSignatureStore() {
		if (counterSignaturesStore == null) {
			counterSignaturesStore = signerInformation.getCounterSignatures();
		}
		return counterSignaturesStore;
	}

	/**
	 * Returns the original signed document
	 *
	 * @return {@link DSSDocument}
	 */
	public DSSDocument getOriginalDocument() {
		// RFC 5652 ch 11.4.
		if (isCounterSignature()) {
			return new InMemoryDocument(getMasterSignature().getSignatureValue());
		}

		return CMSUtils.getOriginalDocument(cmsSignedData, detachedContents);
	}
	
	@Override
	protected SignatureIdentifierBuilder getSignatureIdentifierBuilder() {
		return new CAdESSignatureIdentifierBuilder(this);
	}
	
	@Override
	public String getDAIdentifier() {
		// not applicable for CAdES
		return null;
	}

	/**
	 * Returns a Set of CertificateIdentifier extracted from a
	 * SignerInformationStore of CMS Signed Data
	 * 
	 * @return a Set of {@link SignerIdentifier}s
	 */
	public Set getSignerInformationStoreInfos() {
		return getCertificateSource().getAllCertificateIdentifiers();
	}

	@Override
	public void addExternalTimestamp(TimestampToken timestamp) {
		if (!timestamp.isProcessed()) {
			throw new DSSException("Timestamp token must be validated first !");
		}
		getTimestampSource().addExternalTimestamp(timestamp);
	}

	@Override
	public SignatureLevel getDataFoundUpToLevel() {
		if (!hasBESProfile()) {
			return SignatureLevel.CMS_NOT_ETSI;
		}

		boolean baselineProfile = hasBProfile();

		if (!hasExtendedTProfile()) {
			if (baselineProfile) {
				return SignatureLevel.CAdES_BASELINE_B;
			} else if (hasEPESProfile()) {
				return SignatureLevel.CAdES_EPES;
			}
			return SignatureLevel.CAdES_BES;
		}

		baselineProfile = baselineProfile && hasTProfile();

		if (baselineProfile && hasLTProfile()) {
			if (hasLTAProfile()) {
				return SignatureLevel.CAdES_BASELINE_LTA;
			}
			return SignatureLevel.CAdES_BASELINE_LT;

		} else if (hasCProfile()) {
			if (hasXLProfile()) {
				if (hasAProfile()) {
					return SignatureLevel.CAdES_A;
				}
				if (hasXProfile()) {
					return SignatureLevel.CAdES_XL;
				}
			}
			if (hasXProfile()) {
				return SignatureLevel.CAdES_X;
			}
			return SignatureLevel.CAdES_C;

		} else if (hasXLProfile()) {
			if (hasAProfile()) {
				return SignatureLevel.CAdES_A; // CAdES-E-A can be built on CAdES-E-T directly
			}
			return SignatureLevel.CAdES_LT;
		}

		return baselineProfile ? SignatureLevel.CAdES_BASELINE_T : SignatureLevel.CAdES_T;
	}

	@Override
	protected CAdESBaselineRequirementsChecker getBaselineRequirementsChecker() {
		return (CAdESBaselineRequirementsChecker) super.getBaselineRequirementsChecker();
	}

	@Override
	protected CAdESBaselineRequirementsChecker createBaselineRequirementsChecker(CertificateVerifier certificateVerifier) {
		return new CAdESBaselineRequirementsChecker(this, certificateVerifier);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy