Skip to content

Mutual SSL authentication not working with intermediate-only certificates #16305

@buglloc

Description

@buglloc

What version of gRPC and what language are you using?

C++ with gRPC v1.14.1

What operating system (Linux, Windows, …) and version?

GNU/Linux, Ubuntu 16.04 LTS

What did you do?

gRPC in during verification client certificates doesn't support SSL authentication based on intermediate certificates. My PKI setup:

RootCA -> IntermediateCA1 -> Client1 
RootCA -> IntermediateCA2 -> Client2

I want to use in gRPC IntermediateCA1, to allow access only to owner of the Client1 certificate, but can't.
If I setting up IntermediateCA1 certificate as pem_root_certs - gRPC fails to verify client certificate with error:

E0810 00:26:25.917160966  165457 ssl_transport_security.cc:1227] Handshake failed with fatal error SSL_ERROR_SSL: error:14089086:SSL routines:ssl3_get_client_certificate:certificate verify failed.

Or in case of using boringssl:

E0810 00:51:23.781119720  188272 ssl_transport_security.cc:1227] Handshake failed with fatal error SSL_ERROR_SSL: error:1000007d:SSL routines:OPENSSL_internal:CERTIFICATE_VERIFY_FAILED.

This is expected behavior, because by default certificate must be verified up to a trusted root (i.e. RootCA). But if I use bundle of IntermediateCA1 + RootCA gRPC allows connection for Client1 and Client2. Which, unfortunately, is also expected :(

I wrote a minimal example based on your helloworld to easily reproduce my case: https://github.com/buglloc/grpc-helloworld

What did you expect to see?

I expect that gRPC allows to use mutual SSL authentication in this case. For example, grpc-go are perfectly worked with intermediate-only trusted certificates.
What you think about setting up X509_V_FLAG_PARTIAL_CHAIN flag to allow intermediate certificates in the trust store to be treated as trust-anchors, in the same way as the self-signed root CA certificates?
I'll try to create the minimal patch:

diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc
index e66fc9b..fc3875f 100644
--- a/src/core/tsi/ssl_transport_security.cc
+++ b/src/core/tsi/ssl_transport_security.cc
@@ -645,6 +645,9 @@ static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
                                                   STACK_OF(X509_NAME) *
                                                       *root_name) {
   X509_STORE* cert_store = SSL_CTX_get_cert_store(context);
+#ifdef X509_V_FLAG_PARTIAL_CHAIN
+  X509_STORE_set_flags(cert_store, X509_VP_FLAG_DEFAULT | X509_V_FLAG_PARTIAL_CHAIN);
+#endif
   return x509_store_load_certs(cert_store, pem_roots, pem_roots_size,
                                root_name);
 }

Original gRPC behavior:

  • greeter_server (IntermediateCA1 only) - rejects any connections from Client1 or Client2
  • greeter_server --bundle (IntermediateCA1 + RootCA) - accepts connections from Client1 and Client2

After path:

  • greeter_server (IntermediateCA1 only) - accepts connection only from Client1
  • greeter_server --bundle (IntermediateCA1 + RootCA) - accepts connections from Client1 and Client2

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions