I am trying to do mTLS with a server using gRPC 1.46.0/OpenSSL 3.0.3 on
Linux/C++
Below is a snippet of how I prepare `SSLChannelCredentials`:
std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials() {
std::ifstream root_cert_path(GetRootCertPath());
std::string root_cert(std::istreambuf_iterator<char>{root_cert_path}, {});
std::ifstream client_key_path(GetClientKeyPath());
std::string client_key(std::istreambuf_iterator<char>{client_key_path},
{});
std::ifstream client_cert_path(GetClientCertPath());
std::string client_cert(std::istreambuf_iterator<char>{client_cert_path},
{});
grpc::SslCredentialsOptions cred_opts;
cred_opts.pem_root_certs = root_cert;
cred_opts.pem_private_key = client_key;
cred_opts.pem_cert_chain = client_cert;
return grpc::SslCredentials(cred_opts);
}
And this fails with the following debug log:
I0617 10:21:51.992245501 409 socket_utils_common_posix.cc:353]
TCP_USER_TIMEOUT is available. TCP_USER_TIMEOUT will be used thereafter
I0617 10:21:54.979146083 407 ssl_transport_security.cc:226] HANDSHAKE START
- before SSL initialization - PINIT I0617 10:21:54.979203105 407
ssl_transport_security.cc:226] LOOP - before SSL initialization - PINIT
I0617 10:21:54.979849401 407 ssl_transport_security.cc:226] LOOP -
SSLv3/TLS write client hello - TWCH I0617 10:21:59.975724008 409
ssl_transport_security.cc:226] LOOP - SSLv3/TLS write client hello - TWCH
I0617 10:21:59.975958355 409 ssl_transport_security.cc:226] LOOP -
SSLv3/TLS read server hello - TRSH I0617 10:21:59.975972388 409
ssl_transport_security.cc:226] LOOP - TLSv1.3 read encrypted extensi - TREE
I0617 10:21:59.976032247 409 ssl_transport_security.cc:226] LOOP -
SSLv3/TLS read server certific - TRCR E0617 10:21:59.976188482 409
ssl_transport_security.cc:1495] Handshake failed with fatal error
SSL_ERROR_SSL: error:1416F086:SSL
routines:tls_process_server_certificate:certificate verify failed. D0617
10:21:59.976230069 409 security_handshaker.cc:181] Security handshake
failed: {"created":"@1655461319.976196203","description":"Handshake
failed","file":"/grpc/src/core/lib/security/transport/security_handshaker.cc","file_line":377,"tsi_code":10,"tsi_error":"TSI_PROTOCOL_FAILURE"}
I0617 10:21:59.976453245 409 subchannel.cc:948] subchannel 0x619000064a80
{address=ipv6:[2a05:d014:c4b:3500:bb49:5b5c:47c:5191]:443,
args=grpc.client_channel_factory=0x602000001cb0,
grpc.default_authority=mtls.gateway.nightowl.go-e.co:443,
grpc.http2.max_pings_without_data=0, grpc.http2_scheme=https,
grpc.internal.channel_credentials=0x606000005b40,
grpc.internal.security_connector=0x60d000023280,
grpc.internal.subchannel_pool=0x607000009b70,
grpc.keepalive_permit_without_calls=1, grpc.keepalive_time_ms=86400000,
grpc.keepalive_timeout_ms=86400000,
grpc.primary_user_agent=grpc-c++/1.46.0,
grpc.resource_quota=0x60400000fa90,
grpc.server_uri=dns:///mtls.gateway.nightowl.go-e.co:443}: connect failed:
{"created":"@1655461319.976196203","description":"Handshake
failed","file":"/grpc/src/core/lib/security/transport/security_handshaker.cc","file_line":377,"tsi_code":10,"tsi_error":"TSI_PROTOCOL_FAILURE"}
This is really surprising, because I thought the prefix SSL in
SSLChannelCredentials is only for historical purposes and it does not
actually try to use SSLv3 any more.
To double check, I used the Python bindings to put together a simple
example:
def certs():
path = "certificate_file_path"
with open(path + "ca.crt") as fd:
ca = fd.read()
with open(path + "client.crt") as fd:
crt = fd.read()
with open(path + "client.key") as fd:
key = fd.read()
return {
"root_certificates": ca.encode("utf8"),
"private_key": key.encode("utf8"),
"certificate_chain": crt.encode("utf8"),
}
async def main() -> None:
credentials = grpc.ssl_channel_credentials(**certs())
async with grpc.aio.secure_channel(
"server_url:port", credentials
) as channel:
stub = xxxxx(channel)
await stream(stub)
And surely enough, this works like a charm with the following debug log:
D0617 12:25:37.611607359 5824 certificate_provider_registry.cc:33]
registering certificate provider factory for "file_watcher" D0617
12:25:37.611612059 5824 lb_policy_registry.cc:42] registering LB policy
factory for "cds_experimental" D0617 12:25:37.611812743 5824
lb_policy_registry.cc:42] registering LB policy factory for
"xds_cluster_impl_experimental" D0617 12:25:37.611817173 5824
lb_policy_registry.cc:42] registering LB policy factory for
"xds_cluster_resolver_experimental" D0617 12:25:37.611824862 5824
lb_policy_registry.cc:42] registering LB policy factory for
"xds_cluster_manager_experimental" E0617 12:25:37.611829462 5824
trace.cc:66] Unknown trace var: 'transport_security' I0617
12:25:37.664472925 5825 ssl_transport_security.cc:226] HANDSHAKE START -
TLS client start_connect - !!!!!! I0617 12:25:37.664616500 5825
ssl_transport_security.cc:226] LOOP - TLS client enter_early_data - !!!!!!
I0617 12:25:37.664622010 5825 ssl_transport_security.cc:226] LOOP - TLS
client read_server_hello - !!!!!! I0617 12:25:37.694303510 5828
ssl_transport_security.cc:226] LOOP - TLS 1.3 client read_hello_retr -
!!!!!! I0617 12:25:37.694320800 5828 ssl_transport_security.cc:226] LOOP -
TLS 1.3 client read_server_hel - !!!!!! I0617 12:25:37.694401058 5828
ssl_transport_security.cc:226] LOOP - TLS 1.3 client read_encrypted_ -
!!!!!! I0617 12:25:37.694410227 5828 ssl_transport_security.cc:226] LOOP -
TLS 1.3 client read_certificat - !!!!!! I0617 12:25:37.694434267 5828
ssl_transport_security.cc:226] LOOP - TLS 1.3 client read_server_cer -
!!!!!! I0617 12:25:37.694463286 5828 ssl_transport_security.cc:226] LOOP -
TLS 1.3 client read_server_cer - !!!!!! I0617 12:25:37.694742638 5828
ssl_transport_security.cc:226] LOOP - TLS 1.3 client read_server_fin -
!!!!!! I0617 12:25:37.694764417 5828 ssl_transport_security.cc:226] LOOP -
TLS 1.3 client send_end_of_ear - !!!!!! I0617 12:25:37.694769907 5828
ssl_transport_security.cc:226] LOOP - TLS 1.3 client send_client_enc -
!!!!!! I0617 12:25:37.694773247 5828 ssl_transport_security.cc:226] LOOP -
TLS 1.3 client send_client_cer - !!!!!! I0617 12:25:37.694779987 5828
ssl_transport_security.cc:226] LOOP - TLS 1.3 client send_client_cer -
!!!!!! I0617 12:25:37.695587273 5828 ssl_transport_security.cc:226] LOOP -
TLS 1.3 client complete_second - !!!!!! I0617 12:25:37.695603763 5828
ssl_transport_security.cc:226] LOOP - TLS 1.3 client done - !!!!!! I0617
12:25:37.695607223 5828 ssl_transport_security.cc:226] LOOP - TLS client
finish_client_hands - !!!!!! I0617 12:25:37.695614203 5828
ssl_transport_security.cc:226] LOOP - TLS client done - !!!!!! I0617
12:25:37.695616983 5828 ssl_transport_security.cc:226] HANDSHAKE DONE - TLS
client done - !!!!!!
So, the python bindings try nothing but TLS 1.3, which is exactly what I
expected.
I figured, perhaps the SSL in SSLChannelCredentials in C++ is taken
literally by the gRPC team and I am supposed to use the experimental
TLSCredentials. So I tried something like this:
std::shared_ptr<grpc::ChannelCredentials> GetChannelCredentials() {
std::ifstream root_cert_path(GetRootCertPath());
std::string root_cert(std::istreambuf_iterator<char>{root_cert_path}, {});
std::ifstream client_key_path(GetClientKeyPath());
std::string client_key(std::istreambuf_iterator<char>{client_key_path},
{});
std::ifstream client_cert_path(GetClientCertPath());
std::string client_cert(std::istreambuf_iterator<char>{client_cert_path},
{});
std::vector<grpc::experimental::IdentityKeyCertPair> keypairs =
{{client_key, client_cert}};
auto certificate_provider =
std::make_shared<grpc::experimental::StaticDataCertificateProvider>(root_cert,
keypairs);
grpc::experimental::TlsChannelCredentialsOptions cred_opts;
cred_opts.set_certificate_provider(certificate_provider);
cred_opts.
cred_opts.set_verify_server_certs(true);
return grpc::experimental::TlsCredentials(cred_opts);
}
And at least this tries to do TLS 1.3, but fails with the following message:
I0617 19:26:21.349515081 81267 ssl_utils.cc:422] No root
certificates specified; use ones stored in system default locations instead
I0617 19:26:21.360184162 81267 ssl_utils.cc:422] No root
certificates specified; use ones stored in system default locations instead
I0617 19:26:21.360424123 81267 ssl_utils.cc:422] No root
certificates specified; use ones stored in system default locations instead
I0617 19:26:21.360607314 81267 ssl_utils.cc:422] No root
certificates specified; use ones stored in system default locations instead
I0617 19:26:21.360816715 81267 ssl_utils.cc:422] No root
certificates specified; use ones stored in system default locations instead
I0617 19:26:21.361017545 81267 ssl_utils.cc:422] No root
certificates specified; use ones stored in system default locations instead
I0617 19:26:21.361262535 81267 socket_utils_common_posix.cc:353]
TCP_USER_TIMEOUT is available. TCP_USER_TIMEOUT will be used thereafter
I0617 19:26:24.348350517 81265 ssl_transport_security.cc:226]
HANDSHAKE START - before SSL initialization - PINIT
I0617 19:26:24.348468056 81265 ssl_transport_security.cc:226]
LOOP - before SSL initialization - PINIT
I0617 19:26:24.348747673 81265 ssl_transport_security.cc:226]
LOOP - SSLv3/TLS write client hello - TWCH
I0617 19:26:29.347766352 81267 ssl_transport_security.cc:226]
LOOP - SSLv3/TLS write client hello - TWCH
I0617 19:26:29.348116633 81267 ssl_transport_security.cc:226]
LOOP - SSLv3/TLS read server hello - TRSH
I0617 19:26:29.348155419 81267 ssl_transport_security.cc:226]
LOOP - TLSv1.3 read encrypted extensi - TREE
I0617 19:26:29.348220587 81267 ssl_transport_security.cc:226]
LOOP - SSLv3/TLS read server certific - TRCR
E0617 19:26:29.348505470 81267 ssl_transport_security.cc:1495] Handshake
failed with fatal error SSL_ERROR_SSL: error:1416F086:SSL
routines:tls_process_server_certificate:certificate verify failed.
D0617 19:26:29.348590787 81267 security_handshaker.cc:181] Security
handshake failed:
{"created":"@1655486789.348516884","description":"Handshake
failed","file":"/home/ssengupta/git/grpc/src/core/lib/security/transport/security_handshaker.cc","file_line":377,"tsi_code":10,"tsi_error":"TSI_PROTOCOL_FAILURE"}
I0617 19:26:29.348826737 81267 subchannel.cc:948] subchannel
0x619000065480 {address=ipv6:[2a05:d014:c4b:3500:bb49:5b5c:47c:5191]:443,
args=grpc.client_channel_factory=0x602000001cb0,
grpc.default_authority=mtls.gateway.nightowl.go-e.co:443,
grpc.http2.max_pings_without_data=0, grpc.http2_scheme=https,
grpc.internal.channel_credentials=0x60300001e010,
grpc.internal.security_connector=0x613000040700,
grpc.internal.subchannel_pool=0x6070000099b0,
grpc.keepalive_permit_without_calls=1, grpc.keepalive_time_ms=86400000,
grpc.keepalive_timeout_ms=86400000,
grpc.primary_user_agent=grpc-c++/1.46.0-dev,
grpc.resource_quota=0x60400000fa90,
grpc.server_uri=dns:///mtls.gateway.nightowl.go-e.co:443}: connect failed:
{"created":"@1655486789.348516884","description":"Handshake
failed","file":"/home/ssengupta/git/grpc/src/core/lib/security/transport/security_handshaker.cc","file_line":377,"tsi_code":10,"tsi_error":"TSI_PROTOCOL_FAILURE"}
I am confused now what I should do. What is the preferred method to use TLS
with a gRPC client for C++?
--
You received this message because you are subscribed to the Google Groups
"grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/grpc-io/9e694bf9-264b-4104-a06c-71ab73ef9fc6n%40googlegroups.com.