You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2006/07/28 10:59:56 UTC

svn commit: r426443 [1/2] - /incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/

Author: mloenko
Date: Fri Jul 28 01:59:55 2006
New Revision: 426443

URL: http://svn.apache.org/viewvc?rev=426443&view=rev
Log:
applied patch for HARMONY-993
Keytool - added interaction with user, certificate import, certificate revocation status check

Added:
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CRLManager.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertChainVerifier.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertImporter.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertReader.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/HelpPrinter.java
Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/Command.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/EntryManager.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/KeyStoreCertPrinter.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/KeyStoreLoaderSaver.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/KeytoolParameters.java
    incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/Main.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java?rev=426443&r1=426442&r2=426443&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java Fri Jul 28 01:59:55 2006
@@ -16,7 +16,15 @@
 
 package org.apache.harmony.tools.keytool;
 
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStreamReader;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
 
 /**
  * The class to interact with the user - parse the program arguments, ask for
@@ -25,7 +33,26 @@
  */
 
 class ArgumentsParser {
-    // / options names to compare to ///
+    // used to get additional data prompted
+    static InputStreamReader in = new InputStreamReader(System.in);
+
+    // buffer for the data read
+    static char[] readData = new char[256];
+
+    // number of symbols read
+    static int charsRead;
+
+    // minimum password length permitted
+    static int minPwdLength = 6;
+
+    // maximum number of attempts to set the password
+    static int maxNrOfAttempts = 3;
+
+    // length of the "\r\n" which is added to the end of the line,
+    // when ENTER is pressed.
+    private static int newLineLength = 2;
+
+    // options names to compare to //
     // commands
     final static String sGenkey = "-genkey";
 
@@ -41,11 +68,9 @@
 
     final static String sCertreq = "-certreq";
 
-    final static String sSign = "-sign";
-
     final static String sCheck = "-checkcrl";
 
-    final static String sAdd = "-addtocrl";
+    final static String sConvert = "-convert";
 
     final static String sVerify = "-verify";
 
@@ -97,11 +122,9 @@
     final static String sNew = "-new";
 
     final static String sIssuerAlias = "-issuer";
-
+    
     final static String sIssuerPass = "-issuerpass";
-
-    final static String sCertstore = "-certstore";
-
+    
     final static String sSecretkey = "-secretkey";
 
     final static String sX509Version = "-x509version";
@@ -110,18 +133,37 @@
 
     final static String sDestAlias = "-dest";
 
-    final static String sCRLstore = "-crlstore";
+    final static String sCRLfile = "-crlfile";
+    
+    final static String sCA = "-ca";
+    
+    final static String sConvStorePath = "-convkeystore";
+    
+    final static String sConvStorePass = "-convstorepass";
+    
+    final static String sConvStoreType = "-convtype";
+
+    final static String sConvKeyEntries = "-convkeys";
+    
+    final static String sCAcertsPath = "-cacerts";
+    
+    final static String sCAcertsPass = "-cacertspass";
 
     /**
      * The method finds known options in args which is usually taken from
      * command line and sets the corresponding fields of the returned
      * KeytoolParameters object to given values.
      * 
-     * @throws KeytoolException
+     * @param args -
+     *            String array to parse.
+     * @return null if args is null or zero-sized, one of the elements of args
+     *         is null or empty, an unknown option is found or an expected
+     *         option value is not given or not of an expected type.
      * @throws IOException
      */
-    static KeytoolParameters parseArgs(String[] args) throws KeytoolException,
-            IOException {
+
+    static KeytoolParameters parseArgs(String[] args)
+            throws NumberFormatException, KeytoolException, IOException {
         if (args == null || args.length == 0) {
             return null;
         }
@@ -164,8 +206,8 @@
                     param.setCommand(Command.CHECK);
                     continue;
                 }
-                if (args[i].compareToIgnoreCase(sAdd) == 0) {
-                    param.setCommand(Command.ADD);
+                if (args[i].compareToIgnoreCase(sConvert) == 0) {
+                    param.setCommand(Command.CONVERT);
                     continue;
                 }
                 if (args[i].compareToIgnoreCase(sVerify) == 0) {
@@ -230,10 +272,6 @@
                     param.setIssuerAlias(args[++i]);
                     continue;
                 }
-                if (args[i].compareToIgnoreCase(sCertstore) == 0) {
-                    param.setStorePath(args[++i]);
-                    continue;
-                }
                 if (args[i].compareToIgnoreCase(sStorepass) == 0) {
                     param.setStorePass(args[++i].toCharArray());
                     continue;
@@ -246,8 +284,8 @@
                     param.setIssuerPass(args[++i].toCharArray());
                     continue;
                 }
-                if (args[i].compareToIgnoreCase(sCRLstore) == 0) {
-                    param.setCrlStore(args[++i]);
+                if (args[i].compareToIgnoreCase(sCRLfile) == 0) {
+                    param.setCrlFile(args[++i]);
                     continue;
                 }
                 if (args[i].compareToIgnoreCase(sDestAlias) == 0) {
@@ -258,6 +296,26 @@
                     param.setNewPasswd(args[++i].toCharArray());
                     continue;
                 }
+                if (args[i].compareToIgnoreCase(sConvStorePath) == 0) {
+                    param.setConvertedKeyStorePath(args[++i]);
+                    continue;
+                }
+                if (args[i].compareToIgnoreCase(sConvStoreType) == 0) {
+                    param.setConvertedKeyStoreType(args[++i]);
+                    continue;
+                }
+                if (args[i].compareToIgnoreCase(sConvStorePass) == 0) {
+                    param.setConvertedKeyStorePass(args[++i].toCharArray());
+                    continue;
+                }
+                if (args[i].compareToIgnoreCase(sCAcertsPath) == 0) {
+                    param.setCacertsPath(args[++i]);
+                    continue;
+                }
+                if (args[i].compareToIgnoreCase(sCAcertsPass) == 0) {
+                    param.setCacertsPass(args[++i].toCharArray());
+                    continue;
+                }
                 if (args[i].compareToIgnoreCase(sKeysize) == 0) {
 
                     param.setKeySize((new Integer(args[++i])).intValue());
@@ -314,6 +372,14 @@
                     param.setSecretKey(true);
                     continue;
                 }
+                if (args[i].compareToIgnoreCase(sCA) == 0) {
+                    param.setCA(true);
+                    continue;
+                }
+                if (args[i].compareToIgnoreCase(sConvKeyEntries) == 0) {
+                    param.setConvertKeyEntries(true);
+                    continue;
+                }
 
                 System.out.println("Illegal option: " + args[i]);
                 return null;
@@ -322,7 +388,6 @@
             // ignore the last option if its value is not provided
         }
 
-        // set flag to use certstore, not keystore.
         Command cmd = param.getCommand();
 
         // check whether -v and -rfc options are used separately with -list.
@@ -337,14 +402,358 @@
             return param;
         }
 
-        // TODO: if the store password has not been entered, prompt for it
+        // if the store password has not been entered, prompt for it
+        if (param.getStorePass() == null) {
+            // get path to the store
+            String storePath = (param.getStorePath() != null) ? param
+                    .getStorePath() : KeytoolParameters.defaultKeystorePath;
+            // get store password
+            String prompt = "Enter keystore password: ";
+            System.out.print(prompt);
+            charsRead = in.read(readData);
+            char[] storePass;
+            File storeFile = new File(storePath);
+            if (storeFile.isDirectory()) {
+                throw new KeytoolException("The keystore path " + storePath
+                        + " points to a directory.");
+            }
+            // Allow short passwords to unlock existing stores and
+            // disallow passwords shorter than minPwdLength symbols for new
+            // ones.
+            // Check whether the file exists
+            if (!storeFile.exists()) {
+                // check of password length and additional prompts for
+                // password are made here
+                storePass = promptLongerPassword(prompt);
+            } else {
+                // if the store exists don't check the length
+                storePass = new char[charsRead - newLineLength];// remove "\r\n"
+                System.arraycopy(readData, 0, storePass, 0, charsRead
+                        - newLineLength);
+            }
+            if (storePass.length != 0) {
+                param.setStorePass(storePass);
+            } else {
+                param.setStorePass(null);
+            }
+        }
+
         return param;
     }
 
     /**
      * Checks if the needed values are set and, if not, prompts for them.
+     * 
+     * This method must be called after the keystore is loaded.
+     * 
+     * @param param
+     * @return
+     * @throws KeytoolException
+     * @throws UnrecoverableKeyException
+     * @throws NoSuchAlgorithmException
+     * @throws IOException
+     * @throws KeyStoreException
+     * @throws NoSuchProviderException 
+     * @throws CertificateException 
      */
-    static void getAdditionalParameters(KeytoolParameters param) {
-        // TODO
+    static void getAdditionalParameters(KeytoolParameters param)
+            throws KeytoolException, IOException, KeyStoreException,
+            UnrecoverableKeyException, NoSuchAlgorithmException,
+            CertificateException, NoSuchProviderException {
+        // this method must be called after the keystore is loaded.
+        KeyStore keyStore = param.getKeyStore();
+
+        // set the alias to "mykey" if it's not set up
+        Command command = param.getCommand();
+        if (param.getAlias() == null
+                && (command == Command.KEYCLONE || command == Command.EXPORT
+                        || command == Command.CERTREQ
+                        || command == Command.GENKEY
+                        || command == Command.SELFCERT
+                        || command == Command.IMPORT || command == Command.KEYPASSWD)) {
+            param.setAlias("mykey");
+        }
+        String alias = param.getAlias();
+        
+        // check if the alias exists
+        if (command == Command.CERTREQ || command == Command.DELETE
+                || command == Command.EXPORT || command == Command.KEYCLONE
+                || command == Command.KEYPASSWD || command == Command.SELFCERT
+                || (command == Command.LIST && param.getAlias() != null)) {
+            if (!keyStore.containsAlias(param.getAlias())) {
+                throw new KeytoolException("Alias <" + alias
+                        + "> doesn't exist");
+            }
+        } else if (command == Command.GENKEY){
+            if (keyStore.containsAlias(param.getAlias())) {
+                throw new KeytoolException("Key(s) not generated, alias <"
+                        + alias + "> already exists.");
+            }
+        }
+
+        // if the key password has not been entered and the password is required
+        // to get the key (it is not a password for a newly created entry)
+        if (param.getKeyPass() == null
+                && (command == Command.KEYCLONE || command == Command.EXPORT
+                        || command == Command.CERTREQ
+                        || command == Command.KEYPASSWD
+                        || command == Command.SELFCERT
+                // if keystore contains alias, import of a certificate reply
+                // is considered, otherwise password is unnecessary.
+                || (command == Command.IMPORT && keyStore.containsAlias(alias)))) {
+            param.setKeyPass(tryStorePassAsKeyPass(keyStore, alias, param
+                    .getStorePass()));
+        }
+        
+        switch (command) {
+            case KEYCLONE:
+                // prompt for a destination alias, if one is not specified
+                if (param.getDestAlias() == null) {
+                    System.out.print("Enter destination alias name: ");
+                    charsRead = in.read(readData);
+                    if (charsRead <= newLineLength) {
+                        throw new KeytoolException(
+                                "Must specify destination alias");
+                    } else {
+                        param.setDestAlias(new String(readData).substring(0,
+                                charsRead - newLineLength));
+                    }
+                }
+                // if the password for a newly created entry is not specified,
+                // ask for it.
+                if (param.getNewPasswd() == null) {
+                    param.setNewPasswd(getNewPassword(alias, param
+                            .getDestAlias(), param.getKeyPass()));
+                }
+                break;
+            case DELETE:
+                // prompt for an alias to delete, if one is not specified
+                if (alias == null) {
+                    System.out.print("Enter alias name: ");
+                    charsRead = in.read(readData);
+                    if (charsRead <= newLineLength) {
+                        throw new KeytoolException("Must specify alias");
+                    } else {
+                        param.setAlias(new String(readData).substring(0,
+                                charsRead - newLineLength));
+                    }
+                }
+                break;
+            case STOREPASSWD:
+            case KEYPASSWD:
+                String prompt;
+                String promptReenter;
+                // prompt for a new password, if it is not specified
+                if (command == Command.KEYPASSWD) {
+                    prompt = "Enter new key password for <" + alias + ">: ";
+                    promptReenter = "Re-enter new keystore password for <"
+                            + alias + ">: ";
+                } else { // if param.getCommand() == Command.STOREPASSWD
+                    // prompt for a new store password, if it is not specified
+                    prompt = "Enter new keystore password: ";
+                    promptReenter = "Re-enter new keystore password: ";
+                }
+
+                // if the new password is not entered
+                if (param.getNewPasswd() == null) {
+                    System.out.print(prompt);
+                    charsRead = in.read(readData);
+                    char[] password = promptLongerPassword(prompt);
+                    System.out.print(promptReenter);
+                    charsRead = in.read(readData);
+                    if (charsRead == password.length + newLineLength) {
+                        for (int i = 0; i < password.length; i++) {
+                            if (readData[i] != password[i]) {
+                                throw new KeytoolException(
+                                        "Passwords do not match");
+                            }
+                        }
+                        param.setNewPasswd(password);
+                    } else {
+                        throw new KeytoolException("Passwords do not match");
+                    }
+                    // if entered a short password in the command line
+                } else if (param.getNewPasswd().length < minPwdLength) {
+                    throw new KeytoolException("The password must be at least "
+                            + minPwdLength + " characters");
+                }
+
+                break;
+            case LIST:
+                if (alias != null) {
+                    // This check is not where the same thing for other
+                    // commands done, because (alias != null) check is
+                    // necessary.
+                    if (keyStore.entryInstanceOf(alias,
+                            KeyStore.SecretKeyEntry.class)
+                            && param.getKeyPass() == null) {
+                        param.setKeyPass(tryStorePassAsKeyPass(keyStore, alias,
+                                param.getStorePass()));
+                    }
+                }
+                break;
+        }// switch (param.getCommand())
+
+    }
+
+    /**
+     * The method should be called only after the password was entered and put into
+     * readData. charsRead also shouldn't be changed after the password was
+     * entered and before the method is called. If charsRead is less than
+     * minPwdLength + newLineLength, the method just copies the password from
+     * readData into a newly created char array; otherwise it prompts for a
+     * longer password for maxNrOfAttempts times.
+     * 
+     * @param prompt
+     * @return new password of length equal or longer than minPwdLength
+     * @throws IOException
+     * @throws KeytoolException
+     */
+    private static char[] promptLongerPassword(String prompt)
+            throws IOException, KeytoolException {
+        int cntAttempts = 0;
+        while (charsRead < minPwdLength + newLineLength) {
+            System.out.println("The password must be at least " + minPwdLength
+                    + " characters");
+            System.out.print(prompt);
+            charsRead = in.read(readData);
+            ++cntAttempts;
+            if (cntAttempts >= maxNrOfAttempts) {
+                throw new KeytoolException("Too many failures. "
+                        + "Please, try again later.");
+            }
+        }
+        char[] password = new char[charsRead - newLineLength];
+        System.arraycopy(readData, 0, password, 0, charsRead - newLineLength);
+        return password;
     }
+
+    /**
+     * Does all work to get from the user a password for a newly created (cloned
+     * or generated) key.
+     * 
+     * @param -
+     *            srcAlias is the alias of the entry to clone, or if it is null,
+     *            the keystore password will be prompted to use.
+     * @param -
+     *            destAlias is the alias of the newly created entry.
+     * @param -
+     *            srcPass is the password to be used with a new entry if the
+     *            user doesn't enter a new one.
+     * 
+     * @return - char array representing the password for the entry. It can be
+     *         equal to the keystore password or the password of a cloned key.
+     */
+    private static char[] getNewPassword(String srcAlias, String destAlias,
+            char[] srcPass) throws IOException, KeytoolException {
+        if (destAlias == null) {
+            return null;
+        }
+        String prompt = "Enter key password for <" + destAlias + ">: ";
+        System.out.print(prompt);
+        if (srcAlias == null) {
+            System.out.print("(Press RETURN if same as for keystore) ");
+        } else {
+            System.out.print("(Press RETURN if same as for <" + srcAlias
+                    + ">) ");
+        }
+        charsRead = in.read(readData);
+        char[] destPass;
+        // if RETURN was pressed
+        if (charsRead <= newLineLength) {
+            destPass = new char[srcPass.length];
+            System.arraycopy(srcPass, 0, destPass, 0, srcPass.length);
+        } else {// if some password was entered
+            destPass = promptLongerPassword(prompt);
+        }
+        return destPass;
+    }
+
+    /**
+     * Prints a promt. Reads what the user enters. If the user has entered
+     * 'y'/"yes" or 'n'/"no" (case insensitively) the method returns
+     * respectively true or false. Depending on acceptAnother parameter the
+     * method can return false if anything except 'y' or "yes" is entered, or it
+     * can prompt for a correct answer. If only ENTER is pressed false is
+     * returned.
+     * 
+     * @param promt -
+     *            text printed to ask the user for a confirmation
+     * @param acceptAnother -
+     *            if set to true, the method returns true if and only if the
+     *            user enters 'y' or "yes"; if set to false prompts to reenter
+     *            the answer from user until 'y'/"yes" or 'n'/"no" is entered.
+     * @return true if the user confirms the request, false - otherwise.
+     * @throws IOException
+     */
+    static boolean getConfirmation(String promt, boolean acceptAnother)
+            throws IOException, KeytoolException {
+        int counter = 0;
+        while (counter++ < 100) {
+            System.out.print(promt);
+            charsRead = in.read(readData);
+            // if pressed ENTER return the default value
+            if (charsRead == newLineLength) {
+                return false;
+            }
+            // confirm, if the user enters 'y' or "yes"
+            if ((charsRead == newLineLength + 1 && (readData[0] == 'y' || readData[0] == 'Y'))
+                    || (charsRead == newLineLength + 3 && "yes"
+                            .equalsIgnoreCase(new String(readData).substring(0,
+                                    3)))) {
+                return true;
+            } else if (acceptAnother) {
+                return false;
+            } else {
+                // if entered 'n' or "no"
+                if (readData[0] == 'n'
+                        || readData[0] == 'N'
+                        && ((charsRead == newLineLength + 1) || (charsRead == newLineLength + 2
+                                && readData[0] == 'o' || readData[0] == 'O'))) {
+                    return false;
+                } else {
+                    System.out.println("Wrong answer, please, try again");
+                }
+            }
+        }
+        throw new KeytoolException("Too many failures. ");
+    }
+    
+    // method tries to get the key, associated with alias, using the storePass,
+    // if it can be recovered using the password storePass is returned,
+    // otherwise - the password is prompted for. Another attempt to recover the
+    // key with entered password. If it is ok, it is returned, otherwise
+    // UnrecoverableKeyException is thrown.
+    private static char[] tryStorePassAsKeyPass(KeyStore keyStore,
+            String alias, char[] storePass) throws KeyStoreException,
+            IOException, UnrecoverableKeyException, NoSuchAlgorithmException {
+        try {
+            // try to get a key with keystore password
+            // if succeed set key password same as that for keystore
+            keyStore.getKey(alias, storePass);
+
+            // will not come here if exception is thrown
+            return storePass;
+        } catch (UnrecoverableKeyException e) {
+            // if key password is not equal to store password, ask for it.
+            System.out.print("Enter key password for <" + alias + ">: ");
+            charsRead = in.read(readData);
+            char[] keyPass = new char[charsRead - newLineLength];
+            System
+                    .arraycopy(readData, 0, keyPass, 0, charsRead
+                            - newLineLength);
+            // if the new password is incorrect an axception will be thrown
+            try {
+                keyStore.getKey(alias, keyPass);
+            } catch (NoSuchAlgorithmException nsae) {
+                throw new NoSuchAlgorithmException(
+                        "Cannot find the algorithm to recover the key. ", e);
+            }
+            return keyPass;
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(
+                    "Cannot find the algorithm to recover the key. ", e);
+        }
+    }
+
 }

Added: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CRLManager.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CRLManager.java?rev=426443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CRLManager.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CRLManager.java Fri Jul 28 01:59:55 2006
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.tools.keytool;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Class for managing Certificate Revocation Lists (CRLs).
+ */
+public class CRLManager {
+    /**
+     * Checks if the certificate given in the file is contained in the CRL which
+     * is stored in the certstore. If the file name is not given, stdin is used.
+     * File with CRL and the checked certificate file are specified in param.
+     * 
+     * @param param
+     * @throws KeytoolException
+     * @throws IOException
+     * @throws CRLException
+     * @throws NoSuchProviderException
+     * @throws CertificateException
+     * @throws FileNotFoundException
+     * @throws NoSuchAlgorithmException 
+     */
+    static void checkRevoked(KeytoolParameters param) throws FileNotFoundException,
+            CertificateException, NoSuchProviderException, CRLException,
+            IOException, KeytoolException, NoSuchAlgorithmException {
+
+        String providerName = param.getProvider();
+        // firstly, get CRLs from the file 
+        Collection crls = CertReader.readCRLs(param.getCrlFile(), providerName);
+        // quit, if couldn't read anything
+        if (crls.isEmpty()) {
+            throw new CRLException("Failed to generate a CRL from the input. ");
+        }
+
+        // secondly, get certificates from another file
+        Collection certs = CertReader.readCerts(param.getFileName(), false,
+                param.getProvider());
+        if (certs.isEmpty()) {
+            throw new CertificateException(
+                    "Failed to generate a certificate from the input. ");
+        }
+
+        boolean foundRevoked = false;
+        
+        // search in the CRLs for revocations of the certificates
+        Iterator crlIter = crls.iterator();
+        while (crlIter.hasNext()) {
+            X509CRL crl = (X509CRL) crlIter.next();
+            Iterator certIter = certs.iterator();
+            while (certIter.hasNext()){
+                X509Certificate cert = (X509Certificate)certIter.next();
+                X509CRLEntry entry = crl.getRevokedCertificate(cert); 
+                if (entry != null) {
+                    System.out.println("The certificate ...");
+                    KeyStoreCertPrinter.printX509CertDetailed(cert, providerName);
+                    System.out.println("... is revoked on "
+                            + entry.getRevocationDate() + "\n");
+                    foundRevoked = true;
+                    continue;
+                } 
+            }
+        }
+        
+        if (certs.size() == 1 && !foundRevoked){
+            System.out.println("The certificate ...");
+            KeyStoreCertPrinter.printX509CertDetailed((X509Certificate) certs
+                    .iterator().next(), providerName);
+            System.out.println("... is not found in CRLs given");
+        } else if (!foundRevoked){
+            System.out.println("The certificates are not found in CRLs given");
+        }
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertChainVerifier.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertChainVerifier.java?rev=426443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertChainVerifier.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertChainVerifier.java Fri Jul 28 01:59:55 2006
@@ -0,0 +1,590 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.tools.keytool;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertificateException;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * A class for checking X.509 certifcicates and building and verifying X.509
+ * certificate chains.
+ */
+public class CertChainVerifier {
+    private final static String strFailed = "Failed to build a certificate chain from reply.\n";
+
+    /**
+     * A cerificate chain is built by looking up the certificate of the issuer
+     * of the current certificate. If a sertificate is self-signed it is assumed
+     * to be the root CA. After that the certificates are searched in the lists
+     * of revoked certificates. Certificate signatures are checked and
+     * certificate path is built in the same way as in import operation. If an
+     * error occurs the flow is not stopped but an attempt to continue is made.
+     * The results of the verification are printed to stdout.
+     */
+    static void verifyChain(KeytoolParameters param){
+        // TODO
+        throw new RuntimeException("Method is not implemented yet.");
+    }
+    
+    /**
+     * Builds a certificate chain from the given X509Certificate newCert to a
+     * self-signed root CA whose certificate is contained in the keystore or
+     * cacerts file (if "-trustcacerts" option is specified).
+     * 
+     * @param param -
+     *            specifies the keystore, provider name and other options (such
+     *            as "-trustcacerts").
+     * @param newCert -
+     *            certificate to start the chain
+     * @return the chain as an array of X509Certificate-s. If the chain cannot
+     *         be built for some reason an exception is thrown.
+     * @throws KeyStoreException
+     * @throws FileNotFoundException
+     * @throws NoSuchAlgorithmException
+     * @throws CertificateException
+     * @throws IOException
+     * @throws KeytoolException
+     * @throws NoSuchProviderException
+     * @throws CertPathBuilderException
+     */
+    static X509Certificate[] buildFullCertPath(KeytoolParameters param,
+            X509Certificate newCert) throws KeyStoreException,
+            FileNotFoundException, NoSuchAlgorithmException,
+            CertificateException, IOException, KeytoolException,
+            CertPathBuilderException, NoSuchProviderException {
+
+        X509CertSelector selector = new X509CertSelector();
+        selector.setCertificate(newCert);
+
+        Collection[] trustedSeparated = separateTrusted(param);
+        Set selfSignedTAs = (Set) trustedSeparated[0];
+        Collection trustedCerts = trustedSeparated[1];
+        Collection selfSignedTAsCerts = trustedSeparated[2];
+
+        CertPathBuilderResult bldResult = buildCertPath(param.getProvider(),
+                newCert, selfSignedTAs, trustedCerts);
+
+        // The validation of the certificate path.
+        // According to black-box testing, RI keytool doesn't perform
+        // the certificate path validation procedure. Therefore this
+        // implementation also doesn't validate the certificate chain
+        // The path validation procedure can be done in future as an
+        // extension of the current functionality.
+
+        // The imported certificate should be included in the chain;
+        // The root CA is not included in it.
+        X509Certificate[] newChainNoCA = (X509Certificate[]) bldResult
+                .getCertPath().getCertificates()
+                .toArray(new X509Certificate[0]);
+
+        // get the subject of the root CA which will be the last element of the
+        // chain
+        X500Principal caSubject = newChainNoCA[newChainNoCA.length - 1]
+                .getIssuerX500Principal();
+
+        // set the search parameter for the root CA
+        selector.setCertificate(null);
+        selector.setSubject(caSubject);
+
+        // add all root CAs to the CertStore to search through them
+        CollectionCertStoreParameters rootCAs = new CollectionCertStoreParameters(
+                selfSignedTAsCerts);
+        CertStore rootCAsCertStore;
+        try {
+            rootCAsCertStore = CertStore.getInstance("Collection", rootCAs);
+        } catch (Exception e) {
+            throw new KeytoolException(strFailed, e);
+        }
+
+        // find certificate to add to the end of the certificate chain
+        X509Certificate rootCA;
+        try {
+            rootCA = (X509Certificate) rootCAsCertStore.getCertificates(
+                    selector).iterator().next();
+        } catch (CertStoreException e) {
+            throw new KeytoolException(strFailed, e);
+        }
+        // create a new array of certificates with the root CA in it.
+        X509Certificate[] newChain = new X509Certificate[newChainNoCA.length + 1];
+        System.arraycopy(newChainNoCA, 0, newChain, 0, newChainNoCA.length);
+        newChain[newChain.length - 1] = rootCA;
+
+        return newChain;
+    }
+
+    /**
+     * Build a certificte chain up to the trust anchor, based on trusted
+     * certificates contained in the keystore and possibly cacerts file (if
+     * param.isTrustCACerts() returns true).
+     * 
+     * @param param
+     * @param newCert
+     * @return
+     * @throws NoSuchAlgorithmException
+     * @throws CertificateException
+     * @throws KeyStoreException
+     * @throws CertPathBuilderException
+     * @throws IOException
+     * @throws KeytoolException
+     * @throws NoSuchProviderException
+     */
+    static CertPathBuilderResult buildCertPath(KeytoolParameters param,
+            X509Certificate newCert) throws NoSuchAlgorithmException,
+            CertificateException, KeyStoreException, CertPathBuilderException,
+            IOException, KeytoolException, NoSuchProviderException {
+        Collection[] trustedSeparated = separateTrusted(param);
+        Set selfSignedTAs = (Set) trustedSeparated[0];
+        Collection trustedCerts = trustedSeparated[1];
+
+        return buildCertPath(param.getProvider(), newCert, selfSignedTAs,
+                trustedCerts);
+    }
+
+    
+    // Build a certificte chain up to the self-signed trust anchor, based on
+    // trusted certificates given.
+    // 
+    // @param provider
+    // @param newCert
+    //            is a certificate to build chain for.
+    // @param selfSignedTAs
+    //            are used as trust anchors.
+    // @param trustedCerts
+    //            elements of trustedCerts are used as chain links It can be
+    //            null if no intermediate certifictaes allowed.
+    private static CertPathBuilderResult buildCertPath(String provider,
+            X509Certificate newCert, Set selfSignedTAs, Collection trustedCerts)
+            throws NoSuchAlgorithmException, CertificateException, IOException,
+            KeyStoreException, CertPathBuilderException, KeytoolException,
+            NoSuchProviderException {
+
+        X509CertSelector selector = new X509CertSelector();
+        selector.setCertificate(newCert);
+
+        String strPKIX = "PKIX";
+        String strNoSelfSigned = "Possibly, keystore doesn't "
+                + "contain any self-signed (root CA) trusted certificates. ";
+
+        // this parameter will be used to generate the certificate chain
+        PKIXBuilderParameters builderParam = null;
+        try {
+            // set the search parameters with selector
+            // and TrustAnchors with selfSignedTAs
+            builderParam = new PKIXBuilderParameters(selfSignedTAs, selector);
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new KeytoolException(strFailed + strNoSelfSigned, e);
+        }
+
+        if (trustedCerts != null) {
+            CollectionCertStoreParameters trustedCertsCCSParams = 
+                    new CollectionCertStoreParameters(trustedCerts);
+            CertStore trustedCertStore;
+            try {
+                trustedCertStore = CertStore.getInstance("Collection",
+                        trustedCertsCCSParams);
+            } catch (Exception e) {
+                throw new KeytoolException(strFailed, e);
+            }
+
+            // add certificates to use as chain links
+            builderParam.addCertStore(trustedCertStore);
+        }
+
+        // disable the revocation checking
+        builderParam.setRevocationEnabled(false);
+
+        CertPathBuilder cpBuilder;
+        try {
+            if (provider == null) {
+                cpBuilder = CertPathBuilder.getInstance(strPKIX);
+            } else {
+                cpBuilder = CertPathBuilder.getInstance(strPKIX, provider);
+            }
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException("The algorithm " + strPKIX
+                    + " is not available.", e);
+        } catch (NoSuchProviderException e) {
+            throw (NoSuchProviderException) new NoSuchProviderException(
+                    "The provider " + provider
+                            + " is not found in the environment.").initCause(e);
+        }
+
+        CertPathBuilderResult bldResult = null;
+        try {
+            // the actual building of the certificate chain is done here
+            bldResult = cpBuilder.build(builderParam);
+        } catch (CertPathBuilderException e) {
+            throw new CertPathBuilderException(strFailed, e);
+        } catch (InvalidAlgorithmParameterException e) {
+            throw new KeytoolException(strFailed + strNoSelfSigned, e);
+        }
+
+        return bldResult;
+    }
+
+    
+    // Separates the trusted certificates from keystore (and cacerts file if
+    // "-trustcacerts" option is specified) into self-signed certificate
+    // authority certificates and non-self-signed certifcates.
+    // @return - Returns an array of Collection-s.
+    // The first element of the array is Set<TrustAnchors> - self-signed CAs.
+    // The second - ArrayList of non-self-signed trusted certifcates.
+    // The third - ArrayList of self-signed certificates which correspond to
+    // TrustAnchors containied in the first element of the array.
+    private static Collection[] separateTrusted(KeytoolParameters param)
+            throws KeyStoreException, FileNotFoundException, IOException,
+            NoSuchAlgorithmException, CertificateException, KeytoolException,
+            NoSuchProviderException {
+        // Are there any trusted certificates in the keyStore?
+        boolean trustedExistInKS = false;
+        // Is "-trustcacerts" option specified?
+        boolean trustCaCerts = param.isTrustCACerts();
+        String strNoTrusted = "Possibly, keystore doesn't "
+                + "contain any trusted certificates. ";
+
+        // This one is temporary. Used just to get trusted certificates
+        // from keyStore.
+        PKIXBuilderParameters keyStoreBuilderParam = null;
+        X509CertSelector selector = new X509CertSelector();
+
+        // After getting the trusted certificates, they will be sorted into
+        // self-signed (they are considered to be CAs) and interim trusted
+        // certs.
+
+        // self-signed trust anchors. The CertPath is ok if it finishes
+        // on such trust anchor.
+        Set selfSignedTAs = null;
+        // certificates of selfSignedTAs
+        Collection selfSignedTAsCerts = null;
+        // trusted certiifcates which can be the chain links of the CertPath
+        Collection trustedCerts = null;
+        try {
+            keyStoreBuilderParam = new PKIXBuilderParameters(param
+                    .getKeyStore(), selector);
+
+            // won't come here if exception is thrown
+            trustedExistInKS = true;
+        } catch (InvalidAlgorithmParameterException e) {
+            // if "-trustcacerts" option is NOT specified
+            if (!trustCaCerts) {
+                throw new KeytoolException(strFailed + strNoTrusted);
+            }
+        }
+
+        // if there are trusted certificates in the keyStore
+        if (keyStoreBuilderParam != null) {
+            // trustAnchorsSet is a set of trusted certificates
+            // contained in keyStore
+            Set trustAnchorsSet = keyStoreBuilderParam.getTrustAnchors();
+            int halfSize = trustAnchorsSet.size() / 2;
+            selfSignedTAs = new HashSet(halfSize);
+            selfSignedTAsCerts = new ArrayList(halfSize);
+            trustedCerts = new ArrayList(halfSize);
+
+            Iterator trustAnchorsIter = trustAnchorsSet.iterator();
+            while (trustAnchorsIter.hasNext()) {
+                TrustAnchor ta = (TrustAnchor) trustAnchorsIter.next();
+                X509Certificate trCert = ta.getTrustedCert();
+                // if the trusted certificate is self-signed,
+                // add it to the selfSignedTAs.
+                if (Arrays.equals(
+                        trCert.getSubjectX500Principal().getEncoded(), trCert
+                                .getIssuerX500Principal().getEncoded())) {
+                    selfSignedTAs.add(ta);
+                    selfSignedTAsCerts.add(trCert);
+                } else {// otherwise just add it to the list of
+                    // trusted certs
+                    trustedCerts.add(trCert);
+                }
+            }
+        }
+        
+        // if "-trustcacerts" is specified, add CAs from cacerts
+        if (trustCaCerts) {
+            KeyStore cacertsFile = null;
+            try {
+                cacertsFile = param.getCacerts();
+            } catch (Exception e) {
+                if (trustedExistInKS) {
+                    // if there are trusted certificates in keyStore,
+                    // just print the notification
+                    System.err.println(e.getMessage());
+                } else {// otherwise quit
+                    throw new KeytoolException(strFailed, e);
+                }
+            }
+
+            // if cacerts loaded
+            if (cacertsFile != null) {
+                PKIXBuilderParameters cacertsBuilderParam = null;
+                try {
+                    cacertsBuilderParam = new PKIXBuilderParameters(
+                            cacertsFile, selector);
+                } catch (InvalidAlgorithmParameterException e) {
+                    if (!trustedExistInKS) {
+                        throw new KeytoolException(strFailed + strNoTrusted);
+                    } else {
+                        // if there are trusted certificates in keyStore,
+                        // just return what have now
+                        return new Collection[] { selfSignedTAs, trustedCerts,
+                                selfSignedTAsCerts };
+                    }
+                }
+
+                Set<TrustAnchor> cacertsCAs = cacertsBuilderParam
+                        .getTrustAnchors();
+
+                // if there are no trusted certificates in the
+                // keyStore
+                if (!trustedExistInKS) {
+                    Set trustAnchorsSet = cacertsBuilderParam.getTrustAnchors();
+                    int size = trustAnchorsSet.size();
+                    // usually only self-signed CAs are in the
+                    // cacerts file, so selfSignedTAs is of the
+                    // same size as trustAnchorsSet.
+                    selfSignedTAs = new HashSet(size);
+                    selfSignedTAsCerts = new HashSet(size);
+                    trustedCerts = new ArrayList();
+                }
+
+                Iterator cacertsCAsIter = cacertsCAs.iterator();
+                while (cacertsCAsIter.hasNext()) {
+                    TrustAnchor ta = (TrustAnchor) cacertsCAsIter.next();
+                    X509Certificate trCert = ta.getTrustedCert();
+                    // if the trusted certificate is self-signed,
+                    // add it to the selfSignedTAs.
+                    if (Arrays.equals(trCert.getSubjectX500Principal()
+                            .getEncoded(), trCert.getIssuerX500Principal()
+                            .getEncoded())) {
+                        selfSignedTAs.add(ta);
+                        selfSignedTAsCerts.add(trCert);
+                    } else {// otherwise just add it to the list of
+                        // trusted certs
+                        trustedCerts.add(trCert);
+                    }
+                }
+            }// if (cacertsFile != null)...
+        }// if (trustCacerts)...
+        return new Collection[] { selfSignedTAs, trustedCerts,
+                selfSignedTAsCerts };
+    }
+
+    /**
+     * Orders a collection of certificates into a certificate chain beginning
+     * with the certificate which has public key equal to aliasPubKey.
+     * 
+     * @throws KeytoolException
+     */
+    static X509Certificate[] orderChain(Collection<X509Certificate> certs,
+            PublicKey aliasPubKey) throws KeytoolException {
+
+        String strOrderFailed = "Failed to order the certiticate chain.";
+
+        // add certificates to the certstore to ease the search
+        CollectionCertStoreParameters chainCCSParams = new CollectionCertStoreParameters(
+                certs);
+        CertStore certStore;
+        try {
+            certStore = CertStore.getInstance("Collection", chainCCSParams);
+        } catch (Exception e) {
+            throw new KeytoolException(strOrderFailed, e);
+        }
+
+        // set up selector to search the certificates
+        X509CertSelector selector = new X509CertSelector();
+        // try to find the first certificate in the chain
+        selector.setSubjectPublicKey(aliasPubKey);
+
+        // current certificate
+        X509Certificate current = null;
+        try {
+            current = (X509Certificate) certStore.getCertificates(selector)
+                    .iterator().next();
+        } catch (CertStoreException e) {
+            // do nothing
+        } catch (NoSuchElementException e) {
+            // do nothing
+        }
+
+        if (current == null) {
+            throw new KeytoolException(
+                    "Failed to find the requested public key "
+                            + "in certificate reply.");
+        }
+        // number of certificates in collection
+        int colSize = certs.size();
+        // new chain to return
+        X509Certificate[] ordered = new X509Certificate[colSize];
+        ordered[0] = current;
+        selector.setSubjectPublicKey((PublicKey) null);
+
+        // counter of ordered certificates
+        // it will be incremented later
+        int orderedCnt = 0;
+
+        if (!Arrays.equals(current.getSubjectX500Principal().getEncoded(),
+                current.getIssuerX500Principal().getEncoded())) {
+            // orderedCnt = 1, because the first certificate is already in
+            // the resulting array
+            for (orderedCnt = 1; orderedCnt < colSize; orderedCnt++) {
+                // set new filter
+                selector.setSubject(current.getIssuerX500Principal());
+                try {
+                    // get issuer's certificate
+                    current = (X509Certificate) certStore.getCertificates(
+                            selector).iterator().next();
+                } catch (CertStoreException e) {
+                    throw new KeytoolException(strOrderFailed, e);
+                } catch (NoSuchElementException e) {
+                    break;
+                }
+
+                if (Arrays.equals(current.getSubjectX500Principal()
+                        .getEncoded(), current.getIssuerX500Principal()
+                        .getEncoded())) {
+                    // if self-signed, save it and quit. It is the last.
+                    ordered[orderedCnt] = current;
+                    break;
+                } else {
+                    // add current certificate to the chain and continue
+                    ordered[orderedCnt] = current;
+                }
+            }
+        }
+
+        // If the certificate collection contains certificates which
+        // are not a part of the chain.
+        // ++orderedCnt is used because 'break's don't let the
+        // variable be incremented when it should be.
+        if (++orderedCnt < colSize) {
+            X509Certificate[] orderedShort = new X509Certificate[orderedCnt];
+            System.arraycopy(ordered, 0, orderedShort, 0, orderedCnt);
+            return orderedShort;
+        }
+
+        return ordered;
+    }
+    
+    // orders a chain without a starting element given
+    static X509Certificate[] orderChain(Collection<X509Certificate> certs)
+            throws KeytoolException {
+
+        int certsLen = certs.size();
+        int startPos = -1;
+
+        List<X509Certificate> certsList = new ArrayList<X509Certificate>(certs);
+
+        // searching for the first element of the chain
+        for (int i = 0; i < certsLen; i++) {
+            X509Certificate curCert = certsList.get(i);
+            for (int j = 0; j < certsLen; j++) {
+                if (j != i) {
+                    // if the subject is the issuer of another cert, it is not
+                    // the first in the chain.
+                    if (Arrays.equals(curCert.getSubjectX500Principal()
+                            .getEncoded(), certsList.get(j)
+                            .getIssuerX500Principal().getEncoded())) {
+                        break;
+                    }
+                }
+                // If the certificate's subject is not found to be an issuer to
+                // any other cert in this chain, then it is the first element.
+                if (j == certsLen - 1) {
+                    startPos = i;
+                    break;
+                }
+            }
+            // don't search any more, if the first element is found.
+            if (startPos > -1) {
+                break;
+            }
+        }
+
+        return orderChain(certsList, certsList.get(startPos).getPublicKey());
+    }
+            
+    
+    /**
+     * Checks if the X509Certificate cert is contained as a trusted certificate
+     * entry in keystore and possibly cacerts file (if "-trustcacerts" option is
+     * specified).
+     * 
+     * @param param
+     * @param cert
+     * @return true if the certificate is trused, false - otherwise.
+     * @throws FileNotFoundException
+     * @throws NoSuchAlgorithmException
+     * @throws CertificateException
+     * @throws IOException
+     * @throws KeytoolException
+     * @throws KeyStoreException
+     * @throws NoSuchProviderException
+     */
+    static boolean isTrusted(KeytoolParameters param, X509Certificate cert)
+            throws FileNotFoundException, NoSuchAlgorithmException,
+            CertificateException, IOException, KeytoolException,
+            KeyStoreException, NoSuchProviderException {
+        // check the main keyStore
+        KeyStore keyStore = param.getKeyStore();
+        String alias = keyStore.getCertificateAlias(cert);
+        if (alias != null) {
+            if (keyStore.isCertificateEntry(alias)) {
+                return true;
+            }
+        }
+
+        if (!param.isTrustCACerts()) {
+            return false;
+        } else {// check cacerts file
+            KeyStore cacerts = param.getCacerts();
+            alias = cacerts.getCertificateAlias(cert);
+            if (alias != null) {
+                if (cacerts.isCertificateEntry(alias)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}

Modified: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java?rev=426443&r1=426442&r2=426443&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java Fri Jul 28 01:59:55 2006
@@ -23,7 +23,10 @@
 import java.io.OutputStream;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
 import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 
 import org.apache.harmony.luni.util.Base64;
@@ -36,17 +39,20 @@
 
     /**
      * Reads an X.509 certificate associated with alias and prints it into the
-     * given file. alias and the file name are supplied in param. If the file
+     * given file. alias and the file name are supplied in param. if The file
      * name is not given, the certificate is printed to stdout.
      * 
      * @param param
      * @throws KeyStoreException
-     * @throws CertificateEncodingException
      * @throws IOException
      * @throws KeytoolException
+     * @throws NoSuchProviderException 
+     * @throws CertificateException 
+     * @throws NoSuchAlgorithmException 
      */
     static void exportCert(KeytoolParameters param) throws KeyStoreException,
-            CertificateEncodingException, IOException, KeytoolException {
+            IOException, KeytoolException, NoSuchAlgorithmException,
+            CertificateException, NoSuchProviderException {
         KeyStore keyStore = param.getKeyStore();
         String alias = param.getAlias();
         if (keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {

Added: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertImporter.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertImporter.java?rev=426443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertImporter.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertImporter.java Fri Jul 28 01:59:55 2006
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.tools.keytool;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Class for importing certificates - adding to trusted certificates or
+ * Certificate Signing Request (CSR) replies from certificate authorirties
+ * (CAs). CSR reply can be a single X.509 certificate or a PKCS#7-formatted
+ * certificate chain containing X.509 certificates. X.509 v1, v2 and v3
+ * certificates are supported. Certificates to import can be in binary (DER) or
+ * printable (PEM) encoding format.
+ */
+public class CertImporter {
+
+    /**
+     * Reads an X.509 certificate or a PKCS#7 formatted certificate chain from
+     * the file specified in param and puts it into the entry identified by the
+     * supplied alias. If the input file is not specified, the certificates are
+     * read from the standard input.
+     * 
+     * @param param
+     * @throws KeytoolException
+     * @throws IOException
+     * @throws CertPathBuilderException
+     * @throws UnrecoverableKeyException
+     * @throws NoSuchAlgorithmException
+     * @throws CertificateException
+     * @throws FileNotFoundException
+     * @throws NoSuchProviderException
+     * @throws KeyStoreException
+     */
+    static void importCert(KeytoolParameters param)
+            throws FileNotFoundException, CertificateException,
+            NoSuchAlgorithmException, UnrecoverableKeyException,
+            CertPathBuilderException, IOException, KeytoolException,
+            NoSuchProviderException, KeyStoreException {
+
+        String alias = param.getAlias();
+        KeyStore keyStore = param.getKeyStore();
+        boolean contains = keyStore.containsAlias(alias);
+
+        // if the alias already exists, try to import the certificate as
+        // a cert reply
+        if (contains
+                && keyStore.entryInstanceOf(alias,
+                        KeyStore.PrivateKeyEntry.class)) {
+            // read the certificates
+            Collection<X509Certificate> certCollection = CertReader.readCerts(
+                    param.getFileName(), false, param.getProvider());
+
+            importReply(param, certCollection);
+        } else if (!contains) { // import a trusted certificate
+            // read the certificate
+            Collection<X509Certificate> trustedCert = CertReader.readCerts(
+                    param.getFileName(), true, param.getProvider());
+
+            importTrusted(param, trustedCert.iterator().next());
+        } else {// if the existing entry is not a private key entry
+            throw new KeytoolException(
+                    "Failed to import the certificate. \nAlias <" + alias
+                            + "> already exists and is not a private key entry");
+        }
+    }
+
+    /**
+     * Imports a Certificate Signing Request (CSR) reply - single X.509
+     * certificate or PKCS#7 formatted certificate chain, consisting of X.509
+     * certificates.
+     * 
+     * @param param
+     * @throws FileNotFoundException
+     * @throws CertificateException
+     * @throws IOException
+     * @throws KeyStoreException
+     * @throws NoSuchAlgorithmException
+     * @throws UnrecoverableKeyException
+     * @throws CertPathBuilderException
+     * @throws InvalidAlgorithmParameterException
+     * @throws KeytoolException
+     * @throws NoSuchProviderException
+     */
+    private static void importReply(KeytoolParameters param,
+            Collection<X509Certificate> certCollection)
+            throws FileNotFoundException, CertificateException, IOException,
+            KeyStoreException, NoSuchAlgorithmException,
+            UnrecoverableKeyException, CertPathBuilderException,
+            KeytoolException, NoSuchProviderException {
+        if (certCollection.size() == 1) {
+            importSingleX509Reply(param, certCollection.iterator().next());
+        } else if (certCollection.size() > 0) {
+            importCertChain(param, certCollection);
+        }
+    }
+
+    /**
+     * Imports a single X.509 certificate Certificate Signing Request (CSR)
+     * reply.
+     * 
+     * @param param
+     * @param newCert
+     * @throws CertificateException
+     * @throws FileNotFoundException
+     * @throws IOException
+     * @throws KeyStoreException
+     * @throws NoSuchAlgorithmException
+     * @throws UnrecoverableKeyException
+     * @throws CertPathBuilderException
+     * @throws KeytoolException
+     * @throws NoSuchProviderException
+     */
+
+    private static void importSingleX509Reply(KeytoolParameters param,
+            X509Certificate newCert) throws CertificateException,
+            FileNotFoundException, IOException, KeyStoreException,
+            NoSuchAlgorithmException, UnrecoverableKeyException,
+            CertPathBuilderException, KeytoolException, NoSuchProviderException {
+
+        String alias = param.getAlias();
+        KeyStore keyStore = param.getKeyStore();
+
+        // the certificate to be replaced with certificate reply.
+        X509Certificate csrCert = (X509Certificate) keyStore
+                .getCertificate(alias);
+        // quit if public keys of the imported certificate and csrCert don't
+        // match
+        PublicKey publicKey = csrCert.getPublicKey();
+        if (!Arrays.equals(publicKey.getEncoded(), newCert.getPublicKey()
+                .getEncoded())) {
+            throw new KeytoolException("Public keys don't match.");
+        }
+        // quit if the certificates are identical
+        if (newCert.equals(csrCert)) {
+            throw new KeytoolException("Certificate reply is identical to the "
+                    + "certificate in keystore");
+        }
+
+        // save the private key to put it in a newly created entry
+        PrivateKey privateKey;
+        try {
+            privateKey = (PrivateKey) keyStore
+                    .getKey(alias, param.getKeyPass());
+        } catch (NoSuchAlgorithmException e) {
+            throw new NoSuchAlgorithmException(
+                    "Cannot find the algorithm to recover the key. ", e);
+        }
+
+        X509Certificate[] newChain = CertChainVerifier.buildFullCertPath(param,
+                newCert);
+
+        // changing the certificate chain //
+        // remove the entry with old certificate chain
+        keyStore.deleteEntry(alias);
+
+        // set the new certificate chain
+        keyStore.setKeyEntry(alias, privateKey, param.getKeyPass(), newChain);
+        param.setNeedSaveKS(true);
+        System.out
+                .println("Certificate reply is successfully installed into the keystore.");
+    }
+
+    /**
+     * Imports an X.509 certificate into a trusted certificate entry.
+     * 
+     * @param param
+     * @throws KeytoolException
+     * @throws IOException
+     * @throws CertPathBuilderException
+     * @throws CertificateException
+     * @throws NoSuchAlgorithmException
+     * @throws KeyStoreException
+     * @throws NoSuchProviderException
+     */
+    private static void importTrusted(KeytoolParameters param,
+            X509Certificate newCert) throws NoSuchAlgorithmException,
+            CertificateException, CertPathBuilderException, IOException,
+            KeytoolException, KeyStoreException, NoSuchProviderException {
+        String alias = param.getAlias();
+        KeyStore keyStore = param.getKeyStore();
+
+        // should the certificate be added to the store or not
+        boolean addIt = false;
+
+        // if "-noprompt" option has been specified, don't make
+        // additional checks.
+        if (param.isNoPrompt()) {
+            addIt = true;
+        } else {
+            // search for an equal certificate in the keystore
+            String equalCertName = keyStore.getCertificateAlias(newCert);
+
+            if (equalCertName != null) {
+                // if an equal certificate exists in the store
+                System.out.println("The certificate already exists in the "
+                        + "keystore under alias <" + equalCertName + ">");
+                // ask if a duplicating certificate should be added to the
+                // store
+                addIt = ArgumentsParser.getConfirmation(
+                        "Do you still want to add it? [no] ", false);
+            } else {
+                try {
+                    if (CertChainVerifier.buildCertPath(param, newCert) != null) {
+                        addIt = true;
+                    }
+                } catch (Exception e) {
+                    // if the certificate chain cannot be built
+                    // print it and ask if it should be trusted or not.
+                    KeyStoreCertPrinter.printX509CertDetailed(newCert, param
+                            .getProvider());
+                    addIt = ArgumentsParser.getConfirmation(
+                            "Trust this certificate? [no] ", false);
+                }
+            }
+        }
+        if (addIt) {
+            keyStore.setCertificateEntry(alias, newCert);
+            param.setNeedSaveKS(true);
+            System.out.println("The certificate is added to the keystore\n");
+        } else {
+            System.out
+                    .println("The certificate is not added to the keystore\n");
+        }
+    }
+
+    /**
+     * Imports a PKCS#7-formatted certificate chain as a CSR reply. The
+     * certificte chain is firstly ordered. After that top-level certificate of
+     * the chain is checked to be a trusted one. If it is not a trusted
+     * certificate, the user is asked if the certificate should be trusted. If
+     * the certificate is considered to be trusted, old certificate chain,
+     * associated with param.getAlias() is replaced with the new one.
+     * Certificates can be in DER or PEM format.
+     * 
+     * @param param
+     * @param newCerts
+     * @throws Exception
+     * @throws NoSuchAlgorithmException
+     * @throws KeytoolException
+     * @throws KeyStoreException
+     * @throws IOException
+     * @throws UnrecoverableKeyException
+     * @throws NoSuchProviderException
+     * @throws CertificateException 
+     */
+    private static void importCertChain(KeytoolParameters param,
+            Collection<X509Certificate> newCerts)
+            throws NoSuchAlgorithmException, KeytoolException,
+            KeyStoreException, IOException, UnrecoverableKeyException,
+            NoSuchProviderException, CertificateException {
+
+        String alias = param.getAlias();
+        KeyStore keyStore = param.getKeyStore();
+        // get the public key of the certiciate, associated with alias,
+        // to import reply to.
+        PublicKey publicKey = keyStore.getCertificate(alias).getPublicKey();
+        // order the certificate chain
+        X509Certificate[] orderedChain = CertChainVerifier.orderChain(newCerts,
+                publicKey);
+        // get the top-level certificate in the chain
+        X509Certificate lastInChain = orderedChain[orderedChain.length - 1];
+
+        // should the chain be added to the keystore or not
+        boolean needAddChain;
+        // try to build a chain of trust beginning with the top certificate
+        needAddChain = CertChainVerifier.isTrusted(param, lastInChain);
+
+        if (!needAddChain) {
+            // If couldn't build full cert path for some reason,
+            // ask user if the certificate should be trusted.
+            System.out.println("Top-level certificate in the reply chain:\n");
+            KeyStoreCertPrinter.printX509CertDetailed(lastInChain, param
+                    .getProvider());
+            needAddChain = ArgumentsParser.getConfirmation("... is not trusted.\n"
+                    + "Do you still want to install the reply? [no]:  ", false);
+            
+            if (!needAddChain) {
+                System.out.println("The certificate reply is " + "not "
+                        + "installed into the keystore.");
+                return;
+            }
+        }
+
+        // replacing old certificate chain with the new one
+        char[] keyPassword = param.getKeyPass();
+        PrivateKey privateKey = (PrivateKey) keyStore
+                .getKey(alias, keyPassword);
+        keyStore.deleteEntry(alias);
+        keyStore.setKeyEntry(alias, privateKey, keyPassword, orderedChain);
+        param.setNeedSaveKS(true);
+        System.out.println("The certificate reply is " + "successfully "
+                + "installed into the keystore.");
+    }
+
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertReader.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertReader.java?rev=426443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertReader.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertReader.java Fri Jul 28 01:59:55 2006
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.tools.keytool;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.NoSuchProviderException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Class for reading an X.509 certificate or an X.509 certificate chain from the
+ * file or standard input.
+ */
+public class CertReader {
+    // certificate factory to read certificates and CRLs
+    private static CertificateFactory certFactory;
+    // time to wait for user to input the data.
+    // need this for user to have time to paste the certificate to stdin.
+    private static long sleepPeriod;
+
+    
+    /**
+     * Reads an X.509 certificate or a certificate chain from the file with the
+     * given name or from stdin if the fileName is null and generates a
+     * collection of Certifices.
+     * 
+     * @param fileName
+     * @param readOnlyFirst
+     * @param providerName
+     * @return
+     * @throws NoSuchProviderException 
+     * @throws CertificateException 
+     * @throws KeytoolException 
+     * @throws IOException 
+     */
+    static Collection readCerts(String fileName, boolean readOnlyFirst,
+            String providerName) throws CertificateException,
+            NoSuchProviderException, IOException, KeytoolException {
+
+        InputStream input = getInputStream(fileName);
+        CertificateFactory factory = getCertificateFactory(providerName);
+        if (input == System.in){
+            System.out.println("Please, input certificate(s)...");
+        }
+        try {
+            // let the user paste the certificates or CRLs, if read from stdin.
+            // If reading from file, don't sleep.
+            Thread.sleep(sleepPeriod);
+        } catch (InterruptedException e) {
+            // do nothing
+        }
+
+        // if the file is empty or nothing was entered
+        // FIXME: remove available. Try to read and catch exception?
+        if (input.available() <= 0) {
+            throw new KeytoolException("Empty input");
+        }
+
+        Collection certCollection;
+        try {
+            // if only the first certificate is requested, return a
+            // single-element Collection
+            if (readOnlyFirst) {
+                certCollection = Collections.singleton(factory
+                        .generateCertificate(input));
+            } else {
+                certCollection = factory.generateCertificates(input);
+            }
+            if (input != System.in) {
+                input.close();
+            }
+            return certCollection;
+        } catch (CertificateException e) {
+            throw new CertificateException(
+                    "Failed to generate a certificate from the input. ", e);
+        }
+    }
+
+    /**
+     * Reads CRLs from the file with given name and generates a collection of
+     * CRLs.
+     * 
+     * @param fileName
+     * @param providerName
+     * @return
+     * @throws NoSuchProviderException
+     * @throws CertificateException
+     * @throws KeytoolException
+     * @throws IOException
+     * @throws CRLException
+     * 
+     */
+    static Collection readCRLs(String fileName, String providerName)
+            throws CertificateException, NoSuchProviderException, IOException,
+            KeytoolException, CRLException {
+
+        InputStream input = getInputStream(fileName);
+        CertificateFactory factory = getCertificateFactory(providerName);
+        if (input == System.in){
+            System.out.println("Please, input CRL(s)...");
+        }
+        try {
+            // let the user paste the certificates or CRLs, if read from stdin.
+            // If reading from file, don't sleep.
+            Thread.sleep(sleepPeriod);
+        } catch (InterruptedException e) {
+            // do nothing
+        }
+
+        // if the file is empty or nothing was entered
+        // FIXME: remove available. Try to read and catch exception?
+        if (input.available() <= 0) {
+            throw new KeytoolException("Empty input");
+        }
+
+        try {
+            Collection crlCollection = factory.generateCRLs(input);
+            if (input != System.in) {
+                input.close();
+            }
+            return crlCollection;
+        } catch (CRLException e) {
+            throw new CRLException("Failed to generate a CRL from the input. ",
+                    e);
+        }
+    }
+
+    
+    // Returns an input stream - FileInputStream or System.in.
+    private static InputStream getInputStream(String fileName)
+            throws FileNotFoundException {
+        if (fileName != null) {
+            sleepPeriod = 0;
+            // use the file if its name is specified
+            return new FileInputStream(fileName);
+        } else {// if the file name is not given, use stdin
+            sleepPeriod = 3000;
+            return System.in;
+        }
+    }
+
+    // Sets certFactory if it is still not set and returns it
+    private static CertificateFactory getCertificateFactory(String providerName)
+            throws CertificateException, NoSuchProviderException {
+        if (certFactory == null) {
+            try {
+                if (providerName == null) {
+                    certFactory = CertificateFactory.getInstance("X.509");
+                } else {
+                    certFactory = CertificateFactory.getInstance("X.509",
+                            providerName);
+                }
+            } catch (CertificateException e) {
+                throw new CertificateException(
+                        "This type of certificate is not "
+                                + "available from the provider. ", e);
+            } catch (NoSuchProviderException e) {
+                throw (NoSuchProviderException) new NoSuchProviderException(
+                        "The provider " + providerName
+                                + " is not found in the environment.")
+                        .initCause(e);
+            }
+        }
+        return certFactory;
+    }
+}

Modified: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/Command.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/Command.java?rev=426443&r1=426442&r2=426443&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/Command.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/Command.java Fri Jul 28 01:59:55 2006
@@ -37,8 +37,8 @@
     CERTREQ,
     // check a CRL
     CHECK,
-    // add a certificate to a CRL
-    ADD,
+    // convert keystore to another format
+    CONVERT,
     // verify a certificate chain
     VERIFY,
     // copy a key entry into a newly created one

Modified: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/EntryManager.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/EntryManager.java?rev=426443&r1=426442&r2=426443&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/EntryManager.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/EntryManager.java Fri Jul 28 01:59:55 2006
@@ -16,12 +16,16 @@
 
 package org.apache.harmony.tools.keytool;
 
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.security.Key;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
 
 /**
  * Class for managing keystore entries - cloning, deleting, changing entry
@@ -38,10 +42,15 @@
      * @throws NoSuchAlgorithmException
      * @throws KeyStoreException
      * @throws KeytoolException
+     * @throws IOException 
+     * @throws NoSuchProviderException 
+     * @throws FileNotFoundException 
+     * @throws CertificateException 
      */
     static void keyClone(KeytoolParameters param) throws KeyStoreException,
             NoSuchAlgorithmException, UnrecoverableKeyException,
-            KeytoolException {
+            KeytoolException, CertificateException, FileNotFoundException,
+            NoSuchProviderException, IOException {
         KeyStore keyStore = param.getKeyStore();
         String alias = param.getAlias();
         Key srcKey;
@@ -67,8 +76,17 @@
      * 
      * @param param
      * @throws KeyStoreException
+     * @throws KeytoolException 
+     * @throws IOException 
+     * @throws NoSuchProviderException 
+     * @throws FileNotFoundException 
+     * @throws CertificateException 
+     * @throws NoSuchAlgorithmException 
      */
-    static void delete(KeytoolParameters param) throws KeyStoreException {
+    static void delete(KeytoolParameters param) throws KeyStoreException,
+            NoSuchAlgorithmException, CertificateException,
+            FileNotFoundException, NoSuchProviderException, IOException,
+            KeytoolException {
         param.getKeyStore().deleteEntry(param.getAlias());
         param.setNeedSaveKS(true);
     }
@@ -80,9 +98,16 @@
      * @throws KeyStoreException
      * @throws NoSuchAlgorithmException
      * @throws UnrecoverableKeyException
+     * @throws KeytoolException 
+     * @throws IOException 
+     * @throws NoSuchProviderException 
+     * @throws FileNotFoundException 
+     * @throws CertificateException 
      */
     static void keyPasswd(KeytoolParameters param) throws KeyStoreException,
-            NoSuchAlgorithmException, UnrecoverableKeyException {
+            NoSuchAlgorithmException, UnrecoverableKeyException,
+            CertificateException, FileNotFoundException,
+            NoSuchProviderException, IOException, KeytoolException {
         KeyStore keyStore = param.getKeyStore();
         String alias = param.getAlias();
         Key key;

Added: incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/HelpPrinter.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/HelpPrinter.java?rev=426443&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/HelpPrinter.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/tools/src/main/java/org/apache/harmony/tools/keytool/HelpPrinter.java Fri Jul 28 01:59:55 2006
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.harmony.tools.keytool;
+
+/**
+ * Class for printing help messages .
+ */
+public class HelpPrinter {
+    /**
+     * Prints the help message.
+     */
+    static void printHelp() {
+        // TODO
+        System.out.println("Help message here");
+    }
+}