I have a gRPC server which is using mutual TLS for encryption and authentication. So, every client that connects to this server provides an SSL certificate and I want to reject connections from clients who have a public key size less than 2048 bits. There seems to be no straightforward way to do this yet.
I was able to do it using a ServerInterceptor
this way
public class SSLInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
try {
SSLSession sslSession = call.getAttributes().get(Grpc.TRANSPORT_ATTR_SSL_SESSION);
RSAPublicKeyImpl pk = (RSAPublicKeyImpl) sslSession.getPeerCertificates()[0].getPublicKey();
if (pk.getModulus().bitLength() < 2048) {
// reject call
}
// proceed with the call
} catch (SSLPeerUnverifiedException e) {
// do something
}
...
}
}
This is a bad way to do it because
- The validation is being done after the connection is already established.
- The validation is only triggered when a request/call is made.
- Every single call involves an extra overhead of validation.
- In case of a validation failure, only the call is rejected but not the connection to the client.
In an ideal scenario
- The validation is done during the connection establishment phase. (or some point during the creation of the channel between client and server)
- The validation failure would prevent the connection from being created and not set it up and disconnect later.
- A client is only validated once per session and all the calls made during that session do not incur any overhead.
How can I do this better?