如何解决Mutual TLS身份验证中的协议错误

时间:2019-11-17 14:40:12

标签: android ssl okhttp grpc-java

我在android客户端和python服务器之间使用双向TLS身份验证,握手正常,但是我在python服务器上收到错误UNSUPPORTED_PROTOCOL。 我的服务器不是基于Web的,当我尝试通过python客户端连接到它时,它运行良好。 这是我的android客户端:

try {
            ProviderInstaller.installIfNeeded(getApplicationContext());
        } catch (GooglePlayServicesRepairableException e) {
            e.printStackTrace();
        } catch (GooglePlayServicesNotAvailableException e) {
            e.printStackTrace();
        }
 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.connectionSpec(ConnectionSpec.COMPATIBLE_TLS);
            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();
    }

我的证书采用.crt格式,我的密钥采用PKCS#8。 我认为问题是我没有使用TLS v1.2,但是每当我将SSLContext实例更改为“ TLSv1.2”时,它都不会执行任何操作,并且当我更改channelBuilder.connectionSpec(ConnectionSpec.COMPATIBLE_TLS);时 其他问题,握手没有通过,我的服务器抛出了LAST OCTET INVALIDFIRST OCTET INVALID

0 个答案:

没有答案