0
votes

I'm trying to write a GRPC server that talks to both a C++ and golang client. Since this is all internal to our system, there will be a self-signed certificate that signs the server certificate, and the server will sign the client certificates.

I'm able to connect to the server from the golang client. However, the C++ client doesn't connect, and I see a bunch of errors from the ssl layer. What am I doing incorrectly in my configuration of the C++ grpc client?

(My certificates all use a 2048bit RSA key for now)

Here are the client codes that I thought were equivalent (error handling elided):

Golang:

import (
    "crypto/tls"
    "io/ioutil"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
)

func getConnection(hostPort string) (*grpc.ClientConn, error) {
    var config tls.Config
    cert, _ := tls.LoadX509KeyPair("client.crt", "client.key")
    config.Certificates = append(config.Certificates, cert)
    b, _ := ioutil.ReadFile("root.crt")
    config.RootCAs.AppendCertsFromPEM(b)

    options := grpc.WithTransportCredentials(credentials.NewTLS(config))
    return grpc.Dial(hostPort, options)
}

C++:

#include <fstream>
#include <string>
#include <grpc++/grpc++.h>

std::shared_ptr<grpc::Channel> get_connection(const std::string& host_port) {
    auto contents = [](const std::string& filename) -> std::string {
        std::ifstream fh(filename);
        std::stringstream buffer;
        buffer << fh.rdbuf();
        fh.close();
        return buffer.str();
    };

    auto ssl_options = grpc::SslCredentialsOptions();
    ssl_options.pem_cert_chain = contents("client.crt");
    ssl_options.pem_private_key = contents("client.key");
    ssl_options.pem_root_certs = contents("root.crt");
    auto creds = grpc::SslCredentials(ssl_options);
    auto channel = grpc::CreateChannel(hostport, creds);
}

My error messages:

C++ Client error messages

D0322 14:42:12.882767371   11701 env_linux.c:77]             Warning: insecure environment read function 'getenv' used
getting job record
E0322 14:42:12.930157873   11701 ssl_transport_security.c:945] Handshake failed with fatal error SSL_ERROR_SSL: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed.
E0322 14:42:12.930231627   11701 handshake.c:128]            Security handshake failed: {"created":"@1490218932.930210185","description":"Handshake failed","file":"src/core/lib/security/transport/handshake.c","file_line":264,"tsi_code":10,"tsi_error":"TSI_PROTOCOL_FAILURE"}
E0322 14:42:12.964082644   11701 ssl_transport_security.c:945] Handshake failed with fatal error SSL_ERROR_SSL: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed.
E0322 14:42:12.964134746   11701 handshake.c:128]            Security handshake failed: {"created":"@1490218932.964114213","description":"Handshake failed","file":"src/core/lib/security/transport/handshake.c","file_line":264,"tsi_code":10,"tsi_error":"TSI_PROTOCOL_FAILURE"}
std::string JobServerClient::getJobRecord(const string&) const: GRPC connection error 14 []

Golang Client error messages

2017/03/22 17:42:12 grpc: Server.Serve failed to create ServerTransport:  connection error: desc = "transport: EOF"
2017/03/22 17:42:12 grpc: Server.Serve failed to create ServerTransport:  connection error: desc = "transport: EOF"

What additional debugging can I do to determine where the C++ client is going awry?

1

1 Answers

1
votes

The error message is caused by the certificate being presented is not trusted on the system that the C++ code is running on.

If you're using a self-signed certificate you either need to add your root signing key to the ca-certificates on that system or configure your C++ code to read and recognise that root signing key.

If you provide more information on the keys in your code (I assume the root.crt is your root signing key), someone may be able to give you more specific help.