BUG-2511: disable external entitiy resolution with EXI 74/13774/1
authorColin Dixon <colin@colindixon.com>
Mon, 15 Dec 2014 13:38:25 +0000 (14:38 +0100)
committerColin Dixon <colin@colindixon.com>
Fri, 19 Dec 2014 20:58:51 +0000 (14:58 -0600)
OpenEXI transmogrifier can resolve external entities. This should never
be necessary in NETCONF context, so disallow that. The same goes for the
reader, but there we need to add a custom EntityResolver.

Origial work done by Robert Vargag. Cherry-picked from
8350f87e0e1190fcc84099d3b7446a2f1de9e5f9 by Colin Dixon.

Change-Id: Idf4b7faf13063c88624f2ba16f3871679c072b3e
Signed-off-by: Robert Varga <rovarga@cisco.com>
Signed-off-by: Colin Dixon <colin@colindixon.com>
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXICodec.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfMessageToEXIEncoder.java

index 98baef0f8580fb5ae8b2677ee20072ff14c3ab5c..30867bcd186390ff6d73c737a02d457c60955f92 100644 (file)
@@ -8,6 +8,9 @@ import org.openexi.proc.common.GrammarOptions;
 import org.openexi.proc.grammars.GrammarCache;
 import org.openexi.sax.EXIReader;
 import org.openexi.sax.Transmogrifier;
+import org.openexi.sax.TransmogrifierException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
 
 public final class NetconfEXICodec {
     /**
@@ -16,6 +19,17 @@ public final class NetconfEXICodec {
      * of the stream. This is really useful, so let's output it now.
      */
     private static final boolean OUTPUT_EXI_COOKIE = true;
+    /**
+     * OpenEXI does not allow us to directly prevent resolution of external entities. In order
+     * to prevent XXE attacks, we reuse a single no-op entity resolver.
+     */
+    private static final EntityResolver ENTITY_RESOLVER = new EntityResolver() {
+        @Override
+        public InputSource resolveEntity(final String publicId, final String systemId) {
+            return new InputSource();
+        }
+    };
+
     private final EXIOptions exiOptions;
 
     public NetconfEXICodec(final EXIOptions exiOptions) {
@@ -44,16 +58,18 @@ public final class NetconfEXICodec {
         final EXIReader r = new EXIReader();
         r.setPreserveLexicalValues(exiOptions.getPreserveLexicalValues());
         r.setGrammarCache(getGrammarCache());
+        r.setEntityResolver(ENTITY_RESOLVER);
         return r;
     }
 
-    Transmogrifier getTransmogrifier() throws EXIOptionsException {
+    Transmogrifier getTransmogrifier() throws EXIOptionsException, TransmogrifierException {
         final Transmogrifier transmogrifier = new Transmogrifier();
         transmogrifier.setAlignmentType(exiOptions.getAlignmentType());
         transmogrifier.setBlockSize(exiOptions.getBlockSize());
         transmogrifier.setGrammarCache(getGrammarCache());
         transmogrifier.setOutputCookie(OUTPUT_EXI_COOKIE);
         transmogrifier.setOutputOptions(HeaderOptionsOutputType.all);
+        transmogrifier.setResolveExternalGeneralEntities(false);
         return transmogrifier;
     }
 }
index 0a866fffaa082c346cb726b1d815b170e9b77a0e..9048fea6a3767236805b3068b0f75a5c68574b97 100644 (file)
@@ -7,22 +7,30 @@
  */
 package org.opendaylight.controller.netconf.nettyutil.handler;
 
-import com.google.common.base.Preconditions;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufOutputStream;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.MessageToByteEncoder;
+
+import java.io.IOException;
 import java.io.OutputStream;
+
 import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.sax.SAXTransformerFactory;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.openexi.proc.common.EXIOptionsException;
 import org.openexi.sax.Transmogrifier;
+import org.openexi.sax.TransmogrifierException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
 public final class NetconfMessageToEXIEncoder extends MessageToByteEncoder<NetconfMessage> {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToEXIEncoder.class);
@@ -35,7 +43,7 @@ public final class NetconfMessageToEXIEncoder extends MessageToByteEncoder<Netco
     }
 
     @Override
-    protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws Exception {
+    protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws EXIOptionsException, IOException, TransformerException, TransmogrifierException {
         LOG.trace("Sent to encode : {}", XmlUtil.toString(msg.getDocument()));
 
         try (final OutputStream os = new ByteBufOutputStream(out)) {