BUG-2511: disable external entitiy resolution with EXI 51/13651/2
authorRobert Varga <rovarga@cisco.com>
Mon, 15 Dec 2014 13:38:25 +0000 (14:38 +0100)
committerRobert Varga <rovarga@cisco.com>
Tue, 16 Dec 2014 10:54:14 +0000 (11:54 +0100)
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.

Change-Id: Idf4b7faf13063c88624f2ba16f3871679c072b3e
Signed-off-by: Robert Varga <rovarga@cisco.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 98baef0..30867bc 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 f1e72ed..e90bc79 100644 (file)
@@ -20,6 +20,7 @@ import javax.xml.transform.sax.SAXResult;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.openexi.proc.common.EXIOptionsException;
 import org.openexi.sax.Transmogrifier;
+import org.openexi.sax.TransmogrifierException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,7 +33,7 @@ public final class NetconfMessageToEXIEncoder extends MessageToByteEncoder<Netco
     }
 
     @Override
-    protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws EXIOptionsException, IOException, TransformerException {
+    protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws EXIOptionsException, IOException, TransformerException, TransmogrifierException {
         LOG.trace("Sent to encode : {}", msg);
 
         try (final OutputStream os = new ByteBufOutputStream(out)) {