IceSSL.TrustManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ice-compat Show documentation
Show all versions of ice-compat Show documentation
Ice is a comprehensive RPC framework that helps you build distributed applications with minimal effort using familiar object-oriented idioms
//
// Copyright (c) ZeroC, Inc. All rights reserved.
//
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 dict = properties.getPropertiesForPrefix("IceSSL.TrustOnly.Server.");
for(java.util.Map.Entry p : dict.entrySet())
{
key = p.getKey();
String name = key.substring("IceSSL.TrustOnly.Server.".length());
java.util.List > reject =
new java.util.LinkedList >();
java.util.List > accept =
new java.util.LinkedList >();
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(ConnectionInfo info, String desc)
{
java.util.List > >
reject = new java.util.LinkedList > >(),
accept = new java.util.LinkedList > >();
if(!_rejectAll.isEmpty())
{
reject.add(_rejectAll);
}
if(info.incoming)
{
if(!_rejectAllServer.isEmpty())
{
reject.add(_rejectAllServer);
}
if(info.adapterName.length() > 0)
{
java.util.List > 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 > 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.certs != null && info.certs.length > 0)
{
javax.security.auth.x500.X500Principal subjectDN = ((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" +
desc);
}
else
{
_communicator.getLogger().trace("Security", "trust manager evaluating server:\n" +
"subject = " + subjectName + "\n" + desc);
}
}
java.util.List dn = RFC2253.parseStrict(subjectName);
//
// Fail if we match anything in the reject set.
//
for(java.util.List> 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> 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 > matchSet, java.util.List subject)
{
for(java.util.List r : matchSet)
{
if(matchRDNs(r, subject))
{
return true;
}
}
return false;
}
private boolean
matchRDNs(java.util.List match, java.util.List 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 > reject,
java.util.List > 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 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> matchSet, StringBuilder s)
{
boolean addSemi = false;
for(java.util.List 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 > _rejectAll =
new java.util.LinkedList >();
private java.util.List > _rejectClient =
new java.util.LinkedList >();
private java.util.List > _rejectAllServer =
new java.util.LinkedList >();
private java.util.Map > > _rejectServer =
new java.util.HashMap > >();
private java.util.List > _acceptAll =
new java.util.LinkedList >();
private java.util.List > _acceptClient =
new java.util.LinkedList >();
private java.util.List > _acceptAllServer =
new java.util.LinkedList >();
private java.util.Map > > _acceptServer =
new java.util.HashMap > >();
}