package eu.europa.esig.dss.validation;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.europa.esig.dss.DSSASN1Utils;
import eu.europa.esig.dss.DSSDocument;
import eu.europa.esig.dss.DSSPKUtils;
import eu.europa.esig.dss.DSSUtils;
import eu.europa.esig.dss.DigestAlgorithm;
import eu.europa.esig.dss.EncryptionAlgorithm;
import eu.europa.esig.dss.SignatureAlgorithm;
import eu.europa.esig.dss.SignatureLevel;
import eu.europa.esig.dss.jaxb.diagnostic.DiagnosticData;
import eu.europa.esig.dss.jaxb.diagnostic.XmlBasicSignature;
import eu.europa.esig.dss.jaxb.diagnostic.XmlCertificate;
import eu.europa.esig.dss.jaxb.diagnostic.XmlCertifiedRole;
import eu.europa.esig.dss.jaxb.diagnostic.XmlChainItem;
import eu.europa.esig.dss.jaxb.diagnostic.XmlContainerInfo;
import eu.europa.esig.dss.jaxb.diagnostic.XmlDigestAlgoAndValue;
import eu.europa.esig.dss.jaxb.diagnostic.XmlDistinguishedName;
import eu.europa.esig.dss.jaxb.diagnostic.XmlManifestFile;
import eu.europa.esig.dss.jaxb.diagnostic.XmlMessage;
import eu.europa.esig.dss.jaxb.diagnostic.XmlOID;
import eu.europa.esig.dss.jaxb.diagnostic.XmlPolicy;
import eu.europa.esig.dss.jaxb.diagnostic.XmlRevocation;
import eu.europa.esig.dss.jaxb.diagnostic.XmlSignature;
import eu.europa.esig.dss.jaxb.diagnostic.XmlSignatureProductionPlace;
import eu.europa.esig.dss.jaxb.diagnostic.XmlSignatureScope;
import eu.europa.esig.dss.jaxb.diagnostic.XmlSignedObjects;
import eu.europa.esig.dss.jaxb.diagnostic.XmlSignedSignature;
import eu.europa.esig.dss.jaxb.diagnostic.XmlSigningCertificate;
import eu.europa.esig.dss.jaxb.diagnostic.XmlStructuralValidation;
import eu.europa.esig.dss.jaxb.diagnostic.XmlTimestamp;
import eu.europa.esig.dss.jaxb.diagnostic.XmlTimestampedTimestamp;
import eu.europa.esig.dss.jaxb.diagnostic.XmlTrustedList;
import eu.europa.esig.dss.jaxb.diagnostic.XmlTrustedService;
import eu.europa.esig.dss.jaxb.diagnostic.XmlTrustedServiceProvider;
import eu.europa.esig.dss.tsl.Condition;
import eu.europa.esig.dss.tsl.KeyUsageBit;
import eu.europa.esig.dss.tsl.ServiceInfo;
import eu.europa.esig.dss.tsl.ServiceInfoStatus;
import eu.europa.esig.dss.tsl.TLInfo;
import eu.europa.esig.dss.tsl.TrustedListsCertificateSource;
import eu.europa.esig.dss.utils.Utils;
import eu.europa.esig.dss.x509.CertificateSource;
import eu.europa.esig.dss.x509.CertificateSourceType;
import eu.europa.esig.dss.x509.CertificateToken;
import eu.europa.esig.dss.x509.RevocationToken;
import eu.europa.esig.dss.x509.SignaturePolicy;
import eu.europa.esig.dss.x509.Token;
/**
* This class is used to build JAXB objects from the DSS model
*
*/
public class DiagnosticDataBuilder {
private static final Logger LOG = LoggerFactory.getLogger(DiagnosticDataBuilder.class);
private DSSDocument signedDocument;
private ContainerInfo containerInfo;
private List<AdvancedSignature> signatures;
private Set<CertificateToken> usedCertificates;
private TrustedListsCertificateSource trustedListCertSource;
private Date validationDate;
/**
* This method allows to set the document which is analysed
*
* @param signedDocument
* the document which is analysed
* @return the builder
*/
public DiagnosticDataBuilder document(DSSDocument signedDocument) {
this.signedDocument = signedDocument;
return this;
}
/**
* This method allows to set the container info (ASiC)
*
* @param containerInfo
* the container information
* @return the builder
*/
public DiagnosticDataBuilder containerInfo(ContainerInfo containerInfo) {
this.containerInfo = containerInfo;
return this;
}
/**
* This method allows to set the found signatures
*
* @param signatures
* the found signatures
* @return the builder
*/
public DiagnosticDataBuilder foundSignatures(List<AdvancedSignature> signatures) {
this.signatures = signatures;
return this;
}
/**
* This method allows to set the used certificates
*
* @param usedCertificates
* the used certificates
* @return the builder
*/
public DiagnosticDataBuilder usedCertificates(Set<CertificateToken> usedCertificates) {
this.usedCertificates = usedCertificates;
return this;
}
/**
* This method allows to set the TrustedListsCertificateSource
*
* @param trustedCertSource
* the trusted lists certificate source
* @return the builder
*/
public DiagnosticDataBuilder trustedListsCertificateSource(CertificateSource trustedCertSource) {
if (trustedCertSource instanceof TrustedListsCertificateSource) {
this.trustedListCertSource = (TrustedListsCertificateSource) trustedCertSource;
}
return this;
}
/**
* This method allows to set the validation date
*
* @param validationDate
* the validation date
* @return the builder
*/
public DiagnosticDataBuilder validationDate(Date validationDate) {
this.validationDate = validationDate;
return this;
}
public DiagnosticData build() {
DiagnosticData diagnosticData = new DiagnosticData();
diagnosticData.setDocumentName(removeSpecialCharsForXml(signedDocument.getName()));
diagnosticData.setValidationDate(validationDate);
diagnosticData.setContainerInfo(getXmlContainerInfo());
Set<DigestAlgorithm> allUsedCertificatesDigestAlgorithms = new HashSet<DigestAlgorithm>();
for (AdvancedSignature advancedSignature : signatures) {
allUsedCertificatesDigestAlgorithms.addAll(advancedSignature.getUsedCertificatesDigestAlgorithms());
diagnosticData.getSignatures().add(getXmlSignature(advancedSignature));
}
List<XmlCertificate> xmlCertificates = new ArrayList<XmlCertificate>();
Set<String> countryCodes = new HashSet<String>();
for (CertificateToken certificateToken : usedCertificates) {
xmlCertificates.add(getXmlCertificate(allUsedCertificatesDigestAlgorithms, certificateToken));
Set<ServiceInfo> associatedTSPS = certificateToken.getAssociatedTSPS();
if (Utils.isCollectionNotEmpty(associatedTSPS)) {
for (ServiceInfo serviceInfo : associatedTSPS) {
countryCodes.add(serviceInfo.getTlCountryCode());
}
}
}
diagnosticData.setUsedCertificates(Collections.unmodifiableList(xmlCertificates));
if (trustedListCertSource != null) {
boolean addLOTL = false;
for (String countryCode : countryCodes) {
TLInfo tlInfo = trustedListCertSource.getTlInfo(countryCode);
if (tlInfo != null) {
diagnosticData.getTrustedLists().add(getXmlTrustedList(countryCode, tlInfo));
addLOTL = true;
}
}
if (addLOTL) {
diagnosticData.setListOfTrustedLists(getXmlTrustedList("LOTL", trustedListCertSource.getLotlInfo()));
}
}
return diagnosticData;
}
private XmlTrustedList getXmlTrustedList(String countryCode, TLInfo tlInfo) {
if (tlInfo != null) {
XmlTrustedList result = new XmlTrustedList();
result.setCountryCode(tlInfo.getCountryCode());
result.setUrl(tlInfo.getUrl());
result.setIssueDate(tlInfo.getIssueDate());
result.setNextUpdate(tlInfo.getNextUpdate());
result.setLastLoading(tlInfo.getLastLoading());
result.setSequenceNumber(tlInfo.getSequenceNumber());
result.setVersion(tlInfo.getVersion());
result.setWellSigned(tlInfo.isWellSigned());
return result;
} else {
LOG.warn("Not info found for country " + countryCode);
return null;
}
}
private XmlContainerInfo getXmlContainerInfo() {
if (containerInfo != null) {
XmlContainerInfo xmlContainerInfo = new XmlContainerInfo();
xmlContainerInfo.setContainerType(containerInfo.getContainerType().getReadable());
String zipComment = containerInfo.getZipComment();
if (Utils.isStringNotBlank(zipComment)) {
xmlContainerInfo.setZipComment(zipComment);
}
xmlContainerInfo.setMimeTypeFilePresent(containerInfo.isMimeTypeFilePresent());
xmlContainerInfo.setMimeTypeContent(containerInfo.getMimeTypeContent());
xmlContainerInfo.setContentFiles(containerInfo.getSignedDocumentFilenames());
xmlContainerInfo.setManifestFiles(getXmlManifests(containerInfo.getManifestFiles()));
return xmlContainerInfo;
}
return null;
}
private List<XmlManifestFile> getXmlManifests(List<ManifestFile> manifestFiles) {
if (Utils.isCollectionNotEmpty(manifestFiles)) {
List<XmlManifestFile> xmlManifests = new ArrayList<XmlManifestFile>();
for (ManifestFile manifestFile : manifestFiles) {
XmlManifestFile xmlManifest = new XmlManifestFile();
xmlManifest.setFilename(manifestFile.getFilename());
xmlManifest.setSignatureFilename(manifestFile.getSignatureFilename());
xmlManifest.getEntries().addAll(manifestFile.getEntries());
xmlManifests.add(xmlManifest);
}
return xmlManifests;
}
return null;
}
private XmlSignature getXmlSignature(AdvancedSignature signature) {
XmlSignature xmlSignature = new XmlSignature();
xmlSignature.setSignatureFilename(removeSpecialCharsForXml(signature.getSignatureFilename()));
final AdvancedSignature masterSignature = signature.getMasterSignature();
if (masterSignature != null) {
xmlSignature.setType(AttributeValue.COUNTERSIGNATURE);
xmlSignature.setParentId(masterSignature.getId());
}
xmlSignature.setId(signature.getId());
xmlSignature.setDateTime(signature.getSigningTime());
xmlSignature.setStructuralValidation(getXmlStructuralValidation(signature));
xmlSignature.setSignatureFormat(getXmlSignatureFormat(signature.getDataFoundUpToLevel()));
xmlSignature.setSignatureProductionPlace(getXmlSignatureProductionPlace(signature.getSignatureProductionPlace()));
xmlSignature.setCommitmentTypeIndication(getXmlCommitmentTypeIndication(signature.getCommitmentTypeIndication()));
xmlSignature.setClaimedRoles(getXmlClaimedRole(signature.getClaimedSignerRoles()));
xmlSignature.getCertifiedRoles().addAll(getXmlCertifiedRoles(signature.getCertifiedSignerRoles()));
xmlSignature.setContentType(signature.getContentType());
xmlSignature.setContentIdentifier(signature.getContentIdentifier());
xmlSignature.setContentHints(signature.getContentHints());
CertificateToken signingCertificateToken = null;
final CandidatesForSigningCertificate candidatesForSigningCertificate = signature.getCandidatesForSigningCertificate();
final CertificateValidity theCertificateValidity = candidatesForSigningCertificate.getTheCertificateValidity();
if (theCertificateValidity != null) {
xmlSignature.setSigningCertificate(getXmlSigningCertificate(theCertificateValidity));
signingCertificateToken = theCertificateValidity.getCertificateToken();
}
xmlSignature.setCertificateChain(getXmlForCertificateChain(signingCertificateToken));
xmlSignature.setBasicSignature(getXmlBasicSignature(signature, signingCertificateToken));
xmlSignature.setPolicy(getXmlPolicy(signature.getPolicyId()));
xmlSignature.setTimestamps(getXmlTimestamps(signature));
xmlSignature.setSignatureScopes(getXmlSignatureScopes(signature.getSignatureScopes()));
return xmlSignature;
}
private XmlStructuralValidation getXmlStructuralValidation(AdvancedSignature signature) {
String structureValidationResult = signature.getStructureValidationResult();
final XmlStructuralValidation xmlStructuralValidation = new XmlStructuralValidation();
xmlStructuralValidation.setValid(Utils.isStringEmpty(structureValidationResult));
if (Utils.isStringNotEmpty(structureValidationResult)) {
xmlStructuralValidation.setMessage(structureValidationResult);
}
return xmlStructuralValidation;
}
/**
* Escape special characters which cause problems with jaxb or documentbuilderfactory and namespace aware mode
*/
private String removeSpecialCharsForXml(String text) {
if (Utils.isStringNotEmpty(text)) {
return text.replaceAll("&", "");
}
return Utils.EMPTY_STRING;
}
private XmlRevocation getXmlRevocation(RevocationToken revocationToken, String xmlId, Set<DigestAlgorithm> usedDigestAlgorithms) {
final XmlRevocation xmlRevocation = new XmlRevocation();
xmlRevocation.setId(xmlId);
xmlRevocation.setOrigin(revocationToken.getOrigin().name());
final Boolean revocationTokenStatus = revocationToken.getStatus();
// revocationTokenStatus can be null when OCSP return Unknown. In
// this case we set status to false.
xmlRevocation.setStatus(revocationTokenStatus == null ? false : revocationTokenStatus);
xmlRevocation.setProductionDate(revocationToken.getProductionDate());
xmlRevocation.setThisUpdate(revocationToken.getThisUpdate());
xmlRevocation.setNextUpdate(revocationToken.getNextUpdate());
xmlRevocation.setRevocationDate(revocationToken.getRevocationDate());
xmlRevocation.setExpiredCertsOnCRL(revocationToken.getExpiredCertsOnCRL());
xmlRevocation.setArchiveCutOff(revocationToken.getArchiveCutOff());
xmlRevocation.setReason(revocationToken.getReason());
xmlRevocation.setSource(revocationToken.getClass().getSimpleName());
String sourceURL = revocationToken.getSourceURL();
if (Utils.isStringNotEmpty(sourceURL)) { // not empty = online
xmlRevocation.setSourceAddress(sourceURL);
xmlRevocation.setAvailable(revocationToken.isAvailable());
}
xmlRevocation.setBasicSignature(getXmlBasicSignature(revocationToken));
xmlRevocation.setDigestAlgoAndValues(getXmlDigestAlgoAndValues(usedDigestAlgorithms, revocationToken));
final CertificateToken issuerToken = revocationToken.getIssuerToken();
xmlRevocation.setSigningCertificate(getXmlSigningCertificate(issuerToken));
xmlRevocation.setCertificateChain(getXmlForCertificateChain(issuerToken));
xmlRevocation.setInfo(getXmlInfo(revocationToken.getValidationInfo()));
return xmlRevocation;
}
private List<XmlDigestAlgoAndValue> getXmlDigestAlgoAndValues(Set<DigestAlgorithm> usedDigestAlgorithms, Token token) {
List<XmlDigestAlgoAndValue> result = new ArrayList<XmlDigestAlgoAndValue>();
for (final DigestAlgorithm digestAlgorithm : usedDigestAlgorithms) {
result.add(getXmlDigestAlgoAndValue(digestAlgorithm, Utils.toBase64(token.getDigest(digestAlgorithm))));
}
return result;
}
private List<XmlMessage> getXmlInfo(List<String> infos) {
List<XmlMessage> messages = new ArrayList<XmlMessage>();
if (Utils.isCollectionNotEmpty(infos)) {
int i = 0;
for (String message : infos) {
final XmlMessage xmlMessage = new XmlMessage();
xmlMessage.setId(i);
xmlMessage.setValue(message);
messages.add(xmlMessage);
i++;
}
}
return messages;
}
private List<XmlChainItem> getXmlForCertificateChain(CertificateToken token) {
if (token != null) {
CertificateToken issuerToken_ = token;
final List<XmlChainItem> certChainTokens = new ArrayList<XmlChainItem>();
do {
certChainTokens.add(getXmlChainItem(issuerToken_));
if (issuerToken_.isTrusted() || issuerToken_.isSelfSigned()) {
break;
}
issuerToken_ = issuerToken_.getIssuerToken();
} while (issuerToken_ != null);
return certChainTokens;
}
return null;
}
private XmlChainItem getXmlChainItem(CertificateToken token) {
final XmlChainItem chainItem = new XmlChainItem();
chainItem.setId(token.getDSSIdAsString());
chainItem.setSource(getCertificateMainSourceType(token).name());
return chainItem;
}
private CertificateSourceType getCertificateMainSourceType(final CertificateToken issuerToken) {
CertificateSourceType mainSource = CertificateSourceType.UNKNOWN;
final Set<CertificateSourceType> sourceList = issuerToken.getSources();
if (sourceList.size() > 0) {
if (sourceList.contains(CertificateSourceType.TRUSTED_LIST)) {
mainSource = CertificateSourceType.TRUSTED_LIST;
} else if (sourceList.contains(CertificateSourceType.TRUSTED_STORE)) {
mainSource = CertificateSourceType.TRUSTED_STORE;
} else {
mainSource = sourceList.iterator().next();
}
}
return mainSource;
}
/**
* This method creates the SigningCertificate element for the current token.
*
* @param token
* the token
* @return
*/
private XmlSigningCertificate getXmlSigningCertificate(CertificateToken token) {
if (token != null) {
final XmlSigningCertificate xmlSignCertType = new XmlSigningCertificate();
xmlSignCertType.setId(token.getDSSIdAsString());
return xmlSignCertType;
}
return null;
}
private XmlSigningCertificate getXmlSigningCertificate(CertificateValidity theCertificateValidity) {
XmlSigningCertificate xmlSignCertType = new XmlSigningCertificate();
CertificateToken signingCertificateToken = theCertificateValidity.getCertificateToken();
if (signingCertificateToken != null) {
xmlSignCertType.setId(signingCertificateToken.getDSSIdAsString());
}
xmlSignCertType.setAttributePresent(theCertificateValidity.isAttributePresent());
xmlSignCertType.setDigestValuePresent(theCertificateValidity.isDigestPresent());
xmlSignCertType.setDigestValueMatch(theCertificateValidity.isDigestEqual());
final boolean issuerSerialMatch = theCertificateValidity.isSerialNumberEqual() && theCertificateValidity.isDistinguishedNameEqual();
xmlSignCertType.setIssuerSerialMatch(issuerSerialMatch);
xmlSignCertType.setSigned(theCertificateValidity.getSigned());
return xmlSignCertType;
}
private XmlSignatureProductionPlace getXmlSignatureProductionPlace(SignatureProductionPlace signatureProductionPlace) {
if (signatureProductionPlace != null) {
final XmlSignatureProductionPlace xmlSignatureProductionPlace = new XmlSignatureProductionPlace();
xmlSignatureProductionPlace.setCountryName(signatureProductionPlace.getCountryName());
xmlSignatureProductionPlace.setStateOrProvince(signatureProductionPlace.getStateOrProvince());
xmlSignatureProductionPlace.setPostalCode(signatureProductionPlace.getPostalCode());
xmlSignatureProductionPlace.setAddress(signatureProductionPlace.getStreetAddress());
xmlSignatureProductionPlace.setCity(signatureProductionPlace.getCity());
return xmlSignatureProductionPlace;
}
return null;
}
private List<XmlCertifiedRole> getXmlCertifiedRoles(List<CertifiedRole> certifiedRoles) {
List<XmlCertifiedRole> xmlCertRoles = new ArrayList<XmlCertifiedRole>();
if (Utils.isCollectionNotEmpty(certifiedRoles)) {
for (final CertifiedRole certifiedRole : certifiedRoles) {
final XmlCertifiedRole xmlCertifiedRole = new XmlCertifiedRole();
xmlCertifiedRole.setCertifiedRole(certifiedRole.getRole());
xmlCertifiedRole.setNotBefore(certifiedRole.getNotBefore());
xmlCertifiedRole.setNotAfter(certifiedRole.getNotAfter());
xmlCertRoles.add(xmlCertifiedRole);
}
}
return Collections.emptyList();
}
private List<String> getXmlClaimedRole(String[] claimedRoles) {
if (Utils.isArrayNotEmpty(claimedRoles)) {
return Arrays.asList(claimedRoles);
}
return Collections.emptyList();
}
private List<String> getXmlCommitmentTypeIndication(CommitmentType commitmentTypeIndication) {
if (commitmentTypeIndication != null) {
return commitmentTypeIndication.getIdentifiers();
}
return Collections.emptyList();
}
private String getXmlSignatureFormat(SignatureLevel signatureLevel) {
return signatureLevel == null ? "UNKNOWN" : signatureLevel.toString();
}
private XmlDistinguishedName getXmlDistinguishedName(final String x500PrincipalFormat, final X500Principal X500PrincipalName) {
final XmlDistinguishedName xmlDistinguishedName = new XmlDistinguishedName();
xmlDistinguishedName.setFormat(x500PrincipalFormat);
xmlDistinguishedName.setValue(X500PrincipalName.getName(x500PrincipalFormat));
return xmlDistinguishedName;
}
private List<XmlTimestamp> getXmlTimestamps(AdvancedSignature signature) {
List<XmlTimestamp> xmlTimestamps = new ArrayList<XmlTimestamp>();
xmlTimestamps.addAll(getXmlTimestamps(signature.getContentTimestamps()));
xmlTimestamps.addAll(getXmlTimestamps(signature.getSignatureTimestamps()));
xmlTimestamps.addAll(getXmlTimestamps(signature.getTimestampsX1()));
xmlTimestamps.addAll(getXmlTimestamps(signature.getTimestampsX2()));
xmlTimestamps.addAll(getXmlTimestamps(signature.getArchiveTimestamps()));
return xmlTimestamps;
}
/**
* This method deals with the signature policy. The retrieved information is transformed to the JAXB object.
*
* @param signaturePolicy
* The Signature Policy
*
*/
private XmlPolicy getXmlPolicy(SignaturePolicy signaturePolicy) {
if (signaturePolicy == null) {
return null;
}
final XmlPolicy xmlPolicy = new XmlPolicy();
final String policyId = signaturePolicy.getIdentifier();
xmlPolicy.setId(policyId);
final String policyUrl = signaturePolicy.getUrl();
xmlPolicy.setUrl(policyUrl);
final String notice = signaturePolicy.getNotice();
xmlPolicy.setNotice(notice);
final String digestValue = signaturePolicy.getDigestValue();
final DigestAlgorithm signPolicyHashAlgFromSignature = signaturePolicy.getDigestAlgorithm();
if (Utils.isStringNotEmpty(digestValue)) {
xmlPolicy.setDigestAlgoAndValue(getXmlDigestAlgoAndValue(signPolicyHashAlgFromSignature, digestValue));
}
/**
* ETSI 102 853: 3) Obtain the digest of the resulting document against which the digest value present in the
* property/attribute will be checked:
*/
final DSSDocument policyContent = signaturePolicy.getPolicyContent();
byte[] policyBytes = null;
if (policyContent == null) {
xmlPolicy.setIdentified(false);
if (policyId.isEmpty()) {
xmlPolicy.setStatus(true);
} else {
xmlPolicy.setStatus(false);
}
return xmlPolicy;
} else {
policyBytes = DSSUtils.toByteArray(policyContent);
xmlPolicy.setStatus(true);
}
xmlPolicy.setIdentified(true);
if (Utils.isArrayEmpty(policyBytes)) {
xmlPolicy.setIdentified(false);
xmlPolicy.setProcessingError("Empty content for policy");
return xmlPolicy;
}
ASN1Sequence asn1Sequence = null;
try {
asn1Sequence = DSSASN1Utils.toASN1Primitive(policyBytes);
} catch (Exception e) {
LOG.info("Policy bytes are not asn1 processable : " + e.getMessage());
}
try {
if (asn1Sequence != null) {
xmlPolicy.setAsn1Processable(true);
/**
* a) If the resulting document is based on TR 102 272 [i.2] (ESI: ASN.1 format for signature policies),
* use the digest value present in the
* SignPolicyDigest element from the resulting document. Check that the digest algorithm indicated in
* the SignPolicyDigestAlg from the resulting
* document is equal to the digest algorithm indicated in the property.
*/
final ASN1Sequence signPolicyHashAlgObject = (ASN1Sequence) asn1Sequence.getObjectAt(0);
final AlgorithmIdentifier signPolicyHashAlgIdentifier = AlgorithmIdentifier.getInstance(signPolicyHashAlgObject);
DigestAlgorithm signPolicyHashAlgFromPolicy = DigestAlgorithm.forOID(signPolicyHashAlgIdentifier.getAlgorithm().getId());
/**
* b) If the resulting document is based on TR 102 038 [i.3] ((ESI) XML format for signature policies),
* use the digest value present in
* signPolicyHash element from the resulting document. Check that the digest algorithm indicated in the
* signPolicyHashAlg from the resulting
* document is equal to the digest algorithm indicated in the attribute.
*/
/**
* The use of a zero-sigPolicyHash value is to ensure backwards compatibility with earlier versions of
* the current document. If sigPolicyHash is
* zero, then the hash value should not be checked against the calculated hash value of the signature
* policy.
*/
if (!signPolicyHashAlgFromPolicy.equals(signPolicyHashAlgFromSignature)) {
xmlPolicy.setProcessingError("The digest algorithm indicated in the SignPolicyHashAlg from the resulting document ("
+ signPolicyHashAlgFromPolicy + ") is not equal to the digest " + "algorithm (" + signPolicyHashAlgFromSignature + ").");
xmlPolicy.setDigestAlgorithmsEqual(false);
xmlPolicy.setStatus(false);
return xmlPolicy;
} else {
xmlPolicy.setDigestAlgorithmsEqual(true);
}
String recalculatedDigestValue = Utils.toBase64(DSSASN1Utils.getAsn1SignaturePolicyDigest(signPolicyHashAlgFromPolicy, policyBytes));
boolean equal = Utils.areStringsEqual(digestValue, recalculatedDigestValue);
xmlPolicy.setStatus(equal);
if (!equal) {
xmlPolicy.setProcessingError(
"The policy digest value (" + digestValue + ") does not match the re-calculated digest value (" + recalculatedDigestValue + ").");
return xmlPolicy;
}
final ASN1OctetString signPolicyHash = (ASN1OctetString) asn1Sequence.getObjectAt(2);
final String policyDigestValueFromPolicy = Utils.toBase64(signPolicyHash.getOctets());
equal = Utils.areStringsEqual(digestValue, policyDigestValueFromPolicy);
xmlPolicy.setStatus(equal);
if (!equal) {
xmlPolicy.setProcessingError("The policy digest value (" + digestValue + ") does not match the digest value from the policy file ("
+ policyDigestValueFromPolicy + ").");
}
} else {
/**
* c) In all other cases, compute the digest using the digesting algorithm indicated in the children of
* the property/attribute.
*/
String recalculatedDigestValue = Utils.toBase64(DSSUtils.digest(signPolicyHashAlgFromSignature, policyBytes));
boolean equal = Utils.areStringsEqual(digestValue, recalculatedDigestValue);
xmlPolicy.setStatus(equal);
if (!equal) {
xmlPolicy.setProcessingError(
"The policy digest value (" + digestValue + ") does not match the re-calculated digest value (" + recalculatedDigestValue + ").");
}
}
} catch (Exception e) {
// When any error (communication) we just set the status to false
xmlPolicy.setStatus(false);
xmlPolicy.setProcessingError(e.getMessage());
// Do nothing
LOG.warn(e.getMessage(), e);
}
return xmlPolicy;
}
private List<XmlTimestamp> getXmlTimestamps(List<TimestampToken> timestamps) {
List<XmlTimestamp> xmlTimestamps = new ArrayList<XmlTimestamp>();
if (Utils.isCollectionNotEmpty(timestamps)) {
for (TimestampToken timestampToken : timestamps) {
xmlTimestamps.add(getXmlTimestamp(timestampToken));
}
}
return xmlTimestamps;
}
private XmlTimestamp getXmlTimestamp(final TimestampToken timestampToken) {
final XmlTimestamp xmlTimestampToken = new XmlTimestamp();
xmlTimestampToken.setId(timestampToken.getDSSIdAsString());
xmlTimestampToken.setType(timestampToken.getTimeStampType().name());
xmlTimestampToken.setProductionTime(timestampToken.getGenerationTime());
xmlTimestampToken.setSignedDataDigestAlgo(timestampToken.getSignedDataDigestAlgo().getName());
xmlTimestampToken.setEncodedSignedDataDigestValue(timestampToken.getEncodedSignedDataDigestValue());
xmlTimestampToken.setMessageImprintDataFound(timestampToken.isMessageImprintDataFound());
xmlTimestampToken.setMessageImprintDataIntact(timestampToken.isMessageImprintDataIntact());
xmlTimestampToken.setCanonicalizationMethod(timestampToken.getCanonicalizationMethod());
xmlTimestampToken.setBasicSignature(getXmlBasicSignature(timestampToken));
final CertificateToken issuerToken = timestampToken.getIssuerToken();
xmlTimestampToken.setSigningCertificate(getXmlSigningCertificate(issuerToken));
xmlTimestampToken.setCertificateChain(getXmlForCertificateChain(issuerToken));
xmlTimestampToken.setSignedObjects(getXmlSignedObjects(timestampToken.getTimestampedReferences()));
return xmlTimestampToken;
}
private XmlSignedObjects getXmlSignedObjects(List<TimestampReference> timestampReferences) {
if (Utils.isCollectionNotEmpty(timestampReferences)) {
final XmlSignedObjects xmlSignedObjectsType = new XmlSignedObjects();
final List<XmlDigestAlgoAndValue> xmlDigestAlgAndValueList = xmlSignedObjectsType.getDigestAlgoAndValues();
for (final TimestampReference timestampReference : timestampReferences) {
final TimestampReferenceCategory timestampedCategory = timestampReference.getCategory();
if (TimestampReferenceCategory.SIGNATURE.equals(timestampedCategory)) {
final XmlSignedSignature xmlSignedSignature = new XmlSignedSignature();
xmlSignedSignature.setId(timestampReference.getSignatureId());
xmlSignedObjectsType.getSignedSignature().add(xmlSignedSignature);
} else if (TimestampReferenceCategory.TIMESTAMP.equals(timestampedCategory)) {
final XmlTimestampedTimestamp xmlTimestampedTimestamp = new XmlTimestampedTimestamp();
xmlTimestampedTimestamp.setId(timestampReference.getSignatureId());
xmlSignedObjectsType.getTimestampedTimestamp().add(xmlTimestampedTimestamp);
} else {
final XmlDigestAlgoAndValue xmlDigestAlgAndValue = getXmlDigestAlgoAndValue(timestampReference.getDigestAlgorithm(),
timestampReference.getDigestValue());
xmlDigestAlgAndValue.setCategory(timestampedCategory.name());
xmlDigestAlgAndValueList.add(xmlDigestAlgAndValue);
}
}
return xmlSignedObjectsType;
}
return null;
}
private XmlBasicSignature getXmlBasicSignature(final Token token) {
final XmlBasicSignature xmlBasicSignatureType = new XmlBasicSignature();
SignatureAlgorithm signatureAlgorithm = token.getSignatureAlgorithm();
if (signatureAlgorithm != null) {
xmlBasicSignatureType.setEncryptionAlgoUsedToSignThisToken(signatureAlgorithm.getEncryptionAlgorithm().getName());
xmlBasicSignatureType.setDigestAlgoUsedToSignThisToken(signatureAlgorithm.getDigestAlgorithm().getName());
}
xmlBasicSignatureType.setKeyLengthUsedToSignThisToken(DSSPKUtils.getPublicKeySize(token));
final boolean signatureValid = token.isSignatureValid();
xmlBasicSignatureType.setReferenceDataFound(signatureValid);
xmlBasicSignatureType.setReferenceDataIntact(signatureValid);
xmlBasicSignatureType.setSignatureIntact(signatureValid);
xmlBasicSignatureType.setSignatureValid(signatureValid);
return xmlBasicSignatureType;
}
private List<String> getXmlKeyUsages(Set<KeyUsageBit> keyUsageBits) {
final List<String> xmlKeyUsageBitItems = new ArrayList<String>();
if (Utils.isCollectionNotEmpty(keyUsageBits)) {
for (final KeyUsageBit keyUsageBit : keyUsageBits) {
xmlKeyUsageBitItems.add(keyUsageBit.name());
}
}
return xmlKeyUsageBitItems;
}
private XmlBasicSignature getXmlBasicSignature(AdvancedSignature signature, CertificateToken signingCertificateToken) {
XmlBasicSignature xmlBasicSignature = new XmlBasicSignature();
final EncryptionAlgorithm encryptionAlgorithm = signature.getEncryptionAlgorithm();
final String encryptionAlgorithmString = encryptionAlgorithm == null ? "?" : encryptionAlgorithm.getName();
xmlBasicSignature.setEncryptionAlgoUsedToSignThisToken(encryptionAlgorithmString);
final int keyLength = signingCertificateToken == null ? 0 : DSSPKUtils.getPublicKeySize(signingCertificateToken.getPublicKey());
xmlBasicSignature.setKeyLengthUsedToSignThisToken(String.valueOf(keyLength));
final DigestAlgorithm digestAlgorithm = getDigestAlgorithm(signature);
final String digestAlgorithmString = digestAlgorithm == null ? "?" : digestAlgorithm.getName();
xmlBasicSignature.setDigestAlgoUsedToSignThisToken(digestAlgorithmString);
SignatureCryptographicVerification scv = signature.getSignatureCryptographicVerification();
xmlBasicSignature.setReferenceDataFound(scv.isReferenceDataFound());
xmlBasicSignature.setReferenceDataIntact(scv.isReferenceDataIntact());
xmlBasicSignature.setSignatureIntact(scv.isSignatureIntact());
xmlBasicSignature.setSignatureValid(scv.isSignatureValid());
return xmlBasicSignature;
}
private DigestAlgorithm getDigestAlgorithm(final AdvancedSignature signature) {
DigestAlgorithm digestAlgorithm = null;
try {
digestAlgorithm = signature.getDigestAlgorithm();
} catch (Exception e) {
LOG.error("Unable to retrieve digest algorithm : " + e.getMessage());
}
return digestAlgorithm;
}
private List<XmlSignatureScope> getXmlSignatureScopes(List<SignatureScope> scopes) {
List<XmlSignatureScope> xmlScopes = new ArrayList<XmlSignatureScope>();
if (Utils.isCollectionNotEmpty(scopes)) {
for (SignatureScope xmlSignatureScope : scopes) {
xmlScopes.add(getXmlSignatureScope(xmlSignatureScope));
}
}
return xmlScopes;
}
private XmlSignatureScope getXmlSignatureScope(SignatureScope scope) {
final XmlSignatureScope xmlSignatureScope = new XmlSignatureScope();
xmlSignatureScope.setName(scope.getName());
xmlSignatureScope.setScope(scope.getType());
xmlSignatureScope.setValue(scope.getDescription());
return xmlSignatureScope;
}
private XmlCertificate getXmlCertificate(Set<DigestAlgorithm> usedDigestAlgorithms, CertificateToken certToken) {
final XmlCertificate xmlCert = new XmlCertificate();
xmlCert.setId(certToken.getDSSIdAsString());
xmlCert.getSubjectDistinguishedName().add(getXmlDistinguishedName(X500Principal.CANONICAL, certToken.getSubjectX500Principal()));
xmlCert.getSubjectDistinguishedName().add(getXmlDistinguishedName(X500Principal.RFC2253, certToken.getSubjectX500Principal()));
xmlCert.getIssuerDistinguishedName().add(getXmlDistinguishedName(X500Principal.CANONICAL, certToken.getIssuerX500Principal()));
xmlCert.getIssuerDistinguishedName().add(getXmlDistinguishedName(X500Principal.RFC2253, certToken.getIssuerX500Principal()));
xmlCert.setSerialNumber(certToken.getSerialNumber());
X500Principal x500Principal = certToken.getSubjectX500Principal();
xmlCert.setCommonName(DSSASN1Utils.extractAttributeFromX500Principal(BCStyle.CN, x500Principal));
xmlCert.setCountryName(DSSASN1Utils.extractAttributeFromX500Principal(BCStyle.C, x500Principal));
xmlCert.setOrganizationName(DSSASN1Utils.extractAttributeFromX500Principal(BCStyle.O, x500Principal));
xmlCert.setGivenName(DSSASN1Utils.extractAttributeFromX500Principal(BCStyle.GIVENNAME, x500Principal));
xmlCert.setOrganizationalUnit(DSSASN1Utils.extractAttributeFromX500Principal(BCStyle.OU, x500Principal));
xmlCert.setSurname(DSSASN1Utils.extractAttributeFromX500Principal(BCStyle.SURNAME, x500Principal));
xmlCert.setPseudonym(DSSASN1Utils.extractAttributeFromX500Principal(BCStyle.PSEUDONYM, x500Principal));
xmlCert.setAuthorityInformationAccessUrls(DSSASN1Utils.getCAAccessLocations(certToken));
xmlCert.setOCSPAccessUrls(DSSASN1Utils.getOCSPAccessLocations(certToken));
xmlCert.setCRLDistributionPoints(DSSASN1Utils.getCrlUrls(certToken));
xmlCert.setDigestAlgoAndValues(getXmlDigestAlgoAndValues(usedDigestAlgorithms, certToken));
xmlCert.setNotAfter(certToken.getNotAfter());
xmlCert.setNotBefore(certToken.getNotBefore());
final PublicKey publicKey = certToken.getPublicKey();
xmlCert.setPublicKeySize(DSSPKUtils.getPublicKeySize(publicKey));
xmlCert.setPublicKeyEncryptionAlgo(DSSPKUtils.getPublicKeyEncryptionAlgo(publicKey));
xmlCert.setKeyUsageBits(getXmlKeyUsages(certToken.getKeyUsageBits()));
xmlCert.setIdKpOCSPSigning(DSSASN1Utils.isOCSPSigning(certToken));
xmlCert.setIdPkixOcspNoCheck(DSSASN1Utils.hasIdPkixOcspNoCheckExtension(certToken));
xmlCert.setBasicSignature(getXmlBasicSignature(certToken));
final CertificateToken issuerToken = certToken.getIssuerToken();
xmlCert.setSigningCertificate(getXmlSigningCertificate(issuerToken));
xmlCert.setCertificateChain(getXmlForCertificateChain(issuerToken));
xmlCert.setQCStatementIds(getXmlOids(DSSASN1Utils.getQCStatementsIdList(certToken)));
xmlCert.setQCTypes(getXmlOids(DSSASN1Utils.getQCTypesIdList(certToken)));
xmlCert.setCertificatePolicyIds(getXmlOids(DSSASN1Utils.getPolicyIdentifiers(certToken)));
xmlCert.setSelfSigned(certToken.isSelfSigned());
xmlCert.setTrusted(certToken.isTrusted());
xmlCert.setInfo(getXmlInfo(certToken.getValidationInfo()));
final Set<RevocationToken> revocationTokens = certToken.getRevocationTokens();
if (Utils.isCollectionNotEmpty(revocationTokens)) {
for (RevocationToken revocationToken : revocationTokens) {
// In case of CRL, the X509CRL can be the same for different certificates
String xmlId = Utils.toHex(certToken.getDigest(DigestAlgorithm.SHA256)) + Utils.toHex(revocationToken.getDigest(DigestAlgorithm.SHA256));
xmlCert.getRevocations().add(getXmlRevocation(revocationToken, xmlId, usedDigestAlgorithms));
}
}
xmlCert.setTrustedServiceProviders(getXmlTrustedServiceProviders(certToken));
return xmlCert;
}
private List<XmlOID> getXmlOids(List<String> oidList) {
List<XmlOID> result = new ArrayList<XmlOID>();
for (String oid : oidList) {
XmlOID xmlOID = new XmlOID();
xmlOID.setValue(oid);
xmlOID.setDescription(OidRepository.getDescription(oid));
result.add(xmlOID);
}
return result;
}
private List<XmlTrustedServiceProvider> getXmlTrustedServiceProviders(CertificateToken certToken) {
List<XmlTrustedServiceProvider> result = new ArrayList<XmlTrustedServiceProvider>();
Set<ServiceInfo> services = getLinkedTrustedServices(certToken);
Map<String, List<ServiceInfo>> servicesByProviders = classifyByServiceProvider(services);
for (List<ServiceInfo> serviceByProvider : servicesByProviders.values()) {
ServiceInfo first = serviceByProvider.get(0);
XmlTrustedServiceProvider serviceProvider = new XmlTrustedServiceProvider();
serviceProvider.setCountryCode(first.getTlCountryCode());
serviceProvider.setTSPName(first.getTspName());
serviceProvider.setTSPServiceName(first.getServiceName());
serviceProvider.setTrustedServices(getXmlTrustedServices(serviceByProvider, certToken));
result.add(serviceProvider);
}
return Collections.unmodifiableList(result);
}
private List<XmlTrustedService> getXmlTrustedServices(List<ServiceInfo> serviceInfos, CertificateToken certToken) {
List<XmlTrustedService> result = new ArrayList<XmlTrustedService>();
for (ServiceInfo serviceInfo : serviceInfos) {
List<ServiceInfoStatus> serviceStatusAfterOfEqualsCertIssuance = serviceInfo.getStatus().getAfter(certToken.getNotBefore());
if (Utils.isCollectionNotEmpty(serviceStatusAfterOfEqualsCertIssuance)) {
for (ServiceInfoStatus serviceInfoStatus : serviceStatusAfterOfEqualsCertIssuance) {
XmlTrustedService trustedService = new XmlTrustedService();
trustedService.setServiceType(serviceInfoStatus.getType());
trustedService.setStatus(serviceInfoStatus.getStatus());
trustedService.setStartDate(serviceInfoStatus.getStartDate());
trustedService.setEndDate(serviceInfoStatus.getEndDate());
List<String> qualifiers = getQualifiers(serviceInfoStatus, certToken);
if (Utils.isCollectionNotEmpty(qualifiers)) {
trustedService.setCapturedQualifiers(qualifiers);
}
List<String> additionalServiceInfoUris = serviceInfoStatus.getAdditionalServiceInfoUris();
if (Utils.isCollectionNotEmpty(additionalServiceInfoUris)) {
trustedService.setAdditionalServiceInfoUris(additionalServiceInfoUris);
}
trustedService.setExpiredCertsRevocationInfo(serviceInfoStatus.getExpiredCertsRevocationInfo());
result.add(trustedService);
}
}
}
return Collections.unmodifiableList(result);
}
private Map<String, List<ServiceInfo>> classifyByServiceProvider(Set<ServiceInfo> services) {
Map<String, List<ServiceInfo>> servicesByProviders = new HashMap<String, List<ServiceInfo>>();
if (Utils.isCollectionNotEmpty(services)) {
for (ServiceInfo serviceInfo : services) {
String tradeName = serviceInfo.getTspTradeName();
List<ServiceInfo> servicesByProvider = servicesByProviders.get(tradeName);
if (servicesByProvider == null) {
servicesByProvider = new ArrayList<ServiceInfo>();
servicesByProviders.put(tradeName, servicesByProvider);
}
servicesByProvider.add(serviceInfo);
}
}
return servicesByProviders;
}
private Set<ServiceInfo> getLinkedTrustedServices(final CertificateToken certToken) {
Set<ServiceInfo> services = null;
if (certToken.isTrusted()) {
services = certToken.getAssociatedTSPS();
} else {
final CertificateToken trustAnchor = certToken.getTrustAnchor();
if (trustAnchor != null) {
services = trustAnchor.getAssociatedTSPS();
}
}
return services;
}
/**
* Retrieves all the qualifiers for which the corresponding conditionEntry is true.
*
* @param certificateToken
* @return
*/
private List<String> getQualifiers(ServiceInfoStatus serviceInfoStatus, CertificateToken certificateToken) {
LOG.trace("--> GET_QUALIFIERS()");
List<String> list = new ArrayList<String>();
final Map<String, List<Condition>> qualifiersAndConditions = serviceInfoStatus.getQualifiersAndConditions();
for (Entry<String, List<Condition>> conditionEntry : qualifiersAndConditions.entrySet()) {
List<Condition> conditions = conditionEntry.getValue();
LOG.trace(" --> " + conditions);
for (final Condition condition : conditions) {
if (condition.check(certificateToken)) {
LOG.trace(" --> CONDITION TRUE / " + conditionEntry.getKey());
list.add(conditionEntry.getKey());
break;
}
}
}
return list;
}
private XmlDigestAlgoAndValue getXmlDigestAlgoAndValue(DigestAlgorithm digestAlgo, String digestValue) {
XmlDigestAlgoAndValue xmlDigestAlgAndValue = new XmlDigestAlgoAndValue();
xmlDigestAlgAndValue.setDigestMethod(digestAlgo == null ? "" : digestAlgo.getName());
xmlDigestAlgAndValue.setDigestValue(digestValue);
return xmlDigestAlgAndValue;
}
}