x509_certificate/
rfc5958.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! ASN.1 primitives from RFC 5958.
6
7use {
8    crate::{rfc5280::AlgorithmIdentifier, rfc5652::Attribute, rfc5915::EcPrivateKey},
9    bcder::{
10        decode::{Constructed, DecodeError, IntoSource, Source},
11        encode::{self, PrimitiveContent, Values},
12        BitString, Integer, Mode, OctetString, Tag,
13    },
14    std::ops::{Deref, DerefMut},
15};
16
17/// A single asymmetric key.
18///
19/// ```ASN.1
20/// OneAsymmetricKey ::= SEQUENCE {
21///   version                   Version,
22///   privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
23///   privateKey                PrivateKey,
24///   attributes            [0] Attributes OPTIONAL,
25///   ...,
26///   [[2: publicKey        [1] PublicKey OPTIONAL ]],
27///   ...
28/// }
29/// ```
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub struct OneAsymmetricKey {
32    pub version: Version,
33    pub private_key_algorithm: PrivateKeyAlgorithmIdentifier,
34    pub private_key: PrivateKey,
35    pub attributes: Option<Attributes>,
36    pub public_key: Option<PublicKey>,
37}
38
39impl OneAsymmetricKey {
40    pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
41        cons.take_sequence(|cons| {
42            let version = Version::take_from(cons)?;
43            let private_key_algorithm = PrivateKeyAlgorithmIdentifier::take_from(cons)?;
44            let private_key = PrivateKey::take_from(cons)?;
45            let attributes = cons.take_opt_constructed_if(Tag::CTX_0, |cons| {
46                let mut attributes = Attributes::default();
47
48                while let Some(attribute) = Attribute::take_opt_from(cons)? {
49                    attributes.push(attribute);
50                }
51
52                Ok(attributes)
53            })?;
54
55            // Note: legacy versions of ring incorrectly encoded the public key as a
56            // constructed/nested value. We changed this code to the proper form. But
57            // PKCS#8 keys generated by the old code were technically invalid.
58            let public_key = cons.take_opt_value_if(Tag::CTX_1, |c| BitString::from_content(c))?;
59
60            Ok(Self {
61                version,
62                private_key_algorithm,
63                private_key,
64                attributes,
65                public_key,
66            })
67        })
68    }
69
70    pub fn encode_ref(&self) -> impl Values + '_ {
71        encode::sequence((
72            self.version.encode(),
73            &self.private_key_algorithm,
74            self.private_key.encode_ref(),
75            self.attributes
76                .as_ref()
77                .map(|attrs| attrs.encode_ref_as(Tag::CTX_0)),
78            self.public_key
79                .as_ref()
80                .map(|public_key| public_key.encode_ref()),
81        ))
82    }
83}
84
85/// Version enumeration.
86///
87/// ```ASN.1
88/// Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2)
89/// ```
90#[derive(Clone, Copy, Debug, Eq, PartialEq)]
91pub enum Version {
92    V1 = 0,
93    V2 = 1,
94}
95
96impl Version {
97    pub fn take_from<S: Source>(cons: &mut Constructed<S>) -> Result<Self, DecodeError<S::Error>> {
98        match cons.take_primitive_if(Tag::INTEGER, Integer::i8_from_primitive)? {
99            0 => Ok(Self::V1),
100            1 => Ok(Self::V2),
101            _ => Err(cons.content_err("unexpected Version value")),
102        }
103    }
104
105    pub fn encode(self) -> impl Values {
106        u8::from(self).encode()
107    }
108}
109
110impl From<Version> for u8 {
111    fn from(v: Version) -> u8 {
112        match v {
113            Version::V1 => 0,
114            Version::V2 => 1,
115        }
116    }
117}
118
119/// Private key data.
120///
121/// This is actually an [EcPrivateKey] stored as an OctetString.
122pub type PrivateKey = OctetString;
123
124impl TryFrom<&PrivateKey> for EcPrivateKey {
125    type Error = DecodeError<std::convert::Infallible>;
126
127    fn try_from(v: &PrivateKey) -> Result<Self, Self::Error> {
128        let source = v.clone().into_source();
129
130        Constructed::decode(
131            v.as_slice()
132                .ok_or_else(|| source.content_err("missing private key data"))?,
133            Mode::Der,
134            EcPrivateKey::take_from,
135        )
136    }
137}
138
139/// Public key data.
140pub type PublicKey = BitString;
141
142/// Algorithm identifier for the private key.
143pub type PrivateKeyAlgorithmIdentifier = AlgorithmIdentifier;
144
145/// Attributes.
146///
147/// ```asn.1
148/// Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
149/// ```
150#[derive(Clone, Debug, Default, Eq, PartialEq)]
151pub struct Attributes(Vec<Attribute>);
152
153impl Deref for Attributes {
154    type Target = Vec<Attribute>;
155
156    fn deref(&self) -> &Self::Target {
157        &self.0
158    }
159}
160
161impl DerefMut for Attributes {
162    fn deref_mut(&mut self) -> &mut Self::Target {
163        &mut self.0
164    }
165}
166
167impl Attributes {
168    pub fn encode_ref_as(&self, tag: Tag) -> impl Values + '_ {
169        encode::set_as(tag, encode::slice(&self.0, |x| x.clone().encode()))
170    }
171}
172
173#[cfg(test)]
174mod test {
175    use {super::*, bcder::Mode};
176
177    #[test]
178    fn parse_generated_cert() {
179        let rng = ring::rand::SystemRandom::new();
180
181        let doc = ring::signature::EcdsaKeyPair::generate_pkcs8(
182            &ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING,
183            &rng,
184        )
185        .unwrap();
186
187        ring::signature::EcdsaKeyPair::from_pkcs8(
188            &ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING,
189            doc.as_ref(),
190            &ring::rand::SystemRandom::new(),
191        )
192        .unwrap();
193
194        let key = Constructed::decode(doc.as_ref(), Mode::Der, |cons| {
195            OneAsymmetricKey::take_from(cons)
196        })
197        .unwrap();
198
199        let private_key = EcPrivateKey::try_from(&key.private_key).unwrap();
200        assert_eq!(private_key.version, Integer::from(1));
201        assert!(private_key.parameters.is_none());
202    }
203}