use {once_cell::sync::Lazy, std::ops::Deref, x509_certificate::CapturedX509Certificate};
static APPLE_INC_ROOT_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(
include_bytes!("apple-certs/AppleIncRootCertificate.cer").to_vec(),
)
.unwrap()
});
static APPLE_COMPUTER_INC_ROOT_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(
include_bytes!("apple-certs/AppleComputerRootCertificate.cer").to_vec(),
)
.unwrap()
});
static APPLE_ROOT_CA_G2_ROOT_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleRootCA-G2.cer").to_vec())
.unwrap()
});
static APPLE_ROOT_CA_G3_ROOT_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleRootCA-G3.cer").to_vec())
.unwrap()
});
static APPLE_IST_CA_2_G1_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleISTCA2G1.cer").to_vec())
.unwrap()
});
static APPLE_IST_CA_8_G1_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleISTCA8G1.cer").to_vec())
.unwrap()
});
static APPLICATION_INTEGRATION_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleAAICA.cer").to_vec())
.unwrap()
});
static APPLICATION_INTEGRATION_2_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleAAI2CA.cer").to_vec())
.unwrap()
});
static APPLICATION_INTEGRATION_G3_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleAAICAG3.cer").to_vec())
.unwrap()
});
static APPLE_APPLICATION_INTEGRATION_CA_5_G1_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(
include_bytes!("apple-certs/AppleApplicationIntegrationCA5G1.cer").to_vec(),
)
.unwrap()
});
static APPLE_APPLICATION_INTEGRATION_CA_7_G1_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(
include_bytes!("apple-certs/AppleApplicationIntegrationCA7G1.cer").to_vec(),
)
.unwrap()
});
static DEVELOPER_AUTHENTICATION_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/DevAuthCA.cer").to_vec()).unwrap()
});
static DEVELOPER_ID_G1_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/DeveloperIDCA.cer").to_vec())
.unwrap()
});
static DEVELOPER_ID_G2_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/DeveloperIDG2CA.cer").to_vec())
.unwrap()
});
static SOFTWARE_UPDATE_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(
include_bytes!("apple-certs/AppleSoftwareUpdateCertificationAuthority.cer").to_vec(),
)
.unwrap()
});
static TIMESTAMP_CERTIFICATE: Lazy<CapturedX509Certificate> = Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleTimestampCA.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G1_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCA.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G2_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCAG2.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G3_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCAG3.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G4_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCAG4.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G5_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCAG5.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G6_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCAG6.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G7_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCAG7.cer").to_vec())
.unwrap()
});
static WORLD_WIDE_DEVELOPER_RELATIONS_G8_CERTIFICATE: Lazy<CapturedX509Certificate> =
Lazy::new(|| {
CapturedX509Certificate::from_der(include_bytes!("apple-certs/AppleWWDRCAG8.cer").to_vec())
.unwrap()
});
static KNOWN_CERTIFICATES: Lazy<Vec<&CapturedX509Certificate>> = Lazy::new(|| {
vec![
APPLE_ROOT_CA_G3_ROOT_CERTIFICATE.deref(),
APPLE_ROOT_CA_G2_ROOT_CERTIFICATE.deref(),
APPLE_INC_ROOT_CERTIFICATE.deref(),
APPLE_COMPUTER_INC_ROOT_CERTIFICATE.deref(),
APPLE_IST_CA_2_G1_CERTIFICATE.deref(),
APPLE_IST_CA_8_G1_CERTIFICATE.deref(),
APPLICATION_INTEGRATION_CERTIFICATE.deref(),
APPLICATION_INTEGRATION_2_CERTIFICATE.deref(),
APPLICATION_INTEGRATION_G3_CERTIFICATE.deref(),
APPLE_APPLICATION_INTEGRATION_CA_5_G1_CERTIFICATE.deref(),
APPLE_APPLICATION_INTEGRATION_CA_7_G1_CERTIFICATE.deref(),
DEVELOPER_AUTHENTICATION_CERTIFICATE.deref(),
DEVELOPER_ID_G1_CERTIFICATE.deref(),
DEVELOPER_ID_G2_CERTIFICATE.deref(),
SOFTWARE_UPDATE_CERTIFICATE.deref(),
TIMESTAMP_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G1_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G2_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G3_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G4_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G5_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G6_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G7_CERTIFICATE.deref(),
WORLD_WIDE_DEVELOPER_RELATIONS_G8_CERTIFICATE.deref(),
]
});
static KNOWN_ROOTS: Lazy<Vec<&CapturedX509Certificate>> = Lazy::new(|| {
vec![
APPLE_ROOT_CA_G3_ROOT_CERTIFICATE.deref(),
APPLE_ROOT_CA_G2_ROOT_CERTIFICATE.deref(),
APPLE_INC_ROOT_CERTIFICATE.deref(),
APPLE_COMPUTER_INC_ROOT_CERTIFICATE.deref(),
]
});
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum KnownCertificate {
AppleComputerIncRoot,
AppleRootCa,
AppleRootCaG2Root,
AppleRootCaG3Root,
AppleIstCa2G1,
AppleIstCa8G1,
ApplicationIntegration,
ApplicationIntegration2,
ApplicationIntegrationG3,
AppleApplicationIntegrationCa5G1,
AppleApplicationIntegrationCa7G1,
DeveloperAuthentication,
DeveloperIdG1,
DeveloperIdG2,
SoftwareUpdate,
Timestamp,
WwdrG1,
WwdrG2,
WwdrG3,
WwdrG4,
WwdrG5,
WwdrG6,
WwdrG7,
WwdrG8,
}
impl Deref for KnownCertificate {
type Target = CapturedX509Certificate;
fn deref(&self) -> &Self::Target {
match self {
Self::AppleComputerIncRoot => APPLE_COMPUTER_INC_ROOT_CERTIFICATE.deref(),
Self::AppleRootCa => APPLE_INC_ROOT_CERTIFICATE.deref(),
Self::AppleRootCaG2Root => APPLE_ROOT_CA_G2_ROOT_CERTIFICATE.deref(),
Self::AppleRootCaG3Root => APPLE_ROOT_CA_G3_ROOT_CERTIFICATE.deref(),
Self::AppleIstCa2G1 => APPLE_IST_CA_2_G1_CERTIFICATE.deref(),
Self::AppleIstCa8G1 => APPLE_IST_CA_8_G1_CERTIFICATE.deref(),
Self::ApplicationIntegration => APPLICATION_INTEGRATION_CERTIFICATE.deref(),
Self::ApplicationIntegration2 => APPLICATION_INTEGRATION_2_CERTIFICATE.deref(),
Self::ApplicationIntegrationG3 => APPLICATION_INTEGRATION_G3_CERTIFICATE.deref(),
Self::AppleApplicationIntegrationCa5G1 => {
APPLE_APPLICATION_INTEGRATION_CA_5_G1_CERTIFICATE.deref()
}
Self::AppleApplicationIntegrationCa7G1 => {
APPLE_APPLICATION_INTEGRATION_CA_7_G1_CERTIFICATE.deref()
}
Self::DeveloperAuthentication => DEVELOPER_AUTHENTICATION_CERTIFICATE.deref(),
Self::DeveloperIdG1 => DEVELOPER_ID_G1_CERTIFICATE.deref(),
Self::DeveloperIdG2 => DEVELOPER_ID_G2_CERTIFICATE.deref(),
Self::SoftwareUpdate => SOFTWARE_UPDATE_CERTIFICATE.deref(),
Self::Timestamp => TIMESTAMP_CERTIFICATE.deref(),
Self::WwdrG1 => WORLD_WIDE_DEVELOPER_RELATIONS_G1_CERTIFICATE.deref(),
Self::WwdrG2 => WORLD_WIDE_DEVELOPER_RELATIONS_G2_CERTIFICATE.deref(),
Self::WwdrG3 => WORLD_WIDE_DEVELOPER_RELATIONS_G3_CERTIFICATE.deref(),
Self::WwdrG4 => WORLD_WIDE_DEVELOPER_RELATIONS_G4_CERTIFICATE.deref(),
Self::WwdrG5 => WORLD_WIDE_DEVELOPER_RELATIONS_G5_CERTIFICATE.deref(),
Self::WwdrG6 => WORLD_WIDE_DEVELOPER_RELATIONS_G6_CERTIFICATE.deref(),
Self::WwdrG7 => WORLD_WIDE_DEVELOPER_RELATIONS_G7_CERTIFICATE.deref(),
Self::WwdrG8 => WORLD_WIDE_DEVELOPER_RELATIONS_G8_CERTIFICATE.deref(),
}
}
}
impl AsRef<CapturedX509Certificate> for KnownCertificate {
fn as_ref(&self) -> &CapturedX509Certificate {
self.deref()
}
}
impl TryFrom<&CapturedX509Certificate> for KnownCertificate {
type Error = &'static str;
fn try_from(cert: &CapturedX509Certificate) -> Result<Self, Self::Error> {
let want = cert.constructed_data();
match cert.constructed_data() {
_ if APPLE_ROOT_CA_G3_ROOT_CERTIFICATE.constructed_data() == want => {
Ok(Self::AppleRootCaG3Root)
}
_ if APPLE_ROOT_CA_G2_ROOT_CERTIFICATE.constructed_data() == want => {
Ok(Self::AppleRootCaG2Root)
}
_ if APPLE_INC_ROOT_CERTIFICATE.constructed_data() == want => Ok(Self::AppleRootCa),
_ if APPLE_COMPUTER_INC_ROOT_CERTIFICATE.constructed_data() == want => {
Ok(Self::AppleComputerIncRoot)
}
_ if APPLE_IST_CA_2_G1_CERTIFICATE.constructed_data() == want => {
Ok(Self::AppleIstCa2G1)
}
_ if APPLE_IST_CA_8_G1_CERTIFICATE.constructed_data() == want => {
Ok(Self::AppleIstCa8G1)
}
_ if APPLICATION_INTEGRATION_CERTIFICATE.constructed_data() == want => {
Ok(Self::ApplicationIntegration)
}
_ if APPLICATION_INTEGRATION_2_CERTIFICATE.constructed_data() == want => {
Ok(Self::ApplicationIntegration2)
}
_ if APPLICATION_INTEGRATION_G3_CERTIFICATE.constructed_data() == want => {
Ok(Self::ApplicationIntegrationG3)
}
_ if APPLE_APPLICATION_INTEGRATION_CA_5_G1_CERTIFICATE.constructed_data() == want => {
Ok(Self::AppleApplicationIntegrationCa5G1)
}
_ if APPLE_APPLICATION_INTEGRATION_CA_7_G1_CERTIFICATE.constructed_data() == want => {
Ok(Self::AppleApplicationIntegrationCa7G1)
}
_ if DEVELOPER_AUTHENTICATION_CERTIFICATE.constructed_data() == want => {
Ok(Self::DeveloperAuthentication)
}
_ if DEVELOPER_ID_G1_CERTIFICATE.constructed_data() == want => Ok(Self::DeveloperIdG1),
_ if DEVELOPER_ID_G2_CERTIFICATE.constructed_data() == want => Ok(Self::DeveloperIdG2),
_ if SOFTWARE_UPDATE_CERTIFICATE.constructed_data() == want => Ok(Self::SoftwareUpdate),
_ if TIMESTAMP_CERTIFICATE.constructed_data() == want => Ok(Self::Timestamp),
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G1_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG1)
}
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G2_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG2)
}
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G3_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG3)
}
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G4_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG4)
}
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G5_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG5)
}
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G6_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG6)
}
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G7_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG7)
}
_ if WORLD_WIDE_DEVELOPER_RELATIONS_G8_CERTIFICATE.constructed_data() == want => {
Ok(Self::WwdrG8)
}
_ => Err("certificate not found"),
}
}
}
impl KnownCertificate {
pub fn all() -> &'static [&'static CapturedX509Certificate] {
KNOWN_CERTIFICATES.deref().as_ref()
}
pub fn all_roots() -> &'static [&'static CapturedX509Certificate] {
KNOWN_ROOTS.deref()
}
}
#[cfg(test)]
mod test {
use {
super::*,
crate::certificate::{AppleCertificate, CertificateAuthorityExtension},
};
#[test]
fn all() {
for cert in KnownCertificate::all() {
assert!(cert.subject_common_name().is_some());
assert!(KnownCertificate::try_from(*cert).is_ok());
}
}
#[test]
fn apple_root_ca() {
assert!(APPLE_INC_ROOT_CERTIFICATE.is_apple_root_ca());
assert!(!APPLE_INC_ROOT_CERTIFICATE.is_apple_intermediate_ca());
assert!(APPLE_COMPUTER_INC_ROOT_CERTIFICATE.is_apple_root_ca());
assert!(!APPLE_COMPUTER_INC_ROOT_CERTIFICATE.is_apple_intermediate_ca());
assert!(APPLE_ROOT_CA_G2_ROOT_CERTIFICATE.is_apple_root_ca());
assert!(!APPLE_ROOT_CA_G2_ROOT_CERTIFICATE.is_apple_intermediate_ca());
assert!(APPLE_ROOT_CA_G3_ROOT_CERTIFICATE.is_apple_root_ca());
assert!(!APPLE_ROOT_CA_G3_ROOT_CERTIFICATE.is_apple_intermediate_ca());
assert!(!WORLD_WIDE_DEVELOPER_RELATIONS_G3_CERTIFICATE.is_apple_root_ca());
assert!(WORLD_WIDE_DEVELOPER_RELATIONS_G3_CERTIFICATE.is_apple_intermediate_ca());
let wanted = [APPLE_INC_ROOT_CERTIFICATE.deref(),
APPLE_COMPUTER_INC_ROOT_CERTIFICATE.deref(),
APPLE_ROOT_CA_G2_ROOT_CERTIFICATE.deref(),
APPLE_ROOT_CA_G3_ROOT_CERTIFICATE.deref()];
for cert in KnownCertificate::all() {
if wanted.contains(cert) {
continue;
}
assert!(!cert.is_apple_root_ca());
assert!(cert.is_apple_intermediate_ca());
}
}
#[test]
fn intermediate_have_apple_ca_extension() {
for cert in KnownCertificate::all()
.iter()
.filter(|cert| !cert.is_apple_root_ca())
.filter(|cert| {
cert.issuer_name()
.iter_common_name()
.all(|atv| !atv.to_string().unwrap().contains("GeoTrust"))
})
{
assert!(!cert.apple_ca_extensions().is_empty());
}
assert_eq!(
KnownCertificate::DeveloperIdG1
.apple_ca_extensions()
.first(),
Some(&CertificateAuthorityExtension::DeveloperId)
);
assert_eq!(
KnownCertificate::DeveloperIdG2
.apple_ca_extensions()
.first(),
Some(&CertificateAuthorityExtension::DeveloperId)
);
assert_eq!(
KnownCertificate::WwdrG1.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelations)
);
assert_eq!(
KnownCertificate::WwdrG2.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelationsG2)
);
assert_eq!(
KnownCertificate::WwdrG3.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelations)
);
assert_eq!(
KnownCertificate::WwdrG4.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelations)
);
assert_eq!(
KnownCertificate::WwdrG5.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelations)
);
assert_eq!(
KnownCertificate::WwdrG6.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelations)
);
assert_eq!(
KnownCertificate::WwdrG7.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelations)
);
assert_eq!(
KnownCertificate::WwdrG8.apple_ca_extensions().first(),
Some(&CertificateAuthorityExtension::AppleWorldwideDeveloperRelations)
);
}
#[test]
fn chaining() {
let relevant = KnownCertificate::all()
.iter()
.filter(|cert| {
cert.issuer_name()
.iter_common_name()
.all(|atv| !atv.to_string().unwrap().contains("GeoTrust"))
})
.filter(|cert| {
cert.constructed_data() != APPLICATION_INTEGRATION_G3_CERTIFICATE.constructed_data()
&& cert.constructed_data()
!= APPLE_APPLICATION_INTEGRATION_CA_5_G1_CERTIFICATE.constructed_data()
});
for cert in relevant {
let chain = cert.resolve_signing_chain(KnownCertificate::all().iter().copied());
let apple_chain = cert.apple_issuing_chain();
assert_eq!(chain.len(), apple_chain.len());
}
}
}