From 6536ca0f61b329670a6c1b4cbaa5965f7659f849 Mon Sep 17 00:00:00 2001 From: Arturo Marquez Date: Tue, 21 Jun 2022 20:02:33 -0500 Subject: [PATCH] Replace `base64` crate with `base64ct` crate Note: the `base64ct` crate rejects invalid characters when the decoding is done on padded strings. However, the `FromStr` impl for `B64` can have both padded **and** unpadded inputs, so all inputs are now padded first, before decoding. --- Cargo.lock | 9 +++++---- crates/tor-netdoc/Cargo.toml | 1 + crates/tor-netdoc/src/parse/tokenize.rs | 6 +++--- crates/tor-netdoc/src/types/misc.rs | 25 +++++++++++++++++++++---- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index feaad683b..b858a8f63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -510,9 +510,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "base64ct" -version = "1.1.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" +checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" [[package]] name = "bitflags" @@ -2288,9 +2288,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e93a3b1cc0510b03020f33f21e62acdde3dcaef432edc95bea377fbd4c2cd4" +checksum = "8f22eb0e3c593294a99e9ff4b24cf6b752d43f193aa4415fe5077c159996d497" dependencies = [ "base64ct", ] @@ -3821,6 +3821,7 @@ name = "tor-netdoc" version = "0.4.0" dependencies = [ "base64", + "base64ct", "bitflags", "derive_more", "digest 0.10.3", diff --git a/crates/tor-netdoc/Cargo.toml b/crates/tor-netdoc/Cargo.toml index 94a681de5..ac9fa3b8f 100644 --- a/crates/tor-netdoc/Cargo.toml +++ b/crates/tor-netdoc/Cargo.toml @@ -46,6 +46,7 @@ dangerous-expose-struct-fields = ["visible", "visibility"] [dependencies] base64 = "0.13.0" +base64ct = { version = "1.5.0", features = ["alloc"] } bitflags = "1" derive_more = "0.99" digest = "0.10.0" diff --git a/crates/tor-netdoc/src/parse/tokenize.rs b/crates/tor-netdoc/src/parse/tokenize.rs index 3b0a5abdb..43cc83bb7 100644 --- a/crates/tor-netdoc/src/parse/tokenize.rs +++ b/crates/tor-netdoc/src/parse/tokenize.rs @@ -8,6 +8,7 @@ use crate::parse::keyword::Keyword; use crate::types::misc::FromBytes; use crate::util::PauseAt; use crate::{Error, ParseErrorKind as EK, Pos, Result}; +use base64ct::{Base64, Encoding}; use std::cell::{Ref, RefCell}; use std::str::FromStr; use tor_error::internal; @@ -290,12 +291,11 @@ impl<'a, K: Keyword> Iterator for NetDocReaderBase<'a, K> { /// Helper: as base64::decode(), but allows newlines in the middle of the /// encoded object. -fn base64_decode_multiline(s: &str) -> std::result::Result, base64::DecodeError> { +fn base64_decode_multiline(s: &str) -> std::result::Result, base64ct::Error> { // base64 module hates whitespace. - let mut v = Vec::new(); let mut s = s.to_string(); s.retain(|ch| ch != '\n'); - base64::decode_config_buf(s, base64::STANDARD, &mut v)?; + let v = Base64::decode_vec(&s)?; Ok(v) } diff --git a/crates/tor-netdoc/src/types/misc.rs b/crates/tor-netdoc/src/types/misc.rs index 49147a9b2..be6001305 100644 --- a/crates/tor-netdoc/src/types/misc.rs +++ b/crates/tor-netdoc/src/types/misc.rs @@ -36,6 +36,7 @@ pub(crate) trait FromBytes: Sized { /// Types for decoding base64-encoded values. mod b64impl { use crate::{Error, ParseErrorKind as EK, Pos, Result}; + use base64ct::{Base64, Encoding}; use std::ops::RangeBounds; /// A byte array, encoded in base64 with optional padding. @@ -44,12 +45,26 @@ mod b64impl { impl std::str::FromStr for B64 { type Err = Error; fn from_str(s: &str) -> Result { - let bytes = base64::decode_config(s, base64::STANDARD_NO_PAD).map_err(|_| { + // The `base64ct` crate only rejects invalid + // characters when the input is padded. Therefore, + // the input must be padded fist. + let mut string = s.to_string(); + // Determine padding length + let offset = 4 - s.len() % 4; + match offset { + 4 => (), + _ => { + // Add pad to input + string.push_str("=".repeat(offset).as_str()); + } + } + let v = Base64::decode_vec(&string); + let v = v.map_err(|_| { EK::BadArgument .with_msg("Invalid base64") .at_pos(Pos::at(s)) })?; - Ok(B64(bytes)) + Ok(B64(v)) } } @@ -455,14 +470,16 @@ mod nickname { #[cfg(test)] mod test { #![allow(clippy::unwrap_used)] + use base64ct::Encoding; + use super::*; use crate::{Pos, Result}; /// Decode s as a multi-line base64 string, ignoring ascii whitespace. - fn base64_decode_ignore_ws(s: &str) -> std::result::Result, base64::DecodeError> { + fn base64_decode_ignore_ws(s: &str) -> std::result::Result, base64ct::Error> { let mut s = s.to_string(); s.retain(|c| !c.is_ascii_whitespace()); - base64::decode(s) + base64ct::Base64::decode_vec(s.as_str()) } #[test]