tasign 0.2.0

TA ELF signing utilities with CMS/PKCS#7 support
//! 端到端:plain → CMS → `object` 写入 `.ta_signature`。

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");
}