From 4fbd82ec94217f472df21fedcfa6ee1ec09f092a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 2 Jan 2021 23:02:00 +0000 Subject: [PATCH 1/4] age: Re-enable age test vectors on Windows --- age/tests/test_vectors.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/age/tests/test_vectors.rs b/age/tests/test_vectors.rs index 1b40539c..de93838f 100644 --- a/age/tests/test_vectors.rs +++ b/age/tests/test_vectors.rs @@ -2,7 +2,6 @@ use secrecy::SecretString; use std::fs; use std::io::{self, Read}; -#[cfg(unix)] #[test] fn age_test_vectors() -> Result<(), age::DecryptError> { for test_vector in fs::read_dir("./tests/testdata")?.filter(|res| { From e18e58ea53a4a1400960c9fd9caf471bad7b787d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Jan 2021 02:08:08 +0000 Subject: [PATCH 2/4] age: Add filename and line number to identity file parsing error --- age/src/identity.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/age/src/identity.rs b/age/src/identity.rs index 61e00bab..206bd277 100644 --- a/age/src/identity.rs +++ b/age/src/identity.rs @@ -16,19 +16,23 @@ pub struct IdentityFile { impl IdentityFile { /// Parses one or more identities from a file containing valid UTF-8. pub fn from_file(filename: String) -> io::Result { - File::open(filename) + File::open(&filename) .map(io::BufReader::new) - .and_then(IdentityFile::from_buffer) + .and_then(|data| IdentityFile::parse_identities(Some(filename), data)) } /// Parses one or more identities from a buffered input containing valid UTF-8. pub fn from_buffer(data: R) -> io::Result { + Self::parse_identities(None, data) + } + + fn parse_identities(filename: Option, data: R) -> io::Result { let mut identities = vec![]; #[cfg(feature = "plugin")] let mut plugin_identities = vec![]; - for line in data.lines() { + for (line_number, line) in data.lines().enumerate() { let line = line?; if line.is_empty() || line.starts_with('#') { continue; @@ -54,9 +58,22 @@ impl IdentityFile { #[cfg(not(feature = "plugin"))] let _: () = identity; } else { + // Return a line number in place of the line, so we don't leak the file + // contents in error messages. return Err(io::Error::new( io::ErrorKind::InvalidData, - "invalid identity file", + if let Some(filename) = filename { + format!( + "identity file {} contains non-identity data on line {}", + filename, + line_number + 1 + ) + } else { + format!( + "identity file contains non-identity data on line {}", + line_number + 1 + ) + }, )); } } From 484c0ae732951bcae82d5e092f9161b097d9376c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Jan 2021 02:28:01 +0000 Subject: [PATCH 3/4] age: Require ssh feature for test_vectors test --- age/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/age/Cargo.toml b/age/Cargo.toml index c2e06896..f30e3ddc 100644 --- a/age/Cargo.toml +++ b/age/Cargo.toml @@ -112,6 +112,10 @@ unstable = ["age-core/unstable"] [lib] bench = false +[[test]] +name = "test_vectors" +required-features = ["ssh"] + [[bench]] name = "throughput" harness = false From 3d2c9489d25ba3010f4238e8f01effcd53056fc2 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Jan 2021 02:50:30 +0000 Subject: [PATCH 4/4] age: Allow either kind of line ending in SSH identities --- age/CHANGELOG.md | 4 ++++ age/src/ssh/identity.rs | 12 ++++++------ age/src/util.rs | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/age/CHANGELOG.md b/age/CHANGELOG.md index ccad342d..970b1da4 100644 --- a/age/CHANGELOG.md +++ b/age/CHANGELOG.md @@ -27,6 +27,10 @@ to 1.0.0 are beta releases. (instead of wrapping `std::io::File` directly), which does not open the file until it is first written to. +### Fixed +- `age::cli_common::read_identities` now allows either kind of line ending in + SSH identity files. + ## [0.5.0] - 2020-11-22 ### Added - Italian, Spanish, and Chinese translations! diff --git a/age/src/ssh/identity.rs b/age/src/ssh/identity.rs index 0c97e7b2..36b0aa8f 100644 --- a/age/src/ssh/identity.rs +++ b/age/src/ssh/identity.rs @@ -6,7 +6,7 @@ use i18n_embed_fl::fl; use nom::{ branch::alt, bytes::streaming::{is_not, tag}, - character::streaming::newline, + character::streaming::{line_ending, newline}, combinator::{map_opt, opt}, sequence::{pair, preceded, terminated, tuple}, IResult, @@ -299,11 +299,11 @@ fn rsa_pem_encryption_header(input: &str) -> IResult<&str, &str> { fn rsa_privkey(input: &str) -> IResult<&str, Identity> { preceded( - pair(tag("-----BEGIN RSA PRIVATE KEY-----"), newline), + pair(tag("-----BEGIN RSA PRIVATE KEY-----"), line_ending), terminated( map_opt( pair( - opt(terminated(rsa_pem_encryption_header, newline)), + opt(terminated(rsa_pem_encryption_header, line_ending)), wrapped_str_while_encoded(base64::STANDARD), ), |(enc_header, privkey)| { @@ -322,19 +322,19 @@ fn rsa_privkey(input: &str) -> IResult<&str, Identity> { } }, ), - pair(newline, tag("-----END RSA PRIVATE KEY-----")), + pair(line_ending, tag("-----END RSA PRIVATE KEY-----")), ), )(input) } fn openssh_privkey(input: &str) -> IResult<&str, Identity> { preceded( - pair(tag("-----BEGIN OPENSSH PRIVATE KEY-----"), newline), + pair(tag("-----BEGIN OPENSSH PRIVATE KEY-----"), line_ending), terminated( map_opt(wrapped_str_while_encoded(base64::STANDARD), |privkey| { read_ssh::openssh_privkey(&privkey).ok().map(|(_, key)| key) }), - pair(newline, tag("-----END OPENSSH PRIVATE KEY-----")), + pair(line_ending, tag("-----END OPENSSH PRIVATE KEY-----")), ), )(input) } diff --git a/age/src/util.rs b/age/src/util.rs index 0a7c2ad4..84fb9860 100644 --- a/age/src/util.rs +++ b/age/src/util.rs @@ -70,12 +70,12 @@ pub(crate) mod read { pub(crate) fn wrapped_str_while_encoded( config: base64::Config, ) -> impl Fn(&str) -> IResult<&str, Vec> { - use nom::{bytes::streaming::take_while1, character::streaming::newline}; + use nom::{bytes::streaming::take_while1, character::streaming::line_ending}; move |input: &str| { map_res( separated_nonempty_list( - newline, + line_ending, take_while1(|c| { let c = c as u8; // Substitute the character in twice after AA, so that padding