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

eu.europa.esig.dss.tsl.service.TSLParser Maven / Gradle / Ivy

There is a newer version: 6.0.d4j.2
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.tsl.service;

import java.io.InputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

import javax.security.auth.x500.X500Principal;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.datatype.XMLGregorianCalendar;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.DSSUtils;
import eu.europa.esig.dss.tsl.CompositeCondition;
import eu.europa.esig.dss.tsl.Condition;
import eu.europa.esig.dss.tsl.CriteriaListCondition;
import eu.europa.esig.dss.tsl.KeyUsageCondition;
import eu.europa.esig.dss.tsl.MatchingCriteriaIndicator;
import eu.europa.esig.dss.tsl.PolicyIdCondition;
import eu.europa.esig.dss.tsl.TSLConditionsForQualifiers;
import eu.europa.esig.dss.tsl.TSLParserResult;
import eu.europa.esig.dss.tsl.TSLPointer;
import eu.europa.esig.dss.tsl.TSLService;
import eu.europa.esig.dss.tsl.TSLServiceExtension;
import eu.europa.esig.dss.tsl.TSLServiceProvider;
import eu.europa.esig.dss.x509.CertificateToken;
import eu.europa.esig.jaxb.ecc.CriteriaListType;
import eu.europa.esig.jaxb.ecc.KeyUsageBitType;
import eu.europa.esig.jaxb.ecc.KeyUsageType;
import eu.europa.esig.jaxb.ecc.PoliciesListType;
import eu.europa.esig.jaxb.ecc.QualificationElementType;
import eu.europa.esig.jaxb.ecc.QualificationsType;
import eu.europa.esig.jaxb.ecc.QualifierType;
import eu.europa.esig.jaxb.ecc.QualifiersType;
import eu.europa.esig.jaxb.tsl.AnyType;
import eu.europa.esig.jaxb.tsl.DigitalIdentityListType;
import eu.europa.esig.jaxb.tsl.DigitalIdentityType;
import eu.europa.esig.jaxb.tsl.ExtensionType;
import eu.europa.esig.jaxb.tsl.ExtensionsListType;
import eu.europa.esig.jaxb.tsl.InternationalNamesType;
import eu.europa.esig.jaxb.tsl.MultiLangNormStringType;
import eu.europa.esig.jaxb.tsl.NextUpdateType;
import eu.europa.esig.jaxb.tsl.NonEmptyMultiLangURIType;
import eu.europa.esig.jaxb.tsl.NonEmptyURIListType;
import eu.europa.esig.jaxb.tsl.ObjectFactory;
import eu.europa.esig.jaxb.tsl.OtherTSLPointerType;
import eu.europa.esig.jaxb.tsl.PostalAddressType;
import eu.europa.esig.jaxb.tsl.ServiceHistoryInstanceType;
import eu.europa.esig.jaxb.tsl.ServiceHistoryType;
import eu.europa.esig.jaxb.tsl.TSPInformationType;
import eu.europa.esig.jaxb.tsl.TSPServiceInformationType;
import eu.europa.esig.jaxb.tsl.TSPServiceType;
import eu.europa.esig.jaxb.tsl.TSPServicesListType;
import eu.europa.esig.jaxb.tsl.TSPType;
import eu.europa.esig.jaxb.tsl.TrustServiceProviderListType;
import eu.europa.esig.jaxb.tsl.TrustStatusListType;
import eu.europa.esig.jaxb.xades.IdentifierType;
import eu.europa.esig.jaxb.xades.ObjectIdentifierType;

/**
 * This class allows to parse a TSL from JAXB object to DTO's. It can be executed as a Callable
 */
public class TSLParser implements Callable {

	private static final Logger logger = LoggerFactory.getLogger(TSLParser.class);

	private static final String TSL_MIME_TYPE = "application/vnd.etsi.tsl+xml";

	private static final JAXBContext jaxbContext;

	private InputStream inputStream;

	static {
		try {
			jaxbContext = JAXBContext.newInstance(ObjectFactory.class, eu.europa.esig.jaxb.ecc.ObjectFactory.class);
		} catch (JAXBException e) {
			throw new DSSException("Unable to initialize JaxB : " + e.getMessage(), e);
		}
	}

	public TSLParser(InputStream inputStream) {
		this.inputStream = inputStream;
	}

	@Override
	@SuppressWarnings("unchecked")
	public TSLParserResult call() throws Exception {
		try {
			Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
			JAXBElement jaxbElement = (JAXBElement) unmarshaller.unmarshal(inputStream);
			TrustStatusListType trustStatusList = jaxbElement.getValue();
			return getTslModel(trustStatusList);
		} catch (Exception e) {
			throw new DSSException("Unable to parse inputstream : " + e.getMessage(), e);
		}
	}

	private TSLParserResult getTslModel(TrustStatusListType tsl) {
		TSLParserResult tslModel = new TSLParserResult();
		tslModel.setTerritory(getTerritory(tsl));
		tslModel.setSequenceNumber(getSequenceNumber(tsl));
		tslModel.setIssueDate(getIssueDate(tsl));
		tslModel.setNextUpdateDate(getNextUpdate(tsl));
		tslModel.setDistributionPoints(getDistributionPoints(tsl));
		tslModel.setPointers(getMachineProcessableTSLPointers(tsl));
		tslModel.setServiceProviders(getServiceProviders(tsl));
		return tslModel;
	}

	private int getSequenceNumber(TrustStatusListType tsl) {
		BigInteger tslSequenceNumber = tsl.getSchemeInformation().getTSLSequenceNumber();
		if (tslSequenceNumber != null) {
			return tslSequenceNumber.intValue();
		}
		return -1;
	}

	private String getTerritory(TrustStatusListType tsl) {
		return tsl.getSchemeInformation().getSchemeTerritory();
	}

	private Date getIssueDate(TrustStatusListType tsl) {
		XMLGregorianCalendar gregorianCalendar = tsl.getSchemeInformation().getListIssueDateTime();
		return convertToDate(gregorianCalendar);
	}

	private Date getNextUpdate(TrustStatusListType tsl) {
		NextUpdateType nextUpdate = tsl.getSchemeInformation().getNextUpdate();
		if (nextUpdate != null) {
			return convertToDate(nextUpdate.getDateTime());
		}
		return null;
	}

	private List getDistributionPoints(TrustStatusListType tsl) {
		NonEmptyURIListType distributionPoints = tsl.getSchemeInformation().getDistributionPoints();
		if (distributionPoints != null) {
			return distributionPoints.getURI();
		}
		return new ArrayList();
	}

	private Date convertToDate(XMLGregorianCalendar gregorianCalendar) {
		if (gregorianCalendar != null) {
			GregorianCalendar toGregorianCalendar = gregorianCalendar.toGregorianCalendar();
			if (toGregorianCalendar != null) {
				return toGregorianCalendar.getTime();
			}
		}
		return null;
	}

	private List getMachineProcessableTSLPointers(TrustStatusListType tsl) {
		List list = new ArrayList();
		List tslPointers = getTSLPointers(tsl);
		if (CollectionUtils.isNotEmpty(tslPointers)) {
			for (TSLPointer tslPointer : tslPointers) {
				if (TSL_MIME_TYPE.equals(tslPointer.getMimeType())) {
					list.add(tslPointer);
				}
			}
		}
		return list;
	}

	private List getTSLPointers(TrustStatusListType tsl) {
		List list = new ArrayList();
		if ((tsl.getSchemeInformation() != null) && (tsl.getSchemeInformation().getPointersToOtherTSL() != null)) {
			List pointers = tsl.getSchemeInformation().getPointersToOtherTSL().getOtherTSLPointer();
			for (OtherTSLPointerType otherTSLPointerType : pointers) {
				list.add(getPointerInfos(otherTSLPointerType));
			}
		}
		return list;
	}

	private TSLPointer getPointerInfos(OtherTSLPointerType otherTSLPointerType) {
		TSLPointer pointer = new TSLPointer();
		pointer.setUrl(otherTSLPointerType.getTSLLocation());
		pointer.setPotentialSigners(getPotentialSigners(otherTSLPointerType));
		fillPointerTerritoryAndMimeType(otherTSLPointerType, pointer);
		return pointer;
	}

	private void fillPointerTerritoryAndMimeType(OtherTSLPointerType otherTSLPointerType, TSLPointer pointer) {
		List textualInformationOrOtherInformation = otherTSLPointerType.getAdditionalInformation().getTextualInformationOrOtherInformation();
		if (CollectionUtils.isNotEmpty(textualInformationOrOtherInformation)) {
			Map properties = new HashMap();
			for (Serializable serializable : textualInformationOrOtherInformation) {
				if (serializable instanceof AnyType) {
					AnyType anyInfo = (AnyType) serializable;
					for (Object content : anyInfo.getContent()) {
						if (content instanceof JAXBElement) {
							@SuppressWarnings("rawtypes")
							JAXBElement jaxbElement = (JAXBElement) content;
							properties.put(jaxbElement.getName().toString(), jaxbElement.getValue().toString());
						} else if (content instanceof Element) {
							Element element = (Element) content;
							properties.put("{" + element.getNamespaceURI() + "}" + element.getLocalName(), element.getTextContent());
						}
					}
				}
			}
			pointer.setMimeType(properties.get("{http://uri.etsi.org/02231/v2/additionaltypes#}MimeType"));
			pointer.setTerritory(properties.get("{http://uri.etsi.org/02231/v2#}SchemeTerritory"));
		}
	}

	private List getPotentialSigners(OtherTSLPointerType otherTSLPointerType) {
		List list = new ArrayList();
		if (otherTSLPointerType.getServiceDigitalIdentities() != null) {
			List serviceDigitalIdentity = otherTSLPointerType.getServiceDigitalIdentities().getServiceDigitalIdentity();
			extractCertificates(serviceDigitalIdentity, list);
		}
		return list;
	}

	private void extractCertificates(List serviceDigitalIdentity, List result) {
		for (DigitalIdentityListType digitalIdentityListType : serviceDigitalIdentity) {
			List certificates = extractCertificates(digitalIdentityListType);
			if (CollectionUtils.isNotEmpty(certificates)) {
				result.addAll(certificates);
			}
		}
	}

	private List extractCertificates(DigitalIdentityListType digitalIdentityListType) {
		List certificates = new ArrayList();
		List digitalIds = digitalIdentityListType.getDigitalId();
		for (DigitalIdentityType digitalId : digitalIds) {
			if (digitalId.getX509Certificate() != null) {
				try {
					CertificateToken certificate = DSSUtils.loadCertificate(digitalId.getX509Certificate());
					certificates.add(certificate);
				} catch (Exception e) {
					logger.warn("Unable to load certificate : " + e.getMessage(), e);
				}
			}
		}
		return certificates;
	}

	private List extractX500Principals(DigitalIdentityListType digitalIdentityListType) {
		List result = new ArrayList();
		List digitalIds = digitalIdentityListType.getDigitalId();
		for (DigitalIdentityType digitalId : digitalIds) {
			if (digitalId.getX509SubjectName() != null) {
				try {
					X500Principal x500Principal = DSSUtils.getX500Principal(digitalId.getX509SubjectName());
					result.add(x500Principal);
				} catch (Exception e) {
					logger.warn("Unable to load X500Principal : " + e.getMessage());
				}
			}
		}
		return result;
	}

	private List getServiceProviders(TrustStatusListType tsl) {
		List serviceProviders = new ArrayList();
		TrustServiceProviderListType trustServiceProviderList = tsl.getTrustServiceProviderList();
		if ((trustServiceProviderList != null) && (CollectionUtils.isNotEmpty(trustServiceProviderList.getTrustServiceProvider()))) {
			for (TSPType tsp : trustServiceProviderList.getTrustServiceProvider()) {
				serviceProviders.add(getServiceProvider(tsp));
			}
		}
		return serviceProviders;
	}

	private TSLServiceProvider getServiceProvider(TSPType tsp) {
		TSLServiceProvider serviceProvider = new TSLServiceProvider();
		TSPInformationType tspInformation = tsp.getTSPInformation();
		if (tspInformation != null) {
			serviceProvider.setName(getEnglishOrFirst(tspInformation.getTSPName()));
			serviceProvider.setTradeName(getEnglishOrFirst(tspInformation.getTSPTradeName()));
			serviceProvider.setPostalAddress(getPostalAddress(tspInformation));
			serviceProvider.setElectronicAddress(getElectronicAddress(tspInformation));
			serviceProvider.setServices(getServices(tsp.getTSPServices()));
		}
		return serviceProvider;
	}

	private List getServices(TSPServicesListType tspServices) {
		List services = new ArrayList();
		if ((tspServices != null) && CollectionUtils.isNotEmpty(tspServices.getTSPService())) {
			Date previousStartDate = null;
			for (TSPServiceType tslService : tspServices.getTSPService()) {
				if (tslService.getServiceInformation() != null) {
					TSLService service = getService(tslService.getServiceInformation());
					previousStartDate = service.getStartDate();
					services.add(service);
				}
				ServiceHistoryType serviceHistory = tslService.getServiceHistory();
				if ((serviceHistory != null) && CollectionUtils.isNotEmpty(serviceHistory.getServiceHistoryInstance())) {
					for (ServiceHistoryInstanceType serviceHistoryInstance : serviceHistory.getServiceHistoryInstance()) {
						TSLService service = getService(serviceHistoryInstance, previousStartDate);
						previousStartDate = service.getStartDate();
						services.add(service);
					}
				}
			}
		}
		return services;
	}

	private TSLService getService(TSPServiceInformationType serviceInfo) {
		TSLService service = new TSLService();
		service.setName(getEnglishOrFirst(serviceInfo.getServiceName()));
		service.setStatus(serviceInfo.getServiceStatus());
		service.setStartDate(convertToDate(serviceInfo.getStatusStartingTime()));
		service.setType(serviceInfo.getServiceTypeIdentifier());
		service.setCertificateUrls(extractCertificatesUrls(serviceInfo));
		service.setCertificates(extractCertificates(serviceInfo.getServiceDigitalIdentity()));
		service.setX500Principals(extractX500Principals(serviceInfo.getServiceDigitalIdentity()));
		service.setExtensions(extractExtensions(serviceInfo.getServiceInformationExtensions()));
		return service;
	}

	private List extractCertificatesUrls(TSPServiceInformationType serviceInfo) {
		Set certificateUrls = new HashSet();
		if ((serviceInfo.getSchemeServiceDefinitionURI() != null) && CollectionUtils.isNotEmpty(serviceInfo.getSchemeServiceDefinitionURI().getURI())) {
			List uris = serviceInfo.getSchemeServiceDefinitionURI().getURI();
			for (NonEmptyMultiLangURIType uri : uris) {
				String value = uri.getValue();
				if (isCertificateURI(value)) {
					certificateUrls.add(value);
				}
			}
		}
		return new ArrayList(certificateUrls);
	}

	private boolean isCertificateURI(String value) {
		return StringUtils.endsWithIgnoreCase(value, ".crt");
	}

	private TSLService getService(ServiceHistoryInstanceType serviceHistory, Date endDate) {
		TSLService service = new TSLService();
		service.setName(getEnglishOrFirst(serviceHistory.getServiceName()));
		service.setStatus(serviceHistory.getServiceStatus());
		service.setType(serviceHistory.getServiceTypeIdentifier());
		service.setStartDate(convertToDate(serviceHistory.getStatusStartingTime()));
		service.setEndDate(endDate);
		service.setCertificateUrls(new ArrayList());
		service.setCertificates(extractCertificates(serviceHistory.getServiceDigitalIdentity()));
		service.setX500Principals(extractX500Principals(serviceHistory.getServiceDigitalIdentity()));
		service.setExtensions(extractExtensions(serviceHistory.getServiceInformationExtensions()));
		return service;
	}

	@SuppressWarnings("rawtypes")
	private List extractExtensions(ExtensionsListType serviceInformationExtensions) {
		if ((serviceInformationExtensions != null) && CollectionUtils.isNotEmpty(serviceInformationExtensions.getExtension())) {
			List extensions = new ArrayList();
			for (ExtensionType extensionType : serviceInformationExtensions.getExtension()) {
				List content = extensionType.getContent();
				if (CollectionUtils.isNotEmpty(content)) {
					List conditionsForQualifiers = new ArrayList();
					for (Object object : content) {
						if (object instanceof JAXBElement) {
							JAXBElement jaxbElement = (JAXBElement) object;
							Object objectValue = jaxbElement.getValue();
							if (objectValue instanceof QualificationsType) {
								QualificationsType qt = (QualificationsType) jaxbElement.getValue();
								if ((qt != null) && CollectionUtils.isNotEmpty(qt.getQualificationElement())) {
									for (QualificationElementType qualificationElement : qt.getQualificationElement()) {
										CriteriaListType criteriaList = qualificationElement.getCriteriaList();
										if(criteriaList != null) { //Added null check for TSL v5
											List qualifiers = extractQualifiers(qualificationElement);
											Condition condition = getCondition(criteriaList);
											if (CollectionUtils.isNotEmpty(qualifiers) && (condition != null)) {
												conditionsForQualifiers.add(new TSLConditionsForQualifiers(qualifiers, condition));
											}
										}
									}
								}
							}
						}
					}
					if (CollectionUtils.isNotEmpty(conditionsForQualifiers)) {
						TSLServiceExtension extension = new TSLServiceExtension();
						extension.setCritical(extensionType.isCritical());
						extension.setConditionsForQualifiers(conditionsForQualifiers);
						extensions.add(extension);
					}
				}
			}
			return extensions;
		}
		return null;
	}

	private List extractQualifiers(QualificationElementType qualificationElement) {
		List qualifiers = new ArrayList();
		QualifiersType qualifiersType = qualificationElement.getQualifiers();
		if ((qualifiersType != null) && CollectionUtils.isNotEmpty(qualifiersType.getQualifier())) {
			for (QualifierType qualitierType : qualifiersType.getQualifier()) {
				qualifiers.add(qualitierType.getUri());
			}
		}
		return qualifiers;
	}

	private Condition getCondition(CriteriaListType criteriaList) {
		MatchingCriteriaIndicator matchingCriteriaIndicator = MatchingCriteriaIndicator.valueOf(criteriaList.getAssert());
		CompositeCondition condition = new CriteriaListCondition(matchingCriteriaIndicator);
		addKeyUsageConditionsIfPresent(criteriaList.getKeyUsage(), condition);
		addPolicyIdConditionsIfPresent(criteriaList.getPolicySet(), condition);
		addCriteriaListConditionsIfPresent(criteriaList.getCriteriaList(), condition);
		return condition;
	}

	private void addPolicyIdConditionsIfPresent(List policySet, CompositeCondition condition) {
		if (CollectionUtils.isNotEmpty(policySet)) {
			for (PoliciesListType policiesListType : policySet) {
				for (ObjectIdentifierType oidType : policiesListType.getPolicyIdentifier()) {
					IdentifierType identifier = oidType.getIdentifier();
					String id = identifier.getValue();

					// ES TSL :  urn:oid:1.3.6.1.4.1.36035.1.3.1
					if (id.indexOf(':') >= 0) {
						id = id.substring(id.lastIndexOf(':') + 1);
					}

					condition.addChild(new PolicyIdCondition(id));
				}
			}
		}
	}

	private void addKeyUsageConditionsIfPresent(List keyUsages, CompositeCondition condition) {
		if (CollectionUtils.isNotEmpty(keyUsages)) {
			for (KeyUsageType keyUsageType : keyUsages) {
				for (KeyUsageBitType keyUsageBit : keyUsageType.getKeyUsageBit()) {
					condition.addChild(new KeyUsageCondition(keyUsageBit.getName(), keyUsageBit.isValue()));
				}
			}
		}
	}

	private void addCriteriaListConditionsIfPresent(List criteriaList, CompositeCondition condition) {
		if (CollectionUtils.isNotEmpty(criteriaList)) {
			CompositeCondition compositeConditions = new CompositeCondition();
			for (CriteriaListType criteriaListType : criteriaList) {
				compositeConditions.addChild(getCondition(criteriaListType));
			}
			condition.addChild(compositeConditions);
		}
	}

	private String getPostalAddress(TSPInformationType tspInformation) {
		PostalAddressType a = null;
		if (tspInformation.getTSPAddress() == null) {
			return null;
		}
		for (PostalAddressType c : tspInformation.getTSPAddress().getPostalAddresses().getPostalAddress()) {
			if ("en".equalsIgnoreCase(c.getLang())) {
				a = c;
				break;
			}
		}
		if (a == null) {
			a = tspInformation.getTSPAddress().getPostalAddresses().getPostalAddress().get(0);
		}

		StringBuffer sb = new StringBuffer();
		if (StringUtils.isNotEmpty(a.getStreetAddress())) {
			sb.append(a.getStreetAddress());
			sb.append(", ");
		}
		if (StringUtils.isNotEmpty(a.getPostalCode())) {
			sb.append(a.getPostalCode());
			sb.append(", ");
		}
		if (StringUtils.isNotEmpty(a.getLocality())) {
			sb.append(a.getLocality());
			sb.append(", ");
		}
		if (StringUtils.isNotEmpty(a.getStateOrProvince())) {
			sb.append(a.getStateOrProvince());
			sb.append(", ");
		}
		if (StringUtils.isNotEmpty(a.getCountryName())) {
			sb.append(a.getCountryName());
		}
		return sb.toString();
	}

	private String getElectronicAddress(TSPInformationType tspInformation) {
		if (tspInformation.getTSPAddress().getElectronicAddress() == null) {
			return null;
		}
		return tspInformation.getTSPAddress().getElectronicAddress().getURI().get(0).getValue();
	}

	private String getEnglishOrFirst(InternationalNamesType names) {
		if (names == null) {
			return null;
		}
		for (MultiLangNormStringType s : names.getName()) {
			if ("en".equalsIgnoreCase(s.getLang())) {
				return s.getValue();
			}
		}
		return names.getName().get(0).getValue();
	}

}