picky_asn1_x509/
subject_public_key_info.rs

1use crate::{oids, AlgorithmIdentifier, AlgorithmIdentifierParameters};
2use oid::ObjectIdentifier;
3use picky_asn1::{
4    bit_string::BitString,
5    wrapper::{BitStringAsn1, BitStringAsn1Container, IntegerAsn1, OctetStringAsn1},
6};
7use serde::{de, ser, Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Debug, PartialEq, Eq, Clone)]
11pub enum PublicKey {
12    Rsa(EncapsulatedRsaPublicKey),
13    Ec(EncapsulatedEcPoint),
14    /// Used For Ed25519, Ed448, X25519, and X448 keys
15    Ed(EncapsulatedEcPoint),
16}
17
18#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
19pub struct RsaPublicKey {
20    pub modulus: IntegerAsn1,         // n
21    pub public_exponent: IntegerAsn1, // e
22}
23
24pub type EncapsulatedRsaPublicKey = BitStringAsn1Container<RsaPublicKey>;
25
26pub type EcPoint = OctetStringAsn1;
27
28pub type EncapsulatedEcPoint = BitStringAsn1;
29
30#[derive(Debug, PartialEq, Eq, Clone)]
31pub struct SubjectPublicKeyInfo {
32    pub algorithm: AlgorithmIdentifier,
33    pub subject_public_key: PublicKey,
34}
35
36impl SubjectPublicKeyInfo {
37    pub fn new_rsa_key(modulus: IntegerAsn1, public_exponent: IntegerAsn1) -> Self {
38        Self {
39            algorithm: AlgorithmIdentifier::new_rsa_encryption(),
40            subject_public_key: PublicKey::Rsa(
41                RsaPublicKey {
42                    modulus,
43                    public_exponent,
44                }
45                .into(),
46            ),
47        }
48    }
49
50    pub fn new_ec_key(curve: ObjectIdentifier, point: BitString) -> Self {
51        Self {
52            algorithm: AlgorithmIdentifier::new_elliptic_curve(curve.into()),
53            subject_public_key: PublicKey::Ec(point.into()),
54        }
55    }
56
57    pub fn new_ed_key(curve: ObjectIdentifier, point: BitString) -> Self {
58        Self {
59            algorithm: AlgorithmIdentifier::new_unchecked(curve, AlgorithmIdentifierParameters::None),
60            subject_public_key: PublicKey::Ed(point.into()),
61        }
62    }
63}
64
65impl ser::Serialize for SubjectPublicKeyInfo {
66    fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
67    where
68        S: ser::Serializer,
69    {
70        use ser::SerializeSeq;
71
72        let mut seq = serializer.serialize_seq(Some(2))?;
73        seq.serialize_element(&self.algorithm)?;
74
75        match &self.subject_public_key {
76            PublicKey::Rsa(key) => seq.serialize_element(key)?,
77            PublicKey::Ec(key) => seq.serialize_element(key)?,
78            PublicKey::Ed(key) => seq.serialize_element(key)?,
79        }
80
81        seq.end()
82    }
83}
84
85impl<'de> de::Deserialize<'de> for SubjectPublicKeyInfo {
86    fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
87    where
88        D: de::Deserializer<'de>,
89    {
90        struct Visitor;
91
92        impl<'de> de::Visitor<'de> for Visitor {
93            type Value = SubjectPublicKeyInfo;
94
95            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
96                formatter.write_str("a valid DER-encoded subject public key info")
97            }
98
99            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
100            where
101                A: de::SeqAccess<'de>,
102            {
103                let algorithm: AlgorithmIdentifier = seq_next_element!(seq, AlgorithmIdentifier, "algorithm oid");
104
105                let subject_public_key = match Into::<String>::into(algorithm.oid()).as_str() {
106                    oids::RSA_ENCRYPTION => PublicKey::Rsa(seq_next_element!(seq, SubjectPublicKeyInfo, "rsa key")),
107                    oids::EC_PUBLIC_KEY => {
108                        PublicKey::Ec(seq_next_element!(seq, SubjectPublicKeyInfo, "elliptic curves key"))
109                    }
110                    oids::ED25519 | oids::X25519 => {
111                        PublicKey::Ed(seq_next_element!(seq, SubjectPublicKeyInfo, "curve25519 key"))
112                    }
113                    oids::ED448 | oids::X448 => {
114                        PublicKey::Ed(seq_next_element!(seq, SubjectPublicKeyInfo, "curve448 key"))
115                    }
116                    _ => {
117                        return Err(serde_invalid_value!(
118                            SubjectPublicKeyInfo,
119                            "unsupported algorithm (unknown oid)",
120                            "a supported algorithm"
121                        ));
122                    }
123                };
124
125                Ok(SubjectPublicKeyInfo {
126                    algorithm,
127                    subject_public_key,
128                })
129            }
130        }
131
132        deserializer.deserialize_seq(Visitor)
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139    use base64::{engine::general_purpose, Engine as _};
140    use num_bigint_dig::BigInt;
141
142    #[test]
143    fn rsa_subject_public_key_info() {
144        let encoded = general_purpose::STANDARD
145            .decode(
146                "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsiLoIx\
147             mXaZAFRBKtHYZhiF8m+pYR+xGIpupvsdDEvKO92D6fIccgVLIW6p6sSNk\
148             oXx5J6KDSMbA/chy5M6pRvJkaCXCI4zlCPMYvPhI8OxN3RYPfdQTLpgPy\
149             wrlfdn2CAum7o4D8nR4NJacB3NfPnS9tsJ2L3p5iHviuTB4xm03IKmPPq\
150             saJy+nXUFC1XS9E/PseVHRuNvKa7WmlwSZngQzKAVSIwqpgCc+oP1pKEe\
151             J0M3LHFo8ao5SuzhfXUIGrPnkUKEE3m7B0b8xXZfP1N6ELoonWDK+RMgY\
152             IBaZdgBhPfHxF8KfTHvSzcUzWZojuR+ynaFL9AJK+8RiXnB4CJwIDAQAB",
153            )
154            .expect("invalid base64");
155
156        // RSA algorithm identifier
157
158        let algorithm = AlgorithmIdentifier::new_rsa_encryption();
159        check_serde!(algorithm: AlgorithmIdentifier in encoded[4..19]);
160
161        // RSA modulus and public exponent
162
163        let modulus = IntegerAsn1::from_bytes_be_signed(vec![
164            0x00, 0xb2, 0x22, 0xe8, 0x23, 0x19, 0x97, 0x69, 0x90, 0x5, 0x44, 0x12, 0xad, 0x1d, 0x86, 0x61, 0x88, 0x5f,
165            0x26, 0xfa, 0x96, 0x11, 0xfb, 0x11, 0x88, 0xa6, 0xea, 0x6f, 0xb1, 0xd0, 0xc4, 0xbc, 0xa3, 0xbd, 0xd8, 0x3e,
166            0x9f, 0x21, 0xc7, 0x20, 0x54, 0xb2, 0x16, 0xea, 0x9e, 0xac, 0x48, 0xd9, 0x28, 0x5f, 0x1e, 0x49, 0xe8, 0xa0,
167            0xd2, 0x31, 0xb0, 0x3f, 0x72, 0x1c, 0xb9, 0x33, 0xaa, 0x51, 0xbc, 0x99, 0x1a, 0x9, 0x70, 0x88, 0xe3, 0x39,
168            0x42, 0x3c, 0xc6, 0x2f, 0x3e, 0x12, 0x3c, 0x3b, 0x13, 0x77, 0x45, 0x83, 0xdf, 0x75, 0x4, 0xcb, 0xa6, 0x3,
169            0xf2, 0xc2, 0xb9, 0x5f, 0x76, 0x7d, 0x82, 0x2, 0xe9, 0xbb, 0xa3, 0x80, 0xfc, 0x9d, 0x1e, 0xd, 0x25, 0xa7,
170            0x1, 0xdc, 0xd7, 0xcf, 0x9d, 0x2f, 0x6d, 0xb0, 0x9d, 0x8b, 0xde, 0x9e, 0x62, 0x1e, 0xf8, 0xae, 0x4c, 0x1e,
171            0x31, 0x9b, 0x4d, 0xc8, 0x2a, 0x63, 0xcf, 0xaa, 0xc6, 0x89, 0xcb, 0xe9, 0xd7, 0x50, 0x50, 0xb5, 0x5d, 0x2f,
172            0x44, 0xfc, 0xfb, 0x1e, 0x54, 0x74, 0x6e, 0x36, 0xf2, 0x9a, 0xed, 0x69, 0xa5, 0xc1, 0x26, 0x67, 0x81, 0xc,
173            0xca, 0x1, 0x54, 0x88, 0xc2, 0xaa, 0x60, 0x9, 0xcf, 0xa8, 0x3f, 0x5a, 0x4a, 0x11, 0xe2, 0x74, 0x33, 0x72,
174            0xc7, 0x16, 0x8f, 0x1a, 0xa3, 0x94, 0xae, 0xce, 0x17, 0xd7, 0x50, 0x81, 0xab, 0x3e, 0x79, 0x14, 0x28, 0x41,
175            0x37, 0x9b, 0xb0, 0x74, 0x6f, 0xcc, 0x57, 0x65, 0xf3, 0xf5, 0x37, 0xa1, 0xb, 0xa2, 0x89, 0xd6, 0xc, 0xaf,
176            0x91, 0x32, 0x6, 0x8, 0x5, 0xa6, 0x5d, 0x80, 0x18, 0x4f, 0x7c, 0x7c, 0x45, 0xf0, 0xa7, 0xd3, 0x1e, 0xf4,
177            0xb3, 0x71, 0x4c, 0xd6, 0x66, 0x88, 0xee, 0x47, 0xec, 0xa7, 0x68, 0x52, 0xfd, 0x0, 0x92, 0xbe, 0xf1, 0x18,
178            0x97, 0x9c, 0x1e, 0x2, 0x27,
179        ]);
180        check_serde!(modulus: IntegerAsn1 in encoded[28..289]);
181
182        let public_exponent: IntegerAsn1 = BigInt::from(65537).to_signed_bytes_be().into();
183        check_serde!(public_exponent: IntegerAsn1 in encoded[289..294]);
184
185        // RSA public key
186
187        let subject_public_key: EncapsulatedRsaPublicKey = RsaPublicKey {
188            modulus,
189            public_exponent,
190        }
191        .into();
192        check_serde!(subject_public_key: EncapsulatedRsaPublicKey in encoded[19..294]);
193
194        // full encode / decode
195
196        let info = SubjectPublicKeyInfo {
197            algorithm,
198            subject_public_key: PublicKey::Rsa(subject_public_key),
199        };
200        check_serde!(info: SubjectPublicKeyInfo in encoded);
201    }
202}