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");
+ }
+}