app_store_server_library/
chain_verifier.rs1use crate::x509::x509::X509Error;
2use crate::chain_verifier::ChainVerificationFailureReason::{
3 CertificateExpired, InvalidCertificate, InvalidEffectiveDate,
4};
5use thiserror::Error;
6
7use x509_cert::Certificate;
8use const_oid::ObjectIdentifier;
9use crate::x509::x509;
10
11#[derive(Error, Debug, PartialEq)]
12pub enum ChainVerifierError {
13 #[error("VerificationFailure: [{0}]")]
14 VerificationFailure(ChainVerificationFailureReason),
15
16 #[error("InternalX509Error: [{0}]")]
17 InternalX509Error(String),
18
19 #[error("InternalDecodeError: [{0}]")]
20 InternalDecodeError(#[from] base64::DecodeError),
21}
22
23impl From<X509Error> for ChainVerifierError {
24 fn from(err: X509Error) -> Self {
25 ChainVerifierError::InternalX509Error(err.to_string())
26 }
27}
28
29#[derive(Error, Debug, PartialEq)]
30pub enum ChainVerificationFailureReason {
31 #[error("InvalidAppIdentifier")]
32 InvalidAppIdentifier,
33
34 #[error("InvalidIssuer")]
35 InvalidIssuer,
36
37 #[error("InvalidCertificate")]
38 InvalidCertificate,
39
40 #[error("InvalidChainLength")]
41 InvalidChainLength,
42
43 #[error("InvalidChain")]
44 InvalidChain,
45
46 #[error("InvalidEnvironment")]
47 InvalidEffectiveDate,
48
49 #[error("CertificateExpired")]
50 CertificateExpired,
51
52 #[error("CertificateRevoked")]
53 CertificateRevoked,
54
55 #[error("RetryableVerificationFailure")]
56 RetryableVerificationFailure,
57}
58
59pub struct ChainVerifier {
63 root_certificates: Vec<Vec<u8>>,
64}
65
66impl ChainVerifier {
67 pub fn new(root_certificates: Vec<Vec<u8>>) -> Self {
77 ChainVerifier { root_certificates }
78 }
79
80 pub fn verify(
97 &self,
98 leaf_certificate: &Vec<u8>,
99 intermediate_certificate: &Vec<u8>,
100 effective_date: Option<u64>,
101 ) -> Result<Vec<u8>, ChainVerifierError> {
102 if self.root_certificates.is_empty() {
103 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
104 }
105
106 let leaf_certificate = x509::parse_certificate(leaf_certificate.as_slice())
107 .map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
108
109 let leaf_oid = ObjectIdentifier::new("1.2.840.113635.100.6.11.1")
111 .map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
112
113 if !x509::has_extension(&leaf_certificate, &leaf_oid) {
114 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
115 }
116
117 let intermediate_certificate = x509::parse_certificate(intermediate_certificate.as_slice())
118 .map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
119
120 let intermediate_oid = ObjectIdentifier::new("1.2.840.113635.100.6.2.1")
122 .map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
123
124 if !x509::has_extension(&intermediate_certificate, &intermediate_oid) {
125 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
126 }
127
128 let mut root_certificate: Option<Certificate> = None;
129
130 for cert in &self.root_certificates {
131 let cert = x509::parse_certificate(&cert)
132 .map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
133
134 if x509::verify_signature(&intermediate_certificate, &cert).is_ok() {
135 root_certificate = Some(cert);
136 break;
137 }
138 }
139
140 let Some(root_certificate) = root_certificate else {
141 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
142 };
143
144 self.verify_chain(
145 &leaf_certificate,
146 &intermediate_certificate,
147 &root_certificate,
148 effective_date,
149 )
150 }
151
152 fn verify_chain(
153 &self,
154 leaf: &Certificate,
155 intermediate: &Certificate,
156 root_certificate: &Certificate,
157 effective_date: Option<u64>,
158 ) -> Result<Vec<u8>, ChainVerifierError> {
159 x509::verify_signature(leaf, intermediate)?;
160
161 if let Some(date) = effective_date {
162 let timestamp = i64::try_from(date)
163 .map_err(|_| ChainVerifierError::VerificationFailure(InvalidEffectiveDate))?;
164
165 if !x509::is_valid_at(leaf, timestamp) ||
166 !x509::is_valid_at(intermediate, timestamp) ||
167 !x509::is_valid_at(root_certificate, timestamp)
168 {
169 return Err(ChainVerifierError::VerificationFailure(CertificateExpired));
170 }
171 }
172
173 let public_key_bytes = x509::public_key_bytes(leaf);
174
175 #[cfg(all(feature = "ocsp"))]
176 {
177 match self.check_ocsp_status(leaf, intermediate) {
179 Ok(()) => {
180 }
182 Err(ChainVerifierError::VerificationFailure(ChainVerificationFailureReason::CertificateRevoked)) => {
183 return Err(ChainVerifierError::VerificationFailure(
185 ChainVerificationFailureReason::CertificateRevoked,
186 ));
187 }
188 Err(e) => {
189 eprintln!("OCSP check failed (non-fatal): {:?}", e);
191 }
192 }
193 };
194
195 Ok(public_key_bytes)
196 }
197}