Skip to content

Commit 7b95cee

Browse files
committed
omaha: bring back base64 decoding functionality
Since we need to support decoding of both hex and base64 formats, bring back base64 decoding functionality. Note, while hash_sha256 of Package has hex format, sha256 of Action has base64 format. That is the reason why we need to keep both mod sha256_from_hex_str and mod sha256_from_base64_str. Signed-off-by: Dongsu Park <[email protected]>
1 parent bdb0bba commit 7b95cee

File tree

5 files changed

+93
-19
lines changed

5 files changed

+93
-19
lines changed

Cargo.lock

Lines changed: 14 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

omaha/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ uuid = "1.2"
1010
url = "2"
1111
sha2 = "0.10.8"
1212
sha1 = "0.10.6"
13+
ct-codecs = "1.1.6"
1314

1415
[dependencies.hard-xml]
1516
path = "../vendor/hard-xml"

omaha/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::num::ParseIntError;
44
#[derive(Debug)]
55
pub enum Error {
66
TryFromHex(ParseIntError),
7+
TryFromBase64(ct_codecs::Error),
78
InvalidDigestLength {
89
expected: usize,
910
actual: usize,
@@ -19,6 +20,7 @@ impl Display for Error {
1920
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2021
match self {
2122
Error::TryFromHex(err) => write!(fmt, "failed to convert from hex: {err}"),
23+
Error::TryFromBase64(err) => write!(fmt, "failed to convert from base64: {err}"),
2224
Error::InvalidDigestLength {
2325
expected,
2426
actual,

omaha/src/hash_types.rs

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::str;
2+
use ct_codecs::{Base64, Decoder};
23

34
use sha2::Digest;
45

@@ -42,8 +43,12 @@ pub trait Hasher {
4243
fn finalize(self) -> Self::Output;
4344

4445
/// Construct a hash of the output format of the associated hashing
45-
/// algorithm using a provided string.
46+
/// algorithm using a provided hex string.
4647
fn try_from_hex_string(s: &str) -> Result<Self::Output>;
48+
49+
/// Construct a hash of the output format of the associated hashing
50+
/// algorithm using a provided base64 string.
51+
fn try_from_base64_string(s: &str) -> Result<Self::Output>;
4752
}
4853

4954
impl Hasher for Sha1 {
@@ -67,15 +72,19 @@ impl Hasher for Sha1 {
6772
fn try_from_hex_string(s: &str) -> Result<Self::Output> {
6873
try_from_hex_string::<Self>(s)
6974
}
75+
76+
fn try_from_base64_string(s: &str) -> Result<Self::Output> {
77+
try_from_base64_string::<Self>(s)
78+
}
7079
}
7180

72-
pub(crate) mod sha1_from_str {
81+
pub(crate) mod sha1_from_base64_str {
7382
use crate::{Hasher, Sha1, Sha1Digest};
7483
use crate::Result;
7584

7685
#[inline]
7786
pub(crate) fn from_str(s: &str) -> Result<Sha1Digest> {
78-
<Sha1 as Hasher>::try_from_hex_string(s)
87+
<Sha1 as Hasher>::try_from_base64_string(s)
7988
}
8089
}
8190

@@ -96,12 +105,17 @@ impl Hasher for Sha256 {
96105
fn finalize(self) -> Self::Output {
97106
self.0.finalize().into()
98107
}
108+
99109
fn try_from_hex_string(s: &str) -> Result<Self::Output> {
100110
try_from_hex_string::<Self>(s)
101111
}
112+
113+
fn try_from_base64_string(s: &str) -> Result<Self::Output> {
114+
try_from_base64_string::<Self>(s)
115+
}
102116
}
103117

104-
pub(crate) mod sha256_from_str {
118+
pub(crate) mod sha256_from_hex_str {
105119
use crate::{Hasher, Sha256, Sha256Digest};
106120
use crate::Result;
107121

@@ -111,6 +125,16 @@ pub(crate) mod sha256_from_str {
111125
}
112126
}
113127

128+
pub(crate) mod sha256_from_base64_str {
129+
use crate::{Hasher, Sha256, Sha256Digest};
130+
use crate::Result;
131+
132+
#[inline]
133+
pub(crate) fn from_str(s: &str) -> Result<Sha256Digest> {
134+
<Sha256 as Hasher>::try_from_base64_string(s)
135+
}
136+
}
137+
114138
/// Parse a hexadecimal string into the output of the generically typed hashing
115139
/// algorithm.
116140
fn try_from_hex_string<T: Hasher>(s: &str) -> Result<T::Output> {
@@ -136,10 +160,29 @@ fn try_from_hex_string<T: Hasher>(s: &str) -> Result<T::Output> {
136160
}
137161
}
138162

163+
/// Parse a base64 string into the output of the generically typed hashing
164+
/// algorithm.
165+
fn try_from_base64_string<T: Hasher>(s: &str) -> Result<T::Output> {
166+
let mut bytes = vec![0; s.len()];
167+
168+
let bytes = Base64::decode(bytes.as_mut(), s, None).map_err(Error::TryFromBase64)?;
169+
170+
if bytes.len() == T::FINGERPRINT_SIZE {
171+
let mut digest = T::Output::default();
172+
digest.as_mut().copy_from_slice(bytes);
173+
Ok(digest)
174+
} else {
175+
Err(Error::InvalidDigestLength {
176+
expected: T::FINGERPRINT_SIZE,
177+
actual: bytes.len(),
178+
})
179+
}
180+
}
181+
139182
#[cfg(test)]
140183
mod tests {
141184
use crate::Hasher;
142-
use super::{Sha256, Sha1, try_from_hex_string};
185+
use super::{Sha256, Sha1, try_from_hex_string, try_from_base64_string};
143186
use sha1::Digest;
144187

145188
const TEST_DATA: &[u8] = b"test string";
@@ -197,4 +240,25 @@ mod tests {
197240
assert!(sha256_digest.is_ok());
198241
assert_eq!(sha256_digest.unwrap(), exp_bytes);
199242
}
243+
244+
#[test]
245+
fn try_from_base64_string_sha1() {
246+
let base64_string = "FF+ci4cThKAdESIk5GbSgrN0Q7A=";
247+
let exp_bytes = [20, 95, 156, 139, 135, 19, 132, 160, 29, 17, 34, 36, 228, 102, 210, 130, 179, 116, 67, 176];
248+
let sha1_digest = try_from_base64_string::<Sha1>(base64_string);
249+
250+
assert!(sha1_digest.is_ok());
251+
assert_eq!(sha1_digest.unwrap(), exp_bytes);
252+
}
253+
254+
#[test]
255+
fn try_from_base64_string_sha256() {
256+
let base64_string = "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=";
257+
258+
let exp_bytes = [44, 242, 77, 186, 95, 176, 163, 14, 38, 232, 59, 42, 197, 185, 226, 158, 27, 22, 30, 92, 31, 167, 66, 94, 115, 4, 51, 98, 147, 139, 152, 36];
259+
let sha256_digest = try_from_base64_string::<Sha256>(base64_string);
260+
261+
assert!(sha256_digest.is_ok());
262+
assert_eq!(sha256_digest.unwrap(), &exp_bytes[..]);
263+
}
200264
}

omaha/src/response.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use url::Url;
88

99
use crate::Error::{UnknownActionEvent, UnknownSuccessAction};
1010
use crate::uuid::braced_uuid;
11-
use crate::{Sha1Digest, Sha256Digest, Error, sha1_from_str, sha256_from_str};
11+
use crate::{Sha1Digest, Sha256Digest, Error, sha1_from_base64_str, sha256_from_base64_str, sha256_from_hex_str};
1212

1313
#[derive(XmlRead, Debug)]
1414
#[xml(tag = "response")]
@@ -150,7 +150,7 @@ pub struct Package<'a> {
150150
#[xml(attr = "name")]
151151
pub name: Cow<'a, str>,
152152

153-
#[xml(attr = "hash", with = "sha1_from_str")]
153+
#[xml(attr = "hash", with = "sha1_from_base64_str")]
154154
pub hash: Option<Sha1Digest>,
155155

156156
#[xml(attr = "size")]
@@ -159,7 +159,7 @@ pub struct Package<'a> {
159159
#[xml(attr = "required")]
160160
pub required: bool,
161161

162-
#[xml(attr = "hash_sha256", with = "sha256_from_str")]
162+
#[xml(attr = "hash_sha256", with = "sha256_from_hex_str")]
163163
pub hash_sha256: Option<Sha256Digest>,
164164
}
165165

@@ -178,7 +178,7 @@ pub struct Action {
178178
#[xml(attr = "event")]
179179
pub event: ActionEvent,
180180

181-
#[xml(attr = "sha256", with = "sha256_from_str")]
181+
#[xml(attr = "sha256", with = "sha256_from_base64_str")]
182182
pub sha256: Sha256Digest,
183183

184184
#[xml(attr = "DisablePayloadBackoff")]
@@ -333,16 +333,16 @@ mod tests {
333333
#[test]
334334
fn package_xml_read_hashes() {
335335
const NAME: &str = "name";
336-
const SHA1_STR: &str = "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d";
336+
const BASE64_STR: &str = "FF+ci4cThKAdESIk5GbSgrN0Q7A=";
337337
const SIZE: usize = 1;
338338
const REQUIRED: bool = false;
339339
const SHA256_STR: &str = "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824";
340340

341341
test_xml_read(
342-
format!("<package name=\"{NAME}\" hash=\"{SHA1_STR}\" size=\"{SIZE}\" required=\"{REQUIRED}\" hash_sha256=\"{SHA256_STR}\"/>",).as_str(),
342+
format!("<package name=\"{NAME}\" hash=\"{BASE64_STR}\" size=\"{SIZE}\" required=\"{REQUIRED}\" hash_sha256=\"{SHA256_STR}\"/>",).as_str(),
343343
Package {
344344
name: Cow::Borrowed(NAME),
345-
hash: Some(Sha1::try_from_hex_string(SHA1_STR).unwrap()),
345+
hash: Some(Sha1::try_from_base64_string(BASE64_STR).unwrap()),
346346
size: SIZE,
347347
required: REQUIRED,
348348
hash_sha256: Some(Sha256::try_from_hex_string(SHA256_STR).unwrap()),

0 commit comments

Comments
 (0)