Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow path building to return the validated path #53

Closed
Tracked by #57
cpu opened this issue Apr 27, 2023 · 7 comments
Closed
Tracked by #57

Allow path building to return the validated path #53

cpu opened this issue Apr 27, 2023 · 7 comments

Comments

@cpu
Copy link
Member

cpu commented Apr 27, 2023

Presently the validate_cert.rs implementation of build_path used for path-building only returns an indication of whether the operation failed or not:

pub(crate) fn build_chain(
required_eku_if_present: KeyPurposeId,
supported_sig_algs: &[&SignatureAlgorithm],
trust_anchors: &[TrustAnchor],
intermediate_certs: &[&[u8]],
cert: &Cert,
time: time::Time,
sub_ca_count: usize,
) -> Result<(), Error> {

CRL validation also requires building a path from the issuer of the CRL to a trust anchor. Further, RFC 5280 6.3.3 says the path must be built to the same trust anchor used to validate the target end-entity certificate for which we're considering revocation status:

(f)  Obtain and validate the certification path for the issuer of
     the complete CRL.  The trust anchor for the certification
     path MUST be the same as the trust anchor used to validate
     the target certificate.  ....

At a minimum, the build_path implementation should yield the final TrustAnchor that was used to build the validated path so that we can ensure this requirement is met.

To avoid having to build a path from scratch from the issuer to that TrustAnchor it would be best if build_path could yield the full validated path including the intermediate certificates used. That would allow the CRL validation to proceed using the same validation path to the same root. This is the approach used by the gRPC implementation of CRL validation based on providing the implementation the verifiedChains [][]*x509.Certificate produced by path building.

Changing the implementation to yield just a TrustAnchor is fairly straight forward. Producing the full chain that was validated without making it require alloc is likely to be more difficult.

Related issue: briansmith/webpki#264

@cpu
Copy link
Member Author

cpu commented May 3, 2023

Changing the implementation to yield just a TrustAnchor is fairly straight forward. Producing the full chain that was validated without making it require alloc is likely to be more difficult.

Reading the existing cert.rs and verify_cert.rs code more carefully I realized we already have a way to represent this to look at for inspiration. The Cert.ee_or_ca field's Ca variant holds a &'a Cert<'a> ref that's used to track the child cert of the CA Cert in-hand. The verify_cert::check_signatures fn uses this to walk the chain built in build_chain backwards from the selected trust anchor to the leaf end entity certificate.

@cpu
Copy link
Member Author

cpu commented May 3, 2023

I thought I'd be able to smuggle out a &Cert from build_chain to use to reconstruct the path through ee_or_ca but the snag I'm hitting is that build_chain builds a Cert from intermediate DER internal to the second loop_while_non_fatal_error body while processing intermediates. I can't return a value from build_chain that references the value owned by that function:

let potential_issuer =
cert::parse_cert(untrusted::Input::from(cert_der), EndEntityOrCa::Ca(cert))?;

I can't change build_chain to take an owned Cert instead of &Cert because the consumers of build_chain are &self and can't move the inner Cert out. I'm going to continue trying to figure something out and will push a broken branch for some help if I stay stuck.

@djc
Copy link
Member

djc commented May 3, 2023

Can you replace the potential_issuer part of Cert with a Cow-like thing that would allow us to do either?

@cpu
Copy link
Member Author

cpu commented May 3, 2023

I experimented with that and I think the catch there was that Cert isn't Clone and some of its fields aren't either. I don't have the error in front of me at the moment. I might have been holding it wrong.

I also thought about having the caller transform the slice of DER references into Cert's up-front but that can't be done easily either (I thought I'd need to map + Collect into a vec which requires alloc, and there's the catch of needing to set the ee_or_ca field for the intermediates with pointers to the child certs). It might be doable but wasn't coming easy and front-loads parsing work we defer until later otherwise.

I had to log off for the day but my thought for a next idea is to try to return references to the DER of the built chain intermediates instead of the parsed Cert at the cost of having to re-build Cert from the DER elsewhere. The DER comes from the caller and has a lifetime that would encapsulate the built chain.

@cpu
Copy link
Member Author

cpu commented May 5, 2023

I think I'm going to take a different approach. I don't want to heavily refactor the existing path building just to support CRLs and haven't been able to arrive at a minimal change that's workable. I think it will be easier to consider the CRL path building and signature validation separate from the existing implementation to start.

@cpu
Copy link
Member Author

cpu commented May 5, 2023

I need to add test coverage but I think I've figured out a way forward. I was making life harder for myself trying to handle CRL validation separately from path building. Threading the CRL data into the existing validation works out better and obviates the requirement to pull the validated path out. It's also a better match to how 5280 + friends recommend this be handled.

@cpu
Copy link
Member Author

cpu commented May 17, 2023

Closing this since the approach I used in #66 doesn't require this and implementing it will require more significant changes to the core path building than I'm keen to bite off right now.

@cpu cpu closed this as completed May 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants