View Javadoc
1 /* 2 * $Id: JCESigner.java,v 1.28 2004/07/21 23:07:16 pelle Exp $ 3 * $Log: JCESigner.java,v $ 4 * Revision 1.28 2004/07/21 23:07:16 pelle 5 * Updated the Signer interface with a new generateKey() method, which doesn't take any parameters. 6 * It stores the generated key using the Base32 encoded SHA1 digest as it's alias. 7 * 8 * Revision 1.27 2004/05/16 00:04:00 pelle 9 * Added SigningServer which encapsulates all the web serving functionality. 10 * Added IdentityPanel which contains an IdentityTree of Identities. 11 * Added AssetPanel 12 * Save now works and Add Personality as well. 13 * 14 * Revision 1.26 2004/05/14 23:47:02 pelle 15 * Moved PersonalSigner and OpenSignerDialog to neuclear-commons where they belong. 16 * The whole mechanism of opening keystores is pretty smooth right now. 17 * Currently working on saving, which doesnt quite work yet. I have added a save method to OpenSignerDialog, which 18 * should handle it. 19 * 20 * Revision 1.25 2004/04/20 23:32:05 pelle 21 * All unit tests (junit and cactus) work. The AssetControllerServlet is operational. 22 * 23 * Revision 1.24 2004/04/14 00:10:52 pelle 24 * Added a MessageLabel for handling errors, validation and info 25 * Save works well now. 26 * It's pretty much there I think. 27 * 28 * Revision 1.23 2004/04/13 17:32:07 pelle 29 * Now has save dialog 30 * Remembers passphrases 31 * 32 * Revision 1.22 2004/04/12 23:50:08 pelle 33 * implemented the queue and improved the DefaultSigner 34 * 35 * Revision 1.21 2004/04/09 22:56:45 pelle 36 * SwingAgent now manages key creation as well through the NewAliasDialog. 37 * Many small uservalidation features have also been added. 38 * 39 * Revision 1.20 2004/04/09 18:40:45 pelle 40 * BrowsableSigner now inherits Signer and PublicKeySource, which means implementations only need to implement BrowsableSigner now. 41 * Added NewAliasDialog, which isnt yet complete. 42 * 43 * Revision 1.19 2004/04/07 17:22:10 pelle 44 * Added support for the new improved interactive signing model. A new Agent is also available with SwingAgent. 45 * The XMLSig classes have also been updated to support this. 46 * 47 * Revision 1.18 2004/03/22 20:09:05 pelle 48 * Added simple ledger for unit testing and in memory use 49 * 50 * Revision 1.17 2004/01/20 17:38:58 pelle 51 * Further updates to unit tests 52 * 53 * Revision 1.16 2004/01/19 17:53:14 pelle 54 * Various clean ups 55 * 56 * Revision 1.15 2003/12/22 22:14:37 pelle 57 * Last minute cleanups and documentation prior to release 0.8.1 58 * 59 * Revision 1.14 2003/12/19 18:02:53 pelle 60 * Revamped a lot of exception handling throughout the framework, it has been simplified in most places: 61 * - For most cases the main exception to worry about now is InvalidNamedObjectException. 62 * - Most lowerlevel exception that cant be handled meaningful are now wrapped in the LowLevelException, a 63 * runtime exception. 64 * - Source and Store patterns each now have their own exceptions that generalizes the various physical 65 * exceptions that can happen in that area. 66 * 67 * Revision 1.13 2003/12/19 00:31:15 pelle 68 * Lots of usability changes through out all the passphrase agents and end user tools. 69 * 70 * Revision 1.12 2003/12/18 17:40:07 pelle 71 * You can now create keys that get stored with a X509 certificate in the keystore. These can be saved as well. 72 * IdentityCreator has been modified to allow creation of keys. 73 * Note The actual Creation of Certificates still have a problem that will be resolved later today. 74 * 75 * Revision 1.11 2003/12/16 21:09:22 pelle 76 * The Sample Web App is semi stable for now. 77 * 78 * Revision 1.10 2003/12/14 20:52:54 pelle 79 * Added ServletPassPhraseAgent which uses ThreadLocal to transfer the passphrase to the signer. 80 * Added ServletSignerFactory, which builds Signers for use within servlets based on parameters in the Servlets 81 * Init parameters in web.xml 82 * Updated SQLContext to use ThreadLocal 83 * Added jakarta cactus unit tests to neuclear-commons to test the 2 new features above. 84 * Added use of the new features in neuclear-commons to the servilets within neuclear-id and added 85 * configuration parameters in web.xml 86 * 87 * Revision 1.9 2003/12/10 23:55:45 pelle 88 * Did some cleaning up in the builders 89 * Fixed some stuff in IdentityCreator 90 * New maven goal to create executable jarapp 91 * We are close to 0.8 final of ID, 0.11 final of XMLSIG and 0.5 of commons. 92 * Will release shortly. 93 * 94 * Revision 1.8 2003/11/22 00:22:52 pelle 95 * All unit tests in commons, id and xmlsec now work. 96 * AssetController now successfully processes payments in the unit test. 97 * Payment Web App has working form that creates a TransferRequest presents it to the signer 98 * and forwards it to AssetControlServlet. (Which throws an XML Parser Exception) I think the XMLReaderServlet is bust. 99 * 100 * Revision 1.7 2003/11/21 04:43:41 pelle 101 * EncryptedFileStore now works. It uses the PBECipher with DES3 afair. 102 * Otherwise You will Finaliate. 103 * Anything that can be final has been made final throughout everyting. We've used IDEA's Inspector tool to find all instance of variables that could be final. 104 * This should hopefully make everything more stable (and secure). 105 * 106 * Revision 1.6 2003/11/19 23:32:50 pelle 107 * Signers now can generatekeys via the generateKey() method. 108 * Refactored the relationship between SignedNamedObject and NamedObjectBuilder a bit. 109 * SignedNamedObject now contains the full xml which is returned with getEncoded() 110 * This means that it is now possible to further receive on or process a SignedNamedObject, leaving 111 * NamedObjectBuilder for its original purposes of purely generating new Contracts. 112 * NamedObjectBuilder.sign() now returns a SignedNamedObject which is the prefered way of processing it. 113 * Updated all major interfaces that used the old model to use the new model. 114 * 115 * Revision 1.5 2003/11/18 15:07:18 pelle 116 * Changes to JCE Implementation 117 * Working on getting all tests working including store tests 118 * 119 * Revision 1.4 2003/11/18 00:01:02 pelle 120 * The simple signing web application for logging in and out is now working. 121 * There had been an issue in the canonicalizer when dealing with the embedded object of the SignatureRequest object. 122 * 123 * Revision 1.3 2003/11/13 23:26:17 pelle 124 * The signing service and web authentication application is now almost working. 125 * 126 * Revision 1.2 2003/11/12 23:47:50 pelle 127 * Much work done in creating good test environment. 128 * PaymentReceiverTest works, but needs a abit more work in its environment to succeed testing. 129 * 130 * Revision 1.1 2003/11/11 21:17:47 pelle 131 * Further vital reshuffling. 132 * org.neudist.crypto.* and org.neudist.utils.* have been moved to respective areas under org.neuclear.commons 133 * org.neuclear.signers.* as well as org.neuclear.passphraseagents have been moved under org.neuclear.commons.crypto as well. 134 * Did a bit of work on the Canonicalizer and changed a few other minor bits. 135 * 136 * Revision 1.3 2003/11/08 20:27:06 pelle 137 * Updated the Signer interface to return a key type to be used for XML SignatureInfo. Thus we now support DSA sigs yet again. 138 * 139 * Revision 1.2 2003/10/29 23:17:53 pelle 140 * Updated some javadocs 141 * Added a neuclear specific maven repository at: 142 * http://neuclear.org/maven/ and updated the properties files to reflect that. 143 * 144 * Revision 1.1 2003/10/29 21:16:28 pelle 145 * Refactored the whole signing process. Now we have an interface called Signer which is the old SignerStore. 146 * To use it you pass a byte array and an alias. The sign method then returns the signature. 147 * If a Signer needs a passphrase it uses a PassPhraseAgent to present a dialogue box, read it from a command line etc. 148 * This new Signer pattern allows us to use secure signing hardware such as N-Cipher in the future for server applications as well 149 * as SmartCards for end user applications. 150 * 151 * Revision 1.4 2003/10/28 23:44:03 pelle 152 * The GuiDialogAgent now works. It simply presents itself as a simple modal dialog box asking for a passphrase. 153 * The two Signer implementations both use it for the passphrase. 154 * 155 * Revision 1.3 2003/10/21 22:29:59 pelle 156 * Renamed NeudistException to NeuClearException and moved it to org.neuclear.commons where it makes more sense. 157 * Unhooked the XMLException in the xmlsig library from NeuClearException to make all of its exceptions an independent hierarchy. 158 * Obviously had to perform many changes throughout the code to support these changes. 159 * 160 * Revision 1.2 2003/02/20 13:26:41 pelle 161 * Adding all of the modification from Rams?s Morales ramses@computer.org to support DSASHA1 Signatures 162 * Thanks Rams?s good work. 163 * So this means there is now support for: 164 * - DSA KeyInfo blocks 165 * - DSA Key Generation within CryptoTools 166 * - Signing using DSASHA1 167 * 168 * Revision 1.1 2003/02/18 00:03:32 pelle 169 * Moved the Signer classes from neuclearframework into neuclear-xmlsig 170 * 171 * Revision 1.2 2003/02/09 00:15:55 pelle 172 * Fixed things so they now compile with r_0.7 of XMLSig 173 * 174 * Revision 1.1 2002/10/06 00:39:26 pelle 175 * I have now expanded support for different types of Signers. 176 * There is now a JCESigner which uses a JCE KeyStore for signing. 177 * I have refactored the SigningServlet a bit, eliminating most of the demo code. 178 * This has been moved into DemoSigningServlet. 179 * I have expanded the CommandLineSigner, so it now also has an option for specifying a default signing service. 180 * The default web application now contains two signers. 181 * - The Demo one is still at /Signer 182 * - There is a new one at /personal/Signer this uses the testkeys.ks for 183 * signing anything under neu://test 184 * Note neu://test now has a default interactive signer running on localhost. 185 * So to play with this you must install the webapp on your own local machine. 186 * 187 * Revision 1.2 2002/09/23 15:09:11 pelle 188 * Got the SimpleSigner working properly. 189 * I couldn't get SealedObjects working with BouncyCastle's Symmetric keys. 190 * Don't know what I was doing, so I reimplemented it. Encrypting 191 * and decrypting it my self. 192 * 193 * Revision 1.1 2002/09/21 23:11:16 pelle 194 * A bunch of clean ups. Got rid of as many hard coded URL's as I could. 195 * 196 * User: pelleb 197 * Date: Sep 20, 2002 198 * Time: 12:37:32 PM 199 */ 200 package org.neuclear.commons.crypto.signers; 201 202 import org.neuclear.commons.LowLevelException; 203 import org.neuclear.commons.Utility; 204 import org.neuclear.commons.crypto.CryptoException; 205 import org.neuclear.commons.crypto.CryptoTools; 206 import org.neuclear.commons.crypto.passphraseagents.AlwaysTheSamePassphraseAgent; 207 import org.neuclear.commons.crypto.passphraseagents.InteractiveAgent; 208 import org.neuclear.commons.crypto.passphraseagents.PassPhraseAgent; 209 import org.neuclear.commons.crypto.passphraseagents.UserCancellationException; 210 211 import java.io.*; 212 import java.security.*; 213 import java.security.cert.Certificate; 214 import java.security.cert.CertificateException; 215 import java.security.interfaces.DSAPublicKey; 216 import java.security.interfaces.RSAPublicKey; 217 import java.util.Enumeration; 218 import java.util.Iterator; 219 220 /*** 221 * Wrapper around JCE KeyStore 222 */ 223 public class JCESigner implements BrowsableSigner { 224 225 /*** 226 * Constructs a JCESigner with the agent providing the keystore passphrase. 227 * 228 * @param filename 229 * @param type 230 * @param provider 231 * @param agent 232 * @throws InvalidPassphraseException If the given passphrase is incorrect 233 * @throws UserCancellationException If the user choses to cancel the process in the passphrase agent, this should cancel the loading process 234 */ 235 public JCESigner(final String filename, final String type, final String provider, final PassPhraseAgent agent) throws UserCancellationException, InvalidPassphraseException { 236 this(filename, createInputStream(filename), type, provider, agent); 237 this.filename = filename; 238 } 239 240 /*** 241 * Constructs a JCESigner providing a initial passphrase in the parameters. 242 * 243 * @param filename 244 * @param type 245 * @param provider 246 * @param agent 247 * @param initialpassphrase 248 * @throws InvalidPassphraseException If the given passphrase is incorrect 249 */ 250 public JCESigner(final String filename, final String type, final String provider, final PassPhraseAgent agent, final char[] initialpassphrase) throws InvalidPassphraseException { 251 this(filename, createInputStream(filename), type, provider, agent, initialpassphrase); 252 this.filename = filename; 253 254 } 255 256 /*** 257 * The purpose of this method is to either return an InputStream or Null. The reason being that the Keystore accepts null 258 * to create a new KeyStore in memory. 259 * 260 * @param filename 261 * @return 262 */ 263 private static InputStream createInputStream(final String filename) { 264 if (Utility.isEmpty(filename)) 265 return null; 266 final File file = new File(filename); 267 if (!file.exists()) 268 return null; 269 try { 270 return new FileInputStream(file); 271 } catch (FileNotFoundException e) { 272 System.err.println(e.getLocalizedMessage()); 273 throw new LowLevelException(e); 274 } 275 } 276 277 /*** 278 * Constructs a JCESigner using the agent to provide the initial passphrase 279 * 280 * @param name 281 * @param in 282 * @param type 283 * @param provider 284 * @param agent 285 * @throws InvalidPassphraseException If the given passphrase is incorrect 286 * @throws UserCancellationException If the user choses to cancel the process in the passphrase agent, this should cancel the loading process 287 */ 288 protected JCESigner(final String name, final InputStream in, final String type, final String provider, final PassPhraseAgent agent) throws UserCancellationException, InvalidPassphraseException { 289 this(loadKeyStore(provider, type, in, agent, name), agent); 290 } 291 292 /*** 293 * Constructs a JCESigner using the provided Initial passphrase to load the keystore 294 * 295 * @param name 296 * @param in 297 * @param type 298 * @param provider 299 * @param agent 300 * @param initpassphrase 301 * @throws InvalidPassphraseException If the given passphrase is incorrect 302 */ 303 protected JCESigner(final String name, final InputStream in, final String type, final String provider, final PassPhraseAgent agent, final char[] initpassphrase) throws InvalidPassphraseException { 304 this(loadKeyStore(provider, type, in, initpassphrase), agent); 305 } 306 307 private static KeyStore loadKeyStore(final String provider, final String type, final InputStream in, final char[] passphrase) throws InvalidPassphraseException { 308 try { 309 return loadKeyStore(provider, type, in, new AlwaysTheSamePassphraseAgent(passphrase), "keystore"); 310 } catch (UserCancellationException e) { 311 throw new LowLevelException(e); 312 } 313 } 314 315 private static KeyStore loadKeyStore(final String provider, final String type, final InputStream in, final PassPhraseAgent agent, final String name) throws InvalidPassphraseException, UserCancellationException { 316 // System.out.println("Loading JCESigner using passphrase: "+new String(passphrase)); 317 try { 318 KeyStore ki = null; 319 if (provider == null) 320 ki = KeyStore.getInstance(type); 321 else 322 ki = KeyStore.getInstance(type, provider); 323 if (in != null) 324 ki.load(in, agent.getPassPhrase("Keystore password for: " + name)); 325 else 326 ki.load(null, null); 327 return ki; 328 } catch (KeyStoreException e) { 329 throw new LowLevelException(e); 330 } catch (NoSuchProviderException e) { 331 throw new LowLevelException(e); 332 } catch (IOException e) { 333 System.err.println("Incorrect Passphrase"); 334 throw new InvalidPassphraseException("entered passphrase was invalid"); 335 } catch (NoSuchAlgorithmException e) { 336 throw new LowLevelException(e); 337 } catch (CertificateException e) { 338 throw new LowLevelException(e); 339 } 340 } 341 342 /*** 343 * Creates a signer based on a fully loaded keystore 344 * 345 * @param ks 346 * @param agent 347 */ 348 public JCESigner(final KeyStore ks, final PassPhraseAgent agent) { 349 this.agent = agent; 350 this.ks = ks; 351 cache = new KeyCache(ks); 352 try { 353 kpg = KeyPairGenerator.getInstance("RSA"); 354 kpg.initialize(1024, SecureRandom.getInstance("SHA1PRNG")); 355 } catch (NoSuchAlgorithmException e) { 356 throw new LowLevelException(e); 357 } 358 359 } 360 361 private PrivateKey getKey(final String name, final char[] passphrase) throws UnrecoverableKeyException, NonExistingSignerException, NoSuchAlgorithmException, KeyStoreException { 362 try { 363 final PrivateKey key = (PrivateKey) cache.getKey(name, passphrase); 364 if (key == null) 365 throw new NonExistingSignerException("No keys for: " + name); 366 return key; 367 } catch (ClassCastException e) { 368 throw new NonExistingSignerException("Incorrect Key type found"); 369 } 370 371 } 372 373 public final byte[] sign(final String name, final byte[] data) throws NonExistingSignerException, UserCancellationException { 374 return sign(name, data, false); 375 } 376 377 public final byte[] sign(final String name, final byte[] data, boolean incorrect) throws UserCancellationException, NonExistingSignerException { 378 try { 379 final char[] pass = getPassPhrase(name, incorrect); 380 return CryptoTools.sign(getKey(name, pass), data); 381 } catch (UnrecoverableKeyException e) { 382 System.err.println("Incorrect Passphrase Attemt on: " + name); 383 return sign(name, data, true); 384 } catch (NoSuchAlgorithmException e) { 385 throw new LowLevelException(e); 386 } catch (KeyStoreException e) { 387 // Could try to reload it here but I wont for now 388 throw new LowLevelException(e); 389 } catch (CryptoException e) { 390 throw new LowLevelException(e); 391 } 392 } 393 394 private char[] getPassPhrase(final String name, boolean incorrect) throws UserCancellationException { 395 if (incorrect && (agent instanceof InteractiveAgent)) 396 ((InteractiveAgent) agent).getPassPhrase(name, true); 397 return agent.getPassPhrase(name); 398 } 399 400 public final boolean canSignFor(final String name) { 401 try { 402 return ks.containsAlias(name); 403 } catch (KeyStoreException e) { 404 throw new LowLevelException(e); 405 } 406 } 407 408 public final int getKeyType(final String name) { 409 try { 410 if (ks.isKeyEntry(name)) { 411 final PublicKey pk = getPublicKey(name); 412 if (pk instanceof RSAPublicKey) 413 return KEY_RSA; 414 if (pk instanceof DSAPublicKey) 415 return KEY_DSA; 416 return KEY_OTHER; 417 } 418 } catch (KeyStoreException e) { 419 throw new LowLevelException(e); 420 } catch (NonExistingSignerException e) { 421 return KEY_NONE; 422 } 423 return KEY_NONE; //To change body of implemented methods use Options | File Templates. 424 } 425 426 427 public final PublicKey generateKey(final String alias) throws UserCancellationException { 428 try { 429 final KeyPair kp = kpg.generateKeyPair(); 430 ks.setKeyEntry(alias, kp.getPrivate(), agent.getPassPhrase(alias), new Certificate[]{CryptoTools.createCertificate(alias, kp)}); 431 return kp.getPublic(); 432 } catch (KeyStoreException e) { 433 throw new LowLevelException(e); 434 } catch (SignatureException e) { 435 throw new LowLevelException(e); 436 } catch (InvalidKeyException e) { 437 throw new LowLevelException(e); 438 } 439 } 440 441 public PublicKey generateKey() throws UserCancellationException { 442 try { 443 final KeyPair kp = kpg.generateKeyPair(); 444 String alias = CryptoTools.encodeBase32(CryptoTools.digest(kp.getPublic().getEncoded())); 445 ks.setKeyEntry(alias, kp.getPrivate(), agent.getPassPhrase(alias), new Certificate[]{CryptoTools.createCertificate(alias, kp)}); 446 return kp.getPublic(); 447 } catch (KeyStoreException e) { 448 throw new LowLevelException(e); 449 } catch (SignatureException e) { 450 throw new LowLevelException(e); 451 } catch (InvalidKeyException e) { 452 throw new LowLevelException(e); 453 } 454 } 455 456 public final PublicKey getPublicKey(final String name) throws NonExistingSignerException { 457 try { 458 final Certificate certificate = ks.getCertificate(name); 459 if (certificate == null) 460 throw new NonExistingSignerException(name); 461 462 PublicKey pub = certificate.getPublicKey(); 463 if (pub == null) 464 throw new NonExistingSignerException(name); 465 return pub; 466 467 } catch (KeyStoreException e) { 468 throw new LowLevelException(e); 469 } 470 } 471 472 public byte[] sign(byte data[], SetPublicKeyCallBack callback) throws UserCancellationException { 473 return ((InteractiveAgent) agent).sign(this, data, callback); 474 } 475 476 public byte[] sign(String name, char pass[], byte data[], SetPublicKeyCallBack callback) throws InvalidPassphraseException { 477 try { 478 final byte[] bytes = CryptoTools.sign(getKey(name, pass), data); 479 if (callback != null) 480 callback.setPublicKey(getPublicKey(name)); 481 return bytes; 482 } catch (UnrecoverableKeyException e) { 483 throw new InvalidPassphraseException(name); 484 } catch (NoSuchAlgorithmException e) { 485 throw new LowLevelException(e); 486 } catch (KeyStoreException e) { 487 throw new LowLevelException(e); 488 } catch (CryptoException e) { 489 throw new LowLevelException(e); 490 } 491 } 492 493 public void createKeyPair(String alias, char passphrase[]) throws CryptoException { 494 try { 495 final KeyPair kp = kpg.generateKeyPair(); 496 ks.setKeyEntry(alias, kp.getPrivate(), passphrase, new Certificate[]{CryptoTools.createCertificate(alias, kp)}); 497 // if (!Utility.isEmpty(filename)) save(); 498 } catch (KeyStoreException e) { 499 throw new LowLevelException(e); 500 } catch (SignatureException e) { 501 throw new LowLevelException(e); 502 } catch (InvalidKeyException e) { 503 throw new LowLevelException(e); 504 } 505 } 506 507 public void save() throws UserCancellationException { 508 try { 509 save(filename); 510 } catch (FileNotFoundException e) { 511 throw new LowLevelException(e); 512 } 513 } 514 515 public synchronized final void save(String filename) throws FileNotFoundException, UserCancellationException { 516 save(filename, agent.getPassPhrase(filename)); 517 } 518 519 public synchronized final void save(String filename, char passphrase[]) throws FileNotFoundException { 520 if (Utility.isEmpty(filename)) 521 throw new FileNotFoundException("no keystore filename"); 522 try { 523 File ksfile = new File(filename); 524 ksfile.getParentFile().mkdirs(); 525 System.out.println("Saving " + filename + " " + Thread.currentThread()); 526 ks.store(new FileOutputStream(ksfile), passphrase); 527 } catch (Exception e) { 528 throw new LowLevelException(e); 529 } 530 } 531 532 public Iterator iterator() throws KeyStoreException { 533 final Enumeration enumerator = ks.aliases(); 534 return new Iterator() { 535 public void remove() { 536 537 } 538 539 public boolean hasNext() { 540 return enumerator.hasMoreElements(); 541 } 542 543 public Object next() { 544 return enumerator.nextElement(); 545 } 546 547 }; 548 } 549 550 private final KeyStore ks; 551 private final KeyCache cache; 552 private final PassPhraseAgent agent; 553 private final KeyPairGenerator kpg; 554 private String filename; 555 }

This page was automatically generated by Maven