Skip to content

Commit ebafbd4

Browse files
authored
chore: Remove x509-parser crate from deps (#90)
1 parent 78ebf7a commit ebafbd4

File tree

9 files changed

+488
-114
lines changed

9 files changed

+488
-114
lines changed

Cargo.toml

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,44 +14,46 @@ edition = "2021"
1414
[dependencies]
1515

1616
# Cryptography
17-
x509-parser = { version = "0.18.0", features = ["verify", "validate"] }
18-
jsonwebtoken = { version = "9.3.1" }
17+
jsonwebtoken = { version = "10.2.0", features = ["rust_crypto"] }
1918
ring = "0.17.14"
20-
pem-rfc7468 = "1.0.0-rc.3"
21-
der = { version = "0.7.10", features = ["alloc", "oid"], optional = true }
22-
x509-ocsp = { version = "0.2.1", optional = true}
23-
x509-cert = { version = "0.2.5", optional = true }
19+
pem-rfc7468 = "1.0.0"
20+
der = { version = "0.7.10", features = ["alloc", "oid"] }
21+
x509-cert = { version = "0.2.5", features = ["std"] }
22+
x509-ocsp = { version = "0.2.1" , optional = true }
23+
const-oid = { version = "0.9.6" }
24+
spki = { version = "0.7.3" }
25+
sha1 = { version = "0.10.6" }
2426

2527
# Serialization
26-
serde = { version = "1.0.219", features = ["derive"] }
27-
serde_json = { version = "1.0.143" }
28-
serde_with = { version = "3.14.0", features = ["chrono"] }
28+
serde = { version = "1.0.228", features = ["derive"] }
29+
serde_json = { version = "1.0.145" }
30+
serde_with = { version = "3.15.1", features = ["chrono"] }
2931
serde_repr = "0.1.20"
3032
uuid = { version = "1.18.1", features = ["serde", "v4"] }
31-
chrono = { version = "0.4.41", features = ["serde"] }
33+
chrono = { version = "0.4.42", features = ["serde"] }
3234
base64 = "0.22.1"
3335

3436
# Networking
35-
reqwest = { version = "0.12.23", default-features = false, features = ["json"], optional = true }
37+
reqwest = { version = "0.12.24", default-features = false, features = ["json"], optional = true }
3638
http = { version = "1.3.1", optional = true }
3739

3840
# Utils
39-
thiserror = "2.0.16"
41+
thiserror = "2.0.17"
4042

4143
# Tools
42-
regex = { version = "1.11.2", optional = true }
44+
regex = { version = "1.12.2", optional = true }
4345

4446
[dev-dependencies]
4547

46-
tokio = { version = "1.47.1", features = ["test-util", "macros"] }
47-
jsonwebtoken = { version = "9.3.1", features = ["use_pem"] }
48+
tokio = { version = "1.48.0", features = ["test-util", "macros"] }
49+
jsonwebtoken = { version = "10.2.0", features = ["use_pem"] }
4850

4951
[features]
5052
api-client = ["dep:http"]
5153
api-client-reqwest = ["api-client", "dep:reqwest", "reqwest/rustls-tls-native-roots"]
5254
api-client-reqwest-native-tls = ["api-client", "dep:reqwest", "reqwest/default-tls"]
5355
receipt-utility = ["dep:regex"]
54-
ocsp = ["dep:x509-ocsp", "dep:x509-cert", "dep:reqwest", "reqwest/blocking", "dep:der"]
56+
ocsp = ["dep:x509-ocsp", "dep:reqwest", "reqwest/blocking"]
5557

5658
[[test]]
5759
name = "ass_api_client"

src/asn1/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#![cfg(feature = "receipt-utility")]
2-
pub mod asn1_basics;
1+
#[cfg(any(feature = "receipt-utility", feature = "ocsp"))]
2+
pub mod asn1_basics;

src/chain_verifier.rs

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,31 @@
1+
use crate::x509::x509::X509Error;
12
use crate::chain_verifier::ChainVerificationFailureReason::{
23
CertificateExpired, InvalidCertificate, InvalidEffectiveDate,
34
};
45
use thiserror::Error;
56

6-
use x509_parser::certificate::X509Certificate;
7-
use x509_parser::der_parser::asn1_rs::oid;
8-
use x509_parser::error::X509Error;
9-
use x509_parser::prelude::{ASN1Time, FromDer};
7+
use x509_cert::Certificate;
8+
use const_oid::ObjectIdentifier;
9+
use crate::x509::x509;
1010

1111
#[derive(Error, Debug, PartialEq)]
1212
pub enum ChainVerifierError {
1313
#[error("VerificationFailure: [{0}]")]
1414
VerificationFailure(ChainVerificationFailureReason),
1515

1616
#[error("InternalX509Error: [{0}]")]
17-
InternalX509Error(#[from] X509Error),
17+
InternalX509Error(String),
1818

1919
#[error("InternalDecodeError: [{0}]")]
2020
InternalDecodeError(#[from] base64::DecodeError),
2121
}
2222

23+
impl From<X509Error> for ChainVerifierError {
24+
fn from(err: X509Error) -> Self {
25+
ChainVerifierError::InternalX509Error(err.to_string())
26+
}
27+
}
28+
2329
#[derive(Error, Debug, PartialEq)]
2430
pub enum ChainVerificationFailureReason {
2531
#[error("InvalidAppIdentifier")]
@@ -96,37 +102,39 @@ impl ChainVerifier {
96102
if self.root_certificates.is_empty() {
97103
return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
98104
}
99-
let Ok(leaf_certificate) = X509Certificate::from_der(leaf_certificate.as_slice()) else {
100-
return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
101-
};
102-
let leaf_certificate = leaf_certificate.1;
103105

104-
let Some(_) = leaf_certificate.get_extension_unique(&oid!(1.2.840.113635.100.6.11.1))? else {
105-
return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
106-
};
106+
let leaf_certificate = x509::parse_certificate(leaf_certificate.as_slice())
107+
.map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
108+
109+
// Check for Apple-specific leaf certificate extension (1.2.840.113635.100.6.11.1)
110+
let leaf_oid = ObjectIdentifier::new("1.2.840.113635.100.6.11.1")
111+
.map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
107112

108-
let Ok(intermediate_certificate) = X509Certificate::from_der(intermediate_certificate.as_slice()) else {
113+
if !x509::has_extension(&leaf_certificate, &leaf_oid) {
109114
return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
110-
};
111-
let intermediate_certificate = intermediate_certificate.1;
115+
}
116+
117+
let intermediate_certificate = x509::parse_certificate(intermediate_certificate.as_slice())
118+
.map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
119+
120+
// Check for Apple-specific intermediate certificate extension (1.2.840.113635.100.6.2.1)
121+
let intermediate_oid = ObjectIdentifier::new("1.2.840.113635.100.6.2.1")
122+
.map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
112123

113-
let Some(_) = intermediate_certificate.get_extension_unique(&oid!(1.2.840.113635.100.6.2.1))? else {
124+
if !x509::has_extension(&intermediate_certificate, &intermediate_oid) {
114125
return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
115-
};
126+
}
116127

117-
let mut root_certificate: Option<X509Certificate> = None;
128+
let mut root_certificate: Option<Certificate> = None;
118129

119130
for cert in &self.root_certificates {
120-
let Ok(cert) = X509Certificate::from_der(&cert) else {
121-
return Err(ChainVerifierError::VerificationFailure(InvalidCertificate));
122-
};
131+
let cert = x509::parse_certificate(&cert)
132+
.map_err(|_| ChainVerifierError::VerificationFailure(InvalidCertificate))?;
123133

124-
match intermediate_certificate.verify_signature(Some(cert.1.public_key())) {
125-
Ok(_) => (),
126-
Err(_) => continue,
134+
if x509::verify_signature(&intermediate_certificate, &cert).is_ok() {
135+
root_certificate = Some(cert);
136+
break;
127137
}
128-
129-
root_certificate = Some(cert.1)
130138
}
131139

132140
let Some(root_certificate) = root_certificate else {
@@ -143,31 +151,27 @@ impl ChainVerifier {
143151

144152
fn verify_chain(
145153
&self,
146-
leaf: &X509Certificate,
147-
intermediate: &X509Certificate,
148-
root_certificate: &X509Certificate,
154+
leaf: &Certificate,
155+
intermediate: &Certificate,
156+
root_certificate: &Certificate,
149157
effective_date: Option<u64>,
150158
) -> Result<Vec<u8>, ChainVerifierError> {
151-
leaf.verify_signature(Some(intermediate.public_key()))?;
159+
x509::verify_signature(leaf, intermediate)?;
152160

153161
if let Some(date) = effective_date {
154-
let Ok(time) = ASN1Time::from_timestamp(i64::try_from(date).unwrap()) else {
155-
return Err(ChainVerifierError::VerificationFailure(
156-
InvalidEffectiveDate,
157-
));
158-
};
159-
160-
if !(root_certificate.validity.is_valid_at(time) &&
161-
leaf.validity.is_valid_at(time) &&
162-
intermediate.validity.is_valid_at(time))
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)
163168
{
164169
return Err(ChainVerifierError::VerificationFailure(CertificateExpired));
165170
}
166171
}
167172

168-
let k = leaf.public_key().raw.to_vec();
173+
let public_key_bytes = x509::public_key_bytes(leaf);
169174

170-
// Make online verification as additional step if ocsp flag enabled
171175
#[cfg(all(feature = "ocsp"))]
172176
{
173177
// Perform OCSP check - this is best-effort, so we don't fail on OCSP errors
@@ -188,6 +192,6 @@ impl ChainVerifier {
188192
}
189193
};
190194

191-
Ok(k)
195+
Ok(public_key_bytes)
192196
}
193197
}

0 commit comments

Comments
 (0)