use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use std::fs;
use std::path::PathBuf;
use std::process::Command;
use tempfile::tempdir;
use tasign::{
append_ta_signature, build_plain_bin, sign_sm2_cms, verify_elf_signature, verify_sm2_cms,
CmsSignAlgorithm, SignInputs,
};
static LEAF_PEM: &str = include_str!("fixtures/gmssl/leaf.crt");
static INT_PEM: &str = include_str!("fixtures/gmssl/intermediate.crt");
static CA_PEM: &str = include_str!("fixtures/gmssl/ca.crt");
const LEAF_KEY_PATH: &str = "tests/fixtures/gmssl/leaf.key";
const KEY_PASS: &str = "123456";
fn cert_der_from_pem(pem: &str) -> Vec<u8> {
let b64 = pem
.lines()
.filter(|l| !l.starts_with("-----"))
.collect::<String>();
STANDARD.decode(b64).expect("pem b64")
}
#[test]
fn e2e_sign_elf_and_write_section() {
let dir = tempdir().expect("tempdir");
let elf_src = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("fixtures")
.join("trivial_elf64.o");
let elf = dir.path().join("unsigned.o");
fs::copy(&elf_src, &elf).expect("copy elf");
let raw = fs::read(&elf).unwrap();
let plain = build_plain_bin(&raw).expect("plain");
let leaf_der = cert_der_from_pem(LEAF_PEM);
let int_der = cert_der_from_pem(INT_PEM);
let ints: Vec<&[u8]> = vec![&int_der];
let pkcs7 = sign_sm2_cms(SignInputs {
plain: &plain,
leaf_cert_der: Some(&leaf_der),
intermediate_certs_der: &ints,
cms_attached: false,
cms_use_gmssl_oid: false,
leaf_key_path: Some(std::path::Path::new(LEAF_KEY_PATH)),
leaf_key_pass: Some(KEY_PASS),
gmssl_path: None,
algorithm: CmsSignAlgorithm::Sm2WithSm3,
use_bjca: false,
bjca_config_path: None,
})
.expect("cms");
verify_sm2_cms(&pkcs7, &plain).expect("verify");
let sig_path = dir.path().join("signature.bin");
fs::write(&sig_path, &pkcs7).unwrap();
let out_elf = dir.path().join("signed.o");
append_ta_signature(&elf, &sig_path, &out_elf).expect("append .ta_signature");
let out = Command::new("readelf")
.args(["-S", out_elf.to_str().unwrap()])
.output()
.expect("readelf");
let s = String::from_utf8_lossy(&out.stdout);
assert!(
s.contains(".ta_signature"),
"readelf should list .ta_signature:\n{s}"
);
let signed_bytes = fs::read(&out_elf).expect("read signed elf");
verify_elf_signature(&signed_bytes, None).expect("verify_elf_signature without CA");
verify_elf_signature(&signed_bytes, Some(CA_PEM.as_bytes()))
.expect("verify_elf_signature with CA chain");
}