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