[Help] use self-signed cert on Android

64 views
Skip to first unread message

yz

unread,
Mar 19, 2018, 6:53:16 AM3/19/18
to grpc.io
I am trying to make gRPC over TLS working on Android using a self-signed cert. The code is as following:

InputStream testCA = new ByteArrayInputStream(CA.getBytes("UTF8"));
mChannel = ZnzGrpcChannelBuilder.build(mHost, mPort, null, true, testCA, "alpn");
GRPCDummyServerGrpc.GRPCDummyServerBlockingStub stub = GRPCDummyServerGrpc.newBlockingStub(mChannel);
SumRequest sumRequest = SumRequest.newBuilder().setStart(start).setCount(20).build();
SumResponse sumResponse = stub.sum(sumRequest);


ZnzGrpcChannelBuilder is a customized channel builder to enable self-signed cert. As can be seen from Wireshark, the TLS negotiation has completed and the server starts
to send SETTINGS to the Android client. But the client did not send any SETTINGS frames.
What I am missing here? Thank you very much.

public class ZnzGrpcChannelBuilder {
public static ManagedChannel build(String host, int port, @Nullable String serverHostOverride,
boolean useTls, @Nullable InputStream testCa, @Nullable String androidSocketFactoryTls) {
ManagedChannelBuilder<?> channelBuilder = ManagedChannelBuilder.forAddress(host, port);
if (serverHostOverride != null) {
// Force the hostname to match the cert the server uses.
channelBuilder.overrideAuthority(serverHostOverride);
}
if (useTls) {
try {
SSLSocketFactory factory;
if (androidSocketFactoryTls != null) {
factory = getSslCertificateSocketFactory(testCa, androidSocketFactoryTls);
} else {
factory = getSslSocketFactory(testCa);
}
((OkHttpChannelBuilder) channelBuilder).negotiationType(NegotiationType.TLS);
((OkHttpChannelBuilder) channelBuilder).sslSocketFactory(factory);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
channelBuilder.usePlaintext(true);
}
return channelBuilder.build();
}
private static SSLSocketFactory getSslSocketFactory(@Nullable InputStream testCa)
throws Exception {
if (testCa == null) {
return (SSLSocketFactory) SSLSocketFactory.getDefault();
}
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, getTrustManagers(testCa), null);
return context.getSocketFactory();
}
@TargetApi(14)
private static SSLCertificateSocketFactory getSslCertificateSocketFactory(
@Nullable InputStream testCa, String androidSocketFatoryTls) throws Exception {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH /* API level 14 */) {
throw new RuntimeException(
"android_socket_factory_tls doesn't work with API level less than 14.");
}
SSLCertificateSocketFactory factory = (SSLCertificateSocketFactory)
SSLCertificateSocketFactory.getDefault(5000 /* Timeout in ms*/);
// Use HTTP/2.0
byte[] h2 = "h2".getBytes();
byte[][] protocols = new byte[][]{h2};
if (androidSocketFatoryTls.equals("alpn")) {
Method setAlpnProtocols =
factory.getClass().getDeclaredMethod("setAlpnProtocols", byte[][].class);
setAlpnProtocols.invoke(factory, new Object[]{protocols});
} else if (androidSocketFatoryTls.equals("npn")) {
Method setNpnProtocols =
factory.getClass().getDeclaredMethod("setNpnProtocols", byte[][].class);
setNpnProtocols.invoke(factory, new Object[]{protocols});
} else {
throw new RuntimeException("Unknown protocol: " + androidSocketFatoryTls);
}
if (testCa != null) {
factory.setTrustManagers(getTrustManagers(testCa));
}
return factory;
}
private static TrustManager[] getTrustManagers(InputStream testCa) throws Exception {
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(testCa);
X500Principal principal = cert.getSubjectX500Principal();
ks.setCertificateEntry(principal.getName("RFC2253"), cert);
// Set up trust manager factory to use our key store.
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(ks);
return trustManagerFactory.getTrustManagers();
}
}

Carl Mastrangelo

unread,
Mar 28, 2018, 1:41:06 PM3/28/18
to grpc.io
Are you sure negotiation completed from the Android client POV?  Since the android code uses OkHTTP framing and a thread per connection, you should be able to see where it is hung up by getting a stack trace.
Reply all
Reply to author
Forward
0 new messages