Skip to main content

structured_pkix/key/
dsa.rs

1//! Borrowed DSA key components, before bigint or group validation.
2//!
3//! RFC 3279 §2.3.2 carries optional `Dss-Parms ::= SEQUENCE { p INTEGER,
4//! q INTEGER, g INTEGER }` and a DER INTEGER `y` inside subjectPublicKey.
5//! [`read`] preserves these sources and effective parameter inheritance;
6//! success does not establish a usable DSA group, key strength or signature.
7//! <https://www.rfc-editor.org/rfc/rfc3279#section-2.3.2>
8
9use super::same_oid;
10use crate::error::{Error, ErrorCode, Located, Result};
11use crate::path::WorkingKey;
12use structured_asn1::memory::Work;
13use structured_asn1::{Element, Encoding, Integer, Oid, ScopedReader, Tag, universal};
14
15const OID: Oid<'static> = Oid::from_bytes(&[0x2a, 0x86, 0x48, 0xce, 0x38, 0x04, 0x01]);
16const FIELD: &str = "subjectPublicKey.dsa";
17const PARAMETERS: &str = "subjectPublicKeyInfo.algorithm.parameters";
18
19/// A nonnegative component with its original INTEGER and location.
20///
21/// Zero is inspectable, not a valid DSA component. Group and range validation
22/// belongs to the selected backend, before arithmetic or key acceptance.
23#[derive(Debug, Clone, Copy)]
24pub struct Component<'a> {
25    element: Element<'a>,
26    integer: Integer<'a>,
27}
28
29impl<'a> Component<'a> {
30    /// Borrowed unsigned magnitude, excluding a required positive sign octet.
31    /// Zero is represented by the single octet `0x00`.
32    #[must_use]
33    pub fn as_bytes(&self) -> &'a [u8] {
34        match self.integer.as_bytes() {
35            [0, rest @ ..] if !rest.is_empty() => rest,
36            bytes => bytes,
37        }
38    }
39
40    /// Original minimal two's-complement encoding, including any sign octet.
41    #[must_use]
42    pub fn integer(&self) -> Integer<'a> {
43        self.integer
44    }
45
46    /// Original whole INTEGER element in its source's coordinates.
47    #[must_use]
48    pub fn element(&self) -> Element<'a> {
49        self.element
50    }
51}
52
53/// The domain parameters in force, still borrowing their original source.
54#[derive(Debug, Clone, Copy)]
55pub struct Parameters<'a> {
56    element: Element<'a>,
57    p: Component<'a>,
58    q: Component<'a>,
59    g: Component<'a>,
60    inherited: bool,
61}
62
63impl<'a> Parameters<'a> {
64    /// The encoded prime candidate; primality has not been established.
65    #[must_use]
66    pub fn p(&self) -> &Component<'a> {
67        &self.p
68    }
69
70    /// The encoded subgroup-order candidate; no group check is implied.
71    #[must_use]
72    pub fn q(&self) -> &Component<'a> {
73        &self.q
74    }
75
76    /// The encoded generator candidate; no range or order check is implied.
77    #[must_use]
78    pub fn g(&self) -> &Component<'a> {
79        &self.g
80    }
81
82    /// The whole original Dss-Parms SEQUENCE, including its header.
83    #[must_use]
84    pub fn element(&self) -> Element<'a> {
85        self.element
86    }
87
88    /// Whether these parameters came from an authority above this key.
89    #[must_use]
90    pub fn is_inherited(&self) -> bool {
91        self.inherited
92    }
93}
94
95/// The subject's original DSA public component and effective parameters.
96#[derive(Debug, Clone, Copy)]
97pub struct PublicKey<'a> {
98    y: Component<'a>,
99    parameters: Option<Parameters<'a>>,
100}
101
102impl<'a> PublicKey<'a> {
103    /// Original unsigned public component; no mathematical validity is claimed.
104    #[must_use]
105    pub fn y(&self) -> &Component<'a> {
106        &self.y
107    }
108
109    /// Effective parameters, or None when neither written nor inherited.
110    /// The caller needs independently supplied parameters before verification
111    /// in the latter case (RFC 3279 §2.3.2).
112    #[must_use]
113    pub fn parameters(&self) -> Option<&Parameters<'a>> {
114        self.parameters.as_ref()
115    }
116}
117
118/// Reads DSA structure under the current execution and original source ceilings.
119///
120/// Accepts only id-dsa. Written NULL is malformed, even if the generic path
121/// state carries inherited parameters. Absent parameters remain distinguishable
122/// from supplied ones. Parameters use their original encoding; `y` must be DER
123/// even under a BER parent. Reader metadata is funded before allocation; all
124/// returned views borrow original bytes and retain no storage or execution.
125///
126/// # Errors
127/// Reports another algorithm, malformed unsigned components, missing/extra
128/// fields, encoding errors and original located resource failures separately.
129/// This does not check primes, group membership, strength or signature validity.
130///
131/// # Examples
132/// ```
133/// use std::sync::Arc;
134/// use structured_asn1::{Parser, memory::{Memory, MemoryAccount}};
135/// use structured_pkix::{PublicKeyInfo, key::dsa, path::WorkingKey};
136/// let memory = Memory::new(Arc::new(MemoryAccount::new(4096, 4096)));
137/// let parser = Parser::der(memory.clone());
138/// // id-dsa, omitted parameters; subjectPublicKey contains INTEGER 7.
139/// let bytes = b"\x30\x11\x30\x09\x06\x07\x2a\x86\x48\xce\x38\x04\x01\x03\x04\x00\x02\x01\x07";
140/// let mut reader = parser.read(bytes, 400).unwrap();
141/// let element = reader.next_element().unwrap().unwrap();
142/// let info = PublicKeyInfo::read_element(&reader, &element, "key")?;
143/// let key = dsa::read(WorkingKey::standing(info), &memory)?;
144/// assert_eq!(key.y().as_bytes(), [7]);
145/// assert!(key.parameters().is_none());
146/// # Ok::<(), structured_pkix::Error>(())
147/// ```
148pub fn read<'a, W: Work>(key: WorkingKey<'a>, execution: &W) -> Result<PublicKey<'a>> {
149    let info = key.key();
150    let own = info.algorithm();
151    // Even an identity mismatch belongs to the original key source, before
152    // any independently sourced inherited parameters are decoded.
153    let query = own.query_in(execution);
154    if !same_oid(own.algorithm(), OID, &query, FIELD, own.offset())? {
155        return Err(Error::new(ErrorCode::UnexpectedField, FIELD, own.offset()));
156    }
157    // RFC 3279 §2.3.2: omission means no parameter element at all. Generic
158    // RFC5280 NULL inheritance must not repair an invalid DSA spelling.
159    if let Some(source) = own.parameters_nested()
160        && own.has_null_parameter()
161    {
162        let (_, written) = source.open(execution, PARAMETERS)?;
163        return Err(Error::new(
164            ErrorCode::MalformedValue,
165            PARAMETERS,
166            written.span().start,
167        ));
168    }
169    let parameters = if let Some(source) = key.parameter_source() {
170        let (reader, element) = source.open(execution, PARAMETERS)?;
171        if element.tag() != Tag::constructed(universal::SEQUENCE) {
172            return Err(Error::new(
173                ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
174                PARAMETERS,
175                element.span().start,
176            ));
177        }
178        let mut fields = reader.enter(&element).field(PARAMETERS)?;
179        let p = component(&mut fields, PARAMETERS)?;
180        let q = component(&mut fields, PARAMETERS)?;
181        let g = component(&mut fields, PARAMETERS)?;
182        if !fields.is_empty() {
183            return Err(Error::new(
184                ErrorCode::TrailingData,
185                PARAMETERS,
186                fields.offset(),
187            ));
188        }
189        Some(Parameters {
190            element,
191            p,
192            q,
193            g,
194            inherited: own.parameters().is_none(),
195        })
196    } else {
197        None
198    };
199    let octets = info.whole_octets(FIELD)?;
200    let (reader, element) = own
201        .nested(octets, info.key_offset())
202        .open(execution, FIELD)?;
203    // RFC 3279 §2.3.2 requires DER for the INTEGER carried in the bits,
204    // independently of the enclosing source's BER permission.
205    let y = if reader.encoding().is_der() {
206        unsigned(&reader, element, FIELD)?
207    } else {
208        let mut strict = reader.reread(&element, Encoding::Der).field(FIELD)?;
209        component(&mut strict, FIELD)?
210    };
211    Ok(PublicKey { y, parameters })
212}
213
214fn component<'a>(reader: &mut ScopedReader<'a, '_>, field: &'static str) -> Result<Component<'a>> {
215    let element = reader
216        .expect(Tag::primitive(universal::INTEGER))
217        .field(field)?;
218    unsigned(reader, element, field)
219}
220
221fn unsigned<'a>(
222    reader: &ScopedReader<'a, '_>,
223    element: Element<'a>,
224    field: &'static str,
225) -> Result<Component<'a>> {
226    if element.tag() != Tag::primitive(universal::INTEGER) {
227        return Err(Error::new(
228            ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
229            field,
230            element.span().start,
231        ));
232    }
233    let integer = reader.integer(&element).field(field)?;
234    if integer.is_negative() {
235        return Err(Error::new(
236            ErrorCode::MalformedValue,
237            field,
238            element.span().start,
239        ));
240    }
241    Ok(Component { element, integer })
242}