app_store_server_library/
chain_verifier.rs1use crate::chain_verifier::ChainVerificationFailureReason::{
2 CertificateExpired, InvalidCertificate, InvalidEffectiveDate,
3};
4use thiserror::Error;
5
6use x509_parser::certificate::X509Certificate;
7use x509_parser::der_parser::asn1_rs::oid;
8use x509_parser::error::X509Error;
9use x509_parser::prelude::{ASN1Time, FromDer};
10
11#[derive(Error, Debug, PartialEq)]
12pub enum ChainVerifierError {
13 #[error("VerificationFailure: [{0}]")]
14 VerificationFailure(ChainVerificationFailureReason),
15
16 #[error("InternalX509Error: [{0}]")]
17 InternalX509Error(#[from] X509Error),
18
19 #[error("InternalDecodeError: [{0}]")]
20 InternalDecodeError(#[from] base64::DecodeError),
21}
22
23#[derive(Error, Debug, PartialEq)]
24pub enum ChainVerificationFailureReason {
25 #[error("InvalidAppIdentifier")]
26 InvalidAppIdentifier,
27
28 #[error("InvalidIssuer")]
29 InvalidIssuer,
30
31 #[error("InvalidCertificate")]
32 InvalidCertificate,
33
34 #[error("InvalidChainLength")]
35 InvalidChainLength,
36
37 #[error("InvalidChain")]
38 InvalidChain,
39
40 #[error("InvalidEnvironment")]
41 InvalidEffectiveDate,
42
43 #[error("CertificateExpired")]
44 CertificateExpired,
45
46 #[error("CertificateRevoked")]
47 CertificateRevoked,
48}
49
50pub struct ChainVerifier {
54 root_certificates: Vec<Vec<u8>>,
55}
56
57impl ChainVerifier {
58 pub fn new(root_certificates: Vec<Vec<u8>>) -> Self {
68 ChainVerifier { root_certificates }
69 }
70
71 pub fn verify(
88 &self,
89 leaf_certificate: &Vec<u8>,
90 intermediate_certificate: &Vec<u8>,
91 effective_date: Option<u64>,
92 ) -> Result<Vec<u8>, ChainVerifierError> {
93 if self.root_certificates.is_empty() {
94 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
95 }
96 let Ok(leaf_certificate) = X509Certificate::from_der(leaf_certificate.as_slice()) else {
97 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
98 };
99 let leaf_certificate = leaf_certificate.1;
100
101 let Some(_) = leaf_certificate.get_extension_unique(&oid!(1.2.840.113635.100.6.11.1))? else {
102 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
103 };
104
105 let Ok(intermediate_certificate) = X509Certificate::from_der(intermediate_certificate.as_slice()) else {
106 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
107 };
108 let intermediate_certificate = intermediate_certificate.1;
109
110 let Some(_) = intermediate_certificate.get_extension_unique(&oid!(1.2.840.113635.100.6.2.1))? else {
111 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
112 };
113
114 let mut root_certificate: Option<X509Certificate> = None;
115
116 for cert in &self.root_certificates {
117 let Ok(cert) = X509Certificate::from_der(&cert) else {
118 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
119 };
120
121 match intermediate_certificate.verify_signature(Some(cert.1.public_key())) {
122 Ok(_) => (),
123 Err(_) => continue,
124 }
125
126 root_certificate = Some(cert.1)
127 }
128
129 let Some(root_certificate) = root_certificate else {
130 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
131 };
132
133 self.verify_chain(
134 &leaf_certificate,
135 &intermediate_certificate,
136 &root_certificate,
137 effective_date,
138 )
139 }
140
141 fn verify_chain(
142 &self,
143 leaf: &X509Certificate,
144 intermediate: &X509Certificate,
145 root_certificate: &X509Certificate,
146 effective_date: Option<u64>,
147 ) -> Result<Vec<u8>, ChainVerifierError> {
148 leaf.verify_signature(Some(intermediate.public_key()))?;
149
150 if let Some(date) = effective_date {
151 let Ok(time) = ASN1Time::from_timestamp(i64::try_from(date).unwrap()) else {
152 return Err(ChainVerifierError::VerificationFailure(
153 InvalidEffectiveDate,
154 ));
155 };
156
157 if !(root_certificate.validity.is_valid_at(time) &&
158 leaf.validity.is_valid_at(time) &&
159 intermediate.validity.is_valid_at(time))
160 {
161 return Err(ChainVerifierError::VerificationFailure(CertificateExpired));
162 }
163 }
164
165 let k = leaf.public_key().raw.to_vec();
166
167 #[cfg(all(feature = "ocsp"))]
169 {
170 match self.check_ocsp_status(leaf, intermediate) {
172 Ok(()) => {
173 }
175 Err(ChainVerifierError::VerificationFailure(ChainVerificationFailureReason::CertificateRevoked)) => {
176 return Err(ChainVerifierError::VerificationFailure(
178 ChainVerificationFailureReason::CertificateRevoked,
179 ));
180 }
181 Err(e) => {
182 eprintln!("OCSP check failed (non-fatal): {:?}", e);
184 }
185 }
186 };
187
188 Ok(k)
189 }
190}