From 105dfe940667d73310a88fd5d54443c0f0c708b1 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Thu, 11 Apr 2024 17:43:11 +0200 Subject: [PATCH] Enforce same origin for all resources of an RRDP server. (#953) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR enforces that all resources fetched for an RRDP server have the same origin as the URI provided in the CA certificate. It checks this for all URIs provided in the server’s notification file and restricts redirects to URIs with the same origin. --- Cargo.lock | 2 +- src/collector/rrdp/http.rs | 28 +++++++++++++++++++++++++++- src/collector/rrdp/update.rs | 6 ++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a941c356..2eeecd2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1150,7 +1150,7 @@ dependencies = [ [[package]] name = "rpki" version = "0.18.2-dev" -source = "git+https://github.com/NLnetLabs/rpki-rs.git#6e3e89b5aa5ff9a4924150efabed004d20dd2a9f" +source = "git+https://github.com/NLnetLabs/rpki-rs.git#d16df4f644f093423b3fc95410d8d326746e0197" dependencies = [ "arbitrary", "base64", diff --git a/src/collector/rrdp/http.rs b/src/collector/rrdp/http.rs index 1926f23b..e6ec478f 100644 --- a/src/collector/rrdp/http.rs +++ b/src/collector/rrdp/http.rs @@ -5,7 +5,7 @@ use std::time::Duration; use bytes::Bytes; use chrono::{DateTime, Utc}; use log::{error, warn}; -use reqwest::header; +use reqwest::{header, redirect}; use reqwest::{Certificate, Proxy, StatusCode}; use reqwest::blocking::{Client, ClientBuilder, RequestBuilder, Response}; use rpki::uri; @@ -52,6 +52,9 @@ impl HttpClient { builder = builder.user_agent(&config.rrdp_user_agent); builder = builder.tcp_keepalive(config.rrdp_tcp_keepalive); builder = builder.timeout(None); // Set per request. + builder = builder.redirect( + redirect::Policy::custom(Self::redirect_policy) + ); if let Some(timeout) = config.rrdp_connect_timeout { builder = builder.connect_timeout(timeout); } @@ -256,6 +259,29 @@ impl HttpClient { } } */ + + /// The redirect policy. + /// + /// We allow up to 10 redirects (reqwest’s default policy) but only if + /// the origin stays the same. + fn redirect_policy(attempt: redirect::Attempt) -> redirect::Action { + if attempt.previous().len() > 9 { + return attempt.stop(); + } + let orig = match attempt.previous().first() { + Some(url) => url, + None => return attempt.follow() // Shouldn’t happen? + }; + let new = attempt.url(); + let orig = (orig.scheme(), orig.host(), orig.port()); + let new = (new.scheme(), new.host(), new.port()); + if orig == new { + attempt.follow() + } + else { + attempt.stop() + } + } } diff --git a/src/collector/rrdp/update.rs b/src/collector/rrdp/update.rs index 4d2038af..157b9645 100644 --- a/src/collector/rrdp/update.rs +++ b/src/collector/rrdp/update.rs @@ -98,6 +98,12 @@ impl Notification { warn!("RRDP {}: {}", uri, err); Failed })?; + if !content.has_matching_origins(&uri) { + warn!("RRDP {}: snapshot or delta files with different origin", + uri + ); + return Err(Failed) + } content.sort_deltas(); Ok(Notification { uri, content, etag, last_modified }) }