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.Security;
  58: import java.security.UnrecoverableKeyException;
  59: import java.security.cert.Certificate;
  60: import java.security.cert.CertificateException;
  61: import java.security.cert.X509Certificate;
  62: import java.security.interfaces.DSAPrivateKey;
  63: import java.security.interfaces.DSAPublicKey;
  64: import java.security.interfaces.RSAPrivateKey;
  65: import java.security.interfaces.RSAPublicKey;
  66: 
  67: import java.util.Collections;
  68: import java.util.HashMap;
  69: import java.util.Iterator;
  70: import java.util.Map;
  71: import java.util.List;
  72: 
  73: import javax.crypto.interfaces.DHPrivateKey;
  74: import javax.crypto.interfaces.DHPublicKey;
  75: 
  76: import javax.net.ssl.KeyManager;
  77: import javax.net.ssl.KeyManagerFactorySpi;
  78: import javax.net.ssl.ManagerFactoryParameters;
  79: import javax.net.ssl.X509KeyManager;
  80: 
  81: import gnu.javax.net.ssl.NullManagerParameters;
  82: import gnu.javax.net.ssl.PrivateCredentials;
  83: 
  84: /**
  85:  * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine
  86:  * for the ``JessieX509'' algorithm.
  87:  */
  88: public class X509KeyManagerFactory extends KeyManagerFactorySpi
  89: {
  90: 
  91:   // Fields.
  92:   // -------------------------------------------------------------------------
  93: 
  94:   private Manager current;
  95: 
  96:   // Constructor.
  97:   // -------------------------------------------------------------------------
  98: 
  99:   public X509KeyManagerFactory()
 100:   {
 101:     super();
 102:   }
 103: 
 104:   // Instance methods.
 105:   // -------------------------------------------------------------------------
 106: 
 107:   protected KeyManager[] engineGetKeyManagers()
 108:   {
 109:     if (current == null)
 110:       {
 111:         throw new IllegalStateException();
 112:       }
 113:     return new KeyManager[] { current };
 114:   }
 115: 
 116:   protected void engineInit(ManagerFactoryParameters params)
 117:     throws InvalidAlgorithmParameterException
 118:   {
 119:     if (params instanceof NullManagerParameters)
 120:       {
 121:         current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
 122:       }
 123:     else if (params instanceof PrivateCredentials)
 124:       {
 125:         List chains = ((PrivateCredentials) params).getCertChains();
 126:         List keys = ((PrivateCredentials) params).getPrivateKeys();
 127:         int i = 0;
 128:         HashMap certMap = new HashMap();
 129:         HashMap keyMap = new HashMap();
 130:         Iterator c = chains.iterator();
 131:         Iterator k = keys.iterator();
 132:         while (c.hasNext() && k.hasNext())
 133:           {
 134:             certMap.put(String.valueOf(i), c.next());
 135:             keyMap.put(String.valueOf(i), k.next());
 136:             i++;
 137:           }
 138:         current = new Manager(keyMap, certMap);
 139:       }
 140:     else
 141:       {
 142:         throw new InvalidAlgorithmParameterException();
 143:       }
 144:   }
 145: 
 146:   protected void engineInit(KeyStore store, char[] passwd)
 147:     throws KeyStoreException, NoSuchAlgorithmException,
 148:            UnrecoverableKeyException
 149:   {
 150:     if (store == null)
 151:       {
 152:         String s = Util.getProperty("javax.net.ssl.keyStoreType");
 153:         if (s == null)
 154:           s = KeyStore.getDefaultType();
 155:         store = KeyStore.getInstance(s);
 156:         s = Util.getProperty("javax.net.ssl.keyStore");
 157:         if (s == null)
 158:           return;
 159:         String p = Util.getProperty("javax.net.ssl.keyStorePassword");
 160:         try
 161:           {
 162:             store.load(new FileInputStream(s), p != null ? p.toCharArray() : null);
 163:           }
 164:         catch (IOException ioe)
 165:           {
 166:             throw new KeyStoreException(ioe.toString());
 167:           }
 168:         catch (CertificateException ce)
 169:           {
 170:             throw new KeyStoreException(ce.toString());
 171:           }
 172:       }
 173: 
 174:     HashMap p = new HashMap();
 175:     HashMap c = new HashMap();
 176:     Enumeration aliases = store.aliases();
 177:     UnrecoverableKeyException exception = null;
 178:     while (aliases.hasMoreElements())
 179:       {
 180:         String alias = (String) aliases.nextElement();
 181:         if (!store.isKeyEntry(alias))
 182:           {
 183:             continue;
 184:           }
 185:         X509Certificate[] chain = null;
 186:         Certificate[] chain2 = store.getCertificateChain (alias);
 187:         if (chain2 != null && chain2.length > 0 &&
 188:             (chain2[0] instanceof X509Certificate))
 189:           {
 190:             chain = toX509Chain(chain2);
 191:           }
 192:         else
 193:           {
 194:             continue;
 195:           }
 196:         PrivateKey key = null;
 197:         try
 198:           {
 199:             key = (PrivateKey) store.getKey(alias, passwd);
 200:           }
 201:         catch (UnrecoverableKeyException uke)
 202:           {
 203:             exception = uke;
 204:             continue;
 205:           }
 206:         if (key == null)
 207:           {
 208:             continue;
 209:           }
 210:         p.put(alias, key);
 211:         c.put(alias, chain);
 212:       }
 213:     if (p.isEmpty () && c.isEmpty ())
 214:       {
 215:         if (exception != null)
 216:           {
 217:             throw exception;
 218:           }
 219:         throw new KeyStoreException ("no private credentials found");
 220:       }
 221:     current = this.new Manager(p, c);
 222:   }
 223: 
 224:   private static X509Certificate[] toX509Chain(Certificate[] chain)
 225:   {
 226:     if (chain instanceof X509Certificate[])
 227:       {
 228:         return (X509Certificate[]) chain;
 229:       }
 230:     X509Certificate[] _chain = new X509Certificate[chain.length];
 231:     for (int i = 0; i < chain.length; i++)
 232:       _chain[i] = (X509Certificate) chain[i];
 233:     return _chain;
 234:   }
 235: 
 236:   // Inner class.
 237:   // -------------------------------------------------------------------------
 238: 
 239:   private class Manager implements X509KeyManager
 240:   {
 241:     // Fields.
 242:     // -----------------------------------------------------------------------
 243: 
 244:     private final Map privateKeys;
 245:     private final Map certChains;
 246: 
 247:     // Constructor.
 248:     // -----------------------------------------------------------------------
 249: 
 250:     Manager(Map privateKeys, Map certChains)
 251:     {
 252:       this.privateKeys = privateKeys;
 253:       this.certChains = certChains;
 254:     }
 255: 
 256:     // Instance methods.
 257:     // -----------------------------------------------------------------------
 258: 
 259:     public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
 260:                                     Socket socket)
 261:     {
 262:       for (int i = 0; i < keyTypes.length; i++)
 263:         {
 264:           String[] s = getClientAliases(keyTypes[i], issuers);
 265:           if (s.length > 0)
 266:             return s[0];
 267:         }
 268:       return null;
 269:     }
 270: 
 271:     public String[] getClientAliases(String keyType, Principal[] issuers)
 272:     {
 273:       return getAliases(keyType, issuers);
 274:     }
 275: 
 276:     public String chooseServerAlias(String keyType, Principal[] issuers,
 277:                                     Socket socket)
 278:     {
 279:       String[] s = getServerAliases(keyType, issuers);
 280:       if (s.length > 0)
 281:         return s[0];
 282:       return null;
 283:     }
 284: 
 285:     public String[] getServerAliases(String keyType, Principal[] issuers)
 286:     {
 287:       return getAliases(keyType, issuers);
 288:     }
 289: 
 290:     private String[] getAliases(String keyType, Principal[] issuers)
 291:     {
 292:       LinkedList l = new LinkedList();
 293:       for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); )
 294:         {
 295:           String alias = (String) i.next();
 296:           X509Certificate[] chain = getCertificateChain(alias);
 297:           if (chain.length == 0)
 298:             continue;
 299:           PrivateKey privKey = getPrivateKey(alias);
 300:           if (privKey == null)
 301:             continue;
 302:           PublicKey pubKey = chain[0].getPublicKey();
 303:           if (keyType.equals("RSA") || keyType.equals("DHE_RSA") ||
 304:               keyType.equals("SRP_RSA") || keyType.equals("rsa_sign"))
 305:             {
 306:               if (!(privKey instanceof RSAPrivateKey) ||
 307:                   !(pubKey instanceof RSAPublicKey))
 308:                 continue;
 309:             }
 310:           if (keyType.equals("DHE_DSS") || keyType.equals("dss_sign") ||
 311:               keyType.equals("SRP_DSS"))
 312:             {
 313:               if (!(privKey instanceof DSAPrivateKey) ||
 314:                   !(pubKey instanceof DSAPublicKey))
 315:                 continue;
 316:             }
 317:           if (keyType.equals("DH_RSA") || keyType.equals("rsa_fixed_dh"))
 318:             {
 319:               if (!(privKey instanceof DHPrivateKey) ||
 320:                   !(pubKey instanceof DHPublicKey))
 321:                 continue;
 322:               if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA"))
 323:                 continue;
 324:             }
 325:           if (keyType.equals("DH_DSS") || keyType.equals("dss_fixed_dh"))
 326:             {
 327:               if (!(privKey instanceof DHPrivateKey) ||
 328:                   !(pubKey instanceof DHPublicKey))
 329:                 continue;
 330:               if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA"))
 331:                 continue;
 332:             }
 333:           if (issuers == null || issuers.length == 0)
 334:             {
 335:               l.add(alias);
 336:               continue;
 337:             }
 338:           for (int j = 0; j < issuers.length; j++)
 339:             if (chain[0].getIssuerDN().equals(issuers[j]))
 340:               {
 341:                 l.add(alias);
 342:                 break;
 343:               }
 344:         }
 345:       return (String[]) l.toArray(new String[l.size()]);
 346:     }
 347: 
 348:     public X509Certificate[] getCertificateChain(String alias)
 349:     {
 350:       X509Certificate[] c = (X509Certificate[]) certChains.get(alias);
 351:       return c != null ? (X509Certificate[]) c.clone() : null;
 352:     }
 353: 
 354:     public PrivateKey getPrivateKey(String alias)
 355:     {
 356:       return (PrivateKey) privateKeys.get(alias);
 357:     }
 358:   }
 359: }