8

I've been investigating this issue and found something interesting. If I use a server keystore which stores server certificate with commomn name as real domain to establish a connection with server, it works fine, however if I use ip address instead for the common name it does not work, but just in android device self made app(not desktop browser or browser app in android device).noted i used openssl to create these two certificate/keystore. enter image description here

and it turns out this exception is host name not verified

enter image description here

but the strange thing is in browser for desktop or android device both are fine

enter image description here

After investigation I found actually we can build our own host name verifier which can add exception to host name, but how does android's default verifier work? it must be some code that skip ip address as common name and return false.

I checked the okhttp's source code found this line of code it's throwing the exception

enter image description here

but I can not find the code customized the host name verifier.

Anyone can offer me some hints about this?

Thanks~

update:: after I debug in android studio, in run time its actually OkHostnameVerifier

it checks whether host name is ip address, if it is will check all the subject alternative name in the certificate , if a match found return true vice versa.

private boolean verifyIpAddress(String ipAddress, X509Certificate certificate) {
    for (String altName : getSubjectAltNames(certificate, ALT_IPA_NAME)) {
      if (ipAddress.equalsIgnoreCase(altName)) {
        return true;
      }
    }
    return false;
  }
Qing
  • 1,401
  • 2
  • 21
  • 41
  • 1
    You should not use `CN` for hostnames. *If* you do, then the hostname must be in both the `CN` and the `SAN`. You should put a friendly name in the `CN` because that is displayed to the user. There's no way to avoid putting a hostname (or IP address) in the `SAN`. See [How to create a self-signed certificate with openssl?](http://stackoverflow.com/a/27931596) for details (including references to the various standards) – jww Apr 09 '15 at 18:11
  • Also, use of an IP address is being moved against. In the future, it might cause trouble. For example, you cannot use IP Addresses with [HTTP Strict Transport Security (HSTS)](https://tools.ietf.org/html/rfc6797), and you cannot use them for [Host Public Key Pinning with Overrides (HPKP)](https://tools.ietf.org/html/draft-ietf-websec-key-pinning-21). – jww Apr 09 '15 at 18:14
  • If a subjectAltName extension of type dNSName is present, that MUST be used as the identity. Otherwise, the (most specific) Common Name field in the Subject field of the certificate MUST be used. Although the use of the Common Name is existing practice, it is deprecated and Certification Authorities are encouraged to use the dNSName instead. [...] 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. – Qing Apr 13 '15 at 03:41

1 Answers1

6

If I use a server keystore which stores server certificate with commomn name is real domain for establishing a connection with server it works fine, however if I use ip address instead for the common name it does not work,

That's how it should work. IP addresses have to be given as a subject alternative name of type IP. Unfortunately different browsers handle this in a different way and often contrary to the standard. Some accept IP in common name, others don't. Some expect the address as DNS entry in the subject alternative section instead of an IP entry. To be on the safe side you should therefore use subject alternative names of both types IP and DNS.

we can build our own host name verifier which can add exception to host name

Don't do this. If you ignore the host name then the validation is reduced to just the check of the trust chain, which means any certificate signed by a trusted CA can be used for a transparent man-in-the-middle attack against any other host. Even if you disable the name check only for IP addresses it is still possible to use any valid certificate once the user accesses a site by IP.

Dave Moten
  • 11,957
  • 2
  • 40
  • 47
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • thanks for the explaination! btw, do you know where does the okhttp handle this host verifier? I can not find the code which handle this part. – Qing Apr 09 '15 at 15:06
  • 1
    @Qing: I know practically nothing about OkHttp, but a short search returns [OkHTTPClient.setHostnameVerifier](http://square.github.io/okhttp/javadoc/com/squareup/okhttp/OkHttpClient.html#setHostnameVerifier-javax.net.ssl.HostnameVerifier-) – Steffen Ullrich Apr 09 '15 at 15:50
  • I just debug the source with android studio, the correct verifier should be :com.android.okhttp.internal.tls.OkHostnameVerifier, as I can see if the hostname is ip address, it will do following check: – Qing Apr 09 '15 at 15:53
  • for (String altName : getSubjectAltNames(certificate, ALT_IPA_NAME)) { if (ipAddress.equalsIgnoreCase(altName)) { return true; } } return false; – Qing Apr 09 '15 at 16:01
  • I think just like you said check for Subject Alternative name of the ip , if not it return false! – Qing Apr 09 '15 at 16:02