Skip to content

Commit 7c20605

Browse files
committed
verify_cert: expose builder-like interface for path verification
1 parent ccf7c83 commit 7c20605

10 files changed

Lines changed: 288 additions & 324 deletions

src/end_entity.rs

Lines changed: 7 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,20 @@
1414

1515
use core::ops::Deref;
1616

17-
use pki_types::{
18-
CertificateDer, ServerName, SignatureVerificationAlgorithm, TrustAnchor, UnixTime,
19-
};
17+
use pki_types::{CertificateDer, ServerName, SignatureVerificationAlgorithm};
2018

21-
use crate::crl::RevocationOptions;
2219
use crate::error::Error;
2320
use crate::subject_name::{verify_dns_names, verify_ip_address_names};
24-
use crate::verify_cert::{self, ExtendedKeyUsageValidator, VerifiedPath};
2521
use crate::{cert, sct, signed_data};
2622

2723
/// An end-entity certificate.
2824
///
2925
/// Server certificate processing in a TLS connection consists of several
3026
/// steps. All of these steps are necessary:
3127
///
32-
/// * [`EndEntityCert::verify_for_usage()`]: Verify that the peer's certificate
33-
/// is valid for the current usage scenario. For server authentication, use
34-
/// [`crate::ExtendedKeyUsage::SERVER_AUTH`].
28+
/// * Build a [`VerifiedPath`][crate::VerifiedPath] using a [PathBuilder][crate::PathBuilder]:
29+
/// verify that the peer's certificate is valid for the current usage scenario. For server
30+
/// authentication, use [`crate::ExtendedKeyUsage::SERVER_AUTH`].
3531
/// * [`EndEntityCert::verify_is_valid_for_subject_name()`]: Verify that the server's
3632
/// certificate is valid for the host or IP address that is being connected to.
3733
/// * [`EndEntityCert::verify_signature()`]: Verify that the signature of server's
@@ -40,9 +36,9 @@ use crate::{cert, sct, signed_data};
4036
/// Client certificate processing in a TLS connection consists of analogous
4137
/// steps. All of these steps are necessary:
4238
///
43-
/// * [`EndEntityCert::verify_for_usage()`]: Verify that the peer's certificate
44-
/// is valid for the current usage scenario. For client authentication, use
45-
/// [`crate::ExtendedKeyUsage::CLIENT_AUTH`].
39+
/// * Build a [`VerifiedPath`][crate::VerifiedPath] using a [PathBuilder][crate::PathBuilder]:
40+
/// verify that the peer's certificate is valid for the current usage scenario. For client
41+
/// authentication, use [`crate::ExtendedKeyUsage::CLIENT_AUTH`].
4642
/// * [`EndEntityCert::verify_signature()`]: Verify that the signature of client's
4743
/// `CertificateVerify` message is valid using the public key from the
4844
/// client's certificate.
@@ -73,54 +69,6 @@ impl<'a> TryFrom<&'a CertificateDer<'a>> for EndEntityCert<'a> {
7369
}
7470

7571
impl EndEntityCert<'_> {
76-
/// Verifies that the end-entity certificate is valid for use against the
77-
/// specified Extended Key Usage (EKU).
78-
///
79-
/// * `supported_sig_algs` is the list of signature algorithms that are
80-
/// trusted for use in certificate signatures; the end-entity certificate's
81-
/// public key is not validated against this list.
82-
/// * `trust_anchors` is the list of root CAs to trust in the built path.
83-
/// * `intermediate_certs` is the sequence of intermediate certificates that
84-
/// a peer sent for the purpose of path building.
85-
/// * `time` is the time for which the validation is effective (usually the
86-
/// current time).
87-
/// * `usage` is the intended usage of the certificate, indicating what kind
88-
/// of usage we're verifying the certificate for. The default [`ExtendedKeyUsageValidator`]
89-
/// implementation is [`ExtendedKeyUsage`](crate::ExtendedKeyUsage).
90-
/// * `crls` is the list of certificate revocation lists to check
91-
/// the certificate against.
92-
/// * `verify_path` is an optional verification function for path candidates.
93-
///
94-
/// If successful, yields a `VerifiedPath` type that can be used to inspect a verified chain
95-
/// of certificates that leads from the `end_entity` to one of the `self.trust_anchors`.
96-
///
97-
/// `verify_path` will only be called for potentially verified paths, that is, paths that
98-
/// have been verified up to the trust anchor. As such, `verify_path()` cannot be used to
99-
/// verify a path that doesn't satisfy the constraints listed above; it can only be used to
100-
/// reject a path that does satisfy the aforementioned constraints. If `verify_path` returns
101-
/// an error, path building will continue in order to try other options.
102-
#[expect(clippy::too_many_arguments, clippy::type_complexity)]
103-
pub fn verify_for_usage<'p>(
104-
&'p self,
105-
supported_sig_algs: &[&dyn SignatureVerificationAlgorithm],
106-
trust_anchors: &'p [TrustAnchor<'_>],
107-
intermediate_certs: &'p [CertificateDer<'p>],
108-
time: UnixTime,
109-
usage: &dyn ExtendedKeyUsageValidator,
110-
revocation: Option<RevocationOptions<'_>>,
111-
verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
112-
) -> Result<VerifiedPath<'p>, Error> {
113-
verify_cert::PathBuilder {
114-
eku: usage,
115-
supported_sig_algs,
116-
trust_anchors,
117-
intermediate_certs,
118-
revocation,
119-
verify_path,
120-
}
121-
.build(self, time)
122-
}
123-
12472
/// Verifies that the certificate is valid for the given Subject Name.
12573
pub fn verify_is_valid_for_subject_name(
12674
&self,

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub use {
8383
trust_anchor::anchor_from_trusted_cert,
8484
verify_cert::{
8585
ExtendedKeyUsage, ExtendedKeyUsageValidator, IntermediateIterator, KeyPurposeId,
86-
KeyPurposeIdIter, RequiredEkuNotFoundContext, VerifiedPath,
86+
KeyPurposeIdIter, PathBuilder, RequiredEkuNotFoundContext, VerifiedPath,
8787
},
8888
};
8989

src/verify_cert.rs

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ use crate::error::Error;
3030
use crate::spki_for_anchor;
3131
use crate::{public_values_eq, subject_name};
3232

33+
/// Build a [`VerifiedPath`] for an end-entity certificate from the given trust anchors.
3334
// Use `'a` for lifetimes that we don't care about, `'p` for lifetimes that become a part of
3435
// the `VerifiedPath`.
35-
pub(crate) struct PathBuilder<'a, 'p> {
36-
pub(crate) eku: &'a dyn ExtendedKeyUsageValidator,
36+
pub struct PathBuilder<'a, 'p> {
37+
pub(crate) eku: &'p dyn ExtendedKeyUsageValidator,
3738
pub(crate) supported_sig_algs: &'a [&'a dyn SignatureVerificationAlgorithm],
3839
pub(crate) trust_anchors: &'p [TrustAnchor<'p>],
3940
pub(crate) intermediate_certs: &'p [CertificateDer<'p>],
@@ -43,7 +44,68 @@ pub(crate) struct PathBuilder<'a, 'p> {
4344
}
4445

4546
impl<'a, 'p: 'a> PathBuilder<'a, 'p> {
46-
pub(crate) fn build(
47+
/// Build a new [`PathBuilder`] with the given parameters.
48+
///
49+
/// * `eku` is the intended usage of the certificate, indicating what kind
50+
/// of usage we're verifying the certificate for. The default [`ExtendedKeyUsageValidator`]
51+
/// implementation is [`ExtendedKeyUsage`](crate::ExtendedKeyUsage).
52+
/// * `supported_sig_algs` is the list of signature algorithms that are
53+
/// trusted for use in certificate signatures; the end-entity certificate's
54+
/// public key is not validated against this list.
55+
/// * `trust_anchors` is the list of root CAs to trust in the built path.
56+
pub fn new(
57+
eku: &'p dyn ExtendedKeyUsageValidator,
58+
supported_sig_algs: &'a [&'a dyn SignatureVerificationAlgorithm],
59+
trust_anchors: &'p [TrustAnchor<'p>],
60+
) -> Self {
61+
Self {
62+
eku,
63+
supported_sig_algs,
64+
trust_anchors,
65+
intermediate_certs: &[],
66+
revocation: None,
67+
verify_path: None,
68+
}
69+
}
70+
71+
/// Set the sequence of intermediate certificates to use for path building.
72+
///
73+
/// These should be sent by the peer. Defaults to empty.
74+
pub fn with_intermediate_certs(mut self, intermediate_certs: &'p [CertificateDer<'p>]) -> Self {
75+
self.intermediate_certs = intermediate_certs;
76+
self
77+
}
78+
79+
/// Set the revocation options to use for path building.
80+
///
81+
/// By default, revocation checking is disabled.
82+
pub fn with_revocation(mut self, revocation: RevocationOptions<'a>) -> Self {
83+
self.revocation = Some(revocation);
84+
self
85+
}
86+
87+
/// Set a path verification function to use for path building.
88+
///
89+
/// `verify()` will only be called for potentially verified paths, that is, paths that
90+
/// have been verified up to the trust anchor. As such, `verify()` cannot be used to
91+
/// verify a path that doesn't satisfy the constraints listed above; it can only be used to
92+
/// reject a path that does satisfy the aforementioned constraints. If `verify()` returns
93+
/// an error, path building will continue in order to try other options.
94+
///
95+
/// By default, no additional path verification is done.
96+
pub fn with_path_verification(
97+
mut self,
98+
verify: &'a dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>,
99+
) -> Self {
100+
self.verify_path = Some(verify);
101+
self
102+
}
103+
104+
/// Build a [`VerifiedPath`] for `end_entity` at the given `time`.
105+
///
106+
/// If successful, yields a `VerifiedPath` type that can be used to inspect a verified chain
107+
/// of certificates that leads from the `end_entity` to one of the `self.trust_anchors`.
108+
pub fn build(
47109
&self,
48110
end_entity: &'p EndEntityCert<'p>,
49111
time: UnixTime,
@@ -173,9 +235,7 @@ impl<'a, 'p: 'a> PathBuilder<'a, 'p> {
173235
}
174236
}
175237

176-
/// Path from end-entity certificate to trust anchor that's been verified.
177-
///
178-
/// See [`EndEntityCert::verify_for_usage()`] for more details on what verification entails.
238+
/// Path from end-entity certificate to trust anchor that's been verified by a [`PathBuilder`].
179239
pub struct VerifiedPath<'p> {
180240
end_entity: &'p EndEntityCert<'p>,
181241
intermediates: Intermediates<'p>,
@@ -1361,18 +1421,23 @@ mod tests {
13611421
) -> Result<VerifiedPath<'a>, ControlFlow<Error, Error>> {
13621422
let time = UnixTime::since_unix_epoch(Duration::from_secs(0x1fed_f00d));
13631423
let mut path = PartialPath::new(ee_cert);
1364-
let opts = PathBuilder {
1365-
eku: &ExtendedKeyUsage::SERVER_AUTH,
1366-
supported_sig_algs: rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
1424+
1425+
let builder = PathBuilder::new(
1426+
&ExtendedKeyUsage::SERVER_AUTH,
1427+
rustls_aws_lc_rs::ALL_VERIFICATION_ALGS,
13671428
trust_anchors,
1368-
intermediate_certs,
1369-
revocation: None,
1370-
verify_path,
1429+
)
1430+
.with_intermediate_certs(intermediate_certs);
1431+
let builder = match verify_path {
1432+
Some(verify) => builder.with_path_verification(verify),
1433+
None => builder,
13711434
};
13721435

1373-
match opts.build_chain_inner(&mut path, time, 0, &mut budget.unwrap_or_default()) {
1436+
match builder.build_chain_inner(&mut path, time, 0, &mut budget.unwrap_or_default()) {
13741437
Ok(anchor) => Ok(VerifiedPath::new(ee_cert, anchor, path)),
13751438
Err(err) => Err(err),
13761439
}
13771440
}
1441+
1442+
//const EKU_SERVER_AUTH: ExtendedKeyUsage = ExtendedKeyUsage::server_auth();
13781443
}

0 commit comments

Comments
 (0)