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
175
176
177
178
//! C509 Issuer Signature Algorithm as a part of `TBSCertificate` used in C509
//! Certificate.
//!
//! ```cddl
//! subjectPublicKeyAlgorithm: AlgorithmIdentifier
//! ```

// cspell: words spka

mod data;

use std::str::FromStr;

use asn1_rs::Oid;
use data::{get_oid_from_int, SUBJECT_PUB_KEY_ALGO_LOOKUP};
use minicbor::{encode::Write, Decode, Decoder, Encode, Encoder};
use serde::{Deserialize, Deserializer, Serialize};

use crate::{algorithm_identifier::AlgorithmIdentifier, oid::C509oidRegistered};

/// A struct represents the `SubjectPubKeyAlgorithm`
#[derive(Debug, Clone, PartialEq)]
pub struct SubjectPubKeyAlgorithm {
    /// The registered OID of the `SubjectPubKeyAlgorithm`.
    registered_oid: C509oidRegistered,
    /// An `AlgorithmIdentifier` type
    algo_identifier: AlgorithmIdentifier,
}

impl SubjectPubKeyAlgorithm {
    /// Create new instance of `SubjectPubKeyAlgorithm` where it registered with
    /// Subject Public Key Algorithm lookup table.
    pub fn new(oid: Oid<'static>, param: Option<String>) -> Self {
        Self {
            registered_oid: C509oidRegistered::new(
                oid.clone(),
                SUBJECT_PUB_KEY_ALGO_LOOKUP.get_int_to_oid_table(),
            ),
            algo_identifier: AlgorithmIdentifier::new(oid, param),
        }
    }
}

/// Helper struct for deserialize and serialize `SubjectPubKeyAlgorithm`.
#[derive(Debug, Deserialize, Serialize)]
struct Helper {
    /// OID as string.
    oid: String,
    /// Optional parameter.
    param: Option<String>,
}

impl<'de> Deserialize<'de> for SubjectPubKeyAlgorithm {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'de> {
        let helper = Helper::deserialize(deserializer)?;
        let oid =
            Oid::from_str(&helper.oid).map_err(|e| serde::de::Error::custom(format!("{e:?}")))?;

        Ok(SubjectPubKeyAlgorithm::new(oid, helper.param))
    }
}

impl Serialize for SubjectPubKeyAlgorithm {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: serde::Serializer {
        let helper = Helper {
            oid: self.registered_oid.get_c509_oid().get_oid().to_string(),
            param: self.algo_identifier.get_param().clone(),
        };
        helper.serialize(serializer)
    }
}

impl Encode<()> for SubjectPubKeyAlgorithm {
    fn encode<W: Write>(
        &self, e: &mut Encoder<W>, ctx: &mut (),
    ) -> Result<(), minicbor::encode::Error<W::Error>> {
        if let Some(&i) = self
            .registered_oid
            .get_table()
            .get_map()
            .get_by_right(&self.registered_oid.get_c509_oid().get_oid())
        {
            e.i16(i)?;
        } else {
            AlgorithmIdentifier::encode(&self.algo_identifier, e, ctx)?;
        }
        Ok(())
    }
}

impl Decode<'_, ()> for SubjectPubKeyAlgorithm {
    fn decode(d: &mut Decoder<'_>, ctx: &mut ()) -> Result<Self, minicbor::decode::Error> {
        // Check u8 for 0 - 28
        if d.datatype()? == minicbor::data::Type::U8 {
            let i = d.i16()?;
            let oid = get_oid_from_int(i).map_err(minicbor::decode::Error::message)?;
            Ok(Self::new(oid, None))
        } else {
            let algo_identifier = AlgorithmIdentifier::decode(d, ctx)?;
            Ok(SubjectPubKeyAlgorithm::new(
                algo_identifier.get_oid(),
                algo_identifier.get_param().clone(),
            ))
        }
    }
}

// ------------------Test----------------------

#[cfg(test)]
mod test_subject_public_key_algorithm {
    use asn1_rs::oid;

    use super::*;

    #[test]
    fn test_registered_oid() {
        let mut buffer = Vec::new();
        let mut encoder = Encoder::new(&mut buffer);

        let spka = SubjectPubKeyAlgorithm::new(oid!(1.3.101 .112), None);
        spka.encode(&mut encoder, &mut ())
            .expect("Failed to encode SubjectPubKeyAlgorithm");

        // Ed25519 - int 10: 0x0a
        assert_eq!(hex::encode(buffer.clone()), "0a");

        let mut decoder = Decoder::new(&buffer);
        let decoded_spka = SubjectPubKeyAlgorithm::decode(&mut decoder, &mut ())
            .expect("Failed to decode SubjectPubKeyAlgorithm");
        assert_eq!(decoded_spka, spka);
    }

    #[test]
    fn test_unregistered_oid() {
        let mut buffer = Vec::new();
        let mut encoder = Encoder::new(&mut buffer);

        let spka = SubjectPubKeyAlgorithm::new(oid!(2.16.840 .1 .101 .3 .4 .2 .1), None);
        spka.encode(&mut encoder, &mut ())
            .expect("Failed to encode SubjectPubKeyAlgorithm");

        // 2.16.840 .1 .101 .3 .4 .2 .1: 0x49608648016503040201
        assert_eq!(hex::encode(buffer.clone()), "49608648016503040201");

        let mut decoder = Decoder::new(&buffer);
        let decoded_spka = SubjectPubKeyAlgorithm::decode(&mut decoder, &mut ())
            .expect("Failed to decode SubjectPubKeyAlgorithm");
        assert_eq!(decoded_spka, spka);
    }

    #[test]
    fn test_unregistered_oid_with_param() {
        let mut buffer = Vec::new();
        let mut encoder = Encoder::new(&mut buffer);

        let spka = SubjectPubKeyAlgorithm::new(
            oid!(2.16.840 .1 .101 .3 .4 .2 .1),
            Some("example".to_string()),
        );
        spka.encode(&mut encoder, &mut ())
            .expect("Failed to encode SubjectPubKeyAlgorithm");
        // Array of 2 items: 0x82
        // 2.16.840 .1 .101 .3 .4 .2 .1: 0x49608648016503040201
        // bytes "example": 0x476578616d706c65
        assert_eq!(
            hex::encode(buffer.clone()),
            "8249608648016503040201476578616d706c65"
        );

        let mut decoder = Decoder::new(&buffer);
        let decoded_spka = SubjectPubKeyAlgorithm::decode(&mut decoder, &mut ())
            .expect("Failed to decode SubjectPubKeyAlgorithm");
        assert_eq!(decoded_spka, spka);
    }
}