Hi Lloyd,
I am not in security now.
Forward emails to security team.
Regards,
Shing Wai Chan
Lloyd L Chambers wrote:
> TIMEOUT: 13:00 PM PST Tuesday June 5, 2007
>
> https://glassfish.dev.java.net/issues/show_bug.cgi?id=3029
>
> I had previously prepared this fix on the 9.0 code base for 8.2; it
> was backported and has been in 8.2 for some time. For some reason the
> code never went into 9.0. This fix rectifies that omission. Diffs
> and modified file attached. I have tested it with all variants I
> could think of, including changing the master password and password
> aliases multiple times.
>
> Lloyd Chambers
> ---------------
>
> llcMP:/gf/build/glassfish/appserv-commons lloyd$ cvs diff -w -u
> src/java/com/sun/enterprise/security/store/PasswordAdapter.java
> Index: src/java/com/sun/enterprise/security/store/PasswordAdapter.java
> ===================================================================
> RCS file:
> /cvs/glassfish/appserv-commons/src/java/com/sun/enterprise/security/store/PasswordAdapter.java,v
>
> retrieving revision 1.5
> diff -w -u -r1.5 PasswordAdapter.java
> ---
> src/java/com/sun/enterprise/security/store/PasswordAdapter.java 5
> May 2007 05:32:04 -0000 1.5
> +++
> src/java/com/sun/enterprise/security/store/PasswordAdapter.java 4
> Jun 2007 22:28:30 -0000
> @@ -58,11 +58,12 @@
> * This class implements an adapter for password manipulation a JCEKS.
> * @author Shing Wai Chan
> */
> -public class PasswordAdapter {
> +public final class PasswordAdapter {
> public static final String PASSWORD_ALIAS_KEYSTORE =
> "domain-passwords";
> - private KeyStore _pwdStore = null;
> - private String _keyFile = null;
> - private char[] _masterPassword = null;
> +
> + private KeyStore _pwdStore;
> + private final File _keyFile;
> + private char[] _masterPassword;
> private char[] getMasterPassword() {
> return _masterPassword;
> @@ -72,6 +73,50 @@
> _masterPassword = smp;
> }
>
> + private static final boolean DEBUG = true;
> +
> + private void debug( final Object o )
> + {
> + if ( DEBUG )
> + {
> + System.out.println( "PasswordAdapter.debug: " + o );
> + }
> + }
> + private void
> + debugState( final String when)
> + {
> + if ( DEBUG )
> + {
> + final String INDENT = " ";
> + try
> + {
> + String s = "PasswordAdapter Status: " + when + "\n";
> + s = s +INDENT + "Master password: " + new String(
> getMasterPassword() ) +"\n";
> + s = s + INDENT + "Key file: " + _keyFile + "\n";
> + s = s +INDENT + "Aliases:\n";
> + final Enumeration<String> aliases = getAliases();
> + while ( aliases.hasMoreElements() )
> + {
> + final String alias = aliases.nextElement();
> + s = s +INDENT + INDENT + alias + "=" +
> + new String( getPasswordForAlias(alias) )
> + "\n";
> + }
> + debug(s);
> + }
> + catch( Throwable t )
> + {
> + t.printStackTrace();
> + }
> + }
> + }
> +
> + private static String
> + getDefaultKeyFileName()
> + {
> + return
> System.getProperty(SystemPropertyConstants.INSTANCE_ROOT_PROPERTY) +
> + File.separator + "config" + File.separator +
> PASSWORD_ALIAS_KEYSTORE;
> + }
> +
> /**
> * Construct a PasswordAdapter with given Shared Master Password,
> * SMP using the default keyfile (domain-passwords.jceks)
> @@ -81,14 +126,11 @@
> * @throws KeyStoreException
> * @throws NoSuchAlgorithmException
> */
> - public PasswordAdapter(char[] smp)
> + public PasswordAdapter(char[] masterPassword)
> throws CertificateException, IOException,
> KeyStoreException, NoSuchAlgorithmException
> {
> -
> - String keyfileName =
> System.getProperty(SystemPropertyConstants.INSTANCE_ROOT_PROPERTY) +
> - File.separator + "config" + File.separator +
> PASSWORD_ALIAS_KEYSTORE;
> - init(keyfileName, smp);
> + this( getDefaultKeyFileName(), masterPassword );
> }
>
> /**
> @@ -101,11 +143,21 @@
> * @throws KeyStoreException
> * @throws NoSuchAlgorithmException
> */
> - public PasswordAdapter(String keyfileName, char[] smp)
> + public PasswordAdapter(
> + final String keyStoreFileName,
> + final char[] masterPassword)
> throws CertificateException, IOException,
> KeyStoreException, NoSuchAlgorithmException
> {
> - init(keyfileName, smp);
> + final File keyStoreFile = new File( keyStoreFileName );
> +
> + _pwdStore = loadKeyStore( keyStoreFile, masterPassword);
> +
> + // assign these only once the store is good; no need to keep
> copies otherwise!
> + _keyFile = keyStoreFile;
> + _masterPassword = masterPassword;
> +
> + debugState( "PasswordAdapter constructor" );
> }
>
> /**
> @@ -118,34 +170,30 @@
> * @exception KeyStoreException
> * @exception NoSuchAlgorithmException
> */
> - private void init(String keyfileName, char[] smp)
> + private static KeyStore
> + loadKeyStore( final File keyStoreFile, final char[] masterPassword )
> throws CertificateException, IOException,
> KeyStoreException, NoSuchAlgorithmException
> {
> - _keyFile = keyfileName;
> - _pwdStore = KeyStore.getInstance("JCEKS");
> - setMasterPassword(smp);
> - BufferedInputStream bInput = null;
> - File file = new File(keyfileName);
> - if (file.exists()) {
> - bInput = new BufferedInputStream(new FileInputStream(file));
> - }
> + final KeyStore keyStore = KeyStore.getInstance("JCEKS");
> +
> + if ( keyStoreFile.exists() )
> + {
> + // don't buffer keystore; it's tiny anyway
> + final FileInputStream input = new FileInputStream(
> keyStoreFile );
> try {
> - //load must be called with null to initialize an empty
> keystore
> - _pwdStore.load(bInput, getMasterPassword());
> - if (bInput != null) {
> - bInput.close();
> - bInput = null;
> + keyStore.load( input, masterPassword );
> }
> - } finally {
> - if (bInput != null) {
> - try {
> - bInput.close();
> - } catch(Exception ex) {
> - //ignore we are cleaning up
> + finally {
> + input.close();
> }
> }
> + else
> + {
> + keyStore.load( null, masterPassword );
> }
> +
> + return keyStore;
> }
>
> /**
> @@ -156,16 +204,21 @@
> * @exception NoSuchAlgorithmException
> * @exception UnrecoverableKeyException
> */
> - public String getPasswordForAlias(String alias)
> + public synchronized String getPasswordForAlias(final String alias)
> throws KeyStoreException, NoSuchAlgorithmException,
> - UnrecoverableKeyException {
> -
> - Key key = _pwdStore.getKey(alias, getMasterPassword());
> - if (key != null) {
> - return new String(key.getEncoded());
> - } else {
> - return null;
> + UnrecoverableKeyException
> + {
> + final byte[] bytes = getKeyBytesForAlias( alias,
> getMasterPassword() );
> + return bytes == null ? null : new String( bytes );
> }
> +
> + private byte[]
> + getKeyBytesForAlias( final String alias, final char[]
> masterPassword )
> + throws KeyStoreException,
> + NoSuchAlgorithmException, UnrecoverableKeyException
> + {
> + final Key key = _pwdStore.getKey( alias, masterPassword );
>
>
>
> -----------
>
> REVISED FILE (minus boilerplate header)
>
> package com.sun.enterprise.security.store;
>
> import com.sun.enterprise.util.SystemPropertyConstants;
>
> import java.io.File;
> import java.io.FileInputStream;
> import java.io.FileOutputStream;
> import java.io.BufferedInputStream;
> import java.io.BufferedOutputStream;
> import java.io.IOException;
> import java.security.Key;
> import java.security.KeyStore;
> import java.security.KeyStoreException;
> import java.security.NoSuchAlgorithmException;
> import java.security.UnrecoverableKeyException;
> import java.security.cert.CertificateException;
> import javax.crypto.SecretKey;
> import javax.crypto.spec.SecretKeySpec;
>
> import java.util.Enumeration;
>
> /**
> * This class implements an adapter for password manipulation a JCEKS.
> * @author Shing Wai Chan
> */
> public final class PasswordAdapter {
> public static final String PASSWORD_ALIAS_KEYSTORE =
> "domain-passwords";
>
> private KeyStore _pwdStore;
> private final File _keyFile;
> private char[] _masterPassword;
>
> private char[] getMasterPassword() {
> return _masterPassword;
> }
>
> private void setMasterPassword(char[] smp) {
> _masterPassword = smp;
> }
>
> private static final boolean DEBUG = true;
>
> private void debug( final Object o )
> {
> if ( DEBUG )
> {
> System.out.println( "PasswordAdapter.debug: " + o );
> }
> }
> private void
> debugState( final String when)
> {
> if ( DEBUG )
> {
> final String INDENT = " ";
> try
> {
> String s = "PasswordAdapter Status: " + when + "\n";
> s = s +INDENT + "Master password: " + new String(
> getMasterPassword() ) +"\n";
> s = s + INDENT + "Key file: " + _keyFile + "\n";
> s = s +INDENT + "Aliases:\n";
> final Enumeration<String> aliases = getAliases();
> while ( aliases.hasMoreElements() )
> {
> final String alias = aliases.nextElement();
> s = s +INDENT + INDENT + alias + "=" +
> new String( getPasswordForAlias(alias) ) +
> "\n";
> }
> debug(s);
> }
> catch( Throwable t )
> {
> t.printStackTrace();
> }
> }
> }
>
> private static String
> getDefaultKeyFileName()
> {
> return
> System.getProperty(SystemPropertyConstants.INSTANCE_ROOT_PROPERTY) +
> File.separator + "config" + File.separator +
> PASSWORD_ALIAS_KEYSTORE;
> }
>
> /**
> * Construct a PasswordAdapter with given Shared Master Password,
> * SMP using the default keyfile (domain-passwords.jceks)
> * @param smp master password
> * @throws CertificateException
> * @throws IOException
> * @throws KeyStoreException
> * @throws NoSuchAlgorithmException
> */
> public PasswordAdapter(char[] masterPassword)
> throws CertificateException, IOException,
> KeyStoreException, NoSuchAlgorithmException
> {
> this( getDefaultKeyFileName(), masterPassword );
> }
>
> /**
> * Construct a PasswordAdapter with given Shared Master Password,
> * SMP.
> * @param keyfileName the jceks key file name
> * @param smp master password
> * @throws CertificateException
> * @throws IOException
> * @throws KeyStoreException
> * @throws NoSuchAlgorithmException
> */
> public PasswordAdapter(
> final String keyStoreFileName,
> final char[] masterPassword)
> throws CertificateException, IOException,
> KeyStoreException, NoSuchAlgorithmException
> {
> final File keyStoreFile = new File( keyStoreFileName );
>
> _pwdStore = loadKeyStore( keyStoreFile, masterPassword);
>
> // assign these only once the store is good; no need to keep
> copies otherwise!
> _keyFile = keyStoreFile;
> _masterPassword = masterPassword;
>
> debugState( "PasswordAdapter constructor" );
> }
>
> /**
> * Construct a PasswordAdapter with given Shared Master Password,
> * SMP.
> * @param keyfileName the jceks key file name
> * @param smp the master password
> * @exception CertificateException
> * @exception IOException
> * @exception KeyStoreException
> * @exception NoSuchAlgorithmException
> */
> private static KeyStore
> loadKeyStore( final File keyStoreFile, final char[] masterPassword )
> throws CertificateException, IOException,
> KeyStoreException, NoSuchAlgorithmException
> {
> final KeyStore keyStore = KeyStore.getInstance("JCEKS");
>
> if ( keyStoreFile.exists() )
> {
> // don't buffer keystore; it's tiny anyway
> final FileInputStream input = new FileInputStream(
> keyStoreFile );
> try {
> keyStore.load( input, masterPassword );
> }
> finally {
> input.close();
> }
> }
> else
> {
> keyStore.load( null, masterPassword );
> }
>
> return keyStore;
> }
>
> /**
> * This methods returns password String for a given alias and SMP.
> * @param alias
> * @return corresponding password or null if the alias does not
> exist.
> * @exception KeyStoreException
> * @exception NoSuchAlgorithmException
> * @exception UnrecoverableKeyException
> */
> public synchronized String getPasswordForAlias(final String alias)
> throws KeyStoreException, NoSuchAlgorithmException,
> UnrecoverableKeyException
> {
> final byte[] bytes = getKeyBytesForAlias( alias,
> getMasterPassword() );
> return bytes == null ? null : new String( bytes );
> }
>
> private byte[]
> getKeyBytesForAlias( final String alias, final char[]
> masterPassword )
> throws KeyStoreException,
> NoSuchAlgorithmException, UnrecoverableKeyException
> {
> final Key key = _pwdStore.getKey( alias, masterPassword );
> return key == null ? null : key.getEncoded();
> }
>
> /**
> * This methods returns password SecretKey for a given alias and SMP.
> * @param alias
> * @return corresponding password SecretKey or
> * null if the alias does not exist.
> * @exception KeyStoreException
> * @exception NoSuchAlgorithmException
> * @exception UnrecoverableKeyException
> */
> public synchronized SecretKey getPasswordSecretKeyForAlias(String
> alias)
> throws KeyStoreException, NoSuchAlgorithmException,
> UnrecoverableKeyException {
>
> return (SecretKey)_pwdStore.getKey(alias, getMasterPassword());
> }
>
>
> /**
> * See if the given alias exists
> * @param alias the alias name
> * @return true if the alias exists in the keystore
> */
> public synchronized boolean aliasExists( final String alias)
> throws KeyStoreException
> {
> return _pwdStore.containsAlias(alias);
> }
>
> /**
> * Remove an alias from the keystore
> * @param alias The name of the alias to remove
> * @throws KeyStoreException
> * @throws IOException
> * @throws NoSuchAlgorithmException
> * @throws CertificateException
> */
> public synchronized void removeAlias( final String alias)
> throws KeyStoreException, IOException,
> NoSuchAlgorithmException, CertificateException
> {
> _pwdStore.deleteEntry(alias);
> writeStore();
> }
>
> /**
> * Return the aliases from the keystore.
> * @return An enumeration containing all the aliases in the keystore.
> */
> public synchronized Enumeration<String> getAliases()
> throws KeyStoreException
> {
> return _pwdStore.aliases();
> }
>
> private static synchronized void writeStore(
> final KeyStore keyStore,
> final File file,
> final char[] masterPassword )
> throws KeyStoreException, IOException,
> NoSuchAlgorithmException, CertificateException
> {
> // this can potentially wipe out the original
> // while changePassword() uses a temporary file,
> // setPasswordForAlias() and removeAlias() do not.
> final FileOutputStream out = new FileOutputStream(file);
> try
> {
> keyStore.store( out, masterPassword);
> }
> finally
> {
> out.close();
> }
> }
>
>
> /**
> * Writes the keystore to disk
> * @throws KeyStoreException
> * @throws IOException
> * @throws NoSuchAlgorithmException
> * @throws CertificateException
> */
> private void writeStore() throws KeyStoreException, IOException,
> NoSuchAlgorithmException, CertificateException
> {
> writeStore( _pwdStore, _keyFile, getMasterPassword() );
> }
>
> /**
> * This methods set alias, secretKey into JCEKS keystore.
> * @param alias
> * @param secretKey
> * @exception CertificateException
> * @exception IOException
> * @exception KeyStoreException
> * @exception NoSuchAlgorithmException
> */
> public synchronized void setPasswordForAlias(String alias, byte[]
> keyBytes)
> throws CertificateException, IOException, KeyStoreException,
> NoSuchAlgorithmException
> {
> debugState( "BEFORE setPasswordForAlias" );
> setPasswordForAlias( alias, keyBytes, getMasterPassword() );
> writeStore();
> debugState( "AFTER setPasswordForAlias" );
> }
>
>
> private void
> setPasswordForAlias(
> final String alias,
> final byte[] keyBytes,
> final char[] masterPassword )
> throws CertificateException, IOException,
> KeyStoreException, NoSuchAlgorithmException
> {
> final Key key = new SecretKeySpec(keyBytes, "AES");
> _pwdStore.setKeyEntry( alias, key, masterPassword, null);
> }
>
>
> /**
> Make a new KeyStore with all the keys secured with the new
> master password.
> */
> private KeyStore
> newKeyStore( final char[] newMasterPassword)
> throws KeyStoreException, IOException, NoSuchAlgorithmException,
> CertificateException, UnrecoverableKeyException
> {
> final char[] oldMasterPassword = getMasterPassword();
>
> final KeyStore oldStore = _pwdStore;
> final KeyStore newStore = KeyStore.getInstance("JCEKS",
> _pwdStore.getProvider() );
> newStore.load( null, newMasterPassword );
>
> final Enumeration<String> aliasesEnum = oldStore.aliases();
> while ( aliasesEnum.hasMoreElements() )
> {
> final String alias = aliasesEnum.nextElement();
>
> if ( ! oldStore.isKeyEntry( alias ) )
> {
> throw new IllegalArgumentException( "Expecting keys
> only" );
> }
>
> final Key key = oldStore.getKey( alias,
> oldMasterPassword );
> newStore.setKeyEntry( alias, key, newMasterPassword, null);
> }
>
> return newStore;
> }
>
>
> /**
> Changes the keystore password, including the encoding of the
> keys within it.
> <p>
> There are several error conditions that could occur:
> <ul>
> <li>Problem extracting existing alias keys with new
> ones.</li>
> <li>Problem writing the keystore, including destroying it
> if an I/O problem occurs.</li>
> <li></li>
> </ul>
> For these reasons, we make a new KeyStore and write it, then
> swap it with the old
> one.
>
> * @param newpassword the new keystore password
> * @throws KeyStoreException
> * @throws IOException
> * @throws NoSuchAlgorithmException
> * @throws CertificateException
> */
> public synchronized void changePassword(char[] newMasterPassword)
> throws KeyStoreException, IOException, NoSuchAlgorithmException,
> CertificateException, UnrecoverableKeyException
> {
> final char[] oldMasterPassword = getMasterPassword();
> debug( "Changing master password from " + new
> String(oldMasterPassword) + " to " + new String(newMasterPassword) );
> debugState( "BEFORE changing master password" );
>
> final KeyStore oldStore = _pwdStore;
> final KeyStore newStore = newKeyStore( newMasterPassword );
>
> // 'newStore' is now complete; rename the old KeyStore, the
> write the new one in its place
> final File saveOld = new File( _keyFile.toString() + ".save" );
> if ( ! _keyFile.renameTo( saveOld ) )
> {
> final String msg = "Can't rename " + _keyFile + " to "
> + saveOld;
> debug( msg );
> throw new IOException( msg );
> }
>
> try
> {
> debug( "Writing KeyStore to " + _keyFile + " using new
> master password = " + new String(newMasterPassword) );
> writeStore( newStore, _keyFile, newMasterPassword );
> _pwdStore = newStore;
> _masterPassword = newMasterPassword;
> debug( "KeyStore written successfully" );
> }
> catch( final Throwable t )
> {
> try {
> saveOld.renameTo( _keyFile );
> }
> catch( Throwable tt )
> {
> /* best effort failed */
> }
>
> throw new RuntimeException( "Can't write new KeyStore", t );
> }
>
> try
> {
> debug( "deleting old keystore " + saveOld );
> saveOld.delete();
> // debug( "done deleting old keystore " saveOld );
> }
> catch( Throwable t )
> {
> throw new RuntimeException( "Can't remove old file \"" +
> _keyFile + "\"", t );
> }
>
> debugState( "AFTER changing master password" );
>
> loadKeyStore( _keyFile, getMasterPassword() );
>
> debugState( "AFTER forcing reload from file" );
> }
> }
>
>