From b6c8f060962ebf244594de2e108b3cbd6d0a69d0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 17 Nov 2024 23:57:56 +0000 Subject: [PATCH 01/11] Add tests for invalid plugin name chars --- age/src/plugin.rs | 62 +++++++++++++++++++ .../file.age.txt | 8 +++ .../rage/decrypt-invalid-identity-chars.toml | 13 ++++ .../decrypt-invalid-plugin-name-chars.toml | 12 ++++ .../rage/encrypt-invalid-recipient-chars.toml | 11 ++++ 5 files changed, 106 insertions(+) create mode 100644 rage/tests/cmd/rage/decrypt-invalid-identity-chars.in/file.age.txt create mode 100644 rage/tests/cmd/rage/decrypt-invalid-identity-chars.toml create mode 100644 rage/tests/cmd/rage/decrypt-invalid-plugin-name-chars.toml create mode 100644 rage/tests/cmd/rage/encrypt-invalid-recipient-chars.toml diff --git a/age/src/plugin.rs b/age/src/plugin.rs index 97a1465b..387bf9ff 100644 --- a/age/src/plugin.rs +++ b/age/src/plugin.rs @@ -461,3 +461,65 @@ impl crate::Identity for IdentityPluginV1 { self.unwrap_stanzas(stanzas.iter()) } } + +#[cfg(test)] +mod tests { + use crate::{Callbacks, DecryptError, EncryptError}; + + use super::{ + Identity, IdentityPluginV1, Recipient, RecipientPluginV1, PLUGIN_IDENTITY_PREFIX, + PLUGIN_RECIPIENT_PREFIX, + }; + + const INVALID_PLUGIN_NAME: &str = "foobar/../../../../../../../usr/bin/echo"; + + struct NoCallbacks; + impl Callbacks for NoCallbacks { + fn prompt(&self, _: &str) {} + fn request_public_string(&self, _: &str) -> Option { + None + } + fn request_passphrase(&self, _: &str) -> Option { + None + } + } + + #[test] + fn recipient_rejects_invalid_chars() { + let invalid_recipient = bech32::encode( + &format!("{}{}", PLUGIN_RECIPIENT_PREFIX, INVALID_PLUGIN_NAME), + [], + bech32::Variant::Bech32, + ) + .unwrap(); + assert!(invalid_recipient.parse::().is_err()); + } + + #[test] + fn identity_rejects_invalid_chars() { + let invalid_identity = bech32::encode( + &format!("{}{}-", PLUGIN_IDENTITY_PREFIX, INVALID_PLUGIN_NAME), + [], + bech32::Variant::Bech32, + ) + .expect("HRP is valid") + .to_uppercase(); + assert!(invalid_identity.parse::().is_err()); + } + + #[test] + fn recipient_plugin_v1_rejects_invalid_chars() { + assert!(matches!( + RecipientPluginV1::new(INVALID_PLUGIN_NAME, &[], &[], NoCallbacks), + Err(EncryptError::MissingPlugin { binary_name }) if binary_name == INVALID_PLUGIN_NAME, + )); + } + + #[test] + fn identity_plugin_v1_rejects_invalid_chars() { + assert!(matches!( + IdentityPluginV1::new(INVALID_PLUGIN_NAME, &[], NoCallbacks), + Err(DecryptError::MissingPlugin { binary_name }) if binary_name == INVALID_PLUGIN_NAME, + )); + } +} diff --git a/rage/tests/cmd/rage/decrypt-invalid-identity-chars.in/file.age.txt b/rage/tests/cmd/rage/decrypt-invalid-identity-chars.in/file.age.txt new file mode 100644 index 00000000..6f9dc67f --- /dev/null +++ b/rage/tests/cmd/rage/decrypt-invalid-identity-chars.in/file.age.txt @@ -0,0 +1,8 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHUGc3Zlhpekp0K012aXdu +T1VZN0lmWlRmNjdLYVB4RldkTFVLTkNDUXlBCmJjRUcrM3E0a0U0N3IyK1JsTitG +dHVTd0N6TVFRTWgzdG5uSzJmNm9YMTgKLT4gQXQ1WWAtZ3JlYXNlIDxodGFSVHJg +IFg0cWYsO0ogZ2Fzc1EKZGtPSTB3Ci0tLSBKazRIaHJxdnNJcHpyclRkQjg3QW5r +SVE2MHdtWkErYTNrNWJibWd1bmNBCkK9FoOkiLB93gD79vNed8L3LM9rhKm5qma2 +lSiwRx/aM1DKaZO0CMmYQkoM2tPReA== +-----END AGE ENCRYPTED FILE----- diff --git a/rage/tests/cmd/rage/decrypt-invalid-identity-chars.toml b/rage/tests/cmd/rage/decrypt-invalid-identity-chars.toml new file mode 100644 index 00000000..d3350d2a --- /dev/null +++ b/rage/tests/cmd/rage/decrypt-invalid-identity-chars.toml @@ -0,0 +1,13 @@ +bin.name = "rage" +args = "--decrypt --identity - file.age.txt" +status = "failed" +stdin = """ +AGE-PLUGIN-FOOBAR/../../../../../../../USR/BIN/ECHO-1HKGPY3 +""" +stdout = "" +stderr = """ +Error: identity file contains non-identity data on line 1 + +[ Did rage not do what you expected? Could an error be more useful? ] +[ Tell us: https://str4d.xyz/rage/report ] +""" diff --git a/rage/tests/cmd/rage/decrypt-invalid-plugin-name-chars.toml b/rage/tests/cmd/rage/decrypt-invalid-plugin-name-chars.toml new file mode 100644 index 00000000..968a8b25 --- /dev/null +++ b/rage/tests/cmd/rage/decrypt-invalid-plugin-name-chars.toml @@ -0,0 +1,12 @@ +bin.name = "rage" +args = "--decrypt -j foobar/../../../../../../../usr/bin/echo" +status = "failed" +stdin = "" +stdout = "" +stderr = """ +Error: Could not find 'foobar/../../../../../../../usr/bin/echo' on the PATH. +Have you installed the plugin? + +[ Did rage not do what you expected? Could an error be more useful? ] +[ Tell us: https://str4d.xyz/rage/report ] +""" diff --git a/rage/tests/cmd/rage/encrypt-invalid-recipient-chars.toml b/rage/tests/cmd/rage/encrypt-invalid-recipient-chars.toml new file mode 100644 index 00000000..ce03d5e5 --- /dev/null +++ b/rage/tests/cmd/rage/encrypt-invalid-recipient-chars.toml @@ -0,0 +1,11 @@ +bin.name = "rage" +args = "--encrypt --recipient age1foobar/../../../../../../../usr/bin/echo1849l6e" +status = "failed" +stdin = "" +stdout = "" +stderr = """ +Error: Invalid recipient 'age1foobar/../../../../../../../usr/bin/echo1849l6e'. + +[ Did rage not do what you expected? Could an error be more useful? ] +[ Tell us: https://str4d.xyz/rage/report ] +""" From 703152ecfa86f27952a35b57dd525ed39396a227 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 00:29:11 +0000 Subject: [PATCH 02/11] Restrict set of valid characters for plugin names Previously, plugin names were allowed to be `1*VCHAR`, which permits path separators and parent directory syntax. Under certain conditions, this could cause `rage` to execute a different binary than intended when launching a plugin. Plugin names are now restricted to alphanumeric characters or +-._ which covers all binary names generally observed in practice. --- age/CHANGELOG.md | 6 +++ age/src/plugin.rs | 104 +++++++++++++++++++++++++++++----------------- rage/CHANGELOG.md | 6 +++ 3 files changed, 79 insertions(+), 37 deletions(-) diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index 2543e30f..2c22bea2 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to Rust's notion of to 1.0.0 are beta releases. ## [Unreleased] +### Security +- The age plugin protocol previously allowed plugin names that could be + interpreted as file paths. Under certain conditions, this could lead to a + different binary being executed as an age plugin than intended. Plugin names + are now required to only contain alphanumeric characters or the four special + characters `+-._`. ## [0.6.0] - 2021-05-02 ### Security diff --git a/age/src/plugin.rs b/age/src/plugin.rs index 387bf9ff..494f593f 100644 --- a/age/src/plugin.rs +++ b/age/src/plugin.rs @@ -29,6 +29,13 @@ const CMD_REQUEST_PUBLIC: &str = "request-public"; const CMD_REQUEST_SECRET: &str = "request-secret"; const CMD_FILE_KEY: &str = "file-key"; +#[inline] +fn valid_plugin_name(plugin_name: &str) -> bool { + plugin_name + .bytes() + .all(|b| b.is_ascii_alphanumeric() | matches!(b, b'+' | b'-' | b'.' | b'_')) +} + fn binary_name(plugin_name: &str) -> String { format!("age-plugin-{}", plugin_name) } @@ -53,10 +60,15 @@ impl std::str::FromStr for Recipient { if hrp.len() > PLUGIN_RECIPIENT_PREFIX.len() && hrp.starts_with(PLUGIN_RECIPIENT_PREFIX) { - Ok(Recipient { - name: hrp.split_at(PLUGIN_RECIPIENT_PREFIX.len()).1.to_owned(), - recipient: s.to_owned(), - }) + let name = hrp.split_at(PLUGIN_RECIPIENT_PREFIX.len()).1.to_owned(); + if valid_plugin_name(&name) { + Ok(Recipient { + name, + recipient: s.to_owned(), + }) + } else { + Err("invalid plugin name") + } } else { Err("invalid HRP") } @@ -97,14 +109,20 @@ impl std::str::FromStr for Identity { if hrp.len() > PLUGIN_IDENTITY_PREFIX.len() && hrp.starts_with(PLUGIN_IDENTITY_PREFIX) { - Ok(Identity { - name: hrp - .split_at(PLUGIN_IDENTITY_PREFIX.len()) - .1 - .trim_end_matches('-') - .to_owned(), - identity: s.to_owned(), - }) + // TODO: Decide whether to allow plugin names to end in - + let name = hrp + .split_at(PLUGIN_IDENTITY_PREFIX.len()) + .1 + .trim_end_matches('-') + .to_owned(); + if valid_plugin_name(&name) { + Ok(Identity { + name, + identity: s.to_owned(), + }) + } else { + Err("invalid plugin name") + } } else { Err("invalid HRP") } @@ -178,22 +196,28 @@ impl RecipientPluginV1 { identities: &[Identity], callbacks: C, ) -> Result { - Plugin::new(plugin_name) - .map_err(|binary_name| EncryptError::MissingPlugin { binary_name }) - .map(|plugin| RecipientPluginV1 { - plugin, - recipients: recipients - .iter() - .filter(|r| r.name == plugin_name) - .cloned() - .collect(), - identities: identities - .iter() - .filter(|r| r.name == plugin_name) - .cloned() - .collect(), - callbacks, + if valid_plugin_name(plugin_name) { + Plugin::new(plugin_name) + .map_err(|binary_name| EncryptError::MissingPlugin { binary_name }) + .map(|plugin| RecipientPluginV1 { + plugin, + recipients: recipients + .iter() + .filter(|r| r.name == plugin_name) + .cloned() + .collect(), + identities: identities + .iter() + .filter(|r| r.name == plugin_name) + .cloned() + .collect(), + callbacks, + }) + } else { + Err(EncryptError::MissingPlugin { + binary_name: plugin_name.to_string(), }) + } } } @@ -344,17 +368,23 @@ impl IdentityPluginV1 { identities: &[Identity], callbacks: C, ) -> Result { - Plugin::new(plugin_name) - .map_err(|binary_name| DecryptError::MissingPlugin { binary_name }) - .map(|plugin| IdentityPluginV1 { - plugin, - identities: identities - .iter() - .filter(|r| r.name == plugin_name) - .cloned() - .collect(), - callbacks, + if valid_plugin_name(plugin_name) { + Plugin::new(plugin_name) + .map_err(|binary_name| DecryptError::MissingPlugin { binary_name }) + .map(|plugin| IdentityPluginV1 { + plugin, + identities: identities + .iter() + .filter(|r| r.name == plugin_name) + .cloned() + .collect(), + callbacks, + }) + } else { + Err(DecryptError::MissingPlugin { + binary_name: plugin_name.to_string(), }) + } } fn unwrap_stanzas<'a>( diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 922666d3..17879dd1 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to Rust's notion of to 1.0.0 are beta releases. ## [Unreleased] +### Security +- The age plugin protocol previously allowed plugin names that could be + interpreted as file paths. Under certain conditions, this could lead to a + different binary being executed as an age plugin than intended. Plugin names + are now required to only contain alphanumeric characters or the four special + characters `+-._`. ## [0.6.0] - 2021-05-02 ### Added From 5501bb6220baab685557112de3f4f410de7f4fc7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 05:24:53 +0000 Subject: [PATCH 03/11] v0.6.1 --- Cargo.lock | 4 ++-- age/CHANGELOG.md | 2 ++ age/Cargo.toml | 2 +- rage/CHANGELOG.md | 2 ++ rage/Cargo.toml | 4 ++-- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3083d51..fa0b6f3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ dependencies = [ [[package]] name = "age" -version = "0.6.0" +version = "0.6.1" dependencies = [ "aes", "aes-ctr", @@ -1614,7 +1614,7 @@ checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" [[package]] name = "rage" -version = "0.6.0" +version = "0.6.1" dependencies = [ "age", "chrono", diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index 2c22bea2..0d110873 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to Rust's notion of to 1.0.0 are beta releases. ## [Unreleased] + +## [0.6.1] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/age/Cargo.toml b/age/Cargo.toml index 07e7e783..741f886c 100644 --- a/age/Cargo.toml +++ b/age/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "age" description = "[BETA] A simple, secure, and modern encryption library." -version = "0.6.0" +version = "0.6.1" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "README.md" diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 17879dd1..5b0eba2a 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to Rust's notion of to 1.0.0 are beta releases. ## [Unreleased] + +## [0.6.1] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/rage/Cargo.toml b/rage/Cargo.toml index bcd65b94..b385cef6 100644 --- a/rage/Cargo.toml +++ b/rage/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rage" description = "[BETA] A simple, secure, and modern encryption tool." -version = "0.6.0" +version = "0.6.1" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "../README.md" @@ -43,7 +43,7 @@ maintenance = { status = "experimental" } [dependencies] # rage and rage-keygen dependencies -age = { version = "0.6.0", path = "../age", features = ["armor", "cli-common", "plugin"] } +age = { version = "0.6.1", path = "../age", features = ["armor", "cli-common", "plugin"] } chrono = "0.4" console = "0.14" env_logger = "0.8" From f70d84618b7ddf2843e7441041e09709a8ac8862 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 05:33:04 +0000 Subject: [PATCH 04/11] Apply plugin name restriction to 0.7 changes The existing code was already panicking, but this gives it a nicer error message. --- age/src/plugin.rs | 33 ++++++++++++++++++++++++--------- rage/src/bin/rage/main.rs | 13 +++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/age/src/plugin.rs b/age/src/plugin.rs index aa002a8b..8b3c26a9 100644 --- a/age/src/plugin.rs +++ b/age/src/plugin.rs @@ -139,16 +139,25 @@ impl fmt::Display for Identity { impl Identity { /// Returns the identity corresponding to the given plugin name in its default mode. + /// + /// # Panics + /// + /// Panics if `plugin_name` contains invalid characters. pub fn default_for_plugin(plugin_name: &str) -> Self { - bech32::encode( - &format!("{}{}-", PLUGIN_IDENTITY_PREFIX, plugin_name), - &[], - Variant::Bech32, - ) - .expect("HRP is valid") - .to_uppercase() - .parse() - .unwrap() + if valid_plugin_name(plugin_name) { + bech32::encode( + &format!("{}{}-", PLUGIN_IDENTITY_PREFIX, plugin_name), + &[], + Variant::Bech32, + ) + .expect("HRP is valid") + .to_uppercase() + .parse() + .unwrap() + } else { + // TODO: Change the API to be fallible. + panic!("invalid plugin name") + } } /// Returns the plugin name for this identity. @@ -559,6 +568,12 @@ mod tests { assert!(invalid_identity.parse::().is_err()); } + #[test] + #[should_panic] + fn identity_default_for_plugin_rejects_invalid_chars() { + Identity::default_for_plugin(INVALID_PLUGIN_NAME); + } + #[test] fn recipient_plugin_v1_rejects_invalid_chars() { assert!(matches!( diff --git a/rage/src/bin/rage/main.rs b/rage/src/bin/rage/main.rs index 7a2698a9..13e13f01 100644 --- a/rage/src/bin/rage/main.rs +++ b/rage/src/bin/rage/main.rs @@ -348,6 +348,13 @@ fn write_output( Ok(()) } +#[inline] +fn valid_plugin_name(plugin_name: &str) -> bool { + plugin_name + .bytes() + .all(|b| b.is_ascii_alphanumeric() | matches!(b, b'+' | b'-' | b'.' | b'_')) +} + fn decrypt(opts: AgeOptions) -> Result<(), error::DecryptError> { if opts.armor { return Err(error::DecryptError::ArmorFlag); @@ -411,6 +418,12 @@ fn decrypt(opts: AgeOptions) -> Result<(), error::DecryptError> { let identities = if opts.plugin_name.is_empty() { read_identities(opts.identity, opts.max_work_factor)? } else { + if !valid_plugin_name(&opts.plugin_name) { + return Err(age::DecryptError::MissingPlugin { + binary_name: opts.plugin_name, + } + .into()); + } // Construct the default plugin. vec![Box::new(plugin::IdentityPluginV1::new( &opts.plugin_name, From f8d0ef71542130459e8afca1e6f1b6b4551e9d5a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 05:35:48 +0000 Subject: [PATCH 05/11] v0.7.2 --- Cargo.lock | 4 ++-- age/CHANGELOG.md | 2 +- age/Cargo.toml | 2 +- rage/CHANGELOG.md | 2 +- rage/Cargo.toml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5c05af1..84f58edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,7 +45,7 @@ dependencies = [ [[package]] name = "age" -version = "0.7.1" +version = "0.7.2" dependencies = [ "aes", "age-core", @@ -1767,7 +1767,7 @@ dependencies = [ [[package]] name = "rage" -version = "0.7.1" +version = "0.7.2" dependencies = [ "age", "chrono", diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index 76ba8f5c..96a11dbe 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1] - 2024-11-18 +## [0.6.1, 0.7.2] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/age/Cargo.toml b/age/Cargo.toml index 127c40f5..88a27eac 100644 --- a/age/Cargo.toml +++ b/age/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "age" description = "[BETA] A simple, secure, and modern encryption library." -version = "0.7.1" +version = "0.7.2" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "README.md" diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 60e2a127..d0ae41ac 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1] - 2024-11-18 +## [0.6.1, 0.7.2] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/rage/Cargo.toml b/rage/Cargo.toml index 6f7cfaf4..6a9b6e28 100644 --- a/rage/Cargo.toml +++ b/rage/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rage" description = "[BETA] A simple, secure, and modern encryption tool." -version = "0.7.1" +version = "0.7.2" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "../README.md" @@ -43,7 +43,7 @@ maintenance = { status = "experimental" } [dependencies] # rage and rage-keygen dependencies -age = { version = "0.7.1", path = "../age", features = ["armor", "cli-common", "plugin"] } +age = { version = "0.7.2", path = "../age", features = ["armor", "cli-common", "plugin"] } chrono = "0.4" console = { version = "0.15", default-features = false } env_logger = "0.9" From 8673d5687e1c2045c0dd4122f2197bd1937d3404 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 06:42:27 +0000 Subject: [PATCH 06/11] v0.8.2 --- Cargo.lock | 4 ++-- age/CHANGELOG.md | 2 +- age/Cargo.toml | 2 +- rage/CHANGELOG.md | 2 +- rage/Cargo.toml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fe75d64..155f0535 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,7 +39,7 @@ dependencies = [ [[package]] name = "age" -version = "0.8.1" +version = "0.8.2" dependencies = [ "aes", "age-core", @@ -1790,7 +1790,7 @@ dependencies = [ [[package]] name = "rage" -version = "0.8.1" +version = "0.8.2" dependencies = [ "age", "chrono", diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index ed5f0f96..286a78c4 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/age/Cargo.toml b/age/Cargo.toml index f31ac73e..6d9b6d59 100644 --- a/age/Cargo.toml +++ b/age/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "age" description = "[BETA] A simple, secure, and modern encryption library." -version = "0.8.1" +version = "0.8.2" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "README.md" diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 8676d95c..b9512a5c 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/rage/Cargo.toml b/rage/Cargo.toml index 103a292d..a22d83bc 100644 --- a/rage/Cargo.toml +++ b/rage/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rage" description = "[BETA] A simple, secure, and modern encryption tool." -version = "0.8.1" +version = "0.8.2" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "../README.md" @@ -53,7 +53,7 @@ maintenance = { status = "experimental" } [dependencies] # rage and rage-keygen dependencies -age = { version = "0.8.1", path = "../age", features = ["armor", "cli-common", "plugin"] } +age = { version = "0.8.2", path = "../age", features = ["armor", "cli-common", "plugin"] } chrono = "0.4" console = { version = "0.15", default-features = false } env_logger = "0.9" From 2b501beff2bb8f890dfff08dc14c35d12c9907b2 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 06:46:08 +0000 Subject: [PATCH 07/11] v0.9.3 --- Cargo.lock | 4 ++-- age/CHANGELOG.md | 2 +- age/Cargo.toml | 2 +- rage/CHANGELOG.md | 2 +- rage/Cargo.toml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f760612..30229cac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,7 +54,7 @@ dependencies = [ [[package]] name = "age" -version = "0.9.2" +version = "0.9.3" dependencies = [ "aes", "aes-gcm", @@ -1958,7 +1958,7 @@ dependencies = [ [[package]] name = "rage" -version = "0.9.2" +version = "0.9.3" dependencies = [ "age", "chrono", diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index f4f18403..51a3077a 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2, 0.8.2] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2, 0.9.3] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/age/Cargo.toml b/age/Cargo.toml index 63ec0a5f..e20fa97c 100644 --- a/age/Cargo.toml +++ b/age/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "age" description = "[BETA] A simple, secure, and modern encryption library." -version = "0.9.2" +version = "0.9.3" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "README.md" diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 1686670f..afedde83 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2, 0.8.2] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2, 0.9.3] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/rage/Cargo.toml b/rage/Cargo.toml index 38a8f41f..42ffd847 100644 --- a/rage/Cargo.toml +++ b/rage/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rage" description = "[BETA] A simple, secure, and modern encryption tool." -version = "0.9.2" +version = "0.9.3" authors = ["Jack Grigg "] repository = "https://github.com/str4d/rage" readme = "../README.md" @@ -54,7 +54,7 @@ maintenance = { status = "experimental" } [dependencies] # rage and rage-keygen dependencies -age = { version = "0.9.2", path = "../age", features = ["armor", "cli-common", "plugin"] } +age = { version = "0.9.3", path = "../age", features = ["armor", "cli-common", "plugin"] } chrono = "0.4" console = { version = "0.15", default-features = false } env_logger = "0.9" From 62f15b9d9d36a6045e7bb5f6549d4b56da919c32 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 06:56:17 +0000 Subject: [PATCH 08/11] v0.10.1 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- age/CHANGELOG.md | 2 +- age/Cargo.toml | 2 +- rage/CHANGELOG.md | 2 +- rage/Cargo.toml | 2 +- rage/tests/cmd/rage-keygen/version.toml | 2 +- rage/tests/cmd/rage-mount/version.toml | 2 +- rage/tests/cmd/rage/version.toml | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a773cbee..09a06e14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,7 +54,7 @@ dependencies = [ [[package]] name = "age" -version = "0.10.0" +version = "0.10.1" dependencies = [ "aes", "aes-gcm", @@ -2002,7 +2002,7 @@ dependencies = [ [[package]] name = "rage" -version = "0.10.0" +version = "0.10.1" dependencies = [ "age", "chrono", diff --git a/Cargo.toml b/Cargo.toml index dafdd9be..c086a942 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ repository = "https://github.com/str4d/rage" license = "MIT OR Apache-2.0" [workspace.dependencies] -age = { version = "0.10.0", path = "age" } +age = { version = "0.10.1", path = "age" } age-core = { version = "0.10.0", path = "age-core" } # Dependencies required by the age specification: diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index 2267301f..95dda569 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2, 0.8.2, 0.9.3] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/age/Cargo.toml b/age/Cargo.toml index d2ef80a1..d407c62d 100644 --- a/age/Cargo.toml +++ b/age/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "age" description = "[BETA] A simple, secure, and modern encryption library." -version = "0.10.0" +version = "0.10.1" authors.workspace = true repository.workspace = true readme = "README.md" diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 8ff404bd..6a0a52c4 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2, 0.8.2, 0.9.3] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/rage/Cargo.toml b/rage/Cargo.toml index 865cc432..26a22256 100644 --- a/rage/Cargo.toml +++ b/rage/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rage" description = "[BETA] A simple, secure, and modern encryption tool." -version = "0.10.0" +version = "0.10.1" authors.workspace = true repository.workspace = true readme = "../README.md" diff --git a/rage/tests/cmd/rage-keygen/version.toml b/rage/tests/cmd/rage-keygen/version.toml index e7ab5888..a4c0f2cc 100644 --- a/rage/tests/cmd/rage-keygen/version.toml +++ b/rage/tests/cmd/rage-keygen/version.toml @@ -1,6 +1,6 @@ bin.name = "rage-keygen" args = "--version" stdout = """ -rage-keygen 0.10.0 +rage-keygen 0.10.1 """ stderr = "" diff --git a/rage/tests/cmd/rage-mount/version.toml b/rage/tests/cmd/rage-mount/version.toml index 283726f3..5776658f 100644 --- a/rage/tests/cmd/rage-mount/version.toml +++ b/rage/tests/cmd/rage-mount/version.toml @@ -1,6 +1,6 @@ bin.name = "rage-mount" args = "--version" stdout = """ -rage-mount 0.10.0 +rage-mount 0.10.1 """ stderr = "" diff --git a/rage/tests/cmd/rage/version.toml b/rage/tests/cmd/rage/version.toml index 2d3ac3b9..6fb3e4e9 100644 --- a/rage/tests/cmd/rage/version.toml +++ b/rage/tests/cmd/rage/version.toml @@ -1,6 +1,6 @@ bin.name = "rage" args = "--version" stdout = """ -rage 0.10.0 +rage 0.10.1 """ stderr = "" From 383b6f52aa91d48720422b8049bcfc2a4aefbb31 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 07:06:16 +0000 Subject: [PATCH 09/11] Replace the test `NoCallbacks` with the library version --- age/src/plugin.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/age/src/plugin.rs b/age/src/plugin.rs index 98f11d13..f38ec0cf 100644 --- a/age/src/plugin.rs +++ b/age/src/plugin.rs @@ -736,7 +736,7 @@ impl crate::Identity for IdentityPluginV1 { #[cfg(test)] mod tests { - use crate::{Callbacks, DecryptError, EncryptError}; + use crate::{DecryptError, EncryptError, NoCallbacks}; use super::{ Identity, IdentityPluginV1, Recipient, RecipientPluginV1, PLUGIN_IDENTITY_PREFIX, @@ -745,21 +745,6 @@ mod tests { const INVALID_PLUGIN_NAME: &str = "foobar/../../../../../../../usr/bin/echo"; - #[derive(Clone)] - struct NoCallbacks; - impl Callbacks for NoCallbacks { - fn display_message(&self, _: &str) {} - fn confirm(&self, _: &str, _: &str, _: Option<&str>) -> Option { - None - } - fn request_public_string(&self, _: &str) -> Option { - None - } - fn request_passphrase(&self, _: &str) -> Option { - None - } - } - #[test] fn default_for_plugin() { assert_eq!( From a82a76a8491afd17f53c1ce6ca3716667e61a536 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 18 Nov 2024 07:11:33 +0000 Subject: [PATCH 10/11] v0.11.1 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- age/CHANGELOG.md | 2 +- age/Cargo.toml | 2 +- rage/CHANGELOG.md | 2 +- rage/Cargo.toml | 2 +- rage/tests/cmd/rage-keygen/version.toml | 2 +- rage/tests/cmd/rage-mount/version.toml | 2 +- rage/tests/cmd/rage/version.toml | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ae0af05..72e96679 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,7 +60,7 @@ dependencies = [ [[package]] name = "age" -version = "0.11.0" +version = "0.11.1" dependencies = [ "aes", "aes-gcm", @@ -2042,7 +2042,7 @@ dependencies = [ [[package]] name = "rage" -version = "0.11.0" +version = "0.11.1" dependencies = [ "age", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 40b27a58..8468db45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ repository = "https://github.com/str4d/rage" license = "MIT OR Apache-2.0" [workspace.dependencies] -age = { version = "0.11.0", path = "age" } +age = { version = "0.11.1", path = "age" } age-core = { version = "0.11.0", path = "age-core" } # Dependencies required by the age specification: diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index a1a82c8c..e33ddfd7 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1, 0.11.1] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/age/Cargo.toml b/age/Cargo.toml index 720270c1..11510461 100644 --- a/age/Cargo.toml +++ b/age/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "age" description = "[BETA] A simple, secure, and modern encryption library." -version = "0.11.0" +version = "0.11.1" authors.workspace = true repository.workspace = true readme = "README.md" diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 6653d5cc..ab8d47f9 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -10,7 +10,7 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1, 0.11.1] - 2024-11-18 ### Security - The age plugin protocol previously allowed plugin names that could be interpreted as file paths. Under certain conditions, this could lead to a diff --git a/rage/Cargo.toml b/rage/Cargo.toml index 799c03f4..a472f7fc 100644 --- a/rage/Cargo.toml +++ b/rage/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rage" description = "[BETA] A simple, secure, and modern encryption tool." -version = "0.11.0" +version = "0.11.1" authors.workspace = true repository.workspace = true readme = "../README.md" diff --git a/rage/tests/cmd/rage-keygen/version.toml b/rage/tests/cmd/rage-keygen/version.toml index d3dad014..592c1fbe 100644 --- a/rage/tests/cmd/rage-keygen/version.toml +++ b/rage/tests/cmd/rage-keygen/version.toml @@ -1,6 +1,6 @@ bin.name = "rage-keygen" args = "--version" stdout = """ -rage-keygen 0.11.0 +rage-keygen 0.11.1 """ stderr = "" diff --git a/rage/tests/cmd/rage-mount/version.toml b/rage/tests/cmd/rage-mount/version.toml index 0117dd44..e30e8af4 100644 --- a/rage/tests/cmd/rage-mount/version.toml +++ b/rage/tests/cmd/rage-mount/version.toml @@ -1,6 +1,6 @@ bin.name = "rage-mount" args = "--version" stdout = """ -rage-mount 0.11.0 +rage-mount 0.11.1 """ stderr = "" diff --git a/rage/tests/cmd/rage/version.toml b/rage/tests/cmd/rage/version.toml index 3443bd2d..1f92da80 100644 --- a/rage/tests/cmd/rage/version.toml +++ b/rage/tests/cmd/rage/version.toml @@ -1,6 +1,6 @@ bin.name = "rage" args = "--version" stdout = """ -rage 0.11.0 +rage 0.11.1 """ stderr = "" From 07808823074013acab5417de9d6ad176133312c6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 18 Dec 2024 15:17:33 +0000 Subject: [PATCH 11/11] Update changelog with GHSA for security vulnerability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to ⬡-49016 for reporting this issue. --- age/CHANGELOG.md | 9 ++++----- rage/CHANGELOG.md | 11 +++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index e33ddfd7..eb79b409 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -12,11 +12,10 @@ to 1.0.0 are beta releases. ## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1, 0.11.1] - 2024-11-18 ### Security -- The age plugin protocol previously allowed plugin names that could be - interpreted as file paths. Under certain conditions, this could lead to a - different binary being executed as an age plugin than intended. Plugin names - are now required to only contain alphanumeric characters or the four special - characters `+-._`. +- Fixed a security vulnerability that could allow an attacker to execute an + arbitrary binary under certain conditions. See GHSA-4fg7-vxc8-qx5w. Plugin + names are now required to only contain alphanumeric characters or the four + special characters `+-._`. Thanks to ⬡-49016 for reporting this issue. ## [0.11.0] - 2024-11-03 ### Added diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index ab8d47f9..a56681c1 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -10,13 +10,12 @@ to 1.0.0 are beta releases. ## [Unreleased] -## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1, 0.11.1] - 2024-11-18 +## [0.6.1, 0.7.2, 0.8.2, 0.9.3, 0.10.1, 0.11.1] - 2024-12-18 ### Security -- The age plugin protocol previously allowed plugin names that could be - interpreted as file paths. Under certain conditions, this could lead to a - different binary being executed as an age plugin than intended. Plugin names - are now required to only contain alphanumeric characters or the four special - characters `+-._`. +- Fixed a security vulnerability that could allow an attacker to execute an + arbitrary binary under certain conditions. See GHSA-4fg7-vxc8-qx5w. Plugin + names are now required to only contain alphanumeric characters or the four + special characters `+-._`. Thanks to ⬡-49016 for reporting this issue. ## [0.11.0] - 2024-11-03 ### Added