It is only my hunch that this is happening due to the difference between OpenSSL and BoringSSL. I build gRPC with OpenSSL, since other dependencies of my application require it. Prefixing BoringSSL symbols, although seems possible, is apparently not recommended. The Python package grpcio is apparently always built with BoringSSL. Unfortunately I am not involved enough to figure out if setting certain environment variables for my C++ application would make them behave in a similar way. I would really appreciate some input. On Friday, 17 June 2022 at 20:22:33 UTC+2 Subhamoy Sengupta wrote:
> 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 > thereafterI0617 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 - TWCHI0617 10:21:59.975724008 409 > ssl_transport_security.cc:226] LOOP - SSLv3/TLS write > client hello - TWCHI0617 10:21:59.975958355 409 > ssl_transport_security.cc:226] LOOP - SSLv3/TLS read > server hello - TRSHI0617 10:21:59.975972388 409 > ssl_transport_security.cc:226] LOOP - TLSv1.3 read > encrypted extensi - TREEI0617 10:21:59.976032247 409 > ssl_transport_security.cc:226] LOOP - SSLv3/TLS read server > certific - TRCRE0617 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=backend_url: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:///backend_url: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 > insteadI0617 19:26:21.360184162 81267 ssl_utils.cc:422] No root > certificates specified; use ones stored in system default locations > insteadI0617 19:26:21.360424123 81267 ssl_utils.cc:422] No root > certificates specified; use ones stored in system default locations > insteadI0617 19:26:21.360607314 81267 ssl_utils.cc:422] No root > certificates specified; use ones stored in system default locations > insteadI0617 19:26:21.360816715 81267 ssl_utils.cc:422] No root > certificates specified; use ones stored in system default locations > insteadI0617 19:26:21.361017545 81267 ssl_utils.cc:422] No root > certificates specified; use ones stored in system default locations > insteadI0617 19:26:21.361262535 81267 socket_utils_common_posix.cc:353] > TCP_USER_TIMEOUT is available. TCP_USER_TIMEOUT will be used > thereafterI0617 19:26:24.348350517 81265 ssl_transport_security.cc:226] > HANDSHAKE START - before SSL initialization - PINITI0617 > 19:26:24.348468056 81265 ssl_transport_security.cc:226] > LOOP - before SSL initialization - PINITI0617 19:26:24.348747673 > 81265 ssl_transport_security.cc:226] LOOP - SSLv3/TLS > write client hello - TWCHI0617 19:26:29.347766352 81267 > ssl_transport_security.cc:226] LOOP - SSLv3/TLS write > client hello - TWCHI0617 19:26:29.348116633 81267 > ssl_transport_security.cc:226] LOOP - SSLv3/TLS read > server hello - TRSHI0617 19:26:29.348155419 81267 > ssl_transport_security.cc:226] LOOP - TLSv1.3 read > encrypted extensi - TREEI0617 19:26:29.348220587 81267 > ssl_transport_security.cc:226] LOOP - SSLv3/TLS read server > certific - TRCRE0617 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=backend_url: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:///backend_url: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 grpc-io+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/3fab404d-7098-4624-892e-530326d4b494n%40googlegroups.com.