Skip to main content

ferritls_core/
der.rs

1//! 最小 DER 解析:PKCS#8 / SEC1 / PKCS#1 私钥与 SPKI 公钥的拆包。
2//!
3//! 只为 [`crate::sign`] 的密钥加载与 rustls `KeyProvider` 服务,
4//! **不是**通用 ASN.1 库。X.509 证书解析由 rustls-webpki 负责,在边界外。
5//!
6//! 安全:解析对象为攻击者可控输入——任何畸形输入返回
7//! [`Error::InvalidInput`](crate::Error),绝不 panic、绝不越界。
8
9use crate::Error;
10
11/// 算法 OID(DER 编码的 AlgorithmIdentifier 内容里常用值)。
12pub mod oid {
13    /// id-ecPublicKey(1.2.840.10045.2.1)
14    pub const EC_PUBLIC_KEY: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01];
15    /// prime256v1(1.2.840.10045.3.1.7)
16    pub const PRIME256V1: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07];
17    /// secp384r1(1.3.132.0.34)
18    pub const SECP384R1: &[u8] = &[0x2b, 0x81, 0x04, 0x00, 0x22];
19    /// rsaEncryption(1.2.840.113549.1.1.1)
20    pub const RSA_ENCRYPTION: &[u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01];
21    /// Ed25519(1.3.101.112)
22    pub const ED25519: &[u8] = &[0x2b, 0x65, 0x70];
23}
24
25/// 读取一个 TLV 元素:返回 (tag, 内容切片, 剩余字节)。
26pub fn read_tlv(input: &[u8]) -> Result<(u8, &[u8], &[u8]), Error> {
27    if input.len() < 2 {
28        return Err(Error::InvalidInput);
29    }
30    let tag = input[0];
31    // 长度首字节
32    let first = input[1] as usize;
33    let (len, rest_off) = if first < 0x80 {
34        (first, 2)
35    } else {
36        let n = first & 0x7f;
37        // 长度过长(>4 字节)或非最短编码一律拒绝
38        if n == 0 || n > 4 || n + 2 > input.len() {
39            return Err(Error::InvalidInput);
40        }
41        let mut len = 0usize;
42        for k in 0..n {
43            len = (len << 8) | input[2 + k] as usize;
44        }
45        // 非最短编码拒绝(首字节为 0;或长度 < 0x80 却用了长形式)
46        if input[2] == 0 || len < 0x80 {
47            return Err(Error::InvalidInput);
48        }
49        (len, 2 + n)
50    };
51    if rest_off + len > input.len() {
52        return Err(Error::InvalidInput);
53    }
54    Ok((
55        tag,
56        &input[rest_off..rest_off + len],
57        &input[rest_off + len..],
58    ))
59}
60
61/// 期望指定 tag 的 TLV。
62pub fn expect(tag: u8, input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
63    let (t, content, rest) = read_tlv(input)?;
64    if t != tag {
65        return Err(Error::InvalidInput);
66    }
67    Ok((content, rest))
68}
69
70/// SEQUENCE 内容。
71pub fn sequence(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
72    expect(0x30, input)
73}
74
75/// OCTET STRING 内容。
76pub fn octet_string(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
77    expect(0x04, input)
78}
79
80/// BIT STRING:去掉首个未使用位数 octet(必须为 0)。
81pub fn bit_string(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
82    let (content, rest) = expect(0x03, input)?;
83    if content.is_empty() || content[0] != 0 {
84        return Err(Error::InvalidInput);
85    }
86    Ok((&content[1..], rest))
87}
88
89/// OBJECT IDENTIFIER(返回原始内容字节)。
90pub fn object_identifier(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
91    expect(0x06, input)
92}
93
94/// INTEGER:去除符号前导零后的绝对值字节(正数)。
95/// 解析 INTEGER 内容(DER 最短编码)。
96pub fn integer(input: &[u8]) -> Result<(&[u8], &[u8]), Error> {
97    let (content, rest) = expect(0x02, input)?;
98    if content.is_empty() {
99        return Err(Error::InvalidInput);
100    }
101    // 正整数:首字节高位为 0,或长度 1
102    if content[0] & 0x80 != 0 {
103        return Err(Error::InvalidInput);
104    }
105    // DER 最短编码:前导 0x00 只允许出现一次且仅在次字节高位为 1 时
106    // ("prepending 0's" 类攻击即利用宽容解析器)
107    if content.len() >= 2 && content[0] == 0 && content[1] & 0x80 == 0 {
108        return Err(Error::InvalidInput);
109    }
110    // 去除唯一合法的前导零
111    let mut s = 0;
112    while s + 1 < content.len() && content[s] == 0 {
113        s += 1;
114    }
115    Ok((&content[s..], rest))
116}
117
118/// 解析后的私钥内容(按算法分派给 [`crate::sign`] 各类型)。
119#[derive(Debug)]
120pub enum ParsedPrivateKey {
121    /// P-256:32 字节标量与(可选携带的)未压缩 SEC1 公钥点。
122    P256 {
123        /// SEC1 privateKey OCTET STRING 内的标量。
124        scalar: [u8; 32],
125        /// 未压缩 SEC1 公钥点(0x04||X||Y),SEC1 结构中可选携带。
126        public_sec1: Option<Vec<u8>>,
127    },
128    /// P-384:48 字节标量与(可选携带的)未压缩 SEC1 公钥点。
129    P384 {
130        /// SEC1 privateKey OCTET STRING 内的标量。
131        scalar: [u8; 48],
132        /// 未压缩 SEC1 公钥点。
133        public_sec1: Option<Vec<u8>>,
134    },
135    /// RSA PKCS#1 私钥(DER 内容,供 sign::rsa 二次解析)。
136    RsaPkcs1(Vec<u8>),
137    /// Ed25519:32 字节种子。
138    Ed25519(Vec<u8>),
139}
140
141/// 解析 PKCS#8 PrivateKeyInfo(RFC 5958/5208)。
142///
143/// PrivateKeyInfo ::= SEQUENCE {
144///   version INTEGER (0),
145///   privateKeyAlgorithm AlgorithmIdentifier,
146///   privateKey OCTET STRING,
147///   `attributes [0] IMPLICIT OPTIONAL` }
148pub fn parse_pkcs8_private_key(der: &[u8]) -> Result<ParsedPrivateKey, Error> {
149    let (seq, rest) = sequence(der)?;
150    // PKCS#8 后不得有剩余字节
151    if !rest.is_empty() {
152        return Err(Error::InvalidInput);
153    }
154    let (version, rest) = integer(seq)?;
155    if version.len() != 1 || version[0] != 0 {
156        return Err(Error::InvalidInput);
157    }
158    // AlgorithmIdentifier ::= SEQUENCE { algorithm OID, parameters ANY }
159    let (alg_seq, rest) = sequence(rest)?;
160    let (oid, alg_rest) = object_identifier(alg_seq)?;
161    let (_ptag, _params, _alg_rest_rest) = match read_tlv(alg_rest) {
162        Ok(x) => x,
163        Err(_) => return Err(Error::InvalidInput),
164    };
165    let (key_bytes, rest) = octet_string(rest)?;
166    // [0] attributes 可选——存在则忽略,但必须是 context-tag 0
167    if !rest.is_empty() && rest[0] != 0xa0 {
168        return Err(Error::InvalidInput);
169    }
170
171    if oid == oid::ED25519 {
172        // Ed25519 私钥 = OCTET STRING(32)
173        let (seed, inner_rest) = octet_string(key_bytes)?;
174        if !inner_rest.is_empty() || seed.len() != 32 {
175            return Err(Error::InvalidInput);
176        }
177        return Ok(ParsedPrivateKey::Ed25519(seed.to_vec()));
178    }
179    if oid == oid::RSA_ENCRYPTION {
180        // privateKey OCTET STRING 的内容即 PKCS#1 RSAPrivateKey DER
181        //(RSA 不再包一层 OCTET STRING;Ed25519 才是双层包裹)
182        return Ok(ParsedPrivateKey::RsaPkcs1(key_bytes.to_vec()));
183    }
184    if oid == oid::EC_PUBLIC_KEY {
185        // parameters = namedCurve OID(TLV:tag 0x06 + 长度 + OID 内容)
186        let (ptag, params, _alg_rest_rest) = read_tlv(alg_rest)?;
187        if ptag != 0x06 {
188            return Err(Error::InvalidInput);
189        }
190        let curve_oid = params;
191        let curve = if curve_oid == oid::PRIME256V1 {
192            32usize
193        } else if curve_oid == oid::SECP384R1 {
194            48usize
195        } else {
196            return Err(Error::InvalidInput);
197        };
198        // SEC1 ECPrivateKey ::= SEQUENCE { version INTEGER(1), privateKey OCTET STRING,
199        //   publicKey [1] BIT STRING OPTIONAL }
200        let (sec1, sec1_rest) = sequence(key_bytes)?;
201        if !sec1_rest.is_empty() {
202            return Err(Error::InvalidInput);
203        }
204        let (sec_ver, sec1_rest) = integer(sec1)?;
205        if sec_ver.len() != 1 || sec_ver[0] != 1 {
206            return Err(Error::InvalidInput);
207        }
208        let (priv_key, sec1_rest) = octet_string(sec1_rest)?;
209        if priv_key.len() != curve || !sec1_rest.is_empty() && sec1_rest[0] != 0xa1 {
210            return Err(Error::InvalidInput);
211        }
212        // 可选公钥 [1]:两种现实编码都要接受——
213        //  - [1] EXPLICIT:内容 = 内层 BIT STRING TLV(openssl 产物);
214        //  - [1] IMPLICIT:内容 = 未使用位数(0x00)+ 未压缩 SEC1 点。
215        let mut public_sec1 = None;
216        if !sec1_rest.is_empty() {
217            let (ptag, content, pub_rest) = read_tlv(sec1_rest)?;
218            if ptag != 0xa1 || !pub_rest.is_empty() || content.is_empty() {
219                return Err(Error::InvalidInput);
220            }
221            let point: &[u8] = if content[0] == 0x03 {
222                let (itag, bits, rest2) = read_tlv(content)?;
223                if itag != 0x03 || !rest2.is_empty() || bits.is_empty() || bits[0] != 0 {
224                    return Err(Error::InvalidInput);
225                }
226                &bits[1..]
227            } else if content[0] == 0x00 {
228                &content[1..]
229            } else {
230                return Err(Error::InvalidInput);
231            };
232            if point.len() != 1 + 2 * curve || point[0] != 0x04 {
233                return Err(Error::InvalidInput);
234            }
235            public_sec1 = Some(point.to_vec());
236        }
237        let mut scalar = [0u8; 48];
238        scalar[..curve].copy_from_slice(priv_key);
239        return if curve == 32 {
240            let mut s256 = [0u8; 32];
241            s256.copy_from_slice(&scalar[..32]);
242            Ok(ParsedPrivateKey::P256 {
243                scalar: s256,
244                public_sec1,
245            })
246        } else {
247            Ok(ParsedPrivateKey::P384 {
248                scalar,
249                public_sec1,
250            })
251        };
252    }
253    Err(Error::InvalidInput)
254}