summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2017-07-17 16:23:32 -0700
committerMark Spruiell <mes@zeroc.com>2017-07-17 16:23:32 -0700
commit55cb5f5a91dc29895139e5db3f64add2c4d061c9 (patch)
tree9add89a09ac9a3d020bc4a149957bb06e078855e
parentFixed typo (diff)
downloadice-55cb5f5a91dc29895139e5db3f64add2c4d061c9.tar.bz2
ice-55cb5f5a91dc29895139e5db3f64add2c4d061c9.tar.xz
ice-55cb5f5a91dc29895139e5db3f64add2c4d061c9.zip
ICE-8350 - restore CheckCertName code for java compat SSLEngine
-rw-r--r--java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java139
1 files changed, 131 insertions, 8 deletions
diff --git a/java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java b/java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java
index 234f8fd83fe..3a2c88769b9 100644
--- a/java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java
+++ b/java-compat/src/Ice/src/main/java/IceSSL/SSLEngine.java
@@ -855,9 +855,10 @@ class SSLEngine
else
{
//
- // Enable the HTTPS hostname verification algorithm
+ // Enable the HTTPS hostname verification algorithm. This requires Android API 24 therefore we
+ // don't use it on Android in Java Compat.
//
- if(_checkCertName && _verifyPeer > 0 && host != null)
+ if(_checkCertName && _verifyPeer > 0 && host != null && !IceInternal.Util.isAndroid())
{
SSLParameters params = new SSLParameters();
params.setEndpointIdentificationAlgorithm("HTTPS");
@@ -971,16 +972,138 @@ class SSLEngine
void verifyPeer(String address, ConnectionInfo info, String desc)
{
- //
- // IceSSL.VerifyPeer is translated into the proper SSLEngine configuration
- // for a server, but we have to do it ourselves for a client.
- //
- if(!info.incoming)
+ if(!info.incoming && _verifyPeer > 0)
{
- if(_verifyPeer > 0 && !info.verified)
+ //
+ // IceSSL.VerifyPeer is translated into the proper SSLEngine configuration
+ // for a server, but we have to do it ourselves for a client.
+ //
+ if(!info.verified)
{
throw new Ice.SecurityException("IceSSL: server did not supply a certificate");
}
+
+ assert(info.certs != null && info.certs.length > 0);
+
+ //
+ // If IceSSL.CheckCertName is enabled on Android, we have to handle this manually.
+ //
+ if(_checkCertName && address.length() > 0 && IceInternal.Util.isAndroid())
+ {
+ //
+ // For an outgoing connection, we compare the proxy address (if any) against
+ // fields in the server's certificate (if any).
+ //
+ X509Certificate cert = (X509Certificate)info.certs[0];
+
+ //
+ // Extract the IP addresses and the DNS names from the subject
+ // alternative names.
+ //
+ java.util.ArrayList<String> ipAddresses = new java.util.ArrayList<String>();
+ java.util.ArrayList<String> dnsNames = new java.util.ArrayList<String>();
+ try
+ {
+ java.util.Collection<java.util.List<?> > subjectAltNames = cert.getSubjectAlternativeNames();
+ if(subjectAltNames != null)
+ {
+ for(java.util.List<?> l : subjectAltNames)
+ {
+ assert(!l.isEmpty());
+ Integer n = (Integer)l.get(0);
+ if(n.intValue() == 7)
+ {
+ ipAddresses.add((String)l.get(1));
+ }
+ else if(n.intValue() == 2)
+ {
+ dnsNames.add(((String)l.get(1)).toLowerCase());
+ }
+ }
+ }
+ }
+ catch(CertificateParsingException ex)
+ {
+ assert(false);
+ }
+
+ //
+ // Compare the peer's address against the common name as well as
+ // the dnsName and ipAddress values in the subject alternative name.
+ //
+ boolean certNameOK = false;
+ String dn = "";
+ String addrLower = address.toLowerCase();
+ {
+ javax.security.auth.x500.X500Principal principal = cert.getSubjectX500Principal();
+ dn = principal.getName(javax.security.auth.x500.X500Principal.CANONICAL);
+ //
+ // Canonical format is already in lower case.
+ //
+ String cn = "cn=" + addrLower;
+ int pos = dn.indexOf(cn);
+ if(pos >= 0)
+ {
+ //
+ // Ensure we match the entire common name.
+ //
+ certNameOK = (pos + cn.length() == dn.length()) || (dn.charAt(pos + cn.length()) == ',');
+ }
+ }
+
+ //
+ // Compare the peer's address against the dnsName and ipAddress
+ // values in the subject alternative name.
+ //
+ if(!certNameOK)
+ {
+ certNameOK = ipAddresses.contains(addrLower);
+ }
+ if(!certNameOK)
+ {
+ certNameOK = dnsNames.contains(addrLower);
+ }
+
+ if(!certNameOK)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("IceSSL: certificate validation failure:\npeer certificate does not have `");
+ sb.append(address);
+ sb.append("' as its commonName or in its subjectAltName extension");
+ if(dn.length() > 0)
+ {
+ sb.append("\nSubject DN: ");
+ sb.append(dn);
+ }
+ if(!dnsNames.isEmpty())
+ {
+ sb.append("\nDNS names found in certificate: ");
+ for(int j = 0; j < dnsNames.size(); ++j)
+ {
+ if(j > 0)
+ {
+ sb.append(", ");
+ }
+ sb.append(dnsNames.get(j));
+ }
+ }
+ if(!ipAddresses.isEmpty())
+ {
+ sb.append("\nIP addresses found in certificate: ");
+ for(int j = 0; j < ipAddresses.size(); ++j)
+ {
+ if(j > 0)
+ {
+ sb.append(", ");
+ }
+ sb.append(ipAddresses.get(j));
+ }
+ }
+ Ice.SecurityException ex = new Ice.SecurityException();
+ ex.reason = sb.toString();
+ throw ex;
+ }
+ }
}
if(_verifyDepthMax > 0 && info.certs != null && info.certs.length > _verifyDepthMax)