1use alloc::vec::Vec;
18
19use super::der::{DerError, Reader};
20
21const TAG_SEQUENCE: u8 = 0x30;
22const TAG_INTEGER: u8 = 0x02;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum EcdsaError {
27 Der(DerError),
29 InvalidOutputLength,
31 Negative,
33 IntegerTooLarge,
35}
36
37impl core::fmt::Display for EcdsaError {
38 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
39 match self {
40 EcdsaError::Der(err) => write!(f, "{err}"),
41 EcdsaError::InvalidOutputLength => write!(f, "output length must be a non-zero multiple of two"),
42 EcdsaError::Negative => write!(f, "ECDSA integer is negative"),
43 EcdsaError::IntegerTooLarge => write!(f, "ECDSA integer does not fit in the output"),
44 }
45 }
46}
47
48impl From<DerError> for EcdsaError {
49 fn from(err: DerError) -> Self {
50 EcdsaError::Der(err)
51 }
52}
53
54impl core::error::Error for EcdsaError {}
55
56fn push_length(out: &mut Vec<u8>, len: usize) {
57 if len < 0x80 {
58 out.push(len as u8);
59 return;
60 }
61 let bytes = len.to_be_bytes();
62 let first = bytes.iter().position(|b| *b != 0).unwrap_or(bytes.len() - 1);
63 let significant = &bytes[first..];
64 out.push(0x80 | significant.len() as u8);
65 out.extend_from_slice(significant);
66}
67
68fn encode_integer(value: &[u8], out: &mut Vec<u8>) {
69 let mut start = 0;
71 while start + 1 < value.len() && value[start] == 0 {
72 start += 1;
73 }
74 let value = &value[start..];
75
76 let pad = value[0] & 0x80 != 0;
79
80 out.push(TAG_INTEGER);
81 push_length(out, value.len() + pad as usize);
82 if pad {
83 out.push(0x00);
84 }
85 out.extend_from_slice(value);
86}
87
88pub fn encode_signature_der(r: &[u8], s: &[u8]) -> Vec<u8> {
91 let mut body = Vec::with_capacity(r.len() + s.len() + 8);
92 encode_integer(r, &mut body);
93 encode_integer(s, &mut body);
94
95 let mut out = Vec::with_capacity(body.len() + 4);
96 out.push(TAG_SEQUENCE);
97 push_length(&mut out, body.len());
98 out.extend_from_slice(&body);
99 out
100}
101
102fn write_fixed(value: &[u8], out: &mut [u8]) -> Result<(), EcdsaError> {
103 let (negative, value) = match value {
106 [0x00, rest @ ..] => (false, rest),
107 [first, ..] => (first & 0x80 != 0, value),
108 [] => (false, value),
109 };
110 if negative {
111 return Err(EcdsaError::Negative);
112 }
113 if value.is_empty() {
114 return Ok(());
116 }
117 if value.len() > out.len() {
118 return Err(EcdsaError::IntegerTooLarge);
119 }
120 let start = out.len() - value.len();
121 out[start..].copy_from_slice(value);
122 Ok(())
123}
124
125pub fn decode_signature_der(der: &[u8], raw_out: &mut [u8]) -> Result<(), EcdsaError> {
134 if raw_out.is_empty() || !raw_out.len().is_multiple_of(2) {
135 return Err(EcdsaError::InvalidOutputLength);
136 }
137
138 let mut outer = Reader::new(der);
139 let mut seq = outer.read_sequence()?;
140 outer.finish()?;
141
142 let r = seq.read_integer()?;
143 let s = seq.read_integer()?;
144 seq.finish()?;
145
146 let (r_out, s_out) = raw_out.split_at_mut(raw_out.len() / 2);
147 r_out.fill(0);
148 s_out.fill(0);
149 write_fixed(r, r_out)?;
150 write_fixed(s, s_out)?;
151 Ok(())
152}
153
154pub fn decode_p256_signature_der(der: &[u8]) -> Result<[u8; 64], EcdsaError> {
157 let mut raw = [0u8; 64];
158 decode_signature_der(der, &mut raw)?;
159 Ok(raw)
160}
161
162pub fn decode_p384_signature_der(der: &[u8]) -> Result<[u8; 96], EcdsaError> {
165 let mut raw = [0u8; 96];
166 decode_signature_der(der, &mut raw)?;
167 Ok(raw)
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn encodes_small_values() {
176 let der = encode_signature_der(&[0x01], &[0x01]);
177 assert_eq!(der, [0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01]);
178 }
179
180 #[test]
181 fn encodes_with_sign_padding() {
182 let r = [0x80];
183 let s = [0x7f];
184 let der = encode_signature_der(&r, &s);
185 assert_eq!(der, [0x30, 0x07, 0x02, 0x02, 0x00, 0x80, 0x02, 0x01, 0x7f]);
186 }
187
188 #[test]
189 fn trims_leading_zeros() {
190 let r = [0x00, 0x00, 0x01];
191 let s = [0x00, 0x02];
192 let der = encode_signature_der(&r, &s);
193 assert_eq!(der, [0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02]);
194 }
195
196 #[test]
197 fn encodes_zero() {
198 let der = encode_signature_der(&[0x00], &[0x00]);
199 assert_eq!(der, [0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]);
200 }
201
202 #[test]
203 fn round_trip_p256() {
204 let mut raw = [0u8; 64];
205 for (i, b) in raw.iter_mut().enumerate() {
206 *b = i as u8;
207 }
208 raw[0] = 0xff;
210 raw[32] = 0xf0;
211
212 let der = encode_signature_der(&raw[..32], &raw[32..]);
213 let decoded = decode_p256_signature_der(&der).unwrap();
214 assert_eq!(decoded, raw);
215 }
216
217 #[test]
218 fn round_trip_p384() {
219 let mut raw = [0u8; 96];
220 for (i, b) in raw.iter_mut().enumerate() {
221 *b = (i * 7) as u8;
222 }
223 raw[0] = 0x80;
224 raw[48] = 0xff;
225
226 let der = encode_signature_der(&raw[..48], &raw[48..]);
227 let decoded = decode_p384_signature_der(&der).unwrap();
228 assert_eq!(decoded, raw);
229 }
230
231 #[test]
232 fn decode_rejects_trailing_data() {
233 let mut der = encode_signature_der(&[0x01], &[0x01]);
234 der.push(0xff);
235 assert!(matches!(
236 decode_signature_der(&der, &mut [0u8; 64]),
237 Err(EcdsaError::Der(DerError::TrailingData))
238 ));
239 }
240
241 #[test]
242 fn decode_rejects_negative_integer() {
243 let der = [0x30, 0x06, 0x02, 0x01, 0x80, 0x02, 0x01, 0x01];
245 assert_eq!(decode_signature_der(&der, &mut [0u8; 64]), Err(EcdsaError::Negative));
246 }
247
248 #[test]
249 fn decodes_positively_padded_integer() {
250 let der = [0x30, 0x07, 0x02, 0x02, 0x00, 0x80, 0x02, 0x01, 0x01];
252 let mut raw = [0u8; 64];
253 decode_signature_der(&der, &mut raw).unwrap();
254 assert_eq!(raw[31], 0x80);
255 assert_eq!(raw[63], 0x01);
256 }
257
258 #[test]
259 fn decode_rejects_oversized_integer() {
260 let value = [0x01u8; 33];
261 let der = encode_signature_der(&value, &[0x01]);
262 assert_eq!(decode_signature_der(&der, &mut [0u8; 64]), Err(EcdsaError::IntegerTooLarge));
263 }
264
265 #[test]
266 fn decode_rejects_bad_output_length() {
267 let der = encode_signature_der(&[0x01], &[0x01]);
268 assert_eq!(decode_signature_der(&der, &mut [0u8; 63]), Err(EcdsaError::InvalidOutputLength));
269 }
270}