Index: modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java =================================================================== --- modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java (revision 414567) +++ modules/tools/src/main/java/org/apache/harmony/tools/keytool/ArgumentsParser.java (working copy) @@ -16,6 +16,8 @@ package org.apache.harmony.tools.keytool; +import java.io.IOException; + /** * The class to interact with the user - parse the program arguments, ask for * confirmations, and necessary parameters which haven't been set in the command @@ -94,8 +96,10 @@ final static String sNew = "-new"; - final static String sCertalias = "-certalias"; + final static String sIssuerAlias = "-issuer"; + final static String sIssuerPass = "-issuerpass"; + final static String sCertstore = "-certstore"; final static String sSecretkey = "-secretkey"; @@ -112,13 +116,228 @@ * 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 + * @throws IOException */ - static KeytoolParameters parseArgs(String[] args) { - // TODO: look for known options and get their values + static KeytoolParameters parseArgs(String[] args) throws KeytoolException, + IOException { if (args == null || args.length == 0) { return null; } KeytoolParameters param = new KeytoolParameters(); + + // look for known options and get their values. + try { + for (int i = 0; i < args.length; i++) { + + // commands + if (args[i].compareToIgnoreCase(sGenkey) == 0) { + param.setCommand(Command.GENKEY); + continue; + } + if (args[i].compareToIgnoreCase(sSelfcert) == 0) { + param.setCommand(Command.SELFCERT); + continue; + } + if (args[i].compareToIgnoreCase(sImport) == 0) { + param.setCommand(Command.IMPORT); + continue; + } + if (args[i].compareToIgnoreCase(sExport) == 0) { + param.setCommand(Command.EXPORT); + continue; + } + if (args[i].compareToIgnoreCase(sStorepasswd) == 0) { + param.setCommand(Command.STOREPASSWD); + continue; + } + if (args[i].compareToIgnoreCase(sKeypasswd) == 0) { + param.setCommand(Command.KEYPASSWD); + continue; + } + if (args[i].compareToIgnoreCase(sCertreq) == 0) { + param.setCommand(Command.CERTREQ); + continue; + } + if (args[i].compareToIgnoreCase(sCheck) == 0) { + param.setCommand(Command.CHECK); + continue; + } + if (args[i].compareToIgnoreCase(sAdd) == 0) { + param.setCommand(Command.ADD); + continue; + } + if (args[i].compareToIgnoreCase(sVerify) == 0) { + param.setCommand(Command.VERIFY); + continue; + } + if (args[i].compareToIgnoreCase(sPrintcert) == 0) { + param.setCommand(Command.PRINTCERT); + continue; + } + if (args[i].compareToIgnoreCase(sKeyclone) == 0) { + param.setCommand(Command.KEYCLONE); + continue; + } + if (args[i].compareToIgnoreCase(sDelete) == 0) { + param.setCommand(Command.DELETE); + continue; + } + if (args[i].compareToIgnoreCase(sList) == 0) { + param.setCommand(Command.LIST); + continue; + } + if (args[i].compareToIgnoreCase(sHelp) == 0) { + param.setCommand(Command.HELP); + continue; + } + + // additional options + if (args[i].compareToIgnoreCase(sKeystore) == 0) { + param.setStorePath(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sStoretype) == 0) { + param.setStoreType(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sProvider) == 0) { + param.setProvider(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sAlias) == 0) { + param.setAlias(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sKeyalg) == 0) { + param.setKeyAlg(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sSigalg) == 0) { + param.setSigAlg(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sDname) == 0) { + param.setDName(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sFile) == 0) { + param.setFileName(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sIssuerAlias) == 0) { + 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; + } + if (args[i].compareToIgnoreCase(sKeypass) == 0) { + param.setKeyPass(args[++i].toCharArray()); + continue; + } + if (args[i].compareToIgnoreCase(sIssuerPass) == 0) { + param.setIssuerPass(args[++i].toCharArray()); + continue; + } + if (args[i].compareToIgnoreCase(sCRLstore) == 0) { + param.setCrlStore(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sDestAlias) == 0) { + param.setDestAlias(args[++i]); + continue; + } + if (args[i].compareToIgnoreCase(sNew) == 0) { + param.setNewPasswd(args[++i].toCharArray()); + continue; + } + if (args[i].compareToIgnoreCase(sKeysize) == 0) { + + param.setKeySize((new Integer(args[++i])).intValue()); + if (param.getKeySize() <= 0) { + throw new KeytoolException("Key size" + + " must be more than zero."); + } + continue; + } + if (args[i].compareToIgnoreCase(sValidity) == 0) { + param.setValidity((new Integer(args[++i])).intValue()); + if (param.getValidity() <= 0) { + throw new KeytoolException("Validity" + + " must be more than zero."); + } + continue; + } + if (args[i].compareToIgnoreCase(sX509Version) == 0) { + param.setX509version((new Integer(args[++i])).intValue()); + if (param.getX509version() < 1 + || param.getX509version() > 3) { + throw new KeytoolException( + "Certificate version must be " + "1, 2 or 3"); + } + continue; + } + if (args[i].compareToIgnoreCase(sCertSerial) == 0) { + param.setCertSerialNr((new Integer(args[++i])).intValue()); + if (param.getCertSerialNr() <= 0) { + throw new KeytoolException("Certificate serial number" + + " must be more than zero."); + } + continue; + } + + // flags + if (args[i].compareToIgnoreCase(sNoprompt) == 0) { + param.setNoPrompt(true); + continue; + } + if (args[i].compareToIgnoreCase(sTrustcacerts) == 0) { + param.setTrustCACerts(true); + continue; + } + if (args[i].compareToIgnoreCase(sRfc) == 0) { + param.setRfc(true); + continue; + } + if (args[i].compareToIgnoreCase(sV) == 0) { + param.setVerbose(true); + continue; + } + if (args[i].compareToIgnoreCase(sSecretkey) == 0) { + param.setSecretKey(true); + continue; + } + + System.out.println("Illegal option: " + args[i]); + return null; + } + } catch (ArrayIndexOutOfBoundsException e) { + // 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. + if (cmd == Command.LIST && param.isRfc() && param.isVerbose()) { + throw new KeytoolException("There must not be both -v and -rfc " + + "options specified"); + } + + // skip the store password setting if -printcert or -help commands were + // given. + if (cmd == Command.PRINTCERT || cmd == Command.HELP) { + return param; + } + + // TODO: if the store password has not been entered, prompt for it return param; } @@ -129,5 +348,4 @@ // TODO throw new RuntimeException("The method is not implemented yet."); } - } Index: modules/tools/src/main/java/org/apache/harmony/tools/keytool/Main.java =================================================================== --- modules/tools/src/main/java/org/apache/harmony/tools/keytool/Main.java (revision 414567) +++ modules/tools/src/main/java/org/apache/harmony/tools/keytool/Main.java (working copy) @@ -16,6 +16,7 @@ package org.apache.harmony.tools.keytool; + /** * The main class that bundles command line parsing, interaction with the user * and work with keys and certificates. @@ -30,8 +31,12 @@ * param. If something goes wrong an exception is thrown. */ static void doWork(KeytoolParameters param) throws Exception { - // TODO - throw new RuntimeException("The method is not implemented yet."); + switch (param.getCommand()) { + case EXPORT: + CertExporter.exportCert(param); + break; + // TODO: calls for other options. + } } /** @@ -41,8 +46,50 @@ * command line with options. */ public static void run(String[] args) throws Exception { - // TODO - throw new RuntimeException("The method is not implemented yet."); + KeytoolParameters param = ArgumentsParser.parseArgs(args); + + if (param == null) { + System.out.println("Help message is printed here"); + System.exit(-1); + } + + Command command = param.getCommand(); + + // all commands except printcert and help work with a store + if (command != Command.PRINTCERT && command != Command.HELP) { + // all commands that work with store except list and export + // need store password to with keystore. + if (param.getStorePass() == null && command != Command.LIST + && command != Command.EXPORT) { + throw new KeytoolException( + "Must specify store password to work with this command."); + } + // load the keystore + KeyStoreLoaderSaver.loadStore(param); + // prompt for additional parameters if some of the expected + // ones have not been specified. + ArgumentsParser.getAdditionalParameters(param); + } + + // print the warning if store password is not set + if (param.getStorePass() == null) { + System.out + .println("\nWARNING!!!\nThe integrity of the keystore data " + + "has NOT been checked!\n" + + "To check it you must provide your keystore password!\n"); + } + + // the work is being done here + doWork(param); + + if (param.isNeedSaveKS()) { + // if the program should output additional information, do it + if (param.isVerbose()) { + System.out.println("[Saving " + param.getStorePath() + "]"); + } + // save the store + KeyStoreLoaderSaver.saveStore(param); + } } /** Index: modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java =================================================================== --- modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java (revision 0) +++ modules/tools/src/main/java/org/apache/harmony/tools/keytool/CertExporter.java (revision 0) @@ -0,0 +1,101 @@ +/* + * 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.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.apache.harmony.luni.util.Base64; + +/** + * Class for exporting the certificates to a file or stdout in DER or PEM + * formats. + */ +public class CertExporter { + + /** + * 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 + * name is not given, the certificate is printed to stdout. + * + * @param param + * @throws KeyStoreException + * @throws CertificateEncodingException + * @throws IOException + * @throws KeytoolException + */ + static void exportCert(KeytoolParameters param) throws KeyStoreException, + CertificateEncodingException, IOException, KeytoolException { + KeyStore keyStore = param.getKeyStore(); + String alias = param.getAlias(); + if (keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) { + throw new KeytoolException("The alias <" + alias + + "> points to a secret key entry.\n" + + "It has no certificates."); + } + + X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias); + byte[] encodedCert; + try { + encodedCert = cert.getEncoded(); + } catch (CertificateEncodingException e) { + throw new CertificateEncodingException( + "Failed to encode the certificate", e); + } + + OutputStream output; + String fileName = param.getFileName(); + // if no file name is given, output to System.out + if (fileName == null) { + output = System.out; + } else { // output to a file if the name is supplied + File file = new File(fileName); + // the file will be created if it doesn't already exist. + // If it already exists and is not a file, then an IOException will + // be thrown. + file.createNewFile(); + + output = new BufferedOutputStream(new FileOutputStream(file)); + } + + if (param.isRfc()) { + output.write("-----BEGIN CERTIFICATE-----\n".getBytes()); + output.write(Base64.encode(encodedCert, "ISO-8859-1").getBytes()); + output.write("\n-----END CERTIFICATE-----\n".getBytes()); + } else { + output.write(encodedCert); + } + output.flush(); + if (output != System.out) { + output.close(); + + if (param.isVerbose()) { + System.out.println("The certificate is stored in file <" + + fileName + ">."); + } + } + } + +} +