1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Borrowed DSA/ECDSA signature-value structure, separate from verification.
//!
//! RFC 3279 §§2.2.2–2.2.3 define both values as `SEQUENCE { r INTEGER,
//! s INTEGER }`. RFC 5753 §2.1.1 requires DER even inside a BER CMS envelope.
//! [`DssValue`] checks that encoding and structure; it does not check a
//! signature, choose an algorithm, or know a key's group order. In particular,
//! zero and negative integers remain readable. The selected provider must
//! enforce the full scalar range before arithmetic (SEC 1 v2 §4.1.4).
//! <https://www.rfc-editor.org/rfc/rfc3279.html#section-2.2.2>
//! <https://www.secg.org/sec1-v2.pdf>
//!
//! Spans and errors use the supplied reader's coordinate system. When carried
//! fragments have been joined, retain the carrier's source map to project them
//! to physical locations; no contiguous physical range is invented here.
use crate::error::{Error, ErrorCode, Located, Result};
use structured_asn1::{Element, Encoding, Integer, ScopedReader, Span, Tag, universal};
/// The exact DER INTEGER pair used by DSA and ECDSA signatures.
///
/// Every view borrows the received bytes. Successful decoding is a structural
/// fact, not a claim that either scalar or the signature is valid. `XMLDSig`'s
/// fixed-width concatenation is a different encoding, handled by its caller.
#[derive(Debug, Clone, Copy)]
pub struct DssValue<'a> {
element: Element<'a>,
r: Integer<'a>,
s: Integer<'a>,
r_span: Span,
s_span: Span,
}
impl<'a> DssValue<'a> {
/// Reads a complete signature-value window, refusing any trailing bytes.
///
/// The supplied cursor must describe the original window at its actual
/// depth. Its current execution and original source ceilings remain in
/// force; no parser or resource account is created. DER is enforced even
/// when the cursor accepts BER. Only reader/path metadata may need storage;
/// the returned value owns none.
///
/// # Errors
/// Reports located encoding, missing/extra-field, trailing-data or resource
/// failures. Resource refusal never becomes a malformed scalar or mismatch.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use structured_asn1::{Parser, memory::{Memory, MemoryAccount}};
/// use structured_pkix::signature::DssValue;
/// let parser = Parser::ber(Memory::new(Arc::new(MemoryAccount::new(1024, 1024))));
/// let mut reader = parser.read(b"\x30\x07\x02\x02\x00\x80\x02\x01\x01", 400).unwrap();
/// let value = DssValue::read(&mut reader, "signature")?;
/// assert_eq!(value.r().as_bytes(), [0, 0x80]); // original sign octet
/// assert_eq!(value.s().as_u64(), Some(1));
/// assert_eq!(value.r_span().start, 402);
/// # Ok::<(), structured_pkix::Error>(())
/// ```
pub fn read(parent: &mut ScopedReader<'a, '_>, field: &'static str) -> Result<Self> {
let element = parent
.expect(Tag::constructed(universal::SEQUENCE))
.field(field)?;
let value = Self::read_element(parent, &element, field)?;
if !parent.is_empty() {
return Err(Error::new(ErrorCode::TrailingData, field, parent.offset()));
}
Ok(value)
}
/// Reads one embedded value; surrounding siblings belong to the caller.
///
/// `parent` must be the reader that produced `element`. A DER parent uses
/// the already-validated header; a BER parent re-reads that same original
/// element under DER before entering it. Both routes share the field kernel
/// and the same source depth, current work and aggregate accounting.
///
/// # Errors
/// As [`Self::read`], except that bytes after `element` are allowed.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use structured_asn1::{Parser, memory::{Memory, MemoryAccount}};
/// use structured_pkix::signature::DssValue;
/// let parser = Parser::der(Memory::new(Arc::new(MemoryAccount::new(1024, 1024))));
/// let mut reader = parser.read(b"\x30\x06\x02\x01\x01\x02\x01\x02\x05\x00", 0).unwrap();
/// let element = reader.next_element().unwrap().unwrap();
/// let value = DssValue::read_element(&reader, &element, "signature")?;
/// assert_eq!(value.s().as_u64(), Some(2));
/// assert!(!reader.is_empty()); // the following NULL is outside this value
/// # Ok::<(), structured_pkix::Error>(())
/// ```
pub fn read_element(
parent: &ScopedReader<'a, '_>,
element: &Element<'a>,
field: &'static str,
) -> Result<Self> {
if parent.encoding().is_der() {
return Self::fields(parent, element, field);
}
// RFC 5753 §2.1.1: ECDSA-Sig-Value is DER, even in BER SignedData.
// https://www.rfc-editor.org/rfc/rfc5753.html#section-2.1.1
let mut strict = parent.reread(element, Encoding::Der).field(field)?;
let element = strict
.expect(Tag::constructed(universal::SEQUENCE))
.field(field)?;
Self::fields(&strict, &element, field)
}
fn fields(
parent: &ScopedReader<'a, '_>,
element: &Element<'a>,
field: &'static str,
) -> Result<Self> {
if element.tag() != Tag::constructed(universal::SEQUENCE) {
return Err(Error::new(
ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
field,
element.span().start,
));
}
let mut inside = parent.enter(element).field(field)?;
let r = inside
.expect(Tag::primitive(universal::INTEGER))
.field(field)?;
let r_value = inside.integer(&r).field(field)?;
let s = inside
.expect(Tag::primitive(universal::INTEGER))
.field(field)?;
let s_value = inside.integer(&s).field(field)?;
if !inside.is_empty() {
return Err(Error::new(ErrorCode::TrailingData, field, inside.offset()));
}
Ok(Self {
element: *element,
r: r_value,
s: s_value,
r_span: r.span(),
s_span: s.span(),
})
}
/// The whole original encoding, including its SEQUENCE header.
#[must_use]
pub fn element(&self) -> Element<'a> {
self.element
}
/// Original minimal two's-complement `r`, including any required sign octet.
#[must_use]
pub fn r(&self) -> Integer<'a> {
self.r
}
/// Original minimal two's-complement `s`, including any required sign octet.
#[must_use]
pub fn s(&self) -> Integer<'a> {
self.s
}
/// Original whole INTEGER range for `r`, including its tag and length.
#[must_use]
pub fn r_span(&self) -> Span {
self.r_span
}
/// Original whole INTEGER range for `s`, including its tag and length.
#[must_use]
pub fn s_span(&self) -> Span {
self.s_span
}
}