use data_encoding::HEXUPPER;
use ring::digest::{Context, SHA256};
use crate::claims::{Claims, Token};
use crate::parser::ParsedModule;
use crate::{Error, WickComponent};
pub(crate) const SECTION_NAME: &str = "jwt";
#[derive(Debug, Default, Clone)]
pub struct ClaimsOptions {
pub revision: Option<u32>,
pub version: Option<String>,
pub expires_in_days: Option<u64>,
pub not_before_days: Option<u64>,
}
pub(crate) fn decode(bytes: &[u8]) -> Result<Token<WickComponent>, Error> {
let jwt = std::str::from_utf8(bytes)?;
let claims: Claims<WickComponent> = Claims::decode(jwt)?;
Ok(Token {
jwt: jwt.to_owned(),
claims,
})
}
pub(crate) fn hash(module: &ParsedModule, filter: &[&str]) -> Result<String, Error> {
let mut context = Context::new(&SHA256);
for payload in &module.1 {
use wasmparser::Payload::*;
let section = payload.as_section();
match payload {
Version { encoding, .. } => {
context.update(match encoding {
wasmparser::Encoding::Module => &wasm_encoder::Module::HEADER,
wasmparser::Encoding::Component => todo!(),
});
}
CustomSection(c) if (filter.contains(&c.name())) => {
}
_ => {
if let Some((id, range)) = section {
context.update(&id.to_le_bytes());
context.update(&encode_old_u32(range.size_hint().0 as _));
context.update(&module.0[range]);
}
}
}
}
Ok(HEXUPPER.encode(context.finish().as_ref()))
}
const MAX_U32_LENGTH: usize = 5;
fn encode_old_u32(mut amt: u32) -> Vec<u8> {
let mut bytes = Vec::new();
#[allow(clippy::needless_range_loop)]
for i in 0..MAX_U32_LENGTH {
let flag = if i == MAX_U32_LENGTH - 1 { 0 } else { 0x80 };
bytes.push((amt as u8) & 0x7f | flag);
amt >>= 7;
}
bytes
}
#[cfg(test)]
mod test {
use anyhow::Result;
use super::*;
use crate::parser::ParsedModule;
#[rstest::rstest]
#[case(
"./test/1.v0.signed.wasm",
"D3DFCF7F12B01A22025B2341871A46B5A4EE71387B32EE857EDBE69F2D1E1299"
)]
#[case(
"./test/2.v0.signed.wasm",
"2535F3568A2E0798AA376A6F836A65C81F1A258156F9E98E94B33A0E42EFC2C2"
)]
#[case(
"./test/3.v0.signed.wasm",
"8CF411C08AEEF40150E70E0210A4C5A67559871FDB43351664A42DC6F94B8DC5"
)]
#[case(
"./test/4.v0.signed.wasm",
"7E215B19354779A37A5C01740D8D129536C38E1A2659A916F440418129924A11"
)]
fn test_signature(#[case] file: &str, #[case] expected_hash: &str) -> Result<()> {
let bytes = std::fs::read(file)?;
let module = ParsedModule::new(&bytes)?;
let hash = hash(&module, &[SECTION_NAME])?;
assert_eq!(hash, expected_hash);
Ok(())
}
}