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

TlsStream::certificate_chain, ChainIterator type and Certificate::public_key_info_der #117

Open
wants to merge 21 commits into
base: master
Choose a base branch
from

Conversation

SergejJurecko
Copy link

This patch makes certificate pinning possible on top of rust-native-tls. What is required is access to the entire certificate chain and subjectPublicKeyInfo part of a certificate.

This is not ready to be merged yet, as I am waiting for downstream schannel and rust-security-framework patches to be merged.

I've created this PR now to resolve any blockers in the meantime.

@SergejJurecko
Copy link
Author

Also I would like to expose hashing algorithms (md5, sha256, sha384 and sha512) from rust-native-tls. Would this be agreeable? It goes a bit further then the stated goal of this project but it's very useful and quite commonly needed for anyone using this upstream.

@sfackler
Copy link
Owner

I have been thinking a bit about adding a native-crypto crate as a companion to native-tls, yeah. I have less confidence about what a good API for that would be, though. I'm personally more interested in cryptography bits in that context than hashing, since high-quality Rust implementations of sha etc are available.

}
}

pub struct TlsStream<S>(tls_stream::TlsStream<S>, Option<CertStore>);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use a struct here with named fields to make things a bit more clear.

if self.1.is_none() {
match self.0.peer_certificate() {
Ok(cert) => {
self.1 = cert.cert_store();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to cache the cert store?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not find a better solution. CertStore once you call certs is borrowed. You can't drop it and you can't put it in the iterator as it will be a self referenced struct.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like things would be easier to work with if we just returned a Result<Vec<Certificate>>. I don't think we're gaining all that much by not buffing the certs up again.

if let Some(trust) = self.trust.as_ref() {
let pos = self.pos;
self.pos += 1;
return trust.certificate_at_index(pos as _).map(Certificate);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to stop at the end of the chain, right?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trust will return None once it is over limit.

let trust = match self.stream.context().peer_trust2()? {
Some(trust) => trust,
None => {
return Ok(ChainIterator {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be restructured a bit to avoid having to have a separate early return:

let trust = match self.stream.context().peer_trust2()? {
    Some(trust) => {
        trust.evaluate()?;
        Some(trust)
    }
    None => None
};
...

@@ -630,6 +647,11 @@ impl<S: io::Read + io::Write> TlsStream<S> {
Ok(self.0.peer_certificate()?.map(Certificate))
}

/// Returns an iterator over certificate chain, if available.
pub fn certificate_chain(&mut self) -> Result<ChainIterator<S>> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we distinguish the "no chain present" case here by returning something like Result<Option<ChainIterator>>?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to create an empty iterator that just returns None immediately. That is what happens in the downstream crates. Result<Option> is a pretty annoying API.

@sfackler
Copy link
Owner

sfackler commented Mar 8, 2019

Should we add an intermediate PublicKey type instead of directly going from Certificate to DER-encoded public key?

@SergejJurecko
Copy link
Author

Not sure what the API would be for the PublicKey type. schannel-rs looks pretty sparse in this area. Since checks are passing right now, is there anything else to do with regards to this?

@SergejJurecko
Copy link
Author

Can I do anything more or is this not something you want merged?

@edevil
Copy link

edevil commented Sep 2, 2024

Having access to the certificate_chain() of a TlsStream is important when we're trying to implement something like DANE. Is there something that can be improved here so that it can be merged, or is this not something this project is interested in @sfackler ?

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

Successfully merging this pull request may close these issues.

3 participants