Skip to main content

tasign/
lib.rs

1//! TA ELF 签名与验签库。
2//!
3//! 提供两种使用模式:
4//!
5//! - **`std`(默认)**:完整签名工具链,包括 ELF 写入(`objcopy`)、CMS 签名(mbedtls)、
6//!   GmSSL 兼容模式等。供 `tasign-tool` CLI 使用。
7//! - **`kernel-verify`(`no_std` + `alloc`)**:仅验签路径,供 Rust 内核直接调用
8//!   [`verify_elf_signature`] 对已嵌入 `.ta_signature` 的 ELF 做证书验签。
9//!
10//! 密码学运算统一由 `mbedtls-smx` 完成(SM2/SM3、RSA/SHA256、ECDSA/SHA256)。
11//! GmSSL 可执行文件仅在脚本层面用于证书生成与 `cms-compat=gmssl` 兼容验证。
12//!
13//! # 日志(`log` 门面)
14//!
15//! 本 crate 使用 `log` 的 `info!` / `warn!` / `debug!` 等宏,**不**依赖具体实现:
16//! - 在 **x-kernel** 中,由入口/内核侧已注册的 logger(例如 `klogger`,实现 `log::Log`)输出。
17//! - **独立使用**(含 `tasign-tool`):在进程入口初始化 `env_logger`(或其它 `log` 后端);
18//!   单元测试可使用 `env_logger::Builder::...::try_init()`。
19#![cfg_attr(not(feature = "std"), no_std)]
20#[cfg(not(feature = "std"))]
21extern crate alloc;
22
23#[cfg(any(feature = "std", feature = "kernel-verify"))]
24use log::{debug, error, info};
25
26pub mod cms;
27#[cfg(feature = "std")]
28pub mod elf;
29pub mod error;
30#[cfg(feature = "std")]
31mod gmssl_pkcs8_decrypt;
32#[cfg(feature = "std")]
33pub mod gmssl_cli;
34#[cfg(feature = "std")]
35pub mod key;
36#[cfg(any(feature = "std", feature = "kernel-verify"))]
37pub mod limits;
38#[cfg(any(feature = "std", feature = "kernel-verify"))]
39pub mod plain;
40
41pub use cms::{
42    verify_cms_signature_with_ca_opt, verify_cms_signature_with_ca_opt_and_limits, verify_sm2_cms,
43    verify_sm2_cms_with_ca_opt, verify_sm2_cms_with_ca_pem,
44};
45#[cfg(feature = "std")]
46pub use cms::{
47    extract_cms_detached_parts, sign_gmssl_cms_attached_native, sign_sm2_cms,
48    CmsSignAlgorithm, SignInputs,
49};
50pub use error::Error;
51#[cfg(feature = "std")]
52pub use elf::{
53    append_ta_signature, append_ta_signature_bytes, append_ta_signature_objcopy,
54    append_ta_signature_object, normalize_relocatable_elf_bytes,
55    strip_ta_signature_relocatable_bytes, write_outputs,
56};
57#[cfg(feature = "std")]
58pub use gmssl_cli::{find_gmssl_in_path, resolve_gmssl_path, DEFAULT_GMSSL};
59#[cfg(any(feature = "std", feature = "kernel-verify"))]
60pub use limits::{LimitsError, VerifyLimits};
61#[cfg(any(feature = "std", feature = "kernel-verify"))]
62pub use plain::{
63    build_plain_bin, build_plain_bin_with_limits, has_ta_signature_section,
64    plain_bytes_from_signed_elf, plain_bytes_from_signed_elf_with_limits,
65    ta_signature_section_bytes, ta_signature_section_bytes_with_limits, PlainError,
66    TA_SIGNATURE_SECTION,
67};
68
69/// 兼容旧错误类型名。
70#[cfg(any(feature = "std", feature = "kernel-verify"))]
71pub type TasignError = PlainError;
72
73/// 对已嵌入 `.ta_signature` 的整颗 ELF 验签。
74///
75/// 内部流程:
76/// 1. 从 ELF 中提取 `.ta_signature` 节(PKCS#7 DER)
77/// 2. 按 plain 协议重算签名原数据(忽略 `.ta_signature` 本身)
78/// 3. 调用 CMS 验签(摘要比对 + 签名验证 + 可选证书链校验)
79///
80/// # 参数
81/// - `elf_bytes`: 完整的已签名 ELF 文件字节
82/// - `ca_pem`: 信任锚 PEM(`Some` 时校验证书链到根;`None` 时仅校验 CMS 签名)
83///
84/// # Feature
85/// 在 `std` 与 `kernel-verify` 下均可用。
86#[cfg(any(feature = "std", feature = "kernel-verify"))]
87pub fn verify_elf_signature(elf_bytes: &[u8], ca_pem: Option<&[u8]>) -> Result<(), Error> {
88    verify_elf_signature_with_limits(elf_bytes, ca_pem, &VerifyLimits::default())
89}
90
91/// 与 [`verify_elf_signature`] 相同,但使用调用方提供的资源上限。
92#[cfg(any(feature = "std", feature = "kernel-verify"))]
93pub fn verify_elf_signature_with_limits(
94    elf_bytes: &[u8],
95    ca_pem: Option<&[u8]>,
96    limits: &VerifyLimits,
97) -> Result<(), Error> {
98    info!(
99        target: "tasign",
100        "verify_elf_signature_with_limits: elf_bytes.len: {}",
101        elf_bytes.len()
102    );
103    limits.check_elf_input_len(elf_bytes.len()).map_err(|e| {
104        error!(target: "tasign", "verify_elf: ELF 输入长度超过上限: {e}");
105        Error::from(e)
106    })?;
107    let pkcs7 = ta_signature_section_bytes_with_limits(elf_bytes, limits).map_err(|e| {
108        error!(
109            target: "tasign",
110            "verify_elf: 提取 `.ta_signature`(PKCS#7 DER)失败: {e}"
111        );
112        Error::Plain(e)
113    })?;
114    limits.check_cms_der_len(pkcs7.len()).map_err(|e| {
115        error!(target: "tasign", "verify_elf: `.ta_signature` DER 长度超过上限: {e}");
116        Error::from(e)
117    })?;
118    let plain = plain_bytes_from_signed_elf_with_limits(elf_bytes, limits).map_err(|e| {
119        error!(
120            target: "tasign",
121            "verify_elf: 重算签名原数据 plain 失败: {e}"
122        );
123        Error::Plain(e)
124    })?;
125    limits.check_plain_buffer_len(plain.len()).map_err(|e| {
126        error!(target: "tasign", "verify_elf: plain 输出长度超过上限: {e}");
127        Error::from(e)
128    })?;
129    debug!(target: "tasign", "verify: cms_der.len={}, plain.len={}", pkcs7.len(), plain.len());
130    verify_cms_signature_with_ca_opt_and_limits(pkcs7, &plain, ca_pem, limits).map_err(|e| {
131        error!(
132            target: "tasign",
133            "verify_elf: CMS/PKCS#7 验签失败: {e}"
134        );
135        e
136    })
137}
138
139/// 分离式验签:调用方自行提供 `plain` 与 PKCS#7 DER。
140///
141/// 适用于签名数据与 ELF 分开存储的场景。行为等价于
142/// [`verify_cms_signature_with_ca_opt`]。
143///
144/// # Feature
145/// 在 `std` 与 `kernel-verify` 下均可用。
146#[cfg(any(feature = "std", feature = "kernel-verify"))]
147pub fn verify_elf_signature_from_parts(
148    plain_elf_sections: &[u8],
149    signature_der: &[u8],
150    ca_pem: Option<&[u8]>,
151) -> Result<(), Error> {
152    verify_elf_signature_from_parts_with_limits(plain_elf_sections, signature_der, ca_pem, &VerifyLimits::default())
153}
154
155/// 分离式验签,并套用资源上限(分别约束 `plain` 与 PKCS#7 DER 长度)。
156#[cfg(any(feature = "std", feature = "kernel-verify"))]
157pub fn verify_elf_signature_from_parts_with_limits(
158    plain_elf_sections: &[u8],
159    signature_der: &[u8],
160    ca_pem: Option<&[u8]>,
161    limits: &VerifyLimits,
162) -> Result<(), Error> {
163    limits
164        .check_plain_buffer_len(plain_elf_sections.len())
165        .map_err(|e| {
166            error!(target: "tasign", "verify_elf_from_parts: plain 长度超过上限: {e}");
167            Error::from(e)
168        })?;
169    limits.check_cms_der_len(signature_der.len()).map_err(|e| {
170        error!(target: "tasign", "verify_elf_from_parts: PKCS#7 DER 长度超过上限: {e}");
171        Error::from(e)
172    })?;
173    verify_cms_signature_with_ca_opt_and_limits(
174        signature_der,
175        plain_elf_sections,
176        ca_pem,
177        limits,
178    )
179    .map_err(|e| {
180        error!(
181            target: "tasign",
182            "verify_elf_from_parts: CMS/PKCS#7 验签失败(plain 与签名不匹配等): {e}"
183        );
184        e
185    })
186}
187
188#[cfg(all(test, feature = "std"))]
189mod tests {
190    use super::*;
191
192    fn init_log() {
193        let _ = env_logger::builder().is_test(true).try_init();
194    }
195
196    #[test]
197    fn plain_ok_without_ta_signature_fixture() {
198        init_log();
199        static ELF: &[u8] = include_bytes!("../tests/fixtures/trivial_elf64.o");
200        let p = build_plain_bin(ELF).expect("fixture has no .ta_signature");
201        assert!(!p.is_empty());
202    }
203
204    #[test]
205    fn rejects_when_ta_signature_present_fixture() {
206        init_log();
207        static ELF: &[u8] = include_bytes!("../tests/fixtures/trivial_with_ta_sig.o");
208        let err = build_plain_bin(ELF).unwrap_err();
209        match err {
210            PlainError::TaSignatureSectionExists(_) => {}
211            e => panic!("unexpected: {e:?}"),
212        }
213    }
214}