You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中如何使用预编码DER片段构造ASN.1 SEQUENCE的DER编码

问题描述

我需要在Rust中对如下ASN.1结构执行DER编码:

issuerAndSubject ::= SEQUENCE {
    issuer     Name,
    subject    Name
}

上述结构中的Name结构定义于RFC5280标准,逻辑较为复杂,我不希望在Rust代码中重新实现该结构的定义。

我已经通过rust-openssl库创建得到了issuer和subject两个对象:

let issuer: &X509NameRef = get_issuer();
let subject: &X509NameRef = get_subject();

我可以很便捷地获取这两个对象对应的DER编码结果:

let issuer_der = issuer.to_der().unwrap();
let subject_der = subject.to_der().unwrap();

但我需要将这两段已编码的DER数据封装到一个SEQUENCE结构中。我优先选择使用Rust的asn1 crate来创建SEQUENCE,当前编写的示例代码如下:

let ias_der = asn1::write(|w| {
        w.write_element(
            &asn1::SequenceWriter::new(&|w| {
                w.write_element(&issuer_der);   // I know, this doesn't work, but
                w.write_element(&subject_der);  // how do I do it?
        }));
    });

核心诉求:是否存在可行的实现方式,能够直接使用已完成DER编码的数据构造目标SEQUENCE结构?

实现方案

基于asn1 crate的原生实现

你的代码无法正常运行的原因是write_element接收的是实现了Asn1Writable trait的类型,对于已经编码完成的完整DER片段,直接调用write_der方法写入即可,该方法会直接将合法的DER编码字节作为完整元素写入当前序列,不需要额外解析或重构,修正后的代码如下:

let ias_der = asn1::write(|w| {
    w.write_element(&asn1::SequenceWriter::new(&|w| {
        w.write_der(&issuer_der).unwrap();
        w.write_der(&subject_der).unwrap();
    }))
}).unwrap();

注意:write_der要求传入的字节必须是完整合法的DER TLV结构,X509NameRef::to_der()返回的结果刚好是符合要求的完整Name结构编码,可直接使用。

手动拼接DER结构(无额外依赖)

如果不想依赖asn1 crate的特定API,也可以按照DER编码规则手动拼接SEQUENCE结构,逻辑非常简单:

  • 计算所有内部元素的总字节长度:两个DER片段的长度相加
  • 生成SEQUENCE结构的TLV头:固定tag值为构造式通用SEQUENCE即0x30,后接DER规则编码的长度值
  • 按顺序拼接SEQUENCE头、issuer_der、subject_der即可得到最终结果

手动实现的参考代码:

fn wrap_der_sequence(elements: &[&[u8]]) -> Vec<u8> {
    let content_total_len: usize = elements.iter().map(|elem| elem.len()).sum();
    let mut result = Vec::new();
    // 写入SEQUENCE标签
    result.push(0x30);
    // 按DER规则编码长度字段
    match content_total_len {
        len if len < 128 => result.push(len as u8),
        len => {
            let len_be = len.to_be_bytes();
            let valid_len_bytes = len_be.iter().skip_while(|&&b| b == 0).copied().collect::<Vec<u8>>();
            result.push(0x80 | valid_len_bytes.len() as u8);
            result.extend_from_slice(&valid_len_bytes);
        }
    }
    // 拼接所有内部已编码元素
    for elem in elements {
        result.extend_from_slice(elem);
    }
    result
}

// 调用示例
let ias_der = wrap_der_sequence(&[&issuer_der, &subject_der]);

两种方案生成的编码结果完全符合DER规范,均不需要重新实现RFC5280中定义的Name结构。

内容的提问来源于stack exchange,提问作者kletterstein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 12:36:22