基于okHttpClient实现证书绑定

2018-09-12  本文已影响0人  机智的黑猫

最近跟华为做合作项目,主要是我这边提供sdk集成到华为的app里,对方要求sdk与我方服务器的数据通信必须使用证书绑定,这里简单记录一下流程。

 //证书的public key 真实key这里就不放出来了, 可以通过 keytool -printcert -rfc -file xxx.crt得到
  private static final String cert = "-----BEGIN CERTIFICATE-----\n" +
                                                         "-----END CERTIFICATE-----";

  SSLSocketFactory sslSocketFactory = null;

        try {
            InputStream certStream = new Buffer().writeUtf8(certString).inputStream();
             CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
        if (certificates.isEmpty()) {
            throw new IllegalArgumentException("expected non-empty set of trusted certificates");
        }
        char[] password = "".toCharArray(); // Any password will work.
        KeyStore keyStore;
      try {
            keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            InputStream in = null; // By convention, 'null' creates an empty key store.
            keyStore.load(in, password);
        } catch (IOException e) {
            throw new AssertionError(e);
        }
        int index = 0;
        for (Certificate certificate : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificate);
        }
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
                KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, password);
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }

        SSLContext ssContext = SSLContext.getInstance("TLS");
        ssContext.init(keyManagerFactory.getKeyManagers(), trustManagers, null);
         SslSocketFactory   sslSocketFactory = sslContext.getSocketFactory();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            e.printStackTrace();
        }
OkHttpClient client = new OkHttpClient().newBuilder().sslSocketFactory(sslSocketFactory).hostnameVerifier(STRICT_HOSTNAME_VERIFIER) .build();

主要流程是根据证书创建trustmanager,并以此创建SslSocketFactory对象设置到okhttpclient上,同时要记得配置hostnameVerifier,两者前者负责检验证书,后者负责检验域名。目前测试下来会对所有使用该client的https网络请求做证书验证,如何在同一个client下只筛选特定域名请求暂时不知道如何实现,不过也已经满足功能需求。中间尝试跟了一下证书验证的源码,发现实际实现并不在andorid的jar包里,后续有机会再跟。

上一篇下一篇

猜你喜欢

热点阅读