1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 package com.zeroc.IceSSL; 6 7 class TrustManager 8 { TrustManager(com.zeroc.Ice.Communicator communicator)9 TrustManager(com.zeroc.Ice.Communicator communicator) 10 { 11 assert communicator != null; 12 _communicator = communicator; 13 com.zeroc.Ice.Properties properties = communicator.getProperties(); 14 _traceLevel = properties.getPropertyAsInt("IceSSL.Trace.Security"); 15 String key = null; 16 try 17 { 18 key = "IceSSL.TrustOnly"; 19 parse(properties.getProperty(key), _rejectAll, _acceptAll); 20 key = "IceSSL.TrustOnly.Client"; 21 parse(properties.getProperty(key), _rejectClient, _acceptClient); 22 key = "IceSSL.TrustOnly.Server"; 23 parse(properties.getProperty(key), _rejectAllServer, _acceptAllServer); 24 java.util.Map<String, String> dict = properties.getPropertiesForPrefix("IceSSL.TrustOnly.Server."); 25 for(java.util.Map.Entry<String, String> p : dict.entrySet()) 26 { 27 key = p.getKey(); 28 String name = key.substring("IceSSL.TrustOnly.Server.".length()); 29 java.util.List<java.util.List<RFC2253.RDNPair> > reject = 30 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 31 java.util.List<java.util.List<RFC2253.RDNPair> > accept = 32 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 33 parse(p.getValue(), reject, accept); 34 if(!reject.isEmpty()) 35 { 36 _rejectServer.put(name, reject); 37 } 38 if(!accept.isEmpty()) 39 { 40 _acceptServer.put(name, accept); 41 } 42 } 43 } 44 catch(RFC2253.ParseException e) 45 { 46 com.zeroc.Ice.PluginInitializationException ex = new com.zeroc.Ice.PluginInitializationException(); 47 ex.reason = "IceSSL: invalid property " + key + ":\n" + e.reason; 48 throw ex; 49 } 50 } 51 52 boolean verify(ConnectionInfo info, String desc)53 verify(ConnectionInfo info, String desc) 54 { 55 java.util.List<java.util.List<java.util.List<RFC2253.RDNPair> > > 56 reject = new java.util.LinkedList<java.util.List<java.util.List<RFC2253.RDNPair> > >(), 57 accept = new java.util.LinkedList<java.util.List<java.util.List<RFC2253.RDNPair> > >(); 58 59 if(!_rejectAll.isEmpty()) 60 { 61 reject.add(_rejectAll); 62 } 63 if(info.incoming) 64 { 65 if(!_rejectAllServer.isEmpty()) 66 { 67 reject.add(_rejectAllServer); 68 } 69 if(info.adapterName.length() > 0) 70 { 71 java.util.List<java.util.List<RFC2253.RDNPair> > p = _rejectServer.get(info.adapterName); 72 if(p != null) 73 { 74 reject.add(p); 75 } 76 } 77 } 78 else 79 { 80 if(!_rejectClient.isEmpty()) 81 { 82 reject.add(_rejectClient); 83 } 84 } 85 86 if(!_acceptAll.isEmpty()) 87 { 88 accept.add(_acceptAll); 89 } 90 if(info.incoming) 91 { 92 if(!_acceptAllServer.isEmpty()) 93 { 94 accept.add(_acceptAllServer); 95 } 96 if(info.adapterName.length() > 0) 97 { 98 java.util.List<java.util.List<RFC2253.RDNPair> > p = _acceptServer.get(info.adapterName); 99 if(p != null) 100 { 101 accept.add(p); 102 } 103 } 104 } 105 else 106 { 107 if(!_acceptClient.isEmpty()) 108 { 109 accept.add(_acceptClient); 110 } 111 } 112 113 // 114 // If there is nothing to match against, then we accept the cert. 115 // 116 if(reject.isEmpty() && accept.isEmpty()) 117 { 118 return true; 119 } 120 121 // 122 // If there is no certificate then we match false. 123 // 124 if(info.certs != null && info.certs.length > 0) 125 { 126 javax.security.auth.x500.X500Principal subjectDN = 127 ((java.security.cert.X509Certificate)info.certs[0]).getSubjectX500Principal(); 128 String subjectName = subjectDN.getName(javax.security.auth.x500.X500Principal.RFC2253); 129 assert subjectName != null; 130 try 131 { 132 // 133 // Decompose the subject DN into the RDNs. 134 // 135 if(_traceLevel > 0) 136 { 137 if(info.incoming) 138 { 139 _communicator.getLogger().trace("Security", "trust manager evaluating client:\n" + 140 "subject = " + subjectName + "\n" + 141 "adapter = " + info.adapterName + "\n" + 142 desc); 143 } 144 else 145 { 146 _communicator.getLogger().trace("Security", "trust manager evaluating server:\n" + 147 "subject = " + subjectName + "\n" + desc); 148 } 149 } 150 java.util.List<RFC2253.RDNPair> dn = RFC2253.parseStrict(subjectName); 151 152 // 153 // Fail if we match anything in the reject set. 154 // 155 for(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet : reject) 156 { 157 if(_traceLevel > 1) 158 { 159 StringBuilder s = new StringBuilder("trust manager rejecting PDNs:\n"); 160 stringify(matchSet, s); 161 _communicator.getLogger().trace("Security", s.toString()); 162 } 163 if(match(matchSet, dn)) 164 { 165 return false; 166 } 167 } 168 169 // 170 // Succeed if we match anything in the accept set. 171 // 172 for(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet : accept) 173 { 174 if(_traceLevel > 1) 175 { 176 StringBuilder s = new StringBuilder("trust manager accepting PDNs:\n"); 177 stringify(matchSet, s); 178 _communicator.getLogger().trace("Security", s.toString()); 179 } 180 if(match(matchSet, dn)) 181 { 182 return true; 183 } 184 } 185 } 186 catch(RFC2253.ParseException e) 187 { 188 _communicator.getLogger().warning( 189 "IceSSL: unable to parse certificate DN `" + subjectName + "'\nreason: " + e.reason); 190 } 191 192 // 193 // At this point we accept the connection if there are no explicit accept rules. 194 // 195 return accept.isEmpty(); 196 } 197 198 return false; 199 } 200 201 private boolean match(java.util.List<java.util.List<RFC2253.RDNPair> > matchSet, java.util.List<RFC2253.RDNPair> subject)202 match(java.util.List<java.util.List<RFC2253.RDNPair> > matchSet, java.util.List<RFC2253.RDNPair> subject) 203 { 204 for(java.util.List<RFC2253.RDNPair> r : matchSet) 205 { 206 if(matchRDNs(r, subject)) 207 { 208 return true; 209 } 210 } 211 return false; 212 } 213 214 private boolean matchRDNs(java.util.List<RFC2253.RDNPair> match, java.util.List<RFC2253.RDNPair> subject)215 matchRDNs(java.util.List<RFC2253.RDNPair> match, java.util.List<RFC2253.RDNPair> subject) 216 { 217 for(RFC2253.RDNPair matchRDN : match) 218 { 219 boolean found = false; 220 for(RFC2253.RDNPair subjectRDN : subject) 221 { 222 if(matchRDN.key.equals(subjectRDN.key)) 223 { 224 found = true; 225 if(!matchRDN.value.equals(subjectRDN.value)) 226 { 227 return false; 228 } 229 } 230 } 231 if(!found) 232 { 233 return false; 234 } 235 } 236 return true; 237 } 238 239 void parse(String value, java.util.List<java.util.List<RFC2253.RDNPair> > reject, java.util.List<java.util.List<RFC2253.RDNPair> > accept)240 parse(String value, java.util.List<java.util.List<RFC2253.RDNPair> > reject, 241 java.util.List<java.util.List<RFC2253.RDNPair> > accept) 242 throws RFC2253.ParseException 243 { 244 // 245 // Java X500Principal.getName says: 246 // 247 // If "RFC2253" is specified as the format, this method emits 248 // the attribute type keywords defined in RFC 2253 (CN, L, ST, 249 // O, OU, C, STREET, DC, UID). Any other attribute type is 250 // emitted as an OID. Under a strict reading, RFC 2253 only 251 // specifies a UTF-8 string representation. The String 252 // returned by this method is the Unicode string achieved by 253 // decoding this UTF-8 representation. 254 // 255 // This means that things like emailAddress and such will be turned into 256 // something like: 257 // 258 // 1.2.840.113549.1.9.1=#160e696e666f407a65726f632e636f6d 259 // 260 // The left hand side is the OID (see 261 // http://www.columbia.edu/~ariel/ssleay/asn1-oids.html) for a 262 // list. The right hand side is a BER encoding of the value. 263 // 264 // This means that the user input, unless it uses the 265 // unfriendly OID format, will not directly match the 266 // principal. 267 // 268 // Two possible solutions: 269 // 270 // Have the RFC2253 parser convert anything that is not CN, L, 271 // ST, O, OU, C, STREET, DC, UID into OID format, and have it 272 // convert the values into a BER encoding. 273 // 274 // Send the user data through X500Principal to string form and 275 // then through the RFC2253 encoder. This uses the 276 // X500Principal to do the encoding for us. 277 // 278 // The latter is much simpler, however, it means we need to 279 // send the data through the parser twice because we split the 280 // DNs on ';' which cannot be blindly split because of quotes, 281 // \ and such. 282 // 283 java.util.List<RFC2253.RDNEntry> l = RFC2253.parse(value); 284 for(RFC2253.RDNEntry e : l) 285 { 286 StringBuilder v = new StringBuilder(); 287 boolean first = true; 288 for(RFC2253.RDNPair pair : e.rdn) 289 { 290 if(!first) 291 { 292 v.append(","); 293 } 294 first = false; 295 v.append(pair.key); 296 v.append("="); 297 v.append(pair.value); 298 } 299 javax.security.auth.x500.X500Principal princ = new javax.security.auth.x500.X500Principal(v.toString()); 300 String subjectName = princ.getName(javax.security.auth.x500.X500Principal.RFC2253); 301 if(e.negate) 302 { 303 reject.add(RFC2253.parseStrict(subjectName)); 304 } 305 else 306 { 307 accept.add(RFC2253.parseStrict(subjectName)); 308 } 309 } 310 } 311 312 private static void stringify(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet, StringBuilder s)313 stringify(java.util.List<java.util.List<RFC2253.RDNPair>> matchSet, StringBuilder s) 314 { 315 boolean addSemi = false; 316 for(java.util.List<RFC2253.RDNPair> rdnSet : matchSet) 317 { 318 if(addSemi) 319 { 320 s.append(';'); 321 } 322 addSemi = true; 323 boolean addComma = false; 324 for(RFC2253.RDNPair rdn : rdnSet) 325 { 326 if(addComma) 327 { 328 s.append(','); 329 } 330 addComma = true; 331 s.append(rdn.key); 332 s.append('='); 333 s.append(rdn.value); 334 } 335 } 336 } 337 338 private com.zeroc.Ice.Communicator _communicator; 339 private int _traceLevel; 340 341 private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectAll = 342 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 343 private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectClient = 344 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 345 private java.util.List<java.util.List<RFC2253.RDNPair> > _rejectAllServer = 346 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 347 private java.util.Map<String, java.util.List<java.util.List<RFC2253.RDNPair> > > _rejectServer = 348 new java.util.HashMap<String, java.util.List<java.util.List<RFC2253.RDNPair> > >(); 349 350 private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptAll = 351 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 352 private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptClient = 353 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 354 private java.util.List<java.util.List<RFC2253.RDNPair> > _acceptAllServer = 355 new java.util.LinkedList<java.util.List<RFC2253.RDNPair> >(); 356 private java.util.Map<String, java.util.List<java.util.List<RFC2253.RDNPair> > > _acceptServer = 357 new java.util.HashMap<String, java.util.List<java.util.List<RFC2253.RDNPair> > >(); 358 } 359