I have an application where many of our endpoints do not support DNS lookups so for those
endpoints they cannot use a URL to hit our servers.
Our application gives out a list of IPs of our servers they need to hit and this works fine for http.
I am trying to enable use of https to hit our servers and I have created a SAN cert with some
urls as Subject Alternative Names plus the IPs of our servers as Subject Alternative names.
For example in the openssl.cnf I used to create the CSR I have:
DNS.1 = test.example.com
DNS.2 = test2.example.com
IP.1 = xxx.xxx.xxx.xxx
IP.2 = yyy.yyy.yyy.yyy
Note the xxx and yyy are actually real IP addresses in the cert.
Our Java Web Service clients can hit our servers using https with the IP address no problem.
Our .NET Web Service client cannot.
I am using .NET framework 3.5 for the client.
I am using Tomcat 8 for the server.
The .NET client can hit it using the comman name like www.test.example.com and the alternate
names like test2.example.com but if I try to use the IP address it fails.
I enabled Trace from system.diagnostics to see what the SSL handshake is complaining about and
I see in some of the data that comes from the server that the Subject Alternative names for DNS.x are being
sent down to the client but the IPs are not, so the IP cannot be found as an alternative in the cert.
[Subject]
CN=www.test.example.com, O=Epicor Software Corporation, L=Austin, S=Texas,
C=US
Simple Name: www.test.example.com
DNS Name: test.example.com
[Issuer]
CN=DigiCert SHA2 Secure Server CA, O=DigiCert Inc, C=US
Simple Name: DigiCert SHA2 Secure Server CA
DNS Name: DigiCert SHA2 Secure Server CA
[Serial Number]
0DB4E110FDCE072E4D98F756B3D66B3C
[Not Before]
3/27/2016 7:00:00 PM
[Not After]
4/19/2017 7:00:00 AM
[Thumbprint]
6FBC98CA67D77121BC934E0A1AC5AB552EAB88ED
[Signature Algorithm]
sha256RSA(1.2.840.113549.1.1.11)
[Public Key]
Algorithm: RSA
Length: 2048
Key Blob: 30 82 01 0a 02 82 01 01 00 ca 24 0b f0 f4 f6 58 1d 53 f6 5e 11 e6 7c 07 ae 81 4e bd b8 8d 6c ff 2c 7b c9 21 6f d4 99 86 9c 04 23 25 8b 34 31 dd 1c 85 1a 0c 86 34 a3 32 a1 17 12 3f c1 45 bf 38 3d 37 19 29 9c 44 e8 d0 b3 d6 92 9d 3d 9c ad 31 24 55 41 86 1a 2e ff 4c cb bf 32 0a 48 24 05 3f ca 0a 3c 8d f6 e0 31 14 3a a3 d8 7b 97 7b 3d 98 80 3a d8 f6 76 ca....
ProcessId=20004
DateTime=2017-02-27T21:22:06.0846039Z
System.Net Information: 0 : [22244] SecureChannel#66166301 - Remote certificate has errors:
ProcessId=20004
DateTime=2017-02-27T21:22:06.1146042Z
System.Net Information: 0 : [22244] SecureChannel#66166301 - Certificate name mismatch.
ProcessId=20004
DateTime=2017-02-27T21:22:06.1146042Z
System.Net Information: 0 : [22244] SecureChannel#66166301 - Remote certificate was verified as invalid by the user.
ProcessId=20004
DateTime=2017-02-27T21:22:06.1146042Z
System.Net.Sockets Verbose: 0 : [22244] Socket#15688314::Dispose()
ProcessId=20004
DateTime=2017-02-27T21:22:06.1146042Z
System.Net Error: 0 : [22244] Exception in the HttpWebRequest#35320229:: - The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
Well with Steffens help pointing me to Schannel and IP Address fields and a lot of other research I have found an answer to this question.
.NET does not support IP addresses as Subject Alternative Names directly because it relies on Schannel to do the verification of the IP address in the cert.
Schannel only looks for the hostname (IP) given in the https request among the "DNS Name=" fields of the cert. So if you could get a CA to give you a cert with the IP addresses listed in the "DNS Name=" fields then it would probably work. However, my CA would not allow the IP addresses to be placed in the "DNS Name=" fields and required them to be in the "IP Address=" fields as this is the industry standard now.
So this means that Schannel will get a Certificate Mismatch error when it can't find the IP in the cert.
It then looks the ServicePointManager.ServerCertificateValidationCallback property for a method to call to ask the user to validate the cert which by default this property is set to None. So it rejects the connection outright.
With c# as an example here you can create your own callback method and assign it to the ServicePointManager.ServerCertificateValidationCallback property. The method takes a sender object which is the WebRequest object used in the request, an X509Certificate which is the certificate, an X509Chain, and an SslPolicyErrors value which in the case of using an IP in the URL will be the error SslPolicyErrors.RemoteCertificationNameMismatch.