summaryrefslogtreecommitdiff
path: root/java/src/IceSSL/TrustManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/IceSSL/TrustManager.java')
-rw-r--r--java/src/IceSSL/TrustManager.java295
1 files changed, 295 insertions, 0 deletions
diff --git a/java/src/IceSSL/TrustManager.java b/java/src/IceSSL/TrustManager.java
new file mode 100644
index 00000000000..8598c1ac7e6
--- /dev/null
+++ b/java/src/IceSSL/TrustManager.java
@@ -0,0 +1,295 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2007 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";
+ _all = parse(properties.getProperty(key));
+ key = "IceSSL.TrustOnly.Client";
+ _client = parse(properties.getProperty(key));
+ key = "IceSSL.TrustOnly.Server";
+ _allServer = parse(properties.getProperty(key));
+ java.util.Map dict = properties.getPropertiesForPrefix("IceSSL.TrustOnly.Server.");
+ java.util.Iterator p = dict.entrySet().iterator();
+ while(p.hasNext())
+ {
+ java.util.Map.Entry entry = (java.util.Map.Entry)p.next();
+ key = (String)entry.getKey();
+ String name = key.substring("IceSSL.TrustOnly.Server.".length());
+ _server.put(name, parse((String)entry.getValue()));
+ }
+ }
+ catch(RFC2253.ParseException e)
+ {
+ Ice.PluginInitializationException ex = new Ice.PluginInitializationException();
+ ex.reason = "IceSSL: invalid property " + key + ":\n" + e.reason;
+ throw ex;
+ }
+ }
+
+ boolean
+ verify(ConnectionInfo info)
+ {
+ java.util.List trustset = new java.util.LinkedList();
+ if(!_all.isEmpty())
+ {
+ trustset.add(_all);
+ }
+
+ if(info.incoming)
+ {
+ if(!_allServer.isEmpty())
+ {
+ trustset.add(_allServer);
+ }
+ if(info.adapterName.length() > 0)
+ {
+ java.util.List p = (java.util.List)_server.get(info.adapterName);
+ if(p != null)
+ {
+ trustset.add(p);
+ }
+ }
+ }
+ else
+ {
+ if(!_client.isEmpty())
+ {
+ trustset.add(_client);
+ }
+ }
+
+ //
+ // If there is nothing to match against, then we accept the cert.
+ //
+ if(trustset.isEmpty())
+ {
+ return true;
+ }
+
+ //
+ // If there is no certificate then we match false.
+ //
+ if(info.certs != null && info.certs.length > 0)
+ {
+ javax.security.auth.x500.X500Principal subjectDN = (javax.security.auth.x500.X500Principal)
+ ((java.security.cert.X509Certificate)info.certs[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" +
+ "local addr = " + IceInternal.Network.addrToString(info.localAddr) + "\n" +
+ "remote addr = " + IceInternal.Network.addrToString(info.remoteAddr));
+ }
+ else
+ {
+ _communicator.getLogger().trace("Security", "trust manager evaluating server:\n" +
+ "subject = " + subjectName + "\n" +
+ "local addr = " + IceInternal.Network.addrToString(info.localAddr) + "\n" +
+ "remote addr = " + IceInternal.Network.addrToString(info.remoteAddr));
+ }
+ }
+ java.util.List dn = RFC2253.parseStrict(subjectName);
+
+ //
+ // Try matching against everything in the trust set.
+ //
+ java.util.Iterator p = trustset.iterator();
+ while(p.hasNext())
+ {
+ java.util.List matchSet = (java.util.List)p.next();
+ if(_traceLevel > 1)
+ {
+ String s = "trust manager matching PDNs:\n";
+ java.util.Iterator q = matchSet.iterator();
+ boolean addSemi = false;
+ while(q.hasNext())
+ {
+ if(addSemi)
+ {
+ s += ';';
+ }
+ addSemi = true;
+ java.util.List rdnSet = (java.util.List)q.next();
+ java.util.Iterator r = rdnSet.iterator();
+ boolean addComma = false;
+ while(r.hasNext())
+ {
+ if(addComma)
+ {
+ s += ',';
+ }
+ addComma = true;
+ RFC2253.RDNPair rdn = (RFC2253.RDNPair)r.next();
+ s += rdn.key;
+ s += '=';
+ s += rdn.value;
+ }
+ }
+ _communicator.getLogger().trace("Security", s);
+ }
+ if(match(matchSet, dn))
+ {
+ return true;
+ }
+ }
+ }
+ catch(RFC2253.ParseException e)
+ {
+ _communicator.getLogger().warning(
+ "IceSSL: unable to parse certificate DN `" + subjectName + "'\nreason: " + e.reason);
+ }
+ }
+
+ return false;
+ }
+
+ private boolean
+ match(java.util.List matchSet, java.util.List subject)
+ {
+ java.util.Iterator r = matchSet.iterator();
+ while(r.hasNext())
+ {
+ if(matchRDNs((java.util.List)r.next(), subject))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean
+ matchRDNs(java.util.List match, java.util.List subject)
+ {
+ java.util.Iterator p = match.iterator();
+ while(p.hasNext())
+ {
+ RFC2253.RDNPair matchRDN = (RFC2253.RDNPair)p.next();
+ boolean found = false;
+ java.util.Iterator q = subject.iterator();
+ while(q.hasNext())
+ {
+ RFC2253.RDNPair subjectRDN = (RFC2253.RDNPair)q.next();
+ if(matchRDN.key.equals(subjectRDN.key))
+ {
+ found = true;
+ if(!matchRDN.value.equals(subjectRDN.value))
+ {
+ return false;
+ }
+ }
+ }
+ if(!found)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ java.util.List
+ parse(String value)
+ 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 l = RFC2253.parse(value);
+ java.util.List result = new java.util.LinkedList();
+ java.util.Iterator p = l.iterator();
+ while(p.hasNext())
+ {
+ java.util.List dn = (java.util.List)p.next();
+ String v = new String();
+ boolean first = true;
+ java.util.Iterator q = dn.iterator();
+ while(q.hasNext())
+ {
+ if(!first)
+ {
+ v += ",";
+ }
+ first = false;
+ RFC2253.RDNPair pair = (RFC2253.RDNPair)q.next();
+ v += pair.key;
+ v += "=";
+ v += pair.value;
+ }
+ javax.security.auth.x500.X500Principal princ = new javax.security.auth.x500.X500Principal(v);
+ String subjectName = princ.getName(javax.security.auth.x500.X500Principal.RFC2253);
+ result.add(RFC2253.parseStrict(subjectName));
+ }
+ return result;
+ }
+
+ private Ice.Communicator _communicator;
+ private int _traceLevel;
+
+ private java.util.List _all;
+ private java.util.List _client;
+ private java.util.List _allServer;
+ private java.util.Map _server = new java.util.HashMap();
+}