Source for gnu.javax.crypto.keyring.GnuPrivateKeyring

   1: /* GnuPrivateKeyring.java --
   2:    Copyright (C) 2003, 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.crypto.keyring;
  40: 
  41: import gnu.java.security.Configuration;
  42: import gnu.java.security.Registry;
  43: 
  44: import java.io.DataInputStream;
  45: import java.io.DataOutputStream;
  46: import java.io.IOException;
  47: import java.io.InputStream;
  48: import java.io.OutputStream;
  49: import java.security.Key;
  50: import java.security.PublicKey;
  51: import java.security.UnrecoverableKeyException;
  52: import java.security.cert.Certificate;
  53: import java.util.Date;
  54: import java.util.Iterator;
  55: import java.util.logging.Level;
  56: import java.util.logging.Logger;
  57: 
  58: /**
  59:  *
  60:  */
  61: public class GnuPrivateKeyring
  62:     extends BaseKeyring
  63:     implements IPrivateKeyring
  64: {
  65:   private static final Logger log = Logger.getLogger(GnuPrivateKeyring.class.getName());
  66:   public static final int USAGE = Registry.GKR_PRIVATE_KEYS
  67:                                   | Registry.GKR_PUBLIC_CREDENTIALS;
  68:   protected String mac;
  69:   protected int maclen;
  70:   protected String cipher;
  71:   protected String mode;
  72:   protected int keylen;
  73: 
  74:   public GnuPrivateKeyring(String mac, int maclen, String cipher, String mode,
  75:                            int keylen)
  76:   {
  77:     keyring = new PasswordAuthenticatedEntry(mac, maclen, new Properties());
  78:     keyring2 = new CompressedEntry(new Properties());
  79:     keyring.add(keyring2);
  80:     this.mac = mac;
  81:     this.maclen = maclen;
  82:     this.cipher = cipher;
  83:     this.mode = mode;
  84:     this.keylen = keylen;
  85:   }
  86: 
  87:   public GnuPrivateKeyring()
  88:   {
  89:     this("HMAC-SHA-1", 20, "AES", "OFB", 16);
  90:   }
  91: 
  92:   public boolean containsPrivateKey(String alias)
  93:   {
  94:     if (Configuration.DEBUG)
  95:       log.entering(this.getClass().getName(), "containsPrivateKey", alias);
  96:     boolean result = false;
  97:     if (containsAlias(alias))
  98:       for (Iterator it = get(alias).iterator(); it.hasNext();)
  99:         if (it.next() instanceof PasswordAuthenticatedEntry)
 100:           {
 101:             result = true;
 102:             break;
 103:           }
 104:     if (Configuration.DEBUG)
 105:       log.exiting(this.getClass().getName(), "containsPrivateKey",
 106:                   Boolean.valueOf(result));
 107:     return result;
 108:   }
 109: 
 110:   public Key getPrivateKey(String alias, char[] password)
 111:       throws UnrecoverableKeyException
 112:   {
 113:     if (Configuration.DEBUG)
 114:       log.entering(this.getClass().getName(), "getPrivateKey", alias);
 115:     Key result = null;
 116:     if (containsAlias(alias))
 117:       {
 118:         PasswordAuthenticatedEntry e1 = null;
 119:         for (Iterator it = get(alias).iterator(); it.hasNext();)
 120:           {
 121:             Entry e = (Entry) it.next();
 122:             if (Configuration.DEBUG)
 123:               log.finest("Entry: " + e);
 124:             if (e instanceof PasswordAuthenticatedEntry)
 125:               {
 126:                 e1 = (PasswordAuthenticatedEntry) e;
 127:                 break;
 128:               }
 129:           }
 130:         if (Configuration.DEBUG)
 131:           log.fine("e1 = " + e1);
 132:         if (e1 != null)
 133:           {
 134:             try
 135:               {
 136:                 e1.verify(password);
 137:               }
 138:             catch (Exception e)
 139:               {
 140:                 if (Configuration.DEBUG)
 141:                   log.throwing(this.getClass().getName(), "getPrivateKey", e);
 142:                 throw new UnrecoverableKeyException("authentication failed");
 143:               }
 144:             PasswordEncryptedEntry e2 = null;
 145:             for (Iterator it = e1.getEntries().iterator(); it.hasNext();)
 146:               {
 147:                 Entry e = (Entry) it.next();
 148:                 if (e instanceof PasswordEncryptedEntry)
 149:                   {
 150:                     e2 = (PasswordEncryptedEntry) e;
 151:                     break;
 152:                   }
 153:               }
 154:             if (e2 != null)
 155:               {
 156:                 try
 157:                   {
 158:                     e2.decrypt(password);
 159:                   }
 160:                 catch (Exception e)
 161:                   {
 162:                     log.throwing(this.getClass().getName(), "getPrivateKey", e);
 163:                     throw new UnrecoverableKeyException("decryption failed");
 164:                   }
 165:                 for (Iterator it = e2.get(alias).iterator(); it.hasNext();)
 166:                   {
 167:                     Entry e = (Entry) it.next();
 168:                     if (e instanceof PrivateKeyEntry)
 169:                       {
 170:                         result = ((PrivateKeyEntry) e).getKey();
 171:                         break;
 172:                       }
 173:                   }
 174:               }
 175:           }
 176:       }
 177:     if (Configuration.DEBUG)
 178:       log.exiting(this.getClass().getName(), "getPrivateKey",
 179:                   result == null ? "null" : result.getClass().getName());
 180:     return result;
 181:   }
 182: 
 183:   public void putPrivateKey(String alias, Key key, char[] password)
 184:   {
 185:     if (Configuration.DEBUG)
 186:       log.entering(this.getClass().getName(), "putPrivateKey",
 187:                    new Object[] { alias, key.getClass().getName() });
 188:     if (! containsPrivateKey(alias))
 189:       {
 190:         alias = fixAlias(alias);
 191:         Properties p = new Properties();
 192:         p.put("alias", alias);
 193:         PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p);
 194:         if (Configuration.DEBUG)
 195:           log.fine("About to encrypt the key...");
 196:         PasswordEncryptedEntry enc;
 197:         enc = new PasswordEncryptedEntry(cipher, mode, keylen, new Properties());
 198:         enc.add(pke);
 199:         try
 200:           {
 201:             enc.encode(null, password);
 202:           }
 203:         catch (IOException x)
 204:           {
 205:             if (Configuration.DEBUG)
 206:               log.log(Level.FINE, "Exception while encrypting the key. "
 207:                                   + "Rethrow as IllegalArgumentException", x);
 208:             throw new IllegalArgumentException(x.toString());
 209:           }
 210:         if (Configuration.DEBUG)
 211:           log.fine("About to authenticate the encrypted key...");
 212:         PasswordAuthenticatedEntry auth;
 213:         auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties());
 214:         auth.add(enc);
 215:         try
 216:           {
 217:             auth.encode(null, password);
 218:           }
 219:         catch (IOException x)
 220:           {
 221:             if (Configuration.DEBUG)
 222:               log.log(Level.FINE, "Exception while authenticating the encrypted "
 223:                                   + "key. Rethrow as IllegalArgumentException", x);
 224:             throw new IllegalArgumentException(x.toString());
 225:           }
 226:         keyring.add(auth);
 227:       }
 228:     else if (Configuration.DEBUG)
 229:       log.fine("Keyring already contains alias: " + alias);
 230:     if (Configuration.DEBUG)
 231:       log.exiting(this.getClass().getName(), "putPrivateKey");
 232:   }
 233: 
 234:   public boolean containsPublicKey(String alias)
 235:   {
 236:     if (Configuration.DEBUG)
 237:       log.entering(this.getClass().getName(), "containsPublicKey", alias);
 238:     boolean result = false;
 239:     if (containsAlias(alias))
 240:       for (Iterator it = get(alias).iterator(); it.hasNext();)
 241:         if (it.next() instanceof PublicKeyEntry)
 242:           {
 243:             result = true;
 244:             break;
 245:           }
 246:     if (Configuration.DEBUG)
 247:       log.exiting(this.getClass().getName(), "containsPublicKey",
 248:                   Boolean.valueOf(result));
 249:     return result;
 250:   }
 251: 
 252:   public PublicKey getPublicKey(String alias)
 253:   {
 254:     if (Configuration.DEBUG)
 255:       log.entering(this.getClass().getName(), "getPublicKey", alias);
 256:     PublicKey result = null;
 257:     if (containsAlias(alias))
 258:       for (Iterator it = get(alias).iterator(); it.hasNext();)
 259:         {
 260:           Entry e = (Entry) it.next();
 261:           if (e instanceof PublicKeyEntry)
 262:             {
 263:               result = ((PublicKeyEntry) e).getKey();
 264:               break;
 265:             }
 266:         }
 267:     if (Configuration.DEBUG)
 268:       log.exiting(this.getClass().getName(), "getPublicKey",
 269:                   result == null ? "null" : result.getClass().getName());
 270:     return result;
 271:   }
 272: 
 273:   public void putPublicKey(String alias, PublicKey key)
 274:   {
 275:     if (Configuration.DEBUG)
 276:       log.entering(this.getClass().getName(), "putPublicKey",
 277:                    new Object[] { alias, key.getClass().getName() });
 278:     if (! containsPublicKey(alias))
 279:       {
 280:         Properties p = new Properties();
 281:         p.put("alias", fixAlias(alias));
 282:         add(new PublicKeyEntry(key, new Date(), p));
 283:       }
 284:     else if (Configuration.DEBUG)
 285:       log.fine("Keyring already contains alias: " + alias);
 286:     if (Configuration.DEBUG)
 287:       log.exiting(this.getClass().getName(), "putPublicKey");
 288:   }
 289: 
 290:   public boolean containsCertPath(String alias)
 291:   {
 292:     if (Configuration.DEBUG)
 293:       log.entering(this.getClass().getName(), "containsCertPath", alias);
 294:     boolean result = false;
 295:     if (containsAlias(alias))
 296:       for (Iterator it = get(alias).iterator(); it.hasNext();)
 297:         if (it.next() instanceof CertPathEntry)
 298:           {
 299:             result = true;
 300:             break;
 301:           }
 302:     if (Configuration.DEBUG)
 303:       log.exiting(this.getClass().getName(), "containsCertPath",
 304:                   Boolean.valueOf(result));
 305:     return result;
 306:   }
 307: 
 308:   public Certificate[] getCertPath(String alias)
 309:   {
 310:     if (Configuration.DEBUG)
 311:       log.entering(this.getClass().getName(), "getCertPath", alias);
 312:     Certificate[] result = null;
 313:     if (containsAlias(alias))
 314:       for (Iterator it = get(alias).iterator(); it.hasNext();)
 315:         {
 316:           Entry e = (Entry) it.next();
 317:           if (e instanceof CertPathEntry)
 318:             {
 319:               result = ((CertPathEntry) e).getCertPath();
 320:               break;
 321:             }
 322:         }
 323:     if (Configuration.DEBUG)
 324:       log.exiting(this.getClass().getName(), "getCertPath", result);
 325:     return result;
 326:   }
 327: 
 328:   public void putCertPath(String alias, Certificate[] path)
 329:   {
 330:     if (Configuration.DEBUG)
 331:       log.entering(this.getClass().getName(), "putCertPath",
 332:                    new Object[] { alias, path });
 333:     if (! containsCertPath(alias))
 334:       {
 335:         Properties p = new Properties();
 336:         p.put("alias", fixAlias(alias));
 337:         add(new CertPathEntry(path, new Date(), p));
 338:       }
 339:     else if (Configuration.DEBUG)
 340:       log.fine("Keyring already contains alias: " + alias);
 341:     if (Configuration.DEBUG)
 342:       log.exiting(this.getClass().getName(), "putCertPath");
 343:   }
 344: 
 345:   protected void load(InputStream in, char[] password) throws IOException
 346:   {
 347:     if (Configuration.DEBUG)
 348:       log.entering(this.getClass().getName(), "load");
 349:     if (in.read() != USAGE)
 350:       throw new MalformedKeyringException("incompatible keyring usage");
 351:     if (in.read() != PasswordAuthenticatedEntry.TYPE)
 352:       throw new MalformedKeyringException(
 353:           "expecting password-authenticated entry tag");
 354:     keyring = PasswordAuthenticatedEntry.decode(new DataInputStream(in), password);
 355:     if (Configuration.DEBUG)
 356:       log.exiting(this.getClass().getName(), "load");
 357:   }
 358: 
 359:   protected void store(OutputStream out, char[] password) throws IOException
 360:   {
 361:     if (Configuration.DEBUG)
 362:       log.entering(this.getClass().getName(), "store");
 363:     out.write(USAGE);
 364:     keyring.encode(new DataOutputStream(out), password);
 365:     if (Configuration.DEBUG)
 366:       log.exiting(this.getClass().getName(), "store");
 367:   }
 368: }