/* * DSS - Digital Signature Services * * Copyright (C) 2013 European Commission, Directorate-General Internal Market and Services (DG MARKT), B-1049 Bruxelles/Brussel * * Developed by: 2013 ARHS Developments S.A. (rue Nicolas Bové 2B, L-1253 Luxembourg) http://www.arhs-developments.com * * This file is part of the "DSS - Digital Signature Services" project. * * "DSS - Digital Signature Services" 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. * * DSS 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 * "DSS - Digital Signature Services". If not, see <http://www.gnu.org/licenses/>. */ package eu.europa.ec.markt.dss.validation102853.tsl; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.security.auth.x500.X500Principal; import javax.xml.bind.JAXBElement; import javax.xml.datatype.XMLGregorianCalendar; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.TSLConstant; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.exception.DSSNotETSICompliantException; import eu.europa.ec.markt.dss.validation102853.condition.CompositeCondition; import eu.europa.ec.markt.dss.validation102853.condition.Condition; import eu.europa.ec.markt.dss.validation102853.condition.CriteriaListCondition; import eu.europa.ec.markt.dss.validation102853.condition.KeyUsageCondition; import eu.europa.ec.markt.dss.validation102853.condition.MatchingCriteriaIndicator; import eu.europa.ec.markt.dss.validation102853.condition.PolicyIdCondition; import eu.europa.ec.markt.dss.validation102853.condition.ServiceInfo; import eu.europa.ec.markt.tsl.jaxb.ecc.CriteriaListType; import eu.europa.ec.markt.tsl.jaxb.ecc.KeyUsageBitType; import eu.europa.ec.markt.tsl.jaxb.ecc.KeyUsageType; import eu.europa.ec.markt.tsl.jaxb.ecc.PoliciesListType; import eu.europa.ec.markt.tsl.jaxb.ecc.QualificationElementType; import eu.europa.ec.markt.tsl.jaxb.ecc.QualificationsType; import eu.europa.ec.markt.tsl.jaxb.ecc.QualifierType; import eu.europa.ec.markt.tsl.jaxb.ecc.QualifiersType; import eu.europa.ec.markt.tsl.jaxb.tsl.AdditionalServiceInformationType; import eu.europa.ec.markt.tsl.jaxb.tsl.DigitalIdentityListType; import eu.europa.ec.markt.tsl.jaxb.tsl.DigitalIdentityType; import eu.europa.ec.markt.tsl.jaxb.tsl.ExtensionType; import eu.europa.ec.markt.tsl.jaxb.tslx.TakenOverByType; import eu.europa.ec.markt.tsl.jaxb.xades.IdentifierType; import eu.europa.ec.markt.tsl.jaxb.xades.ObjectIdentifierType; /** * Service information from current status and TrustedList shares some common information. * * @version $Revision: 1834 $ - $Date: 2013-03-28 16:04:04 +0100 (Thu, 28 Mar 2013) $ */ abstract class AbstractTrustService { private static final Logger LOG = LoggerFactory.getLogger(AbstractTrustService.class); public static final String TSLX = "TSLX"; public static final String TSL = "TSL"; public static final String ADDITIONAL_SERVICE_INFORMATION = "AdditionalServiceInformation"; public static final String TAKEN_OVER_BY = "TakenOverBy"; private Date expiredCertsRevocationInfo; /** * @return */ abstract List<ExtensionType> getExtensions(); /** * @return */ abstract DigitalIdentityListType getServiceDigitalIdentity(); /** * @return */ abstract String getType(); /** * Return the status of the service * * @return */ abstract String getStatus(); /** * @return */ abstract Date getStatusStartDate(); /** * @return */ abstract Date getStatusEndDate(); /** * @return */ abstract String getServiceName(); /** * Returns the list of certificate representing the digital identity of this service. * * @return {@code List} of {@code Object} which can be {@code X509Certificate} or {@code X500Principal} */ List<Object> getDigitalIdentity() { final List<Object> certs = new ArrayList<Object>(); for (final DigitalIdentityType digitalIdentity : getServiceDigitalIdentity().getDigitalId()) { try { final byte[] x509CertificateBytes = digitalIdentity.getX509Certificate(); if (x509CertificateBytes != null) { final X509Certificate x509Certificate = DSSUtils.loadCertificate(x509CertificateBytes); // System.out.println(" ----- > " + x509Certificate.getSubjectX500Principal()); certs.add(x509Certificate); } else { final String x509SubjectName = digitalIdentity.getX509SubjectName(); if (x509SubjectName != null) { final X500Principal x500Principal = DSSUtils.getX500Principal(x509SubjectName); certs.add(x500Principal); } } } catch (DSSException e) { LOG.warn(e.getLocalizedMessage()); } } return certs; } /** * @return */ ServiceInfo createServiceInfo() { final ServiceInfo service = new ServiceInfo(); final List<QualificationsType> qualificationList = getQualificationsType(); for (final QualificationsType qualifications : qualificationList) { for (final QualificationElementType qualificationElement : qualifications.getQualificationElement()) { parseQualificationElement(qualificationElement, service); } } service.setExpiredCertsRevocationInfo(expiredCertsRevocationInfo); return service; } @SuppressWarnings("rawtypes") private List<QualificationsType> getQualificationsType() { final List<QualificationsType> qualificationList = new ArrayList<QualificationsType>(); for (final ExtensionType extension : getExtensions()) { for (final Object object : extension.getContent()) { if (object instanceof String) { /* do nothing */ // if (DSSUtils.isBlank(object.toString())) { // // } else { // // LOG.warn("Extension containing " + object.toString()); // throw new RuntimeException(); // } } else if (object instanceof JAXBElement) { final JAXBElement jaxbElement = (JAXBElement) object; final Object objectValue = jaxbElement.getValue(); if (objectValue instanceof AdditionalServiceInformationType) { // Do nothing } else if (objectValue instanceof QualificationsType) { qualificationList.add((QualificationsType) jaxbElement.getValue()); } else if (objectValue instanceof TakenOverByType) { // Do nothing } else if (objectValue instanceof XMLGregorianCalendar) { // {http://uri.etsi.org/02231/v2#}ExpiredCertsRevocationInfo XMLGregorianCalendar xmlGregorianCalendar = (XMLGregorianCalendar) objectValue; expiredCertsRevocationInfo = xmlGregorianCalendar.toGregorianCalendar().getTime(); } else { LOG.warn("Unrecognized extension class {}", jaxbElement.getValue().getClass()); } } else if (object instanceof Element) { /* We don't know what to do with the Element without further analysis */ final Element element = (Element) object; final String localName = element.getLocalName(); String namespaceUri = element.getNamespaceURI(); if (ADDITIONAL_SERVICE_INFORMATION.equals(localName) && TSLConstant.TSL.equals(namespaceUri)) { // Do nothing } else if (TAKEN_OVER_BY.equals(localName) && TSLConstant.TSLX.equals(namespaceUri)) { // Do nothing } else { if (TSLConstant.TSLX.equals(namespaceUri)) { namespaceUri = TSLX; } else if (TSLConstant.TSL.equals(namespaceUri)) { namespaceUri = TSL; } throw new DSSNotETSICompliantException(DSSNotETSICompliantException.MSG.UNRECOGNIZED_TAG, namespaceUri + ":" + localName); } } else { throw new DSSException("Unknown extension " + object.getClass()); } } } return qualificationList; } private void parseQualificationElement(final QualificationElementType qualificationElement, final ServiceInfo service) { final QualifiersType qualifierList = qualificationElement.getQualifiers(); if (qualifierList == null || qualifierList.getQualifier().isEmpty()) { return; } try { final CriteriaListType criteriaList = qualificationElement.getCriteriaList(); if (criteriaList != null) { if (criteriaList.getKeyUsage().isEmpty() && criteriaList.getPolicySet().isEmpty() && criteriaList.getCriteriaList().isEmpty()) { LOG.trace("CriteriaList for service is empty, the QualificationElement is skipped."); return; } final Condition compositeCondition = parseCriteriaList(criteriaList); for (QualifierType qualifier : qualifierList.getQualifier()) { service.addQualifierAndCondition(qualifier.getUri(), compositeCondition); } } } catch (IllegalArgumentException e) { throw new DSSNotETSICompliantException(DSSNotETSICompliantException.MSG.UNSUPPORTED_ASSERT); } } private Condition parseCriteriaList(final CriteriaListType criteriaList) { final String assertValue = criteriaList.getAssert(); if (assertValue == null) { LOG.info("CriteriaList assert=null!"); return null; } final boolean traceEnabled = LOG.isTraceEnabled(); if (traceEnabled) { LOG.trace("--- > CriteriaList: assert: " + assertValue); } final MatchingCriteriaIndicator matchingCriteriaIndicator = MatchingCriteriaIndicator.valueOf(assertValue); final CompositeCondition condition = new CriteriaListCondition(matchingCriteriaIndicator); for (final PoliciesListType policies : criteriaList.getPolicySet()) { final CompositeCondition compositeCondition = new CompositeCondition(); for (final ObjectIdentifierType objectIdentifier : policies.getPolicyIdentifier()) { final IdentifierType identifier = objectIdentifier.getIdentifier(); if (identifier.getQualifier() == null) { if (traceEnabled) { LOG.trace("--- > CriteriaList: id1: " + identifier.getValue()); } compositeCondition.addChild(new PolicyIdCondition(identifier.getValue())); } else { String id = identifier.getValue(); // ES TSL // <ns4:Identifier Qualifier="OIDAsURN">urn:oid:1.3.6.1.4.1.36035.1.3.1</ns4:Identifier> if (id.indexOf(':') >= 0) { id = id.substring(id.lastIndexOf(':') + 1); } if (traceEnabled) { LOG.trace("--- > CriteriaList: id2: " + id); } compositeCondition.addChild(new PolicyIdCondition(id)); } } condition.addChild(compositeCondition); } for (final KeyUsageType keyUsage : criteriaList.getKeyUsage()) { final CompositeCondition compositeCondition = new CompositeCondition(); for (final KeyUsageBitType keyUsageBit : keyUsage.getKeyUsageBit()) { if (traceEnabled) { LOG.trace("--- > CriteriaList: kub: " + keyUsageBit.getName() + " [" + keyUsageBit.isValue() + "]"); } final KeyUsageCondition keyUsageCondition = new KeyUsageCondition(keyUsageBit.getName(), keyUsageBit.isValue()); compositeCondition.addChild(keyUsageCondition); } condition.addChild(compositeCondition); } for (final CriteriaListType criteria : criteriaList.getCriteriaList()) { if (traceEnabled) { LOG.trace("--- > CriteriaList: Composite Criteria List:"); } final Condition compositeCondition = parseCriteriaList(criteria); condition.addChild(compositeCondition); } return condition; } }