Search code examples
javasslgrpcmutual-authentication

Grpc Java SSL mutual authentication


I would like to know what needs to be set in the GrpcSslContext in order for Grpc Client to do SSL authentication with the server?

Currently, the following codes are working for the usual 1-way SSL authentication from the server to the client.

At the server,

SslContext sslContext = GrpcSslContexts.forServer(new File(pathToOwnCertPemFile), new File(pathToOwnPrivateKeyPemFile)).trustManager(new File(pathToClientCertPemFile)).build();

ServerImpl server = NettyServerBuilder
        .forPort(port)
        .sslContext(sslContext)
        .addService(MyGrpc.bindService(new MyGrpcService()))
        .build().start();

At the client,

SslContext sslContext = GrpcSslContexts.forClient().trustManager(new File(pathToServerCertPemFile)).keyManager(new File(pathToOwnCertPemFile), new File(pathToOwnPrivateKeyPemFile)).build();

ChannelImpl channel = NettyChannelBuilder.forAddress(host, port)
                .negotiationType(NegotiationType.TLS)
                .sslContext(sslContext).build();

blockingStub = MyGrpc.newBlockingStub(channel);
asyncStub = MyGrpc.newStub(channel);

According to gRPC at https://github.com/grpc/grpc-java/blob/master/SECURITY.md,

If mutual authentication is desired this can also be supported by creating the appropriate SslContext.

I wonder if I had initialised the GrpcSslContexts correctly?

Any advice/comments are appreciated.

[Update]

Upon further troubleshooting, I noticed that the CertificateRequest message (as stated in https://en.wikipedia.org/wiki/Transport_Layer_Security#Client-authenticated_TLS_handshake), was never sent to the client to initiate the Client Authentication.

An excerpt of my server log is as follows: ......

*** ECDH ServerKeyExchange
Signature Algorithm SHA512withRSA
Server key: Sun EC public key, 256 bits
public x coord: 81392923578261760187813715443713168545877454618233337093852615933913992434989
public y coord: 26389586381130695169212775668808794166799180199461581135201001980310825571555
parameters: secp256r1 NIST P-256, X9.62 prime256v1
*** ServerHelloDone
[write] MD5 and SHA1 hashes: len = 1617
0000: 02 00 00 56 03 03 55 DF 34 10 9C 73 B5 00 C2 70 ...V..U.4..s...p
0010: FD B8 CC 36 5B 83 87 70 5B 74 A3 D2 AD B7 75 3B ...6[..p[t....u;
....

I am beginning to suspect it could be an inherent bug in gRPC.


Solution

  • Edit: Support was added. Make your own SslContext and pass it to NettyChannelBuilder.sslContext(), making sure to request the client certificate via SslContextBuilder.clientAuth(). Then for each RPC check the ClientCall.getAttributes() and get the SSLSession via Grpc.TRANSPORT_ATTR_SSL_SESSION.


    It does seem gRPC-Java does not have a way to request the client certificates on the server, which is necessary for mutual auth. It's not quite a bug given how SSL/TLS works, but more of a feature request.

    The Java implementation has not yet worked to support client certificates as a full feature. That would include being able to retrieve the client certificate on the server. The ability to request client authentication would have to be part of that feature.

    Client auth is something that grpc-Java has every intention of supporting, but hasn't been worked on yet.