OkHttp javax.net.ssl.SSLPeerUnverifiedException: Hostname domain.com not verified

后端 未结 5 1281
小鲜肉
小鲜肉 2020-12-04 18:45

I\'ve been trying for days to get this working. I\'m trying to connect to my server over https with a self signed certificate. I don\'t think there is any p

相关标签:
5条回答
  • 2020-12-04 19:02

    This issue is solved by setting setHostNameVerifier to okHttpBuilder. Make sure verify method should return true.

    Sample:

    okHttpClient.setHostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    });
    
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
    OkHttpClient client = builder.build();
    
    0 讨论(0)
  • 2020-12-04 19:03

    Please check if CN name on the client cert is added to the Subject alternative name. I had the same issue

    0 讨论(0)
  • 2020-12-04 19:06

    During cert generation the subjectAltName must be set if the uri is an ip to not fall through validation.

    "In some cases, the URI is specified as an IP address rather than a hostname. In this case, the iPAddress subjectAltName must be present in the certificate and must exactly match the IP in the URI." RFC (mentioned by Bas in comment)

    Instead of fiddeling client side with HostnameVerifier or else, reiusse the self-signed cert (which we have control over) via:

    openssl req \
    -newkey rsa:2048 \
    -nodes \
    -x509 \
    -days 36500 -nodes \
    -addext "subjectAltName = IP.1:1.2.3.4" \
    -keyout /etc/ssl/private/nginx-selfsigned2.key \
    -out /etc/ssl/certs/nginx-selfsigned2.crt
    

    Addon, if on android one also needs to trust the cert:

    the crt is pem format and can be imported into android via
    <?xml version="1.0" encoding="utf-8"?>
        <base-config cleartextTrafficPermitted="false">
            <trust-anchors>
                <certificates src="@raw/nginx_selfsigned2" />
                <certificates src="system" />
            </trust-anchors>
        </base-config>
    </network-security-config>
    

    Thus we verify the cert is from a trusted source And previously by hostname verification (via SAN) ensured the server we talk to presents the right cert for his ip.

    more here: https://developer.android.com/training/articles/security-config https://developer.android.com/training/articles/security-ssl.html#SelfSigned

    0 讨论(0)
  • 2020-12-04 19:08

    I finally got this working with a mix of multiple answers.

    First, the certificates was made wrongly, not sure how. But by creating them using the script in this answer made them work. What was needed was a server certificate and a key. Then the client needed another certificate.

    To use the certificate in android I converted the .pem file to a .crt file like this:

    openssl x509 -outform der -in client.pem  -out client.crt
    

    In android I added the certificate to my OkHttp client like the following:

    public ApiService() {
        mClient = new OkHttpClient();
        mClient.setConnectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
        mClient.setReadTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS);
        mClient.setCache(getCache());
        mClient.setSslSocketFactory(getSSL());
    }
    
    protected SSLSocketFactory getSSL() {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream cert = getAppContext().getResources().openRawResource(R.raw.client);
            Certificate ca = cf.generateCertificate(cert);
            cert.close();
    
            // creating a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
    
            return new AdditionalKeyStore(keyStore);
        } catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    

    The last part with new AdditionalKeyStore() is taken from this very well written answer. Which adds a fallback keystore.

    I hope this might help anyone else! This is the simplest way to get HTTPS working with a self-signed certificate that I have found. Other ways include having a BouncyCastle keystore which seems excessive to me.

    0 讨论(0)
  • 2020-12-04 19:13

    I had the same problem, however I needed my application to work on several staging environments, all of which had self signed certs. To make matters worse, they could change those certs on the fly.

    To fix this, when connecting to staging only, I added a SSLSocketFactory which trusted all certs. This fixed the java error, however it left me with the okhttp exception noted in this ticket.

    To avoid this error, I needed to add one more customization to my okHttpClient. This fixed the error for me.

    okHttpClient.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
    
    0 讨论(0)
提交回复
热议问题