aboutsummaryrefslogtreecommitdiff
path: root/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/tsl/connector/MOATSLVerifier.java
diff options
context:
space:
mode:
Diffstat (limited to 'moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/tsl/connector/MOATSLVerifier.java')
-rw-r--r--moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/tsl/connector/MOATSLVerifier.java265
1 files changed, 265 insertions, 0 deletions
diff --git a/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/tsl/connector/MOATSLVerifier.java b/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/tsl/connector/MOATSLVerifier.java
new file mode 100644
index 0000000..39b2f8c
--- /dev/null
+++ b/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/tsl/connector/MOATSLVerifier.java
@@ -0,0 +1,265 @@
+package at.gv.egovernment.moa.spss.tsl.connector;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.security.cert.X509Certificate;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBIntrospector;
+import javax.xml.crypto.Data;
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.NodeSetData;
+import javax.xml.crypto.URIReferenceException;
+import javax.xml.crypto.dom.DOMCryptoContext;
+import javax.xml.crypto.dsig.Reference;
+import javax.xml.crypto.dsig.SignedInfo;
+import javax.xml.crypto.dsig.Transform;
+import javax.xml.crypto.dsig.XMLSignature;
+import javax.xml.crypto.dsig.XMLSignatureException;
+import javax.xml.crypto.dsig.XMLSignatureFactory;
+import javax.xml.crypto.dsig.dom.DOMValidateContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import iaik.server.modules.xml.MOAXSecProvider;
+import iaik.xml.crypto.tsl.TSLConstants;
+import iaik.xml.crypto.tsl.TSLContext;
+import iaik.xml.crypto.tsl.TSLEngine;
+import iaik.xml.crypto.tsl.ex.SeverityAspect.Severity;
+import iaik.xml.crypto.tsl.ex.TSLSecurityException;
+import iaik.xml.crypto.tsl.ex.TSLVerificationException;
+import iaik.xml.crypto.tsl.gen.TrustStatusListType;
+import iaik.xml.crypto.tsl.verify.ITSLVerifier;
+import iaik.xml.crypto.utils.URIDereferencerImpl;
+
+public class MOATSLVerifier implements ITSLVerifier {
+
+ private static final Logger logger = LoggerFactory.getLogger(MOATSLVerifier.class);
+
+ private static iaik.xml.crypto.xmldsig.gen.ObjectFactory dsOf = new iaik.xml.crypto.xmldsig.gen.ObjectFactory();
+
+ private static JAXBIntrospector JI = TSLEngine.jc.createJAXBIntrospector();
+
+ public Boolean verifyTSL(Document tslDoc, TSLContext tslContext,
+ ListIterator<X509Certificate> euTslCertsHash) {
+
+ boolean coreValidity = false;
+
+ try {
+ // Signature s = new Signature();
+ // TrustServiceStatusList tssl = new TrustServiceStatusList();
+ JAXBElement<iaik.xml.crypto.xmldsig.gen.SignatureType> s = dsOf.createSignature(new iaik.xml.crypto.xmldsig.gen.SignatureType());
+// _l.debug(""+JI.getElementName(s));
+ JAXBElement<TrustStatusListType> tssl = TSLConstants.TSL_OF.createTrustServiceStatusList(new TrustStatusListType());
+// _l.debug(""+JI.getElementName(tssl));
+
+ Element tsslE = tslDoc.getDocumentElement();
+
+ if (tsslE == null) {
+ tslContext.throwException(new TSLVerificationException("Empty XML File", Severity.xml_failed));
+ // } else if (!tsslE.getNamespaceURI().equals(tssl.getName().getNamespaceURI())) {
+ } else if (!tsslE.getNamespaceURI().equals(JI.getElementName(tssl).getNamespaceURI())) {
+ tslContext.throwException(new TSLVerificationException("Incorrect Namespace", Severity.xml_failed));
+ // } else if (!tsslE.getLocalName().equals(tssl.getName().getLocalPart())) {
+ } else if (!tsslE.getLocalName().equals(JI.getElementName(tssl).getLocalPart())) {
+ tslContext.throwException(new TSLVerificationException("Wrong Document Element in document "+tslDoc.getDocumentURI(), Severity.xml_failed));
+ }
+
+ //now we can be sure the right document element is in place, Schema validation does not assure this for us
+ //Schema validation however assures that the internal Structure of TrustServicesStatus List is correct
+
+ // B.6 1) It MUST be an enveloped signature.
+
+ Node n = tsslE.getLastChild();
+
+ while ( n != null && ! (n instanceof Element) ) {
+ n = n.getPreviousSibling();
+ }
+
+ Element sig = (Element) n;
+
+ if (sig == null ||
+ // ! sig.getNamespaceURI().equals(s.getName().getNamespaceURI()) ||
+ // ! sig.getLocalName().equals(s.getName().getLocalPart())) {
+ ! sig.getNamespaceURI().equals(JI.getElementName(s).getNamespaceURI()) ||
+ ! sig.getLocalName().equals(JI.getElementName(s).getLocalPart())) {
+
+ tslContext.throwException(
+ new TSLVerificationException(
+ TSLSecurityException.Type.NO_TSL_SIGNATURE)
+ );
+
+ } else {
+
+ NodeList cn = tsslE.getChildNodes();
+
+ for (int j = 0; j < cn.getLength(); j++) {
+ cn.item(j);
+ }
+
+ //TODO assure connection with the PKI Module
+ DOMValidateContext valContext = new DOMValidateContext(
+ new MOATslKeySelector(euTslCertsHash, tslContext),
+ sig);
+
+ if (valContext.getURIDereferencer() == null) {
+ valContext.setURIDereferencer(new URIDereferencerImpl());
+ }
+
+ // valContext.setProperty("iaik.xml.crypto.debug.OutputStream", System.out);
+ valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
+
+ XMLSignatureFactory fac = MOAXSecProvider.getXMLSignatureFactory();
+
+ // unmarshal the XMLSignature
+ XMLSignature signature = fac.unmarshalXMLSignature(valContext);
+
+ // Validate the XMLSignature (generated above)
+ coreValidity = signature.validate(valContext);
+ // Check core validation status
+ if (coreValidity == false) {
+ debug(valContext, "Signature failed core validation");
+ boolean sv = signature.getSignatureValue().validate(valContext);
+ debug(valContext, "signature validation status: " + sv);
+ // check the validation status of each Reference
+ Iterator it = signature.getSignedInfo().getReferences().iterator();
+ for (int j = 0; it.hasNext(); j++) {
+ boolean refValid = ((Reference) it.next()).validate(valContext);
+ debug(valContext, "ref[" + j + "] validity status: " + refValid);
+ }
+
+ tslContext.throwException(new TSLVerificationException("Signature failed core validation", Severity.signature_failed));
+ }
+
+ SignedInfo si = signature.getSignedInfo();
+ Iterator it = si.getReferences().iterator();
+
+
+ // 2) Its ds:SignedInfo element MUST contain a ds:Reference element with the
+ // URI attribute set to a value referencing the TrustServiceStatusList
+ // element enveloping the signature itself. This ds:Reference element MUST
+ // satisfy the following requirements:
+ // a) It MUST contain only one ds:Transforms element.
+ // b) This ds:Transforms element MUST contain two ds:Transform elements. The
+ // first one will be one whose Algorithm attribute indicates the enveloped
+ // transformation with the value:
+ // "http://www.w3.org/2000/09/xmldsig#enveloped-signature". The second one
+ // will be one whose Algorithm attribute instructs to perform the exclusive
+ // canonicalization "http://www.w3.org/2001/10/xml-exc-c14n#"
+
+ boolean found_proper_tsslE_reference = false;
+
+ for (int j = 0; it.hasNext(); j++) {
+ Reference ref = ((Reference) it.next());
+ Data d = valContext.getURIDereferencer().dereference(ref, valContext);
+
+ if(!(d instanceof NodeSetData)) {
+ continue;
+ } else {
+ NodeSetData nsd = (NodeSetData) d;
+
+
+ if (nsd.iterator().next() == tsslE) {
+
+ //Assured by XMLSchema
+ //throw new TSLException("B.6 2 a) It MUST contain only one ds:Transforms element.");
+
+ if(ref.getTransforms().size() != 2) {
+ tslContext.throwException(
+ new TSLVerificationException(TSLSecurityException.Type.NON_CONFORMANT_TRANSFORMS_IN_TSL_SIGNATURE)
+ );
+ } else {
+
+ Transform[] transforms = (Transform[]) ref.getTransforms().toArray(new Transform[2]);
+
+ //TODO assign severity, code some heuristic showing the problems
+ if (! transforms[0].getAlgorithm().equals("http://www.w3.org/2000/09/xmldsig#enveloped-signature")) {
+ tslContext.throwException(
+ new TSLVerificationException(TSLSecurityException.Type.NON_CONFORMANT_TRANSFORM_IN_TSL_SIGNATURE)
+ );
+
+ }
+
+ //TODO assign severity, code some heuristic showing the problems
+ if (! transforms[1].getAlgorithm().equals("http://www.w3.org/2001/10/xml-exc-c14n#")) {
+ tslContext.throwException(
+ new TSLVerificationException(TSLSecurityException.Type.NON_CONFORMANT_C14N_IN_TSL_SIGNATURE)
+ );
+ }
+ }
+
+ found_proper_tsslE_reference = true;
+ }//if (nsd.iterator().next() == tsslE)
+
+ }
+ }
+
+ if(!found_proper_tsslE_reference) {
+ tslContext.throwException(
+ new TSLVerificationException(TSLSecurityException.Type.NON_CONFORMANT_REFERENCE_IN_TSL_SIGNATURE)
+ );
+ }
+
+ // 3) ds:CanonicalizationMethod MUST be
+ // "http://www.w3.org/2001/10/xml-exc-c14n#".
+ if (! si.getCanonicalizationMethod().getAlgorithm().equals("http://www.w3.org/2001/10/xml-exc-c14n#")){
+ tslContext.throwException(
+ new TSLVerificationException(TSLSecurityException.Type.NON_CONFORMANT_C14N_IN_CANONICALIZATION_METHOD)
+ );
+ }
+
+ // 4) It MAY have other ds:Reference elements.
+
+ }
+ } catch (URIReferenceException e) {
+ tslContext.throwException(new TSLVerificationException(e));
+ } catch (MarshalException e) {
+ tslContext.throwException(new TSLVerificationException(e));
+ } catch (XMLSignatureException e) {
+ logger.error("Failed to verify XML Signature for TSL!", e);
+ return (Boolean) tslContext.throwException(
+ new TSLSecurityException(TSLSecurityException.Type.ERRORS_IN_TSL_SIGNATURE),
+ //we need an anonymous class to find the enclosing Method
+ (new Object(){}).getClass().getEnclosingMethod(),
+ null,
+ new Object[] {tslDoc, tslContext, euTslCertsHash}
+ );
+ }
+ return coreValidity;
+ }
+
+ public static void debug(DOMCryptoContext context, String message) {
+
+ Object propDebug = context.getProperty("iaik.xml.crypto.debug.OutputStream");
+
+ if ( propDebug == null) {
+ return;
+ }
+
+ if (! (propDebug instanceof OutputStream)) {
+ System.err.println("Failed to write to debug output stream. " +
+ "DOMCryptoContext's Property (\"iaik.xml.crypto.debug.OutputStream\") " +
+ "has to be of type OutputStream."
+ );
+ } else {
+
+ OutputStream os = (OutputStream) propDebug;
+ try {
+ (new OutputStreamWriter(os)).write(message);
+ } catch (IOException e) {
+ System.err.println("Failed to write to debug output stream. " + e.getMessage());
+ //TODO we cannot close the output stream here ...
+ }
+ }
+
+ }
+
+}