我在使用gRPC连接我的服务器时遇到问题。服务器使用证书文件(rpc.cert和rpc.key)进行身份验证,但我不知道如何包含这些文件。目前这是我用来连接的代码
ManagedChannel channel = OkHttpChannelBuilder.forAddress("127.0.0.1", 9111)
.usePlaintext(true)
.build();
使用上面的代码会抛出此错误
io.grpc.StatusRuntimeException: UNAVAILABLE: End of stream or IOExceptio
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.jav
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:202)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:131)
at com.dcrwallet.grpc.WalletLoaderServiceGrpc$WalletLoaderServiceBlo
at com.decrediton.MainActivity$2.onClick(MainActivity.java:86)
at android.view.View.performClick(View.java:5675)
at android.view.View$PerformClick.run(View.java:22641)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6285)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(Zygote
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: javax.net.ssl.SSLHandshakeException: Handshake failed
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:444)
at io.grpc.okhttp.OkHttpProtocolNegotiator.negotiate(OkHttpProtocolNegotiator.java:93)
at io.grpc.okhttp.OkHttpProtocolNegotiator$AndroidNegotiator.negotiate(OkHttpProtocolNegotiator.java:159)
at io.grpc.okhttp.OkHttpTlsUpgrader.upgrade(OkHttpTlsUpgrader.java:63)
at io.grpc.okhttp.OkHttpClientTransport$1.run(OkHttpClientTransport.java:429)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb036ce80: Failure in SSL library, usually a protocol error error:1000006b:SSL routines:OPENSSL_internal:BAD_ECC_CERT (external/boringssl/src/ssl/s3_clnt.c:957 0xa74a5d15:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:362)
我找不到任何关于在android中使用grpc okhttp的文档。谷歌的gRPC文档不包含这些,所以我几乎不知道如何处理错误。谢谢
答案 0 :(得分:0)
由于服务器需要TLS,因此您无法使用明文。通常,你不需要做任何事情; grpc-java Channels默认使用TLS:
ManagedChannel channel = OkHttpChannelBuilder.forAddress("127.0.0.1", 9111)
.sslSocketFactory(yourSslSocketFactory)
.build();
客户端不需要任何文件来标识服务器,因为服务器的证书应由受信任的证书颁发机构(CA)签名。
如果情况确实如此,那你的问题就不清楚了。如果您使用自签名证书或自定义CA对证书进行签名,则默认情况下grpc-okhttp使用的SSLSocketFactory.getDefault()
可能不会接受服务器的证书。
在极少数情况下,您需要为gRPC指定SSLSocketFactory
才能使用:
ManagedChannel channel = OkHttpChannelBuilder.forAddress("127.0.0.1", 9111)
.sslSocketFactory(yourSslSocketFactory)
.build();
您需要在客户端二进制文件中包含证书,yourSslSocketFactory
需要为其TrustManager
引用该证书。作为一个例子(取自Taylor series expansion):
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(theRawCert);
ks.setCertificateEntry("customca", cert);
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(ks);
SSLContext context = SSLContext.getInstance("TLS", provider);
context.init(null, trustManagerFactory.getTrustManagers(), null);
return context.getSocketFactory();