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    if !same_oid(own.algorithm(), OID, execution, FIELD, own.offset())? {
152        return Err(Error::new(ErrorCode::UnexpectedField, FIELD, own.offset()));
153    }
154    // RFC 3279 §2.3.2: omission means no parameter element at all. Generic
155    // RFC5280 NULL inheritance must not repair an invalid DSA spelling.
156    if let Some(source) = own.parameters_nested()
157        && own.has_null_parameter()
158    {
159        let (_, written) = source.open(execution, PARAMETERS)?;
160        return Err(Error::new(
161            ErrorCode::MalformedValue,
162            PARAMETERS,
163            written.span().start,
164        ));
165    }
166    let parameters = if let Some(source) = key.parameter_source() {
167        let (reader, element) = source.open(execution, PARAMETERS)?;
168        if element.tag() != Tag::constructed(universal::SEQUENCE) {
169            return Err(Error::new(
170                ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
171                PARAMETERS,
172                element.span().start,
173            ));
174        }
175        let mut fields = reader.enter(&element).field(PARAMETERS)?;
176        let p = component(&mut fields, PARAMETERS)?;
177        let q = component(&mut fields, PARAMETERS)?;
178        let g = component(&mut fields, PARAMETERS)?;
179        if !fields.is_empty() {
180            return Err(Error::new(
181                ErrorCode::TrailingData,
182                PARAMETERS,
183                fields.offset(),
184            ));
185        }
186        Some(Parameters {
187            element,
188            p,
189            q,
190            g,
191            inherited: own.parameters().is_none(),
192        })
193    } else {
194        None
195    };
196    let octets = info.whole_octets(FIELD)?;
197    let (reader, element) = own
198        .nested(octets, info.key_offset())
199        .open(execution, FIELD)?;
200    // RFC 3279 §2.3.2 requires DER for the INTEGER carried in the bits,
201    // independently of the enclosing source's BER permission.
202    let y = if reader.encoding().is_der() {
203        unsigned(&reader, element, FIELD)?
204    } else {
205        let mut strict = reader.reread(&element, Encoding::Der).field(FIELD)?;
206        component(&mut strict, FIELD)?
207    };
208    Ok(PublicKey { y, parameters })
209}
210
211fn component<'a>(reader: &mut ScopedReader<'a, '_>, field: &'static str) -> Result<Component<'a>> {
212    let element = reader
213        .expect(Tag::primitive(universal::INTEGER))
214        .field(field)?;
215    unsigned(reader, element, field)
216}
217
218fn unsigned<'a>(
219    reader: &ScopedReader<'a, '_>,
220    element: Element<'a>,
221    field: &'static str,
222) -> Result<Component<'a>> {
223    if element.tag() != Tag::primitive(universal::INTEGER) {
224        return Err(Error::new(
225            ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
226            field,
227            element.span().start,
228        ));
229    }
230    let integer = reader.integer(&element).field(field)?;
231    if integer.is_negative() {
232        return Err(Error::new(
233            ErrorCode::MalformedValue,
234            field,
235            element.span().start,
236        ));
237    }
238    Ok(Component { element, integer })
239}