Repository: shapesecurity/salvation
Pull request #126 (2016-04-10 23:12:15)

fixes GH-123: local scheme (GUID) matching should be case-insensitive

michaelficarra: LGTM thanks.

Patch:
diff --git a/src/main/java/com/shapesecurity/salvation/data/GUID.java b/src/main/java/com/shapesecurity/salvation/data/GUID.java
index 6e4548c..22b92bb 100644
--- a/src/main/java/com/shapesecurity/salvation/data/GUID.java
+++ b/src/main/java/com/shapesecurity/salvation/data/GUID.java
@@ -12,11 +12,11 @@ public class GUID extends Origin {
     @Override public boolean equals(Object other) {
         if (!(other instanceof GUID))
             return false;
-        return ((GUID) other).value.equals(this.value);
+        return ((GUID) other).value.equalsIgnoreCase(this.value);
     }
 
     @Override public int hashCode() {
-        return this.value.hashCode();
+        return this.value.toLowerCase().hashCode();
     }
 
     @Nonnull @Override public String show() {
diff --git a/src/main/java/com/shapesecurity/salvation/data/Policy.java b/src/main/java/com/shapesecurity/salvation/data/Policy.java
index b076495..9dea583 100644
--- a/src/main/java/com/shapesecurity/salvation/data/Policy.java
+++ b/src/main/java/com/shapesecurity/salvation/data/Policy.java
@@ -142,7 +142,7 @@ public class Policy implements Show {
                     Set<SourceExpression> newSources = sourceListDirective.values()
                         // * remove all other host sources in a source list that contains *
                         .filter(x -> !(x instanceof HostSource))
-                        // * remove schemes sources other than data:, blob:, and filesystem: in source list that contains *
+                        // * remove schemes sources other than about:, data:, blob:, and filesystem: in source list that contains *
                         .filter(x -> !(x instanceof SchemeSource) || ((SchemeSource) x).matchesProtectedScheme())
                         .collect(Collectors.toCollection(LinkedHashSet::new));
                     newSources.add(star.get());
@@ -522,4 +522,12 @@ public class Policy implements Show {
         }
         return frameAncestorsDirective.matchesSource(this.origin, source);
     }
+
+    public boolean allowsFrameAncestor(@Nonnull GUID source) {
+        FrameAncestorsDirective frameAncestorsDirective = this.getDirectiveByType(FrameAncestorsDirective.class);
+        if (frameAncestorsDirective == null) {
+            return true;
+        }
+        return frameAncestorsDirective.matchesSource(this.origin, source);
+    }
 }
diff --git a/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java b/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java
index 2bbd071..44b7b0e 100644
--- a/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java
+++ b/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java
@@ -21,11 +21,12 @@ public class SchemeSource implements SourceExpression, AncestorSource, MatchesSo
     }
 
     @Override public boolean matchesSource(@Nonnull Origin origin, @Nonnull GUID source) {
-        return source.value.startsWith(this.value + ":");
+        return source.value.toLowerCase().startsWith(this.value.toLowerCase() + ":");
     }
 
     public boolean matchesProtectedScheme() {
-        return this.value.equals("data") || this.value.equals("blob") || this.value.equals("filesystem");
+        return this.value.equalsIgnoreCase("about") || this.value.equalsIgnoreCase("blob") ||
+            this.value.equalsIgnoreCase("data") || this.value.equalsIgnoreCase("filesystem");
     }
 
     @Override public boolean equals(@Nullable Object other) {


Test patch:
diff --git a/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java b/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java
index 4b5a466..6ba1c8c 100644
--- a/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java
+++ b/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java
@@ -290,6 +290,37 @@ public class PolicyQueryingTest extends CSPTest {
         assertFalse(p.allowsScriptFromSource(URI.parse("http://example.com/a/b/C")));
     }
 
+    @Test public void testLocalSchemes() {
+        Policy p = Parser.parse("script-src *.example.com data: blob:; frame-ancestors data: about:", "http://example.com");
+        assertTrue(p.allowsScriptFromSource(new GUID("data:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("DATA:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("blob:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("BLOB:")));
+        assertFalse(p.allowsScriptFromSource(new GUID("about::")));
+        assertFalse(p.allowsScriptFromSource(new GUID("ABOUT:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("data:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("DATA:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("about:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("ABOUT:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("blob:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("BLOB:")));
+
+        p = Parser.parse("script-src *.example.com DATA: BLOB:; frame-ancestors DATA: ABOUT:", "http://example.com");
+        assertTrue(p.allowsScriptFromSource(new GUID("data:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("DATA:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("blob:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("BLOB:")));
+        assertFalse(p.allowsScriptFromSource(new GUID("about::")));
+        assertFalse(p.allowsScriptFromSource(new GUID("ABOUT:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("data:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("DATA:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("about:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("ABOUT:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("blob:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("BLOB:")));
+
+    }
+
     @Test public void testWildcards() {
         Policy p;