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

tls: make X.509 certificate parsing and verification explicit. #10621

Closed
wants to merge 14 commits into from

Conversation

PiotrSikora
Copy link
Contributor

@PiotrSikora PiotrSikora commented Apr 2, 2020

BoringSSL would like to deprecate OpenSSL's X.509 certificate parsing
and verification code. Although the replacements are not yet ready,
we can take a step in this direction by making certificate parsing
and certificate chain validation explicit.

This changes Envoy to use TLS_with_buffers_method(), which removes the
OpenSSL behavior of parsing certificates to an |X509| object implicitly,
as well as the behavior of calling X509_verify_cert() implicitly.
Instead, Envoy now does these things explicitly, as required.

Usefully, operations that require parsing (such as extracting a
certificate's serial number) are now distinguished from operations
that do not require parsing (such as returning the SHA-256 hash of a
certificate's DER encoding).

This makes it easier to take the next step of using a better parser,
when it is available.

Risk Level: Medium
Testing: Existing tests
Docs Changes: N/A (not user-visible change)
Release Notes: N/A (not user-visible change)

Signed-off-by: Matt Braithwaite mab@google.com
Signed-off-by: Piotr Sikora piotrsikora@google.com

BoringSSL would like to deprecate OpenSSL's X.509 certificate parsing
and verification code. Although the replacements are not yet ready,
we can take a step in this direction by making certificate parsing
and certificate chain validation explicit.

This changes Envoy to use TLS_with_buffers_method(), which removes the
OpenSSL behavior of parsing certificates to an |X509| object implicitly,
as well as the behavior of calling X509_verify_cert() implicitly.
Instead, Envoy now does these things explicitly, as required.

Usefully, operations that require parsing (such as extracting a
certificate's serial number) are now distinguished from operations
that do not require parsing (such as returning the SHA-256 hash of a
certificate's DER encoding).

This makes it easier to take the next step of using a better parser,
when it is available.

Signed-off-by: Matt Braithwaite <mab@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
@PiotrSikora PiotrSikora requested review from agl and lizan April 2, 2020 00:10
@PiotrSikora
Copy link
Contributor Author

cc @SAHF

@PiotrSikora PiotrSikora requested a review from ggreenway April 2, 2020 00:27
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
@PiotrSikora
Copy link
Contributor Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s), but failed to run 2 pipeline(s).

Copy link
Member

@lizan lizan left a comment

Choose a reason for hiding this comment

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

This looks good but scares me a bit. Can you add the PR template to the PR description, mark it at least Medium risk level? Would love to get @ggreenway to double check.

source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
@ggreenway
Copy link
Contributor

Can you provide more information about the changes happening in BoringSSL, so I have more context on this change? What has happened already, and what is planned for the future?

Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
@PiotrSikora
Copy link
Contributor Author

@ggreenway BoringSSL comes with X.509 parser and verifier it inherited from OpenSSL, but that codebase is not actively maintained, and Google doesn't use it anymore.

This PR effectively removes X.509 parsing and verification from BoringSSL's internal processing, and moves it to Envoy, which coincidentally uses X.509 parser and verifier that's bundled with BoringSSL, but it can be replaced with others in the future.

The certificate verifier that we should eventually use is hidden inside Chromium's codebase, but it's not yet a standalone project, so it's going to be a while before we can use it in Envoy.

Copy link
Contributor

@ggreenway ggreenway left a comment

Choose a reason for hiding this comment

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

I'm uncomfortable with moving core TLS stuff out of the TLS library (BoringSSL) and into Envoy. If BoringSSL is moving towards pushing this into chromium, can we work on factoring out the chromium code into a re-usable library instead of re-implementing it in Envoy?

Copy link
Contributor Author

@PiotrSikora PiotrSikora left a comment

Choose a reason for hiding this comment

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

I'm uncomfortable with moving core TLS stuff out of the TLS library (BoringSSL) and into Envoy. If BoringSSL is moving towards pushing this into chromium, can we work on factoring out the chromium code into a re-usable library instead of re-implementing it in Envoy?

@ggreenway We're not re-implementing certificate verification in Envoy. This PR separates TLS processing (using BoringSSL) from certificate verification (using X.509 verifier from BoringSSL), so that we could use the separate library for certificate verification when it's ready.

I've been asking about moving Chromium's certificate verifier to a standalone library for a while, but I don't have anything to share yet. It's going to be available, eventually...

@ggreenway
Copy link
Contributor

We're not re-implementing certificate verification in Envoy.

Right, but in my mind I was including all the byte-level parsing. I'd like a higher-level API. Either an API that takes the raw DER and finds what it needs itself, or an accessor from BoringSSL that finds the bits we need to pass to a verifier. Anytime I see CBS it seems out of place to me; it doesn't seem like Envoy should be parsing at that level.

@stale
Copy link

stale bot commented Apr 14, 2020

This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale bot added the stale stalebot believes this issue/PR has not been touched recently label Apr 14, 2020
@stale
Copy link

stale bot commented Apr 23, 2020

This pull request has been automatically closed because it has not had activity in the last 14 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale bot closed this Apr 23, 2020
@PiotrSikora
Copy link
Contributor Author

Right, but in my mind I was including all the byte-level parsing. I'd like a higher-level API. Either an API that takes the raw DER and finds what it needs itself, or an accessor from BoringSSL that finds the bits we need to pass to a verifier. Anytime I see CBS it seems out of place to me; it doesn't seem like Envoy should be parsing at that level.

The functions in question are part of the aforementioned Chromium's certificate verifier, so it's unlikely that they'll be added to BoringSSL itself, since they're a part of the component that's getting extracted into a separate library.

Also, as you've already noticed, those functions already exist in Envoy (in QuicCertUtilsImpl), so it's unclear why they're fine there, but we're blocking this PR on them. Seems inconsistent.

@PiotrSikora PiotrSikora reopened this May 18, 2020
@stale stale bot removed the stale stalebot believes this issue/PR has not been touched recently label May 18, 2020
@ggreenway
Copy link
Contributor

The functions in question are part of the aforementioned Chromium's certificate verifier, so it's unlikely that they'll be added to BoringSSL itself, since they're a part of the component that's getting extracted into a separate library.

I don't feel strongly about which library they come from. But I do feel that byte-level parsing certificates (or the protocol) should be coming from some library, not directly in Envoy.

When everything you want to be exported from chromium is exported, what will this code look like? Will it be mostly as it is in this PR, but we'll replace a call to X509_verify_cert() with something else?

As I see it, if BoringSSL removes it's x509 parsing/verifying code, this change will be needed whether I like it or not. I'm trying to get a sense of how much of this is "final" and how much of this is just an intermediate step.

Also, as you've already noticed, those functions already exist in Envoy (in QuicCertUtilsImpl), so it's unclear why they're fine there, but we're blocking this PR on them. Seems inconsistent.

I understand the frustration, but that is somewhat different. That function is part of the quiche API for supporting a platform. I don't think there is any alternative.

@PiotrSikora
Copy link
Contributor Author

I don't feel strongly about which library they come from. But I do feel that byte-level parsing certificates (or the protocol) should be coming from some library, not directly in Envoy.

When everything you want to be exported from chromium is exported, what will this code look like? Will it be mostly as it is in this PR, but we'll replace a call to X509_verify_cert() with something else?

As I see it, if BoringSSL removes it's x509 parsing/verifying code, this change will be needed whether I like it or not. I'm trying to get a sense of how much of this is "final" and how much of this is just an intermediate step.

The certificate-parsing functions would be replaced with calls to their copies in Chromium's certificate verifier (see: ExtractSubjectFromDERCert(), ExtractSPKIFromDERCert()), and X509_verify_cert() would be replaced with CertVerifier::Verify(). But I'm not involved in that work, and there is no timeline, so we might be stuck with functions as in this PR for a while.

Having said that, the switch to CRYPTO_BUFFER APIs (which is majority of this PR) has other benefits, like deduplication of the same certificate when used multiple times in the configuration (intermediate certificates, trusted CAs, etc.). This is not implemented in this PR, but it should be fairly easy to add.

@stale
Copy link

stale bot commented May 30, 2020

This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale bot added the stale stalebot believes this issue/PR has not been touched recently label May 30, 2020
@stale stale bot removed the stale stalebot believes this issue/PR has not been touched recently label Jul 15, 2020
@PiotrSikora
Copy link
Contributor Author

@ggreenway @alyssawilk is there any way that we can move this forward?

@alyssawilk
Copy link
Contributor

The QUIC code you reference is considered to be an untrusted path. As discussed offline, if we need them for QUICHE and Envoy though, maybe we could add them to boringssl directly, since they seem to be general utility functions for crypto handshakes? Then more crypto-savvy folks could own and maintain and we could just consume? cc @agl

source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
source/extensions/transport_sockets/tls/context_impl.cc Outdated Show resolved Hide resolved
}());
}

bool seekToSubject(CRYPTO_BUFFER* cert, CBS* tbs_certificate) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this (and the other similar functions) return optional? I'm assuming CBS is just a pointer and length (not a big struct).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, let's make it return an optional.

@ggreenway
Copy link
Contributor

/wait

@stale
Copy link

stale bot commented Aug 8, 2020

This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale bot added the stale stalebot believes this issue/PR has not been touched recently label Aug 8, 2020
@PiotrSikora
Copy link
Contributor Author

Not stale.

@stale stale bot removed the stale stalebot believes this issue/PR has not been touched recently label Aug 9, 2020
…buffers

Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
@PiotrSikora
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines, to retry CircleCI checks, use /retest-circle.
Check envoy-presubmit (Linux-x64 compile_time_options) didn't fail.

🐱

Caused by: a #10621 (comment) was created by @PiotrSikora.

see: more, trace.

}());
}

bool seekToSubject(CRYPTO_BUFFER* cert, CBS* tbs_certificate) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, let's make it return an optional.


ContextImpl* impl = reinterpret_cast<ContextImpl*>(SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl)));
const Network::TransportSocketOptions* transport_socket_options =
static_cast<const Network::TransportSocketOptions*>(SSL_get_app_data(ssl));
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this would be clearer as a reinterpret_cast

// subject Name,
// subjectPublicKeyInfo SubjectPublicKeyInfo,
// ...
if (!CBS_get_asn1(&der, &certificate, CBS_ASN1_SEQUENCE) ||
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add some test coverage for this. At least the case of of trailing junk after cert, and an invalid cert (either complete junk, or a cert that's in some way invalid (missing a required field, etc)). I want to make sure that the code is exercised a bit since the error path is reachable by client-controlled data.

@stale
Copy link

stale bot commented Aug 23, 2020

This pull request has been automatically marked as stale because it has not had activity in the last 7 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

@stale stale bot added the stale stalebot believes this issue/PR has not been touched recently label Aug 23, 2020
@stale
Copy link

stale bot commented Aug 30, 2020

This pull request has been automatically closed because it has not had activity in the last 14 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale stalebot believes this issue/PR has not been touched recently
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants