我想知道在GrpcSslContext中需要设置什么才能使Grpc客户端使用服务器进行SSL身份验证?
目前,以下代码用于从服务器到客户端的常规单向SSL身份验证。
在服务器上,
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();在客户那里,
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);据gRPC at https://github.com/grpc/grpc-java/blob/master/SECURITY.md说,
如果需要相互身份验证,也可以通过创建适当的SslContext来支持这一点。
我想知道我是否正确地初始化了GrpcSslContexts?
如有任何意见或意见,敬请见谅。
更新
在进一步排除故障时,我注意到CertificateRequest消息(如握手中所述)从未发送到客户端以启动客户端身份验证。
我的服务器日志的摘录如下:.
*** 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;
....我开始怀疑这可能是gRPC中固有的错误。
发布于 2015-08-31 17:50:10
编辑:支持被添加。创建自己的SslContext并将其传递给NettyChannelBuilder.sslContext(),确保通过SslContextBuilder.clientAuth()请求客户端证书。然后,对于每个RPC,检查ClientCall.getAttributes()并通过Grpc.TRANSPORT_ATTR_SSL_SESSION获取SSLSession。
请求服务器上的客户端证书似乎是gRPC 没有办法,这对于互操作是必要的。考虑到SSL/TLS的工作方式,这并不完全是一个错误,但更多的是一个特性请求。
Java实现还没有将客户端证书作为一个完整的特性来支持。这将包括能够检索服务器上的客户端证书。请求客户端身份验证的能力必须是该功能的一部分。
Client是grpc完全打算支持的东西,但还没有被开发出来。
发布于 2017-05-18 09:11:07
要更新现有的答案,现在可以访问服务器端的SSLSession,它为客户端证书提供句柄。github项目( Security.md,https://github.com/grpc/grpc-java/blob/master/SECURITY.md)的Security.md文件给出了一个显式示例,在互TLS一节中,说明了如何这样做。
在编写本报告时,该文件引用了一个不存在的常量(ServerCall.SSL_SESSION_KEY),但我为此创建了一个问题,其中包含一个工作机制(https://github.com/grpc/grpc-java/issues/3013.)。现在,这个问题解决后,我的解决办法不再必要了,您可以按照Security.md的描述:
要获得客户端证书,您必须做什么:
实现ServerInterceptor
public class MyInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
String subjectDn = null;
try {
SSLSession sslSession = (SSLSession) call.attributes().get(Grpc.TRANSPORT_ATTR_SSL_SESSION););
// sslSession.getPeerCertificates(); contains the certificates, you are looking for
}
} catch (SSLPeerUnverifiedException e) {
// do what you need to do
}
return next.startCall(call, headers);
}
}并将其插入您的Server
server = NettyServerBuilder.forPort(port)
.sslContext(context)
.addService(ServerInterceptors.intercept(new MyServiceImpl(), new MyInterceptor()))
.build();Security.md还告诉您如何将SSLSession注入到上下文中,以便在MyServiceImpl方法中对其有一些处理,从而实现要调用的远程过程。
请注意,这是实验性API,所以要小心使用它。
https://stackoverflow.com/questions/32222389
复制相似问题