]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Refuse cross-origin RRDP
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Tue, 28 Apr 2026 23:37:01 +0000 (17:37 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Tue, 28 Apr 2026 23:37:01 +0000 (17:37 -0600)
RFC 9674. This code was mostly copied from Fort 2's current
pseudo-alpha.

src/rrdp.c
src/types/uri.c
src/types/uri.h

index 684b4aaae8b27f0f64f35c3c35057e9a48429480..ba48788b0e39a49655b261f66905eb636a8ef943 100644 (file)
@@ -659,6 +659,23 @@ end:       metadata_cleanup(&tag.meta);
        return error;
 }
 
+static int
+parse_notification_snapshot(xmlTextReaderPtr reader,
+    struct update_notification *notif)
+{
+       int error;
+
+       error = parse_file_metadata(reader, NULL, HR_MANDATORY, &notif->snapshot);
+       if (error)
+               return error;
+
+       if (!uri_same_origin(notif->uri, notif->snapshot.uri))
+               return pr_val_err("Notification '%s' and Snapshot '%s' are not hosted by the same origin.",
+                   uri_get_global(notif->uri), uri_get_global(notif->snapshot.uri));
+
+       return 0;
+}
+
 static int
 parse_notification_delta(xmlTextReaderPtr reader,
     struct update_notification *notif)
@@ -671,13 +688,21 @@ parse_notification_delta(xmlTextReaderPtr reader,
                return error;
 
        error = parse_file_metadata(reader, NULL, HR_MANDATORY, &delta.meta);
-       if (error) {
-               serial_cleanup(&delta.serial);
-               return error;
+       if (error)
+               goto srl;
+
+       if (!uri_same_origin(notif->uri, delta.meta.uri)) {
+               error = pr_val_err("Notification %s and Delta %s are not hosted by the same origin.",
+                   uri_get_global(notif->uri), uri_get_global(delta.meta.uri));
+               goto mta;
        }
 
        notification_deltas_add(&notif->deltas, &delta);
        return 0;
+
+mta:   metadata_cleanup(&delta.meta);
+srl:   serial_cleanup(&delta.serial);
+       return error;
 }
 
 static int
@@ -780,8 +805,7 @@ xml_read_notif(xmlTextReaderPtr reader, void *arg)
                if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_DELTA)) {
                        return parse_notification_delta(reader, notif);
                } else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_SNAPSHOT)) {
-                       return parse_file_metadata(reader, NULL, HR_MANDATORY,
-                           &notif->snapshot);
+                       return parse_notification_snapshot(reader, notif);
                } else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_NOTIFICATION)) {
                        /* No need to validate session ID and serial */
                        return parse_session(reader, &notif->session);
index c6e2039d25de926f49b4e142dee971ed150b922f..e8b6b6f53895c62e3d47820affadb4782eb856d6 100644 (file)
@@ -594,6 +594,36 @@ uri_get_rrdp_workspace(char const *tal, struct rpki_uri *notif)
        return (get_rrdp_workspace(&pb, tal, notif) == 0) ? pb.string : NULL;
 }
 
+bool
+uri_same_origin(struct rpki_uri  const *uri1, struct rpki_uri  const *uri2)
+{
+       char const *str1, *str2;
+       size_t c, slashes;
+
+       str1 = uri1->global;
+       str2 = uri2->global;
+       slashes = 0;
+
+       for (c = 0; str1[c] == str2[c]; c++) {
+               switch (str1[c]) {
+               case '/':
+                       slashes++;
+                       if (slashes == 3)
+                               return true;
+                       break;
+               case '\0':
+                       return slashes == 2;
+               }
+       }
+
+       if (str1[c] == '\0')
+               return (slashes == 2) && str2[c] == '/';
+       if (str2[c] == '\0')
+               return (slashes == 2) && str1[c] == '/';
+
+       return false;
+}
+
 DEFINE_ARRAY_LIST_FUNCTIONS(uri_list, struct rpki_uri *, static)
 
 void
index c5886ec82e8b7d3949d6dba937c1e98700454da2..f0651d6f1fc3b041f046120fe85f55ad6f527620 100644 (file)
@@ -59,6 +59,8 @@ char const *uri_op_get_printable(struct rpki_uri *);
 
 char *uri_get_rrdp_workspace(char const *, struct rpki_uri *);
 
+bool uri_same_origin(struct rpki_uri const *, struct rpki_uri  const *);
+
 /* Plural */
 
 DEFINE_ARRAY_LIST_STRUCT(uri_list, struct rpki_uri *);