summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaif S. Naffah <raif@swiftdsl.com.au>2006-05-02 01:24:37 +0000
committerRaif S. Naffah <raif@swiftdsl.com.au>2006-05-02 01:24:37 +0000
commit2c5e33550737362b8e9277c9a8caeb86dc9db762 (patch)
tree667a81c5aa6e93bc2fb9ece5b4bf81afe13916b5
parent2f87c016b0638a8174c9d5d63b85f7ca080413d9 (diff)
downloadclasspath-2c5e33550737362b8e9277c9a8caeb86dc9db762.tar.gz
2006-05-02 Raif S. Naffah <raif@swiftdsl.com.au>
* tools/keytool.sh.in: New file. * tools/gnu/classpath/tools/keytool/CertReqCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/Command.java: Likewise. * tools/gnu/classpath/tools/keytool/DeleteCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/ExportCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/GenKeyCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/IdentityDBCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/ImportCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/KeyCloneCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/ListCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/Main.java: Likewise. * tools/gnu/classpath/tools/keytool/Messages.java: Likewise. * tools/gnu/classpath/tools/keytool/PrintCertCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/SelfCertCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/StorePasswdCmd.java: Likewise. * tools/gnu/classpath/tools/keytool/keytool.txt: Likewise. * tools/gnu/classpath/tools/keytool/package.html: Likewise. * resource/gnu/classpath/tools/keytool/MessageBundle.properties: Likewise.
-rw-r--r--ChangeLog22
-rw-r--r--resource/gnu/classpath/tools/keytool/MessageBundle.properties95
-rw-r--r--tools/gnu/classpath/tools/keytool/CertReqCmd.java405
-rw-r--r--tools/gnu/classpath/tools/keytool/Command.java1147
-rw-r--r--tools/gnu/classpath/tools/keytool/DeleteCmd.java235
-rw-r--r--tools/gnu/classpath/tools/keytool/ExportCmd.java266
-rw-r--r--tools/gnu/classpath/tools/keytool/GenKeyCmd.java511
-rw-r--r--tools/gnu/classpath/tools/keytool/IdentityDBCmd.java185
-rw-r--r--tools/gnu/classpath/tools/keytool/ImportCmd.java751
-rw-r--r--tools/gnu/classpath/tools/keytool/KeyCloneCmd.java344
-rw-r--r--tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java339
-rw-r--r--tools/gnu/classpath/tools/keytool/ListCmd.java380
-rw-r--r--tools/gnu/classpath/tools/keytool/Main.java219
-rw-r--r--tools/gnu/classpath/tools/keytool/Messages.java115
-rw-r--r--tools/gnu/classpath/tools/keytool/PrintCertCmd.java123
-rw-r--r--tools/gnu/classpath/tools/keytool/SelfCertCmd.java371
-rw-r--r--tools/gnu/classpath/tools/keytool/StorePasswdCmd.java275
-rw-r--r--tools/gnu/classpath/tools/keytool/keytool.txt616
-rw-r--r--tools/gnu/classpath/tools/keytool/package.html65
-rw-r--r--tools/keytool.sh.in63
20 files changed, 6527 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index ed9bf5cc6..4a33e5adb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,27 @@
2006-05-02 Raif S. Naffah <raif@swiftdsl.com.au>
+ * tools/keytool.sh.in: New file.
+ * tools/gnu/classpath/tools/keytool/CertReqCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/Command.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/DeleteCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/ExportCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/GenKeyCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/IdentityDBCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/ImportCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/KeyCloneCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/ListCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/Main.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/Messages.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/PrintCertCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/SelfCertCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/StorePasswdCmd.java: Likewise.
+ * tools/gnu/classpath/tools/keytool/keytool.txt: Likewise.
+ * tools/gnu/classpath/tools/keytool/package.html: Likewise.
+ * resource/gnu/classpath/tools/keytool/MessageBundle.properties: Likewise.
+
+2006-05-02 Raif S. Naffah <raif@swiftdsl.com.au>
+
* tools/gnu/classpath/tools/jarsigner/jarsigner.txt: Re-arranged to
resemble more closely man-page style text.
* tools/gnu/classpath/tools/jarsigner/SFHelper.java:
diff --git a/resource/gnu/classpath/tools/keytool/MessageBundle.properties b/resource/gnu/classpath/tools/keytool/MessageBundle.properties
new file mode 100644
index 000000000..2dd3ce2fc
--- /dev/null
+++ b/resource/gnu/classpath/tools/keytool/MessageBundle.properties
@@ -0,0 +1,95 @@
+# default locale messages for gnu.classpath.tools.keytool package
+
+Main.6=keytool:
+Main.8=keytool error:
+
+Command.19=Failed creating new file at {0}
+Command.20=Unable to find a suitable signature algorithm named {0}, although we found a key-pair generation algorithm named {1}
+Command.21=Enter key password for <{0}>:
+Command.23=A correct key password MUST be provided
+Command.24=Enter key store password:
+#Command.36=Option '-keystore' is undefined, or is an empty string, and 'user.home' is unknown
+Command.36=Unable to locate a valid key store
+Command.40=Provider fully qualified class name:
+Command.42=File object [{0}] exists but is NOT a file
+Command.44=File [{0}] exists but is NOT writable
+Command.46=File object [{0}] MUST be an existing readable file
+Command.48=Signature algorithm is missing and private key is of unknown or unsupported type
+Command.51=Validity period MUST be greater than zero
+Command.52=Unable to get signature algorithm name
+Command.60=Unknown or unsupported signature algorithm: {0}
+Command.63=Saving key store at {0}
+Command.66=Owner: {0}
+Command.67=Issuer: {0}
+Command.68=Serial number: {0,number}
+Command.69=Valid from: {0,date,full} - {0,time,full}
+Command.70=\ \ \ \ \ until: {0,date,full} - {0,time,full}
+Command.71=Certificate fingerprints
+Command.72=\ \ \ \ \ \ MD5: {0}
+Command.73=\ \ SHA-160: {0}
+Command.75=Alias [{0}] MUST be knwon to the key store
+Command.77=Alias [{0}] MUST be associated with a Key Entry
+
+CertReqCmd.27=Certification request stored in {0}
+CertReqCmd.28=Submit this to your CA
+
+DeleteCmd.19=Enter the Alias to delete:
+DeleteCmd.20=Alias MUST NOT be null or an empty string
+
+GenKeyCmd.0=\nYou are about to enter information that will be incorporated into\n\
+your certificate request. This information is what is called a\n\
+Distinguished Name or DN. There are quite a few fields but you\n\
+can use supplied default values, displayed between brackets, by just\n\
+hitting <Enter>, or blank the field by entering the <.> character\n\
+before hitting <Enter>.\n\n
+GenKeyCmd.6=The Sample Company
+GenKeyCmd.7=Sydney
+GenKeyCmd.8=NSW
+GenKeyCmd.9=AU
+GenKeyCmd.10=Common Name (hostname, IP, or your name):
+GenKeyCmd.11=Organization Name (company) [{0}]:
+GenKeyCmd.13=Organizational Unit Name (department, division):
+GenKeyCmd.14=Locality Name (city, district) [{0}]:
+GenKeyCmd.16=State or Province Name (full name) [{0}]:
+GenKeyCmd.18=Country Name (2 letter code) [{0}]:
+GenKeyCmd.54=Key size MUST be greater than zero
+
+StorePasswdCmd.19=Too many failed attempts
+StorePasswdCmd.20=Enter new key store password:
+StorePasswdCmd.21=Password MUST be at least 6 characters.
+StorePasswdCmd.22=New password MUST be different than the old one.
+StorePasswdCmd.23=Re-enter new key store password:
+StorePasswdCmd.24=Passwords MUST be the same in both attempts.
+
+KeyPasswdCmd.24=Enter new key password for <{0}>:
+KeyPasswdCmd.28=Re-enter new key password for <{0}>:
+
+KeyCloneCmd.23=Destination Alias MUST NOT exist in key store
+KeyCloneCmd.26=Enter destination alias:
+KeyCloneCmd.27=Destination alias MUST NOT be null nor empty
+KeyCloneCmd.28=Enter new key password for <{0}> [{1}]:
+
+ListCmd.21=Key store type: {0}
+ListCmd.22=Key store provider: {0}
+ListCmd.24=Key store contains {0,number} entry(ies)
+ListCmd.30=Alias name: {0}
+ListCmd.31=Creation timestamp: {0,date,full} - {0,time,full}
+ListCmd.32=Entry type: trusted-certificate
+ListCmd.33=Entry type: key-entry
+ListCmd.34=Alias [{0}] is unknown to the key store
+ListCmd.38=Certificate chain length: {0,number}
+ListCmd.39=Certificate[1]:
+ListCmd.40=Certificate[{0,number}]:
+ListCmd.42=*******************************************
+ListCmd.43=-----BEGIN CERTIFICATE-----
+ListCmd.44=-----END CERTIFICATE-----
+ListCmd.45=Certificate fingerprint (MD5): {0}
+
+ImportCmd.34=Failed to establish chain-of-trust from reply
+ImportCmd.37=Unable to find anchor certificate for {0}
+ImportCmd.38=Public keys, in key store and certificate, MUST be of the same type
+ImportCmd.32=Can this certificate be trusted?
+ImportCmd.40=Key entry associated with {0} has an unknown or unsupported public key type {1}
+ImportCmd.41=Public keys, in key store and certificate, MUST be the same
+ImportCmd.29=Certificate was added to the key store
+ImportCmd.28=Certificate was not added to the key store
diff --git a/tools/gnu/classpath/tools/keytool/CertReqCmd.java b/tools/gnu/classpath/tools/keytool/CertReqCmd.java
new file mode 100644
index 000000000..0c64246e8
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/CertReqCmd.java
@@ -0,0 +1,405 @@
+/* CertReqCmd.java -- The certreq command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.java.security.OID;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.util.Base64;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The <b>-certreq</b> keytool command handler is used to generate a Certificate
+ * Signing Request (CSR) in PKCS#10 format.
+ * <p>
+ * The ASN.1 specification of a CSR, as stated in RFC-2986 is as follows:
+ * <p>
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version INTEGER -- v1(0)
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo,
+ * attributes [0] IMPLICIT Attributes -- see note later
+ * }
+ *
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ * </pre>
+ * <b>IMPORTANT</b>: Some documentation (e.g. RSA examples) claims that the
+ * <code>attributes</code> field is <i>OPTIONAL</i> while <i>RFC-2986</i>
+ * implies the opposite. This implementation considers this field, by default,
+ * as <i>OPTIONAL</i>, unless the option <code>-attributes</code> is included
+ * on the command line.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-sigalg ALGORITHM</dt>
+ * <dd>The canonical name of the digital signature algorithm to use for
+ * signing the certificate. If this option is omitted, a default value will
+ * be chosen based on the type of the private key associated with the
+ * designated <i>Alias</i>. If the private key is a <code>DSA</code> one,
+ * the value for the signature algorithm will be <code>SHA1withDSA</code>.
+ * If on the other hand the private key is an <code>RSA</code> one, then
+ * the tool will use <code>MD5withRSA</code> as the signature algorithm.
+ * <p></dd>
+ *
+ * <dt>-file FILE_NAME</dt>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.
+ * <p></dd>
+ *
+ * <dt>-attributes</dt>
+ * <dd>Use this option to force the tool to encode a NULL DER value in the
+ * CSR as the value of the Attributes field.</dd>
+ * </dl>
+ */
+class CertReqCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(CertReqCmd.class.getName());
+ private String _alias;
+ private String _sigAlgorithm;
+ private String _certReqFileName;
+ private String _password;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private boolean nullAttributes;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /**
+ * @param algorithm the canonical name of the digital signature algorithm to
+ * use.
+ */
+ public void setSigalg(String algorithm)
+ {
+ this._sigAlgorithm = algorithm;
+ }
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certReqFileName = pathName;
+ }
+
+ /** @param password the (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ /**
+ * @param flag whether to use, or not, a <code>NULL</code> DER value for
+ * the certificate's Attributes field.
+ */
+ public void setAttributes(String flag)
+ {
+ this.nullAttributes = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM //$NON-NLS-1$
+ _sigAlgorithm = args[++i];
+ else if ("-file".equals(opt)) // -file FILE_NAME //$NON-NLS-1$
+ _certReqFileName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else if ("-attributes".equals(opt)) //$NON-NLS-1$
+ nullAttributes = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(_certReqFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+// setSignatureAlgorithm(_sigAlgorithm);
+
+ log.finer("-certreq handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -sigalg=" + _sigAlgorithm); //$NON-NLS-1$
+ log.finer(" -file=" + _certReqFileName); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ log.finer(" -attributes=" + nullAttributes); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ InvalidKeyException, SignatureException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ // 1. get the key entry and certificate chain associated to alias
+ Key privateKey = getAliasPrivateKey();
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ // 2. get alias's DN and public key to use in the CSR
+ X509Certificate bottomCertificate = (X509Certificate) chain[0];
+ X500Principal aliasName = bottomCertificate.getIssuerX500Principal();
+ PublicKey publicKey = bottomCertificate.getPublicKey();
+
+ // 3. generate the CSR
+ setSignatureAlgorithmParam(_sigAlgorithm, privateKey);
+ byte[] derBytes = getCSR(aliasName, publicKey, (PrivateKey) privateKey);
+
+ // 4. encode it in base-64 and write it to outStream
+ String encoded = Base64.encode(derBytes, 0, derBytes.length, true);
+ PrintWriter writer = new PrintWriter(outStream, true);
+ writer.println("-----BEGIN NEW CERTIFICATE REQUEST-----"); //$NON-NLS-1$
+ writer.println(encoded);
+ writer.println("-----END NEW CERTIFICATE REQUEST-----"); //$NON-NLS-1$
+
+ if (verbose)
+ {
+ if (! systemOut)
+ System.out.println(Messages.getFormattedString("CertReqCmd.27", //$NON-NLS-1$
+ _certReqFileName));
+ System.out.println(Messages.getString("CertReqCmd.28")); //$NON-NLS-1$
+ }
+
+ writer.close();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * @param aliasName
+ * @param publicKey
+ * @param privateKey
+ * @return the DER encoded Certificate Signing Request.
+ * @throws IOException
+ * @throws InvalidKeyException
+ * @throws SignatureException
+ */
+ private byte[] getCSR(X500Principal aliasName, PublicKey publicKey,
+ PrivateKey privateKey)
+ throws IOException, InvalidKeyException, SignatureException
+ {
+ DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO);
+ DERValue derSubject = new DERReader(aliasName.getEncoded()).read();
+ DERValue derSubjectPKInfo = new DERReader(publicKey.getEncoded()).read();
+ byte[] b = nullAttributes ? new byte[] { 0x05, 0x00 } : new byte[0];
+ DERValue derAttributes = new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0,
+ b.length, b, null);
+ ArrayList certRequestInfo = new ArrayList(4);
+ certRequestInfo.add(derVersion);
+ certRequestInfo.add(derSubject);
+ certRequestInfo.add(derSubjectPKInfo);
+ certRequestInfo.add(derAttributes);
+ DERValue derCertRequestInfo = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ certRequestInfo);
+
+ OID sigAlgorithmID = getSignatureAlgorithmOID();
+ DERValue derSigAlgorithmID = new DERValue(DER.OBJECT_IDENTIFIER,
+ sigAlgorithmID);
+ ArrayList sigAlgorithm = new ArrayList(2);
+ sigAlgorithm.add(derSigAlgorithmID);
+ if (! sigAlgorithmID.equals(Command.SHA1_WITH_DSA)) // it's an RSA-based
+ sigAlgorithm.add(new DERValue(DER.NULL, null));
+
+ sigAlgorithm.trimToSize();
+ DERValue derSignatureAlgorithm = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ sigAlgorithm);
+
+ signatureAlgorithm.initSign(privateKey);
+ signatureAlgorithm.update(derCertRequestInfo.getEncoded());
+ byte[] sigBytes = signatureAlgorithm.sign();
+ DERValue derSignature = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+
+ ArrayList csr = new ArrayList(3);
+ csr.add(derCertRequestInfo);
+ csr.add(derSignatureAlgorithm);
+ csr.add(derSignature);
+ DERValue derCSR = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, csr);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DERWriter.write(baos, derCSR);
+ byte[] result = baos.toByteArray();
+
+ return result;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/Command.java b/tools/gnu/classpath/tools/keytool/Command.java
new file mode 100644
index 000000000..235f2cc56
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/Command.java
@@ -0,0 +1,1147 @@
+/* Command.java -- Abstract implementation of a keytool command handler
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.SystemProperties;
+import gnu.classpath.tools.common.CallbackUtil;
+import gnu.classpath.tools.common.ProviderUtil;
+import gnu.classpath.tools.common.SecurityProviderInfo;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.java.security.der.BitString;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.hash.MD5;
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.util.Util;
+import gnu.java.security.x509.X500DistinguishedName;
+import gnu.javax.security.auth.callback.ConsoleCallbackHandler;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.math.BigInteger;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAKey;
+import java.security.interfaces.RSAKey;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.logging.Logger;
+import java.util.prefs.Preferences;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * A base class of the keytool command to facilitate implementation of concrete
+ * keytool Handlers.
+ */
+abstract class Command
+{
+ // Fields and constants -----------------------------------------------------
+
+ private static final Logger log = Logger.getLogger(Command.class.getName());
+ /** Default value for the ALIAS argument. */
+ private static final String DEFAULT_ALIAS = "mykey"; //$NON-NLS-1$
+ /** Default algorithm for key-pair generation. */
+ private static final String DEFAULT_KEY_ALGORITHM = "DSA"; //$NON-NLS-1$
+ /** Default DSA digital signature algorithm to use with DSA keys. */
+ private static final String DSA_SIGNATURE_ALGORITHM = "SHA1withDSA"; //$NON-NLS-1$
+ /** Default RSA digital signature algorithm to use with RSA keys. */
+ private static final String RSA_SIGNATURE_ALGORITHM = "MD5withRSA"; //$NON-NLS-1$
+ /** Default validity (in days) of newly generated certificates. */
+ private static final int DEFAULT_VALIDITY = 90;
+ /** OID of SHA1withDSA signature algorithm as stated in RFC-2459. */
+ protected static final OID SHA1_WITH_DSA = new OID("1.2.840.10040.4.3"); //$NON-NLS-1$
+ /** OID of MD2withRSA signature algorithm as stated in RFC-2459. */
+ private static final OID MD2_WITH_RSA = new OID("1.2.840.113549.1.1.2"); //$NON-NLS-1$
+ /** OID of MD5withRSA signature algorithm as stated in RFC-2459. */
+ private static final OID MD5_WITH_RSA = new OID("1.2.840.113549.1.1.4"); //$NON-NLS-1$
+ /** OID of SHA1withRSA signature algorithm as stated in RFC-2459. */
+ private static final OID SHA1_WITH_RSA = new OID("1.2.840.113549.1.1.5"); //$NON-NLS-1$
+ /** Number of milliseconds in one day. */
+ private static final long MILLIS_IN_A_DAY = 24 * 60 * 60 * 1000L;
+
+ /** The Alias to use. */
+ protected String alias;
+ /** The password characters protecting a Key Entry. */
+ protected char[] keyPasswordChars;
+ /** A security provider to add. */
+ protected Provider provider;
+ /** The key store type. */
+ protected String storeType;
+ /** The password characters protecting the key store. */
+ protected char[] storePasswordChars;
+ /** The key store URL. */
+ protected URL storeURL;
+ /** The input stream from the key store URL. */
+ protected InputStream storeStream;
+ /** The key store instance to use. */
+ protected KeyStore store;
+ /** The output stream the concrete handler will use. */
+ protected OutputStream outStream;
+ /** Whether we are printing to System.out. */
+ protected boolean systemOut;
+ /** The key-pair generation algorithm instance to use. */
+ protected KeyPairGenerator keyPairGenerator;
+ /** The digital signature algorithm instance to use. */
+ protected Signature signatureAlgorithm;
+ /** Validity period, in number of days, to use when generating certificates. */
+ protected int validityInDays;
+ /** The input stream the concrete handler will use. */
+ protected InputStream inStream;
+ /** Whether verbose output is required or not. */
+ protected boolean verbose;
+
+ /** MD5 hash to use when generating certificate fingerprints. */
+ private IMessageDigest md5 = new MD5();
+ /** SHA1 hash to use when generating certificate fingerprints. */
+ private IMessageDigest sha = new Sha160();
+ /** The new position of a user-defined provider if it is not already installed. */
+ private int providerNdx = -2;
+ /** The callback handler to use when needing to interact with user. */
+ private CallbackHandler handler;
+
+ // Constructor(s) -----------------------------------------------------------
+
+ // default 0-arguments constructor
+
+ // Methods ------------------------------------------------------------------
+
+ /**
+ * A public method to allow using any keytool command handler programmatically
+ * by using a JavaBeans style of parameter(s) initialization. The user is
+ * assumed to have set individually the required options through their
+ * respective setters before invoking this method.
+ * <p>
+ * If an exception is encountered during the processing of the command, this
+ * implementation attempts to release any resources that may have been
+ * allocated at the time the exception occurs, before re-throwing that
+ * exception.
+ *
+ * @throws Exception if an exception occurs during the processing of this
+ * command. For a more comprehensive list of exceptions that may
+ * occur, see the documentation of the {@link #setup()} and
+ * {@link #start()} methods.
+ */
+ public void doCommand() throws Exception
+ {
+ try
+ {
+ setup();
+ start();
+ }
+ finally
+ {
+ teardown();
+ }
+ }
+
+ /**
+ * @param flag whether to use, or not, more verbose output while processing
+ * the command.
+ */
+ public void setVerbose(String flag)
+ {
+ this.verbose = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ /**
+ * Given a potential sub-array of options for this concrete handler, starting
+ * at position <code>startIndex + 1</code>, potentially followed by other
+ * commands and their options, this method sets up this concrete command
+ * handler with its own options and returns the index of the first unprocessed
+ * argument in the array.
+ * <p>
+ * The general contract of this method is that it is invoked with the
+ * <code>startIndex</code> argument pointing to the keyword argument that
+ * uniquelly identifies the command itself; e.g. <code>-genkey</code> or
+ * <code>-list</code>, etc...
+ *
+ * @param args an array of options for this handler and possibly other
+ * commands and their options.
+ * @param startIndex the index of the first argument in <code>args</code> to
+ * process.
+ * @return the index of the first unprocessed argument in <code>args</code>.
+ */
+ abstract int processArgs(String[] args, int startIndex);
+
+ /**
+ * Initialize this concrete command handler for later invocation of the
+ * {@link #start()} or {@link #doCommand()} methods.
+ * <p>
+ * Handlers usually initialize their local variables and resources within the
+ * scope of this call.
+ *
+ * @throws IOException if an I/O related exception, such as opening an input
+ * stream, occurs during the execution of this method.
+ * @throws UnsupportedCallbackException if a requested callback handler
+ * implementation was not found, or was found but encountered an
+ * exception during its processing.
+ * @throws ClassNotFoundException if a designated security provider class was
+ * not found.
+ * @throws IllegalAccessException no 0-arguments constructor for the
+ * designated security provider class was found.
+ * @throws InstantiationException the designated security provider class is
+ * not instantiable.
+ * @throws KeyStoreException if an exception occurs during the instantiation
+ * of the KeyStore.
+ * @throws CertificateException if a certificate related exception, such as
+ * expiry, occurs during the loading of the KeyStore.
+ * @throws NoSuchAlgorithmException if no current security provider can
+ * provide a needed algorithm referenced by the KeyStore or one of
+ * its Key Entries or Certificates.
+ */
+ abstract void setup() throws Exception;
+
+ /**
+ * Do the real work this handler is supposed to do.
+ * <p>
+ * The code in this (abstract) class throws a <i>Not implemented yet</i>
+ * runtime exception. Concrete implementations MUST override this method.
+ *
+ * @throws CertificateException If no concrete implementation was found for a
+ * certificate Factory of a designated type. In this tool, the type
+ * is usually X.509 v1.
+ * @throws KeyStoreException if a keys-store related exception occurs; e.g.
+ * the key store has not been initialized.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws SignatureException if a digital signature related exception occurs.
+ * @throws InvalidKeyException if the genereated keys are invalid.
+ * @throws UnrecoverableKeyException if the password used to unlock a key in
+ * the key store was invalid.
+ * @throws NoSuchAlgorithmException if a concrete implementation of an
+ * algorithm used to store a Key Entry was not found at runtime.
+ * @throws UnsupportedCallbackException if a requested callback handler
+ * implementation was not found, or was found but encountered an
+ * exception during its processing.
+ */
+ void start() throws Exception
+ {
+ throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
+ }
+
+ /**
+ * Tear down the handler, releasing any resources which may have been
+ * allocated at setup time.
+ */
+ void teardown()
+ {
+ log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+
+ if (storeStream != null)
+ try
+ {
+ storeStream.close();
+ }
+ catch (IOException ignored)
+ {
+ log.fine("Exception while closing key store URL stream. Ignored: " //$NON-NLS-1$
+ + ignored);
+ }
+
+ if (outStream != null)
+ {
+ try
+ {
+ outStream.flush();
+ }
+ catch (IOException ignored)
+ {
+ }
+
+ if (! systemOut)
+ try
+ {
+ outStream.close();
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+
+ if (inStream != null)
+ try
+ {
+ inStream.close();
+ }
+ catch (IOException ignored)
+ {
+ }
+
+ if (providerNdx > 0)
+ ProviderUtil.removeProvider(provider.getName());
+
+ log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ }
+
+ // parameter setup and validation methods -----------------------------------
+
+ /**
+ * Convenience method to setup the key store given its type, its password, its
+ * location and portentially a specialized security provider.
+ *
+ * @param className the potentially null fully qualified class name of a
+ * security provider to add at runtime, if no installed provider is
+ * able to provide a key store implementation of the desired type.
+ * @param type the potentially null type of the key store to request from the
+ * key store factory.
+ * @param password the potentially null password protecting the key store.
+ * @param url the URL of the key store.
+ */
+ protected void setKeyStoreParams(String className, String type,
+ String password, String url)
+ throws IOException, UnsupportedCallbackException, KeyStoreException,
+ NoSuchAlgorithmException, CertificateException
+ {
+ setProviderClassNameParam(className);
+ setKeystoreTypeParam(type);
+ setKeystorePasswordParam(password);
+ setKeystoreURLParam(url);
+ }
+
+ /**
+ * Set a security provider class name to (install and) use for key store
+ * related operations.
+ *
+ * @param className the possibly null, fully qualified class name of a
+ * security provider to add, if it is not already installed, to the
+ * set of available providers.
+ */
+ protected void setProviderClassNameParam(String className)
+ {
+ log.finest("setProviderClassNameParam(" + className + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (className != null && className.trim().length() > 0)
+ {
+ className = className.trim();
+ SecurityProviderInfo spi = ProviderUtil.addProvider(className);
+ provider = spi.getProvider();
+ if (provider == null)
+ log.fine("Was unable to add provider from class " + className);
+
+ providerNdx = spi.getPosition();
+ }
+ }
+
+ /**
+ * Set the type of key store to initialize, load and use.
+ *
+ * @param type the possibly null type of the key store. if this argument is
+ * <code>null</code>, or is an empty string, then this method sets
+ * the type of the key store to be the default value returned from
+ * the invocation of the {@link KeyStore#getDefaultType()} method.
+ * For GNU Classpath this is <i>gkr</i> which stands for the "Gnu
+ * KeyRing" specifications.
+ */
+ protected void setKeystoreTypeParam(String type)
+ {
+ log.finest("setKeystoreTypeParam(" + type + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (type == null || type.trim().length() == 0)
+ storeType = KeyStore.getDefaultType();
+ else
+ storeType = type.trim();
+ }
+
+ /**
+ * Set the key password given a command line option argument. If no value was
+ * present on the command line then prompt the user to provide one.
+ *
+ * @param password a possibly null key password gleaned from the command line.
+ * @throws IOException if an I/O related exception occurs.
+ * @throws UnsupportedCallbackException if no concrete implementation of a
+ * password callback was found at runtime.
+ */
+ protected void setKeyPasswordParam(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ setKeyPasswordNoPrompt(password);
+ if (keyPasswordChars == null)
+ setKeyPasswordParam();
+ }
+
+ /**
+ * Set the Alias to use when associating Key Entries and Trusted Certificates
+ * in the current key store.
+ *
+ * @param name the possibly null alias to use. If this arfument is
+ * <code>null</code>, then a default value of <code>mykey</code>
+ * will be used instead.
+ */
+ protected void setAliasParam(String name)
+ {
+ alias = name == null ? DEFAULT_ALIAS : name.trim();
+ }
+
+ /**
+ * Set the key password given a command line option argument.
+ *
+ * @param password a possibly null key password gleaned from the command line.
+ */
+ protected void setKeyPasswordNoPrompt(String password)
+ {
+ if (password != null)
+ keyPasswordChars = password.toCharArray();
+ }
+
+ /**
+ * Prompt the user to provide a password to protect a Key Entry in the key
+ * store.
+ *
+ * @throws IOException if an I/O related exception occurs.
+ * @throws UnsupportedCallbackException if no concrete implementation of a
+ * password callback was found at runtime.
+ * @throws SecurityException if no password is available, even after prompting
+ * the user.
+ */
+ protected void setKeyPasswordParam() throws IOException,
+ UnsupportedCallbackException
+ {
+ String prompt = Messages.getFormattedString("Command.21", alias); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(prompt, false);
+ getCallbackHandler().handle(new Callback[] { pcb });
+ keyPasswordChars = pcb.getPassword();
+ pcb.clearPassword();
+ if (keyPasswordChars == null)
+ throw new SecurityException(Messages.getString("Command.23")); //$NON-NLS-1$
+ }
+
+ protected void setKeystorePasswordParam(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null)
+ storePasswordChars = password.toCharArray();
+ else // ask the user to provide one
+ {
+ String prompt = Messages.getString("Command.24"); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(prompt, false);
+ getCallbackHandler().handle(new Callback[] { pcb });
+ storePasswordChars = pcb.getPassword();
+ pcb.clearPassword();
+ }
+ log.finest("storePasswordChars = [" + String.valueOf(storePasswordChars)+ "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Set the key store URL to use.
+ *
+ * @param url
+ * @throws IOException
+ * @throws KeyStoreException
+ * @throws UnsupportedCallbackException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ */
+ protected void setKeystoreURLParam(String url) throws IOException,
+ KeyStoreException, UnsupportedCallbackException, NoSuchAlgorithmException,
+ CertificateException
+ {
+ log.finest("setKeystoreURLParam(" + url + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (url == null || url.trim().length() == 0)
+ {
+ String userHome = SystemProperties.getProperty("user.home"); //$NON-NLS-1$
+ if (userHome == null || userHome.trim().length() == 0)
+ throw new InvalidParameterException(Messages.getString("Command.36")); //$NON-NLS-1$
+
+ url = userHome.trim() + "/.keystore"; //$NON-NLS-1$
+ // if it does not exist create it
+ new File(url).createNewFile();
+ url = "file:" + url; //$NON-NLS-1$
+ }
+ else
+ {
+ url = url.trim();
+ if (url.indexOf(":") == -1) // if it does not exist create it //$NON-NLS-1$
+ new File(url).createNewFile();
+
+ url = "file:" + url; //$NON-NLS-1$
+ }
+
+ boolean newKeyStore = false;
+ storeURL = new URL(url);
+ storeStream = storeURL.openStream();
+ if (storeStream.available() == 0)
+ {
+ log.fine("Store is empty. Will use <null> when loading, to create it"); //$NON-NLS-1$
+ newKeyStore = true;
+ }
+
+ try
+ {
+ store = KeyStore.getInstance(storeType);
+ }
+ catch (KeyStoreException x)
+ {
+ if (provider != null)
+ throw x;
+
+ log.fine("Exception while getting key store with default provider(s)." //$NON-NLS-1$
+ + " Will prompt user for another provider and continue"); //$NON-NLS-1$
+ String prompt = Messages.getString("Command.40"); //$NON-NLS-1$
+ NameCallback ncb = new NameCallback(prompt);
+ getCallbackHandler().handle(new Callback[] { ncb });
+ String className = ncb.getName();
+ setProviderClassNameParam(className); // we may have a Provider
+ if (provider == null)
+ {
+ x.fillInStackTrace();
+ throw x;
+ }
+ // try again
+ store = KeyStore.getInstance(storeType, provider);
+ }
+
+ // now we have a KeyStore instance. load it
+ // KeyStore public API claims: "...In order to create an empty keystore,
+ // you pass null as the InputStream argument to the load method.
+ if (newKeyStore)
+ store.load(null, storePasswordChars);
+ else
+ store.load(storeStream, storePasswordChars);
+
+ // close the stream
+ try
+ {
+ storeStream.close();
+ storeStream = null;
+ }
+ catch (IOException x)
+ {
+ log.fine("Exception while closing the key store input stream: " + x //$NON-NLS-1$
+ + ". Ignore"); //$NON-NLS-1$
+ }
+ }
+
+ protected void setOutputStreamParam(String fileName) throws SecurityException,
+ IOException
+ {
+ if (fileName == null || fileName.trim().length() == 0)
+ {
+ outStream = System.out;
+ systemOut = true;
+ }
+ else
+ {
+ fileName = fileName.trim();
+ File outFile = new File(fileName);
+ if (! outFile.exists())
+ {
+ boolean ok = outFile.createNewFile();
+ if (!ok)
+ throw new InvalidParameterException(Messages.getFormattedString("Command.19", //$NON-NLS-1$
+ fileName));
+ }
+ else
+ {
+ if (! outFile.isFile())
+ throw new InvalidParameterException(Messages.getFormattedString("Command.42", //$NON-NLS-1$
+ fileName));
+ if (! outFile.canWrite())
+ throw new InvalidParameterException(Messages.getFormattedString("Command.44", //$NON-NLS-1$
+ fileName));
+ }
+ outStream = new FileOutputStream(outFile);
+ }
+ }
+
+ protected void setInputStreamParam(String fileName)
+ throws FileNotFoundException
+ {
+ if (fileName == null || fileName.trim().length() == 0)
+ inStream = System.in;
+ else
+ {
+ fileName = fileName.trim();
+ File inFile = new File(fileName);
+ if (! (inFile.exists() && inFile.isFile() && inFile.canRead()))
+ throw new InvalidParameterException(Messages.getFormattedString("Command.46", //$NON-NLS-1$
+ fileName));
+ inStream = new FileInputStream(inFile);
+ }
+ }
+
+ /**
+ * Set both the key-pair generation algorithm, and the digital signature
+ * algorithm instances to use when generating new entries.
+ *
+ * @param kpAlg the possibly null name of a key-pair generator algorithm.
+ * if this argument is <code>null</code> or is an empty string, the
+ * "DSS" algorithm will be used.
+ * @param sigAlg the possibly null name of a digital signature algorithm.
+ * If this argument is <code>null</code> or is an empty string, this
+ * method uses the "SHA1withDSA" (Digital Signature Standard, a.k.a.
+ * DSA, with the Secure Hash Algorithm function) as the default
+ * algorithm if, and only if, the key-pair generation algorithm ends
+ * up being "DSS"; otherwise, if the key-pair generation algorithm
+ * was "RSA", then the "MD5withRSA" signature algorithm will be used.
+ * If the key-pair generation algorithm is neither "DSS" (or its
+ * alias "DSA"), nor is it "RSA", then an exception is thrown.
+ * @throws NoSuchAlgorithmException if no concrete implementation of the
+ * designated algorithm is available.
+ */
+ protected void setAlgorithmParams(String kpAlg, String sigAlg)
+ throws NoSuchAlgorithmException
+ {
+ if (kpAlg == null || kpAlg.trim().length() == 0)
+ kpAlg = DEFAULT_KEY_ALGORITHM;
+ else
+ kpAlg = kpAlg.trim().toLowerCase();
+
+ keyPairGenerator = KeyPairGenerator.getInstance(kpAlg);
+
+ if (sigAlg == null || sigAlg.trim().length() == 0)
+ if (kpAlg.equalsIgnoreCase(Registry.DSS_KPG)
+ || kpAlg.equalsIgnoreCase(Registry.DSA_KPG))
+ sigAlg = DSA_SIGNATURE_ALGORITHM;
+ else if (kpAlg.equalsIgnoreCase(Registry.RSA_KPG))
+ sigAlg = RSA_SIGNATURE_ALGORITHM;
+ else
+ throw new IllegalArgumentException(
+ Messages.getFormattedString("Command.20", //$NON-NLS-1$
+ new String[] { sigAlg, kpAlg }));
+ else
+ sigAlg = sigAlg.trim().toLowerCase();
+
+ signatureAlgorithm = Signature.getInstance(sigAlg);
+ }
+
+ /**
+ * Set the signature algorithm to use when digitally signing private keys,
+ * certificates, etc...
+ * <p>
+ * If the designated algorithm name is <code>null</code> or is an empty
+ * string, this method checks the private key (the second argument) and based
+ * on its type decides which algorithm to use. The keytool public
+ * specification states that if the private key is a DSA key, then the
+ * signature algorithm will be <code>SHA1withDSA</code>, otherwise if it is
+ * an RSA private key, then the signature algorithm will be
+ * <code>MD5withRSA</code>. If the private key is neither a private DSA nor
+ * a private RSA key, then this method throws an
+ * {@link IllegalArgumentException}.
+ *
+ * @param algorithm the possibly null name of a digital signature algorithm.
+ * @param privateKey an instance of a private key to use as a fal-back option
+ * when <code>algorithm</code> is invalid.
+ * @throws NoSuchAlgorithmException if no concrete implementation of the
+ * designated, or default, signature algorithm is available.
+ */
+ protected void setSignatureAlgorithmParam(String algorithm, Key privateKey)
+ throws NoSuchAlgorithmException
+ {
+ if (algorithm == null || algorithm.trim().length() == 0)
+ if (privateKey instanceof DSAKey)
+ algorithm = DSA_SIGNATURE_ALGORITHM;
+ else if (privateKey instanceof RSAKey)
+ algorithm = RSA_SIGNATURE_ALGORITHM;
+ else
+ throw new InvalidParameterException(Messages.getString("Command.48")); //$NON-NLS-1$
+ else
+ algorithm = algorithm.trim();
+
+ signatureAlgorithm = Signature.getInstance(algorithm);
+ }
+
+ /**
+ * Set the validity period, in number of days, to use when issuing new
+ * certificates.
+ *
+ * @param days the number of days, as a string, the generated certificate will
+ * be valid for, starting from today's date. if this argument is
+ * <code>null</code>, a default value of <code>90</code> days
+ * will be used.
+ * @throws NumberFormatException if the designated string is not a decimal
+ * integer.
+ * @throws InvalidParameterException if the integer value of the non-null
+ * string is not greater than zero.
+ */
+ protected void setValidityParam(String days)
+ {
+ if (days == null || days.trim().length() == 0)
+ validityInDays = DEFAULT_VALIDITY;
+ else
+ {
+ days = days.trim();
+ validityInDays = Integer.parseInt(days);
+ if (validityInDays < 1)
+ throw new InvalidParameterException(Messages.getString("Command.51")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * RFC-2459 (http://rfc.net/rfc2459.html) fully describes the structure and
+ * semantics of X.509 certificates. The ASN.1 structures below are gleaned
+ * from that reference.
+ *
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING
+ * }
+ *
+ * TBSCertificate ::= SEQUENCE {
+ * version [0] EXPLICIT Version DEFAULT v1,
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo
+ * }
+ *
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ *
+ * CertificateSerialNumber ::= INTEGER
+ *
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time
+ * }
+ *
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime
+ * }
+ *
+ * UniqueIdentifier ::= BIT STRING
+ *
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ * </pre>
+ *
+ * @param distinguishedName the X.500 Distinguished Name to use as both the
+ * Issuer and Subject of the self-signed certificate to generate.
+ * @param publicKey the public key of the issuer/subject.
+ * @param privateKey the private key of the issuer/signer.
+ * @return the DER encoded form of a self-signed X.509 v1 certificate.
+ * @throws IOException If an I/O related exception occurs during the process.
+ * @throws SignatureException If a digital signature related exception occurs.
+ * @throws InvalidKeyException if the designated private key is invalid.
+ * @throws InvalidParameterException if the concrete signature algorithm does
+ * not know its name, no OID is known/supported for that name, or we
+ * were unable to match the name to a known string for which we can
+ * use a standard OID.
+ */
+ protected byte[] getSelfSignedCertificate(X500DistinguishedName distinguishedName,
+ PublicKey publicKey,
+ PrivateKey privateKey)
+ throws IOException, SignatureException, InvalidKeyException
+ {
+ log.entering(this.getClass().getName(), "getSelfSignedCertificate", //$NON-NLS-1$
+ new Object[] { distinguishedName, publicKey, privateKey });
+
+ byte[] versionBytes = new DERValue(DER.INTEGER, BigInteger.ZERO).getEncoded();
+ DERValue derVersion = new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0,
+ versionBytes.length, versionBytes, null);
+
+ // NOTE (rsn): the next 3 lines should be atomic but they're not.
+ Preferences prefs = Preferences.systemNodeForPackage(this.getClass());
+ int lastSerialNumber = prefs.getInt(Main.LAST_SERIAL_NUMBER, 0) + 1;
+ prefs.putInt(Main.LAST_SERIAL_NUMBER, lastSerialNumber);
+ DERValue derSerialNumber = new DERValue(DER.INTEGER,
+ BigInteger.valueOf(lastSerialNumber));
+
+ OID signatureID = getSignatureAlgorithmOID();
+ DERValue derSignatureID = new DERValue(DER.OBJECT_IDENTIFIER, signatureID);
+ ArrayList signature = new ArrayList(1);
+ signature.add(derSignatureID);
+ // rfc-2459 states the following:
+ //
+ // for the DSA signature:
+ // ...Where the id-dsa-with-sha1 algorithm identifier appears as the
+ // algorithm field in an AlgorithmIdentifier, the encoding shall omit
+ // the parameters field. That is, the AlgorithmIdentifier shall be a
+ // SEQUENCE of one component - the OBJECT IDENTIFIER id-dsa-with-sha1.
+ //
+ // for RSA signatures:
+ // ...When any of these three OIDs (i.e. xxxWithRSAEncryption) appears
+ // within the ASN.1 type AlgorithmIdentifier, the parameters component of
+ // that type shall be the ASN.1 type NULL.
+ if (! signatureID.equals(SHA1_WITH_DSA))
+ signature.add(new DERValue(DER.NULL, null));
+
+ DERValue derSignature = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ signature);
+
+ DERValue derIssuer = new DERReader(distinguishedName.getDer()).read();
+
+ long notBefore = System.currentTimeMillis();
+ long notAfter = notBefore + validityInDays * MILLIS_IN_A_DAY;
+
+ ArrayList validity = new ArrayList(2);
+ validity.add(new DERValue(DER.UTC_TIME, new Date(notBefore)));
+ validity.add(new DERValue(DER.UTC_TIME, new Date(notAfter)));
+ DERValue derValidity = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ validity);
+
+ // for a self-signed certificate subject and issuer are identical
+ DERValue derSubject = derIssuer;
+
+ DERValue derSubjectPublicKeyInfo = new DERReader(publicKey.getEncoded()).read();
+
+ ArrayList tbsCertificate = new ArrayList(7);
+ tbsCertificate.add(derVersion);
+ tbsCertificate.add(derSerialNumber);
+ tbsCertificate.add(derSignature);
+ tbsCertificate.add(derIssuer);
+ tbsCertificate.add(derValidity);
+ tbsCertificate.add(derSubject);
+ tbsCertificate.add(derSubjectPublicKeyInfo);
+ DERValue derTBSCertificate = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ tbsCertificate);
+
+ // The 'signature' field MUST contain the same algorithm identifier as the
+ // 'signatureAlgorithm' field in the sequence Certificate.
+ DERValue derSignatureAlgorithm = derSignature;
+
+ signatureAlgorithm.initSign(privateKey);
+ signatureAlgorithm.update(derTBSCertificate.getEncoded());
+ byte[] sigBytes = signatureAlgorithm.sign();
+ DERValue derSignatureValue = new DERValue(DER.BIT_STRING,
+ new BitString(sigBytes));
+
+ ArrayList certificate = new ArrayList(3);
+ certificate.add(derTBSCertificate);
+ certificate.add(derSignatureAlgorithm);
+ certificate.add(derSignatureValue);
+ DERValue derCertificate = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
+ certificate);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DERWriter.write(baos, derCertificate);
+ byte[] result = baos.toByteArray();
+
+ log.exiting(this.getClass().getName(), "getSelfSignedCertificate"); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * This method attempts to find, and return, an OID representing the digital
+ * signature algorithm used to sign the certificate. The OIDs returned are
+ * those described in RFC-2459. They are listed here for the sake of
+ * completness.
+ *
+ * <pre>
+ * id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) x9-57 (10040) x9cm(4) 3
+ * }
+ *
+ * md2WithRSAEncryption OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 2
+ * }
+ *
+ * md5WithRSAEncryption OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 4
+ * }
+ *
+ * sha-1WithRSAEncryption OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 5
+ * }
+ * </pre>
+ *
+ * <b>IMPORTANT</b>: This method checks the signature algorithm name against
+ * (a) The GNU algorithm implementation's name, and (b) publicly referenced
+ * names of the same algorithm. In other words this search is not
+ * comprehensive and may fail for uncommon names of the same algorithms.
+ *
+ * @return the OID of the signature algorithm in use.
+ * @throws InvalidParameterException if the concrete signature algorithm does
+ * not know its name, no OID is known/supported for that name, or we
+ * were unable to match the name to a known string for which we can
+ * return an OID.
+ */
+ protected OID getSignatureAlgorithmOID()
+ {
+ String algorithm = signatureAlgorithm.getAlgorithm();
+ // if we already have a non-null signature then the name was valid. the
+ // only case where algorithm is invalid would be if the implementation is
+ // flawed. check anyway
+ if (algorithm == null || algorithm.trim().length() == 0)
+ throw new InvalidParameterException(Messages.getString("Command.52")); //$NON-NLS-1$
+
+ algorithm = algorithm.trim();
+ if (algorithm.equalsIgnoreCase(Registry.DSS_SIG)
+ || algorithm.equalsIgnoreCase("SHA1withDSA")) //$NON-NLS-1$
+ return SHA1_WITH_DSA;
+
+ if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
+ + Registry.MD2_HASH)
+ || algorithm.equalsIgnoreCase("MD2withRSA")) //$NON-NLS-1$
+ return MD2_WITH_RSA;
+
+ if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
+ + Registry.MD5_HASH)
+ || algorithm.equalsIgnoreCase("MD5withRSA") //$NON-NLS-1$
+ || algorithm.equalsIgnoreCase("rsa")) //$NON-NLS-1$
+ return MD5_WITH_RSA;
+
+ if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
+ + Registry.SHA160_HASH)
+ || algorithm.equalsIgnoreCase("SHA1withRSA")) //$NON-NLS-1$
+ return SHA1_WITH_RSA;
+
+ throw new InvalidParameterException(Messages.getFormattedString("Command.60", //$NON-NLS-1$
+ algorithm));
+ }
+
+ /**
+ * Saves the key store using the designated password. This operation is called
+ * by handlers if/when the key store password has changed, or amendements have
+ * been made to the contents of the store; e.g. addition of a new Key Entry or
+ * a Trusted Certificate.
+ *
+ * @param password the password protecting the key store.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws CertificateException if any of the certificates in the current key
+ * store could not be persisted.
+ * @throws NoSuchAlgorithmException if a required data integrity algorithm
+ * implementation was not found.
+ * @throws KeyStoreException if the key store has not been loaded previously.
+ */
+ protected void saveKeyStore(char[] password) throws IOException,
+ KeyStoreException, NoSuchAlgorithmException, CertificateException
+ {
+ log.entering(this.getClass().getName(), "saveKeyStore", String.valueOf(password)); //$NON-NLS-1$
+
+ URLConnection con = storeURL.openConnection();
+ con.setDoOutput(true);
+ con.setUseCaches(false);
+ OutputStream out = con.getOutputStream();
+ if (verbose)
+ System.out.println(Messages.getFormattedString("Command.63", storeURL.getPath())); //$NON-NLS-1$
+
+ store.store(out, password);
+ out.flush();
+ out.close();
+
+ log.exiting(this.getClass().getName(), "saveKeyStore"); //$NON-NLS-1$
+ }
+
+ /**
+ * Convenience method. Calls the method with the same name passing it the
+ * same password characters used to initially load the key-store.
+ *
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws KeyStoreException if the key store has not been loaded previously.
+ * @throws NoSuchAlgorithmException if a required data integrity algorithm
+ * implementation was not found.
+ * @throws CertificateException if any of the certificates in the current key
+ * store could not be persisted.
+ */
+ protected void saveKeyStore() throws IOException, KeyStoreException,
+ NoSuchAlgorithmException, CertificateException
+ {
+ saveKeyStore(storePasswordChars);
+ }
+
+ /**
+ * Prints a human-readable form of the designated certificate to a designated
+ * {@link PrintWriter}.
+ *
+ * @param certificate the certificate to process.
+ * @param writer where to print it.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form <code>certificate</code>.
+ */
+ protected void printVerbose(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ X509Certificate x509 = (X509Certificate) certificate;
+ writer.println(Messages.getFormattedString("Command.66", x509.getSubjectDN())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.67", x509.getIssuerDN())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.68", x509.getSerialNumber())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.69", x509.getNotBefore())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.70", x509.getNotAfter())); //$NON-NLS-1$
+ writer.println(Messages.getString("Command.71")); //$NON-NLS-1$
+ byte[] derBytes = certificate.getEncoded();
+ writer.println(Messages.getFormattedString("Command.72", digest(md5, derBytes))); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("Command.73", digest(sha, derBytes))); //$NON-NLS-1$
+ }
+
+ /**
+ * Convenience method. Prints a human-readable form of the designated
+ * certificate to <code>System.out</code>.
+ *
+ * @param certificate the certificate to process.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form <code>certificate</code>.
+ */
+ protected void printVerbose(Certificate certificate)
+ throws CertificateEncodingException
+ {
+ printVerbose(certificate, new PrintWriter(System.out, true));
+ }
+
+ /**
+ * Digest the designated contents with MD5 and return a string representation
+ * suitable for use as a fingerprint; i.e. sequence of hexadecimal pairs of
+ * characters separated by a colon.
+ *
+ * @param contents the non-null contents to digest.
+ * @return a sequence of hexadecimal pairs of characters separated by colons.
+ */
+ protected String digestWithMD5(byte[] contents)
+ {
+ return digest(md5, contents);
+ }
+
+ private String digest(IMessageDigest hash, byte[] encoded)
+ {
+ hash.update(encoded);
+ byte[] b = hash.digest();
+ StringBuilder sb = new StringBuilder().append(Util.toString(b, 0, 1));
+ for (int i = 1; i < b.length; i++)
+ sb.append(":").append(Util.toString(b, i, 1)); //$NON-NLS-1$
+
+ String result = sb.toString();
+ return result;
+ }
+
+ /**
+ * Ensure that the currently set Alias is contained in the currently set key
+ * store; otherwise throw an exception.
+ *
+ * @throws KeyStoreException if the keystore has not been loaded.
+ * @throws IllegalArgumentException if the currently set alias is not known to
+ * the currently set key store.
+ */
+ protected void ensureStoreContainsAlias() throws KeyStoreException
+ {
+ if (! store.containsAlias(alias))
+ throw new IllegalArgumentException(Messages.getFormattedString("Command.75", //$NON-NLS-1$
+ alias));
+ }
+
+ /**
+ * Ensure that the currently set Alias is associated with a Key Entry in the
+ * currently set key store; otherwise throw an exception.
+ *
+ * @throws KeyStoreException if the keystore has not been loaded.
+ * @throws SecurityException if the currently set alias is not a Key Entry in
+ * the currently set key store.
+ */
+ protected void ensureAliasIsKeyEntry() throws KeyStoreException
+ {
+ if (! store.isKeyEntry(alias))
+ throw new SecurityException(Messages.getFormattedString("Command.77", //$NON-NLS-1$
+ alias));
+ }
+
+ protected Key getAliasPrivateKey() throws KeyStoreException,
+ NoSuchAlgorithmException, IOException, UnsupportedCallbackException,
+ UnrecoverableKeyException
+ {
+ ensureAliasIsKeyEntry();
+ Key result;
+ if (keyPasswordChars == null)
+ try
+ {
+ result = store.getKey(alias, storePasswordChars);
+ // it worked. assign to keyPasswordChars for later use
+ keyPasswordChars = storePasswordChars;
+ }
+ catch (UnrecoverableKeyException x)
+ {
+ // prompt the user to provide one
+ setKeyPasswordParam();
+ result = store.getKey(alias, keyPasswordChars);
+ }
+ else
+ result = store.getKey(alias, keyPasswordChars);
+
+ return result;
+ }
+
+ /**
+ * Return a CallbackHandler which uses the Console (System.in and System.out)
+ * for interacting with the user.
+ * <p>
+ * This method first finds all currently installed security providers capable
+ * of providing such service and then in turn attempts to instantiate the
+ * handler from those providers. As soon as one provider returns a non-null
+ * instance of the callback handler, the search stops and that instance is
+ * set to be used from now on.
+ * <p>
+ * If no installed providers were found, this method falls back on the GNU
+ * provider, by-passing the Security search mechanism. The default console
+ * callback handler implementation is {@link ConsoleCallbackHandler}.
+ *
+ * @return a console-based {@link CallbackHandler}.
+ */
+ protected CallbackHandler getCallbackHandler()
+ {
+ if (handler == null)
+ CallbackUtil.getConsoleHandler();
+
+ return handler;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/DeleteCmd.java b/tools/gnu/classpath/tools/keytool/DeleteCmd.java
new file mode 100644
index 000000000..968af50f8
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/DeleteCmd.java
@@ -0,0 +1,235 @@
+/* DeleteCmd.java -- The delete command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-delete</b> keytool command handler is used to delete from the key
+ * store the entry associated with a designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class DeleteCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(DeleteCmd.class.getName());
+ private String _alias;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setTheAlias(_alias);
+
+ log.finer("-delete handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ CertificateException, IOException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ ensureStoreContainsAlias();
+ store.deleteEntry(alias);
+ saveKeyStore();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * Set the alias to delete from the key store.
+ * <p>
+ * Unlike in other keytool handlers, the default value (<i>mykey</i>) for the
+ * Alias is not used. Instead, if an alias was not found on the command line,
+ * the user is prompted to enter one.
+ *
+ * @param anAlias a possibly null Alias gleaned from the command line.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws UnsupportedCallbackException if no implementation of a password
+ * callback handler was found.
+ */
+ private void setTheAlias(String anAlias) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (anAlias == null || anAlias.trim().length() == 0)
+ {
+ String prompt = Messages.getString("DeleteCmd.19"); //$NON-NLS-1$
+ NameCallback ncb = new NameCallback(prompt);
+ getCallbackHandler().handle(new Callback[] { ncb });
+ anAlias = ncb.getName();
+ if (anAlias == null || anAlias.trim().length() == 0)
+ throw new SecurityException(Messages.getString("DeleteCmd.20")); //$NON-NLS-1$
+ }
+ alias = anAlias.trim();
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/ExportCmd.java b/tools/gnu/classpath/tools/keytool/ExportCmd.java
new file mode 100644
index 000000000..0d1692245
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/ExportCmd.java
@@ -0,0 +1,266 @@
+/* ExportCmd.java -- The export command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.java.security.util.Base64;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.logging.Logger;
+
+/**
+ * The <b>-export</b> keytool command handler is used to read the certificate
+ * associated with a designated alias from the key store, and write it to a
+ * designated file.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the file where the certificate will be
+ * exported to. If omitted, STDOUT will be used instead.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-rfc</dt>
+ * <dd>Use RFC-1421 specifications when encoding the output.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Output the certificate in binary DER encoding. This is the default
+ * output format of the command if neither <code>-rfc</code> nor
+ * <code>-v</code> options were detected on the command line. If both this
+ * option and the <code>-rfc</code> option are detected on the command
+ * line, the tool will opt for the RFC-1421 style encoding.</dd>
+ * </dl>
+ */
+class ExportCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(ExportCmd.class.getName());
+ private String _alias;
+ private String _certFileName;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private boolean rfc;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certFileName = pathName;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ /**
+ * @param flag whether to use, or not, RFC-1421 format when exporting the
+ * certificate(s).
+ */
+ public void setRfc(String flag)
+ {
+ this.rfc = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS
+ _alias = args[++i];
+ else if ("-file".equals(opt)) // -file FILE_NAME
+ _certFileName = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME
+ _providerClassName = args[++i];
+ else if ("-rfc".equals(opt))
+ rfc = true;
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(_certFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(alias);
+
+ log.finer("-export handler will use the following options:");
+ log.finer(" -alias=" + alias);
+ log.finer(" -file=" + _certFileName);
+ log.finer(" -storetype=" + storeType);
+ log.finer(" -keystore=" + storeURL);
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars));
+ log.finer(" -provider=" + provider);
+ log.finer(" -rfc=" + rfc);
+ log.finer(" -v=" + verbose);
+ }
+
+ void start() throws KeyStoreException, CertificateEncodingException,
+ IOException
+ {
+ log.entering(this.getClass().getName(), "start");
+
+ ensureStoreContainsAlias();
+ Certificate certificate;
+ if (store.isCertificateEntry(alias))
+ {
+ log.fine("Alias [" + alias + "] is a trusted certificate");
+ certificate = store.getCertificate(alias);
+ }
+ else
+ {
+ log.fine("Alias [" + alias + "] is a key entry");
+ Certificate[] chain = store.getCertificateChain(alias);
+ certificate = chain[0];
+ }
+
+ byte[] derBytes = certificate.getEncoded();
+ if (rfc)
+ {
+ String encoded = Base64.encode(derBytes, 0, derBytes.length, true);
+ PrintWriter pw = new PrintWriter(outStream, true);
+ pw.println("-----BEGIN CERTIFICATE-----");
+ pw.println(encoded);
+ pw.println("-----END CERTIFICATE-----");
+ }
+ else
+ outStream.write(derBytes);
+
+ // stream is closed in Command.teardown()
+ log.exiting(this.getClass().getName(), "start");
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/GenKeyCmd.java b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java
new file mode 100644
index 000000000..2d92134c2
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/GenKeyCmd.java
@@ -0,0 +1,511 @@
+/* GenKeyCmd.java -- The genkey command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.java.security.util.Util;
+import gnu.java.security.x509.X500DistinguishedName;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-genkey</b> keytool command handler is used to generate a key pair (a
+ * public, and associated private keys). It then generates a self-signed X509 v1
+ * certificate (authenticating the public key) and stores this certificate and
+ * the private key in the key store associating both to a designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-keyalg ALGORITHM</dt>
+ * <dd>Use this option to specify the canonical name of the key-pair
+ * generation algorithm. The default value for this option is
+ * <code>DSS</code> (a synonym for the Digital Signature Algorithm also
+ * known as <code>DSA</code>).
+ * <p></dd>
+ *
+ * <dt>-keysize KEY_SIZE</dt>
+ * <dd>Use this option to specify the number of bits of the shared modulus
+ * (for both the public and private keys) to use when generating new keys.
+ * A default value of <code>1024</code> will be used if this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-sigalg ALGORITHM</dt>
+ * <dd>The canonical name of the digital signature algorithm to use for
+ * signing certificates. If this option is omitted, a default value will be
+ * chosen based on the type of the key-pair; i.e. the algorithm that ends
+ * up being used by the <code>-keyalg</code> option. If the key-pair
+ * generation algorithm is <code>DSA</code>, the value for the signature
+ * algorithm will be <code>SHA1withDSA</code>. If on the other hand the
+ * key-pair generation algorithm is <code>RSA</code>, then the tool will
+ * use <code>MD5withRSA</code> as the signature algorithm.
+ * <p></dd>
+ *
+ * <dt>-dname NAME</dt>
+ * <dd>This a mandatory value for this command. If this option is omitted
+ * the tool will prompt you to enter a <i>Distinguished Name</i> to use as
+ * both the <i>Owner</i> and <i>Issuer</i> of the generated self-signed
+ * certificate.
+ * <p>
+ * The syntax of a valid value for this option MUST follow RFC-2253
+ * specifications. Namely the following components (with their accepted
+ * meaning) will be recognized. Note that the component name is case-
+ * insensitive:
+ * <dl>
+ * <dt>CN</dt>
+ * <dd>The Common Name; e.g. "host.domain.com"</dd>
+ *
+ * <dt>OU</dt>
+ * <dd>The Organizational Unit; e.g. "IT Department"</dd>
+ *
+ * <dt>O</dt>
+ * <dd>The Organization Name; e.g. "The Sample Company"</dd>
+ *
+ * <dt>L</dt>
+ * <dd>The Locality Name; e.g. "Sydney"</dd>
+ *
+ * <dt>ST</dt>
+ * <dd>The State Name; e.g. "New South Wales"</dd>
+ *
+ * <dt>C</dt>
+ * <dd>The 2-letter Country identifier; e.g. "AU"</dd>
+ * </dl>
+ * <p>
+ * When specified with a <code>-dname</code> option, each pair of component
+ * / value will be separated from the other with a comma. Each component
+ * and value pair MUST be separated by an equal sign. For example, the
+ * following is a valid DN value:
+ * <pre>
+ * CN=host.domain.com, O=The Sample Company, L=Sydney, ST=NSW, C=AU
+ * </pre>
+ * If this option is omitted, the tool will prompt you to enter the
+ * information through the console.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * protect the newly created Key Entry.
+ * <p>
+ * If this option is omitted, you will be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-validity DAY_COUNT</dt>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class GenKeyCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(GenKeyCmd.class.getName());
+ /** Default key size in bits. */
+ private static final int DEFAULT_KEY_SIZE = 1024;
+
+ private String _alias;
+ private String _keyAlgorithm;
+ private String _keySizeStr;
+ private String _sigAlgorithm;
+ private String _dName;
+ private String _password;
+ private String _validityStr;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private int keySize;
+ private X500DistinguishedName distinguishedName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param algorithm the canonical name of the key-pair algorithm to use. */
+ public void setKeyalg(String algorithm)
+ {
+ this._keyAlgorithm = algorithm;
+ }
+
+ /**
+ * @param bits the string representation of the number of bits (a decimal
+ * positive integer) the modulus of the generated keys (private and
+ * public) should have.
+ */
+ public void setKeysize(String bits)
+ {
+ this._validityStr = bits;
+ }
+
+ /**
+ * @param algorithm the canonical name of the digital signature algorithm to
+ * use.
+ */
+ public void setSigalg(String algorithm)
+ {
+ this._sigAlgorithm = algorithm;
+ }
+
+ /** @param name the distiniguished name to use. */
+ public void setDname(String name)
+ {
+ this._dName = name;
+ }
+
+ /** @param password the (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /**
+ * @param days the string representation of the number of days (a decimal,
+ * positive integer) to assign to the generated certificate.
+ */
+ public void setValidity(String days)
+ {
+ this._validityStr = days;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-keyalg".equals(opt)) // -keyalg ALGORITHM //$NON-NLS-1$
+ _keyAlgorithm = args[++i];
+ else if ("-keysize".equals(opt)) // -keysize KEY_SIZE //$NON-NLS-1$
+ _keySizeStr = args[++i];
+ else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM //$NON-NLS-1$
+ _sigAlgorithm = args[++i];
+ else if ("-dname".equals(opt)) // -dname NAME //$NON-NLS-1$
+ _dName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-validity".equals(opt)) // -validity DAY_COUNT //$NON-NLS-1$
+ _validityStr = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordParam(_password);
+ setAlgorithmParams(_keyAlgorithm, _sigAlgorithm);
+ setKeySize(_keySizeStr);
+ setDName(_dName);
+ setValidityParam(_validityStr);
+
+ log.finer("-genkey handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -keyalg=" + keyPairGenerator.getAlgorithm()); //$NON-NLS-1$
+ log.finer(" -keysize=" + keySize); //$NON-NLS-1$
+ log.finer(" -sigalg=" + signatureAlgorithm.getAlgorithm()); //$NON-NLS-1$
+ log.finer(" -dname=" + distinguishedName); //$NON-NLS-1$
+ log.finer(" -keypass=" + String.valueOf(keyPasswordChars)); //$NON-NLS-1$
+ log.finer(" -validity=" + validityInDays); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws CertificateException, KeyStoreException,
+ InvalidKeyException, SignatureException, IOException,
+ NoSuchAlgorithmException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ // 1. generate a new key-pair
+ log.fine("About to generate key-pair...");
+ keyPairGenerator.initialize(keySize);
+ KeyPair kp = keyPairGenerator.generateKeyPair();
+ PublicKey publicKey = kp.getPublic();
+ PrivateKey privateKey = kp.getPrivate();
+
+ // 2. generate a self-signed certificate
+ log.fine("About to generate a self-signed certificate...");
+ byte[] derBytes = getSelfSignedCertificate(distinguishedName,
+ publicKey,
+ privateKey);
+ log.finest(Util.dumpString(derBytes, "derBytes ")); //$NON-NLS-1$
+ CertificateFactory x509Factory = CertificateFactory.getInstance(Main.X_509);
+ ByteArrayInputStream bais = new ByteArrayInputStream(derBytes);
+ Certificate certificate = x509Factory.generateCertificate(bais);
+ log.finest("certificate = " + certificate); //$NON-NLS-1$
+
+ // 3. store it, w/ its private key, associating them to alias
+ Certificate[] chain = new Certificate[] { certificate };
+ log.finest("About to store newly generated material in key store..."); //$NON-NLS-1$
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, chain);
+
+ // 4. persist the key store
+ saveKeyStore();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * @param size the desired key size as a string.
+ * @throws NumberFormatException if the string does not represent a valid
+ * decimal integer value.
+ */
+ private void setKeySize(String size)
+ {
+ if (size == null || size.trim().length() == 0)
+ this.keySize = DEFAULT_KEY_SIZE;
+ else
+ {
+ size = size.trim();
+ keySize = Integer.parseInt(size);
+ // When generating a DSA key pair, the key size must be in the range
+ // from 512 to 1024 bits, and must be a multiple of 64. The default
+ // key size for any algorithm is 1024 bits
+ if (keySize < 1)
+ throw new IllegalArgumentException(Messages.getString("GenKeyCmd.54")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @param name the X.500 distinguished name of the principal for whom the
+ * key/certificate are being generated.
+ * @throws UnsupportedCallbackException if no implementation of a name
+ * callback is available.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws IllegalArgumentException if the designated, or captured, value is
+ * not a valid X.500 distinguished name.
+ */
+ private void setDName(String name) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (name != null && name.trim().length() > 0)
+ name = name.trim();
+ else
+ {
+ // prompt user to provide one
+ String dnTxt = Messages.getString("GenKeyCmd.0"); //$NON-NLS-1$
+ String oDefault = Messages.getString("GenKeyCmd.6"); //$NON-NLS-1$
+ String lDefault = Messages.getString("GenKeyCmd.7"); //$NON-NLS-1$
+ String stDefault = Messages.getString("GenKeyCmd.8"); //$NON-NLS-1$
+ String cDefault = Messages.getString("GenKeyCmd.9"); //$NON-NLS-1$
+ String cnPrompt = Messages.getString("GenKeyCmd.10"); //$NON-NLS-1$
+ String oPrompt = Messages.getFormattedString("GenKeyCmd.11", oDefault); //$NON-NLS-1$
+ String ouPrompt = Messages.getString("GenKeyCmd.13"); //$NON-NLS-1$
+ String lPrompt = Messages.getFormattedString("GenKeyCmd.14", lDefault); //$NON-NLS-1$
+ String stPrompt = Messages.getFormattedString("GenKeyCmd.16", stDefault); //$NON-NLS-1$
+ String cPrompt = Messages.getFormattedString("GenKeyCmd.18", cDefault); //$NON-NLS-1$
+
+ TextOutputCallback dnCB = new TextOutputCallback(TextOutputCallback.INFORMATION,
+ dnTxt);
+ TextInputCallback cnCB = new TextInputCallback(cnPrompt);
+ TextInputCallback oCB = new TextInputCallback(oPrompt, oDefault);
+ TextInputCallback ouCB = new TextInputCallback(ouPrompt);
+ TextInputCallback lCB = new TextInputCallback(lPrompt, lDefault);
+ TextInputCallback sCB = new TextInputCallback(stPrompt, stDefault);
+ TextInputCallback cCB = new TextInputCallback(cPrompt, cDefault);
+ getCallbackHandler().handle(new Callback[] { dnCB, cnCB, oCB, ouCB, lCB, sCB, cCB });
+ StringBuilder sb = new StringBuilder();
+
+ // handle CN
+ name = parseUserPrompt(cnCB);
+ if (name != null && name.length() > 0)
+ sb.append("CN=").append(name); //$NON-NLS-1$
+
+ // handle O
+ name = parseUserPrompt(oCB);
+ if (name != null && name.length() > 0)
+ sb.append(",O=").append(name); //$NON-NLS-1$
+
+ // handle OU
+ name = parseUserPrompt(ouCB);
+ if (name != null && name.length() > 0)
+ sb.append(",OU=").append(name.trim()); //$NON-NLS-1$
+
+ // handle L
+ name = parseUserPrompt(lCB);
+ if (name != null && name.length() > 0)
+ sb.append(",L=").append(name.trim()); //$NON-NLS-1$
+
+ // handle ST
+ name = parseUserPrompt(sCB);
+ if (name != null && name.length() > 0)
+ sb.append(",ST=").append(name.trim()); //$NON-NLS-1$
+
+ // handle C
+ name = parseUserPrompt(cCB);
+ if (name != null && name.length() > 0)
+ sb.append(",C=").append(name.trim()); //$NON-NLS-1$
+
+ name = sb.toString().trim();
+ }
+
+ log.fine("dName=[" + name + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ distinguishedName = new X500DistinguishedName(name);
+ }
+
+ private String parseUserPrompt(TextInputCallback ticb)
+ {
+ String result = ticb.getText();
+ if (result == null || result.trim().length() == 0)
+ result = ticb.getDefaultText();
+ else if (result.trim().equals(".")) //$NON-NLS-1$
+ result = null;
+ else
+ result = result.trim();
+
+ return result;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java b/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java
new file mode 100644
index 000000000..cb6b6dac2
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/IdentityDBCmd.java
@@ -0,0 +1,185 @@
+/* IdentityDBCmd.java -- The identitydb command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import java.util.logging.Logger;
+
+/**
+ * <b>NOT IMPLEMENTED YET</b>
+ * <p>
+ * The <b>-identitydb</b> keytool command handler is used to read the JDK 1.1.x-
+ * style identity database and add its entries to the key store. If a key store
+ * does not exist, it is created.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the identity file to import. If this
+ * option is omitted, the tool will process STDIN.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class IdentityDBCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(IdentityDBCmd.class.getName());
+ private String _idbFileName;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._idbFileName = pathName;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-file".equals(opt)) // -file FILE_NAME
+ _idbFileName = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_idbFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+
+ log.finer("-identitydb handler will use the following options:");
+ log.finer(" -file=" + _idbFileName);
+ log.finer(" -storetype=" + storeType);
+ log.finer(" -keystore=" + storeURL);
+ log.finer(" -storepass=" + new String(storePasswordChars));
+ log.finer(" -provider=" + provider);
+ log.finer(" -v=" + verbose);
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/ImportCmd.java b/tools/gnu/classpath/tools/keytool/ImportCmd.java
new file mode 100644
index 000000000..b5058b581
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/ImportCmd.java
@@ -0,0 +1,751 @@
+/* ImportCmd.java -- The import command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.SystemProperties;
+import gnu.java.security.x509.X509CertPath;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.PKIXParameters;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <code>-import</code> keytool command handler is used to read an X.509
+ * certificate, or a PKCS#7 Certificate Reply from a designated input source and
+ * incorporate the certificates into the key store.
+ * <p>
+ * If the <i>Alias</i> does not already exist in the key store, the tool treats
+ * the certificate read from the input source as a new Trusted Certificate. It
+ * then attempts to discover a chain-of-trust, starting from that certificate
+ * and ending at another <i>Trusted Certificate</i>, already stored in the key
+ * store. If the <code>-trustcacerts</code> option is present, an additional
+ * key store, of type <code>JKS</code> named <code>cacerts</code>, and assumed
+ * to be present in <code>${JAVA_HOME}/lib/security</code> will also be
+ * consulted if found --<code>${JAVA_HOME}</code> refers to the location of an
+ * installed Java Runtime Environment (JRE). If no chain-of-trust can be
+ * established, and unless the <code>-noprompt</code> option has been specified,
+ * the certificate is printed to STDOUT and the user is prompted for a
+ * confirmation.
+ * <p>
+ * If <i>Alias</i> exists in the key store, the tool will treat the
+ * certificate(s) read from the input source as a <i>Certificate Reply</i>,
+ * which can be a chain of certificates, that eventually would replace the chain
+ * of certificates associated with the <i>Key Entry</i> of that <i>Alias</i>.
+ * The substitution of the certificates only occurs if a chain-of-trust can be
+ * established between the bottom certificate of the chain read from the input
+ * file and the <i>Trusted Certificates</i> already present in the key store.
+ * Again, if the <code>-trustcacerts</code> option is specified, additional
+ * <i>Trusted Certificates</i> in the same <code>cacerts</code> key store will
+ * be considered. If no chain-of-trust can be established, the operation will
+ * abort.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the file to read from. If omitted, the
+ * tool will process STDIN.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * protect the <i>Key Entry</i> associated with the designated <i>Alias</i>,
+ * when replacing this <i>Alias</i>' chain of certificates with that found
+ * in the certificate reply.
+ * <p>
+ * If this option is omitted, and the chain-of-trust for the certificate
+ * reply has been established, the tool will first attempt to unlock the
+ * <i>Key Entry</i> using the same password protecting the key store. If
+ * this fails, you will then be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-noprompt</dt>
+ * <dd>Use this option to prevent the tool from prompting the user.
+ * <p></dd>
+ *
+ * <dt>-trustcacerts</dt>
+ * <dd>Use this option to indicate to the tool that a key store, of type
+ * <code>JKS</code>, named <code>cacerts</code>, and usually located in
+ * <code>lib/security</code> in an installed Java Runtime Environment
+ * should be considered when trying to establish chain-of-trusts.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class ImportCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(ImportCmd.class.getName());
+ private String _alias;
+ private String _certFileName;
+ private String _password;
+ private boolean noPrompt;
+ private boolean trustCACerts;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private CertificateFactory x509Factory;
+ private boolean imported;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the existing alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certFileName = pathName;
+ }
+
+ /** @param password the existing (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /**
+ * @param flag whether to prompt, or not, the user to verify certificate
+ * fingerprints.
+ */
+ public void setNoprompt(String flag)
+ {
+ this.noPrompt = Boolean.valueOf(flag).booleanValue();
+ }
+
+ /**
+ * @param flag whether to trust, or not, certificates found in the
+ * <code>cacerts</code> key store.
+ */
+ public void setTrustcacerts(String flag)
+ {
+ this.trustCACerts = Boolean.valueOf(flag).booleanValue();
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-file".equals(opt)) // -file FILE_NAME //$NON-NLS-1$
+ _certFileName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-noprompt".equals(opt)) //$NON-NLS-1$
+ noPrompt = true;
+ else if ("-trustcacerts".equals(opt)) //$NON-NLS-1$
+ trustCACerts = true;
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_certFileName);
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+
+ log.finer("-import handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -file=" + _certFileName); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -noprompt=" + noPrompt); //$NON-NLS-1$
+ log.finer(" -trustcacerts=" + trustCACerts); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws CertificateException, KeyStoreException, IOException,
+ UnsupportedCallbackException, NoSuchAlgorithmException,
+ CertPathValidatorException, UnrecoverableKeyException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ x509Factory = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$
+ // the alias will tell us whether we're dealing with
+ // a new trusted certificate or a certificate reply
+ if (! store.containsAlias(alias))
+ importNewTrustedCertificate();
+ else
+ {
+ ensureAliasIsKeyEntry();
+ importCertificateReply();
+ }
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * When importing a new trusted certificate, <i>alias</i> MUST NOT yet exist
+ * in the key store.
+ * <p>
+ * Before adding the certificate to the key store and associate it with the
+ * designated Alias, this method tries to verify it by attempting to construct
+ * a chain of trust from that certificate to a self-signed certificate
+ * (belonging to a root CA), using (already) trusted certificates that are
+ * available in the key store.
+ * <p>
+ * If the <code>-trustcacerts</code> option was detected on the command
+ * line, additional trusted certificates are considered for establishing the
+ * chain of trust. Those additional certificates are assumed to be in a key
+ * store, of type <code>JKS</code> named <code>cacerts</code> and usually
+ * located in <code>${JAVA_HOME}/lib/security</code>, where
+ * <code>${JAVA_HOME}</code> is the root folder location of a Java runtime.
+ * <p>
+ * If this method fails to establish a trust path from the certificate to be
+ * imported up to a trusted self-signed certificate, the certificate is
+ * printed to <code>STDOUT</code>, and the user is prompted to verify it,
+ * with the option of aborting the import operation. If however the option
+ * <code>-noprompt</code> was detected on the command line, no interaction
+ * with the user will take place and the import operation will abort.
+ *
+ * @throws CertificateException
+ * @throws KeyStoreException
+ * @throws NoSuchAlgorithmException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws CertPathValidatorException
+ */
+ private void importNewTrustedCertificate() throws CertificateException,
+ KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, CertPathValidatorException,
+ UnrecoverableKeyException
+ {
+ log.entering(this.getClass().getName(), "importNewTrustedCertificate"); //$NON-NLS-1$
+
+ Certificate certificate = x509Factory.generateCertificate(inStream);
+ log.finest("certificate = " + certificate); //$NON-NLS-1$
+ LinkedList orderedReply = new LinkedList();
+ orderedReply.addLast(certificate);
+
+ if (findTrustAndUpdate(orderedReply, ! noPrompt))
+ {
+ store.setCertificateEntry(alias, certificate);
+ System.out.println(Messages.getString("ImportCmd.29")); //$NON-NLS-1$
+ saveKeyStore();
+ }
+ else
+ System.out.println(Messages.getString("ImportCmd.28")); //$NON-NLS-1$
+
+ log.exiting(this.getClass().getName(), "importNewTrustedCertificate"); //$NON-NLS-1$
+ }
+
+ /**
+ * A certificate reply is a certificate, whose Owner is stored in the key
+ * store associated to the designated Alias, and now signed by supposedly a
+ * trusted CA (Certificate Authority). In other words, the Subject in this
+ * certificate reply is Alias's own and the Issuer is a CA.
+ * <p>
+ * When importing a certificate reply, the reply is validated using trusted
+ * certificates from the key store, and optionally (if the option
+ * <code>-trustcacerts</code> was detected on the command line) certificates
+ * found in the key store, of type <code>JKS</code> named <code>cacerts</code>
+ * located in <code>${JAVA_HOME}/lib/security</code>, where
+ * <code>${JAVA_HOME}</code> is the root folder location of a Java runtime.
+ *
+ * @throws CertificateException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws KeyStoreException
+ * @throws CertPathValidatorException
+ * @throws NoSuchAlgorithmException
+ * @throws UnrecoverableKeyException
+ */
+ private void importCertificateReply() throws CertificateException,
+ IOException, UnsupportedCallbackException, KeyStoreException,
+ NoSuchAlgorithmException, CertPathValidatorException,
+ UnrecoverableKeyException
+ {
+ log.entering(this.getClass().getName(), "importCertificateReply"); //$NON-NLS-1$
+
+ Collection certificates = x509Factory.generateCertificates(inStream);
+ ensureReplyIsOurs(certificates);
+ // we now have established that the public keys are the same.
+ // find a chain-of-trust if one exists
+ if (certificates.size() == 1)
+ importCertificate((Certificate) certificates.iterator().next());
+ else
+ importChain(certificates);
+
+ log.exiting(this.getClass().getName(), "importCertificateReply"); //$NON-NLS-1$
+ }
+
+ /**
+ * If the reply is a single X.509 certificate, keytool attempts to establish a
+ * trust chain, starting at the certificate reply and ending at a self-signed
+ * certificate (belonging to a root CA). The certificate reply and the
+ * hierarchy of certificates used to authenticate the certificate reply form
+ * the new certificate chain of alias. If a trust chain cannot be established,
+ * the certificate reply is not imported. In this case, keytool does not print
+ * out the certificate, nor does it prompt the user to verify it. This is
+ * because it is very hard (if not impossible) for a user to determine the
+ * authenticity of the certificate reply.
+ *
+ * @param certificate the certificate reply to import into the key store.
+ * @throws NoSuchAlgorithmException
+ * @throws CertPathValidatorException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws KeyStoreException
+ * @throws CertificateException
+ */
+ private void importCertificate(Certificate certificate)
+ throws NoSuchAlgorithmException, CertPathValidatorException,
+ KeyStoreException, UnrecoverableKeyException, IOException,
+ UnsupportedCallbackException, CertificateException
+ {
+ log.entering(this.getClass().getName(), "importCertificate", certificate); //$NON-NLS-1$
+
+ LinkedList reply = new LinkedList();
+ reply.addLast(certificate);
+
+ if (! findTrustAndUpdate(reply, false))
+ throw new CertPathValidatorException(Messages.getString("ImportCmd.34")); //$NON-NLS-1$
+
+ Certificate[] newChain = (Certificate[]) reply.toArray(new Certificate[0]);
+ Key privateKey = getAliasPrivateKey();
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, newChain);
+ saveKeyStore();
+
+ log.exiting(this.getClass().getName(), "importCertificate"); //$NON-NLS-1$
+ }
+
+ /**
+ * If the reply is a PKCS#7 formatted certificate chain, the chain is first
+ * ordered (with the user certificate first and the self-signed root CA
+ * certificate last), before keytool attempts to match the root CA certificate
+ * provided in the reply with any of the trusted certificates in the key store
+ * or the "cacerts" keystore file (if the -trustcacerts option was specified).
+ * If no match can be found, the information of the root CA certificate is
+ * printed out, and the user is prompted to verify it, e.g., by comparing the
+ * displayed certificate fingerprints with the fingerprints obtained from some
+ * other (trusted) source of information, which might be the root CA itself.
+ * The user then has the option of aborting the import operation. If the
+ * -noprompt option is given, however, there will be no interaction with the
+ * user.
+ *
+ * @param chain the collection of certificates parsed from the user
+ * designated input.
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws KeyStoreException
+ * @throws CertPathValidatorException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ */
+ private void importChain(Collection chain) throws NoSuchAlgorithmException,
+ CertPathValidatorException, KeyStoreException, UnrecoverableKeyException,
+ IOException, UnsupportedCallbackException, CertificateException
+ {
+ log.entering(this.getClass().getName(), "importChain", chain); //$NON-NLS-1$
+
+ LinkedList reply = orderChain(chain);
+ if (findTrustAndUpdate(reply, ! noPrompt))
+ {
+ Certificate[] newChain = (Certificate[]) reply.toArray(new Certificate[0]);
+ Key privateKey = getAliasPrivateKey();
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, newChain);
+ saveKeyStore();
+ }
+
+ log.exiting(this.getClass().getName(), "importChain"); //$NON-NLS-1$
+ }
+
+ /**
+ * Check to ensure that alias's public key is the subject of the first
+ * certificate in the passed certificate collection. Throws an exception if
+ * the public keys do not match.
+ *
+ * @param certificates a {@link Collection} of certificate replies (either a
+ * signle certificate reply, or a PKCS#7 certificate reply chain)
+ * usually sent by a CA as a response to a Certificate Signing
+ * Request (CSR).
+ * @throws IOException
+ * @throws UnsupportedCallbackException
+ * @throws KeyStoreException
+ */
+ private void ensureReplyIsOurs(Collection certificates) throws IOException,
+ UnsupportedCallbackException, KeyStoreException
+ {
+ log.entering(this.getClass().getName(), "ensureReplyIsOurs"); //$NON-NLS-1$
+
+ Certificate certificate = (Certificate) certificates.iterator().next();
+ log.finest("certificate = " + certificate); //$NON-NLS-1$
+ Certificate[] chain = store.getCertificateChain(alias);
+ if (chain == null)
+ throw new IllegalArgumentException(Messages.getFormattedString("ImportCmd.37", //$NON-NLS-1$
+ alias));
+ Certificate anchor = chain[0];
+ PublicKey anchorPublicKey = anchor.getPublicKey();
+ PublicKey certPublicKey = certificate.getPublicKey();
+ boolean sameKey;
+ if (anchorPublicKey instanceof DSAPublicKey)
+ {
+ DSAPublicKey pk1 = (DSAPublicKey) anchorPublicKey;
+ if (!(certPublicKey instanceof DSAPublicKey))
+ throw new IllegalArgumentException(Messages.getString("ImportCmd.38")); //$NON-NLS-1$
+
+ sameKey = areEqual(pk1, (DSAPublicKey) certPublicKey);
+ }
+ else if (anchorPublicKey instanceof RSAPublicKey)
+ {
+ RSAPublicKey pk1 = (RSAPublicKey) anchorPublicKey;
+ if (!(certPublicKey instanceof RSAPublicKey))
+ throw new IllegalArgumentException(Messages.getString("ImportCmd.38")); //$NON-NLS-1$
+
+ sameKey = areEqual(pk1, (RSAPublicKey) certPublicKey);
+ }
+ else
+ throw new IllegalArgumentException(
+ Messages.getFormattedString("ImportCmd.40", //$NON-NLS-1$
+ new String[] { alias,
+ anchorPublicKey.getClass().getName() }));
+ if (! sameKey)
+ throw new IllegalArgumentException(Messages.getString("ImportCmd.41")); //$NON-NLS-1$
+
+ log.exiting(this.getClass().getName(), "ensureReplyIsOurs"); //$NON-NLS-1$
+ }
+
+ private boolean areEqual(DSAPublicKey pk1, DSAPublicKey pk2)
+ {
+ if (pk1.getY().compareTo(pk2.getY()) != 0)
+ return false;
+
+ DSAParams p1 = pk1.getParams();
+ DSAParams p2 = pk2.getParams();
+ if (p1.getG().compareTo(p2.getG()) != 0)
+ return false;
+
+ if (p1.getP().compareTo(p2.getP()) != 0)
+ return false;
+
+ return p1.getQ().compareTo(p2.getQ()) == 0;
+ }
+
+ private boolean areEqual(RSAPublicKey pk1, RSAPublicKey pk2)
+ {
+ if (pk1.getPublicExponent().compareTo(pk2.getPublicExponent()) != 0)
+ return false;
+
+ return pk1.getModulus().compareTo(pk2.getModulus()) == 0;
+ }
+
+ /**
+ * @param chain
+ * @return the input collection, ordered with own certificate first, and CA's
+ * self-signed certificate last.
+ */
+ private LinkedList orderChain(Collection chain)
+ {
+ log.entering(this.getClass().getName(), "orderChain"); //$NON-NLS-1$
+
+ LinkedList result = new LinkedList();
+
+
+ log.entering(this.getClass().getName(), "orderChain", result); //$NON-NLS-1$
+ return result;
+ }
+
+ /**
+ * Given an ordered list of certificates, this method attempts to validate the
+ * chain, and if successful, updates the key store entry for the designated
+ * alias. The list of certificates is expected to be ordered as a chain, where
+ * the first is the alias's own certificate and the last being a self-signed
+ * CA certificate.
+ * <p>
+ * if <code>promptUser</code> is <code>true</code>, then even if no
+ * anchor trust certificate is found, the user is prompted to approve, or not,
+ * the import operation. On the other hand if the <code>promptUser</code>
+ * parameter is <code>false</code> then this method will throw an exception
+ * if no trust anchor is to be found.
+ *
+ * @param reply an ordered certificate path, where the last entry is the CA's
+ * self-signed certificate.
+ * @param promptUser a boolean flag indicating whether or not to prompt the
+ * user for explicit trust in a CA certificate.
+ * @return <code>true</code> if the validation succeeds; or <code>false</code>
+ * otherwise.
+ * @throws NoSuchAlgorithmException
+ * @throws CertPathValidatorException
+ * @throws UnsupportedCallbackException
+ * @throws IOException
+ * @throws UnrecoverableKeyException
+ * @throws KeyStoreException
+ * @throws CertificateEncodingException
+ */
+ private boolean findTrustAndUpdate(LinkedList reply, boolean promptUser)
+ throws IOException, NoSuchAlgorithmException, CertPathValidatorException,
+ KeyStoreException, UnrecoverableKeyException, UnsupportedCallbackException,
+ CertificateEncodingException
+ {
+ log.entering(this.getClass().getName(), "findTrustAndUpdate"); //$NON-NLS-1$
+
+ X509CertPath certPath = new X509CertPath(reply);
+ CertPathValidator validator = CertPathValidator.getInstance("PKIX"); //$NON-NLS-1$
+ PKIXCertPathValidatorResult cpvr = findTrustInStore(certPath, validator);
+ if (cpvr == null && trustCACerts)
+ cpvr = findTrustInCACerts(certPath, validator);
+
+ boolean result = false;
+ if (cpvr == null)
+ {
+ if (promptUser)
+ {
+ printVerbose((Certificate) reply.getLast());
+ ConfirmationCallback ccb;
+ ccb = new ConfirmationCallback(Messages.getString("ImportCmd.32"), //$NON-NLS-1$
+ ConfirmationCallback.INFORMATION,
+ ConfirmationCallback.YES_NO_OPTION,
+ ConfirmationCallback.NO);
+ getCallbackHandler().handle(new Callback[] { ccb });
+ int answer = ccb.getSelectedIndex();
+ result = answer == ConfirmationCallback.YES;
+ }
+ }
+ else
+ {
+ log.fine("Found a chain-of-trust anchored by " + cpvr.getTrustAnchor()); //$NON-NLS-1$
+ Certificate trustedCert = cpvr.getTrustAnchor().getTrustedCert();
+ reply.addLast(trustedCert);
+ result = true;
+ }
+
+ log.entering(this.getClass().getName(), "findTrustAndUpdate", //$NON-NLS-1$
+ Boolean.valueOf(result));
+ return result;
+ }
+
+ private PKIXCertPathValidatorResult findTrustInStore(X509CertPath certPath,
+ CertPathValidator validator)
+ {
+ log.entering(this.getClass().getName(), "findTrustInStore"); //$NON-NLS-1$
+
+ PKIXCertPathValidatorResult result;
+ try
+ {
+ PKIXParameters params = new PKIXParameters(store);
+ result = (PKIXCertPathValidatorResult) validator.validate(certPath, params);
+ }
+ catch (Exception x)
+ {
+ log.log(Level.FINE,
+ "Exception in findTrustInStore(). Ignore + Return NULL", //$NON-NLS-1$
+ x);
+ result = null;
+ }
+
+ log.exiting(this.getClass().getName(), "findTrustInStore", result); //$NON-NLS-1$
+ return result;
+ }
+
+ private PKIXCertPathValidatorResult findTrustInCACerts(X509CertPath certPath,
+ CertPathValidator validator)
+ {
+ log.entering(this.getClass().getName(), "findTrustInCACerts"); //$NON-NLS-1$
+
+ FileInputStream stream = null;
+ PKIXCertPathValidatorResult result = null;
+ try
+ {
+ KeyStore cacerts = KeyStore.getInstance("jks"); //$NON-NLS-1$
+ String cacertsPath = SystemProperties.getProperty("java.home");
+ String fs = SystemProperties.getProperty("file.separator"); //$NON-NLS-1$
+ cacertsPath = new StringBuilder(cacertsPath).append(fs)
+ .append("lib").append(fs) //$NON-NLS-1$
+ .append("security").append(fs) //$NON-NLS-1$
+ .append("cacerts").toString(); //$NON-NLS-1$
+ stream = new FileInputStream(cacertsPath);
+ cacerts.load(stream, "changeit".toCharArray()); //$NON-NLS-1$
+ PKIXParameters params = new PKIXParameters(cacerts);
+ result = (PKIXCertPathValidatorResult) validator.validate(certPath,
+ params);
+ }
+ catch (Exception x)
+ {
+ log.log(Level.FINE,
+ "Exception in findTrustInCACerts(). Ignore + Return NULL", //$NON-NLS-1$
+ x);
+ }
+ finally
+ {
+ if (stream != null)
+ try
+ {
+ stream.close();
+ }
+ catch (Exception ignored)
+ {
+ }
+ }
+
+ log.exiting(this.getClass().getName(), "findTrustInCACerts", result); //$NON-NLS-1$
+ return result;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java b/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java
new file mode 100644
index 000000000..5936719f7
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/KeyCloneCmd.java
@@ -0,0 +1,344 @@
+/* KeyCloneCmd.java -- The keyclone command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-keyclone</b> keytool command handler is used to clone an existing
+ * key store entry associated with a designated alias, with its private key and
+ * chain of certificates.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-dest ALIAS</dt>
+ * <dd>Use this option to specify the new <i>Alias</i> which will be used
+ * to identify the cloned copy of the <i>Key Entry</i>.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * unlock the <i>Key Entry</i> associated with the designated <i>Alias</i>.
+ * <p>
+ * If this option is omitted, the tool will first attempt to unlock the
+ * <i>Key Entry</i> using the same password protecting the key store. If
+ * this fails, you will then be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-new PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the private key
+ * material of the newly cloned copy of the <i>Key Entry</i>.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class KeyCloneCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(KeyCloneCmd.class.getName());
+ private String _alias;
+ private String _destAlias;
+ private String _password;
+ private String _newPassword;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private String destinationAlias;
+ private char[] newKeyPasswordChars;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the existing alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param alias the new alias to use. */
+ public void setDest(String alias)
+ {
+ this._destAlias = alias;
+ }
+
+ /** @param password the existing (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param password the new (private) key password to use. */
+ public void setNew(String password)
+ {
+ this._newPassword = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-dest".equals(opt)) // -dest ALIAS //$NON-NLS-1$
+ _destAlias = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$
+ _newPassword = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+ setDestinationAlias(_destAlias);
+// setNewKeyPassword(_newPassword);
+
+ log.finer("-keyclone handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -dest=" + destinationAlias); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -new=" + _newPassword); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ CertificateException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ if (store.containsAlias(destinationAlias))
+ throw new SecurityException(Messages.getString("KeyCloneCmd.23")); //$NON-NLS-1$
+
+ Key privateKey = getAliasPrivateKey();
+
+ setNewKeyPassword(_newPassword);
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ store.setKeyEntry(destinationAlias, privateKey, newKeyPasswordChars, chain);
+
+ saveKeyStore();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ private void setDestinationAlias(String name) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (name == null || name.trim().length() == 0) // ask user to provide one
+ {
+ NameCallback ncb = new NameCallback(Messages.getString("KeyCloneCmd.26")); //$NON-NLS-1$
+ getCallbackHandler().handle(new Callback[] { ncb });
+ name = ncb.getName();
+ if (name == null || name.trim().length() == 0)
+ throw new IllegalArgumentException(Messages.getString("KeyCloneCmd.27")); //$NON-NLS-1$
+ }
+
+ destinationAlias = name.trim();
+ }
+
+ private void setNewKeyPassword(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null) // ask user to provide one
+ newKeyPasswordChars = password.toCharArray();
+ else
+ {
+ boolean ok = false;
+ Callback[] prompts = new Callback[1];
+ Callback[] errors = new Callback[1];
+ for (int i = 0; i < 3; i++)
+ if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
+ {
+ ok = true;
+ break;
+ }
+ if (! ok)
+ throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
+ }
+ }
+
+ private boolean prompt4NewPassword(CallbackHandler handler,
+ Callback[] prompts, Callback[] errors)
+ throws IOException, UnsupportedCallbackException
+ {
+ String p = Messages.getFormattedString("KeyCloneCmd.28", //$NON-NLS-1$
+ new String[] { destinationAlias,
+ String.valueOf(keyPasswordChars) });
+ PasswordCallback pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd1 = pcb.getPassword();
+ pcb.clearPassword();
+ if (pwd1 == null || pwd1.length == 0)
+ {
+ newKeyPasswordChars = (char[]) keyPasswordChars.clone();
+ return true;
+ }
+
+ if (pwd1.length < 6)
+ {
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR,
+ Messages.getString("StorePasswdCmd.21")); //$NON-NLS-1$
+ handler.handle(errors);
+ return false;
+ }
+
+ newKeyPasswordChars = pwd1;
+ return true;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java b/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java
new file mode 100644
index 000000000..9dc7b8164
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java
@@ -0,0 +1,339 @@
+/* KeyPasswdCmd.java -- The keypasswd command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.SystemProperties;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-keypasswd</b> keytool command handler is used to change the password
+ * protecting the private key associated to a designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ * <dd>Use this option to specify the password which the tool will use to
+ * unlock the <i>Key Entry</i> associated with the designated <i>Alias</i>.
+ * <p>
+ * If this option is omitted, the tool will first attempt to unlock the
+ * <i>Key Entry</i> using the same password protecting the key store. If
+ * this fails, you will then be prompted to provide a password.
+ * <p></dd>
+ *
+ * <dt>-new PASSWORD</dt>
+ * <dd>The new, and different, password which will be used to protect the
+ * private key material of the designated Key Entry.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class KeyPasswdCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(KeyPasswdCmd.class.getName());
+ private String _alias;
+ private String _password;
+ private String _newPassword;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private char[] newPasswordChars;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param password the existing (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param password the new (private) key password to use. */
+ public void setNew(String password)
+ {
+ this._newPassword = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
+ _password = args[++i];
+ else if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$
+ _newPassword = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+// setNewKeyPassword(_newPassword);
+
+ log.finer("-keypasswd handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -keypass=" + _password); //$NON-NLS-1$
+ log.finer(" -new=" + _newPassword); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
+ UnsupportedCallbackException, UnrecoverableKeyException,
+ CertificateException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ // 1. get the key entry and certificate chain associated to alias
+ Key privateKey = getAliasPrivateKey();
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ // 2. replace the old entry
+ setNewKeyPassword(_newPassword);
+ store.setKeyEntry(alias, privateKey, newPasswordChars, chain);
+
+ // 3. persist the key store
+ saveKeyStore();
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * Set the new password to use for protecting Alias's private key.
+ *
+ * @param password the new key password. if <code>null</code> prompt the
+ * user to provide one. When prompting, the password is entered twice
+ * and compared for a match.
+ * @throws IOException if an I/O related exception occurs during the process.
+ * @throws UnsupportedCallbackException if no implementation of a password
+ * callback handler was found.
+ */
+ private void setNewKeyPassword(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null)
+ newPasswordChars = password.toCharArray();
+ else
+ {
+ boolean ok = false;
+ Callback[] prompts = new Callback[1];
+ Callback[] errors = new Callback[1];
+ for (int i = 0; i < 3; i++)
+ if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
+ {
+ ok = true;
+ break;
+ }
+ if (! ok)
+ throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
+ }
+ }
+
+ private boolean prompt4NewPassword(CallbackHandler handler,
+ Callback[] prompts, Callback[] errors)
+ throws IOException, UnsupportedCallbackException
+ {
+ // prompt user (1st time) to provide one
+ String p = Messages.getFormattedString("KeyPasswdCmd.24", alias); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd1 = pcb.getPassword();
+ pcb.clearPassword();
+ String ls = SystemProperties.getProperty("line.separator"); //$NON-NLS-1$
+ if (pwd1 == null || pwd1.length < 6)
+ {
+ String m = Messages.getString("StorePasswdCmd.21") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ if (Arrays.equals(keyPasswordChars, pwd1))
+ {
+ String m = Messages.getString("StorePasswdCmd.22") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ // prompt user (2nd time) for confirmation
+ p = Messages.getFormattedString("KeyPasswdCmd.28", alias); //$NON-NLS-1$
+ pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd2 = pcb.getPassword();
+ pcb.clearPassword();
+ if (! Arrays.equals(pwd1, pwd2))
+ {
+ String m = Messages.getString("StorePasswdCmd.24") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ newPasswordChars = pwd2;
+ return true;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/ListCmd.java b/tools/gnu/classpath/tools/keytool/ListCmd.java
new file mode 100644
index 000000000..655242785
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/ListCmd.java
@@ -0,0 +1,380 @@
+/* ListCmd.java -- The list command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.java.security.util.Base64;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.Enumeration;
+import java.util.logging.Logger;
+
+/**
+ * The <b>-list</b> keytool command handler is used to output one or all key
+ * store entries.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-rfc</dt>
+ * <dd>Use RFC-1421 specifications when encoding the output.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Output the certificate in human-readable format. If both this option
+ * and the <code>-rfc</code> option are detected on the command line, the
+ * tool will opt for the human-readable form and will not abort the
+ * command.</dd>
+ * </dl>
+ */
+class ListCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(ListCmd.class.getName());
+ private String _alias;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private boolean rfc;
+ private boolean all;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ /**
+ * @param flag whether to use, or not, RFC-1421 format when listing the
+ * certificate(s).
+ */
+ public void setRfc(String flag)
+ {
+ this.rfc = Boolean.valueOf(flag).booleanValue();
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
+ _alias = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else if ("-rfc".equals(opt)) //$NON-NLS-1$
+ rfc = true;
+ else
+ break;
+ }
+
+ all = _alias == null;
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setOutputStreamParam(null); // use stdout
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ if (! all)
+ setAliasParam(_alias);
+
+ if (verbose & rfc)
+ {
+ log.warning("Both -v and -rfc options were found on the command line. " //$NON-NLS-1$
+ + "Only the former will be considered"); //$NON-NLS-1$
+ rfc = false;
+ }
+
+ log.finer("-list handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -alias=" + alias); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ log.finer(" -rfc=" + rfc); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, CertificateEncodingException,
+ IOException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ PrintWriter writer = new PrintWriter(outStream, true);
+ writer.println(Messages.getFormattedString("ListCmd.21", store.getType())); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("ListCmd.22", //$NON-NLS-1$
+ store.getProvider().getName()));
+ if (all)
+ {
+ log.finest("About to list all aliases in key store..."); //$NON-NLS-1$
+ writer.println();
+ writer.println(Messages.getFormattedString("ListCmd.24", //$NON-NLS-1$
+ Integer.valueOf(store.size())));
+ for (Enumeration e = store.aliases(); e.hasMoreElements(); )
+ {
+ String anAlias = (String) e.nextElement();
+ if (anAlias != null)
+ list1Alias(anAlias, writer);
+ }
+ }
+ else
+ list1Alias(alias, writer);
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ /**
+ * Prints the certificate(s) associated with the designated alias.
+ *
+ * @param anAlias a non-null string denoting an alias in the key-store.
+ * @param writer where to print.
+ * @throws KeyStoreException if an exception occurs while obtaining the
+ * certificate associated to the designated alias.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form of the certificate.
+ * @throws IOException if an I/O related exception occurs during the process.
+ */
+ private void list1Alias(String anAlias, PrintWriter writer)
+ throws KeyStoreException, CertificateEncodingException, IOException
+ {
+ log.entering(this.getClass().getName(), "list1Alias", anAlias); //$NON-NLS-1$
+
+ writer.println();
+ writer.println(Messages.getFormattedString("ListCmd.30", anAlias)); //$NON-NLS-1$
+ writer.println(Messages.getFormattedString("ListCmd.31", store.getCreationDate(anAlias))); //$NON-NLS-1$
+
+ if (store.isCertificateEntry(anAlias))
+ {
+ writer.println(Messages.getString("ListCmd.32")); //$NON-NLS-1$
+ Certificate certificate = store.getCertificate(anAlias);
+ print1Certificate(certificate, writer);
+ }
+ else if (store.isKeyEntry(anAlias))
+ {
+ writer.println(Messages.getString("ListCmd.33")); //$NON-NLS-1$
+ Certificate[] chain = store.getCertificateChain(anAlias);
+ print1Chain(chain, writer);
+ }
+ else
+ throw new IllegalArgumentException(Messages.getFormattedString("ListCmd.34", //$NON-NLS-1$
+ anAlias));
+ log.exiting(this.getClass().getName(), "list1Alias"); //$NON-NLS-1$
+ }
+
+ /**
+ * Prints the designated certificate chain, or a fingerprint of the first
+ * certificate (bottom) in the chain, depending on the values of the flags
+ * <code>v</code> (for verbose) and <code>rfc</code>.
+ * <p>
+ * If both flags are <code>false</code>, only the fingerprint is generated,
+ * otherwise, if the <code>v</code> flag is set, then a human readable output
+ * is generated. If <code>rfc</code> is set, then an RFC-1421 like output
+ * is generated.
+ * <p>Note that both <code>v</code> and <code>rfc</code> cannot both be
+ * <code>true</code> at the same time.
+ *
+ * @param chain the certificate chain to process.
+ * @param writer where to print.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form of the certificate.
+ */
+ private void print1Chain(Certificate[] chain, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ if (!verbose && !rfc)
+ fingerprint(chain[0], writer);
+ else
+ {
+ int limit = chain.length;
+ writer.println(Messages.getFormattedString("ListCmd.38", //$NON-NLS-1$
+ Integer.valueOf(limit)));
+ writer.println(Messages.getString("ListCmd.39")); //$NON-NLS-1$
+ print1Certificate(chain[0], writer);
+ for (int i = 1; i < limit; i++)
+ {
+ writer.println();
+ writer.println(Messages.getFormattedString("ListCmd.40", //$NON-NLS-1$
+ Integer.valueOf(i + 1)));
+ print1Certificate(chain[i], writer);
+ }
+ writer.println();
+ writer.println(Messages.getString("ListCmd.42")); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Prints the designated certificate, or its fingerprint, depending on the
+ * values of the flags <code>v</code> (for verbose) and <code>rfc</code>.
+ * <p>
+ * If both flags are <code>false</code>, only a fingerprint is generated,
+ * otherwise, if the <code>v</code> flag is set, then a human readable output
+ * is generated. If <code>rfc</code> is set, then an RFC-1421 like output
+ * is generated.
+ * <p>Note that both <code>v</code> and <code>rfc</code> cannot both be
+ * <code>true</code> at the same time.
+ *
+ * @param certificate the certificate to process.
+ * @param writer where to print.
+ * @throws CertificateEncodingException if an exception occurs while obtaining
+ * the DER encoded form of the certificate.
+ */
+ private void print1Certificate(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ if (verbose)
+ printVerbose(certificate, writer);
+ else if (rfc)
+ printRFC1421(certificate, writer);
+ else
+ fingerprint(certificate, writer);
+ }
+
+ private void printRFC1421(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ byte[] derBytes = certificate.getEncoded();
+ String encoded = Base64.encode(derBytes, 0, derBytes.length, true);
+ writer.println(Messages.getString("ListCmd.43")); //$NON-NLS-1$
+ writer.println(encoded);
+ writer.println(Messages.getString("ListCmd.44")); //$NON-NLS-1$
+ }
+
+ private void fingerprint(Certificate certificate, PrintWriter writer)
+ throws CertificateEncodingException
+ {
+ byte[] derBytes = certificate.getEncoded();
+ String fingerPrint = digestWithMD5(derBytes);
+ writer.println(Messages.getFormattedString("ListCmd.45", fingerPrint)); //$NON-NLS-1$
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/Main.java b/tools/gnu/classpath/tools/keytool/Main.java
new file mode 100644
index 000000000..fb7aa4509
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/Main.java
@@ -0,0 +1,219 @@
+/* Main.java -- Implementation of the keytool security tool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.tools.HelpPrinter;
+import gnu.classpath.tools.common.ProviderUtil;
+import gnu.java.security.Registry;
+import gnu.javax.crypto.jce.GnuCrypto;
+import gnu.javax.security.auth.callback.GnuCallbacks;
+
+import java.util.logging.Logger;
+
+/**
+ * The GNU Classpath implementation of the keytool security tool.
+ * <p>
+ * Except for the <code>-identitydb</code> command, available for importing
+ * JDK 1.1 <i>identities</i> into a key store, this implementation is intended
+ * to be compatible with the behaviour described in the public documentation of
+ * the same tool included in JDK 1.4.
+ */
+public class Main
+{
+ private static final Logger log = Logger.getLogger(Main.class.getName());
+ /** The relative file path to the command tool's help text. */
+ private static final String HELP_PATH = "keytool/keytool.txt"; //$NON-NLS-1$
+ /** The Preferences key name for the last issued certificate serial nbr. */
+ static final String LAST_SERIAL_NUMBER = "lastSerialNumber"; //$NON-NLS-1$
+ /** Constant denoting the X.509 certificate type. */
+ static final String X_509 = "X.509"; //$NON-NLS-1$
+
+ /** Whether we have already printed the help text or not. */
+ private boolean helpPrinted;
+ /** The new position of GnuCRYPTO provider if it is not already installed. */
+ private int gnuCryptoProviderNdx = -2;
+ /** The new position of GNU Callbacks provider if it is not already installed. */
+ private int gnuCallbacksNdx = -2;
+
+ private Main()
+ {
+ super();
+ }
+
+ public static final void main(String[] args)
+ {
+ log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$
+
+ Main tool = new Main();
+ try
+ {
+ tool.setup();
+ tool.start(args);
+ }
+ catch (SecurityException x)
+ {
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getString("Main.6") + x.getMessage()); //$NON-NLS-1$
+ }
+ catch (Exception x)
+ {
+ log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
+ System.err.println(Messages.getString("Main.8") + x); //$NON-NLS-1$
+ }
+ finally
+ {
+ tool.teardown();
+ }
+
+ log.exiting(Main.class.getName(), "main"); //$NON-NLS-1$
+ // System.exit(0);
+ }
+
+ // helper methods -----------------------------------------------------------
+
+ private void start(String[] args) throws Exception
+ {
+ log.entering(this.getClass().getName(), "start", args); //$NON-NLS-1$
+
+ if (args == null)
+ args = new String[0];
+
+ int limit = args.length;
+ log.finest("args.length=" + limit); //$NON-NLS-1$
+ int i = 0;
+ String opt;
+ Command cmd;
+ while (i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ cmd = null;
+ if ("-genkey".equals(opt)) //$NON-NLS-1$
+ cmd = new GenKeyCmd();
+ else if ("-import".equals(opt)) //$NON-NLS-1$
+ cmd = new ImportCmd();
+ else if ("-selfcert".equals(opt)) //$NON-NLS-1$
+ cmd = new SelfCertCmd();
+ else if ("-identitydb".equals(opt)) //$NON-NLS-1$
+ cmd = new IdentityDBCmd();
+ else if ("-certreq".equals(opt)) //$NON-NLS-1$
+ cmd = new CertReqCmd();
+ else if ("-export".equals(opt)) //$NON-NLS-1$
+ cmd = new ExportCmd();
+ else if ("-list".equals(opt)) //$NON-NLS-1$
+ cmd = new ListCmd();
+ else if ("-printcert".equals(opt)) //$NON-NLS-1$
+ cmd = new PrintCertCmd();
+ else if ("-keyclone".equals(opt)) //$NON-NLS-1$
+ cmd = new KeyCloneCmd();
+ else if ("-storepasswd".equals(opt)) //$NON-NLS-1$
+ cmd = new StorePasswdCmd();
+ else if ("-keypasswd".equals(opt)) //$NON-NLS-1$
+ cmd = new KeyPasswdCmd();
+ else if ("-delete".equals(opt)) //$NON-NLS-1$
+ cmd = new DeleteCmd();
+ else if ("-help".equals(opt)) //$NON-NLS-1$
+ {
+ printHelp();
+ i++;
+ }
+ else
+ {
+ log.fine("Unknown command [" + opt + "] at index #" + i //$NON-NLS-1$ //$NON-NLS-2$
+ + ". Arguments from that token onward will be ignored"); //$NON-NLS-1$
+ break;
+ }
+
+ if (cmd != null)
+ {
+ i = cmd.processArgs(args, i);
+ cmd.doCommand();
+ }
+ }
+
+ // the -help command is the default; i.e.
+ // keytool
+ // is equivalent to:
+ // keytool -help
+ if (i == 0)
+ printHelp();
+
+ if (i < limit) // more options than needed
+ log.fine("Last recognized argument is assumed at index #" + (i - 1) //$NON-NLS-1$
+ + ". Remaining arguments (" + args[i] + "...) will be ignored"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ private void setup()
+ {
+ log.entering(this.getClass().getName(), "setup"); //$NON-NLS-1$
+
+ gnuCryptoProviderNdx = ProviderUtil.addProvider(new GnuCrypto());
+ gnuCallbacksNdx = ProviderUtil.addProvider(new GnuCallbacks());
+
+ log.exiting(this.getClass().getName(), "setup"); //$NON-NLS-1$
+ }
+
+ private void teardown()
+ {
+ log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+
+ // if we added our own providers remove them
+ if (gnuCryptoProviderNdx > 0)
+ ProviderUtil.removeProvider(Registry.GNU_CRYPTO);
+
+ if (gnuCallbacksNdx > 0)
+ ProviderUtil.removeProvider("GNU-CALLBACKS"); //$NON-NLS-1$
+
+ log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
+ }
+
+ private void printHelp()
+ {
+ if (helpPrinted)
+ return;
+
+ HelpPrinter.printHelp(HELP_PATH);
+ helpPrinted = true;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/Messages.java b/tools/gnu/classpath/tools/keytool/Messages.java
new file mode 100644
index 000000000..e3308e021
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/Messages.java
@@ -0,0 +1,115 @@
+/* Messages.java -- I18N related helper class
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.logging.Logger;
+
+/**
+ * An initially generated Eclipse helper class to ease the use of localized
+ * messages.
+ * <p>
+ * Enriched to handle localized message formats.
+ */
+class Messages
+{
+ private static final Logger log = Logger.getLogger(Messages.class.getName());
+ private static final String BUNDLE_NAME = "gnu.classpath.tools.keytool.MessageBundle"; //$NON-NLS-1$
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
+ private static final Map CACHED_FORMATS = new HashMap(5);
+
+ private Messages()
+ {
+ super();
+ }
+
+ public static String getString(String key)
+ {
+ try
+ {
+ return RESOURCE_BUNDLE.getString(key);
+ }
+ catch (MissingResourceException e)
+ {
+ return constructMessage(key, null);
+ }
+ }
+
+ public static String getFormattedString(String key, Object args)
+ {
+ MessageFormat mf = (MessageFormat) CACHED_FORMATS.get(key);
+ if (mf == null)
+ {
+ String formatString = getString(key);
+ if (formatString.startsWith("!"))
+ return constructMessage(key, args);
+
+ mf = new MessageFormat(formatString);
+ CACHED_FORMATS.put(key, mf);
+ }
+
+ // if the argument is not an array, then build one consisiting of the
+ // sole argument before passing it to the format() method
+ try
+ {
+ if (args instanceof Object[])
+ return mf.format(args);
+
+ return mf.format(new Object[] { args });
+ }
+ catch (IllegalArgumentException x)
+ {
+ log.fine("Exception while rendering a message format keyed by ["
+ + key + "]: " + mf.toPattern());
+ return constructMessage(mf.toPattern(), args);
+ }
+ }
+
+ private static final String constructMessage(String m, Object args)
+ {
+ if (args == null)
+ return '!' + m + '!';
+
+ return '!' + m + '!' + String.valueOf(args) + '!';
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/PrintCertCmd.java b/tools/gnu/classpath/tools/keytool/PrintCertCmd.java
new file mode 100644
index 000000000..9ba1d5970
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/PrintCertCmd.java
@@ -0,0 +1,123 @@
+/* PrintCertCmd.java -- The printcert command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import java.io.PrintWriter;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.logging.Logger;
+
+/**
+ * The <b>-printcert</b> keytool command handler is used to read a certificate
+ * from a designated file, and print its contents in a human-readable format.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-file FILE_NAME</dt>
+ * <dd>The fully qualified path of the file to read the certificate from.
+ * If this option is omitted, the tool will process STDIN.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class PrintCertCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(PrintCertCmd.class.getName());
+ private String _certFileName;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param pathName the fully qualified path name of the file to process. */
+ public void setFile(String pathName)
+ {
+ this._certFileName = pathName;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-file".equals(opt)) // -file FILE_NAME
+ _certFileName = args[++i];
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setInputStreamParam(_certFileName);
+
+ log.finer("-printcert handler will use the following options:");
+ log.finer(" -file=" + _certFileName);
+ log.finer(" -v=" + verbose);
+ }
+
+ void start() throws CertificateException
+ {
+ log.entering(getClass().getName(), "start");
+
+ CertificateFactory x509Factory = CertificateFactory.getInstance(Main.X_509);
+ Certificate certificate = x509Factory.generateCertificate(inStream);
+ PrintWriter writer = new PrintWriter(System.out, true);
+ writer.println();
+ printVerbose(certificate, writer);
+
+ log.exiting(getClass().getName(), "start");
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/SelfCertCmd.java b/tools/gnu/classpath/tools/keytool/SelfCertCmd.java
new file mode 100644
index 000000000..db7d45994
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/SelfCertCmd.java
@@ -0,0 +1,371 @@
+/* SelfCertCmd.java -- The selfcert command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.java.security.x509.X500DistinguishedName;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The <b>-selfcert</b> keytool command handler is used to generate a self-
+ * signed X.509 version 1 certificate using key store credentials stored under a
+ * designated alias.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-alias ALIAS</dt>
+ * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
+ * Certificate</i>, in a key store is uniquely identified by a user-defined
+ * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
+ * when referring to an entry in the key store. Unless specified otherwise,
+ * a default value of <code>mykey</code> shall be used when this option is
+ * omitted from the command line.
+ * <p></dd>
+ *
+ * <dt>-sigalg ALGORITHM</dt>
+ * <dd>The canonical name of the digital signature algorithm to use for
+ * signing the certificate. If this option is omitted, a default value will
+ * be chosen based on the type of the private key associated with the
+ * designated <i>Alias</i>. If the private key is a <code>DSA</code> one,
+ * the value for the signature algorithm will be <code>SHA1withDSA</code>.
+ * If on the other hand the private key is an <code>RSA</code> one, then
+ * the tool will use <code>MD5withRSA</code> as the signature algorithm.
+ * <p></dd>
+ *
+ * <dt>-dname NAME</dt>
+ * <dd>Use this option to specify the <i>Distinguished Name</i> of the
+ * newly generated self-signed certificate. If this option is omitted, the
+ * existing <i>Distinguished Name</i> of the base certificate in the chain
+ * associated with the designated <i>Alias</i> will be used instead.
+ * <p>
+ * The syntax of a valid value for this option MUST follow RFC-2253
+ * specifications. Namely the following components (with their accepted
+ * meaning) will be recognized. Note that the component name is case-
+ * insensitive:
+ * <dl>
+ * <dt>CN</dt>
+ * <dd>The Common Name; e.g. "host.domain.com"</dd>
+ *
+ * <dt>OU</dt>
+ * <dd>The Organizational Unit; e.g. "IT Department"</dd>
+ *
+ * <dt>O</dt>
+ * <dd>The Organization Name; e.g. "The Sample Company"</dd>
+ *
+ * <dt>L</dt>
+ * <dd>The Locality Name; e.g. "Sydney"</dd>
+ *
+ * <dt>ST</dt>
+ * <dd>The State Name; e.g. "New South Wales"</dd>
+ *
+ * <dt>C</dt>
+ * <dd>The 2-letter Country identifier; e.g. "AU"</dd>
+ * </dl>
+ * <p>
+ * When specified with a <code>-dname</code> option, each pair of component
+ * / value will be separated from the other with a comma. Each component
+ * and value pair MUST be separated by an equal sign. For example, the
+ * following is a valid DN value:
+ * <pre>
+ * CN=host.domain.com, O=The Sample Company, L=Sydney, ST=NSW, C=AU
+ * </pre>
+ * <p></dd>
+ *
+ * <dt>-validity DAY_COUNT</dt>
+ *
+ * <dt>-keypass PASSWORD</dt>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class SelfCertCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(SelfCertCmd.class.getName());
+ private String _alias;
+ private String _sigAlgorithm;
+ private String _dName;
+ private String _password;
+ private String _validityStr;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private X500DistinguishedName distinguishedName;
+ private int validityInDays;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param alias the alias to use. */
+ public void setAlias(String alias)
+ {
+ this._alias = alias;
+ }
+
+ /**
+ * @param algorithm the canonical name of the digital signature algorithm to
+ * use.
+ */
+ public void setSigalg(String algorithm)
+ {
+ this._sigAlgorithm = algorithm;
+ }
+
+ /**
+ * @param name the distiniguished name of both the issuer and subject (since
+ * we are dealing with a self-signed certificate) to use.
+ */
+ public void setDname(String name)
+ {
+ this._dName = name;
+ }
+
+ /**
+ * @param days the string representation of the number of days (a decimal,
+ * positive integer) to assign to the generated (self-signed)
+ * certificate.
+ */
+ public void setValidity(String days)
+ {
+ this._validityStr = days;
+ }
+
+ /** @param password the (private) key password to use. */
+ public void setKeypass(String password)
+ {
+ this._password = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-alias".equals(opt)) // -alias ALIAS
+ _alias = args[++i];
+ else if ("-sigalg".equals(opt)) // -sigalg ALGORITHM
+ _sigAlgorithm = args[++i];
+ else if ("-dname".equals(opt)) // -dname NAME
+ _dName = args[++i];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD
+ _password = args[++i];
+ else if ("-validity".equals(opt)) // -validity DAY_COUNT
+ _validityStr = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt))
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setAliasParam(_alias);
+ setKeyPasswordNoPrompt(_password);
+// setDName(_dName);
+ setValidityParam(_validityStr);
+// setSignatureAlgorithm(_sigAlgorithm);
+
+ log.finer("-selfcert handler will use the following options:");
+ log.finer(" -alias=" + alias);
+ log.finer(" -sigalg=" + _sigAlgorithm);
+ log.finer(" -dname=" + _dName);
+ log.finer(" -keypass=" + _password);
+ log.finer(" -validity=" + validityInDays);
+ log.finer(" -storetype=" + storeType);
+ log.finer(" -keystore=" + storeURL);
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars));
+ log.finer(" -provider=" + provider);
+ log.finer(" -v=" + verbose);
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException, IOException, UnsupportedCallbackException,
+ InvalidKeyException, SignatureException, CertificateException
+ {
+ log.entering(getClass().getName(), "start");
+
+ // 1. get the key entry and certificate chain associated to alias
+ Key privateKey = getAliasPrivateKey();
+ Certificate[] chain = store.getCertificateChain(alias);
+
+ // 2. if the user has not supplied a DN use one from the certificate chain
+ X509Certificate bottomCertificate = (X509Certificate) chain[0];
+ X500Principal defaultPrincipal = bottomCertificate.getIssuerX500Principal();
+ setDName(_dName, defaultPrincipal);
+
+ // 4. get alias's public key from certificate's SubjectPublicKeyInfo
+ PublicKey publicKey = bottomCertificate.getPublicKey();
+
+ // 5. issue the self-signed certificate
+ setSignatureAlgorithmParam(_sigAlgorithm, privateKey);
+
+ byte[] derBytes = getSelfSignedCertificate(distinguishedName,
+ publicKey,
+ (PrivateKey) privateKey);
+ CertificateFactory x509Factory = CertificateFactory.getInstance("X.509");
+ ByteArrayInputStream bais = new ByteArrayInputStream(derBytes);
+ Certificate certificate = x509Factory.generateCertificate(bais);
+
+ // 6. store it, w/ its private key, associating them to alias
+ chain = new Certificate[] { certificate };
+ store.setKeyEntry(alias, privateKey, keyPasswordChars, chain);
+
+ // 7. persist the key store
+ saveKeyStore();
+
+ log.exiting(getClass().getName(), "start");
+ }
+
+ // own methods --------------------------------------------------------------
+
+ private void setDName(String name, X500Principal defaultName)
+ {
+ if (name != null && name.trim().length() > 0)
+ name = name.trim();
+ else
+ {
+ // If dname is supplied at the command line, it is used as the X.500
+ // Distinguished Name for both the issuer and subject of the certificate.
+ // Otherwise, the X.500 Distinguished Name associated with alias (at the
+ // bottom of its existing certificate chain) is used.
+ name = defaultName.toString().trim();
+ }
+
+ distinguishedName = new X500DistinguishedName(name);
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java b/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java
new file mode 100644
index 000000000..1eb053c1c
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/StorePasswdCmd.java
@@ -0,0 +1,275 @@
+/* StorePasswdCmd.java -- The storepasswd command handler of the keytool
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.tools.keytool;
+
+import gnu.classpath.SystemProperties;
+
+import java.io.IOException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+/**
+ * The <b>-storepasswd</b> keytool command handler is used to change the
+ * password which protects the integrity of the key store.
+ * <p>
+ * Possible options for this command are:
+ * <p>
+ * <dl>
+ * <dt>-new PASSWORD</dt>
+ * <dd>The new, and different, password which will be used to protect the
+ * designated key store.
+ * <p></dd>
+ *
+ * <dt>-storetype STORE_TYP}</dt>
+ * <dd>Use this option to specify the type of the key store to use. The
+ * default value, if this option is omitted, is that of the property
+ * <code>keystore.type</code> in the security properties file, which is
+ * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
+ * static method.
+ * <p></dd>
+ *
+ * <dt>-keystore URL</dt>
+ * <dd>Use this option to specify the location of the key store to use.
+ * The default value is a file {@link java.net.URL} referencing the file
+ * named <code>.keystore</code> located in the path returned by the call to
+ * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
+ * as argument.
+ * <p>
+ * If a URL was specified, but was found to be malformed --e.g. missing
+ * protocol element-- the tool will attempt to use the URL value as a file-
+ * name (with absolute or relative path-name) of a key store --as if the
+ * protocol was <code>file:</code>.
+ * <p></dd>
+ *
+ * <dt>-storepass PASSWORD</dt>
+ * <dd>Use this option to specify the password protecting the key store. If
+ * this option is omitted from the command line, you will be prompted to
+ * provide a password.
+ * <p></dd>
+ *
+ * <dt>-provider PROVIDER_CLASS_NAME</dt>
+ * <dd>A fully qualified class name of a Security Provider to add to the
+ * current list of Security Providers already installed in the JVM in-use.
+ * If a provider class is specified with this option, and was successfully
+ * added to the runtime --i.e. it was not already installed-- then the tool
+ * will attempt to removed this Security Provider before exiting.
+ * <p></dd>
+ *
+ * <dt>-v</dt>
+ * <dd>Use this option to enable more verbose output.</dd>
+ * </dl>
+ */
+class StorePasswdCmd extends Command
+{
+ private static final Logger log = Logger.getLogger(StorePasswdCmd.class.getName());
+ private String _newPassword;
+ private String _ksType;
+ private String _ksURL;
+ private String _ksPassword;
+ private String _providerClassName;
+ private char[] newStorePasswordChars;
+
+ // default 0-arguments constructor
+
+ // public setters -----------------------------------------------------------
+
+ /** @param password the new key-store password to use. */
+ public void setNew(String password)
+ {
+ this._newPassword = password;
+ }
+
+ /** @param type the key-store type to use. */
+ public void setStoretype(String type)
+ {
+ this._ksType = type;
+ }
+
+ /** @param url the key-store URL to use. */
+ public void setKeystore(String url)
+ {
+ this._ksURL = url;
+ }
+
+ /** @param password the key-store password to use. */
+ public void setStorepass(String password)
+ {
+ this._ksPassword = password;
+ }
+
+ /** @param className a security provider fully qualified class name to use. */
+ public void setProvider(String className)
+ {
+ this._providerClassName = className;
+ }
+
+ // life-cycle methods -------------------------------------------------------
+
+ int processArgs(String[] args, int i)
+ {
+ int limit = args.length;
+ String opt;
+ while (++i < limit)
+ {
+ opt = args[i];
+ log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$
+ _newPassword = args[++i];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
+ _ksType = args[++i];
+ else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
+ _ksURL = args[++i];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
+ _ksPassword = args[++i];
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
+ _providerClassName = args[++i];
+ else if ("-v".equals(opt)) //$NON-NLS-1$
+ verbose = true;
+ else
+ break;
+ }
+
+ return i;
+ }
+
+ void setup() throws Exception
+ {
+ setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
+ setNewKeystorePassword(_newPassword);
+
+ log.finer("-storepasswd handler will use the following options:"); //$NON-NLS-1$
+ log.finer(" -new=" + String.valueOf(newStorePasswordChars)); //$NON-NLS-1$
+ log.finer(" -storetype=" + storeType); //$NON-NLS-1$
+ log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
+ log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
+ log.finer(" -provider=" + provider); //$NON-NLS-1$
+ log.finer(" -v=" + verbose); //$NON-NLS-1$
+ }
+
+ void start() throws KeyStoreException, NoSuchAlgorithmException,
+ CertificateException, IOException
+ {
+ log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
+
+ saveKeyStore(newStorePasswordChars);
+
+ log.exiting(getClass().getName(), "start"); //$NON-NLS-1$
+ }
+
+ // own methods --------------------------------------------------------------
+
+ protected void setNewKeystorePassword(String password) throws IOException,
+ UnsupportedCallbackException
+ {
+ if (password != null)
+ newStorePasswordChars = password.toCharArray();
+ else
+ {
+ boolean ok = false;
+ Callback[] prompts = new Callback[1];
+ Callback[] errors = new Callback[1];
+ for (int i = 0; i < 3; i++)
+ if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
+ {
+ ok = true;
+ break;
+ }
+ if (! ok)
+ throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
+ }
+ }
+
+ private boolean prompt4NewPassword(CallbackHandler handler,
+ Callback[] prompts, Callback[] errors)
+ throws IOException, UnsupportedCallbackException
+ {
+ // prompt user (1st time) to provide one
+ String p = Messages.getString("StorePasswdCmd.20"); //$NON-NLS-1$
+ PasswordCallback pcb = new PasswordCallback(p, false);
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd1 = pcb.getPassword();
+ pcb.clearPassword();
+ String ls = SystemProperties.getProperty("line.separator"); //$NON-NLS-1$
+ if (pwd1 == null || pwd1.length < 6)
+ {
+ String m = Messages.getString("StorePasswdCmd.21") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ if (Arrays.equals(storePasswordChars, pwd1))
+ {
+ String m = Messages.getString("StorePasswdCmd.22") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ // prompt user (2nd time) for confirmation
+ pcb = new PasswordCallback(Messages.getString("StorePasswdCmd.23"), false); //$NON-NLS-1$
+ prompts[0] = pcb;
+ handler.handle(prompts);
+ char[] pwd2 = pcb.getPassword();
+ pcb.clearPassword();
+ if (! Arrays.equals(pwd1, pwd2))
+ {
+ String m = Messages.getString("StorePasswdCmd.24") + ls; //$NON-NLS-1$
+ errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
+ handler.handle(errors);
+ return false;
+ }
+
+ newStorePasswordChars = pwd2;
+ return true;
+ }
+}
diff --git a/tools/gnu/classpath/tools/keytool/keytool.txt b/tools/gnu/classpath/tools/keytool/keytool.txt
new file mode 100644
index 000000000..15f9b96f9
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/keytool.txt
@@ -0,0 +1,616 @@
+NAME
+ keytool - manage private keys and public certificates
+
+SYNOPSIS
+ keytool [COMMAND]...
+
+DESCRIPTION
+ A Java-based tool for managing both Key Entries as well as Trusted
+ Certificates.
+
+ Multiple COMMANDs may be specified at once, each complete with its own
+ options. keytool will parse all the arguments, before processing, and
+ executing, each COMMAND. If an exception occurs while executing one
+ COMMAND keytool will abort.
+
+ A COMMAND can be one of the followings:
+
+ -genkey [OPTION]...
+ Generate a new Key Entry, eventually creating a new key store.
+
+ -import [OPTION]...
+ Add, to a key store, Key Entries (private keys and certificate
+ chains authenticating the public keys) and Trusted Certificates
+ (3rd party certificates which can be used as Trust anchors when
+ building chains-of-trust).
+
+ -selfcert [OPTION]...
+ Generate a new self-signed Trusted Certificate.
+
+ -identitydb [OPTION]...
+ NOT IMPLEMENTED YET.
+ Import a JDK 1.1 style Identity Database.
+
+ -certreq [OPTION]...
+ Issue a Certificate Signing Request (CSR) which can be then sent
+ to a Certification Authority (CA) to issue a certificate signed
+ (by the CA) and authenticating the Subject of the request.
+
+ -export [OPTION]...
+ Export a Certificate from a key store.
+
+ -list [OPTION]...
+ Print one or all Certificates in a key store to STDOUT.
+
+ -printcert [OPTION]...
+ Print a human-readable form of a Certificate in a designated
+ file to STDOUT.
+
+ -keyclone [OPTION]...
+ Clone a Key Entry in a key store.
+
+ -storepasswd [OPTION]...
+ Change the password protecting a key store.
+
+ -keypasswd [OPTION]...
+ Change the password protecting a Key Entry in a key store.
+
+ -delete [OPTION]...
+ Delete a Key Entry or a Trusted Certificate from a key store.
+
+ -help Display this text.
+
+OPTIONS COMMON TO MORE THAN ONE COMMAND
+ The following OPTIONs are used in more than one COMMAND. They are
+ described here to reduce redundancy.
+
+ -alias ALIAS
+ Every entry, be it a Key Entry or a Trusted Certificate, in a
+ key store is uniquely identified by a user-defined Alias string.
+ Use this option to specify the Alias to use when referring to an
+ entry in the key store. Unless specified otherwise, a default
+ value of "mykey" (all lower case, without the enclosing quotes)
+ shall be used when this option is omitted from the command line.
+
+ -keyalg ALGORITHM
+ Use this option to specify the canonical name of the key-pair
+ generation algorithm. The default value for this option is
+ "DSS" (a synonym for the Digital Signature Algorithm also known
+ as DSA).
+
+ -keysize SIZE
+ Use this option to specify the number of bits of the shared
+ modulus (for both the public and private keys) to use when
+ generating new keys. A default value of 1024 will be used if
+ this option is omitted from the command line.
+
+ -validity DAY_COUNT
+ Use this option to specify the number of days a newly generated
+ certificate will be valid for. The default value is 90 (days)
+ if this option is omitted from the command line.
+
+ -storetype STORE_TYPE
+ Use this option to specify the type of the key store to use.
+ The default value, if this option is omitted, is that of the
+ property "keystore.type" in the security properties file, which
+ is obtained by invoking the static method call getDefaultType()
+ in java.security.KeyStore.
+
+ -storepass PASSWORD
+ Use this option to specify the password protecting the key
+ store. If this option is omitted from the command line, you
+ will be prompted to provide a password.
+
+ -keystore URL
+ Use this option to specify the location of the key store to use.
+ The default value is a file URL referencing the file named
+ ".keystore" (all lower case and without the enclosing quotes)
+ located in the path returned by the call to
+ java.lang.System#getProperty(String) using "user.home" as
+ argument.
+
+ If a URL was specified, but was found to be malformed --e.g.
+ missing protocol element-- the tool will attempt to use the URL
+ value as a file-name (with absolute or relative path-name) of a
+ key store --as if the protocol was "file:".
+
+ -provider PROVIDER_CLASS_NAME
+ A fully qualified class name of a Security Provider to add to
+ the current list of Security Providers already installed in the
+ JVM in-use. If a provider class is specified with this option,
+ and was successfully added to the runtime --i.e. it was not
+ already installed-- then the tool will attempt to remove this
+ Security Provider before exiting.
+
+ -file FILE_NAME
+ Use this option to designate a file to use with a command. When
+ specified with this option, the value is expected to be the
+ fully qualified path of a file accessible by the File System.
+ Depending on the command, the file may be used as input or as
+ output. When this option is omitted from the command line,
+ STDIN will be used instead, as the source of input, and STDOUT
+ will be used instead as the output destination.
+
+ -v Unless specified otherwise, use this option to enable more
+ verbose output.
+
+X.500 DISTINGUISHED NAME
+ A Distinguished Name (or DN) MUST be supplied with some of the COMMANDs
+ using a -dname option. The syntax of a valid value for this option MUST
+ follow RFC-2253 specifications. Namely the following components (with
+ their accepted meaning) will be recognized. Note that the component
+ name is case-insensitive:
+
+ CN The Common Name; e.g. "host.domain.com"
+ OU The Organizational Unit; e.g. "IT Department"
+ O The Organization Name; e.g. "The Sample Company"
+ L The Locality Name; e.g. "Sydney"
+ ST The State Name; e.g. "New South Wales"
+ C The 2-letter Country identifier; e.g. "AU"
+
+ When specified with a -dname option, each pair of component/value will
+ be separated from the other with a comma. Each component and value pair
+ MUST be separated by an equal sign. For example, the following is
+ a valid DN value:
+
+ CN=host.domain.com, O=The Sample Company, L=Sydney, ST=NSW, C=AU
+
+ If the Distinguished Name is required, and no valid default value can be
+ used, the tool will prompt you to enter the information through the
+ console.
+
+-genkey COMMAND
+ Generate a new key-pair (both private and public keys), and save these
+ credentials in the key store as a Key Entry, associated with the
+ designated (if was specified in the -alias option) or default (if the
+ -alias option is omitted) Alias.
+
+ The private key material will be protected with a user-defined password
+ (see -keypass option). The public key on the other hand will be part
+ of a self-signed X.509 certificate, which will form a 1-element chain
+ and will be saved in the key store.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keyalg ALGORITHM
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keysize KEY_SIZE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -sigalg ALGORITHM
+ The canonical name of the digital signature algorithm to use for
+ signing certificates. If this option is omitted, a default
+ value will be chosen based on the type of the key-pair; i.e. the
+ algorithm that ends up being used by the -keyalg option. If the
+ key-pair generation algorithm is "DSA", the value for the
+ signature algorithm will be "SHA1withDSA". If on the other hand
+ the key-pair generation algorithm is "RSA", then the tool will
+ use "MD5withRSA" as the signature algorithm.
+
+ -dname NAME
+ This a mandatory value for the command. If no value is
+ specified --i.e. the -dname option is omitted-- the tool will
+ prompt you to enter a Distinguished Name to use as both the
+ Owner and Issuer of the generated self-signed certificate.
+
+ (see X.500 DISTINGUISHED NAME)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to protect the newly created Key Entry.
+
+ If this option is omitted, you will be prompted to provide a
+ password.
+
+ -validity DAY_COUNT
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-import COMMAND
+ Read an X.509 certificate, or a PKCS#7 Certificate Reply from a
+ designated input source and incorporate the certificates into the key
+ store.
+
+ If the Alias does not already exist in the key store, the tool treats
+ the certificate read from the input source as a new Trusted Certificate.
+ It then attempts to discover a chain-of-trust, starting from that
+ certificate and ending at another Trusted Certificate, already stored in
+ the key store. If the -trustcacerts option is present, an additional
+ key store, of type "JKS" named "cacerts", and assumed to be present in
+ ${JAVA_HOME}/lib/security will also be consulted if found --${JAVA_HOME}
+ refers to the location of an installed Java Runtime Environment (JRE).
+ If no chain-of-trust can be established, and unless the -noprompt option
+ has been specified, the certificate is printed to STDOUT and the user is
+ prompted for a confirmation.
+
+ If Alias exists in the key store, the tool will treat the certificate(s)
+ read from the input source as a Certificate Reply, which can be a chain
+ of certificates, that eventually would replace the chain of certificates
+ associated with the Key Entry of that Alias. The substitution of the
+ certificates only occurs if a chain-of-trust can be established between
+ the bottom certificate of the chain read from the input file and the
+ Trusted Certificates already present in the key store. Again, if the
+ -trustcacerts option is specified, additional Trusted Certificates in
+ the same "cacerts" key store will be considered. If no chain-of-trust
+ can be established, the operation will abort.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to protect the Key Entry associated with the designated Alias,
+ when replacing this Alias' chain of certificates with that found
+ in the certificate reply.
+
+ If this option is omitted, and the chain-of-trust for the
+ certificate reply has been established, the tool will first
+ attempt to unlock the Key Entry using the same password
+ protecting the key store. If this fails, you will then be
+ prompted to provide a password.
+
+ -noprompt
+ Use this option to prevent the tool from prompting the user.
+
+ -trustcacerts
+ Use this option to indicate to the tool that a key store, of
+ type "JKS", named "cacerts", and usually located in lib/security
+ in an installed Java Runtime Environment should be considered
+ when trying to establish chain-of-trusts.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-selfcert COMMAND
+ Generate a self-signed X.509 version 1 certificate. The newly generated
+ certificate will form a chain of one element which will replace the
+ previous chain associated with the designated Alias (if -alias option
+ was specified), or the default Alias (if -alias option was omitted).
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -sigalg ALGORITHM
+ The canonical name of the digital signature algorithm to use for
+ signing the certificate. If this option is omitted, a default
+ value will be chosen based on the type of the private key
+ associated with the designated Alias. If the private key is a
+ "DSA" one, the value for the signature algorithm will be
+ "SHA1withDSA". If on the other hand the private key is an "RSA"
+ one, then the tool will use "MD5withRSA" as the signature
+ algorithm.
+
+ -dname NAME
+ Use this option to specify the Distinguished Name of the newly
+ generated self-signed certificate. If this option is omitted,
+ the existing Distinguished Name of the base certificate in the
+ chain associated with the designated Alias will be used instead.
+
+ (see X.500 DISTINGUISHED NAME)
+
+ -validity DAY_COUNT
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-identitydb COMMAND
+ NOT IMPLEMENTED YET.
+
+ Import a JDK 1.1 style Identity Database.
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-certreq COMMAND
+ Generate a PKCS#10 Certificate Signing Request (CSR) and writes it to
+ a designated output destination. The contents of the destination
+ should look something like the following:
+
+ -----BEGIN NEW CERTIFICATE REQUEST-----
+ MIICYTCCAiECAQAwXzEUMBIGA1UEAwwLcnNuQGdudS5vcmcxGzAZBgNVBAoMElUg
+ Q29tcGFueTEPMA0GA1UEBwwGU3lkbmV5MQwwCgYDVQQIDANOU1cxCzAJBgNVBACC
+ ...
+ FCTlKlok8KwGuIVwNVOfQLRX+O5kAhQ/a4RTZme2L8PnpvgRwrf7Eg8D6w==
+ -----END NEW CERTIFICATE REQUEST-----
+
+ IMPORTANT: Some documentation (e.g. RSA examples) claims that the
+ Attributes field, in the CSR is OPTIONAL while RFC-2986 implies the
+ opposite. This implementation considers this field, by default, as
+ OPTIONAL, unless the option -attributes is specified on the command
+ line.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -sigalg ALGORITHM
+ The canonical name of the digital signature algorithm to use for
+ signing the certificate. If this option is omitted, a default
+ value will be chosen based on the type of the private key
+ associated with the designated Alias. If the private key is a
+ "DSA" one, the value for the signature algorithm will be
+ "SHA1withDSA". If on the other hand the private key is an "RSA"
+ one, then the tool will use "MD5withRSA" as the signature
+ algorithm.
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -attributes
+ Use this option to force the tool to encode a NULL DER value in
+ the CSR as the value of the Attributes field.
+
+-export COMMAND
+ Export a certificate stored in the key store to a designated output
+ destination, either in binary format (if the -v option is specified),
+ or in RFC-1421 compliant encoding (if the -rfc option is specified
+ instead).
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -rfc Use RFC-1421 specifications when encoding the output.
+
+ -v Output the certificate in binary DER encoding. This is the
+ default output format of the command if neither -rfc nor -v
+ options were detected on the command line. If both this option
+ and the -rfc option are detected on the command line, the tool
+ will opt for the RFC-1421 style encoding.
+
+-list COMMAND
+ Print one or all of the key store entries to STDOUT. Usually this
+ command will only print a fingerprint of the certificate, unless either
+ the -rfc or the -v option is specified.
+
+ -alias ALIAS
+ If this option is omitted, the tool will print ALL the entries
+ found in the key store.
+
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -rfc Use RFC-1421 specifications when encoding the output.
+
+ -v Output the certificate in human-readable format. If both this
+ option and the -rfc option are detected on the command line,
+ the tool will opt for the human-readable form and will not
+ abort the command.
+
+-printcert COMMAND
+ Read a certificate from a designated input source and print it to STDOUT
+ in a human-readable form.
+
+ -file FILE_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-keyclone COMMAND
+ Clone an existing Key Entry and store it under a new (different) Alias
+ protecting, its private key material with possibly a new password.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -dest ALIAS
+ Use this option to specify the new Alias which will be used to
+ identify the cloned copy of the Key Entry.
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -new PASSWORD
+ Use this option to specify the password protecting the private
+ key material of the newly cloned copy of the Key Entry.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-storepasswd COMMAND
+ Change the password protecting a key store.
+
+ -new PASSWORD
+ The new, and different, password which will be used to protect
+ the designated key store.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-keypasswd COMMAND
+ Change the password protecting the private key material of a designated
+ Key Entry.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keypass PASSWORD
+ Use this option to specify the password which the tool will use
+ to unlock the Key Entry associated with the designated Alias.
+
+ If this option is omitted, the tool will first attempt to unlock
+ the Key Entry using the same password protecting the key store.
+ If this fails, you will then be prompted to provide a password.
+
+ -new PASSWORD
+ The new, and different, password which will be used to protect
+ the private key material of the designated Key Entry.
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+-delete COMMAND
+ Delete a designated key store entry.
+
+ -alias ALIAS
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storetype STORE_TYPE
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -keystore URL
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -storepass PASSWORD
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -provider PROVIDER_CLASS_NAME
+ (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+ -v (see OPTIONS COMMON TO MORE THAN ONE COMMAND)
+
+REPORTING BUGS
+ Please report bugs at http://www.gnu.org/software/classpath/bugs.html
+
+COPYRIGHT
+ Copyright (C) 2006 Free Software Foundation, Inc.
+ This is free software; see the source for copying conditions. There is
+ NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.
diff --git a/tools/gnu/classpath/tools/keytool/package.html b/tools/gnu/classpath/tools/keytool/package.html
new file mode 100644
index 000000000..c447b8d01
--- /dev/null
+++ b/tools/gnu/classpath/tools/keytool/package.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.classpath.tools.keytool
+
+Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head>
+<title>GNU Classpath - gnu.classpath.tools.keytool</title>
+</head>
+
+<body>
+This package contains the classes that provide an implementation of the
+Security Tool: <code>keytool</code>. The behaviour of these classes should
+match that of the same tool provided in the RI version 1.4.2, except for the
+following:
+
+<ul>
+ <li>The RI tool accepts -J<i>javaoption</i> options which it then passes to
+ the underlying JVM. This is because the RI tool acts as a <i>wrapper</i>
+ around the JVM launcher.
+ <p>
+ This implementation DOES NOT support these options.
+ </li>
+
+ <li>The RI tool is capable of importing JDK-1.1 style <i>identities</i>.
+ <p>
+ This implementation does not offer this feature.
+ </li>
+</ul>
+</body>
+</html>
diff --git a/tools/keytool.sh.in b/tools/keytool.sh.in
new file mode 100644
index 000000000..6c11dc407
--- /dev/null
+++ b/tools/keytool.sh.in
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+## Copyright (C) 2006 Free Software Foundation, Inc.
+##
+## This file is a part of GNU Classpath.
+##
+## GNU Classpath is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or (at
+## your option) any later version.
+##
+## GNU Classpath is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with GNU Classpath; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+## USA.
+##
+## Linking this library statically or dynamically with other modules is
+## making a combined work based on this library. Thus, the terms and
+## conditions of the GNU General Public License cover the whole
+## combination.
+##
+## As a special exception, the copyright holders of this library give you
+## permission to link this library with independent modules to produce an
+## executable, regardless of the license terms of these independent
+## modules, and to copy and distribute the resulting executable under
+## terms of your choice, provided that you also meet, for each linked
+## independent module, the terms and conditions of the license of that
+## module. An independent module is a module which is not derived from
+## or based on this library. If you modify this library, you may extend
+## this exception to your version of the library, but you are not
+## obligated to do so. If you do not wish to do so, delete this
+## exception statement from your version.
+##
+##
+## A simple shell script to launch the GNU Classpath keytool tool.
+##
+
+prefix=@prefix@
+tools_dir=@datadir@/@PACKAGE@
+tools_cp=${tools_dir}/tools.zip
+
+# find the java executable...
+if [ -z "${JAVA}" ] ; then
+ if [ -n "${JAVA_HOME}" ] ; then
+ if [ -x "${JAVA_HOME}/jre/sh/java" ] ; then
+ JAVA="${JAVA_HOME}/jre/sh/java"
+ else
+ JAVA="${JAVA_HOME}/bin/java"
+ fi
+ else
+ JAVA=`which java 2> /dev/null `
+ if [ -z "${JAVA}" ] ; then
+ JAVA=java
+ fi
+ fi
+fi
+
+exec "${JAVA}" -Xbootclasspath/p:"${tools_cp}" gnu.classpath.tools.keytool.Main $@