summaryrefslogtreecommitdiff
path: root/java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java')
-rw-r--r--java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java362
1 files changed, 362 insertions, 0 deletions
diff --git a/java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java b/java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java
new file mode 100644
index 00000000000..ba17851dee8
--- /dev/null
+++ b/java-compat/src/Ice/src/main/java/IceSSL/TrustManager.java
@@ -0,0 +1,362 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package IceSSL;
+
+class TrustManager
+{
+ TrustManager(Ice.Communicator communicator)
+ {
+ assert communicator != null;
+ _communicator = communicator;
+ Ice.Properties properties = communicator.getProperties();
+ _traceLevel = properties.getPropertyAsInt("IceSSL.Trace.Security");
+ String key = null;
+ try
+ {
+ key = "IceSSL.TrustOnly";
+ parse(properties.getProperty(key), _rejectAll, _acceptAll);
+ key = "IceSSL.TrustOnly.Client";
+ parse(properties.getProperty(key), _rejectClient, _acceptClient);
+ key = "IceSSL.TrustOnly.Server";
+ parse(properties.getProperty(key), _rejectAllServer, _acceptAllServer);
+ java.util.Map<String, String> dict = properties.getPropertiesForPrefix("IceSSL.TrustOnly.Server.");
+ for(java.util.Map.Entry<String, String> p : dict.entrySet())
+ {
+ key = p.getKey();
+ String name = key.substring("IceSSL.TrustOnly.Server.".length());
+ java.util.List<java.util.List<RFC2253.RDNPair> > reject =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ java.util.List<java.util.List<RFC2253.RDNPair> > accept =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ parse(p.getValue(), reject, accept);
+ if(!reject.isEmpty())
+ {
+ _rejectServer.put(name, reject);
+ }
+ if(!accept.isEmpty())
+ {
+ _acceptServer.put(name, accept);
+ }
+ }
+ }
+ catch(RFC2253.ParseException e)
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: invalid property " + key + ":\n" + e.reason;
+ throw ex;
+ }
+ }
+
+ boolean
+ verify(NativeConnectionInfo info, String desc)
+ {
+ java.util.List<java.util.List<java.util.List<RFC2253.RDNPair> > >
+ reject = new java.util.LinkedList<java.util.List<java.util.List<RFC2253.RDNPair> > >(),
+ accept = new java.util.LinkedList<java.util.List<java.util.List<RFC2253.RDNPair> > >();
+
+ if(!_rejectAll.isEmpty())
+ {
+ reject.add(_rejectAll);
+ }
+ if(info.incoming)
+ {
+ if(!_rejectAllServer.isEmpty())
+ {
+ reject.add(_rejectAllServer);
+ }
+ if(info.adapterName.length() > 0)
+ {
+ java.util.List<java.util.List<RFC2253.RDNPair> > p = _rejectServer.get(info.adapterName);
+ if(p != null)
+ {
+ reject.add(p);
+ }
+ }
+ }
+ else
+ {
+ if(!_rejectClient.isEmpty())
+ {
+ reject.add(_rejectClient);
+ }
+ }
+
+ if(!_acceptAll.isEmpty())
+ {
+ accept.add(_acceptAll);
+ }
+ if(info.incoming)
+ {
+ if(!_acceptAllServer.isEmpty())
+ {
+ accept.add(_acceptAllServer);
+ }
+ if(info.adapterName.length() > 0)
+ {
+ java.util.List<java.util.List<RFC2253.RDNPair> > p = _acceptServer.get(info.adapterName);
+ if(p != null)
+ {
+ accept.add(p);
+ }
+ }
+ }
+ else
+ {
+ if(!_acceptClient.isEmpty())
+ {
+ accept.add(_acceptClient);
+ }
+ }
+
+ //
+ // If there is nothing to match against, then we accept the cert.
+ //
+ if(reject.isEmpty() && accept.isEmpty())
+ {
+ return true;
+ }
+
+ //
+ // If there is no certificate then we match false.
+ //
+ if(info.nativeCerts != null && info.nativeCerts.length > 0)
+ {
+ javax.security.auth.x500.X500Principal subjectDN = ((java.security.cert.X509Certificate)info.nativeCerts[0]).getSubjectX500Principal();
+ String subjectName = subjectDN.getName(javax.security.auth.x500.X500Principal.RFC2253);
+ assert subjectName != null;
+ try
+ {
+ //
+ // Decompose the subject DN into the RDNs.
+ //
+ if(_traceLevel > 0)
+ {
+ if(info.incoming)
+ {
+ _communicator.getLogger().trace("Security", "trust manager evaluating client:\n" +
+ "subject = " + subjectName + "\n" +
+ "adapter = " + info.adapterName + "\n" +
+ desc);
+ }
+ else
+ {
+ _communicator.getLogger().trace("Security", "trust manager evaluating server:\n" +
+ "subject = " + subjectName + "\n" + desc);
+ }
+ }
+ java.util.List<RFC2253.RDNPair> dn = RFC2253.parseStrict(subjectName);
+
+ //
+ // Fail if we match anything in the reject set.
+ //
+ for(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet : reject)
+ {
+ if(_traceLevel > 1)
+ {
+ StringBuilder s = new StringBuilder("trust manager rejecting PDNs:\n");
+ stringify(matchSet, s);
+ _communicator.getLogger().trace("Security", s.toString());
+ }
+ if(match(matchSet, dn))
+ {
+ return false;
+ }
+ }
+
+ //
+ // Succeed if we match anything in the accept set.
+ //
+ for(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet : accept)
+ {
+ if(_traceLevel > 1)
+ {
+ StringBuilder s = new StringBuilder("trust manager accepting PDNs:\n");
+ stringify(matchSet, s);
+ _communicator.getLogger().trace("Security", s.toString());
+ }
+ if(match(matchSet, dn))
+ {
+ return true;
+ }
+ }
+ }
+ catch(RFC2253.ParseException e)
+ {
+ _communicator.getLogger().warning(
+ "IceSSL: unable to parse certificate DN `" + subjectName + "'\nreason: " + e.reason);
+ }
+
+ //
+ // At this point we accept the connection if there are no explicit accept rules.
+ //
+ return accept.isEmpty();
+ }
+
+ return false;
+ }
+
+ private boolean
+ match(java.util.List<java.util.List<RFC2253.RDNPair> > matchSet, java.util.List<RFC2253.RDNPair> subject)
+ {
+ for(java.util.List<RFC2253.RDNPair> r : matchSet)
+ {
+ if(matchRDNs(r, subject))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean
+ matchRDNs(java.util.List<RFC2253.RDNPair> match, java.util.List<RFC2253.RDNPair> subject)
+ {
+ for(RFC2253.RDNPair matchRDN : match)
+ {
+ boolean found = false;
+ for(RFC2253.RDNPair subjectRDN : subject)
+ {
+ if(matchRDN.key.equals(subjectRDN.key))
+ {
+ found = true;
+ if(!matchRDN.value.equals(subjectRDN.value))
+ {
+ return false;
+ }
+ }
+ }
+ if(!found)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void
+ parse(String value, java.util.List<java.util.List<RFC2253.RDNPair> > reject,
+ java.util.List<java.util.List<RFC2253.RDNPair> > accept)
+ throws RFC2253.ParseException
+ {
+ //
+ // Java X500Principal.getName says:
+ //
+ // If "RFC2253" is specified as the format, this method emits
+ // the attribute type keywords defined in RFC 2253 (CN, L, ST,
+ // O, OU, C, STREET, DC, UID). Any other attribute type is
+ // emitted as an OID. Under a strict reading, RFC 2253 only
+ // specifies a UTF-8 string representation. The String
+ // returned by this method is the Unicode string achieved by
+ // decoding this UTF-8 representation.
+ //
+ // This means that things like emailAddress and such will be turned into
+ // something like:
+ //
+ // 1.2.840.113549.1.9.1=#160e696e666f407a65726f632e636f6d
+ //
+ // The left hand side is the OID (see
+ // http://www.columbia.edu/~ariel/ssleay/asn1-oids.html) for a
+ // list. The right hand side is a BER encoding of the value.
+ //
+ // This means that the user input, unless it uses the
+ // unfriendly OID format, will not directly match the
+ // principal.
+ //
+ // Two possible solutions:
+ //
+ // Have the RFC2253 parser convert anything that is not CN, L,
+ // ST, O, OU, C, STREET, DC, UID into OID format, and have it
+ // convert the values into a BER encoding.
+ //
+ // Send the user data through X500Principal to string form and
+ // then through the RFC2253 encoder. This uses the
+ // X500Principal to do the encoding for us.
+ //
+ // The latter is much simpler, however, it means we need to
+ // send the data through the parser twice because we split the
+ // DNs on ';' which cannot be blindly split because of quotes,
+ // \ and such.
+ //
+ java.util.List<RFC2253.RDNEntry> l = RFC2253.parse(value);
+ for(RFC2253.RDNEntry e : l)
+ {
+ StringBuilder v = new StringBuilder();
+ boolean first = true;
+ for(RFC2253.RDNPair pair : e.rdn)
+ {
+ if(!first)
+ {
+ v.append(",");
+ }
+ first = false;
+ v.append(pair.key);
+ v.append("=");
+ v.append(pair.value);
+ }
+ javax.security.auth.x500.X500Principal princ = new javax.security.auth.x500.X500Principal(v.toString());
+ String subjectName = princ.getName(javax.security.auth.x500.X500Principal.RFC2253);
+ if(e.negate)
+ {
+ reject.add(RFC2253.parseStrict(subjectName));
+ }
+ else
+ {
+ accept.add(RFC2253.parseStrict(subjectName));
+ }
+ }
+ }
+
+ private static void
+ stringify(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet, StringBuilder s)
+ {
+ boolean addSemi = false;
+ for(java.util.List<RFC2253.RDNPair> rdnSet : matchSet)
+ {
+ if(addSemi)
+ {
+ s.append(';');
+ }
+ addSemi = true;
+ boolean addComma = false;
+ for(RFC2253.RDNPair rdn : rdnSet)
+ {
+ if(addComma)
+ {
+ s.append(',');
+ }
+ addComma = true;
+ s.append(rdn.key);
+ s.append('=');
+ s.append(rdn.value);
+ }
+ }
+ }
+
+ private Ice.Communicator _communicator;
+ private int _traceLevel;
+
+ private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectAll =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectClient =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectAllServer =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ private java.util.Map<String, java.util.List<java.util.List<RFC2253.RDNPair> > > _rejectServer =
+ new java.util.HashMap<String, java.util.List<java.util.List<RFC2253.RDNPair> > >();
+
+ private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptAll =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptClient =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptAllServer =
+ new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >();
+ private java.util.Map<String, java.util.List<java.util.List<RFC2253.RDNPair> > > _acceptServer =
+ new java.util.HashMap<String, java.util.List<java.util.List<RFC2253.RDNPair> > >();
+}