rc_crypto/certificate/id/
issuer_cert_id.rs1use std::fmt::Display;
16
17use thiserror::Error;
18use valuable::Valuable;
19use x509_parser::extensions::ParsedExtension;
20use x509_parser::prelude::X509Certificate;
21
22use crate::certificate::id::{CertId, DangerousComparableId, InvalidLength};
23
24#[derive(Debug, Error)]
26#[error("no Authority Key Identifier found")]
27pub struct ErrorNoAKI;
28
29#[derive(Debug, Error)]
31pub enum InvalidIssuerCertId {
32 #[error(transparent)]
34 NoAKI(#[from] ErrorNoAKI),
35
36 #[error(transparent)]
38 InvalidLength(#[from] InvalidLength),
39}
40
41#[derive(Debug, Hash, Clone)] pub struct IssuerCertId(CertId);
63
64impl IssuerCertId {
65 pub fn as_hex_str(&self) -> &str {
68 self.0.as_hex_str()
69 }
70
71 pub(super) fn as_bytes(&self) -> &[u8] {
73 self.0.as_bytes()
74 }
75
76 pub fn as_cert_id(&self) -> &CertId {
80 &self.0
81 }
82
83 pub fn as_dangerous_comparable(&self) -> DangerousComparableId<'_, Self> {
87 DangerousComparableId::from(self)
88 }
89}
90
91impl Display for IssuerCertId {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.write_str(self.as_hex_str())
94 }
95}
96
97impl Valuable for IssuerCertId {
98 fn as_value(&self) -> valuable::Value<'_> {
99 self.0.as_value()
100 }
101
102 fn visit(&self, visit: &mut dyn valuable::Visit) {
103 self.0.visit(visit);
104 }
105}
106
107impl TryFrom<&[u8]> for IssuerCertId {
108 type Error = InvalidLength;
109
110 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
111 Ok(IssuerCertId(CertId::try_from(value)?))
112 }
113}
114
115impl TryFrom<Vec<u8>> for IssuerCertId {
116 type Error = InvalidLength;
117
118 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
119 Ok(IssuerCertId(CertId::try_from(value)?))
120 }
121}
122
123impl<'a> TryFrom<&X509Certificate<'a>> for IssuerCertId {
124 type Error = InvalidIssuerCertId;
125
126 fn try_from(cert: &X509Certificate<'a>) -> Result<Self, Self::Error> {
127 let bytes = cert
128 .iter_extensions()
129 .find_map(|v| match v.parsed_extension() {
130 ParsedExtension::AuthorityKeyIdentifier(aki) => {
131 aki.key_identifier.as_ref().map(|kid| kid.0)
132 }
133 _ => None,
134 })
135 .ok_or(ErrorNoAKI)?;
136 Ok(IssuerCertId(CertId::try_from(bytes)?))
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use rc_x509_test_helpers::assert_valuable_repr;
143 use static_assertions::assert_not_impl_any;
144 use x509_parser::prelude::FromDer as _;
145
146 use super::*;
147
148 use crate::certificate::tests::cert_fixture;
149
150 const FIXTURE_AKI_STR: &str = "20:6c:8e:cf:e4:21:a7:ff:ed:23:c8:3d:37:0f:77:81:84:71:0e:15";
151
152 assert_not_impl_any!(IssuerCertId: PartialEq, Eq);
157
158 fn fixture_aki() -> IssuerCertId {
159 let der = cert_fixture().as_der();
160 let cert = X509Certificate::from_der(&der).expect("valid DER").1;
161
162 IssuerCertId::try_from(&cert).expect("extract AKI")
163 }
164
165 #[test]
166 fn test_fixture() {
167 let aki = fixture_aki();
168
169 assert_eq!(aki.as_hex_str(), FIXTURE_AKI_STR,);
170 assert_eq!(aki.as_cert_id().as_hex_str(), FIXTURE_AKI_STR);
171 }
172
173 #[test]
174 fn test_valuable_repr() {
175 let aki = fixture_aki();
176
177 assert_valuable_repr(&aki, FIXTURE_AKI_STR);
178 }
179
180 #[test]
181 fn test_danger_eq() {
182 let aki = fixture_aki();
183
184 assert_eq!(aki.as_dangerous_comparable(), aki);
185 }
186}