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(())
}

主要功能

  1. 支持多种CMS数据类型:

    • ContentInfo
    • SignedData
    • EncryptedData
    • EnvelopedData
    • 等等
  2. 编码/解码支持:

    • 支持DER和BER编码格式
    • 高效的类型转换
  3. 类型安全:

    • 严格的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()],
    }
}

性能提示

  1. 对于大型CMS数据,考虑使用流式处理
  2. 重复解析相同结构时,可以重用分配的内存
  3. 启用rasnalloc特性可以减少内存分配

错误处理

rasn-cms使用rasn::de::Errorrasn::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消息验证成功!");
    }
}
回到顶部