Coverage Report

Created: 2026-08-13 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/spki-0.7.3/src/spki.rs
Line
Count
Source
1
//! X.509 `SubjectPublicKeyInfo`
2
3
use crate::{AlgorithmIdentifier, Error, Result};
4
use core::cmp::Ordering;
5
use der::{
6
    asn1::{AnyRef, BitStringRef},
7
    Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, Header, Length, Reader,
8
    Sequence, ValueOrd, Writer,
9
};
10
11
#[cfg(feature = "alloc")]
12
use der::{
13
    asn1::{Any, BitString},
14
    Document,
15
};
16
17
#[cfg(feature = "fingerprint")]
18
use crate::{fingerprint, FingerprintBytes};
19
20
#[cfg(feature = "pem")]
21
use der::pem::PemLabel;
22
23
/// [`SubjectPublicKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BitStringRef`] params.
24
pub type SubjectPublicKeyInfoRef<'a> = SubjectPublicKeyInfo<AnyRef<'a>, BitStringRef<'a>>;
25
26
/// [`SubjectPublicKeyInfo`] with [`Any`] algorithm parameters, and [`BitString`] params.
27
#[cfg(feature = "alloc")]
28
pub type SubjectPublicKeyInfoOwned = SubjectPublicKeyInfo<Any, BitString>;
29
30
/// X.509 `SubjectPublicKeyInfo` (SPKI) as defined in [RFC 5280 § 4.1.2.7].
31
///
32
/// ASN.1 structure containing an [`AlgorithmIdentifier`] and public key
33
/// data in an algorithm specific format.
34
///
35
/// ```text
36
///    SubjectPublicKeyInfo  ::=  SEQUENCE  {
37
///         algorithm            AlgorithmIdentifier,
38
///         subjectPublicKey     BIT STRING  }
39
/// ```
40
///
41
/// [RFC 5280 § 4.1.2.7]: https://tools.ietf.org/html/rfc5280#section-4.1.2.7
42
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
43
#[derive(Clone, Debug, Eq, PartialEq)]
44
pub struct SubjectPublicKeyInfo<Params, Key> {
45
    /// X.509 [`AlgorithmIdentifier`] for the public key type
46
    pub algorithm: AlgorithmIdentifier<Params>,
47
48
    /// Public key data
49
    pub subject_public_key: Key,
50
}
51
52
impl<'a, Params, Key> SubjectPublicKeyInfo<Params, Key>
53
where
54
    Params: Choice<'a> + Encode,
55
    // TODO: replace FixedTag with FixedTag<TAG = { Tag::BitString }> once
56
    // https://github.com/rust-lang/rust/issues/92827 is fixed
57
    Key: Decode<'a> + Encode + FixedTag,
58
{
59
    /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] and
60
    /// encode it as a Base64 string.
61
    ///
62
    /// See [RFC7469 § 2.1.1] for more information.
63
    ///
64
    /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
65
    #[cfg(all(feature = "fingerprint", feature = "alloc", feature = "base64"))]
66
    pub fn fingerprint_base64(&self) -> Result<alloc::string::String> {
67
        use base64ct::{Base64, Encoding};
68
        Ok(Base64::encode_string(&self.fingerprint_bytes()?))
69
    }
70
71
    /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] as
72
    /// a raw byte array.
73
    ///
74
    /// See [RFC7469 § 2.1.1] for more information.
75
    ///
76
    /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
77
    #[cfg(feature = "fingerprint")]
78
    pub fn fingerprint_bytes(&self) -> Result<FingerprintBytes> {
79
        let mut builder = fingerprint::Builder::new();
80
        self.encode(&mut builder)?;
81
        Ok(builder.finish())
82
    }
83
}
84
85
impl<'a: 'k, 'k, Params, Key: 'k> DecodeValue<'a> for SubjectPublicKeyInfo<Params, Key>
86
where
87
    Params: Choice<'a> + Encode,
88
    Key: Decode<'a>,
89
{
90
22.8k
    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
91
22.8k
        reader.read_nested(header.length, |reader| {
92
            Ok(Self {
93
22.7k
                algorithm: reader.decode()?,
94
21.2k
                subject_public_key: Key::decode(reader)?,
95
            })
96
22.7k
        })
<spki::spki::SubjectPublicKeyInfo<der::asn1::any::allocating::Any, der::asn1::bit_string::allocating::BitString> as der::decode::DecodeValue>::decode_value::<der::reader::nested::NestedReader<der::reader::nested::NestedReader<der::reader::slice::SliceReader>>>::{closure#0}
Line
Count
Source
91
22.7k
        reader.read_nested(header.length, |reader| {
92
            Ok(Self {
93
22.7k
                algorithm: reader.decode()?,
94
21.2k
                subject_public_key: Key::decode(reader)?,
95
            })
96
22.7k
        })
Unexecuted instantiation: <spki::spki::SubjectPublicKeyInfo<der::asn1::any::allocating::Any, der::asn1::bit_string::allocating::BitString> as der::decode::DecodeValue>::decode_value::<der::reader::slice::SliceReader>::{closure#0}
Unexecuted instantiation: <spki::spki::SubjectPublicKeyInfo<_, _> as der::decode::DecodeValue>::decode_value::<_>::{closure#0}
97
22.8k
    }
<spki::spki::SubjectPublicKeyInfo<der::asn1::any::allocating::Any, der::asn1::bit_string::allocating::BitString> as der::decode::DecodeValue>::decode_value::<der::reader::nested::NestedReader<der::reader::nested::NestedReader<der::reader::slice::SliceReader>>>
Line
Count
Source
90
22.8k
    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
91
22.8k
        reader.read_nested(header.length, |reader| {
92
            Ok(Self {
93
                algorithm: reader.decode()?,
94
                subject_public_key: Key::decode(reader)?,
95
            })
96
        })
97
22.8k
    }
Unexecuted instantiation: <spki::spki::SubjectPublicKeyInfo<der::asn1::any::allocating::Any, der::asn1::bit_string::allocating::BitString> as der::decode::DecodeValue>::decode_value::<der::reader::slice::SliceReader>
Unexecuted instantiation: <spki::spki::SubjectPublicKeyInfo<_, _> as der::decode::DecodeValue>::decode_value::<_>
98
}
99
100
impl<'a, Params, Key> EncodeValue for SubjectPublicKeyInfo<Params, Key>
101
where
102
    Params: Choice<'a> + Encode,
103
    Key: Encode,
104
{
105
3.86k
    fn value_len(&self) -> der::Result<Length> {
106
3.86k
        self.algorithm.encoded_len()? + self.subject_public_key.encoded_len()?
107
3.86k
    }
<spki::spki::SubjectPublicKeyInfo<der::asn1::any::allocating::Any, der::asn1::bit_string::allocating::BitString> as der::encode::EncodeValue>::value_len
Line
Count
Source
105
3.86k
    fn value_len(&self) -> der::Result<Length> {
106
3.86k
        self.algorithm.encoded_len()? + self.subject_public_key.encoded_len()?
107
3.86k
    }
Unexecuted instantiation: <spki::spki::SubjectPublicKeyInfo<_, _> as der::encode::EncodeValue>::value_len
108
109
1.28k
    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
110
1.28k
        self.algorithm.encode(writer)?;
111
1.28k
        self.subject_public_key.encode(writer)?;
112
1.28k
        Ok(())
113
1.28k
    }
<spki::spki::SubjectPublicKeyInfo<der::asn1::any::allocating::Any, der::asn1::bit_string::allocating::BitString> as der::encode::EncodeValue>::encode_value::<der::writer::slice::SliceWriter>
Line
Count
Source
109
1.28k
    fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
110
1.28k
        self.algorithm.encode(writer)?;
111
1.28k
        self.subject_public_key.encode(writer)?;
112
1.28k
        Ok(())
113
1.28k
    }
Unexecuted instantiation: <spki::spki::SubjectPublicKeyInfo<_, _> as der::encode::EncodeValue>::encode_value::<_>
114
}
115
116
impl<'a, Params, Key> Sequence<'a> for SubjectPublicKeyInfo<Params, Key>
117
where
118
    Params: Choice<'a> + Encode,
119
    Key: Decode<'a> + Encode + FixedTag,
120
{
121
}
122
123
impl<'a, Params, Key> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<Params, Key>
124
where
125
    Params: Choice<'a> + Encode,
126
    Key: Decode<'a> + Encode + FixedTag,
127
{
128
    type Error = Error;
129
130
0
    fn try_from(bytes: &'a [u8]) -> Result<Self> {
131
0
        Ok(Self::from_der(bytes)?)
132
0
    }
133
}
134
135
impl<'a, Params, Key> ValueOrd for SubjectPublicKeyInfo<Params, Key>
136
where
137
    Params: Choice<'a> + DerOrd + Encode,
138
    Key: ValueOrd,
139
{
140
0
    fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
141
0
        match self.algorithm.der_cmp(&other.algorithm)? {
142
0
            Ordering::Equal => self.subject_public_key.value_cmp(&other.subject_public_key),
143
0
            other => Ok(other),
144
        }
145
0
    }
146
}
147
148
#[cfg(feature = "alloc")]
149
impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<SubjectPublicKeyInfo<Params, Key>> for Document
150
where
151
    Params: Choice<'a> + Encode,
152
    Key: Decode<'a> + Encode + FixedTag,
153
    BitStringRef<'a>: From<&'k Key>,
154
{
155
    type Error = Error;
156
157
0
    fn try_from(spki: SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
158
0
        Self::try_from(&spki)
159
0
    }
160
}
161
162
#[cfg(feature = "alloc")]
163
impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<&SubjectPublicKeyInfo<Params, Key>> for Document
164
where
165
    Params: Choice<'a> + Encode,
166
    Key: Decode<'a> + Encode + FixedTag,
167
    BitStringRef<'a>: From<&'k Key>,
168
{
169
    type Error = Error;
170
171
0
    fn try_from(spki: &SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
172
0
        Ok(Self::encode_msg(spki)?)
173
0
    }
174
}
175
176
#[cfg(feature = "pem")]
177
impl<Params, Key> PemLabel for SubjectPublicKeyInfo<Params, Key> {
178
    const PEM_LABEL: &'static str = "PUBLIC KEY";
179
}
180
181
#[cfg(feature = "alloc")]
182
mod allocating {
183
    use super::*;
184
    use crate::EncodePublicKey;
185
    use der::referenced::*;
186
187
    impl<'a> RefToOwned<'a> for SubjectPublicKeyInfoRef<'a> {
188
        type Owned = SubjectPublicKeyInfoOwned;
189
0
        fn ref_to_owned(&self) -> Self::Owned {
190
0
            SubjectPublicKeyInfo {
191
0
                algorithm: self.algorithm.ref_to_owned(),
192
0
                subject_public_key: self.subject_public_key.ref_to_owned(),
193
0
            }
194
0
        }
195
    }
196
197
    impl OwnedToRef for SubjectPublicKeyInfoOwned {
198
        type Borrowed<'a> = SubjectPublicKeyInfoRef<'a>;
199
0
        fn owned_to_ref(&self) -> Self::Borrowed<'_> {
200
0
            SubjectPublicKeyInfo {
201
0
                algorithm: self.algorithm.owned_to_ref(),
202
0
                subject_public_key: self.subject_public_key.owned_to_ref(),
203
0
            }
204
0
        }
205
    }
206
207
    impl SubjectPublicKeyInfoOwned {
208
        /// Create a [`SubjectPublicKeyInfoOwned`] from any object that implements
209
        /// [`EncodePublicKey`].
210
0
        pub fn from_key<T>(source: T) -> Result<Self>
211
0
        where
212
0
            T: EncodePublicKey,
213
        {
214
0
            Ok(source.to_public_key_der()?.decode_msg::<Self>()?)
215
0
        }
216
    }
217
}