use crate::error::*;
use crate::signature::sig_sections::{SignatureData, SIGNATURE_SECTION_HEADER_NAME};
use crate::wasm_module::{Module, Section};
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;
#[derive(Debug, Clone)]
pub struct SignatureInfo {
key_ids: Vec<Vec<u8>>,
signature_count: usize,
pub specification_version: u8,
pub content_type: u8,
pub hash_function: u8,
}
impl SignatureInfo {
fn from_signature_data(data: &SignatureData) -> Self {
let mut key_ids = Vec::new();
let mut signature_count = 0;
for signed_hashes in &data.signed_hashes_set {
for sig in &signed_hashes.signatures {
if let Some(key_id) = &sig.key_id {
key_ids.push(key_id.clone());
}
signature_count += 1;
}
}
SignatureInfo {
key_ids,
signature_count,
specification_version: data.specification_version,
content_type: data.content_type,
hash_function: data.hash_function,
}
}
pub fn key_ids(&self) -> &[Vec<u8>] {
&self.key_ids
}
pub fn signature_count(&self) -> usize {
self.signature_count
}
pub fn is_signed(&self) -> bool {
self.signature_count > 0
}
}
impl Module {
pub fn signature_info(&self) -> Result<SignatureInfo, WSError> {
for section in &self.sections {
if let Section::Custom(custom) = section {
if custom.is_signature_header() {
let data = custom.signature_data()?;
return Ok(SignatureInfo::from_signature_data(&data));
}
}
}
Err(WSError::NoSignatures)
}
}
pub fn signature_info_from_file(path: impl AsRef<Path>) -> Result<SignatureInfo, WSError> {
let fp = File::open(path.as_ref())?;
signature_info_from_reader(&mut BufReader::new(fp), None)
}
pub fn signature_info_from_reader(
reader: &mut impl Read,
detached_signature: Option<&[u8]>,
) -> Result<SignatureInfo, WSError> {
if let Some(detached) = detached_signature {
let data = SignatureData::deserialize(detached)?;
return Ok(SignatureInfo::from_signature_data(&data));
}
let stream = Module::init_from_reader(reader)?;
let mut sections = Module::iterate(stream)?;
let first_section = sections.next().ok_or(WSError::ParseError)??;
match first_section {
Section::Custom(custom) if custom.name() == SIGNATURE_SECTION_HEADER_NAME => {
let data = custom.signature_data()?;
Ok(SignatureInfo::from_signature_data(&data))
}
_ => Err(WSError::NoSignatures),
}
}
pub fn signature_info_from_detached(detached_signature: &[u8]) -> Result<SignatureInfo, WSError> {
let data = SignatureData::deserialize(detached_signature)?;
Ok(SignatureInfo::from_signature_data(&data))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::KeyPair;
use std::io::Cursor;
fn create_test_module() -> Module {
Module {
header: [0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00],
sections: vec![],
}
}
#[test]
fn test_signature_info_from_signed_module() {
let kp = KeyPair::generate();
let module = create_test_module();
let (signed_module, _) = kp
.sk
.sign_multi(module, None, false, false)
.expect("Failed to sign");
let info = signed_module
.signature_info()
.expect("Failed to get signature info");
assert!(info.is_signed());
assert_eq!(info.signature_count(), 1);
assert_eq!(info.specification_version, 0x01);
assert_eq!(info.content_type, 0x01);
assert_eq!(info.hash_function, 0x01);
}
#[test]
fn test_signature_info_with_key_id() {
let kp = KeyPair::generate();
let pk_with_id = kp.pk.clone().attach_default_key_id();
let key_id = pk_with_id.key_id().expect("Should have key ID");
let module = create_test_module();
let (signed_module, _) = kp
.sk
.sign_multi(module, Some(&key_id), false, false)
.expect("Failed to sign");
let info = signed_module
.signature_info()
.expect("Failed to get signature info");
assert_eq!(info.key_ids().len(), 1);
assert_eq!(&info.key_ids()[0], key_id);
}
#[test]
fn test_signature_info_unsigned_module() {
let module = create_test_module();
let result = module.signature_info();
assert!(matches!(result, Err(WSError::NoSignatures)));
}
#[test]
fn test_signature_info_from_reader() {
let kp = KeyPair::generate();
let module = create_test_module();
let (signed_module, _) = kp
.sk
.sign_multi(module, None, false, false)
.expect("Failed to sign");
let mut bytes = Vec::new();
signed_module
.serialize(&mut bytes)
.expect("Failed to serialize");
let info = signature_info_from_reader(&mut Cursor::new(&bytes), None)
.expect("Failed to get signature info");
assert!(info.is_signed());
assert_eq!(info.signature_count(), 1);
}
#[test]
fn test_signature_info_from_detached() {
let kp = KeyPair::generate();
let module = create_test_module();
let (_, detached_sig) = kp
.sk
.sign_multi(module, None, true, false)
.expect("Failed to sign");
let info =
signature_info_from_detached(&detached_sig).expect("Failed to get signature info");
assert!(info.is_signed());
assert_eq!(info.signature_count(), 1);
}
#[test]
fn test_multiple_signatures_info() {
let kp1 = KeyPair::generate();
let kp2 = KeyPair::generate();
let module = create_test_module();
let (signed_once, _) = kp1
.sk
.sign_multi(module, None, false, false)
.expect("Failed to sign");
let (signed_twice, _) = kp2
.sk
.sign_multi(signed_once, None, false, false)
.expect("Failed to sign");
let info = signed_twice
.signature_info()
.expect("Failed to get signature info");
assert!(info.is_signed());
assert_eq!(info.signature_count(), 2);
}
}