Source for gnu.javax.net.ssl.provider.X509KeyManagerFactory

   1: /* X509KeyManagerFactory.java -- X.509 key manager factory.
   2:    Copyright (C) 2006  Free Software Foundation, Inc.
   3: 
   4: This file is a part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2 of the License, or (at
   9: your option) any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: USA
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.  */
  37: 
  38: 
  39: package gnu.javax.net.ssl.provider;
  40: 
  41: import java.io.FileInputStream;
  42: import java.io.IOException;
  43: import java.net.Socket;
  44: 
  45: import java.util.HashMap;
  46: import java.util.Iterator;
  47: import java.util.LinkedList;
  48: import java.util.Enumeration;
  49: 
  50: import java.security.InvalidAlgorithmParameterException;
  51: import java.security.KeyStore;
  52: import java.security.KeyStoreException;
  53: import java.security.NoSuchAlgorithmException;
  54: import java.security.Principal;
  55: import java.security.PrivateKey;
  56: import java.security.PublicKey;
  57: import java.security.UnrecoverableKeyException;
  58: import java.security.cert.Certificate;
  59: import java.security.cert.CertificateException;
  60: import java.security.cert.X509Certificate;
  61: import java.security.interfaces.DSAPrivateKey;
  62: import java.security.interfaces.DSAPublicKey;
  63: import java.security.interfaces.RSAPrivateKey;
  64: import java.security.interfaces.RSAPublicKey;
  65: 
  66: import java.util.Collections;
  67: import java.util.Map;
  68: import java.util.List;
  69: 
  70: import javax.crypto.interfaces.DHPrivateKey;
  71: import javax.crypto.interfaces.DHPublicKey;
  72: 
  73: import javax.net.ssl.KeyManager;
  74: import javax.net.ssl.KeyManagerFactorySpi;
  75: import javax.net.ssl.ManagerFactoryParameters;
  76: import javax.net.ssl.SSLEngine;
  77: import javax.net.ssl.X509ExtendedKeyManager;
  78: import gnu.javax.net.ssl.NullManagerParameters;
  79: import gnu.javax.net.ssl.PrivateCredentials;
  80: 
  81: /**
  82:  * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine
  83:  * for the ``JessieX509'' algorithm.
  84:  */
  85: public class X509KeyManagerFactory extends KeyManagerFactorySpi
  86: {
  87: 
  88:   // Fields.
  89:   // -------------------------------------------------------------------------
  90: 
  91:   private Manager current;
  92: 
  93:   // Constructor.
  94:   // -------------------------------------------------------------------------
  95: 
  96:   public X509KeyManagerFactory()
  97:   {
  98:     super();
  99:   }
 100: 
 101:   // Instance methods.
 102:   // -------------------------------------------------------------------------
 103: 
 104:   protected KeyManager[] engineGetKeyManagers()
 105:   {
 106:     if (current == null)
 107:       {
 108:         throw new IllegalStateException();
 109:       }
 110:     return new KeyManager[] { current };
 111:   }
 112: 
 113:   protected void engineInit(ManagerFactoryParameters params)
 114:     throws InvalidAlgorithmParameterException
 115:   {
 116:     if (params instanceof NullManagerParameters)
 117:       {
 118:         current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
 119:       }
 120:     else if (params instanceof PrivateCredentials)
 121:       {
 122:         List<X509Certificate[]> chains
 123:           = ((PrivateCredentials) params).getCertChains();
 124:         List<PrivateKey> keys
 125:           = ((PrivateCredentials) params).getPrivateKeys();
 126:         int i = 0;
 127:         HashMap<String, X509Certificate[]> certMap
 128:           = new HashMap<String, X509Certificate[]>();
 129:         HashMap<String, PrivateKey> keyMap
 130:           = new HashMap<String, PrivateKey>();
 131:         Iterator<X509Certificate[]> c = chains.iterator();
 132:         Iterator<PrivateKey> k = keys.iterator();
 133:         while (c.hasNext() && k.hasNext())
 134:           {
 135:             certMap.put(String.valueOf(i), c.next());
 136:             keyMap.put(String.valueOf(i), k.next());
 137:             i++;
 138:           }
 139:         current = new Manager(keyMap, certMap);
 140:       }
 141:     else
 142:       {
 143:         throw new InvalidAlgorithmParameterException();
 144:       }
 145:   }
 146: 
 147:   protected void engineInit(KeyStore store, char[] passwd)
 148:     throws KeyStoreException, NoSuchAlgorithmException,
 149:            UnrecoverableKeyException
 150:   {
 151:     if (store == null)
 152:       {
 153:         String s = Util.getProperty("javax.net.ssl.keyStoreType");
 154:         if (s == null)
 155:           s = KeyStore.getDefaultType();
 156:         store = KeyStore.getInstance(s);
 157:         s = Util.getProperty("javax.net.ssl.keyStore");
 158:         if (s == null)
 159:           return;
 160:         String p = Util.getProperty("javax.net.ssl.keyStorePassword");
 161:         try
 162:           {
 163:             store.load(new FileInputStream(s), p != null ? p.toCharArray() : null);
 164:           }
 165:         catch (IOException ioe)
 166:           {
 167:             throw new KeyStoreException(ioe.toString());
 168:           }
 169:         catch (CertificateException ce)
 170:           {
 171:             throw new KeyStoreException(ce.toString());
 172:           }
 173:       }
 174: 
 175:     HashMap<String, PrivateKey> p = new HashMap<String, PrivateKey>();
 176:     HashMap<String, X509Certificate[]> c
 177:       = new HashMap<String, X509Certificate[]>();
 178:     Enumeration aliases = store.aliases();
 179:     UnrecoverableKeyException exception = null;
 180:     while (aliases.hasMoreElements())
 181:       {
 182:         String alias = (String) aliases.nextElement();
 183:         if (!store.isKeyEntry(alias))
 184:           {
 185:             continue;
 186:           }
 187:         X509Certificate[] chain = null;
 188:         Certificate[] chain2 = store.getCertificateChain (alias);
 189:         if (chain2 != null && chain2.length > 0 &&
 190:             (chain2[0] instanceof X509Certificate))
 191:           {
 192:             chain = toX509Chain(chain2);
 193:           }
 194:         else
 195:           {
 196:             continue;
 197:           }
 198:         PrivateKey key = null;
 199:         try
 200:           {
 201:             key = (PrivateKey) store.getKey(alias, passwd);
 202:           }
 203:         catch (UnrecoverableKeyException uke)
 204:           {
 205:             exception = uke;
 206:             continue;
 207:           }
 208:         if (key == null)
 209:           {
 210:             continue;
 211:           }
 212:         p.put(alias, key);
 213:         c.put(alias, chain);
 214:       }
 215:     if (p.isEmpty () && c.isEmpty ())
 216:       {
 217:         if (exception != null)
 218:           {
 219:             throw exception;
 220:           }
 221:         throw new KeyStoreException ("no private credentials found");
 222:       }
 223:     current = this.new Manager(p, c);
 224:   }
 225: 
 226:   private static X509Certificate[] toX509Chain(Certificate[] chain)
 227:   {
 228:     if (chain instanceof X509Certificate[])
 229:       {
 230:         return (X509Certificate[]) chain;
 231:       }
 232:     X509Certificate[] _chain = new X509Certificate[chain.length];
 233:     for (int i = 0; i < chain.length; i++)
 234:       _chain[i] = (X509Certificate) chain[i];
 235:     return _chain;
 236:   }
 237: 
 238:   // Inner class.
 239:   // -------------------------------------------------------------------------
 240: 
 241:   private class Manager extends X509ExtendedKeyManager
 242:   {
 243:     // Fields.
 244:     // -----------------------------------------------------------------------
 245: 
 246:     private final Map<String, PrivateKey> privateKeys;
 247:     private final Map<String, X509Certificate[]> certChains;
 248: 
 249:     // Constructor.
 250:     // -----------------------------------------------------------------------
 251: 
 252:     Manager(Map<String, PrivateKey> privateKeys,
 253:             Map<String, X509Certificate[]> certChains)
 254:     {
 255:       this.privateKeys = privateKeys;
 256:       this.certChains = certChains;
 257:     }
 258: 
 259:     // Instance methods.
 260:     // -----------------------------------------------------------------------
 261: 
 262:     public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
 263:                                     Socket socket)
 264:     {
 265:       for (int i = 0; i < keyTypes.length; i++)
 266:         {
 267:           String[] s = getClientAliases(keyTypes[i], issuers);
 268:           if (s.length > 0)
 269:             return s[0];
 270:         }
 271:       return null;
 272:     }
 273: 
 274:     public @Override String chooseEngineClientAlias(String[] keyTypes,
 275:                                                     Principal[] issuers,
 276:                                                     SSLEngine engine)
 277:     {
 278:       for (String type : keyTypes)
 279:         {
 280:           String[] s = getClientAliases(type, issuers);
 281:           if (s.length > 0)
 282:             return s[0];
 283:         }
 284:       return null;
 285:     }
 286: 
 287:     public String[] getClientAliases(String keyType, Principal[] issuers)
 288:     {
 289:       return getAliases(keyType, issuers);
 290:     }
 291: 
 292:     public String chooseServerAlias(String keyType, Principal[] issuers,
 293:                                     Socket socket)
 294:     {
 295:       String[] s = getServerAliases(keyType, issuers);
 296:       if (s.length > 0)
 297:         return s[0];
 298:       return null;
 299:     }
 300: 
 301:     public @Override String chooseEngineServerAlias(String keyType,
 302:                                                     Principal[] issuers,
 303:                                                     SSLEngine engine)
 304:     {
 305:       String[] s = getServerAliases(keyType, issuers);
 306:       if (s.length > 0)
 307:         return s[0];
 308:       return null;
 309:     }
 310: 
 311:     public String[] getServerAliases(String keyType, Principal[] issuers)
 312:     {
 313:       return getAliases(keyType, issuers);
 314:     }
 315: 
 316:     private String[] getAliases(String keyType, Principal[] issuers)
 317:     {
 318:       LinkedList<String> l = new LinkedList<String>();
 319:       for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); )
 320:         {
 321:           String alias = (String) i.next();
 322:           X509Certificate[] chain = getCertificateChain(alias);
 323:           if (chain.length == 0)
 324:             continue;
 325:           PrivateKey privKey = getPrivateKey(alias);
 326:           if (privKey == null)
 327:             continue;
 328:           PublicKey pubKey = chain[0].getPublicKey();
 329:           if (keyType.equalsIgnoreCase("RSA")
 330:               || keyType.equalsIgnoreCase("DHE_RSA")
 331:               || keyType.equalsIgnoreCase("SRP_RSA")
 332:               || keyType.equalsIgnoreCase("rsa_sign")
 333:               || keyType.equalsIgnoreCase("RSA_PSK"))
 334:             {
 335:               if (!(privKey instanceof RSAPrivateKey) ||
 336:                   !(pubKey instanceof RSAPublicKey))
 337:                 continue;
 338:             }
 339:           else if (keyType.equalsIgnoreCase("DHE_DSS")
 340:               || keyType.equalsIgnoreCase("dss_sign")
 341:               || keyType.equalsIgnoreCase("SRP_DSS")
 342:               || keyType.equalsIgnoreCase("DSA"))
 343:             {
 344:               if (!(privKey instanceof DSAPrivateKey) ||
 345:                   !(pubKey instanceof DSAPublicKey))
 346:                 continue;
 347:             }
 348:           else if (keyType.equalsIgnoreCase("DH_RSA")
 349:               || keyType.equalsIgnoreCase("rsa_fixed_dh"))
 350:             {
 351:               if (!(privKey instanceof DHPrivateKey) ||
 352:                   !(pubKey instanceof DHPublicKey))
 353:                 continue;
 354:               if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA"))
 355:                 continue;
 356:             }
 357:           else if (keyType.equalsIgnoreCase("DH_DSS")
 358:               || keyType.equalsIgnoreCase("dss_fixed_dh"))
 359:             {
 360:               if (!(privKey instanceof DHPrivateKey) ||
 361:                   !(pubKey instanceof DHPublicKey))
 362:                 continue;
 363:               if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA"))
 364:                 continue;
 365:             }
 366:           else // Unknown key type; ignore it.
 367:             continue;
 368:           if (issuers == null || issuers.length == 0)
 369:             {
 370:               l.add(alias);
 371:               continue;
 372:             }
 373:           for (Principal issuer : issuers)
 374:             {
 375:               if (chain[0].getIssuerDN().equals(issuer))
 376:                 {
 377:                   l.add(alias);
 378:                   break;
 379:                 }
 380:             }
 381:         }
 382:       return l.toArray(new String[l.size()]);
 383:     }
 384: 
 385:     public X509Certificate[] getCertificateChain(String alias)
 386:     {
 387:       X509Certificate[] c = (X509Certificate[]) certChains.get(alias);
 388:       return c != null ? (X509Certificate[]) c.clone() : null;
 389:     }
 390: 
 391:     public PrivateKey getPrivateKey(String alias)
 392:     {
 393:       return (PrivateKey) privateKeys.get(alias);
 394:     }
 395:   }
 396: }