From: Alberto Leiva Popper Date: Tue, 28 Apr 2026 23:37:01 +0000 (-0600) Subject: Refuse cross-origin RRDP X-Git-Tag: 1.6.8~3^2 X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=e6b953cec420bd6fa10ada8e9727edae64521e16;p=thirdparty%2FFORT-validator.git Refuse cross-origin RRDP RFC 9674. This code was mostly copied from Fort 2's current pseudo-alpha. --- diff --git a/src/rrdp.c b/src/rrdp.c index 684b4aaa..ba48788b 100644 --- a/src/rrdp.c +++ b/src/rrdp.c @@ -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, ¬if->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(¬if->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, - ¬if->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, ¬if->session); diff --git a/src/types/uri.c b/src/types/uri.c index c6e2039d..e8b6b6f5 100644 --- a/src/types/uri.c +++ b/src/types/uri.c @@ -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 diff --git a/src/types/uri.h b/src/types/uri.h index c5886ec8..f0651d6f 100644 --- a/src/types/uri.h +++ b/src/types/uri.h @@ -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 *);