Rust ASN.1编解码库rasn-cms的使用,支持高效解析和生成CMS(Cryptographic Message Syntax)格式数据
Rust ASN.1编解码库rasn-cms的使用,支持高效解析和生成CMS(Cryptographic Message Syntax)格式数据
rasn-cms
是一个实现了 IETF RFC 4108、RFC 5083、RFC 5084 和 RFC 5652 中定义的数据类型的库。这些标准也被称为 Cryptographic Message Syntax (CMS) 或 PKCS#7。
该库不提供CMS生成器或验证器的实现,而是提供了底层数据类型的实现,用于从DER或BER解码和编码CMS结构。
安装
在项目目录中运行以下Cargo命令:
cargo add rasn-cms
或者在Cargo.toml中添加以下行:
rasn-cms = "0.27.0"
使用示例
以下是一个完整的示例,展示如何使用rasn-cms
库来解析和生成CMS格式数据:
use rasn_cms::{ContentInfo, SignedData};
use rasn::der;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 示例DER编码的CMS数据
let der_data = hex::decode("3082020b06092a864886f70d010703a08201fc3081f8020101310f300d060960864801650304020105003081c906092a864886f70d010701a081bb0481b81581b53081b2300d0609608648016503040201050003819f0030819c0201003074300b0609608648016503040201300b06092a864886f70d010701301c06092a864886f70d010905310f170d3737303130313030303030305a301f06092a864886f70d010904311204103f4c3b3a4d3b3a4d3b3a4d3b3a4d3b3a300b06092a864886f70d010910300d060960864801650304020105000414f1d619e3e5e3e5e3e5e3e5e3e5e3e5e3e5e3e5e3e5")?;
// 解码ContentInfo
let content_info: ContentInfo = der::decode(&der_data)?;
println!("Decoded ContentInfo: {:?}", content_info);
// 如果是SignedData,可以进一步解码
if let Some(signed_data) = content_info.signed_data {
let signed_data: SignedData = der::decode(&signed_data.content)?;
println!("Decoded SignedData: {:?}", signed_data);
}
// 编码回DER
let encoded = der::encode(&content_info)?;
println!("Re-encoded data matches original: {}", encoded == der_data);
Ok(())
}
完整示例代码
以下是一个更完整的示例,展示如何创建、编码和解码CMS数据:
use rasn_cms::{ContentInfo, ContentType, SignedData, EncapsulatedContentInfo};
use rasn::{der, types::ObjectIdentifier};
use hex_literal::hex;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 创建一个简单的SignedData结构
let signed_data = SignedData {
version: rasn_cms::Version::v1(),
digest_algorithms: vec![],
encap_content_info: EncapsulatedContentInfo {
econtent_type: ContentType::DATA,
econtent: None,
},
certificates: None,
crls: None,
signer_infos: vec![],
};
// 2. 将SignedData编码为DER格式
let signed_data_der = der::encode(&signed_data)?;
// 3. 创建ContentInfo包装器
let content_info = ContentInfo {
content_type: ContentType::SIGNED_DATA,
content: Some(signed_data_der.clone()),
signed_data: Some(signed_data),
};
// 4. 编码整个ContentInfo
let encoded = der::encode(&content_info)?;
println!("Encoded CMS data (hex): {}", hex::encode(&encoded));
// 5. 解码过程
let decoded: ContentInfo = der::decode(&encoded)?;
println!("Decoded ContentInfo: {:?}", decoded);
// 6. 验证解码后的数据
if let Some(sd) = decoded.signed_data {
let reencoded = der::encode(&sd)?;
assert_eq!(reencoded, signed_data_der);
println!("Data verified successfully!");
}
Ok(())
}
主要功能
-
支持多种CMS数据类型:
- ContentInfo
- SignedData
- EncryptedData
- EnvelopedData
- 等等
-
编码/解码支持:
- 支持DER和BER编码格式
- 高效的类型转换
-
类型安全:
- 严格的ASN.1类型系统
- 编译时类型检查
许可证
该项目采用MIT或Apache-2.0双重许可。
1 回复
Rust ASN.1编解码库rasn-cms使用指南
rasn-cms是一个专门用于处理CMS(Cryptographic Message Syntax)格式数据的Rust库,它基于ASN.1标准实现,提供了高效的解析和生成功能。
特性
- 完全支持RFC 5652定义的CMS标准
- 基于rasn框架的ASN.1编解码
- 零拷贝解析
- 类型安全的API设计
- 支持DER和BER编码格式
安装
在Cargo.toml中添加依赖:
[dependencies]
rasn-cms = "0.3"
基本用法
解析CMS数据
use rasn_cms::{ContentInfo, SignedData};
fn parse_cms(der_data: &[u8]) -> Result<(), rasn::de::Error> {
let info: ContentInfo = rasn::der::decode(der_data)?;
if let ContentInfo::SignedData(data) = info {
let signed_data: SignedData = rasn::der::decode(&data.content)?;
println!("Parsed SignedData with {} signers", signed_data.signer_infos.len());
}
Ok(())
}
生成CMS数据
use rasn_cms::{
ContentInfo, SignedData, EncapsulatedContentInfo,
SignerInfo, IssuerAndSerialNumber, AlgorithmIdentifier
};
use rasn::types::ObjectIdentifier;
fn create_signed_data() -> Result<Vec<u8>, rasn::enc::Error> {
let signed_data = SignedData {
version: rasn_cms::CMSVersion::V1,
digest_algorithms: vec![
AlgorithmIdentifier {
algorithm: ObjectIdentifier::new(vec![1, 2, 840, 113549, 1, 1, 11]), // sha256WithRSAEncryption
parameters: Some(rasn::der::encode(&())?),
},
],
encap_content_info: EncapsulatedContentInfo {
content_type: ObjectIdentifier::new(vec![1, 2, 840, 113549, 1, 7, 1]), // data
content: None,
},
certificates: None,
signer_infos: vec![
SignerInfo {
version: rasn_cms::CMSVersion::V1,
sid: IssuerAndSerialNumber {
issuer: rasn_cms::Name::new(),
serial_number: rasn_cms::CertificateSerialNumber::from(123456),
},
digest_algorithm: AlgorithmIdentifier {
algorithm: ObjectIdentifier::new(vec![1, 2, 840, 113549, 1, 1, 11]),
parameters: Some(rasn::der::encode(&())?),
},
signature_algorithm: AlgorithmIdentifier {
algorithm: ObjectIdentifier::new(vec![1, 2, 840, 113549, 1, 1, 1]),
parameters: Some(rasn::der::encode(&())?),
},
signature: vec![0x01, 0x02, 0x03].into(),
},
],
};
let content_info = ContentInfo::SignedData(rasn::der::encode(&signed_data)?);
rasn::der::encode(&content_info)
}
高级功能
处理加密数据
use rasn_cms::{ContentInfo, EnvelopedData};
fn parse_enveloped_data(der_data: &[u8]) -> Result<(), rasn::de::Error> {
let info: ContentInfo = rasn::der::decode(der_data)?;
if let ContentInfo::EnvelopedData(data) = info {
let enveloped_data: EnvelopedData = rasn::der::decode(&data.content)?;
println!("Found {} recipient infos", enveloped_data.recipient_infos.len());
}
Ok(())
}
自定义扩展
rasn-cms支持通过扩展处理自定义属性:
use rasn_cms::{Attribute, ObjectIdentifier};
fn create_custom_attribute() -> Attribute {
Attribute {
attr_type: ObjectIdentifier::new(vec![1, 3, 6, 1, 4, 1, 54321, 极客时间, 1, 1]), // 自定义OID
attr_values: vec![rasn::der::encode("custom value").unwrap()],
}
}
性能提示
- 对于大型CMS数据,考虑使用流式处理
- 重复解析相同结构时,可以重用分配的内存
- 启用
rasn
的alloc
特性可以减少内存分配
错误处理
rasn-cms使用rasn::de::Error
和rasn::enc::Error
来处理编解码错误:
fn handle_cms(data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
match rasn::der::decode::<ContentInfo>(data) {
Ok(info) => {
// 处理成功
Ok(())
}
Err(e) => {
eprintln!("CMS解析失败: {}", e);
Err(Box::new(e))
}
}
}
rasn-cms为Rust开发者提供了处理CMS格式数据的强大工具,特别适合需要处理数字签名、加密消息等安全相关数据的应用场景。
完整示例
以下是一个完整的CMS签名和验证示例:
use rasn_cms::{
ContentInfo, SignedData, EncapsulatedContentInfo,
SignerInfo, IssuerAndSerialNumber, AlgorithmIdentifier,
ContentType, CMSVersion
};
use rasn::types::ObjectIdentifier;
use rasn::{der, Decode, Encode};
// 创建一个简单的CMS签名数据
fn create_signed_message() -> Vec<u8> {
// 1. 准备签名数据
let signed_data = SignedData {
version: CMSVersion::V1,
digest_algorithms: vec![
AlgorithmIdentifier {
algorithm: ObjectIdentifier::new(vec![1, 2, 840, 113549, 1, 1, 11]), // sha256WithRSAEncryption
parameters: Some(der::encode(&()).unwrap()),
},
],
encap_content_info: EncapsulatedContentInfo {
content_type: ContentType::Data,
content: None,
},
certificates: None,
signer_infos: vec![
SignerInfo {
version: CMSVersion::V1,
sid: IssuerAndSerialNumber {
issuer: Default::default(),
serial_number: 12345.into(),
},
digest_algorithm: AlgorithmIdentifier {
algorithm: ObjectIdentifier::new(vec![1, 2, 840, 113549, 1, 1, 11]),
parameters: Some(der::encode(&()).unwrap()),
},
signature_algorithm: AlgorithmIdentifier {
algorithm: ObjectIdentifier::new(vec![1, 2, 840, 113549, 1, 1, 1]),
parameters: Some(der::encode(&()).unwrap()),
},
signature: vec![0x01, 0x02, 0x03].into(),
},
],
};
// 2. 编码为DER格式
let signed_data_der = der::encode(&signed_data).unwrap();
// 3. 创建ContentInfo包装
let content_info = ContentInfo::SignedData(signed_data_der);
// 4. 最终编码
der::encode(&content_info).unwrap()
}
// 验证CMS签名数据
fn verify_signed_message(data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
// 1. 解码ContentInfo
let content_info: ContentInfo = der::decode(data)?;
// 2. 检查是否是签名数据
if let ContentInfo::SignedData(encoded_sd) = content_info {
// 3. 解码SignedData
let signed_data: SignedData = der::decode(&encoded_sd)?;
// 4. 验证签名者信息
println!("找到 {} 个签名者", signed_data.signer_infos.len());
for signer in signed_data.signer_infos {
println!("签名者序列号: {}", signer.sid.serial_number);
// 这里应该添加实际的签名验证逻辑
}
}
Ok(())
}
fn main() {
// 创建并验证CMS消息
let cms_data = create_signed_message();
if let Err(e) = verify_signed_message(&cms_data) {
eprintln!("验证失败: {}", e);
} else {
println!("CMS消息验证成功!");
}
}