app_store_server_library/
chain_verifier.rs1use crate::chain_verifier::ChainVerificationFailureReason::{
2 CertificateExpired, InvalidCertificate, InvalidChainLength, 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
50const EXPECTED_CHAIN_LENGTH: usize = 3;
51
52pub fn verify_chain(
87 certificates: &Vec<Vec<u8>>,
88 root_certificates: &Vec<Vec<u8>>,
89 effective_date: Option<u64>,
90) -> Result<Vec<u8>, ChainVerifierError> {
91 if root_certificates.is_empty() {
92 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
93 }
94
95 if certificates.len() != EXPECTED_CHAIN_LENGTH {
96 return Err(ChainVerifierError::VerificationFailure(InvalidChainLength));
97 }
98
99 let leaf_certificate = &certificates[0];
100 let Ok(leaf_certificate) = X509Certificate::from_der(leaf_certificate.as_slice()) else {
101 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
102 };
103 let leaf_certificate = leaf_certificate.1;
104
105 let Some(_) = leaf_certificate.get_extension_unique(&oid!(1.2.840.113635.100.6.11.1))? else {
106 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
107 };
108
109 let intermediate_certificate = &certificates[1];
110 let Ok(intermediate_certificate) = X509Certificate::from_der(intermediate_certificate.as_slice()) else {
111 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
112 };
113 let intermediate_certificate = intermediate_certificate.1;
114
115 let Some(_) = intermediate_certificate.get_extension_unique(&oid!(1.2.840.113635.100.6.2.1))? else {
116 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
117 };
118
119 let mut root_certificate: Option<X509Certificate> = None;
120
121 for cert in root_certificates {
122 let Ok(cert) = X509Certificate::from_der(&cert) else {
123 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
124 };
125
126 match intermediate_certificate.verify_signature(Some(cert.1.public_key())) {
127 Ok(_) => (),
128 Err(_) => continue,
129 }
130
131 root_certificate = Some(cert.1)
132 }
133
134 let Some(root_certificate) = root_certificate else {
135 return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
136 };
137
138 verify_chain_impl(
139 &leaf_certificate,
140 &intermediate_certificate,
141 &root_certificate,
142 effective_date,
143 )
144}
145
146fn verify_chain_impl(
147 leaf: &X509Certificate,
148 intermediate: &X509Certificate,
149 root_certificate: &X509Certificate,
150 effective_date: Option<u64>,
151) -> Result<Vec<u8>, ChainVerifierError> {
152 leaf.verify_signature(Some(intermediate.public_key()))?;
153
154 if let Some(date) = effective_date {
155 let Ok(time) = ASN1Time::from_timestamp(i64::try_from(date).unwrap()) else {
156 return Err(ChainVerifierError::VerificationFailure(
157 InvalidEffectiveDate,
158 ));
159 };
160
161 if !(root_certificate.validity.is_valid_at(time) &&
162 leaf.validity.is_valid_at(time) &&
163 intermediate.validity.is_valid_at(time))
164 {
165 return Err(ChainVerifierError::VerificationFailure(CertificateExpired));
166 }
167 }
168
169 let k = leaf.public_key().raw.to_vec();
170
171 #[cfg(all(feature = "ocsp"))]
173 {
174 use crate::chain_verifier_ocsp::check_ocsp_status;
175 match check_ocsp_status(leaf, intermediate) {
177 Ok(()) => {
178 }
180 Err(ChainVerifierError::VerificationFailure(ChainVerificationFailureReason::CertificateRevoked)) => {
181 return Err(ChainVerifierError::VerificationFailure(
183 ChainVerificationFailureReason::CertificateRevoked,
184 ));
185 }
186 Err(e) => {
187 eprintln!("OCSP check failed (non-fatal): {:?}", e);
189 }
190 }
191 };
192
193 Ok(k)
194}