从Android客户端到python服务器的TLS

时间:2019-11-17 08:34:40

标签: java android security ssl grpc

我在Java android上使用grpc,使用双向SSL(tls),我的服务器为我生成了2个证书(server.ca和client.ca)和一个私钥(key.key),我更改了密钥我知道了(对PKCS8进行基本密钥加密) 来自

-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----

收件人:

   -----END PRIVATE KEY-----

并使用此代码通过grpc用okhttp生成了我的sslcontext。

    private static byte[] getBytesFromInputStream(InputStream is) throws IOException {
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            byte[] buffer = new byte[0xFFFF];
            for (int len = is.read(buffer); len != -1; len = is.read(buffer)) {
                os.write(buffer, 0, len);
            }
            return os.toByteArray();
        }

        // build a key store from a set of raw certificates
        private static KeyStore createKeyStore(Resources resources, int certsId, boolean ca) {
            KeyStore ks = null;
            try {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                if (ca) {
                    ks = KeyStore.getInstance(KeyStore.getDefaultType());
                    ks.load(null, null);
                    InputStream certIS = resources.openRawResource(R.raw.server);
                    X509Certificate cert = (X509Certificate) cf.generateCertificate(certIS);
                    ks.setCertificateEntry("ca", cert);
                } else {
                    ks = KeyStore.getInstance("AndroidKeyStore");
                    ks.load(null, null);
                    InputStream certIS = resources.openRawResource(R.raw.client);
                    Certificate cert = cf.generateCertificate(certIS);
                    InputStream privateKeyIS = resources.openRawResource(R.raw.key);
                    byte[] privateKeyBytes = getBytesFromInputStream(privateKeyIS);
                    KeyFactory kf = KeyFactory.getInstance("RSA");
                    PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(privateKeyBytes)));
                    Certificate[] certChain = new Certificate[1];
                    certChain[0] = cert;
                    ks.setKeyEntry("client", privateKey, null, certChain);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return ks;
        }

        public static ManagedChannel build(String host, int port, Resources resources,
                                           @Nullable String serverHostOverride) {
            KeyStore ca = createKeyStore(resources, R.array.certs, true);
            KeyStore client = createKeyStore(resources, R.array.certs, false);
            OkHttpChannelBuilder channelBuilder =
                    OkHttpChannelBuilder.forAddress(host, port);
            if (serverHostOverride != null) {
                // Force the hostname to match the cert the server uses.
                channelBuilder.overrideAuthority(serverHostOverride);
            }
            try {
                channelBuilder.negotiationType(io.grpc.okhttp.NegotiationType.TLS);
                channelBuilder.useTransportSecurity();
                channelBuilder.sslSocketFactory(getSslSocketFactory(ca, client));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return channelBuilder.build();
        }

        private static SSLSocketFactory getSslSocketFactory(KeyStore ca, KeyStore client)
                throws Exception {
            KeyManagerFactory kmf =
                    KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            String password = "";
            kmf.init(client, password.toCharArray());

            // initialize trust manager factor from certs keystore
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(ca);

            // initialize SSL context from trust manager factory
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

            // return socket factory from the SSL context
            return context.getSocketFactory();
        }

    public void connectGrpc() throws Exception {
            ManagedChannel c = build("MyPc", 5051, this.getResources(), null);
            TabletServiceGrpc.TabletServiceBlockingStub bs = TabletServiceGrpc.newBlockingStub(c);
            GetName g= GetName.newBuilder().setField(1).build();
            GetNameResponse res=bs.getNameByField(g);
            Log.e(TAG,res.getCategoryName());

    }

我收到以下错误:


    Read error: ssl=0x7890e89c88: Failure in SSL library, usually a protocol error
        error:100000d7:SSL routines:OPENSSL_internal:SSL_HANDSHAKE_FAILURE 
    (third_party/openssl/boringssl/src/ssl/ssl_lib.cc:1017 0x787007e1bb:0x00000000)

io.grpc.StatusRuntimeException: UNAVAILABLE: End of stream or IOException

我的密钥从PKCS#1转换为PKCS#8是否有问题?还是还有其他东西? 我尝试根据android docs更改代码,但它与之匹配,并且可以正常工作。

0 个答案:

没有答案