quiche: make cert verification check extended key usage of the cert#18309
quiche: make cert verification check extended key usage of the cert#18309yanavlasov merged 11 commits intoenvoyproxy:mainfrom
Conversation
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
6713370 to
e634d47
Compare
|
/retest |
|
Retrying Azure Pipelines: |
|
/assign-from @envoyproxy/first-pass-reviewers |
|
@envoyproxy/first-pass-reviewers assignee is @wbpcode |
| return false; | ||
| } | ||
| // Currently only EnvoyQuicProofVerifier, which is used by the client code, calls this method. So | ||
| // hard-code "ssl_server" for now. |
There was a problem hiding this comment.
I think that since this method is always called to verify a chain of certs presented by a server, it is fine to use ssl_server here. In other words I don't think we need to mention EnvoyQuicProofVerifier in the comment and instead can simply explain that this method is always call to verify server certs.
What do you think?
There was a problem hiding this comment.
I rephrased the comment.
| } | ||
|
|
||
| TEST_F(EnvoyQuicProofVerifierTest, VerifyCertChainFailureNonServerAuthEKU) { | ||
| root_ca_cert_ = R"(-----BEGIN CERTIFICATE----- |
There was a problem hiding this comment.
Do we have documentation somewhere that explains how these certs were generated?
There was a problem hiding this comment.
Under test/config/integration/certs/ there are bunch of cert configs and certs.sh to generate various kinda cert. I just modified servercert.cfg a bit and run the script.
Commented about where this cert comes from.
RyanTheOptimist
left a comment
There was a problem hiding this comment.
Looks great. Thanks, Dan!
| } | ||
|
|
||
| TEST_F(EnvoyQuicProofVerifierTest, VerifyCertChainFailureNonServerAuthEKU) { | ||
| root_ca_cert_ = R"(-----BEGIN CERTIFICATE----- |
There was a problem hiding this comment.
Thanks for your contributions and sorry for the delayed review comments. Add some minor comments to the PR.
In addition, can you add a little more detailed background info about why we need this PR? Although I probably understand the purpose of your PR. But if there is some clear description, it will be more convenient for others to view this part of the code in the future.
| error_details = "Failed to verify certificate chain: X509_STORE_CTX_set_default"; | ||
| return false; |
There was a problem hiding this comment.
Can we add a case to test this if branch?
There was a problem hiding this comment.
TBH, it's not clear to me how X509_STORE_CTX_set_default() would return 0 with "ssl_server". Probably this is impossible if the name is hard-coded to "ssl_server". But I'm not a boring SSL expert.
There was a problem hiding this comment.
Even if it is impossible with the hard-coded parameter, I would still prefer to handle the case where it returns 0 so that future BoringSSL change doesn't break Envoy in a unexpected way.
There was a problem hiding this comment.
Get it. But it seems that without this test, the test coverage is not up to the requirements. We can let the maintainer decide whether we can reduce the coverage requirement of this module.
There was a problem hiding this comment.
added a few irrelevant tls unit tests to raise coverage.
There was a problem hiding this comment.
Correct, this is impossible with a hard-coded parameter. To synthetically generate code coverage, you'd have to allow the name ("ssl_server") to be injectable by the test, and then supply an invalid/unregistered name.
| } | ||
|
|
||
| TEST_F(EnvoyQuicProofVerifierTest, VerifyCertChainFailureNonServerAuthEKU) { | ||
| // Override the CA cert with test/config/integration/certs/ca.pem |
There was a problem hiding this comment.
spelling error: ca.pem -> cacert.pem
and
minor suggestion: May be Override the CA cert with cert copied from test/config/integration/certs/cacert.pem. is more clear.
| // This is a cert same as test/config/integration/certs/servercert.pem but with extKeyUsage: | ||
| // clientAuth. |
There was a problem hiding this comment.
I think here should be a more accurate description of the process of generating this cert.
May be: This is a cert generated with the test/config/integration/certs/certs.sh. And the config that used to generate this cert is same as test/config/integration/certs/servercert.cfg but with 'extKeyUsage: clientAuth'.
|
Thanks, it's look good overall for me. However, it seems that because the newly added code is not covered by the test, the coverage does not meet the requirements.
@envoyproxy/envoy-maintainers |
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
|
/retest |
|
Retrying Azure Pipelines: |
|
/retest |
|
Retrying Azure Pipelines: |
| bool isThreadSafe() const { | ||
| return callbacks_ != nullptr && callbacks_->connection().dispatcher().isThreadSafe(); | ||
| } |
There was a problem hiding this comment.
It is only called in one place in ASSERT() which is not ignored in coverage tests. In order to raise the coverage, I inlined it instead.
There was a problem hiding this comment.
I see. But I personally don't think this is good choice. 🤣
There was a problem hiding this comment.
Can we just add some other tests to raise up cov or just edit the cov requirements?
There was a problem hiding this comment.
c296145 already added some unit tests which is irrelevant to this PR. And now the coverage CI is happy.
As to inlining isThreadSafe() it makes much sense to me as it was a private method called only in one place which is an ASSERT().
There was a problem hiding this comment.
I know it's OK to inline this method. But besides improving cov, what other useful effects does this removing have? 🤔
There was a problem hiding this comment.
I mean, maybe we shouldn't make this kind of modification that has nothing to do with this PR or feature itself just in order to improve cov. Of course, this is just a personal thought.
Anyway, I have already approve this PR for the maintainer to do further review. Thanks very much for you contributions. 😃
There was a problem hiding this comment.
Thanks. I will give an approve to push the PR to the next step.
It is only called in one place in ASSERT() which is not ignored in coverage tests. In order to raise the coverage, I inlined it instead.
I personally think this is not a good choice but keep it for the further review of @envoyproxy/senior-maintainers
|
/assign @alyssawilk |
| if (!X509_STORE_CTX_set_default(ctx.get(), "ssl_server")) { | ||
| error_details = "Failed to verify certificate chain: X509_STORE_CTX_set_default"; | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Question: Should you also be inheriting the params from the SSL_CTX? I don't see this file manipulating them in any way, but it's an edge case I wanted to call out. Specifically, the following elements of the SSL_CTX are not carried over, so if they were ever used to configure the SSL_CTX, they wouldn't be propagated to the Quiche path:
SSL{_CTX}_set_verify_depthSSL{_CTX}_set1_paramSSL{_CTX}_set_purposeSSL{_CTX}_set_trust
Because this code already grabs the SSL_CTX_set_cert_store path (line 1169), perhaps it makes sense to do so here as well?
| } | |
| } | |
| if (!X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(ctx.get()), | |
| SSL_CTX_get0_param(ssl_ctx))) { | |
| error_details = "Failed to verify certificate chain: X509_VERIFY_PARAM_set1"; | |
| return false; | |
| } |
This will copy the X509_VERIFY_PARAM config from the SSL_CTX into the X509_STORE_CTX's verify param as appropriate, and matches the SSL/TLS layer implementation.
There was a problem hiding this comment.
To address the testing/coverage question: This is also an "impossible failure" scenario; the only way for this to fail is for SSL_CTX_get0_param to return an invalid parameter (since it will not return nullptr)
Because X509_VERIFY_PARAM is an opaque struct, whose setters validate the incoming parameters, to get an invalid parameter into the SSL_CTX_get0_param, you must have first used one of the X509_VERIFY_PARAM_set functions, which would have similarly validated the parameters then. So this leaves the only possible room for failure being a malloc failure, which presumably will blow things up spectacularly anyways out of necessity :)
There was a problem hiding this comment.
Envoy doesn't config those aspects of SSL_CTX objects AFAIK. But sure that we can add X509_VERIFY_PARAM_set1() just in case.
Q please, with X509_VERIFY_PARAM_set1(), do I still need to call X509_STORE_CTX_set_default()?
| error_details = "Failed to verify certificate chain: X509_STORE_CTX_set_default"; | ||
| return false; |
There was a problem hiding this comment.
Correct, this is impossible with a hard-coded parameter. To synthetically generate code coverage, you'd have to allow the name ("ssl_server") to be injectable by the test, and then supply an invalid/unregistered name.
Signed-off-by: Dan Zhang <danzh@google.com>
|
/assign @yanavlasov |
|
/retest |
|
Retrying Azure Pipelines: |
|
@sleevi @yanavlasov PTAL |
sleevi
left a comment
There was a problem hiding this comment.
LGTM from a Boring/OpenSSL perspective.
Restrict the set of certificates Envoy, as a TLS client, accepts from the peer to only those certificates that contain extendedKeyUsage: serverAuth. The change only affects QUIC.
Risk Level: low, QUIC support is in alpha
Testing: added unit tests in QUIC proof verifier