android改造主机名未验证

Rai*_*ker 6 android ssl-certificate retrofit2

我获得了为 IP 地址(不是通用名称)颁发的证书,我正在尝试使用该证书连接到服务器。

OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
OkHttpClient okHttpClient = builder.build();
Gson gson = new GsonBuilder()
                .setLenient()
                .create();
retrofit = new Retrofit.Builder()
                .baseUrl(url)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
ServerRouts service = retrofit.create(ServerRouts.class);
Resp_json> call = service.login(param, user, pw);
Run Code Online (Sandbox Code Playgroud)

我得到了一个错误:

Hostname 11.8.222.333 not verified:
Run Code Online (Sandbox Code Playgroud)

但是当我使用

builder.hostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
Run Code Online (Sandbox Code Playgroud)

然后一切正常。

如何在不关闭主机名验证程序的情况下解决该错误?

PS 我为 IP 颁发的证书 (11.8.222.333)

Rai*_*ker 2

我重新定义了这样的验证方法(只是从 DefaultHostnameVerifier.java 复制源),现在一切正常。我不知道为什么它不起作用,但现在好了。

builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {

                Certificate[] certs;
                try {
                    certs = session.getPeerCertificates();
                } catch (SSLException e) {
                    return false;
                }
                X509Certificate x509 = (X509Certificate) certs[0];
                // We can be case-insensitive when comparing the host we used to
                // establish the socket to the hostname in the certificate.
                String hostName = hostname.trim().toLowerCase(Locale.ENGLISH);
                // Verify the first CN provided. Other CNs are ignored. Firefox, wget,
                // curl, and Sun Java work this way.
                String firstCn = getFirstCn(x509);
                if (matches(hostName, firstCn)) {
                    return true;
                }
                for (String cn : getDNSSubjectAlts(x509)) {
                    if (matches(hostName, cn)) {
                        return true;
                    }
                }
                return false;

            }
        });


private String getFirstCn(X509Certificate cert) {
        String subjectPrincipal = cert.getSubjectX500Principal().toString();
        for (String token : subjectPrincipal.split(",")) {
            int x = token.indexOf("CN=");
            if (x >= 0) {
                return token.substring(x + 3);
            }
        }
        return null;
    }
Run Code Online (Sandbox Code Playgroud)