From 6463a5c64d24b901bc1e92e5df84016a1f61ccba Mon Sep 17 00:00:00 2001 From: chenbohan Date: Fri, 6 Feb 2026 15:51:11 +0800 Subject: [PATCH] add cbor_cert_op.rs Signed-off-by: chenbohan --- src/cbor_cert_op.rs | 902 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 35 +- src/mbedtls_sm2dsa.rs | 108 +++-- 3 files changed, 971 insertions(+), 74 deletions(-) create mode 100644 src/cbor_cert_op.rs diff --git a/src/cbor_cert_op.rs b/src/cbor_cert_op.rs new file mode 100644 index 0000000..f7b083e --- /dev/null +++ b/src/cbor_cert_op.rs @@ -0,0 +1,902 @@ +use crate::mbedtls_sm2dsa::{dice_hash, dice_kdf, dice_keypair_from_seed, dice_sign}; +extern crate cty; + +pub const DICE_PUBLIC_KEY_BUFFER_SIZE: usize = 64; +pub const DICE_MAX_PUBLIC_KEY_SIZE: usize = 96; +pub const COSE_KEY_KTY_EC2: i64 = 2; +pub const COSE_ALG_SM2: i64 = -248; +pub const COSE_CRV_SM2: i64 = 9; +pub const DICE_SIGNATURE_BUFFER_SIZE: usize = 64; +pub const DICE_PROFILE_NAME: &str = "opendice.example.sm2"; +pub const DICE_PRIVATE_KEY_BUFFER_SIZE: usize = 32; +pub const DICE_MAX_PROTECTED_ATTRIBUTES_SIZE: usize = 16; + +pub const DICE_CDI_SIZE: usize = 32; +pub const DICE_HASH_SIZE: usize = 32; +pub const DICE_HIDDEN_SIZE: usize = 64; +pub const DICE_INLINE_CONFIG_SIZE: usize = 64; +pub const DICE_PRIVATE_KEY_SEED_SIZE: usize = 32; +pub const DICE_ID_SIZE: usize = 20; + +pub const K_COSE_KEY_KTY_LABEL: i64 = 1; +pub const K_COSE_KEY_ALG_LABEL: i64 = 3; +pub const K_COSE_KEY_OPS_LABEL: i64 = 4; +pub const K_COSE_KEY_CRV_LABEL: i64 = -1; +pub const K_COSE_KEY_X_LABEL: i64 = -2; +pub const K_COSE_KEY_Y_LABEL: i64 = -3; + +// Key Types (KTY) +pub const K_COSE_KEY_KTY_OKP: i64 = 1; +pub const K_COSE_KEY_KTY_EC2: i64 = 2; + +// Operations +pub const K_COSE_KEY_OPS_VERIFY: i64 = 2; + +pub const kIdSalt: [u8; 64] = [ + 0xDB, 0xDB, 0xAE, 0xBC, 0x80, 0x20, 0xDA, 0x9F, 0xF0, 0xDD, 0x5A, 0x24, 0xC8, 0x3A, 0xA5, 0xA5, + 0x42, 0x86, 0xDF, 0xC2, 0x63, 0x03, 0x1E, 0x32, 0x9B, 0x4D, 0xA1, 0x48, 0x43, 0x06, 0x59, 0xFE, + 0x62, 0xCD, 0xB5, 0xB7, 0xE1, 0xE0, 0x0F, 0xC6, 0x80, 0x30, 0x67, 0x11, 0xEB, 0x44, 0x4A, 0xF7, + 0x72, 0x09, 0x35, 0x94, 0x96, 0xFC, 0xFF, 0x1D, 0xB9, 0x52, 0x0B, 0xA5, 0x1C, 0x7B, 0x29, 0xEA, +]; + +// DicePrincipal 枚举定义 +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Principal { + /// 授权机构 + Authority, + /// 目标主体 + Subject, +} + +// // 如果你需要在代码中判断某种逻辑,可以直接在枚举上实现方法 +// impl Principal { +// /// 判断是否为授权机构 +// pub fn is_authority(&self) -> bool { +// matches!(self, Self::Authority) +// } +// } + +/// DiceKeyParam 结构体定义 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct KeyParam<'a> { + /// 配置名称(纯 Rust 使用 &str 替代 const char*) + pub profile_name: &'a str, + + /// 公钥大小 + pub public_key_size: usize, + + /// 签名大小 + pub signature_size: usize, + + /// COSE 相关参数(使用 i64 对应 int64_t) + pub cose_key_type: i64, + pub cose_key_algorithm: i64, + pub cose_key_curve: i64, +} + +/// DicePrincipal 枚举定义 +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DiceResult { + Ok, + InvalidInput, + BufferTooSmall, + PlatformError, +} + +#[repr(u8)] +pub enum CborType { + UnsignedInt = 0, + NegativeInt = 1, + ByteString = 2, + TextString = 3, + Array = 4, + Map = 5, + Tag = 6, + Simple = 7, +} + +/// CborOut 结构体定义 +pub struct CborOut<'a> { + /// 使用可变字节切片,替代 uint8_t* 和 buffer_size + /// 生命周期 'a 确保 CborOut 不会比它持有的 buffer 活得更久 + buffer: &'a mut [u8], + /// 当前写入的位置索引 + cursor: usize, + /// 记录是否发生过溢出(对应原代码中的 Overflowed 逻辑) + overflowed: bool, +} + +impl<'a> CborOut<'a> { + /// 替代 CborOutInit + pub fn new(buffer: &'a mut [u8]) -> Self { + Self { + buffer, + cursor: 0, + overflowed: false, + } + } + + /// 替代 CborWriteInt + pub fn write_int(&mut self, val: i64) { + if val >= 0 { + self.write_type(CborType::UnsignedInt, val as u64); + } else { + // CBOR 负整数编码为 -(n + 1) + self.write_type(CborType::NegativeInt, (-1 - val) as u64); + } + } + + pub fn write_uint(&mut self, val: u64) { + self.write_type(CborType::UnsignedInt, val); + } + + pub fn write_array(&mut self, num_elements: usize) { + // usize as u64 是安全的,因为 u64 总是大于等于处理器的字长 + self.write_type(CborType::Array, num_elements as u64); + } + + pub fn write_map(&mut self, num_pairs: usize) { + self.write_type(CborType::Map, num_pairs as u64); + } + + pub fn write_tag(&mut self, tag: u64) { + self.write_type(CborType::Tag, tag); + } + + pub fn write_false(&mut self) { + self.write_type(CborType::Simple, 20); + } + + pub fn write_true(&mut self) { + self.write_type(CborType::Simple, 21); + } + + pub fn write_null(&mut self) { + self.write_type(CborType::Simple, 22); + } + + /// 预留出 data_size 大小的空间,并返回该空间的引用供外部填充数据 + pub fn alloc_str(&mut self, cbor_type: CborType, data_size: usize) -> Option<&mut [u8]> { + // 1. 先写入 Header + self.write_type(cbor_type, data_size as u64); + + // 如果 header 写入已经导致溢出,直接返回 None + if self.overflowed { + return None; + } + + // 2. 检查数据部分是否放得下 + match self.cursor.checked_add(data_size) { + Some(next) if next <= self.buffer.len() => { + let start = self.cursor; + self.cursor = next; // 移动指针,提前占坑 + Some(&mut self.buffer[start..next]) + } + _ => { + self.overflowed = true; + self.cursor = usize::MAX; + None + } + } + } + + pub fn alloc_bstr(&mut self, data_size: usize) -> Option<&mut [u8]> { + self.alloc_str(CborType::ByteString, data_size) + } + + pub fn alloc_tstr(&mut self, data_size: usize) -> Option<&mut [u8]> { + self.alloc_str(CborType::TextString, data_size) + } + + fn write_str(&mut self, cbor_type: CborType, data: &[u8]) { + if let Some(dest) = self.alloc_str(cbor_type, data.len()) { + // 这里的 copy_from_slice 对应 C 的 memcpy + if !data.is_empty() { + dest.copy_from_slice(data); + } + } + } + + pub fn write_bstr(&mut self, data: &[u8]) { + self.write_str(CborType::ByteString, data); + } + + pub fn write_tstr(&mut self, text: &str) { + // text.as_bytes() 将 &str 转换为 &[u8] + self.write_str(CborType::TextString, text.as_bytes()); + } + + /// 内部核心方法,替代 CborWriteType + fn write_type(&mut self, cbor_type: CborType, val: u64) { + // 1. 确定编码所需的额外字节数和首字节的 'info' 部分 + let (size, info) = if val <= 23 { + (1, val as u8) + } else if val <= 0xff { + (2, 24) + } else if val <= 0xffff { + (3, 25) + } else if val <= 0xffffffff { + (5, 26) + } else { + (9, 27) + }; + + // 2. 安全检查:计算新指针位置 (替代 C 的 WouldOverflow 和 FitsInBuffer) + match self.cursor.checked_add(size) { + Some(next) if next <= self.buffer.len() => { + let type_code = cbor_type as u8; + let current = self.cursor; + + // 写入首字节 (Type << 5 | Additional Info) + self.buffer[current] = (type_code << 5) | info; + + // 根据 size 写入后续字节 (大端序) + match size { + 2 => self.buffer[current + 1] = val as u8, + 3 => self.buffer[current + 1..current + 3] + .copy_from_slice(&(val as u16).to_be_bytes()), + 5 => self.buffer[current + 1..current + 5] + .copy_from_slice(&(val as u32).to_be_bytes()), + 9 => self.buffer[current + 1..current + 9].copy_from_slice(&val.to_be_bytes()), + _ => {} // size == 1 无需额外操作 + } + + // 3. 移动指针:对应 C 语言最后的 out->cursor += size; + self.cursor = next; + } + _ => { + // 发生任何形式的溢出,触发熔断 + self.overflowed = true; + // 将 cursor 设为最大值,确保后续所有写入都失败 (保持与 C 逻辑语义一致) + self.cursor = usize::MAX; + } + } + } + + pub fn is_overflowed(&self) -> bool { + // 1. 如果我们手动设置了溢出标志 + // 2. 或者 cursor 逻辑上超出了 buffer 长度 + self.overflowed || self.cursor > self.buffer.len() + } + + pub fn size(&mut self) -> usize { + self.cursor + } +} + +pub fn EncodeProtectedAttributes( + context: &mut u8, // 假设 context 是某种上下文指针,使用 &mut u8 作为占位符 + principal: Principal, + buffer: &mut [u8], // 使用切片替代 uint8_t* 和 size_t +) -> Result { + // 返回 Result,成功时包含编码长度 + + // RFC 8152 常量 + const COSE_HEADER_ALG_LABEL: i64 = 1; + + // 初始化 CBOR 写入器(假设 CborOut 是已有的 Rust 实现) + let mut out = CborOut::new(buffer); + + // 写入 Map 头部 + out.write_map(1); + + // 获取密钥参数 + // 这里调用之前定义的 KeyParam 和 DiceGetKeyParam + // 使用 ? 语法糖直接处理错误返回 + let key_param = DiceGetKeyParam(context, principal)?; + + // 写入算法信息 + out.write_int(COSE_HEADER_ALG_LABEL); + out.write_int(key_param.cose_key_algorithm); + + // 检查是否溢出并返回结果 + if out.is_overflowed() { + Err(DiceResult::BufferTooSmall) + } else { + Ok(out.size()) + } +} + +/// 获取 Dice 密钥参数,SM2算法 +/// 在纯 Rust 风格中,我们直接返回 Result +/// 这样调用者可以直接拿到结果,而不是传入一个待修改的指针 +pub fn DiceGetKeyParam( + _context: &mut u8, + _principal: Principal, +) -> Result, DiceResult> { + // 这里的 'static 生命周期是因为字符串常量存储在 Flash/只读区 + + Ok(KeyParam { + profile_name: DICE_PROFILE_NAME, + public_key_size: DICE_PUBLIC_KEY_BUFFER_SIZE, + signature_size: DICE_SIGNATURE_BUFFER_SIZE, + + // 使用 i64 存储 COSE 参数 + cose_key_type: COSE_KEY_KTY_EC2, + cose_key_algorithm: COSE_ALG_SM2, + cose_key_curve: COSE_CRV_SM2, + }) +} + +pub struct TbsResult { + /// 编码后的总长度(buffer 的前 encoded_size 字节是 TBS) + pub encoded_size: usize, + /// payload 在 buffer 中的起始偏移(相对于 buffer 开始) + pub payload_offset: usize, +} + +pub fn dice_derive_cdi_certificate_id( + _context: &mut u8, + cdi_public_key: &[u8], + id: &mut [u8; DICE_ID_SIZE], // 确保这是 20 字节 +) -> Result<(), DiceResult> { + // 1. 定义 64 字节的固定 Salt + const ID_INFO: &[u8] = b"ID"; + + // 2. 调用 KDF (HKDF-Extract + HKDF-Expand) + // 直接传入 id 数组引用,结果会写进 id 中 + dice_kdf(cdi_public_key, Some(&kIdSalt), Some(ID_INFO), id) + .map_err(|_| DiceResult::PlatformError)?; + + // 3. 按照 DICE 标准清除最高位 + id[0] &= 0x7F; + + Ok(()) +} + +pub fn EncodeCoseTbs( + buffer: &mut [u8], + protected_attributes: &[u8], + payload_size: usize, + aad: &[u8], +) -> Result { + // 1. 在一个局部作用域里使用 CborOut + let (encoded_size, overflowed) = { + let mut out = CborOut::new(buffer); + out.write_array(4); + out.write_tstr("Signature1"); + out.write_bstr(protected_attributes); + out.write_bstr(aad); + out.alloc_str(CborType::ByteString, payload_size); // 仅为了移动 cursor + + (out.size(), out.is_overflowed()) + // 闭包/作用域结束,out 在这里被销毁(Drop) + // 它对 buffer 的借用也随之彻底解除 + }; + + // 2. 检查结果 + if overflowed { + // 返回错误同时带上已计算出的 encoded_size(与 C 版本相似) + return Err((DiceResult::BufferTooSmall, encoded_size)); + } + + let start = encoded_size + .checked_sub(payload_size) + .ok_or((DiceResult::PlatformError, 0))?; + + Ok(TbsResult { + encoded_size, + payload_offset: start, + }) +} + +pub fn EncodeCoseSign1( + context: &mut u8, + protected_attributes: &[u8], + payload: &[u8], + move_payload: bool, + signature: &[u8; DICE_SIGNATURE_BUFFER_SIZE], // 长度应符合 DICE_SIGNATURE_BUFFER_SIZE + buffer: &mut [u8], +) -> Result { + let mut out = CborOut::new(buffer); + + // 1. COSE_Sign1 是一个包含 4 个元素的数组 + out.write_array(4); + + // 2. 写入保护属性 + out.write_bstr(protected_attributes); + + // 3. 写入空的未保护属性 Map (0对) + out.write_map(0); + + // 4. 处理 Payload + if move_payload { + // 在 C 语言逻辑中,payload 已经在 buffer 里的某个位置了 + let payload_size = payload.len(); + let payload_ptr = payload.as_ptr(); + + // 预留空间 + if let Some(dest) = out.alloc_bstr(payload_size) { + let dest_ptr = dest.as_mut_ptr(); + + // 安全检查:payload 必须在 dest 之后(防止覆盖尚未读取的数据) + if payload_ptr < dest_ptr { + return Err(DiceResult::PlatformError); + } + + // 计算偏移量并移动数据 + // Rust 中处理同一内存块移动的更安全方式: + let src_offset = unsafe { payload_ptr.offset_from(out.buffer.as_ptr()) as usize }; + let dest_offset = unsafe { dest_ptr.offset_from(out.buffer.as_ptr()) as usize }; + + out.buffer + .copy_within(src_offset..src_offset + payload_size, dest_offset); + } + } else { + out.write_bstr(payload); + } + + // 5. 获取签名参数并写入签名 + // 这里假设 DiceGetKeyParam 已经在别处实现 + let key_param = DiceGetKeyParam(context, Principal::Authority)?; + out.write_bstr(&signature[..key_param.signature_size]); + + // 6. 检查溢出 + let encoded_size = out.size(); + if out.is_overflowed() { + return Err(DiceResult::BufferTooSmall); + } + + Ok(encoded_size) +} + +pub fn DiceCoseSignAndEncodeSign1( + context: &mut u8, + payload: &[u8], + aad: &[u8], + private_key: &[u8; DICE_PRIVATE_KEY_BUFFER_SIZE], + buffer: &mut [u8], +) -> Result { + // 1. 编码受保护属性 (Protected Attributes) + // 这里我们预留一个本地缓冲区 + let mut protected_attributes = [0u8; DICE_MAX_PROTECTED_ATTRIBUTES_SIZE]; + + // 假设这个函数返回 (实际长度) + let prot_attrs_size = + EncodeProtectedAttributes(context, Principal::Authority, &mut protected_attributes) + .map_err(|_| DiceResult::PlatformError)?; + + let prot_attrs_slice = &protected_attributes[..prot_attrs_size]; + + // 2. 构建 TBS (To-Be-Signed) 结构 + // 注意:TBS 会直接写在传入的 buffer 中 + let tbs_res = match EncodeCoseTbs(buffer, prot_attrs_slice, payload.len(), aad) { + Ok(res) => res, + Err((DiceResult::BufferTooSmall, _tbs_size)) => { + // 在 no_std 环境下无法使用 vec! 动态分配 + // 由于 EncodeCoseSign1 需要足够的空间来计算最终大小,这里无法完美处理 + // 最安全的做法是直接返回错误,由调用者提供足够的 buffer + return Err(DiceResult::BufferTooSmall); + } + Err((e, _)) => return Err(e), + }; + // 3. 将 payload 填充到 TBS 预留的空间中(使用偏移避免借用冲突) + let payload_offset = tbs_res.payload_offset; + let payload_end = payload_offset + payload.len(); + if payload_end > buffer.len() { + return Err(DiceResult::PlatformError); + } + buffer[payload_offset..payload_end].copy_from_slice(payload); + + // 4. 对整个 TBS 进行签名 + // 签名输入是 buffer 中已经编码好的内容,长度为 tbs_res.encoded_size + let mut signature = [0u8; DICE_SIGNATURE_BUFFER_SIZE]; + dice_sign( + context, + &buffer[..tbs_res.encoded_size], + private_key, + &mut signature, + ) + .map_err(|_| DiceResult::PlatformError)?; + // 5. 生成最终的 COSE_Sign1 结构 + // 此时我们会覆写 buffer(重新从开头开始写,把之前的 TBS 覆盖掉) + EncodeCoseSign1( + context, + prot_attrs_slice, + payload, + false, // move_payload 为 false,因为 payload 是作为参数传进来的 + &signature, + buffer, + ) +} + +#[derive(Debug, Clone, Copy)] +pub enum DiceMode { + NotInitialized, + Normal, + Debug, + Maintenance, +} +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DiceConfigType { + Inline, + Descriptor, +} +pub struct DiceInputValues<'a> { + pub code_hash: [u8; DICE_HASH_SIZE], + pub code_descriptor: &'a [u8], // 对应 const uint8_t* + size_t + pub config_type: DiceConfigType, + pub config_value: [u8; DICE_INLINE_CONFIG_SIZE], + pub config_descriptor: &'a [u8], // 对应 const uint8_t* + size_t + pub authority_hash: [u8; DICE_HASH_SIZE], + pub authority_descriptor: &'a [u8], // 对应 const uint8_t* + size_t + pub mode: DiceMode, + pub hidden: [u8; DICE_HIDDEN_SIZE], +} + +pub fn EncodeCwt( + context: &mut u8, + input_values: &DiceInputValues, + authority_id_hex: &str, + subject_id_hex: &str, + encoded_public_key: &[u8], + buffer: &mut [u8], +) -> Result { + // 1. 定义常量 (保持与 C 逻辑一致) + const CWT_ISSUER_LABEL: i64 = 1; + const CWT_SUBJECT_LABEL: i64 = 2; + const CODE_HASH_LABEL: i64 = -4670545; + const CODE_DESCRIPTOR_LABEL: i64 = -4670546; + const CONFIG_HASH_LABEL: i64 = -4670547; + const CONFIG_DESCRIPTOR_LABEL: i64 = -4670548; + const AUTHORITY_HASH_LABEL: i64 = -4670549; + const AUTHORITY_DESCRIPTOR_LABEL: i64 = -4670550; + const MODE_LABEL: i64 = -4670551; + const SUBJECT_PUBLIC_KEY_LABEL: i64 = -4670552; + const KEY_USAGE_LABEL: i64 = -4670553; + const PROFILE_NAME_LABEL: i64 = -4670554; + const KEY_USAGE_CERT_SIGN: u8 = 32; + + // 2. 获取 KeyParam (假设已经定义了该函数) + let key_param = DiceGetKeyParam(context, Principal::Subject)?; + + // 3. 计算 Map 键值对数量 + let mut map_pairs = 7; + if !input_values.code_descriptor.is_empty() { + map_pairs += 1; + } + if input_values.config_type == DiceConfigType::Descriptor { + map_pairs += 2; + } else { + map_pairs += 1; + } + if !input_values.authority_descriptor.is_empty() { + map_pairs += 1; + } + if !key_param.profile_name.is_empty() { + map_pairs += 1; + } + + // 4. 开始 CBOR 编码 + let mut out = CborOut::new(buffer); + out.write_map(map_pairs); + + out.write_int(CWT_ISSUER_LABEL); + out.write_tstr(authority_id_hex); + + out.write_int(CWT_SUBJECT_LABEL); + out.write_tstr(subject_id_hex); + + out.write_int(CODE_HASH_LABEL); + out.write_bstr(&input_values.code_hash); + + if !input_values.code_descriptor.is_empty() { + out.write_int(CODE_DESCRIPTOR_LABEL); + out.write_bstr(input_values.code_descriptor); + } + + // 处理 Config 逻辑 + if input_values.config_type == DiceConfigType::Descriptor { + let mut config_descriptor_hash = [0u8; DICE_HASH_SIZE]; + // 只有在目前没有溢出的情况下才进行哈希运算,节省性能 + if !out.is_overflowed() { + dice_hash( + context, + input_values.config_descriptor, + &mut config_descriptor_hash, + ) + .map_err(|_| DiceResult::PlatformError)?; + } + out.write_int(CONFIG_DESCRIPTOR_LABEL); + out.write_bstr(input_values.config_descriptor); + out.write_int(CONFIG_HASH_LABEL); + out.write_bstr(&config_descriptor_hash); + } else if input_values.config_type == DiceConfigType::Inline { + out.write_int(CONFIG_DESCRIPTOR_LABEL); + out.write_bstr(&input_values.config_value); + } + + out.write_int(AUTHORITY_HASH_LABEL); + out.write_bstr(&input_values.authority_hash); + + if !input_values.authority_descriptor.is_empty() { + out.write_int(AUTHORITY_DESCRIPTOR_LABEL); + out.write_bstr(input_values.authority_descriptor); + } + + let mode_byte = [input_values.mode as u8]; + out.write_int(MODE_LABEL); + out.write_bstr(&mode_byte); + + out.write_int(SUBJECT_PUBLIC_KEY_LABEL); + out.write_bstr(encoded_public_key); + + let key_usage = [KEY_USAGE_CERT_SIGN]; + out.write_int(KEY_USAGE_LABEL); + out.write_bstr(&key_usage); + + if !key_param.profile_name.is_empty() { + out.write_int(PROFILE_NAME_LABEL); + out.write_tstr(key_param.profile_name); + } + + // 5. 结果检查 (对应方案 A/B) + let encoded_size = out.size(); + if out.is_overflowed() { + // 如果你采用了带参数的错误类型,可以返回 Err(DiceResult::BufferTooSmall(encoded_size)) + Err(DiceResult::BufferTooSmall) + } else { + Ok(encoded_size) + } +} + +//dice.c中的函数DiceDeriveCdiCertificateId的Rust版本 +// no_std compatible hex encoding function +pub fn dice_hex_encode(input: &[u8], output: &mut [u8]) { + const HEX_MAP: &[u8; 16] = b"0123456789abcdef"; + + let mut out_pos = 0; + for &byte in input { + if out_pos < output.len() { + output[out_pos] = HEX_MAP[(byte >> 4) as usize]; + out_pos += 1; + } + if out_pos < output.len() { + output[out_pos] = HEX_MAP[(byte & 0x0F) as usize]; + out_pos += 1; + } + } +} + +pub fn dice_generate_certificate( + context: &mut u8, + subject_seed: &[u8; DICE_PRIVATE_KEY_SEED_SIZE], + authority_seed: &[u8; DICE_PRIVATE_KEY_SEED_SIZE], + input_values: &DiceInputValues, + certificate: &mut [u8], +) -> Result { + // 1. 输入校验 + if input_values.config_type != DiceConfigType::Descriptor + && input_values.config_type != DiceConfigType::Inline + { + return Err(DiceResult::InvalidInput); + } + + // 2. 准备密钥缓冲区 + let mut subject_private_buf = [0u8; DICE_PRIVATE_KEY_BUFFER_SIZE]; + let mut authority_private_buf = [0u8; DICE_PRIVATE_KEY_BUFFER_SIZE]; + + // 3. 派生 Subject 密钥对 + let mut subject_public = [0u8; DICE_PUBLIC_KEY_BUFFER_SIZE]; + dice_keypair_from_seed(subject_seed).map_err(|_| DiceResult::PlatformError)?; + + // 4. 获取 Subject ID + let mut subject_id = [0u8; DICE_ID_SIZE]; + let _subj_key_param = DiceGetKeyParam(context, Principal::Subject)?; + dice_derive_cdi_certificate_id(context, &subject_public, &mut subject_id)?; + + let mut subject_id_hex = [0u8; 41]; + dice_hex_encode(&subject_id, &mut subject_id_hex); + let subject_id_str = + core::str::from_utf8(&subject_id_hex[..40]).map_err(|_| DiceResult::PlatformError)?; + + // 5. 派生 Authority 密钥对 + let mut authority_public = [0u8; DICE_PUBLIC_KEY_BUFFER_SIZE]; + dice_keypair_from_seed(authority_seed).map_err(|_| { + subject_private_buf.fill(0); + DiceResult::PlatformError + })?; + + // 6. 获取 Authority ID + let mut authority_id = [0u8; DICE_ID_SIZE]; + let _auth_key_param = DiceGetKeyParam(context, Principal::Authority)?; + dice_derive_cdi_certificate_id(context, &authority_public, &mut authority_id)?; + + let mut authority_id_hex = [0u8; 41]; + dice_hex_encode(&authority_id, &mut authority_id_hex); + let authority_id_str = + core::str::from_utf8(&authority_id_hex[..40]).map_err(|_| DiceResult::PlatformError)?; + + // 7. 编码公钥为 COSE_Key + let mut encoded_pub_key = [0u8; DICE_MAX_PUBLIC_KEY_SIZE]; + let encoded_pub_key_size = DiceCoseEncodePublicKey( + context, + Principal::Subject, + &subject_public, + &mut encoded_pub_key, + ) + .map_err(|_| { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + DiceResult::PlatformError + })?; + let encoded_pub_key_slice = &encoded_pub_key[..encoded_pub_key_size]; + + // 8. 编码受保护属性 + let mut protected_attrs = [0u8; DICE_MAX_PROTECTED_ATTRIBUTES_SIZE]; + let prot_attrs_size = + EncodeProtectedAttributes(context, Principal::Authority, &mut protected_attrs).map_err( + |_| { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + DiceResult::PlatformError + }, + )?; + let prot_attrs_slice = &protected_attrs[..prot_attrs_size]; + + // 9. 计算 CWT 大小 + let cwt_size = match EncodeCwt( + context, + input_values, + &authority_id_str, + &subject_id_str, + encoded_pub_key_slice, + &mut [], + ) { + Ok(s) => s, + Err(e) => { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + return Err(e); + } + }; + + // 10. 编码 TBS + let tbs_res = match EncodeCoseTbs(certificate, prot_attrs_slice, cwt_size, &[]) { + Ok(r) => r, + Err((e, _)) => { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + return Err(e); + } + }; + + // 11. 填充 Payload 区域 + let payload_offset = tbs_res.payload_offset; + let payload_end = payload_offset.checked_add(cwt_size).ok_or_else(|| { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + DiceResult::PlatformError + })?; + + if payload_end > certificate.len() { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + return Err(DiceResult::BufferTooSmall); + } + + let payload_buf = &mut certificate[payload_offset..payload_end]; + let final_cwt_size = match EncodeCwt( + context, + input_values, + &authority_id_str, + &subject_id_str, + encoded_pub_key_slice, + payload_buf, + ) { + Ok(s) => s, + Err(_) => { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + return Err(DiceResult::PlatformError); + } + }; + + if final_cwt_size != cwt_size { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + return Err(DiceResult::PlatformError); + } + + // 12. 签名 TBS + let mut signature = [0u8; DICE_SIGNATURE_BUFFER_SIZE]; + dice_sign( + context, + &certificate[..tbs_res.encoded_size], + &authority_private_buf, + &mut signature, + ) + .map_err(|_| { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + DiceResult::PlatformError + })?; + + // 13. 生成最终 COSE_Sign1 + // 注意:EncodeCoseSign1 会写入到 certificate,所以需要复制 payload 以避免借用冲突 + let mut payload_copy = [0u8; 2048]; + let payload_len = payload_end - payload_offset; + if payload_len > payload_copy.len() { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + return Err(DiceResult::BufferTooSmall); + } + payload_copy[..payload_len].copy_from_slice(&certificate[payload_offset..payload_end]); + let cert_size = EncodeCoseSign1( + context, + prot_attrs_slice, + &payload_copy[..payload_len], + true, + &signature, + certificate, + ) + .map_err(|e| { + subject_private_buf.fill(0); + authority_private_buf.fill(0); + e + })?; + + // 14. 清除敏感数据 + subject_private_buf.fill(0); + authority_private_buf.fill(0); + + Ok(cert_size) +} + +// FFI: 编码公钥为 COSE_Key +pub fn DiceCoseEncodePublicKey( + context: &mut u8, + principal: Principal, + public_key: &[u8; DICE_PUBLIC_KEY_BUFFER_SIZE], + buffer: &mut [u8], +) -> Result { + let key_param = DiceGetKeyParam(context, principal)?; + let mut out = CborOut::new(buffer); + + // 1. 根据 KTY 确定 Map 长度 + match key_param.cose_key_type { + K_COSE_KEY_KTY_OKP => out.write_map(5), + K_COSE_KEY_KTY_EC2 => out.write_map(6), + _ => return Err(DiceResult::InvalidInput), + } + + // 2. 写入通用 Key 属性 + out.write_int(K_COSE_KEY_KTY_LABEL); + out.write_int(key_param.cose_key_type); + + out.write_int(K_COSE_KEY_ALG_LABEL); + out.write_int(key_param.cose_key_algorithm); + + out.write_int(K_COSE_KEY_OPS_LABEL); + out.write_array(1); + out.write_int(K_COSE_KEY_OPS_VERIFY); + + out.write_int(K_COSE_KEY_CRV_LABEL); + out.write_int(key_param.cose_key_curve); + + // 3. 写入公钥坐标 (X, Y) + match key_param.cose_key_type { + K_COSE_KEY_KTY_OKP => { + // OKP (Ed25519): 只有一个 X 坐标 + out.write_int(K_COSE_KEY_X_LABEL); + out.write_bstr(&public_key[..key_param.public_key_size]); + } + K_COSE_KEY_KTY_EC2 => { + // EC2 (SM2/P-256/P-384): 拆分为 X 和 Y + let xy_size = key_param.public_key_size / 2; + + out.write_int(K_COSE_KEY_X_LABEL); + out.write_bstr(&public_key[..xy_size]); + + out.write_int(K_COSE_KEY_Y_LABEL); + out.write_bstr(&public_key[xy_size..(xy_size * 2)]); + } + _ => unreachable!(), + } + + if out.is_overflowed() { + Err(DiceResult::BufferTooSmall) + } else { + Ok(out.size()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 0a97545..b04fad1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ extern crate cty; - -mod mbedtls_sm2dsa; -pub use mbedtls_sm2dsa::{sm2_keypair_from_seed,sm2_sign, sm2_verify}; +pub mod cbor_cert_op; +pub mod mbedtls_sm2dsa; +pub use mbedtls_sm2dsa::{sm2_keypair_from_seed, sm2_sign, sm2_verify}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DiceResult { @@ -11,8 +11,6 @@ pub enum DiceResult { PlatformError, } - - mod bindings { #![allow(non_camel_case_types)] #![allow(non_snake_case)] @@ -21,19 +19,28 @@ mod bindings { include!(concat!(env!("OUT_DIR"), "/dice-bindings.rs")); } -pub use bindings::{DiceInputValues, DiceInputValues_}; pub use bindings::DICE_HIDDEN_SIZE; -pub use bindings::{DiceMode, DiceMode_kDiceModeDebug, DiceMode_kDiceModeNormal}; -pub use bindings::{DiceConfigType, DiceConfigType_kDiceConfigTypeInline, DiceConfigType_kDiceConfigTypeDescriptor}; -pub use bindings::DiceAndroidMainFlow; -pub use bindings::{DiceResult_kDiceResultBufferTooSmall, DiceResult_kDiceResultOk, DiceResult_kDiceResultInvalidInput, DiceResult_kDiceResultPlatformError}; -pub use bindings::DiceDeriveCdiPrivateKeySeed; -pub use bindings::SM2KeypairFromSeed; -pub use bindings::{DICE_ANDROID_CONFIG_COMPONENT_NAME, DICE_ANDROID_CONFIG_COMPONENT_VERSION, DICE_ANDROID_CONFIG_RESETTABLE, DICE_ANDROID_CONFIG_RKP_VM_MARKER, DICE_ANDROID_CONFIG_SECURITY_VERSION}; pub use bindings::DiceAndroidConfigValues; pub use bindings::DiceAndroidFormatConfigDescriptor; -pub use bindings::DiceMainFlow; pub use bindings::DiceAndroidHandoverParse; +pub use bindings::DiceAndroidMainFlow; +pub use bindings::DiceDeriveCdiPrivateKeySeed; +pub use bindings::DiceMainFlow; +pub use bindings::SM2KeypairFromSeed; +pub use bindings::{ + DICE_ANDROID_CONFIG_COMPONENT_NAME, DICE_ANDROID_CONFIG_COMPONENT_VERSION, + DICE_ANDROID_CONFIG_RESETTABLE, DICE_ANDROID_CONFIG_RKP_VM_MARKER, + DICE_ANDROID_CONFIG_SECURITY_VERSION, +}; +pub use bindings::{ + DiceConfigType, DiceConfigType_kDiceConfigTypeDescriptor, DiceConfigType_kDiceConfigTypeInline, +}; +pub use bindings::{DiceInputValues, DiceInputValues_}; +pub use bindings::{DiceMode, DiceMode_kDiceModeDebug, DiceMode_kDiceModeNormal}; +pub use bindings::{ + DiceResult_kDiceResultBufferTooSmall, DiceResult_kDiceResultInvalidInput, + DiceResult_kDiceResultOk, DiceResult_kDiceResultPlatformError, +}; pub fn dice_parse_handover<'a>(buffer: &'a [u8]) -> Result<(&'a [u8], &'a [u8], &'a [u8]), u32> { let mut cdi_attest_ptr: *const u8 = core::ptr::null(); diff --git a/src/mbedtls_sm2dsa.rs b/src/mbedtls_sm2dsa.rs index 8999547..b6848e3 100644 --- a/src/mbedtls_sm2dsa.rs +++ b/src/mbedtls_sm2dsa.rs @@ -1,7 +1,7 @@ +use mbedtls::bignum::Mpi; +use mbedtls::ecp::{EcGroup, EcPoint}; use mbedtls::hash::{Hmac, Type as HashType}; use mbedtls::pk::{EcGroupId, Pk, Type as PkType}; -use mbedtls::ecp::{EcGroup, EcPoint}; -use mbedtls::bignum::Mpi; use mbedtls::rng::HmacDrbg as MbedtlsHmacDrbg; // 重新定义常量(如果在其他地方没有定义的话) @@ -9,15 +9,8 @@ const DICE_PRIVATE_KEY_BUFFER_SIZE: usize = 32; const DICE_SIGNATURE_BUFFER_SIZE: usize = 64; const DICE_PUBLIC_KEY_BUFFER_SIZE: usize = 64; - // 基于mbedtls-rust库的实现 -pub fn hmac_rust( - key: &[u8], - input: &[u8; 64], - output: &mut [u8], - out_len: usize, -) -> i32 { - +pub fn hmac_rust(key: &[u8], input: &[u8; 64], output: &mut [u8], out_len: usize) -> i32 { match Hmac::hmac(HashType::SM3, key, input, output) { Ok(len) => { let copy_len = std::cmp::min(out_len, len); @@ -52,7 +45,7 @@ pub fn hmac3_rust( } match Hmac::hmac(HashType::SM3, key, &combined_data, out) { - Ok(_) => 0, // 成功 + Ok(_) => 0, // 成功 Err(_) => -1, // HMAC计算失败 } } @@ -154,7 +147,9 @@ pub fn sm2_keypair_from_seed( let generator = curve.generator().map_err(|_| -1)?; // 计算公钥点: Q = d * G - let public_point = generator.mul_with_rng(&mut curve, &private_mpi, &mut rng).map_err(|_| -1)?; + let public_point = generator + .mul_with_rng(&mut curve, &private_mpi, &mut rng) + .map_err(|_| -1)?; // 将公钥点导出为字节数组 (未压缩格式: 0x04 || X || Y) let curve_ref = &curve; @@ -170,7 +165,6 @@ pub fn sm2_keypair_from_seed( Ok(()) } - /// SM2 签名 /// /// # 参数 @@ -204,10 +198,13 @@ pub fn sm2_sign( private_mpi, &mut rng, PkType::SM2.into(), - ).map_err(|_| -1)?; + ) + .map_err(|_| -1)?; // 使用 SM3 哈希对消息进行签名 - let sig_len = pk.sign(HashType::SM3, message, signature, &mut rng).map_err(|_| -1)?; + let sig_len = pk + .sign(HashType::SM3, message, signature, &mut rng) + .map_err(|_| -1)?; // 验证签名长度(SM2 签名应该是 64 字节) if sig_len != 64 { @@ -227,11 +224,7 @@ pub fn sm2_sign( /// # 返回 /// * `Ok(())` - 验证成功 /// * `Err(i32)` - 验证失败 -pub fn sm2_verify( - message: &[u8], - signature: &[u8; 64], - public_key: &[u8; 64], -) -> Result<(), i32> { +pub fn sm2_verify(message: &[u8], signature: &[u8; 64], public_key: &[u8; 64]) -> Result<(), i32> { // 创建 SM2 曲线组 let curve = EcGroup::new(EcGroupId::SM2P256R1).map_err(|_| -1)?; // 从公钥创建 EcPoint @@ -241,67 +234,61 @@ pub fn sm2_verify( let public_point = EcPoint::from_components(x_mpi, y_mpi).map_err(|_| -1)?; // 从公钥创建 Pk 对象 - let mut pk = Pk::public_from_ec_components_extend( - curve, - public_point, - PkType::SM2.into(), - ).map_err(|_| -1)?; + let mut pk = Pk::public_from_ec_components_extend(curve, public_point, PkType::SM2.into()) + .map_err(|_| -1)?; // 使用 SM3 哈希验证签名 - pk.verify(HashType::SM3, message, signature).map_err(|_| -1)?; + pk.verify(HashType::SM3, message, signature) + .map_err(|_| -1)?; Ok(()) } /// 从种子生成 SM2 密钥对(Rust 风格) -/// +/// /// # 参数 /// * `seed` - 32字节种子数据 -/// +/// /// # 返回 /// * `Ok(([u8; 64], [u8; 32]))` - 成功时返回 (公钥, 私钥) 元组 /// * `Err(i32)` - 失败,返回错误码 -pub fn dice_keypair_from_seed( - seed: &[u8; 32], -) -> Result<([u8; 64], [u8; 32]), i32> { +pub fn dice_keypair_from_seed(seed: &[u8; 32]) -> Result<([u8; 64], [u8; 32]), i32> { let mut public_key = [0u8; 64]; let mut private_key = [0u8; 32]; - + // 调用现有的 sm2_keypair_from_seed 函数 sm2_keypair_from_seed(&mut public_key, &mut private_key, seed)?; - + Ok((public_key, private_key)) } - /// SM2 签名函数 -/// +/// /// # 参数 /// * `message` - 待签名的消息 /// * `private_key` - 32字节的私钥 -/// +/// /// # 返回 /// * `Ok([u8; 64])` - 64字节的签名 (R 32字节 || S 32字节) /// * `Err(i32)` - 失败,返回错误码 pub fn dice_sign( + _context: &mut u8, message: &[u8], private_key: &[u8; DICE_PRIVATE_KEY_BUFFER_SIZE], -) -> Result<[u8; DICE_SIGNATURE_BUFFER_SIZE], i32> { - let mut signature = [0u8; DICE_SIGNATURE_BUFFER_SIZE]; - + signature: &mut [u8; DICE_SIGNATURE_BUFFER_SIZE], +) -> Result<(), i32> { // 调用现有的 sm2_sign 函数 - sm2_sign(&mut signature, message, private_key)?; - - Ok(signature) + sm2_sign(signature, message, private_key)?; + Ok(()) } /// SM2 签名验证函数 -/// +/// /// # 参数 /// * `message` - 待验证的消息 /// * `signature` - 64字节的签名 /// * `public_key` - 64字节的公钥 (X 32字节 || Y 32字节) -/// +/// /// # 返回 /// * `Ok(())` - 验证成功 /// * `Err(i32)` - 验证失败 @@ -314,26 +301,27 @@ pub fn dice_verify( sm2_verify(message, signature, public_key) } - use mbedtls::hash::{Hkdf, Md, Type as MdType}; // 定义常量 const DICE_HASH_SIZE: usize = 32; // SM3 输出大小 /// SM3 哈希函数,原来于博用的MBEDTLS_MD_SHA512。 -/// +/// /// # 参数 /// * `input` - 输入数据 -/// +/// /// # 返回 /// * `Ok([u8; 32])` - 32字节的SM3哈希值 /// * `Err(i32)` - 失败,返回错误码 -pub fn dice_hash(input: &[u8]) -> Result<[u8; DICE_HASH_SIZE], i32> { - let mut output = [0u8; DICE_HASH_SIZE]; - +pub fn dice_hash( + _context: &mut u8, + input: &[u8], + output: &mut [u8; DICE_HASH_SIZE], +) -> Result<(), i32> { // 使用 mbedtls-rust 的 Md::hash 函数 - match Md::hash(MdType::SM3, input, &mut output) { - Ok(_) => Ok(output), + match Md::hash(MdType::SM3, input, output) { + Ok(_) => Ok(()), Err(_) => Err(-1), // 转换为错误码 } } @@ -349,15 +337,15 @@ pub fn dice_hash(input: &[u8]) -> Result<[u8; DICE_HASH_SIZE], i32> { /// # 返回 /// * `Ok(Vec)` - HKDF 输出 /// * `Err(i32)` - 失败,返回错误码 -pub fn dice_kdf(length: usize, ikm: &[u8], salt: Option<&[u8]>, info: Option<&[u8]>) -> Result, i32> { - let mut output = vec![0u8; length]; - +pub fn dice_kdf( + ikm: &[u8], + salt: Option<&[u8]>, + info: Option<&[u8]>, + output: &mut [u8], +) -> Result<(), i32> { // 使用 mbedtls-rust 的 HKDF 功能 - match Hkdf::hkdf_optional_salt(MdType::SM3, salt, ikm, info.unwrap_or(&[]), &mut output) { - Ok(_) => Ok(output), + match Hkdf::hkdf_optional_salt(MdType::SM3, salt, ikm, info.unwrap_or(&[]), output) { + Ok(_) => Ok(()), Err(_) => Err(-1), // 转换为错误码 } } - - - -- Gitee