Java tutorial
/* * eID Digital Signature Service Project. * Copyright (C) 2010 FedICT. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version * 3.0 as published by the Free Software Foundation. * * This software 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 software; if not, see * http://www.gnu.org/licenses/. */ package be.fedict.eid.dss.spi.utils; import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CRLException; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; import java.util.List; 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.crypto.dsig.DigestMethod; import javax.xml.crypto.dsig.Reference; import javax.xml.crypto.dsig.SignedInfo; import javax.xml.crypto.dsig.XMLSignature; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xpath.XPathAPI; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.SignerId; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.ocsp.OCSPResp; import org.bouncycastle.tsp.TimeStampToken; import org.joda.time.DateTime; import org.joda.time.Duration; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import be.fedict.eid.applet.service.signer.facets.IdentitySignatureFacet; import be.fedict.eid.applet.service.signer.jaxb.identity.IdentityType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CRLRefType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CRLRefsType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CRLValuesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CertIDListType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CertIDType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CertificateValuesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CompleteCertificateRefsType; import be.fedict.eid.applet.service.signer.jaxb.xades132.CompleteRevocationRefsType; import be.fedict.eid.applet.service.signer.jaxb.xades132.DigestAlgAndValueType; import be.fedict.eid.applet.service.signer.jaxb.xades132.EncapsulatedPKIDataType; import be.fedict.eid.applet.service.signer.jaxb.xades132.OCSPRefType; import be.fedict.eid.applet.service.signer.jaxb.xades132.OCSPRefsType; import be.fedict.eid.applet.service.signer.jaxb.xades132.OCSPValuesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.ObjectFactory; import be.fedict.eid.applet.service.signer.jaxb.xades132.QualifyingPropertiesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.RevocationValuesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.SignedSignaturePropertiesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.UnsignedPropertiesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.UnsignedSignaturePropertiesType; import be.fedict.eid.applet.service.signer.jaxb.xades132.XAdESTimeStampType; import be.fedict.eid.applet.service.signer.jaxb.xmldsig.X509IssuerSerialType; import be.fedict.eid.dss.spi.utils.exception.XAdESValidationException; import org.bouncycastle.jce.X509Principal; /** * Some XAdES Utility methods. * * @author Wim Vandenhaute * @author Frank Cornelis */ public abstract class XAdESUtils { private static final Log LOG = LogFactory.getLog(XAdESUtils.class); public static final String XADES_132_NS_URI = "http://uri.etsi.org/01903/v1.3.2#"; public static final String XADES_141_NS_URI = "http://uri.etsi.org/01903/v1.4.1#"; private static final CertificateFactory certificateFactory; private static final Unmarshaller xadesUnmarshaller; private static final Unmarshaller identityUnmarshaller; static { try { JAXBContext xadesJaxbContext = JAXBContext.newInstance(ObjectFactory.class, be.fedict.eid.applet.service.signer.jaxb.xades141.ObjectFactory.class); xadesUnmarshaller = xadesJaxbContext.createUnmarshaller(); JAXBContext identityJaxbContext = JAXBContext .newInstance(be.fedict.eid.applet.service.signer.jaxb.identity.ObjectFactory.class); identityUnmarshaller = identityJaxbContext.createUnmarshaller(); } catch (JAXBException e) { throw new RuntimeException("JAXB error: " + e.getMessage(), e); } try { certificateFactory = CertificateFactory.getInstance("X.509"); } catch (CertificateException e) { throw new RuntimeException("certificate factory error: " + e.getMessage(), e); } } /** * Gives back all time-stamp tokens embedded within the given XAdES * time-stamp container. * * @param xadesTimeStamp * @return * @throws XAdESValidationException */ public static List<TimeStampToken> getTimeStampTokens(XAdESTimeStampType xadesTimeStamp) throws XAdESValidationException { try { List<TimeStampToken> timeStampTokens = new LinkedList<TimeStampToken>(); for (Object timeStampTokenObject : xadesTimeStamp.getEncapsulatedTimeStampOrXMLTimeStamp()) { if (timeStampTokenObject instanceof EncapsulatedPKIDataType) { EncapsulatedPKIDataType encapsulatedTimeStampToken = (EncapsulatedPKIDataType) timeStampTokenObject; byte[] encodedTimestampToken = encapsulatedTimeStampToken.getValue(); timeStampTokens.add(new TimeStampToken(new CMSSignedData(encodedTimestampToken))); } else { throw new XAdESValidationException( "Timestamp token of type: " + timeStampTokenObject.getClass() + " not supported."); } } return timeStampTokens; } catch (Exception e) { throw new XAdESValidationException(e); } } public static void verifyTimeStampTokenSignature(TimeStampToken timeStampToken) throws XAdESValidationException { try { SignerId signerId = timeStampToken.getSID(); BigInteger signerCertSerialNumber = signerId.getSerialNumber(); //X500Principal signerCertIssuer = signerId.getIssuer(); X500Principal signerCertIssuer = new X500Principal(signerId.getIssuer().getEncoded()); CertStore certStore = timeStampToken.getCertificatesAndCRLs("Collection", BouncyCastleProvider.PROVIDER_NAME); Collection<? extends Certificate> certificates = certStore.getCertificates(null); X509Certificate tsaCertificate = null; for (Certificate certificate : certificates) { X509Certificate x509Certificate = (X509Certificate) certificate; if (signerCertIssuer.equals(x509Certificate.getIssuerX500Principal()) && signerCertSerialNumber.equals(x509Certificate.getSerialNumber())) { tsaCertificate = x509Certificate; break; } } if (null == tsaCertificate) { throw new XAdESValidationException("TSA certificate not present in TST"); } timeStampToken.validate(tsaCertificate, BouncyCastleProvider.PROVIDER_NAME); } catch (Exception e) { throw new XAdESValidationException(e); } } public static void verifyTimeStampTokenDigest(TimeStampToken timeStampToken, TimeStampDigestInput digestInput) throws XAdESValidationException { LOG.debug("digest verification: algo=" + timeStampToken.getTimeStampInfo().getMessageImprintAlgOID()); MessageDigest md; try { md = MessageDigest.getInstance(timeStampToken.getTimeStampInfo().getMessageImprintAlgOID().getId()); } catch (NoSuchAlgorithmException e) { throw new XAdESValidationException(e); } // LOG.debug("digest input: " + new String(digestInput.getBytes())); if (!Arrays.equals(md.digest(digestInput.getBytes()), timeStampToken.getTimeStampInfo().getMessageImprintDigest())) { throw new XAdESValidationException("Digest verification failure for " + "timestamp token"); } } public static List<X509Certificate> getCertificates(CertificateValuesType certificateValues) throws XAdESValidationException { try { List<X509Certificate> certificates = new LinkedList<X509Certificate>(); List<Object> certificateValuesContent = certificateValues .getEncapsulatedX509CertificateOrOtherCertificate(); for (Object certificateValueContent : certificateValuesContent) { if (certificateValueContent instanceof EncapsulatedPKIDataType) { EncapsulatedPKIDataType encapsulatedPkiData = (EncapsulatedPKIDataType) certificateValueContent; byte[] encodedCertificate = encapsulatedPkiData.getValue(); X509Certificate certificate = (X509Certificate) certificateFactory .generateCertificate(new ByteArrayInputStream(encodedCertificate)); certificates.add(certificate); } } return certificates; } catch (CertificateException e) { throw new XAdESValidationException(e); } } public static List<OCSPResp> getOCSPResponses(RevocationValuesType revocationValues) throws XAdESValidationException { try { List<OCSPResp> ocspResponses = new LinkedList<OCSPResp>(); OCSPValuesType ocspValues = revocationValues.getOCSPValues(); if (null == ocspValues) { return ocspResponses; } List<EncapsulatedPKIDataType> ocspValuesList = ocspValues.getEncapsulatedOCSPValue(); for (EncapsulatedPKIDataType ocspValue : ocspValuesList) { byte[] encodedOcspResponse = ocspValue.getValue(); OCSPResp ocspResp = new OCSPResp(encodedOcspResponse); ocspResponses.add(ocspResp); } return ocspResponses; } catch (IOException e) { throw new XAdESValidationException(e); } } public static List<X509CRL> getCrls(RevocationValuesType revocationValues) throws XAdESValidationException { try { List<X509CRL> crls = new LinkedList<X509CRL>(); CRLValuesType crlValues = revocationValues.getCRLValues(); if (null == crlValues) { return crls; } List<EncapsulatedPKIDataType> crlValuesList = crlValues.getEncapsulatedCRLValue(); for (EncapsulatedPKIDataType crlValue : crlValuesList) { byte[] encodedCrl = crlValue.getValue(); X509CRL crl = (X509CRL) certificateFactory.generateCRL(new ByteArrayInputStream(encodedCrl)); crls.add(crl); } return crls; } catch (CRLException e) { throw new XAdESValidationException(e); } } @SuppressWarnings("unchecked") public static <T> T findUnsignedSignatureProperty(QualifyingPropertiesType qualifyingProperties, Class<T> declaredType, String name) { UnsignedPropertiesType unsignedProperties = qualifyingProperties.getUnsignedProperties(); UnsignedSignaturePropertiesType unsignedSignatureProperties = unsignedProperties .getUnsignedSignatureProperties(); List<Object> unsignedSignaturePropertiesContentList = unsignedSignatureProperties .getCounterSignatureOrSignatureTimeStampOrCompleteCertificateRefs(); for (Object unsignedSignatureProperty : unsignedSignaturePropertiesContentList) { if (!(unsignedSignatureProperty instanceof JAXBElement)) { continue; } JAXBElement<?> unsignedSignaturePropertyElement = (JAXBElement<?>) unsignedSignatureProperty; Object unsignedSignaturePropertyValue = unsignedSignaturePropertyElement.getValue(); if (unsignedSignaturePropertyValue.getClass().isAssignableFrom(declaredType)) { if (null == name) { return (T) unsignedSignaturePropertyValue; } else if (unsignedSignaturePropertyElement.getName().getLocalPart().equals(name)) { return (T) unsignedSignaturePropertyValue; } } } return null; } @SuppressWarnings("unchecked") public static String findReferenceUri(XMLSignature xmlSignature, String type) { SignedInfo signedInfo = xmlSignature.getSignedInfo(); List<Reference> references = signedInfo.getReferences(); for (Reference reference : references) { if (type.equals(reference.getType())) { return reference.getURI(); } } return null; } @SuppressWarnings("unchecked") public static QualifyingPropertiesType getQualifyingProperties(Element nsElement, XMLSignature xmlSignature, Element signatureElement) throws XAdESValidationException { try { String xadesSignedPropertiesUri = findReferenceUri(xmlSignature, "http://uri.etsi.org/01903#SignedProperties"); if (null == xadesSignedPropertiesUri) { LOG.error("no XAdES SignedProperties as part of signed XML data"); throw new XAdESValidationException("no XAdES SignedProperties"); } String xadesSignedPropertiesId = xadesSignedPropertiesUri.substring(1); Node xadesQualifyingPropertiesNode = XPathAPI.selectSingleNode(signatureElement, "ds:Object/xades:QualifyingProperties[xades:SignedProperties/@Id='" + xadesSignedPropertiesId + "']", nsElement); JAXBElement<QualifyingPropertiesType> qualifyingPropertiesElement = (JAXBElement<QualifyingPropertiesType>) xadesUnmarshaller .unmarshal(xadesQualifyingPropertiesNode); return qualifyingPropertiesElement.getValue(); } catch (TransformerException e) { throw new XAdESValidationException(e); } catch (JAXBException e) { throw new XAdESValidationException(e); } } @SuppressWarnings("unchecked") public static <T> T unmarshall(Element xadesElement, Class<T> xadesType) throws XAdESValidationException { JAXBElement<T> jaxbElement; try { jaxbElement = (JAXBElement<T>) xadesUnmarshaller.unmarshal(xadesElement); } catch (JAXBException e) { throw new XAdESValidationException(e); } T value = jaxbElement.getValue(); return value; } public static Element findQualifyingPropertiesElement(Element nsElement, XMLSignature xmlSignature, Element signatureElement) throws XAdESValidationException { String xadesSignedPropertiesUri = findReferenceUri(xmlSignature, "http://uri.etsi.org/01903#SignedProperties"); if (null == xadesSignedPropertiesUri) { LOG.error("no XAdES SignedProperties as part of signed XML data"); throw new XAdESValidationException("no XAdES SignedProperties"); } String xadesSignedPropertiesId = xadesSignedPropertiesUri.substring(1); Node xadesQualifyingPropertiesNode; try { xadesQualifyingPropertiesNode = XPathAPI.selectSingleNode(signatureElement, "ds:Object/xades:QualifyingProperties[xades:SignedProperties/@Id='" + xadesSignedPropertiesId + "']", nsElement); } catch (TransformerException e) { throw new XAdESValidationException(e); } return (Element) xadesQualifyingPropertiesNode; } @SuppressWarnings("unchecked") public static IdentityType findIdentity(Element nsElement, XMLSignature xmlSignature, Element signatureElement) throws XAdESValidationException { try { String identityUri = XAdESUtils.findReferenceUri(xmlSignature, IdentitySignatureFacet.REFERENCE_TYPE); if (null != identityUri) { String identityId = identityUri.substring(1); Node identityNode = XPathAPI.selectSingleNode(signatureElement, "ds:Object[@Id = '" + identityId + "']/identity:Identity", nsElement); if (null != identityNode) { JAXBElement<IdentityType> identityElement = (JAXBElement<IdentityType>) identityUnmarshaller .unmarshal(identityNode); return identityElement.getValue(); } } return null; } catch (TransformerException e) { throw new XAdESValidationException(e); } catch (JAXBException e) { throw new XAdESValidationException(e); } } /** * Finds a XAdES named unsigned signature property as DOM element. * <p/> * Working DOM based is required if you want to be able to find the next * sibling at the DOM level. JAXB does not expose this properly. * * @param qualifyingPropertiesElement * the XAdES qualifying properties DOM element. * @param localName * @return * @throws XAdESValidationException */ public static Element findUnsignedSignaturePropertyElement(Element qualifyingPropertiesElement, String localName) throws XAdESValidationException { NodeList unsignedSignaturePropertiesNodeList = qualifyingPropertiesElement .getElementsByTagNameNS(XAdESUtils.XADES_132_NS_URI, "UnsignedSignatureProperties"); if (unsignedSignaturePropertiesNodeList.getLength() == 0) { throw new XAdESValidationException("UnsignedSignatureProperties node not present"); } Node unsignedSignaturePropertiesNode = unsignedSignaturePropertiesNodeList.item(0); NodeList childNodes = unsignedSignaturePropertiesNode.getChildNodes(); int childNodesCount = childNodes.getLength(); for (int idx = 0; idx < childNodesCount; idx++) { Node childNode = childNodes.item(idx); if (Node.ELEMENT_NODE != childNode.getNodeType()) { continue; } Element childElement = (Element) childNode; if (!XAdESUtils.XADES_132_NS_URI.equals(childNode.getNamespaceURI())) { continue; } String actualLocalName = childNode.getLocalName(); if (localName.equals(actualLocalName)) { return childElement; } } return null; } /** * Find the next sibling at DOM level of the given XAdES DOM element. * * @param xadesElement * @param namespace * @param localName * @param jaxbType * @return * @throws XAdESValidationException */ public static <T> T findNextSibling(Element xadesElement, String namespace, String localName, Class<T> jaxbType) throws XAdESValidationException { Node siblingNode = xadesElement.getNextSibling(); while (siblingNode != null && siblingNode.getNodeType() != Node.ELEMENT_NODE) { /* * Can happen as shown during latest ETSI XAdES plugtests. */ LOG.debug("skipping a non-Element sibling: " + siblingNode.getNodeType()); if (Node.TEXT_NODE == siblingNode.getNodeType()) { LOG.debug("TEXT node sibling: \"" + siblingNode.getNodeValue() + "\""); } siblingNode = siblingNode.getNextSibling(); } if (null == siblingNode) { return null; } Element element = (Element) siblingNode; if (false == namespace.equals(element.getNamespaceURI())) { return null; } if (false == localName.equals(element.getLocalName())) { return null; } return unmarshall(element, jaxbType); } /** * Checks whether the given date-times are close enough next to each other. * * @param t1 * @param t2 * @param millis * @throws XAdESValidationException */ public static void checkCloseEnough(DateTime t1, DateTime t2, long millis) throws XAdESValidationException { Duration dt; if (t1.isBefore(t2)) { dt = new Duration(t1, t2); } else { dt = new Duration(t2, t1); } if (false == dt.isShorterThan(new Duration(millis))) { throw new XAdESValidationException( "max dt of " + millis + " ms exceeded between " + t1 + " and " + t2 + " with dt = " + dt); } } /** * Checks whether the given OCSP response is being references in the given * XAdES complete revocation refs structure. * * @param ocspResp * @param completeRevocationRefs * @throws XAdESValidationException */ public static void checkReference(OCSPResp ocspResp, CompleteRevocationRefsType completeRevocationRefs) throws XAdESValidationException { byte[] encodedOcsp; try { encodedOcsp = ocspResp.getEncoded(); } catch (IOException e) { throw new XAdESValidationException("OCSP encoding error: " + e.getMessage(), e); } OCSPRefsType ocspRefs = completeRevocationRefs.getOCSPRefs(); if (null == ocspRefs) { throw new XAdESValidationException("missing OCSPRefs"); } for (OCSPRefType ocspRef : ocspRefs.getOCSPRef()) { DigestAlgAndValueType digestAlgAndValue = ocspRef.getDigestAlgAndValue(); if (null == digestAlgAndValue) { continue; } String xmlDigestAlgo = digestAlgAndValue.getDigestMethod().getAlgorithm(); MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance(getDigestAlgo(xmlDigestAlgo)); } catch (NoSuchAlgorithmException e) { throw new XAdESValidationException("message digest algo error: " + e.getMessage(), e); } byte[] expectedDigestValue = messageDigest.digest(encodedOcsp); byte[] refDigestValue = digestAlgAndValue.getDigestValue(); if (Arrays.equals(expectedDigestValue, refDigestValue)) { return; } } throw new XAdESValidationException("OCSP response not referenced"); } public static String getDigestAlgo(String xmlDigestAlgo) { if (DigestMethod.SHA1.equals(xmlDigestAlgo)) { return "SHA-1"; } if (DigestMethod.SHA256.equals(xmlDigestAlgo)) { return "SHA-256"; } if (DigestMethod.SHA512.equals(xmlDigestAlgo)) { return "SHA-512"; } throw new RuntimeException("unsupported XML digest algo: " + xmlDigestAlgo); } public static void checkReference(X509CRL crl, CompleteRevocationRefsType completeRevocationRefs) throws XAdESValidationException { byte[] encodedCRL; try { encodedCRL = crl.getEncoded(); } catch (CRLException e) { throw new XAdESValidationException("CRL encoding error: " + e.getMessage(), e); } CRLRefsType crlRefs = completeRevocationRefs.getCRLRefs(); if (null == crlRefs) { throw new XAdESValidationException("missing CRLRefs"); } for (CRLRefType crlRef : crlRefs.getCRLRef()) { DigestAlgAndValueType digestAlgAndValue = crlRef.getDigestAlgAndValue(); String xmlDigestAlgo = digestAlgAndValue.getDigestMethod().getAlgorithm(); MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance(getDigestAlgo(xmlDigestAlgo)); } catch (NoSuchAlgorithmException e) { throw new XAdESValidationException("message digest algo error: " + e.getMessage(), e); } byte[] expectedDigestValue = messageDigest.digest(encodedCRL); byte[] refDigestValue = digestAlgAndValue.getDigestValue(); if (Arrays.equals(expectedDigestValue, refDigestValue)) { return; } } throw new XAdESValidationException("CRL not referenced"); } public static void checkSigningCertificate(X509Certificate signingCertificate, SignedSignaturePropertiesType signedSignatureProperties) throws XAdESValidationException, CertificateEncodingException { CertIDListType signingCertificateCertIDList = signedSignatureProperties.getSigningCertificate(); List<CertIDType> signingCertificateCertIDs = signingCertificateCertIDList.getCert(); CertIDType signingCertificateCertID = signingCertificateCertIDs.get(0); DigestAlgAndValueType signingCertificateDigestAlgAndValue = signingCertificateCertID.getCertDigest(); String certXmlDigestAlgo = signingCertificateDigestAlgAndValue.getDigestMethod().getAlgorithm(); String certDigestAlgo = XAdESUtils.getDigestAlgo(certXmlDigestAlgo); byte[] certDigestValue = signingCertificateDigestAlgAndValue.getDigestValue(); MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance(certDigestAlgo); } catch (NoSuchAlgorithmException e) { throw new XAdESValidationException("message digest algo error: " + e.getMessage(), e); } byte[] actualCertDigestValue = messageDigest.digest(signingCertificate.getEncoded()); if (!Arrays.equals(actualCertDigestValue, certDigestValue)) { throw new XAdESValidationException( "XAdES signing certificate not corresponding with actual signing certificate"); } X509IssuerSerialType issuerSerial = signingCertificateCertID.getIssuerSerial(); BigInteger serialNumber = issuerSerial.getX509SerialNumber(); if (false == signingCertificate.getSerialNumber().equals(serialNumber)) { throw new XAdESValidationException("xades:SigningCertificate serial number mismatch"); } X509Name issuerName; try { /*issuerName = new X509Name( (ASN1Sequence) new ASN1InputStream(signingCertificate .getIssuerX500Principal().getEncoded()) .readObject());*/ X509Principal sprin = new X509Principal(signingCertificate.getIssuerX500Principal().getEncoded()); //issuerName = new X509Name( signingCertificate.getIssuerX500Principal().getName(X500Principal.RFC1779) ); issuerName = new X509Name(sprin.getName()); } catch (IOException e) { throw new XAdESValidationException("error parsing xades:SigningCertificate ds:X509IssuerName: " + e); } X509Name xadesIssuerName = new X509Name(issuerSerial.getX509IssuerName()); if (false == issuerName.equals(xadesIssuerName)) { throw new XAdESValidationException("xades:SigningCertificate issuer name mismatch"); } LOG.debug("XAdES SigningCertificate OK"); } public static void checkReference(X509Certificate certificate, CompleteCertificateRefsType completeCertificateRefs) throws XAdESValidationException { byte[] encodedCert; try { encodedCert = certificate.getEncoded(); } catch (CertificateEncodingException e) { throw new XAdESValidationException("X509 encoding error: " + e.getMessage(), e); } CertIDListType certIDList = completeCertificateRefs.getCertRefs(); if (null == certIDList) { throw new XAdESValidationException("missing CertRefs"); } for (CertIDType certID : certIDList.getCert()) { DigestAlgAndValueType digestAlgAndValue = certID.getCertDigest(); String xmlDigestAlgo = digestAlgAndValue.getDigestMethod().getAlgorithm(); MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance(getDigestAlgo(xmlDigestAlgo)); } catch (NoSuchAlgorithmException e) { throw new XAdESValidationException("message digest algo error: " + e.getMessage(), e); } byte[] expectedDigestValue = messageDigest.digest(encodedCert); byte[] refDigestValue = digestAlgAndValue.getDigestValue(); if (Arrays.equals(expectedDigestValue, refDigestValue)) { return; } } throw new XAdESValidationException("X509 certificate not referenced"); } public static Document loadDocument(byte[] data) { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); DocumentBuilder domBuilder; try { domBuilder = domFactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new RuntimeException("parser configuration error: " + e.getMessage(), e); } ByteArrayInputStream inputStream = new ByteArrayInputStream(data); InputSource inputSource = new InputSource(inputStream); try { return domBuilder.parse(inputSource); } catch (SAXException e) { throw new RuntimeException("SAX error: " + e.getMessage(), e); } catch (IOException e) { throw new RuntimeException("IO error: " + e.getMessage(), e); } } }