-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Mutual SSL authentication not working with intermediate-only certificates #16305
Description
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(IntermediateCA1only) - rejects any connections fromClient1orClient2greeter_server --bundle(IntermediateCA1 + RootCA) - accepts connections fromClient1andClient2
After path:
greeter_server(IntermediateCA1only) - accepts connection only fromClient1greeter_server --bundle(IntermediateCA1 + RootCA) - accepts connections fromClient1andClient2