From 56c5b96a2d3754736d13eebb73270fb8f925301d Mon Sep 17 00:00:00 2001 From: Guilhem Lavaux Date: Tue, 6 Jun 2006 20:30:07 +0000 Subject: 2006-06-06 Guilhem Lavaux * Merged HEAD as of 2006-05-08. --- tools/.cvsignore | 2 + tools/Makefile.am | 27 +- tools/README | 18 +- tools/appletviewer.c | 235 ++++ tools/appletviewer.in | 63 ++ tools/gnu/classpath/tools/HelpPrinter.java | 41 +- .../tools/appletviewer/AppletClassLoader.java | 81 ++ .../tools/appletviewer/AppletSecurityManager.java | 95 ++ .../classpath/tools/appletviewer/AppletTag.java | 485 +++++++++ .../tools/appletviewer/AppletWarning.java | 66 ++ .../tools/appletviewer/CommonAppletContext.java | 133 +++ .../tools/appletviewer/CommonAppletStub.java | 138 +++ .../tools/appletviewer/ConsoleDialog.java | 175 +++ .../classpath/tools/appletviewer/ErrorApplet.java | 53 + tools/gnu/classpath/tools/appletviewer/Main.java | 303 ++++++ .../tools/appletviewer/PluginAppletContext.java | 72 ++ .../tools/appletviewer/PluginAppletViewer.java | 172 +++ .../tools/appletviewer/PluginAppletWindow.java | 454 ++++++++ .../appletviewer/StandaloneAppletContext.java | 75 ++ .../tools/appletviewer/StandaloneAppletViewer.java | 144 +++ .../tools/appletviewer/StandaloneAppletWindow.java | 559 ++++++++++ .../classpath/tools/appletviewer/TagParser.java | 302 ++++++ tools/gnu/classpath/tools/common/CallbackUtil.java | 145 +++ tools/gnu/classpath/tools/common/ProviderUtil.java | 163 +++ .../tools/common/SecurityProviderInfo.java | 99 ++ .../tools/getopt/ClasspathToolParser.java | 71 ++ .../tools/getopt/FileArgumentCallback.java | 61 ++ tools/gnu/classpath/tools/getopt/Option.java | 201 ++++ .../classpath/tools/getopt/OptionException.java | 52 + tools/gnu/classpath/tools/getopt/OptionGroup.java | 171 +++ tools/gnu/classpath/tools/getopt/Parser.java | 314 ++++++ tools/gnu/classpath/tools/giop/GRMIC.java | 22 +- tools/gnu/classpath/tools/giop/GRMIC.txt | 3 + tools/gnu/classpath/tools/giop/IorParser.java | 18 +- .../tools/giop/grmic/CompilationError.java | 18 +- .../gnu/classpath/tools/giop/grmic/Generator.java | 18 +- tools/gnu/classpath/tools/giop/grmic/GiopIo.java | 18 +- .../tools/giop/grmic/GiopRmicCompiler.java | 33 +- .../gnu/classpath/tools/giop/grmic/HashFinder.java | 22 + .../tools/giop/grmic/MethodGenerator.java | 18 +- tools/gnu/classpath/tools/jar/Action.java | 50 + tools/gnu/classpath/tools/jar/Creator.java | 192 ++++ tools/gnu/classpath/tools/jar/Entry.java | 60 + tools/gnu/classpath/tools/jar/Extractor.java | 100 ++ tools/gnu/classpath/tools/jar/Lister.java | 84 ++ tools/gnu/classpath/tools/jar/Main.java | 225 ++++ tools/gnu/classpath/tools/jar/Updater.java | 81 ++ tools/gnu/classpath/tools/jarsigner/HashUtils.java | 122 +++ tools/gnu/classpath/tools/jarsigner/JarSigner.java | 167 +++ .../gnu/classpath/tools/jarsigner/JarVerifier.java | 339 ++++++ tools/gnu/classpath/tools/jarsigner/Main.java | 567 ++++++++++ tools/gnu/classpath/tools/jarsigner/Messages.java | 115 ++ tools/gnu/classpath/tools/jarsigner/SFHelper.java | 373 +++++++ tools/gnu/classpath/tools/jarsigner/jarsigner.txt | 116 ++ tools/gnu/classpath/tools/jarsigner/package.html | 60 + tools/gnu/classpath/tools/keytool/CertReqCmd.java | 405 +++++++ tools/gnu/classpath/tools/keytool/Command.java | 1147 ++++++++++++++++++++ tools/gnu/classpath/tools/keytool/DeleteCmd.java | 235 ++++ tools/gnu/classpath/tools/keytool/ExportCmd.java | 266 +++++ tools/gnu/classpath/tools/keytool/GenKeyCmd.java | 511 +++++++++ .../gnu/classpath/tools/keytool/IdentityDBCmd.java | 185 ++++ tools/gnu/classpath/tools/keytool/ImportCmd.java | 751 +++++++++++++ tools/gnu/classpath/tools/keytool/KeyCloneCmd.java | 344 ++++++ .../gnu/classpath/tools/keytool/KeyPasswdCmd.java | 339 ++++++ tools/gnu/classpath/tools/keytool/ListCmd.java | 380 +++++++ tools/gnu/classpath/tools/keytool/Main.java | 219 ++++ tools/gnu/classpath/tools/keytool/Messages.java | 115 ++ .../gnu/classpath/tools/keytool/PrintCertCmd.java | 123 +++ tools/gnu/classpath/tools/keytool/SelfCertCmd.java | 371 +++++++ .../classpath/tools/keytool/StorePasswdCmd.java | 275 +++++ tools/gnu/classpath/tools/keytool/keytool.txt | 616 +++++++++++ tools/gnu/classpath/tools/keytool/package.html | 65 ++ tools/gnu/classpath/tools/rmi/Persistent.java | 87 ++ .../tools/rmi/PersistentBidiHashTable.java | 268 +++++ .../classpath/tools/rmi/PersistentHashTable.java | 246 +++++ tools/gnu/classpath/tools/rmi/REGISTRY.java | 165 +++ tools/gnu/classpath/tools/rmi/REGISTRY.txt | 28 + tools/gnu/classpath/tools/rmi/RMIC.java | 23 +- tools/gnu/classpath/tools/rmi/RMIC.txt | 2 + tools/gnu/classpath/tools/rmi/RMID.java | 189 ++++ tools/gnu/classpath/tools/rmi/RMID.txt | 30 + .../classpath/tools/rmi/registry/RegistryImpl.java | 139 +++ .../tools/rmi/registry/RegistryImpl_Skel.java | 278 +++++ .../tools/rmi/registry/RegistryImpl_Stub.java | 263 +++++ .../gnu/classpath/tools/rmi/registry/package.html | 46 + .../tools/rmi/rmic/RmiMethodGenerator.java | 14 +- .../gnu/classpath/tools/rmi/rmic/RmicCompiler.java | 13 +- .../classpath/tools/rmi/rmic/WrapUnWrapper.java | 19 +- .../tools/rmi/rmic/templates/Stub_12Method.jav | 2 +- .../tools/rmi/rmic/templates/Stub_12MethodVoid.jav | 2 +- .../tools/rmi/rmid/ActivationSystemImpl.java | 244 +++++ .../tools/rmi/rmid/ActivationSystemImpl_Stub.java | 556 ++++++++++ tools/jarsigner.in | 63 ++ tools/keytool.in | 63 ++ 94 files changed, 16673 insertions(+), 205 deletions(-) create mode 100644 tools/appletviewer.c create mode 100644 tools/appletviewer.in create mode 100644 tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java create mode 100644 tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java create mode 100644 tools/gnu/classpath/tools/appletviewer/AppletTag.java create mode 100644 tools/gnu/classpath/tools/appletviewer/AppletWarning.java create mode 100644 tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java create mode 100644 tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java create mode 100644 tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java create mode 100644 tools/gnu/classpath/tools/appletviewer/ErrorApplet.java create mode 100644 tools/gnu/classpath/tools/appletviewer/Main.java create mode 100644 tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java create mode 100644 tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java create mode 100644 tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java create mode 100644 tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java create mode 100644 tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java create mode 100644 tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java create mode 100644 tools/gnu/classpath/tools/appletviewer/TagParser.java create mode 100644 tools/gnu/classpath/tools/common/CallbackUtil.java create mode 100644 tools/gnu/classpath/tools/common/ProviderUtil.java create mode 100644 tools/gnu/classpath/tools/common/SecurityProviderInfo.java create mode 100644 tools/gnu/classpath/tools/getopt/ClasspathToolParser.java create mode 100644 tools/gnu/classpath/tools/getopt/FileArgumentCallback.java create mode 100644 tools/gnu/classpath/tools/getopt/Option.java create mode 100644 tools/gnu/classpath/tools/getopt/OptionException.java create mode 100644 tools/gnu/classpath/tools/getopt/OptionGroup.java create mode 100644 tools/gnu/classpath/tools/getopt/Parser.java create mode 100644 tools/gnu/classpath/tools/jar/Action.java create mode 100644 tools/gnu/classpath/tools/jar/Creator.java create mode 100644 tools/gnu/classpath/tools/jar/Entry.java create mode 100644 tools/gnu/classpath/tools/jar/Extractor.java create mode 100644 tools/gnu/classpath/tools/jar/Lister.java create mode 100644 tools/gnu/classpath/tools/jar/Main.java create mode 100644 tools/gnu/classpath/tools/jar/Updater.java create mode 100644 tools/gnu/classpath/tools/jarsigner/HashUtils.java create mode 100644 tools/gnu/classpath/tools/jarsigner/JarSigner.java create mode 100644 tools/gnu/classpath/tools/jarsigner/JarVerifier.java create mode 100644 tools/gnu/classpath/tools/jarsigner/Main.java create mode 100644 tools/gnu/classpath/tools/jarsigner/Messages.java create mode 100644 tools/gnu/classpath/tools/jarsigner/SFHelper.java create mode 100644 tools/gnu/classpath/tools/jarsigner/jarsigner.txt create mode 100644 tools/gnu/classpath/tools/jarsigner/package.html create mode 100644 tools/gnu/classpath/tools/keytool/CertReqCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/Command.java create mode 100644 tools/gnu/classpath/tools/keytool/DeleteCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/ExportCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/GenKeyCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/IdentityDBCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/ImportCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/KeyCloneCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/KeyPasswdCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/ListCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/Main.java create mode 100644 tools/gnu/classpath/tools/keytool/Messages.java create mode 100644 tools/gnu/classpath/tools/keytool/PrintCertCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/SelfCertCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/StorePasswdCmd.java create mode 100644 tools/gnu/classpath/tools/keytool/keytool.txt create mode 100644 tools/gnu/classpath/tools/keytool/package.html create mode 100644 tools/gnu/classpath/tools/rmi/Persistent.java create mode 100644 tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java create mode 100644 tools/gnu/classpath/tools/rmi/PersistentHashTable.java create mode 100644 tools/gnu/classpath/tools/rmi/REGISTRY.java create mode 100644 tools/gnu/classpath/tools/rmi/REGISTRY.txt create mode 100644 tools/gnu/classpath/tools/rmi/RMID.java create mode 100644 tools/gnu/classpath/tools/rmi/RMID.txt create mode 100644 tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java create mode 100644 tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Skel.java create mode 100644 tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Stub.java create mode 100644 tools/gnu/classpath/tools/rmi/registry/package.html create mode 100644 tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java create mode 100644 tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl_Stub.java create mode 100644 tools/jarsigner.in create mode 100644 tools/keytool.in (limited to 'tools') diff --git a/tools/.cvsignore b/tools/.cvsignore index eaae7d326..75730de04 100644 --- a/tools/.cvsignore +++ b/tools/.cvsignore @@ -1,3 +1,5 @@ +jarsigner +keytool Makefile.in Makefile tools.zip diff --git a/tools/Makefile.am b/tools/Makefile.am index 65858f52a..7a8f1ce97 100755 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,17 +1,19 @@ ## Input file for automake to generate the Makefile.in used by configure +GLIBJ_CLASSPATH='$(top_builddir)/lib':'$(top_builddir)/lib/glibj.zip' + # Setup the compiler to use the GNU Classpath library we just build if FOUND_GCJ -JCOMPILER = $(GCJ) --bootclasspath '$(top_builddir)/lib' --classpath . -C +JCOMPILER = $(GCJ) -encoding UTF-8 --bootclasspath $(GLIBJ_CLASSPATH) --classpath . -C else if FOUND_JIKES -JCOMPILER = $(JIKES) -bootclasspath '' -extdirs '' -sourcepath '' --classpath $(top_builddir)/lib:. +JCOMPILER = $(JIKES) $(JIKESENCODING) -bootclasspath '' -extdirs '' -sourcepath '' --classpath $(GLIBJ_CLASSPATH):. else if FOUND_GCJX -JCOMPILER = $(GCJX) -bootclasspath '' -sourcepath '' -classpath $(top_builddir)/lib:. +JCOMPILER = $(GCJX) -encoding UTF-8 -bootclasspath '' -sourcepath '' -classpath $(GLIBJ_CLASSPATH):. else if FOUND_ECJ -JCOMPILER = $(ECJ) -bootclasspath '$(top_builddir)/lib' -classpath . +JCOMPILER = $(ECJ) -encoding UTF-8 -bootclasspath $(GLIBJ_CLASSPATH) -classpath . else error dunno how to setup the JCOMPILER and compile endif @@ -19,6 +21,9 @@ endif endif endif +bin_SCRIPTS = jarsigner keytool +EXTRA_DIST = jarsigner.in keytool.in + # All our example java source files TOOLS_JAVA_FILES = $(srcdir)/gnu/classpath/tools/*.java $(srcdir)/gnu/classpath/tools/*/*.java $(srcdir)/gnu/classpath/tools/*/*/*.java @@ -30,7 +35,7 @@ TOOLS_ZIP = tools.zip BUILT_SOURCES = $(TOOLS_ZIP) # The templates that must be included into the generated zip file. -GRMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/giop/grmic/templates/*.jav +GRMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/giop/grmic/templates/*.jav RMIC_TEMPLATES = $(srcdir)/gnu/classpath/tools/rmi/rmic/templates/*.jav TOOLS_TEMPLATES = $(GRMIC_TEMPLATES) $(RMIC_TEMPLATES) @@ -38,8 +43,10 @@ TOOLS_TEMPLATES = $(GRMIC_TEMPLATES) $(RMIC_TEMPLATES) # This covers the built-in help texts, both for giop and rmic subpackages. GIOP_HELPS = $(srcdir)/gnu/classpath/tools/giop/*.txt RMI_HELPS = $(srcdir)/gnu/classpath/tools/rmi/*.txt +JARSIGNER_HELPS = $(srcdir)/gnu/classpath/tools/jarsigner/*.txt +KEYTOOL_HELPS = $(srcdir)/gnu/classpath/tools/keytool/*.txt -TOOLS_HELPS = $(GIOP_HELPS) $(RMI_HELPS) +TOOLS_HELPS = $(GIOP_HELPS) $(RMI_HELPS) $(JARSIGNER_HELPS) $(KEYTOOL_HELPS) # The tool specific README files. READMES = $(srcdir)/gnu/classpath/tools/giop/README @@ -74,11 +81,15 @@ dist-hook: $(TOOLS_ZIP): $(TOOLS_JAVA_FILES) mkdir -p classes/gnu/classpath/tools/giop/grmic/templates mkdir -p classes/gnu/classpath/tools/rmi/rmic/templates + mkdir -p classes/gnu/classpath/tools/jarsigner + mkdir -p classes/gnu/classpath/tools/keytool cp $(RMIC_TEMPLATES) classes/gnu/classpath/tools/rmi/rmic/templates - cp $(GRMIC_TEMPLATES) classes/gnu/classpath/tools/giop/grmic/templates + cp $(GRMIC_TEMPLATES) classes/gnu/classpath/tools/giop/grmic/templates cp $(RMI_HELPS) classes/gnu/classpath/tools/rmi/ cp $(GIOP_HELPS) classes/gnu/classpath/tools/giop/ - $(JCOMPILER) -d classes $(TOOLS_JAVA_FILES) + cp $(JARSIGNER_HELPS) classes/gnu/classpath/tools/jarsigner/ + cp $(KEYTOOL_HELPS) classes/gnu/classpath/tools/keytool/ + $(JCOMPILER) -d classes $(TOOLS_JAVA_FILES) (cd classes; \ if test "$(ZIP)" != ""; then $(ZIP) -r ../$(TOOLS_ZIP) .; fi; \ if test "$(FASTJAR)" != ""; then $(FASTJAR) cf ../$(TOOLS_ZIP) .; fi; \ diff --git a/tools/README b/tools/README index de8c2c5b4..dc049d3b5 100644 --- a/tools/README +++ b/tools/README @@ -39,6 +39,20 @@ in gnu.classpath.tools.rmi package): research and backward-compatibile applications, as Classpath supports the 1.5 feature to replace such stubs by proxy classes. +* REGISTRY - The persistent RMI naming service. +* RMID - The persistent RMI activation daemon, supports the + java.rmi.activation package. - - \ No newline at end of file +== Security tools == + +Security tools (currently) are used for signing and verifying JAR files +as well as (planned) generating and managing cryptographic tokens and +credentials. + +The list of individual tools, the name of their main class that should be +invoked by the Java launcher, and a summary of what they provide follows: + +* jarsigner gnu.classpath.tools.jarsigner.Main + A drop-in replacement for the "jarsigner" tool. + + diff --git a/tools/appletviewer.c b/tools/appletviewer.c new file mode 100644 index 000000000..2609ccaf6 --- /dev/null +++ b/tools/appletviewer.c @@ -0,0 +1,235 @@ +/* appletviewer.c -- a native appletviewer wrapper for VMs that + support the JNI invocation interface + 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. */ + +#include +#include +#include +#include +#include "config.h" + +#ifndef JNI_VERSION_1_2 +# error JNI version 1.2 or greater required +#endif + +union env_union +{ + void *void_env; + JNIEnv *jni_env; +}; + +int +main (int argc, const char** argv) +{ + union env_union tmp; + JNIEnv* env; + JavaVM* jvm; + JavaVMInitArgs vm_args; + jint result; + jclass class_id; + jmethodID method_id; + jstring str; + jclass string_class_id; + jobjectArray args_array; + char** non_vm_argv; + int non_vm_argc; + int i; + int classpath_found = 0; + + env = NULL; + jvm = NULL; + + vm_args.nOptions = 0; + vm_args.options = NULL; + + non_vm_argc = 0; + non_vm_argv = NULL; + + if (argc > 1) + { + for (i = 1; i < argc; i++) + { + if (!strncmp (argv[i], "-J", 2)) + { + if (!strncmp (argv[i], "-J-Djava.class.path=", 20)) + classpath_found = 1; + + /* A virtual machine option. */ + vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption)); + + if (vm_args.options == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + + if (strlen (argv[i]) == 2) + { + g_printerr ("appletviewer: the -J option must not be followed by a space.\n"); + goto destroy; + } + else + vm_args.options[vm_args.nOptions++].optionString = g_strdup (argv[i] + 2); + } + else if (!strncmp (argv[i], "--version", 9) + && argv[i][9] == '\0') + { + g_print ("appletviewer (GCJ Applet Viewer) " PACKAGE_VERSION "\n"); + exit (0); + } + else if (!strncmp (argv[i], "-debug", 6) + && argv[i][6] == '\0') + { + /* FIXME: Ignore for now. The debug option will be + unsupported until we have the ability to debug + bytecode. For now, just strip it out of the argument + list. */ + } + else + { + non_vm_argv = (char**) realloc (non_vm_argv, (non_vm_argc + 1) * sizeof (char*)); + if (non_vm_argv == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + non_vm_argv[non_vm_argc++] = g_strdup (argv[i]); + } + } + } + + if (!classpath_found) + { + /* Set the invocation classpath. */ + vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption)); + + if (vm_args.options == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + + vm_args.options[vm_args.nOptions++].optionString = "-Djava.class.path=" "@datadir@/@PACKAGE@/tools.zip"; + } + + /* Terminate vm_args.options with a NULL element. */ + vm_args.options = (JavaVMOption*) realloc (vm_args.options, (vm_args.nOptions + 1) * sizeof (JavaVMOption)); + if (vm_args.options == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + vm_args.options[vm_args.nOptions].optionString = NULL; + + /* Terminate non_vm_argv with a NULL element. */ + non_vm_argv = (char**) realloc (non_vm_argv, (non_vm_argc + 1) * sizeof (char*)); + if (non_vm_argv == NULL) + { + g_printerr ("appletviewer: realloc failed.\n"); + goto destroy; + } + non_vm_argv[non_vm_argc] = NULL; + + vm_args.version = JNI_VERSION_1_2; + vm_args.ignoreUnrecognized = JNI_TRUE; + + result = JNI_CreateJavaVM (&jvm, &tmp.void_env, &vm_args); + + if (result < 0) + { + g_printerr ("appletviewer: couldn't create virtual machine\n"); + goto destroy; + } + + env = tmp.jni_env; + + string_class_id = (*env)->FindClass (env, "java/lang/String"); + if (string_class_id == NULL) + { + g_printerr ("appletviewer: FindClass failed.\n"); + goto destroy; + } + + args_array = (*env)->NewObjectArray (env, non_vm_argc, string_class_id, NULL); + if (args_array == NULL) + { + g_printerr ("appletviewer: NewObjectArray failed.\n"); + goto destroy; + } + + for (i = 0; i < non_vm_argc; i++) + { + str = (*env)->NewStringUTF (env, non_vm_argv[i]); + if (str == NULL) + { + g_printerr ("appletviewer: NewStringUTF failed.\n"); + goto destroy; + } + + (*env)->SetObjectArrayElement (env, args_array, i, str); + } + + class_id = (*env)->FindClass (env, "gnu/classpath/tools/appletviewer/Main"); + if (class_id == NULL) + { + g_printerr ("appletviewer: FindClass failed.\n"); + goto destroy; + } + + method_id = (*env)->GetStaticMethodID (env, class_id, "main", "([Ljava/lang/String;)V"); + + if (method_id == NULL) + { + g_printerr ("appletviewer: GetStaticMethodID failed.\n"); + goto destroy; + } + + (*env)->CallStaticVoidMethod (env, class_id, method_id, args_array); + + destroy: + + if (env != NULL) + { + if ((*env)->ExceptionOccurred (env)) + (*env)->ExceptionDescribe (env); + + if (jvm != NULL) + (*jvm)->DestroyJavaVM (jvm); + } + + return 1; +} diff --git a/tools/appletviewer.in b/tools/appletviewer.in new file mode 100644 index 000000000..61571d906 --- /dev/null +++ b/tools/appletviewer.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 appletviewer 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.appletviewer.Main $@ diff --git a/tools/gnu/classpath/tools/HelpPrinter.java b/tools/gnu/classpath/tools/HelpPrinter.java index 61a3e683b..89468918a 100644 --- a/tools/gnu/classpath/tools/HelpPrinter.java +++ b/tools/gnu/classpath/tools/HelpPrinter.java @@ -70,30 +70,47 @@ public class HelpPrinter } /** - * Prints the help message and terminates. + * Prints the contents of the resource specified by the designated path. * - * @param helpResourcePath the path to the help resource, related to the + * @param helpResourcePath the path to a help resource, related to the * HelpPrinter class. */ - public static void printHelpAndExit(String helpResourcePath) + public static void printHelp(String helpResourcePath) { InputStream in = HelpPrinter.class.getResourceAsStream(helpResourcePath); - BufferedReader r = new BufferedReader(new InputStreamReader(in)); - + BufferedReader br = new BufferedReader(new InputStreamReader(in)); try { String s; - while ((s = r.readLine()) != null) - { - System.out.println(s); - } - r.close(); + while ((s = br.readLine()) != null) + System.out.println(s); } - catch (IOException e) + catch (IOException x) { System.err.print("Resource loading is broken:"); - e.printStackTrace(); + x.printStackTrace(System.err); + } + finally + { + try + { + br.close(); + } + catch (IOException ignored) + { + } } + } + + /** + * Prints the help message and terminates. + * + * @param helpResourcePath the path to the help resource, related to the + * HelpPrinter class. + */ + public static void printHelpAndExit(String helpResourcePath) + { + printHelp(helpResourcePath); System.exit(0); } } diff --git a/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java b/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java new file mode 100644 index 000000000..dfbedfe36 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletClassLoader.java @@ -0,0 +1,81 @@ +/* AppletClassLoader -- a loader for applet classes + Copyright (C) 2004, 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.appletviewer; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; + +public class AppletClassLoader extends URLClassLoader +{ + /** + * Constructs a new AppletLoader object. + * + * @param codebase the codebase of the applet + * @param archives the urls to add to the search path + */ + public AppletClassLoader(URL codebase, ArrayList archives) + { + super(new URL[0]); + + for (int count = 0; count < archives.size(); count++) + addURL((URL) archives.get(count)); + + addURL(codebase); + } + + /** + * Finds the specified class. This method should be overridden by + * class loader implementations that follow the delegation model for + * loading classes, and will be invoked by the loadClass method after + * checking the parent class loader for the requested class. The default + * implementation throws a ClassNotFoundException. + * + * (description copied from java.lang.ClassLoader.findClass(String)) + * + * @param name The name of the class. + * + * @return the resulting Class object. + * + * @exception ClassNotFoundException if the class is not found. + */ + protected Class findClass(String name) throws ClassNotFoundException + { + return super.findClass(name); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java b/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java new file mode 100644 index 000000000..32ab31639 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletSecurityManager.java @@ -0,0 +1,95 @@ +/* AppletSecurityManager.java -- an applet security manager + Copyright (C) 2004, 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.appletviewer; + +import java.io.FilePermission; +import java.net.SocketPermission; +import java.security.Permission; +import java.security.SecurityPermission; +import java.util.PropertyPermission; + +class AppletSecurityManager extends SecurityManager +{ + private boolean plugin; + + AppletSecurityManager(boolean plugin) + { + this.plugin = plugin; + } + + public void checkPermission(Permission permission) + { + if (permission == null) + throw new NullPointerException(); + + // FIXME: we need to restrict this. + // + // libgcj asks for "java.io.FilePermission <> execute" + // to be able to execute "addr2line" to get proper stack traces. + if (permission instanceof FilePermission) + return; + + // FIXME: we need to restrict this. + if (permission instanceof SecurityPermission) + return; + + // FIXME: is this really needed ? + if (permission instanceof PropertyPermission) + return; + + // Needed to allow to access AWT event queue. + if (permission.getName().equals("accessEventQueue")) + return; + + // Needed to create a class loader for each codebase. + if (permission.getName().equals("createClassLoader")) + return; + + // FIXME: we need to allow access to codebase here. + + if (permission instanceof SocketPermission // for net access + || permission instanceof RuntimePermission) // for checkWrite(FileDescriptor) + return; + + if (! plugin && permission.getName().equals("exitVM")) + return; + + // Reject all other permissions. + throw new SecurityException(); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/AppletTag.java b/tools/gnu/classpath/tools/appletviewer/AppletTag.java new file mode 100644 index 000000000..b2d7ccb2b --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletTag.java @@ -0,0 +1,485 @@ +/* AppletTag.java -- a representation of an HTML APPLET tag + Copyright (C) 2003, 2004, 2005, 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.appletviewer; + +import gnu.xml.dom.html2.DomHTMLAppletElement; +import gnu.xml.dom.html2.DomHTMLEmbedElement; +import gnu.xml.dom.html2.DomHTMLObjectElement; + +import java.awt.Dimension; +import java.awt.Toolkit; + +import java.io.File; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.text.NumberFormat; +import java.text.ParseException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +/** + * @author Lillian Angel (langel@redhat.com) + * @author Thomas Fitzsimmons (fitzsim@redhat.com) + */ +class AppletTag +{ + + /** + * The document base of this applet. + */ + URL documentbase; + + /** + * name of applet tag. + */ + String name = ""; + + /** + * code of applet tag. + */ + String code = ""; + + /** + * codebase of applet tag. + */ + String codebase = ""; + + /** + * The archives. + */ + ArrayList archives = new ArrayList(); + + /** + * The parameters. + */ + HashMap parameters = new HashMap(); + + /** + * The screen size. + */ + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + /** + * Default constructor. + */ + AppletTag() + { + // Do nothing. + } + + /** + * Constructs an AppletTag and parses the given applet element. + * + * @param appElement - the Applet element to parse. + */ + AppletTag(DomHTMLAppletElement appElement) + { + name = appElement.getName(); + parameters.put("name", name); + + parameters.put("object", appElement.getObject()); + parameters.put("align", appElement.getAlign()); + parameters.put("alt", appElement.getAlt()); + parameters.put("height", appElement.getHeight()); + parameters.put("hspace", Integer.toString(appElement.getHspace())); + parameters.put("vspace", Integer.toString(appElement.getVspace())); + parameters.put("width", appElement.getWidth()); + + TagParser.parseParams(appElement, this); + + if (code.equals("")) + { + code = appElement.getCode(); + if (code.equals("")) + code = appElement.getCls(); + } + + // Must initialize codebase before archives + if (codebase.equals("")) + { + codebase = appElement.getCodeBase(); + if (codebase.equals("")) + codebase = appElement.getSrc(); + } + + if (archives.size() == 0) + { + String arcs = ""; + String arch = appElement.getArchive(); + + if (code.indexOf(".") < 0) + arcs = code + ".jar"; + + if (!arch.equals("")) + arcs += "," + arch; + + if (!arcs.equals("")) + archives = TagParser.parseArchives(arcs, this); + } + } + + /** + * Constructs an AppletTag and parses the given embed element. + * + * @param embElement - the Embed element to parse. + */ + AppletTag(DomHTMLEmbedElement embElement) + { + // In an EMBED tag, a parameter is any non-standard attribute. This + // is a problem for applets that take parameters named "code", + // "codebase", "archive", "object", or "type". The solution is to + // allow the same attributes, prefixed by "java_". The presence of + // a "java_" attribute indicates that the non-prefixed attribute + // should be interpreted as a parameter. For example if "java_code" + // and "code" attributes are present in the EMBED tag then the + // "code" attribute is interpreted as a parameter. + + name = embElement.getName(); + parameters.put("name", name); + + String jobj = embElement.getJavaObject(); + if (!jobj.equals("")) + parameters.put("java_object", jobj); + else + parameters.put("object", embElement.getObject()); + + parameters.put("width", embElement.getWidth()); + parameters.put("height", embElement.getHeight()); + parameters.put("align", embElement.getAlign()); + parameters.put("alt", embElement.getAlt()); + parameters.put("hspace", Integer.toString(embElement.getHspace())); + parameters.put("mayscript", embElement.getMayscript()); + parameters.put("pluginspage", embElement.getPluginsPage()); + parameters.put("title", embElement.getTitle()); + parameters.put("type", embElement.getType()); + parameters.put("java_type", embElement.getJavaType()); + parameters.put("vspace", Integer.toString(embElement.getVspace())); + + TagParser.parseParams(embElement, this); + + // Must initialize codebase before archives + if (codebase.equals("")) + { + String javacb = embElement.getJavaCodeBase(); + if (!javacb.equals("")) + codebase = javacb; + else + codebase = embElement.getCodeBase(); + } + + if (code.equals("")) + { + String jcode = embElement.getJavaCode(); + if (!jcode.equals("")) + code = jcode; + else + code = embElement.getCode(); + } + + if (archives.size() == 0) + { + String arcs = ""; + String jarch = embElement.getJavaArchive(); + String arch = embElement.getArchive(); + + if (code.indexOf(".") < 0) + arcs = code + ".jar"; + + if (!jarch.equals("")) + arcs += "," + jarch; + else if (!arch.equals("")) + arcs += "," + arch; + + if (!arcs.equals("")) + archives = TagParser.parseArchives(arcs, this); + } + } + + /** + * Constructs an AppletTag and parses the given object element. + * + * @param objElement - the Object element to parse. + */ + AppletTag(DomHTMLObjectElement objElement) + { + // In an OBJECT tag, a parameter is any non-standard attribute. This + // is a problem for applets that take parameters named "code", + // "codebase", "archive", "object", or "type". The solution is to + // allow the same attributes, prefixed by "java_". The presence of + // a "java_" attribute indicates that the non-prefixed attribute + // should be interpreted as a parameter. For example if "java_code" + // and "code" attributes are present in the OBJECT tag then the + // "code" attribute is interpreted as a parameter. + + name = objElement.getName(); + parameters.put("name", name); + + String jobj = objElement.getJavaObject(); + if (!jobj.equals("")) + parameters.put("java_object", jobj); + else + parameters.put("object", objElement.getObject()); + + parameters.put("type", objElement.getType()); + parameters.put("java_type", objElement.getJavaType()); + parameters.put("align", objElement.getAlign()); + parameters.put("codetype", objElement.getCodeType()); + parameters.put("data", objElement.getData()); + parameters.put("declare", Boolean.toString(objElement.getDeclare())); + parameters.put("height", objElement.getHeight()); + parameters.put("hspace", Integer.toString(objElement.getHspace())); + parameters.put("border", objElement.getBorder()); + parameters.put("standby", objElement.getStandby()); + parameters.put("tabindex", Integer.toString(objElement.getTabIndex())); + parameters.put("usemap", objElement.getUseMap()); + parameters.put("vspace", Integer.toString(objElement.getVspace())); + parameters.put("width", objElement.getWidth()); + parameters.put("mayscript", objElement.getMayscript()); + parameters.put("scriptable", objElement.getScriptable()); + + TagParser.parseParams(objElement, this); + + // Must initialize codebase before archives + if (codebase.equals("")) + { + String javacb = objElement.getJavaCodeBase(); + if (! javacb.equals("")) + codebase = javacb; + else + codebase = objElement.getCodeBase(); + } + + if (code.equals("")) + { + String jcode = objElement.getJavaCode(); + if (!jcode.equals("")) + code = jcode; + else + code = objElement.getCode(); + } + + if (archives.size() == 0) + { + String arcs = ""; + String jarch = objElement.getJavaArchive(); + String arch = objElement.getArchive(); + + if (code.indexOf(".") < 0) + arcs = code + ".jar"; + + if (!jarch.equals("")) + arcs += "," + jarch; + else if (!arch.equals("")) + arcs += "," + arch; + + if (!arcs.equals("")) + archives = TagParser.parseArchives(arcs, this); + } + } + + /** + * String representation of the tag. + * + * @return the string representation. + */ + public String toString() + { + return (" name=" + name + "\n" + " code=" + code + "\n" + " codebase=" + + codebase + "\n" + " archive=" + archives + "\n" + " parameters=" + + parameters + "\n" + " documentbase=" + documentbase + "\n"); + } + + /** + * Returns the size of the applet. + * + * @return the size. + */ + Dimension getSize() + { + Dimension size = new Dimension(320, 200); + + try + { + String widthStr = (String) parameters.get("width"); + + if (widthStr != null && ! widthStr.equals("")) + { + if (widthStr.charAt(widthStr.length() - 1) == '%') + { + double p = NumberFormat.getPercentInstance(Locale.US).parse(widthStr).intValue() / 100.0; + size.width = (int)(p * screenSize.width); + } + else + size.width = NumberFormat.getInstance(Locale.US).parse(widthStr).intValue(); + } + } + catch (ParseException e) + { + // Use default. + } + + try + { + String heightStr = (String) parameters.get("height"); + + if (heightStr != null && !heightStr.equals("")) + { + if (heightStr.charAt(heightStr.length() - 1) == '%') + { + double p = NumberFormat.getPercentInstance(Locale.US).parse(heightStr).intValue() / 100.0; + size.height = (int) (p * screenSize.height); + } + else + size.height = NumberFormat.getInstance(Locale.US).parse(heightStr).intValue(); + } + } + catch (ParseException e) + { + // Use default. + } + + return size; + } + + /** + * Gets the code base. + * + * @return the codebase. + */ + String getCodeBase() + { + return codebase; + } + + /** + * Gets the archive list. + * + * @return the archive list. + */ + ArrayList getArchives() + { + return archives; + } + + /** + * Gets the code. + * + * @return the code. + */ + String getCode() + { + return code; + } + + /** + * Gets the document base. + * + * @return the document base. + */ + URL getDocumentBase() + { + return documentbase; + } + + /** + * Gets the specified parameter. + * + * @param name - the specified parameter. + * @return the parameter. + */ + String getParameter(String name) + { + return (String) parameters.get(name.toLowerCase()); + } + + /** + * Prepends the base to the codebase. + * + * @return the new URL. + */ + URL prependCodeBase(String base) throws MalformedURLException + { + if (documentbase == null) + documentbase = TagParser.db; + + URL fullcodebase; + + //If no codebase was specified, default to documentbase. + if (codebase.equals("")) + { + if (documentbase.getFile().endsWith(File.separator)) + fullcodebase = documentbase; + else + { + String dirname = documentbase.getFile(); + + // Determine dirname for file by stripping everything + // past the last file separator. + dirname = dirname.substring(0, + dirname.lastIndexOf(File.separatorChar) + 1); + + fullcodebase = new URL(documentbase.getProtocol(), + documentbase.getHost(), + documentbase.getPort(), dirname); + } + } + else + { + // codebase was specified. + URL codebaseURL = new URL(documentbase, codebase); + + if ("file".equals(codebaseURL.getProtocol())) + { + if (new File(codebaseURL.getFile()).isDirectory() && !codebase.endsWith(File.separator)) + fullcodebase = new URL(documentbase, codebase + File.separator); + else + fullcodebase = new URL(documentbase, codebase); + } + else if (codebase.endsWith(File.separator)) + fullcodebase = new URL(documentbase, codebase); + else + fullcodebase = new URL(documentbase, codebase + File.separator); + } + + return new URL(fullcodebase, base); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/AppletWarning.java b/tools/gnu/classpath/tools/appletviewer/AppletWarning.java new file mode 100644 index 000000000..b2376a4cb --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/AppletWarning.java @@ -0,0 +1,66 @@ +/* AppletWarning -- a security warning message display dialog + Copyright (C) 2003, 2004, 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.appletviewer; + +import javax.swing.JOptionPane; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +public class AppletWarning +{ + private static String TITLE = "WARNING"; + private static boolean showWarning = false; + + private static String MESSAGE = + "The current version of this applet plugin does not provide\n" + + "a security manager capable of handling Java (tm) applets. Applets\n" + + "have UNRESTRICTED access to your computer. This means they can do\n" + + "anything you can do, like deleting all your important data.\n\n" + + "Continue ?"; + + public static int show() + { + if (showWarning) + return JOptionPane.showConfirmDialog(null, MESSAGE, TITLE, + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE); + else + return JOptionPane.YES_OPTION; + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java b/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java new file mode 100644 index 000000000..7e118e931 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/CommonAppletContext.java @@ -0,0 +1,133 @@ +/* CommonAppletContext.java -- a common applet's context + Copyright (C) 2004, 2005, 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.appletviewer; + +import java.applet.Applet; +import java.applet.AppletContext; +import java.applet.AudioClip; +import java.awt.Image; +import java.awt.Toolkit; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + + +/* + * CommonAppletContext represents the common context stuff for both + * types, plugins and standalone. + */ +abstract class CommonAppletContext + implements AppletContext +{ + // FIXME: this needs to be static, and we need one AppletContext per + // Applet. + List applets = new ArrayList(); + HashMap streams = new HashMap(); + + void addApplet(Applet applet) + { + applets.add(applet); + } + + /////////////////////////////// + //// AppletContext methods //// + /////////////////////////////// + public AudioClip getAudioClip(URL url) + { + return Applet.newAudioClip(url); + } + + public Image getImage(URL url) + { + return Toolkit.getDefaultToolkit().getImage(url); + } + + public Applet getApplet(String name) + { + Applet a; + String appletName; + Iterator i = applets.iterator(); + + while (i.hasNext()) + { + a = (Applet) i.next(); + + appletName = a.getParameter("name"); + if (a != null && appletName != null && appletName.equals(name)) + return a; + } + return null; + } + + public Enumeration getApplets() + { + return Collections.enumeration(applets); + } + + public void showDocument(URL url) + { + showDocument(url, "_self"); + } + + /* + // FIXME: implement. + public abstract void showDocument (URL url, String target); + + // FIXME: implement. + public abstract void showStatus (String status); + */ + public void setStream(String key, InputStream stream) + { + streams.put(key, stream); + } + + public InputStream getStream(String key) + { + return (InputStream) streams.get(key); + } + + public Iterator getStreamKeys() + { + return streams.keySet().iterator(); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java b/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java new file mode 100644 index 000000000..bc0cc45e1 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/CommonAppletStub.java @@ -0,0 +1,138 @@ +/* CommonAppletStub.java -- an applet-browser interface class + Copyright (C) 2003, 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.appletviewer; + +import java.applet.AppletContext; +import java.applet.AppletStub; +import java.applet.Applet; +import java.net.MalformedURLException; +import java.net.URL; + + +class CommonAppletStub + implements AppletStub +{ + private AppletTag tag; + private AppletContext context; + private Applet applet; + + CommonAppletStub(AppletTag tag, AppletContext context, Applet applet) + { + this.tag = tag; + this.context = context; + this.applet = applet; + } + + //////////////////////////////// + ////// AppletStub Methods ////// + //////////////////////////////// + + /** + * Tests whether or not this applet is currently active. An applet + * becomes active just before the browser invokes start (), and + * becomes inactive just before the browser invokes stop (). + * + * @return true if applet is active, false otherwise + */ + public boolean isActive() + { + return true; + } + + /** + * Returns the basename URL of the document in which this applet is + * embedded. + * + * @return the document base url. + */ + public URL getDocumentBase() + { + return tag.getDocumentBase(); + } + + /** + * Returns the URL of the code base for this applet. + * + * @return the codebase url + */ + public URL getCodeBase() + { + try + { + return tag.prependCodeBase(""); + } + catch (MalformedURLException e) + { + throw new RuntimeException("unknown codebase"); + } + } + + /** + * Returns the value of the specified parameter that was specified + * in the APPLET tag for this applet. + * + * @param name the key name + * + * @return the key value + */ + public String getParameter(String name) + { + return (String) tag.getParameter(name.toLowerCase()); + } + + /** + * Returns the applet context for this applet. + * + * @return the context + */ + public AppletContext getAppletContext() + { + return context; + } + + /** + * Requests that the applet window for this applet be resized. + * + * @param width the new witdh + * @param height the new height + */ + public void appletResize(int width, int height) + { + applet.setBounds (0, 0, width, height); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java b/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java new file mode 100644 index 000000000..9c937cc77 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/ConsoleDialog.java @@ -0,0 +1,175 @@ +/* ConsoleDialog -- a console dialog for applets + Copyright (C) 2003, 2004, 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.appletviewer; + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + + +/** + * This class is a little dialog showing standard output and standard error output. + * + * @author Michael Koch (konqueror@gmx.de) + */ +public class ConsoleDialog extends Frame + implements ActionListener +{ + static class InternalOutputStream extends OutputStream + { + private ConsoleDialog console; + + public InternalOutputStream(ConsoleDialog console) + { + super(); + this.console = console; + } + + public void write(int data) throws IOException + { + console.print(String.valueOf((char) data)); + } + } + + private TextArea textArea; + private Button buttonClear; + private Button buttonHide; + private PrintStream printStream; + + /** + * Creates a console dialog object. + */ + public ConsoleDialog() + { + super(Main.messages.getString("gcjwebplugin.console_title")); + + setSize(400, 200); + setLayout(new BorderLayout()); + addWindowListener(new WindowAdapter() + { + public void windowClosing(WindowEvent event) + { + hide(); + } + }); + + textArea = new TextArea(); + textArea.setEditable(false); + add(textArea); + + Panel panel = new Panel(); + panel.setLayout(new FlowLayout()); + add(panel, BorderLayout.SOUTH); + + buttonClear = new Button(Main.messages.getString("gcjwebplugin.console_clear")); + buttonClear.addActionListener(this); + panel.add(buttonClear); + + buttonHide = new Button(Main.messages.getString("gcjwebplugin.console_hide")); + buttonHide.addActionListener(this); + panel.add(buttonHide); + + printStream = new PrintStream(new InternalOutputStream(this)); + clearTextArea(); + } + + /** + * Clears the content of the textarea and inserts the initial text. + */ + public void clearTextArea() + { + textArea.setText(""); + + println("java.vm.version: " + System.getProperty("java.vm.version")); + println("java.vm.vendor: " + System.getProperty("java.vm.vendor")); + } + + /** + * Print a message into the console dialog. + * + * @param message the message to print. + */ + public void print(String message) + { + textArea.append(message); + } + + /** + * Print a line into the console dialog. + * + * @param message the line to print. + */ + public void println(String message) + { + print(message + "\n"); + } + + /** + * Perform actions on button clicks inside the console dialog. + * + * @param event the event. + */ + public void actionPerformed(ActionEvent event) + { + if (event.getSource() == buttonHide) + hide(); // Hide console window. + else if (event.getSource() == buttonClear) + clearTextArea(); // Clear text area and insert standard messages. + } + + /** + * Returns a PrintStream object that prints into the + * console dialog. + * + * @return the PrintStream object. + */ + public PrintStream getPrintStream() + { + return printStream; + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java b/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java new file mode 100644 index 000000000..059dbee40 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/ErrorApplet.java @@ -0,0 +1,53 @@ +/* ErrorApplet.java -- an applet to load in case of an error + Copyright (C) 2004, 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.appletviewer; + +import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Button; + +public class ErrorApplet extends Applet +{ + public ErrorApplet(String message) + { + setLayout(new BorderLayout()); + + Button button = new Button(message); + add(button); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/Main.java b/tools/gnu/classpath/tools/appletviewer/Main.java new file mode 100644 index 000000000..878b2be8a --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/Main.java @@ -0,0 +1,303 @@ +/* Main.java -- a standalone viewer for Java applets + Copyright (C) 2003, 2004, 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.appletviewer; + +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; +import java.applet.Applet; +import java.awt.Dimension; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.ResourceBundle; + + +class Main +{ + /** + * The localized strings are kept in a separate file. + */ + public static final ResourceBundle messages = ResourceBundle.getBundle + ("gnu.classpath.tools.appletviewer.MessagesBundle"); + + private static HashMap classLoaderCache = new HashMap(); + + private static ClassLoader getClassLoader(URL codebase, ArrayList archives) + { + // Should load class loader each time. It is possible that there + // are more than one applet to be loaded with different archives. + AppletClassLoader loader = new AppletClassLoader(codebase, archives); + classLoaderCache.put(codebase, loader); + + return loader; + } + + private static String code = null; + private static String codebase = null; + private static String archive = null; + private static List parameters = new ArrayList(); + private static Dimension dimensions = new Dimension(-1, -1); + private static String pipeInName = null; + private static String pipeOutName = null; + private static boolean pluginMode = false; + private static Parser parser = null; + + static Applet createApplet(AppletTag tag) + { + Applet applet = null; + + try + { + ClassLoader loader = getClassLoader(tag.prependCodeBase(""), + tag.getArchives()); + String code = tag.getCode(); + + if (code.endsWith(".class")) + code = code.substring(0, code.length() - 6).replace('/', '.'); + + Class c = loader.loadClass(code); + applet = (Applet) c.newInstance(); + } + catch (Exception e) + { + e.printStackTrace(); + } + + if (applet == null) + applet = new ErrorApplet("Error loading applet"); + + return applet; + } + + protected static boolean verbose; + + /** + * The main method starting the applet viewer. + * + * @param args the arguments given on the command line. + * + * @exception IOException if an error occurs. + */ + public static void main(String[] args) throws IOException + { + parser = new ClasspathToolParser("appletviewer", true); + parser.setHeader("usage: appletviewer [OPTION] --code=FILE | URL..."); + + OptionGroup attributeGroup = new OptionGroup("Applet tag options"); + + attributeGroup.add(new Option("code", Main.messages.getString + ("gcjwebplugin.code_description"), + "") + { + public void parsed(String argument) throws OptionException + { + code = argument; + } + }); + attributeGroup.add(new Option("codebase", Main.messages.getString + ("gcjwebplugin.codebase_description"), + "") + { + public void parsed(String argument) throws OptionException + { + codebase = argument; + } + }); + attributeGroup.add(new Option("archive", Main.messages.getString + ("gcjwebplugin.archive_description"), + "") + { + public void parsed(String argument) throws OptionException + { + archive = argument; + } + }); + attributeGroup.add(new Option("width", Main.messages.getString + ("gcjwebplugin.width_description"), + "") + { + public void parsed(String argument) throws OptionException + { + dimensions.width = Integer.parseInt(argument); + } + }); + attributeGroup.add(new Option("height", Main.messages.getString + ("gcjwebplugin.height_description"), + "") + { + public void parsed(String argument) throws OptionException + { + dimensions.height = Integer.parseInt(argument); + } + }); + attributeGroup.add(new Option("param", Main.messages.getString + ("gcjwebplugin.param_description"), + ",") + { + public void parsed(String argument) throws OptionException + { + parameters.add(argument); + } + }); + OptionGroup pluginGroup = new OptionGroup("Plugin option"); + pluginGroup.add(new Option("plugin", Main.messages.getString + ("gcjwebplugin.plugin_description"), + ",") + { + public void parsed(String argument) throws OptionException + { + pluginMode = true; + int comma = argument.indexOf(','); + pipeInName = argument.substring(0, comma); + pipeOutName = argument.substring(comma + 1); + } + }); + OptionGroup debuggingGroup = new OptionGroup("Debugging option"); + debuggingGroup.add(new Option ("verbose", Main.messages.getString + ("gcjwebplugin.verbose_description"), + null) + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + OptionGroup compatibilityGroup = new OptionGroup("Compatibility options"); + compatibilityGroup.add(new Option("debug", Main.messages.getString + ("gcjwebplugin.debug_description"), + null) + { + public void parsed(String argument) throws OptionException + { + // Currently ignored. + } + }); + compatibilityGroup.add(new Option("encoding", Main.messages.getString + ("gcjwebplugin.encoding_description"), + "") + { + public void parsed(String argument) throws OptionException + { + // FIXME: We should probably be using + // java.nio.charset.CharsetDecoder to handle the encoding. What + // is the status of Classpath's implementation? + } + }); + compatibilityGroup.add(new Option('J', Main.messages.getString + ("gcjwebplugin.j_description"), + "") + { + public void parsed(String argument) throws OptionException + { + // -J should be handled by the appletviewer wrapper binary. + // We add it here so that it shows up in the --help output. + } + }); + parser.add(attributeGroup); + parser.add(pluginGroup); + parser.add(debuggingGroup); + parser.add(compatibilityGroup); + + String[] urls = parser.parse(args); + + // Print arguments. + printArguments(args); + + args = urls; + + if (dimensions.height < 0) + dimensions.height = 200; + + if (dimensions.width < 0) + dimensions.width = (int) (1.6 * dimensions.height); + + //System.setSecurityManager(new AppletSecurityManager(pluginMode)); + + if (pluginMode) + { + InputStream in; + OutputStream out; + + in = new FileInputStream(pipeInName); + out = new FileOutputStream(pipeOutName); + + PluginAppletViewer.start(in, out); + } + else + { + if (code == null) + { + // The --code option wasn't given and there are no URL + // arguments so we have nothing to work with. + if (args.length == 0) + { + System.err.println(Main.messages.getString("gcjwebplugin.no_input_files")); + System.exit(1); + } + // Create a standalone appletviewer from a list of URLs. + new StandaloneAppletViewer(args); + } + else + { + // Create a standalone appletviewer from the --code + // option. + new StandaloneAppletViewer(code, codebase, archive, parameters, dimensions); + } + } + } + + static void printArguments(String[] args) + { + if (verbose) + { + System.out.println("raw arguments:"); + + for (int i = 0; i < args.length; i++) + System.out.println(" " + args[i]); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java new file mode 100644 index 000000000..a0e6acd12 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletContext.java @@ -0,0 +1,72 @@ +/* PluginAppletContext.java -- an applet's context within a web browser + Copyright (C) 2003, 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.appletviewer; + +import java.net.URL; +import java.io.IOException; + +/* + * PluginAppletContext represents the context within a webpage of a + * group of applets that all share the same codebase. + */ +class PluginAppletContext extends CommonAppletContext +{ + public void showDocument(URL url, String target) + { + try + { + PluginAppletViewer.write("url " + url + " " + target); + } + catch(IOException e) + { + System.err.println("showDocument failed: " + e); + } + } + + public void showStatus(String status) + { + try + { + PluginAppletViewer.write("status " + status); + } + catch(IOException e) + { + System.err.println("showDocument failed: " + e); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java new file mode 100644 index 000000000..fdb8097b4 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletViewer.java @@ -0,0 +1,172 @@ +/* PluginAppletViewer.java -- manages embeddable applet windows + Copyright (C) 2003, 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.appletviewer; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.MalformedURLException; +import java.nio.charset.Charset; +import java.util.HashMap; + + +/** + * PluginAppletViewer communicates through pipes with a web browser + * plugin. A PluginAppletViewer manages applet windows that may be + * embedded into web pages. + */ +class PluginAppletViewer +{ + // A mapping of instance IDs to PluginAppletWindows. + static HashMap appletWindows = new HashMap (); + + private static BufferedReader pluginInputStream; + private static BufferedWriter pluginOutputStream; + + static void start(InputStream inputStream, OutputStream outputStream) + throws MalformedURLException, IOException + { + // Set up input and output pipes. Use UTF-8 encoding. + pluginInputStream = + new BufferedReader(new InputStreamReader(inputStream, + Charset.forName("UTF-8"))); + pluginOutputStream = + new BufferedWriter(new OutputStreamWriter(outputStream, + Charset.forName("UTF-8"))); + + write("running"); + + // Read first message. + String message = read(); + + PluginAppletWindow currentWindow = null; + + while (true) + { + if (message.startsWith("instance")) + { + // Read applet instance identifier. + String key = message.substring(9); + + if (appletWindows.get(key) == null) + appletWindows.put(key, new PluginAppletWindow()); + + currentWindow = (PluginAppletWindow) appletWindows.get(key); + } + else if (message.startsWith("tag")) + { + int pos = message.indexOf(' ', 4); + String documentbase = message.substring(4, pos); + String tag = message.substring(pos + 1); + currentWindow.setParser(tag, documentbase); + } + else if (message.startsWith("handle")) + { + long handle = Long.parseLong(message.substring(7)); + + currentWindow.setHandle(handle); + } + else if (message.startsWith("width")) + { + int width = Integer.parseInt(message.substring(6)); + + currentWindow.setSize(width, currentWindow.getHeight()); + } + else if (message.startsWith("height")) + { + int height = Integer.parseInt(message.substring(7)); + + currentWindow.setSize(currentWindow.getWidth(), height); + } + else if (message.startsWith("destroy")) + { + appletWindows.remove(currentWindow); + currentWindow.dispose(); + } + + // Read next message. + message = read(); + } + } + + /** + * Write string to plugin. + * + * @param message the message to write + * + * @exception IOException if an error occurs + */ + static void write(String message) throws IOException + { + pluginOutputStream.write(message, 0, message.length()); + pluginOutputStream.newLine(); + pluginOutputStream.flush(); + + System.err.println(" PIPE: applet viewer wrote: " + message); + } + + /** + * Read string from plugin. + * + * @return the read string + * + * @exception IOException if an error occurs + */ + static String read() throws IOException + { + String message = pluginInputStream.readLine(); + + System.err.println(" PIPE: applet viewer read: " + message); + + if (message == null || message.equals("shutdown")) + { + // Close input/output channels to plugin. + pluginInputStream.close(); + pluginOutputStream.close(); + + System.err.println("appletviewer: exiting plugin applet viewer"); + System.exit(0); + } + + return message; + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java b/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java new file mode 100644 index 000000000..6d36e1cf0 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/PluginAppletWindow.java @@ -0,0 +1,454 @@ +/* PluginAppletWindow.java -- an embeddable applet window + Copyright (C) 2003, 2004, 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.appletviewer; + +import gnu.java.awt.EmbeddedWindow; + +import java.applet.Applet; +import java.applet.AppletContext; +import java.awt.Dimension; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.io.IOException; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; + +import javax.swing.JOptionPane; + + +class PluginAppletWindow + extends EmbeddedWindow + implements ContainerListener, ComponentListener, MouseListener, + MouseMotionListener, InputMethodListener, HierarchyListener, + HierarchyBoundsListener +{ + + // This class implements various listeners because the author of an applet + // may attach listeners to it, unaware of the applet's parent (this class). + // So, we must pass all listener events on this plugin applet window to the + // actual applet. + + private static HashMap contexts = new HashMap(); + private Applet applet; + private TagParser parser; + private AppletTag tag; + + PluginAppletWindow() + { + super(); + addContainerListener(this); + addComponentListener(this); + addMouseListener(this); + addMouseMotionListener(this); + addInputMethodListener(this); + addHierarchyListener(this); + addHierarchyBoundsListener(this); + } + + /////////////////////////////////// + /// ContainerListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when a component is added to the container. + * + * @param event the ContainerEvent indicating component + * addition + */ + public void componentAdded(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentAdded(event); + } + } + + /** + * This method is called when a component is removed from the container. + * + * @param event the ContainerEvent indicating component removal + */ + public void componentRemoved(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentRemoved(event); + } + } + + /////////////////////////////////// + /// ComponentListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when the component is resized. + * + * @param event the ComponentEvent indicating the resize + */ + public void componentResized(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentResized(event); + } + } + + /** + * This method is called when the component is moved. + * + * @param event the ComponentEvent indicating the move + */ + public void componentMoved(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentMoved(event); + } + } + + /** + * This method is called when the component is made visible. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentShown(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentShown(event); + } + } + + /** + * This method is called when the component is hidden. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentHidden(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentHidden(event); + } + } + + /////////////////////////////////// + ////// MouseListener Methods ////// + /////////////////////////////////// + + /** + * This method is called when the mouse is clicked (pressed and released + * in short succession) on a component. + * + * @param event the MouseEvent indicating the click + */ + public void mouseClicked(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseClicked(event); + } + } + + /** + * This method is called when the mouse is pressed over a component. + * + * @param event the MouseEvent for the press + */ + public void mousePressed(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mousePressed(event); + } + } + + /** + * This method is called when the mouse is released over a component. + * + * @param event the MouseEvent for the release + */ + public void mouseReleased(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseReleased(event); + } + } + + /** + * This method is called when the mouse enters a component. + * + * @param event the MouseEvent for the entry + */ + public void mouseEntered(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseEntered(event); + } + } + + /** + * This method is called when the mouse exits a component. + * + * @param event the MouseEvent for the exit + */ + public void mouseExited(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseExited(event); + } + } + + /////////////////////////////////// + /// MouseMotionListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the mouse is moved over a component + * while a button has been pressed. + * + * @param event the MouseEvent indicating the motion + */ + public void mouseDragged(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseDragged(event); + } + } + + /** + * This method is called when the mouse is moved over a component + * while no button is pressed. + * + * @param event the MouseEvent indicating the motion + */ + public void mouseMoved(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseMoved(event); + } + } + + /////////////////////////////////// + /// InputMethodListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the text is changed. + * + * @param event the InputMethodEvent indicating the text change + */ + public void inputMethodTextChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].inputMethodTextChanged(event); + } + } + + /** + * This method is called when the cursor position within the text is changed. + * + * @param event the InputMethodEvent indicating the change + */ + public void caretPositionChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].caretPositionChanged(event); + } + } + + /////////////////////////////////// + //// HierarchyListener Methods //// + /////////////////////////////////// + + /** + * Called when the hierarchy of this component changes. Use + * getChangeFlags() on the event to see what exactly changed. + * + * @param e the event describing the change + */ + public void hierarchyChanged(HierarchyEvent event) + { + if (applet != null) + { + HierarchyListener[] l = applet.getHierarchyListeners(); + for (int i = 0; i < l.length; i++) + l[i].hierarchyChanged(event); + } + } + + ///////////////////////////////////////// + //// HierarchyBoundsListener Methods //// + ///////////////////////////////////////// + + /** + * Called when an ancestor component of the source is moved. + * + * @param e the event describing the ancestor's motion + */ + public void ancestorMoved(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorMoved(e); + } + } + + /** + * Called when an ancestor component is resized. + * + * @param e the event describing the ancestor's resizing + */ + public void ancestorResized(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorResized(e); + } + } + + void setParser(String tag, String documentbase) throws MalformedURLException, IOException + { + URL documentbaseURL = TagParser.getLocationToURL(documentbase); + StringReader in = new StringReader(tag); + this.parser = new TagParser(in, documentbaseURL); + } + + // ///////////////////////////////// + // //// EmbeddedWindow Method ////// + // ///////////////////////////////// + + /** + * Set the native handle of the window system to embed the window in. + * + * @param handle the native handle. + */ + public void setHandle(long handle) + { + super.setHandle(handle); + addNotify(); + + ArrayList l = parser.parseAppletTags(); + int s = l.size(); + + for (int i = 0; i < s; i++) + { + tag = (AppletTag) l.get(i); + applet = Main.createApplet(tag); + + if (contexts.get(tag.getCodeBase()) == null) + contexts.put(tag.getCodeBase(), new PluginAppletContext()); + + int result = AppletWarning.show(); + if (result == JOptionPane.NO_OPTION) + return; + + add(applet); + + AppletContext context = (AppletContext) contexts.get(tag.getCodeBase()); + ((PluginAppletContext) context).addApplet(applet); + + applet.setStub(new CommonAppletStub(tag, context, applet)); + Dimension size = getSize(); + if (size.width == 0 || size.height == 0) + size = tag.getSize(); + applet.setSize(size); + + // Initialize the applet before showing this window so that + // the applet doesn't receive events before it has been + // initialized. + applet.init(); + applet.start(); + setVisible(true); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java new file mode 100644 index 000000000..a779f068a --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletContext.java @@ -0,0 +1,75 @@ +/* StandaloneAppletContext.java -- an applet's context within the + standalone viewer + Copyright (C) 2003, 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.appletviewer; + +import java.net.URL; +import java.util.Iterator; +import java.util.List; + + +/** + * StandaloneAppletContext represents the context within a webpage of a + * group of applets that all share the same codebase. + */ +class StandaloneAppletContext extends CommonAppletContext +{ + private List appletWindows; + + StandaloneAppletContext(List appletWindows) + { + this.appletWindows = appletWindows; + } + + public void showDocument(URL url, String target) + { + System.err.println("showDocument is not implemented in standalone mode"); + } + + // In standalone mode, there are potentially several windows, each + // with its own status bar. In plugin mode, all the applets in the + // same context (on the same page) share the browser's status bar. + // The best way to simulate the plugin mode behaviour in standalone + // mode is to show the same status on each window's status bar. + public void showStatus(String status) + { + Iterator window = appletWindows.iterator(); + while (window.hasNext()) + ((StandaloneAppletWindow) window.next()).showStatus(status); + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java new file mode 100644 index 000000000..2b58f4b87 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletViewer.java @@ -0,0 +1,144 @@ +/* StandaloneAppletViewer.java -- a standalone viewer for Java applets + Copyright (C) 2003, 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.appletviewer; + +import java.awt.Dimension; +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + + +/** + * StandaloneAppletViewer displays an applet in its own Frame. Most + * of the context that is available to an applet within a webpage is + * available to it in StandaloneAppletViewer. + */ +class StandaloneAppletViewer extends Main +{ + static ArrayList appletTags = new ArrayList(); + static ArrayList appletWindows = new ArrayList(); + + StandaloneAppletViewer(String[] urls) + throws MalformedURLException, IOException + { + // Handle each file specified on the command line. + for (int i = 0; i < urls.length; i++) + { + TagParser parser = new TagParser(urls[i]); + appletTags.addAll(parser.parseAppletTags()); + } + + printTags(); + createWindows(); + } + + StandaloneAppletViewer(String code, String codebase, String archives, + List parameters, Dimension dimensions) + throws IOException + { + if (!(code.equals("") || code.endsWith(".class"))) + { + System.err.println("appletviewer: option '--code' requires a class filename"); + System.exit(1); + } + + String tagString = + ""; + + // Handle parameters. + Iterator pairs = parameters.iterator(); + while (pairs.hasNext()) + { + StringTokenizer paramTokenizer = + new StringTokenizer((String) pairs.next(), ","); + tagString += + ""; + } + + tagString += ""; + + StringReader reader = new StringReader(tagString); + String path = System.getProperty("user.dir") + File.separator; + TagParser parser = new TagParser(reader, + new URL("file", "", path)); + appletTags.addAll(parser.parseAppletTags()); + + printTags(); + createWindows(); + } + + void printTags() + { + if (verbose) + { + System.out.println("parsed applet tags:"); + + for (int i = 0; i < appletTags.size(); i++) + { + AppletTag tag = (AppletTag) appletTags.get(i); + + System.out.println(" tag " + i + ":"); + System.out.println(tag); + } + } + } + + void createWindows() + { + for (int i = 0; i < appletTags.size(); i++) + { + AppletTag tag = (AppletTag) appletTags.get(i); + + // Create a StandaloneAppletWindow and add it to the + // appletWindows list. + new StandaloneAppletWindow(tag, appletWindows); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java new file mode 100644 index 000000000..3b337bf80 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/StandaloneAppletWindow.java @@ -0,0 +1,559 @@ +/* StandaloneAppletWindow.java -- an applet frame + Copyright (C) 2003, 2004, 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.appletviewer; + +import java.applet.Applet; +import java.applet.AppletContext; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.HashMap; +import java.util.List; + +class StandaloneAppletWindow + extends Frame + implements ActionListener, ContainerListener, ComponentListener, + MouseListener, MouseMotionListener, InputMethodListener, HierarchyListener, + HierarchyBoundsListener +{ + + // This class implements various listeners because the author of an applet + // may attach listeners to it, unaware of the applet's parent (this class). + // So, we must pass all listener events on this plugin applet window to the + // actual applet. + + private static int testWindowCount; + private static HashMap contexts = new HashMap(); + private Applet applet; + private Label status = new Label(); + + private MenuItem restartItem; + private MenuItem reloadItem; + private MenuItem cancelItem; + private MenuItem saveItem; + private MenuItem startItem; + private MenuItem cloneItem; + private MenuItem tagItem; + private MenuItem infoItem; + private MenuItem editItem; + private MenuItem encodingItem; + private MenuItem printItem; + private MenuItem propertiesItem; + private MenuItem closeItem; + private MenuItem quitItem; + + StandaloneAppletWindow(AppletTag tag, List appletWindows) + { + appletWindows.add(this); + applet = Main.createApplet(tag); + + if (contexts.get(tag.codebase) == null) + contexts.put(tag.codebase, new StandaloneAppletContext(appletWindows)); + + setLayout(new BorderLayout()); + add(applet, BorderLayout.CENTER); + add(status, BorderLayout.SOUTH); + + addWindowListener(new WindowAdapter() + { + public void windowClosing(WindowEvent event) + { + applet.stop(); + StandaloneAppletWindow.this.hide(); + System.exit(0); + } + }); + + addContainerListener(this); + addComponentListener(this); + addMouseListener(this); + addMouseMotionListener(this); + addInputMethodListener(this); + addHierarchyListener(this); + addHierarchyBoundsListener(this); + + restartItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_restart")); + restartItem.setEnabled(false); + restartItem.addActionListener(this); + reloadItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_reload")); + reloadItem.setEnabled(false); + reloadItem.addActionListener(this); + cancelItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_cancel")); + cancelItem.setEnabled(false); + cancelItem.addActionListener(this); + saveItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_save")); + saveItem.setEnabled(false); + saveItem.addActionListener(this); + startItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_start")); + startItem.setEnabled(false); + startItem.addActionListener(this); + cloneItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_clone")); + cloneItem.setEnabled(false); + cloneItem.addActionListener(this); + closeItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_close")); + closeItem.setEnabled(false); + closeItem.addActionListener(this); + tagItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_tag")); + tagItem.setEnabled(false); + tagItem.addActionListener(this); + infoItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_info")); + infoItem.setEnabled(false); + infoItem.addActionListener(this); + editItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_edit")); + editItem.setEnabled(false); + editItem.addActionListener(this); + editItem.setEnabled(false); + encodingItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_encoding")); + encodingItem.setEnabled(false); + encodingItem.addActionListener(this); + printItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_print")); + printItem.setEnabled(false); + printItem.addActionListener(this); + propertiesItem = + new MenuItem(Main.messages.getString("gcjwebplugin.menu_properties")); + propertiesItem.setEnabled(false); + propertiesItem.addActionListener(this); + quitItem = new MenuItem(Main.messages.getString("gcjwebplugin.menu_quit")); + quitItem.addActionListener(this); + + MenuBar menuBar = new MenuBar(); + Menu menuApplet = new Menu(Main.messages.getString("gcjwebplugin.menu_title")); + menuBar.add(menuApplet); + menuApplet.add(restartItem); + menuApplet.add(reloadItem); + menuApplet.add(cancelItem); + menuApplet.add(saveItem); + menuApplet.add(startItem); + menuApplet.add(cloneItem); + menuApplet.addSeparator(); + menuApplet.add(tagItem); + menuApplet.add(infoItem); + menuApplet.add(editItem); + menuApplet.add(encodingItem); + menuApplet.addSeparator(); + menuApplet.add(printItem); + menuApplet.addSeparator(); + menuApplet.add(propertiesItem); + menuApplet.addSeparator(); + menuApplet.add(closeItem); + menuApplet.add(quitItem); + setMenuBar(menuBar); + setTitle("GCJ Applet Viewer: " + tag.code); + + AppletContext context = (AppletContext) contexts.get(tag.codebase); + ((StandaloneAppletContext) context).addApplet(applet); + + applet.setStub(new CommonAppletStub(tag, context, applet)); + + // Create the frame's peer. Otherwise getPreferredSize will read + // its insets as 0. + addNotify(); + Insets i = getInsets(); + Dimension size = tag.getSize(); + setSize(i.left + size.width + i.right, + i.top + size.height + status.getPreferredSize().height + + i.bottom); + applet.setSize(size); + + // Initialize the applet before showing this window so that the + // applet doesn't receive events before it has been initialized. + applet.init(); + applet.start(); + setVisible(true); + } + + private void closeWindow() + { + applet.stop(); + StandaloneAppletViewer.appletWindows.remove(this); + StandaloneAppletWindow.this.hide(); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == quitItem) + { + closeWindow(); + System.exit(0); + } + else if (e.getSource() == closeItem) + { + // Close current window. + closeWindow(); + + // Exit if there are other windows left. + if (StandaloneAppletViewer.appletWindows.isEmpty()) + System.exit(0); + } + } + + void showStatus(String status) + { + this.status.setText(status); + } + + + /////////////////////////////////// + /// ContainerListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when a component is added to the container. + * + * @param event the ContainerEvent indicating component + * addition + */ + public void componentAdded(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentAdded(event); + } + } + + /** + * This method is called when a component is removed from the container. + * + * @param event the ContainerEvent indicating component removal + */ + public void componentRemoved(ContainerEvent event) + { + if (applet != null) + { + ContainerListener[] l = applet.getContainerListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentRemoved(event); + } + } + + /////////////////////////////////// + /// ComponentListener Methods ///// + /////////////////////////////////// + + /** + * This method is called when the component is resized. + * + * @param event the ComponentEvent indicating the resize + */ + public void componentResized(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentResized(event); + } + } + + /** + * This method is called when the component is moved. + * + * @param event the ComponentEvent indicating the move + */ + public void componentMoved(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentMoved(event); + } + } + + /** + * This method is called when the component is made visible. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentShown(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentShown(event); + } + } + + /** + * This method is called when the component is hidden. + * + * @param event the ComponentEvent indicating the visibility + */ + public void componentHidden(ComponentEvent event) + { + if (applet != null) + { + ComponentListener[] l = applet.getComponentListeners(); + for (int i = 0; i < l.length; i++) + l[i].componentHidden(event); + } + } + + /////////////////////////////////// + ////// MouseListener Methods ////// + /////////////////////////////////// + + /** + * This method is called when the mouse is clicked (pressed and released + * in short succession) on a component. + * + * @param event the MouseEvent indicating the click + */ + public void mouseClicked(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseClicked(event); + } + } + + /** + * This method is called when the mouse is pressed over a component. + * + * @param event the MouseEvent for the press + */ + public void mousePressed(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mousePressed(event); + } + } + + /** + * This method is called when the mouse is released over a component. + * + * @param event the MouseEvent for the release + */ + public void mouseReleased(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseReleased(event); + } + } + + /** + * This method is called when the mouse enters a component. + * + * @param event the MouseEvent for the entry + */ + public void mouseEntered(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseEntered(event); + } + } + + /** + * This method is called when the mouse exits a component. + * + * @param event the MouseEvent for the exit + */ + public void mouseExited(MouseEvent event) + { + if (applet != null) + { + MouseListener[] l = applet.getMouseListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseExited(event); + } + } + + /////////////////////////////////// + /// MouseMotionListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the mouse is moved over a component + * while a button has been pressed. + * + * @param event the MouseEvent indicating the motion + */ + public void mouseDragged(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseDragged(event); + } + } + + /** + * This method is called when the mouse is moved over a component + * while no button is pressed. + * + * @param event the MouseEvent indicating the motion + */ + public void mouseMoved(MouseEvent event) + { + if (applet != null) + { + MouseMotionListener[] l = applet.getMouseMotionListeners(); + for (int i = 0; i < l.length; i++) + l[i].mouseMoved(event); + } + } + + /////////////////////////////////// + /// InputMethodListener Methods /// + /////////////////////////////////// + + /** + * This method is called when the text is changed. + * + * @param event the InputMethodEvent indicating the text change + */ + public void inputMethodTextChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].inputMethodTextChanged(event); + } + } + + /** + * This method is called when the cursor position within the text is changed. + * + * @param event the InputMethodEvent indicating the change + */ + public void caretPositionChanged(InputMethodEvent event) + { + if (applet != null) + { + InputMethodListener[] l = applet.getInputMethodListeners(); + for (int i = 0; i < l.length; i++) + l[i].caretPositionChanged(event); + } + } + + /////////////////////////////////// + //// HierarchyListener Methods //// + /////////////////////////////////// + + /** + * Called when the hierarchy of this component changes. Use + * getChangeFlags() on the event to see what exactly changed. + * + * @param e the event describing the change + */ + public void hierarchyChanged(HierarchyEvent event) + { + if (applet != null) + { + HierarchyListener[] l = applet.getHierarchyListeners(); + for (int i = 0; i < l.length; i++) + l[i].hierarchyChanged(event); + } + } + + ///////////////////////////////////////// + //// HierarchyBoundsListener Methods //// + ///////////////////////////////////////// + + /** + * Called when an ancestor component of the source is moved. + * + * @param e the event describing the ancestor's motion + */ + public void ancestorMoved(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorMoved(e); + } + } + + /** + * Called when an ancestor component is resized. + * + * @param e the event describing the ancestor's resizing + */ + public void ancestorResized(HierarchyEvent e) + { + if (applet != null) + { + HierarchyBoundsListener[] l = applet.getHierarchyBoundsListeners(); + for (int i = 0; i < l.length; i++) + l[i].ancestorResized(e); + } + } +} diff --git a/tools/gnu/classpath/tools/appletviewer/TagParser.java b/tools/gnu/classpath/tools/appletviewer/TagParser.java new file mode 100644 index 000000000..68dce97e0 --- /dev/null +++ b/tools/gnu/classpath/tools/appletviewer/TagParser.java @@ -0,0 +1,302 @@ +/* TagParser.java -- a parser for applet tags + 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.appletviewer; + +import gnu.javax.swing.text.html.parser.HTML_401F; + +import gnu.xml.dom.DomNode; +import gnu.xml.dom.html2.DomHTMLAppletElement; +import gnu.xml.dom.html2.DomHTMLDocument; +import gnu.xml.dom.html2.DomHTMLEmbedElement; +import gnu.xml.dom.html2.DomHTMLObjectElement; +import gnu.xml.dom.html2.DomHTMLParamElement; +import gnu.xml.dom.html2.DomHTMLParser; + +import java.io.File; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.util.ArrayList; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.w3c.dom.NodeList; + + +public class TagParser +{ + + /** + * Parsed document. + */ + DomHTMLDocument document; + + /** + * The document base of this applet. + */ + URL documentbase; + + /** + * The document base of all the applets. + */ + static URL db; + + /** + * The tags in the document. + */ + Vector tags = new Vector(); + + /** + * Default constructor. + */ + TagParser() + { + // Do nothing. + } + + /** + * Constructs and parses document using the given location. + * + * @param location - location of applet + */ + TagParser(String location) throws IOException + { + documentbase = getLocationToURL(location); + db = documentbase; + InputStreamReader in = new InputStreamReader(documentbase.openStream()); + document = (DomHTMLDocument) (new DomHTMLParser(HTML_401F.getInstance()).parseDocument(in)); + } + + /** + * Constructs and parses document. + * + * @param in - Reader to parse document from. + * @param documentBase - the URL of the applet + * @throws IOException - is thrown if any IO error occurs. + */ + TagParser(Reader in, URL documentBase) throws IOException + { + documentbase = documentBase; + db = documentbase; + document = (DomHTMLDocument) (new DomHTMLParser(HTML_401F.getInstance()).parseDocument(in)); + } + + /** + * Parses all applet tags in document. + * + * @return a list of AppletTag objects representing the applet tags + * in document + */ + ArrayList parseAppletTags() + { + ArrayList allTags = new ArrayList(); + if (document == null) + return null;; + + recurseDocument(document.getChildNodes()); + + int sz = tags.size(); + for (int j = 0; j < sz; j++) + { + Object curr = tags.get(j); + // Order of checking is important here. + // Must check embed element before applet element + // because DomHTMLEmbedElement extends DomHTMLAppletElement + AppletTag a = null; + if (curr instanceof DomHTMLEmbedElement) + a = new AppletTag((DomHTMLEmbedElement) curr); + else if (curr instanceof DomHTMLAppletElement) + a = new AppletTag((DomHTMLAppletElement) curr); + else if (curr instanceof DomHTMLObjectElement) + a = new AppletTag((DomHTMLObjectElement) curr); + a.documentbase = documentbase; + allTags.add(a); + } + + return allTags; + } + + /** + * Recurses the document in search for the appropriate tags. + * + * @param list - the Node list. + */ + private void recurseDocument(NodeList list) + { + // Recurse and store all APPLET, OBJECT and EMBED tags. + int length = list.getLength(); + for (int i = 0; i < length; i++) + { + DomNode curr = (DomNode) list.item(i); + if ((curr instanceof DomHTMLEmbedElement) || + (curr instanceof DomHTMLAppletElement) || + (curr instanceof DomHTMLObjectElement)) + tags.add(curr); + recurseDocument(curr.getChildNodes()); + } + } + + /** + * Parses the param elements for a given node. + * + * @param node - the node element to parse. + */ + static void parseParams(DomNode node, AppletTag t) + { + boolean ja = false; + boolean jb = false; + boolean jc = false; + NodeList l = node.getChildNodes(); + int size = l.getLength(); + + if (size != 0) + for (int i = 0; i < size; i++) + { + Object c = l.item(i); + if (! (c instanceof DomHTMLParamElement)) + continue; + DomHTMLParamElement curr = (DomHTMLParamElement) c; + String key = curr.getName(); + String val = curr.getValue(); + + if (key.equals("java_code")) + { + jc = true; + t.code = val; + } + else if (key.equals("java_codebase")) + { + jb = true; + t.codebase = val; + } + else if (!jc && key.equals("code")) + t.code = val; + else if (!jc && key.equals("classid")) + { + int x = val.indexOf(":"); + if (x != -1) + val = val.substring(x + 1); + t.code = val; + } + else if (!jb && key.equals("codebase")) + t.codebase = val; + else if (key.equals("java_archive")) + { + ja = true; + t.archives = parseArchives(val, t); + val = t.archives.toString(); + } + else if (!ja && key.equals("archive")) + { + t.archives = parseArchives(val, t); + val = t.archives.toString(); + } + + t.parameters.put(key.toLowerCase(), val); + } + } + + /** + * Parses the archive string and returns a list. + * + * @param the list of archives (comma-separated) in a String. + */ + static ArrayList parseArchives(String arcs, AppletTag t) + { + try + { + ArrayList list = new ArrayList(); + + StringTokenizer tagTokenizer = new StringTokenizer(arcs, ","); + while (tagTokenizer.hasMoreTokens()) + list.add(t.prependCodeBase(tagTokenizer.nextToken().trim())); + + return list; + } + catch (MalformedURLException e) + { + } + return null; + } + + /** + * Gets the location to the URL, given a location. + * + * @param location - the given location. + * @return the URL. + */ + static URL getLocationToURL(String location) throws IOException + { + URL tmpDocumentBase = null; + + try + { + // Try parsing location as a URL. + tmpDocumentBase = new URL(location); + + // If no file was specified in the URL the assume the user + // meant the root page. + String f = tmpDocumentBase.getFile(); + if (f.indexOf(".") == -1 && !f.endsWith(File.separator)) + if (new File(tmpDocumentBase.getFile()).isDirectory()) + tmpDocumentBase = new URL(location.concat(File.separator)); + } + catch (MalformedURLException e) + { + // location is not a URL. See if it is an HTML file. + String path; + + if (location.startsWith(File.separator)) + path = new File(location).getCanonicalPath(); + else + path = new File(System.getProperty("user.dir") + File.separator + + location).getCanonicalPath(); + + tmpDocumentBase = new URL("file", "", path); + + if (new File(tmpDocumentBase.getFile()).isDirectory()) + tmpDocumentBase = new URL("file", "", path + File.separator); + } + + return tmpDocumentBase; + } +} diff --git a/tools/gnu/classpath/tools/common/CallbackUtil.java b/tools/gnu/classpath/tools/common/CallbackUtil.java new file mode 100644 index 000000000..398bb6cae --- /dev/null +++ b/tools/gnu/classpath/tools/common/CallbackUtil.java @@ -0,0 +1,145 @@ +/* CallbackUtil.java -- Callback related utilities + 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.common; + +import gnu.javax.security.auth.callback.ConsoleCallbackHandler; + +import java.security.Provider; +import java.security.Security; +import java.util.logging.Logger; + +import javax.security.auth.callback.CallbackHandler; + +/** + * A Helper class containing general purpose utlity methods dealing with + * callback handlers and their Security Provider. + */ +public abstract class CallbackUtil +{ + private static final Logger log = Logger.getLogger(CallbackUtil.class.getName()); + + // default 0-arguments constructor + + // Class methods + // -------------------------------------------------------------------------- + + /** + * Return an implementation of the {@link CallbackHandler}, from any + * {@link Provider}, capable of handling callbacks through the console; + * i.e. System.in and System.out. + *

+ * If no Security Provider for this type of callback was found, this + * method returns the default GNU implementation. + * + * @return a console {@link CallbackHandler} implementation. + */ + public static final CallbackHandler getConsoleHandler() + { + CallbackHandler result = getHandler("Console"); + if (result == null) + { + log.fine("No console callback handler found. Will use ours"); + result = new ConsoleCallbackHandler(); + } + return result; + } + + /** + * Return a {@link CallbackHandler}, of a designated type, for interacting + * with the user. + *

+ * 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 returned. + * + * @return a {@link CallbackHandler} of the designated type, or + * null if no provider was found for theis type of + * callback. + */ + private static final CallbackHandler getHandler(String handlerType) + { + log.entering(CallbackUtil.class.getName(), "getHandler", handlerType); + + CallbackHandler result = null; + String service = "CallbackHandler." + handlerType; + Provider[] providers = Security.getProviders(service); + if (providers != null) + for (int i = 0; i < providers.length; i++) + { + Provider p = providers[i]; + String className = p.getProperty(service); + if (className != null) + try + { + result = (CallbackHandler) Class.forName(className.trim()).newInstance(); + } + catch (InstantiationException x) + { + log.fine("InstantiationException while creating [" + + className + "] from provider [" + p.getName() + + "]. Ignore"); + } + catch (IllegalAccessException x) + { + log.fine("IllegalAccessException while creating [" + + className + "] from provider [" + p.getName() + + "]. Ignore"); + } + catch (ClassNotFoundException x) + { + log.fine("ClassNotFoundException while creating [" + + className + "] from provider [" + p.getName() + + "]. Ignore"); + } + + if (result != null) + { + + log.fine("Will use [" + result.getClass().getName() + + "] from [" + p.getName() + "]"); + break; + } + } + + log.exiting(CallbackUtil.class.getName(), "getHandler", result); + return result; + } +} diff --git a/tools/gnu/classpath/tools/common/ProviderUtil.java b/tools/gnu/classpath/tools/common/ProviderUtil.java new file mode 100644 index 000000000..8d0434433 --- /dev/null +++ b/tools/gnu/classpath/tools/common/ProviderUtil.java @@ -0,0 +1,163 @@ +/* ProviderUtil.java -- Security Provider related utilities + 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.common; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; +import java.security.Security; +import java.util.logging.Logger; + +/** + * A Helper class containing general purpose utlity methods dealing with + * installing and removing Security Providers at runtime. + */ +public abstract class ProviderUtil +{ + private static final Logger log = Logger.getLogger(ProviderUtil.class.getName()); + + // default 0-arguments constructor + + // Class methods + // -------------------------------------------------------------------------- + + /** + * Attempt to (a) instantiate, and (b) add a designated {@link Provider} by + * inserting at at the top of the list of Security Providers already + * present at runtime, only if it is not already installed. + *

+ * IMPORTANT: This method overrides the security check usually carried + * out by the security manager when inserting a new {@link Provider}. + * + * @param providerClass a fully qualified, non-null, class name of a + * Security Provider to add if it is not already installed. + * @return an instance of {@link SecurityProviderInfo} referencing the + * {@link Provider} instance created with the designated class name, + * and its position in the underlying JVM runtime. + */ + public static final SecurityProviderInfo addProvider(String providerClass) + { + log.entering(ProviderUtil.class.getName(), "addProvider", providerClass); + + Provider provider = null; + try + { + provider = (Provider) Class.forName(providerClass.trim()).newInstance(); + } + catch (InstantiationException x) + { + log.fine("InstantiationException while creating [" + providerClass + + "]. Ignore"); + } + catch (IllegalAccessException x) + { + log.fine("IllegalAccessException while creating [" + providerClass + + "]. Ignore"); + } + catch (ClassNotFoundException x) + { + log.fine("ClassNotFoundException while creating [" + providerClass + + "]. Ignore"); + } + + int position = provider != null ? addProvider(provider) : -1; + SecurityProviderInfo result = new SecurityProviderInfo(provider, position); + + log.exiting(ProviderUtil.class.getName(), "addProvider", result); + return result; + } + + /** + * Attempt to add the designated {@link Provider} by inserting at at the top + * of the list of Security Providers already present at runtime, only + * if it is not already installed. + *

+ * IMPORTANT: This method overrides the security check usually carried + * out by the security manager when inserting a new {@link Provider}. + * + * @param provider a non-null Security Provider to add if it is not + * already installed. + * @return the new position of the designated provider in the list if it was + * not already present, or -1 if it was already + * installed. + */ + public static final int addProvider(final Provider provider) + { + log.entering(ProviderUtil.class.getName(), "addProvider", provider); + + Integer actualPosition = (Integer) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + int result = Security.insertProviderAt(provider, 1); + return Integer.valueOf(result); + } + }); + + int result = actualPosition.intValue(); + log.fine("Provider [" + provider.getName() + "] installed? " + (result != - 1)); + + log.exiting(ProviderUtil.class.getName(), "addProvider", actualPosition); + return result; + } + + /** + * Remove a designated Security Provider. + *

+ * IMPORTANT: This method overrides the security check usually carried + * out by the security manager when removing a {@link Provider}. + * + * @param providerName the name of the {@link Provider} to remove. + */ + public static final void removeProvider(final String providerName) + { + log.entering(ProviderUtil.class.getName(), "removeProvider", providerName); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + Security.removeProvider(providerName); + return null; + } + }); + + log.exiting(ProviderUtil.class.getName(), "removeProvider"); + } +} diff --git a/tools/gnu/classpath/tools/common/SecurityProviderInfo.java b/tools/gnu/classpath/tools/common/SecurityProviderInfo.java new file mode 100644 index 000000000..e12ee4fe3 --- /dev/null +++ b/tools/gnu/classpath/tools/common/SecurityProviderInfo.java @@ -0,0 +1,99 @@ +/* SecurityProviderInfo.java -- Data Access Object for a security provider + 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.common; + +import java.security.Provider; + +/** + * A Data Access Object (DAO) referenceing a Security Provider and its + * position in the list of installed Security Providers in the underlying + * JVM runtime. + */ +public class SecurityProviderInfo +{ + final private Provider provider; + final private int position; + private transient String str; + + /** + * Constructs an instance of SecurityProviderInfo. + *

+ * Used by {@link ProviderUtil} to indicate the result of adding a provider, + * given its class name. + * + * @param provider the possibly null {@link Provider}. + * @param position the position of provider in the list of + * Security Providers in the underlying JVM runtime. -1 + * if that provider (a) is null, or (b) was not added because it + * was already there. + */ + SecurityProviderInfo(Provider provider, int position) + { + super(); + + this.provider = provider; + this.position = position; + } + + /** @return the possibly null {@link Provider} instance. */ + public Provider getProvider() + { + return this.provider; + } + + /** + * @return the position of the {@link Provider}, or -1 if it + * was not added. + */ + public int getPosition() + { + return this.position; + } + + public String toString() + { + if (str == null) + if (provider == null) + str = "SecurityProviderInfo{null, -1}"; + else + str = "SecurityProviderInfo{" + provider.getName() + ", " + position + "}"; + + return str; + } +} diff --git a/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java b/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java new file mode 100644 index 000000000..be382a7a4 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/ClasspathToolParser.java @@ -0,0 +1,71 @@ +/* ClasspathToolParser.java -- Parser subclass for classpath tools + 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.getopt; + +import gnu.classpath.Configuration; + +/** + * This is like the Parser class, but is specialized for use by + * tools distributed with GNU Classpath. In particular it automatically + * computes the version string using the program's name. + */ +public class ClasspathToolParser + extends Parser +{ + private static String getVersionString(String programName) + { + return (programName + " (GNU Classpath) " + + Configuration.CLASSPATH_VERSION + + "\n\n" + + "Copyright 2006 Free Software Foundation, Inc.\n" + + "This is free software; see the source for copying conditions. There is NO\n" + + "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); + + } + + public ClasspathToolParser(String programName) + { + super(programName, getVersionString(programName)); + } + + public ClasspathToolParser(String programName, boolean longOnly) + { + super(programName, getVersionString(programName), longOnly); + } +} diff --git a/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java b/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java new file mode 100644 index 000000000..0c44745c9 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/FileArgumentCallback.java @@ -0,0 +1,61 @@ +/* FileArgumentCallback.java - handle non-option command line arguments + 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.getopt; + +/** + * This is a callback class which is used when a "file name" is found by the + * command-line parser. A file name is any command-line argument which does not + * start with a dash and which is not the argument of some preceding option. + */ +public abstract class FileArgumentCallback +{ + /** + * Create a new instance. + */ + protected FileArgumentCallback() + { + } + + /** + * This is called when a file argument is seen. + * + * @param fileArgument the file name + */ + public abstract void notifyFile(String fileArgument); +} diff --git a/tools/gnu/classpath/tools/getopt/Option.java b/tools/gnu/classpath/tools/getopt/Option.java new file mode 100644 index 000000000..e54aaa103 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/Option.java @@ -0,0 +1,201 @@ +/* Option.java - represent a command-line option + 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.getopt; + +/** + * This is the base class representing an option. An option can have a short + * form. This is a single character, like '-x'. An option can have a long form, + * like '--verbose'; if the parser is working in "long option only" mode, then a + * long flag has a single dash, like '-verbose'. Both a long and a short form + * may be specified; it is not valid to have neither. A description is mandatory + * for options; this is used to automatically generate '--help' output. + */ +public abstract class Option +{ + private char shortName; + + private String longName; + + private String description; + + private String argumentName; + + /** + * Create a new option with the given short name and description. + * + * @param shortName the short name + * @param description the description + */ + protected Option(char shortName, String description) + { + this.shortName = shortName; + this.description = description; + } + + /** + * Create a new option with the given short name and description. + * + * @param shortName the short name + * @param description the description + * @param argumentName the descriptive name of the argument, if this option + * takes an argument; otherwise null + */ + protected Option(char shortName, String description, String argumentName) + { + this.shortName = shortName; + this.description = description; + this.argumentName = argumentName; + } + + /** + * Create a new option with the given long name and description. The long name + * should be specified without any leading dashes. + * + * @param longName the long name + * @param description the description + */ + protected Option(String longName, String description) + { + this.longName = longName; + this.description = description; + } + + /** + * Create a new option with the given long name and description. The long name + * should be specified without any leading dashes. + * + * @param longName the long name + * @param description the description + * @param argumentName the descriptive name of the argument, if this option + * takes an argument; otherwise null + */ + protected Option(String longName, String description, String argumentName) + { + this.longName = longName; + this.description = description; + this.argumentName = argumentName; + } + + /** + * Create a new option with the given short and long names and description. + * The long name should be specified without any leading dashes. + * + * @param longName the long name + * @param shortName the short name + * @param description the description + */ + protected Option(String longName, char shortName, String description) + { + this.shortName = shortName; + this.longName = longName; + this.description = description; + } + + /** + * Create a new option with the given short and long names and description. + * The long name should be specified without any leading dashes. + * + * @param longName the long name + * @param shortName the short name + * @param description the description + * @param argumentName the descriptive name of the argument, if this option + * takes an argument; otherwise null + */ + protected Option(String longName, char shortName, String description, + String argumentName) + { + this.shortName = shortName; + this.longName = longName; + this.argumentName = argumentName; + this.description = description; + } + + /** + * Return the short name of the option, or \0 if none. + */ + public char getShortName() + { + return shortName; + } + + /** + * Return the long name of the option, or null if none. + */ + public String getLongName() + { + return longName; + } + + /** + * Return true if the argument takes an option. + */ + public boolean getTakesArgument() + { + return argumentName != null; + } + + /** + * Return the name of the argument. If the option does not take an argument, + * returns null. + */ + public String getArgumentName() + { + return argumentName; + } + + /** + * Return the description of the option. + */ + public String getDescription() + { + // FIXME: localization. + return description; + } + + /** + * This is called by the parser when this option is recognized. It may be + * called multiple times during a single parse. If this option takes an + * argument, the argument will be passed in. Otherwise the argument will be + * null. + * + * @param argument the argument + * @throws OptionException if the option or its argument is somehow invalid + */ + public abstract void parsed(String argument) throws OptionException; +} diff --git a/tools/gnu/classpath/tools/getopt/OptionException.java b/tools/gnu/classpath/tools/getopt/OptionException.java new file mode 100644 index 000000000..a09d716f4 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/OptionException.java @@ -0,0 +1,52 @@ +/* OptionException.java - when command-line processing fails + 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.getopt; + +/** + * An OptionException is thrown internally when an error is seen when parsing a + * command line. + */ +public class OptionException + extends Exception +{ + public OptionException(String message) + { + super(message); + } +} diff --git a/tools/gnu/classpath/tools/getopt/OptionGroup.java b/tools/gnu/classpath/tools/getopt/OptionGroup.java new file mode 100644 index 000000000..d83b273ba --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/OptionGroup.java @@ -0,0 +1,171 @@ +/* OptionGroup.java - a group of related command-line options + 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.getopt; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * An option group holds a collection of Options. It also has a name. Option + * groups are primarily useful for grouping help output. + */ +public class OptionGroup +{ + private String name; + + ArrayList options = new ArrayList(); + + /** + * Create a new nameless option group. This can only be used by Parser. + */ + OptionGroup() + { + } + + /** + * Create a new option group with the indicated name. + * + * @param name the name + */ + public OptionGroup(String name) + { + this.name = name; + } + + /** + * Add an option to this option group. + * + * @param opt the option to add + */ + public void add(Option opt) + { + options.add(opt); + } + + /** + * Print the help output for this option group. + * + * @param out the stream to which to print + */ + public void printHelp(PrintStream out) + { + // Compute maximum lengths. + int maxArgLen = 0; + int maxShortLen = 0; + Iterator it = options.iterator(); + while (it.hasNext()) + { + Option option = (Option) it.next(); + String argName = option.getArgumentName(); + // First compute the width required for the short + // option. "2" is the initial indentation. In the + // GNU style we don't print an argument name for + // a short option if there is also a long name for + // the option. + int thisArgLen = 2; + if (option.getShortName() != '\0') + { + // The name of the option plus some padding. + thisArgLen += 4; + } + maxShortLen = Math.max(thisArgLen, maxShortLen); + if (option.getLongName() != null) + { + // FIXME: different if parsing in 'long option only' + // mode. + thisArgLen += 2 + option.getLongName().length(); + } + // We only need to add the argument name in once, + // and we don't let it contribute to the width of + // the short name. + if (argName != null) + thisArgLen += 1 + argName.length(); + maxArgLen = Math.max(maxArgLen, thisArgLen); + } + + // Print the help. + if (name != null) + out.println(name + ":"); + it = options.iterator(); + while (it.hasNext()) + { + Option option = (Option) it.next(); + String argName = option.getArgumentName(); + int column = 0; + if (option.getShortName() != '\0') + { + out.print(" -"); + out.print(option.getShortName()); + column += 4; + if (option.getLongName() == null) + { + if (argName != null) + { + out.print(' '); + out.print(argName); + column += 1 + argName.length(); + } + out.print(" "); + } + else + out.print(", "); + column += 2; + } + for (; column < maxShortLen; ++column) + out.print(' '); + if (option.getLongName() != null) + { + out.print("--"); + out.print(option.getLongName()); + column += 2 + option.getLongName().length(); + if (argName != null) + { + out.print("=" + argName); + column += 1 + argName.length(); + } + } + for (; column < maxArgLen; ++column) + out.print(' '); + // FIXME: should have a better heuristic for padding. + out.print(" "); + out.println(option.getDescription()); + } + } +} diff --git a/tools/gnu/classpath/tools/getopt/Parser.java b/tools/gnu/classpath/tools/getopt/Parser.java new file mode 100644 index 000000000..8d70c01d0 --- /dev/null +++ b/tools/gnu/classpath/tools/getopt/Parser.java @@ -0,0 +1,314 @@ +/* Parser.java - parse command line options + 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.getopt; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * An instance of this class is used to parse command-line options. It does "GNU + * style" argument recognition and also automatically handles "--help" and + * "--version" processing. It can also be put in "long option only" mode. In + * this mode long options are recognized with a single dash (as well as a double + * dash) and strings of options like "-abc" are never parsed as a collection of + * short options. + */ +public class Parser +{ + private String programName; + + private String headerText; + + private String footerText; + + private boolean longOnly; + + private ArrayList options = new ArrayList(); + + private ArrayList optionGroups = new ArrayList(); + + private OptionGroup defaultGroup = new OptionGroup(); + + // These are used while parsing. + private int currentIndex; + + private String[] args; + + /** + * Create a new parser. The program name is used when printing error messages. + * The version string is printed verbatim in response to "--version". + * + * @param programName the name of the program + * @param versionString the program's version information + */ + public Parser(String programName, String versionString) + { + this(programName, versionString, false); + } + + /** + * Create a new parser. The program name is used when printing error messages. + * The version string is printed verbatim in response to "--version". + * + * @param programName the name of the program + * @param versionString the program's version information + * @param longOnly true if the parser should work in long-option-only mode + */ + public Parser(String programName, final String versionString, boolean longOnly) + { + this.programName = programName; + this.longOnly = longOnly; + defaultGroup.add(new Option("help", "print this help, then exit") + { + public void parsed(String argument) throws OptionException + { + printHelp(System.out); + System.exit(0); + } + }); + defaultGroup.add(new Option("version", "print version number, then exit") + { + public void parsed(String argument) throws OptionException + { + System.out.println(versionString); + System.exit(0); + } + }); + add(defaultGroup); + } + + /** + * Set the header text that is printed by --help. + * + * @param headerText the header text + */ + public void setHeader(String headerText) + { + this.headerText = headerText; + } + + /** + * Set the footer text that is printed by --help. + * + * @param footerText the footer text + */ + public void setFooter(String footerText) + { + this.footerText = footerText; + } + + /** + * Add an option to this parser. The option is added to the default option + * group; this affects where it is placed in the help output. + * + * @param opt the option + */ + public synchronized void add(Option opt) + { + options.add(opt); + defaultGroup.add(opt); + } + + /** + * Add an option group to this parser. All the options in this group will be + * recognized by the parser. + * + * @param group the option group + */ + public synchronized void add(OptionGroup group) + { + options.addAll(group.options); + optionGroups.add(group); + } + + void printHelp(PrintStream out) + { + if (headerText != null) + { + out.println(headerText); + out.println(); + } + + Iterator it = optionGroups.iterator(); + while (it.hasNext()) + { + OptionGroup group = (OptionGroup) it.next(); + group.printHelp(out); + out.println(); + } + + if (footerText != null) + out.println(footerText); + } + + private String getArgument(String request) throws OptionException + { + ++currentIndex; + if (currentIndex >= args.length) + throw new OptionException("option '" + request + "' requires an argument"); + return args[currentIndex]; + } + + private void handleLongOption(String real, int index) throws OptionException + { + String option = real.substring(index); + String justName = option; + int eq = option.indexOf('='); + if (eq != - 1) + justName = option.substring(0, eq); + Option found = null; + for (int i = options.size() - 1; i >= 0; --i) + { + Option opt = (Option) options.get(i); + if (justName.equals(opt.getLongName())) + { + found = opt; + break; + } + } + if (found == null) + throw new OptionException("unrecognized option '" + real + "'"); + String argument = null; + if (found.getTakesArgument()) + { + if (eq == - 1) + argument = getArgument(real); + else + argument = option.substring(eq + 1); + } + else if (eq != - 1) + { + throw new OptionException("option '" + real.substring(0, eq + index) + + "' doesn't allow an argument"); + } + found.parsed(argument); + } + + private void handleShortOption(char option) throws OptionException + { + Option found = null; + for (int i = options.size() - 1; i >= 0; --i) + { + Option opt = (Option) options.get(i); + if (option == opt.getShortName()) + { + found = opt; + break; + } + } + if (found == null) + throw new OptionException("unrecognized option '-" + option + "'"); + String argument = null; + if (found.getTakesArgument()) + argument = getArgument("-" + option); + found.parsed(argument); + } + + private void handleShortOptions(String option) throws OptionException + { + for (int i = 1; i < option.length(); ++i) + { + handleShortOption(option.charAt(i)); + } + } + + /** + * Parse a command line. Any files which are found will be passed to the file + * argument callback. This method will exit on error or when --help or + * --version is specified. + * + * @param inArgs the command-line arguments + * @param files the file argument callback + */ + public synchronized void parse(String[] inArgs, FileArgumentCallback files) + { + try + { + args = inArgs; + for (currentIndex = 0; currentIndex < args.length; ++currentIndex) + { + if (args[currentIndex].length() == 0 + || args[currentIndex].charAt(0) != '-' + || "-".equals(args[currentIndex])) + { + files.notifyFile(args[currentIndex]); + continue; + } + if ("--".equals(args[currentIndex])) + break; + if (args[currentIndex].charAt(1) == '-') + handleLongOption(args[currentIndex], 2); + else if (longOnly) + handleLongOption(args[currentIndex], 1); + else + handleShortOptions(args[currentIndex]); + } + // Add remaining arguments to leftovers. + for (++currentIndex; currentIndex < args.length; ++currentIndex) + files.notifyFile(args[currentIndex]); + } + catch (OptionException err) + { + System.err.println(programName + ": " + err.getMessage()); + System.err.println(programName + ": Try '" + programName + + " --help' for more information."); + System.exit(1); + } + } + + /** + * Parse a command line. Any files which are found will be returned. This + * method will exit on error or when --help or --version is specified. + * + * @param inArgs the command-line arguments + */ + public String[] parse(String[] inArgs) + { + final ArrayList fileResult = new ArrayList(); + parse(inArgs, new FileArgumentCallback() + { + public void notifyFile(String fileArgument) + { + fileResult.add(fileArgument); + } + }); + return (String[]) fileResult.toArray(new String[0]); + } +} diff --git a/tools/gnu/classpath/tools/giop/GRMIC.java b/tools/gnu/classpath/tools/giop/GRMIC.java index 16ff96f56..a372cfd66 100644 --- a/tools/gnu/classpath/tools/giop/GRMIC.java +++ b/tools/gnu/classpath/tools/giop/GRMIC.java @@ -17,23 +17,7 @@ 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.giop; @@ -105,6 +89,10 @@ public class GRMIC verbose = true; compiler.setVerbose(true); } + else if (c.equals("-force")) + { + compiler.setForce(true); + } else if (c.equals("-d")) { int f = i + 1; diff --git a/tools/gnu/classpath/tools/giop/GRMIC.txt b/tools/gnu/classpath/tools/giop/GRMIC.txt index fcde83895..08aaf148f 100644 --- a/tools/gnu/classpath/tools/giop/GRMIC.txt +++ b/tools/gnu/classpath/tools/giop/GRMIC.txt @@ -19,6 +19,9 @@ Usage: grmic -help Print this help text -v Print version -verbose Verbose output + -force Try to generate code even if the input classes seem not + consistent with RMI specification. + and can include one or more non abstract classes that implement Remote and are accessible via current class path. diff --git a/tools/gnu/classpath/tools/giop/IorParser.java b/tools/gnu/classpath/tools/giop/IorParser.java index 7d70c8aca..411b8997d 100644 --- a/tools/gnu/classpath/tools/giop/IorParser.java +++ b/tools/gnu/classpath/tools/giop/IorParser.java @@ -17,23 +17,7 @@ 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.giop; diff --git a/tools/gnu/classpath/tools/giop/grmic/CompilationError.java b/tools/gnu/classpath/tools/giop/grmic/CompilationError.java index c6b3e56e8..d1fa814ee 100644 --- a/tools/gnu/classpath/tools/giop/grmic/CompilationError.java +++ b/tools/gnu/classpath/tools/giop/grmic/CompilationError.java @@ -17,23 +17,7 @@ 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.giop.grmic; diff --git a/tools/gnu/classpath/tools/giop/grmic/Generator.java b/tools/gnu/classpath/tools/giop/grmic/Generator.java index a45e8d398..17ab821ec 100644 --- a/tools/gnu/classpath/tools/giop/grmic/Generator.java +++ b/tools/gnu/classpath/tools/giop/grmic/Generator.java @@ -17,23 +17,7 @@ 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.giop.grmic; diff --git a/tools/gnu/classpath/tools/giop/grmic/GiopIo.java b/tools/gnu/classpath/tools/giop/grmic/GiopIo.java index 3714c4ce4..0e0df7bc5 100644 --- a/tools/gnu/classpath/tools/giop/grmic/GiopIo.java +++ b/tools/gnu/classpath/tools/giop/grmic/GiopIo.java @@ -17,23 +17,7 @@ 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.giop.grmic; diff --git a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java index c19f635c6..4beba1c9f 100644 --- a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java +++ b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java @@ -17,23 +17,7 @@ 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.giop.grmic; @@ -115,6 +99,11 @@ public class GiopRmicCompiler * Verbose output */ protected boolean verbose = false; + + /** + * Force mode - do not check the exceptions + */ + protected boolean force = false; /** * Clear data, preparing for the next compilation. @@ -204,7 +193,7 @@ public class GiopRmicCompiler remEx = true; break; } - if (! remEx) + if (! remEx && !force) throw new CompilationError(m[i].getName() + ", defined in " + c.getName() + ", does not throw " @@ -483,6 +472,14 @@ public class GiopRmicCompiler { warnings = warn; } + + /** + * Set the error ignore mode. + */ + public void setForce(boolean isforce) + { + force = isforce; + } /** * Get the package name. diff --git a/tools/gnu/classpath/tools/giop/grmic/HashFinder.java b/tools/gnu/classpath/tools/giop/grmic/HashFinder.java index 216e73953..2efdb1e76 100644 --- a/tools/gnu/classpath/tools/giop/grmic/HashFinder.java +++ b/tools/gnu/classpath/tools/giop/grmic/HashFinder.java @@ -1,3 +1,25 @@ +/* HashFinder.java -- finds the hash character. + Copyright (C) 2006 Free Software Foundation + +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. +*/ + + package gnu.classpath.tools.giop.grmic; import java.util.HashSet; diff --git a/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java b/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java index 9a44fad79..80148d51a 100644 --- a/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java +++ b/tools/gnu/classpath/tools/giop/grmic/MethodGenerator.java @@ -17,23 +17,7 @@ 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.giop.grmic; diff --git a/tools/gnu/classpath/tools/jar/Action.java b/tools/gnu/classpath/tools/jar/Action.java new file mode 100644 index 000000000..fea60f797 --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Action.java @@ -0,0 +1,50 @@ +/* Action.java - an action taken by the jar driver + 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.jar; + +import java.io.IOException; + +public abstract class Action +{ + protected Action() + { + } + + public abstract void run(Main parameters) throws IOException; +} diff --git a/tools/gnu/classpath/tools/jar/Creator.java b/tools/gnu/classpath/tools/jar/Creator.java new file mode 100644 index 000000000..a636fca6b --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Creator.java @@ -0,0 +1,192 @@ +/* Creator.java - create a new jar file + 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.jar; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class Creator + extends Action +{ + ZipOutputStream outputStream; + + private long copyFile(CRC32 crc, InputStream is, OutputStream output) + throws IOException + { + byte[] buffer = new byte[1024]; + long size = 0; + while (true) + { + int len = is.read(buffer); + if (len == - 1) + break; + size += len; + output.write(buffer, 0, len); + crc.update(buffer, 0, len); + } + output.close(); + return size; + } + + protected void writeFile(boolean isDirectory, InputStream inputFile, + String filename, boolean verbose) throws IOException + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CRC32 crc = new CRC32(); + long size; + if (isDirectory) + { + size = 0; + } + else + { + size = copyFile(crc, inputFile, out); + } + + ZipEntry entry = new ZipEntry(filename); + entry.setCrc(crc.getValue()); + entry.setSize(size); + + outputStream.putNextEntry(entry); + out.writeTo(outputStream); + outputStream.closeEntry(); + + if (verbose) + { + long csize = entry.getCompressedSize(); + long perc; + if (size == 0) + perc = 0; + else + perc = 100 - (100 * csize) / size; + System.out.println("adding: " + filename + " (in=" + size + ") (out=" + + entry.getSize() + ") (stored " + perc + "%)"); + } + } + + protected void writeFile(File file, String filename, boolean verbose) + throws IOException + { + boolean isDirectory = file.isDirectory(); + InputStream inputStream = null; + if (isDirectory) + { + if (filename.charAt(filename.length() - 1) != '/') + filename += '/'; + } + else + inputStream = new FileInputStream(file); + writeFile(isDirectory, inputStream, filename, verbose); + } + + private void addEntries(ArrayList result, Entry entry) + { + if (entry.file.isDirectory()) + { + String name = entry.name; + if (name.charAt(name.length() - 1) != '/') + { + name += '/'; + entry = new Entry(entry.file, name); + } + result.add(entry); + String[] files = entry.file.list(); + for (int i = 0; i < files.length; ++i) + addEntries(result, new Entry(new File(entry.file, files[i]), + entry.name + '/' + files[i])); + } + else + result.add(entry); + } + + private ArrayList getAllEntries(Main parameters) + { + Iterator it = parameters.entries.iterator(); + ArrayList allEntries = new ArrayList(); + while (it.hasNext()) + { + Entry entry = (Entry) it.next(); + addEntries(allEntries, entry); + } + return allEntries; + } + + protected ArrayList writeCommandLineEntries(Main parameters, File zipFile) + throws IOException + { + outputStream = new ZipOutputStream( + new BufferedOutputStream( + new FileOutputStream( + zipFile))); + outputStream.setMethod(parameters.storageMode); + ArrayList allEntries = getAllEntries(parameters); + Iterator it = parameters.entries.iterator(); + while (it.hasNext()) + { + Entry entry = (Entry) it.next(); + writeFile(entry.file, entry.name, parameters.verbose); + } + return allEntries; + } + + protected void close() throws IOException + { + // FIXME: handle manifest options here. + // FIXME: handle index file here ...? + outputStream.finish(); + outputStream.close(); + } + + public void run(Main parameters) throws IOException + { + writeCommandLineEntries(parameters, parameters.archiveFile); + close(); + } +} diff --git a/tools/gnu/classpath/tools/jar/Entry.java b/tools/gnu/classpath/tools/jar/Entry.java new file mode 100644 index 000000000..aa8679aab --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Entry.java @@ -0,0 +1,60 @@ +/* Entry.java - represent a single file to write to a jar + 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.jar; + +import java.io.File; + +public class Entry +{ + public File file; + + public String name; + + public Entry(File file, String name) + { + this.file = file; + this.name = name; + } + + public Entry(File file) + { + this.file = file; + this.name = file.toString(); + } +} diff --git a/tools/gnu/classpath/tools/jar/Extractor.java b/tools/gnu/classpath/tools/jar/Extractor.java new file mode 100644 index 000000000..245f5e36c --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Extractor.java @@ -0,0 +1,100 @@ +/* Extractor.java - action to extract from a jar file + 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.jar; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class Extractor + extends Action +{ + private void copyFile(InputStream input, File output) throws IOException + { + FileOutputStream os = new FileOutputStream(output); + byte[] buffer = new byte[1024]; + while (true) + { + int len = input.read(buffer); + if (len == - 1) + break; + os.write(buffer, 0, len); + } + os.close(); + } + + public void run(Main parameters) throws IOException + { + ZipFile zip = new ZipFile(parameters.archiveFile); + Enumeration e = zip.entries(); + while (e.hasMoreElements()) + { + ZipEntry entry = (ZipEntry) e.nextElement(); + File file = new File(entry.getName()); + if (entry.isDirectory()) + { + if (file.mkdirs()) + { + if (parameters.verbose) + System.out.println(" created: " + file); + } + continue; + } + + File parent = file.getParentFile(); + if (parent != null) + parent.mkdirs(); + + InputStream input = zip.getInputStream(entry); + copyFile(input, file); + input.close(); + + if (parameters.verbose) + { + String leader = (entry.getMethod() == ZipEntry.STORED ? " extracted" + : " inflated"); + System.out.println(leader + ": " + file); + } + } + } +} diff --git a/tools/gnu/classpath/tools/jar/Lister.java b/tools/gnu/classpath/tools/jar/Lister.java new file mode 100644 index 000000000..fe5792e76 --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Lister.java @@ -0,0 +1,84 @@ +/* Lister.java - action to list contents of a jar file + 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.jar; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Date; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class Lister + extends Action +{ + private void listJar(File jarFile, boolean verbose) throws IOException + { + ZipFile zipFile = new ZipFile(jarFile); + Enumeration i = zipFile.entries(); + MessageFormat format = null; + if (verbose) + format = new MessageFormat(" {0,date,E M dd HH:mm:ss z yyyy} {1}"); + while (i.hasMoreElements()) + { + ZipEntry entry = (ZipEntry) i.nextElement(); + if (verbose) + { + // No easy way to right-justify the size using + // MessageFormat -- how odd. + long size = entry.getSize(); + String s = " " + size; + int index = Math.min(s.length() - 5, 5); + System.out.print(s.substring(index)); + Object[] values = new Object[] { new Date(entry.getTime()), + entry.getName() }; + System.out.println(format.format(values)); + } + else + System.out.println(entry.getName()); + } + zipFile.close(); + } + + public void run(Main parameters) throws IOException + { + listJar(parameters.archiveFile, parameters.verbose); + } +} diff --git a/tools/gnu/classpath/tools/jar/Main.java b/tools/gnu/classpath/tools/jar/Main.java new file mode 100644 index 000000000..ee4da3c27 --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Main.java @@ -0,0 +1,225 @@ +/* Main.java - jar program main() + 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.jar; + +import gnu.classpath.tools.getopt.ClasspathToolParser; +import gnu.classpath.tools.getopt.FileArgumentCallback; +import gnu.classpath.tools.getopt.Option; +import gnu.classpath.tools.getopt.OptionException; +import gnu.classpath.tools.getopt.OptionGroup; +import gnu.classpath.tools.getopt.Parser; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.zip.ZipOutputStream; + +public class Main +{ + // The mode of operation. This is the class representing + // the action; we make a new instance before using it. It + // must be a subclass of Action. 'null' means the mode + // has not yet been set. + Class operationMode; + + // The archive file name. + File archiveFile; + + // The zip storage mode. + int storageMode = ZipOutputStream.DEFLATED; + + // True if we should read file names from stdin. + boolean readNamesFromStdin = false; + + // True for verbose mode. + boolean verbose = false; + + // True if we want a manifest file. + boolean wantManifest = true; + + // Name of manifest file to use. + File manifestFile; + + // A list of Entry objects, each describing a file to write. + ArrayList entries = new ArrayList(); + + // Used only while parsing. + String changedDirectory; + + class HandleFile + extends FileArgumentCallback + { + public void notifyFile(String fileArgument) + { + Entry entry; + if (changedDirectory != null) + { + entry = new Entry(new File(changedDirectory, fileArgument), + fileArgument); + changedDirectory = null; + } + else + entry = new Entry(new File(fileArgument)); + entries.add(entry); + } + } + + // An option that knows how to set the operation mode. + private class ModeOption + extends Option + { + private Class mode; + + public ModeOption(char shortName, String description, Class mode) + { + super(shortName, description); + this.mode = mode; + } + + public void parsed(String argument) throws OptionException + { + if (operationMode != null) + throw new OptionException("operation mode already specified"); + operationMode = mode; + } + } + + private Parser initializeParser() + { + Parser p = new ClasspathToolParser("jar"); + p.setHeader("Usage: jar -ctxu [OPTIONS] jar-file [-C DIR FILE] FILE..."); + + OptionGroup grp = new OptionGroup("Operation mode"); + grp.add(new ModeOption('c', "create a new archive", Creator.class)); + grp.add(new ModeOption('x', "extract from archive", Extractor.class)); + grp.add(new ModeOption('t', "list archive contents", Lister.class)); + grp.add(new ModeOption('u', "update archive", Updater.class)); + p.add(grp); + + grp = new OptionGroup("Operation modifiers"); + grp.add(new Option('f', "specify archive file name", "FILE") + { + public void parsed(String argument) throws OptionException + { + // FIXME: error if already set. + archiveFile = new File(argument); + } + }); + grp.add(new Option('0', "store only; no ZIP compression") + { + public void parsed(String argument) throws OptionException + { + storageMode = ZipOutputStream.STORED; + } + }); + grp.add(new Option('v', "verbose operation") + { + public void parsed(String argument) throws OptionException + { + verbose = true; + } + }); + grp.add(new Option('M', "do not create a manifest file") + { + public void parsed(String argument) throws OptionException + { + wantManifest = false; + } + }); + grp.add(new Option('m', "specify manifest file", "FILE") + { + public void parsed(String argument) throws OptionException + { + manifestFile = new File(argument); + } + }); + // -@ + p.add(grp); + + grp = new OptionGroup("File name selection"); + grp.add(new Option('C', "change to directory before the next file", + "DIR FILE") + { + public void parsed(String argument) throws OptionException + { + changedDirectory = argument; + } + }); + p.add(grp); + // -i - need to parse classes + + return p; + } + + private void run(String[] args) throws OptionException, + InstantiationException, IllegalAccessException, IOException + { + Parser p = initializeParser(); + // Special hack to emulate old tar-style commands. + if (args[0].charAt(0) != '-') + args[0] = '-' + args[0]; + p.parse(args, new HandleFile()); + if (operationMode == null) + throw new OptionException("must specify one of -t, -c, -u, or -x"); + if (changedDirectory != null) + throw new OptionException("-C argument requires both directory and filename"); + Action t = (Action) operationMode.newInstance(); + t.run(this); + } + + public static void main(String[] args) + { + Main jarprogram = new Main(); + try + { + jarprogram.run(args); + } + catch (OptionException arg) + { + System.err.println("jar: " + arg.getMessage()); + System.exit(1); + } + catch (Exception e) + { + System.err.println("jar: internal error:"); + e.printStackTrace(System.err); + System.exit(1); + } + } +} diff --git a/tools/gnu/classpath/tools/jar/Updater.java b/tools/gnu/classpath/tools/jar/Updater.java new file mode 100644 index 000000000..9046b42b0 --- /dev/null +++ b/tools/gnu/classpath/tools/jar/Updater.java @@ -0,0 +1,81 @@ +/* Updater.java - action to update a jar file + 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.jar; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class Updater + extends Creator +{ + public void run(Main parameters) throws IOException + { + // Write all the new entries to a temporary file. + File tmpFile = File.createTempFile("jarcopy", null); + ArrayList newEntries = writeCommandLineEntries(parameters, tmpFile); + HashSet set = new HashSet(); + Iterator it = newEntries.iterator(); + while (it.hasNext()) + { + Entry entry = (Entry) it.next(); + set.add(entry.name); + } + + // Now read the old file and copy extra entries to the new file. + ZipFile zip = new ZipFile(parameters.archiveFile); + Enumeration e = zip.entries(); + while (e.hasMoreElements()) + { + ZipEntry entry = (ZipEntry) e.nextElement(); + if (set.contains(entry.getName())) + continue; + writeFile(entry.isDirectory(), zip.getInputStream(entry), + zip.getName(), parameters.verbose); + } + + close(); + tmpFile.renameTo(parameters.archiveFile); + } +} diff --git a/tools/gnu/classpath/tools/jarsigner/HashUtils.java b/tools/gnu/classpath/tools/jarsigner/HashUtils.java new file mode 100644 index 000000000..2286063f1 --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/HashUtils.java @@ -0,0 +1,122 @@ +/* Utils.java -- Utility methods for JAR file signing/verification + 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.jarsigner; + +import gnu.java.security.hash.Sha160; +import gnu.java.security.util.Base64; +import gnu.java.util.jar.JarUtils; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.logging.Logger; + +/** + * Collection of utility methods used in JAR file signing and verification. + */ +class HashUtils +{ + private static final Logger log = Logger.getLogger(HashUtils.class.getName()); + private Sha160 sha = new Sha160(); + + // default 0-arguments constructor + + /** + * @param stream the input stream to digest. + * @return a base-64 representation of the resulting SHA-1 digest of the + * contents of the designated input stream. + * @throws IOException if an I/O related exception occurs during the process. + */ + String hashStream(InputStream stream) throws IOException + { + BufferedInputStream bis = new BufferedInputStream(stream, 4096); + byte[] buffer = new byte[4096]; + int count = 0; + int n; + while ((n = bis.read(buffer)) != - 1) + if (n > 0) + { + sha.update(buffer, 0, n); + count += n; + } + + byte[] hash = sha.digest(); + log.finest("Hashed " + count + " byte(s)"); + String result = Base64.encode(hash); + return result; + } + + /** + * @param ba the byte array to digest. + * @return a base-64 representation of the resulting SHA-1 digest of the + * contents of the designated buffer. + */ + String hashByteArray(byte[] ba) throws IOException + { + sha.update(ba); + byte[] hash = sha.digest(); + log.finest("Hashed " + ba.length + " byte(s)"); + String result = Base64.encode(hash); + return result; + } + + /** + * @param name the JAR entry name + * @param entryHash the hash of the entry file which appears in the + * manifest. + * @return the base-64 encoded form of the hash of the corresponding Manifest + * JAR entry which will appear in the SF file under the entry with the + * same name. + * @throws UnsupportedEncodingException If UTF-8 character encoding is not + * supported on this platform. + */ + String hashManifestEntry(String name, String entryHash) + throws UnsupportedEncodingException + { + sha.update((JarUtils.NAME + ": " + name).getBytes("UTF-8")); + sha.update(JarUtils.CRLF); + sha.update((Main.DIGEST + ": " + entryHash).getBytes("UTF-8")); + sha.update(JarUtils.CRLF); + sha.update(JarUtils.CRLF); + byte[] sfHash = sha.digest(); + String result = Base64.encode(sfHash); + return result; + } +} diff --git a/tools/gnu/classpath/tools/jarsigner/JarSigner.java b/tools/gnu/classpath/tools/jarsigner/JarSigner.java new file mode 100644 index 000000000..40bee9fe9 --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/JarSigner.java @@ -0,0 +1,167 @@ +/* JarSigner.java -- The signing handler of the gjarsigner 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.jarsigner; + +import gnu.classpath.SystemProperties; +import gnu.java.util.jar.JarUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.logging.Logger; + +/** + * The JAR signing handler of the gjarsigner tool. + */ +public class JarSigner +{ + private static final Logger log = Logger.getLogger(JarSigner.class.getName()); + /** The owner tool of this handler. */ + private Main main; + + JarSigner(Main main) + { + super(); + + this.main = main; + } + + void start() throws Exception + { + log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$ + + JarFile jarFile = new JarFile(main.getJarFileName()); + SFHelper sfHelper = new SFHelper(jarFile); + + sfHelper.startSigning(); + + // 1. compute the digests + for (Enumeration e = jarFile.entries(); e.hasMoreElements(); ) + { + JarEntry je = (JarEntry) e.nextElement(); + String jeName = je.getName(); + if (jeName.equals(JarFile.MANIFEST_NAME) + || jeName.endsWith(File.separator)) + continue; + + sfHelper.updateEntry(je); + if (main.isVerbose()) + System.out.println(Messages.getString("JarSigner.1") + jeName); //$NON-NLS-1$ + } + + sfHelper.finishSigning(main.isSectionsOnly()); + if (main.isVerbose()) + System.out.println(Messages.getString("JarSigner.2") + JarFile.MANIFEST_NAME); //$NON-NLS-1$ + + // 2. write jar entries and manifest + File signedJarFile = File.createTempFile("gcp-", ".jar"); //$NON-NLS-1$ //$NON-NLS-2$ + FileOutputStream fos = new FileOutputStream(signedJarFile); + JarOutputStream outSignedJarFile = new JarOutputStream(fos, + sfHelper.getManifest()); + for (Enumeration e = jarFile.entries(); e.hasMoreElements(); ) + { + JarEntry je = (JarEntry) e.nextElement(); + String jeName = je.getName(); + if (jeName.equals(JarFile.MANIFEST_NAME) + || jeName.endsWith(File.separator)) + continue; + + log.finest("Processing " + jeName); //$NON-NLS-1$ + JarEntry newEntry = new JarEntry(jeName); + newEntry.setTime(je.getTime()); + outSignedJarFile.putNextEntry(newEntry); + InputStream jeis = jarFile.getInputStream(je); + copyFromTo(jeis, outSignedJarFile); + } + + // 3. create the .SF file + String signaturesFileName = main.getSigFileName(); + String sfFileName = JarUtils.META_INF + signaturesFileName + + JarUtils.SF_SUFFIX; + log.finest("Processing " + sfFileName); //$NON-NLS-1$ + JarEntry sfEntry = new JarEntry(sfFileName); + sfEntry.setTime(System.currentTimeMillis()); + outSignedJarFile.putNextEntry(sfEntry); + sfHelper.writeSF(outSignedJarFile); + log.finer("Created .SF file"); //$NON-NLS-1$ + if (main.isVerbose()) + System.out.println(Messages.getString("JarSigner.8") + sfFileName); //$NON-NLS-1$ + + // 4. create the .DSA file + String dsaFileName = JarUtils.META_INF + signaturesFileName + + JarUtils.DSA_SUFFIX; + log.finest("Processing " + dsaFileName); //$NON-NLS-1$ + JarEntry dsaEntry = new JarEntry(dsaFileName); + dsaEntry.setTime(System.currentTimeMillis()); + outSignedJarFile.putNextEntry(dsaEntry); + sfHelper.writeDSA(outSignedJarFile, + main.getSignerPrivateKey(), + main.getSignerCertificateChain(), + main.isInternalSF()); + log.finer("Created .DSA file"); //$NON-NLS-1$ + if (main.isVerbose()) + System.out.println(Messages.getString("JarSigner.11") + dsaFileName); //$NON-NLS-1$ + + // cleanup + outSignedJarFile.close(); + fos.close(); + signedJarFile.renameTo(new File(main.getSignedJarFileName())); + log.finer("Renamed signed JAR file"); //$NON-NLS-1$ + if (main.isVerbose()) + System.out.println(SystemProperties.getProperty("line.separator") //$NON-NLS-1$ + + Messages.getString("JarSigner.14")); //$NON-NLS-1$ + + log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$ + } + + private void copyFromTo(InputStream in, JarOutputStream out) + throws IOException + { + byte[] buffer = new byte[8192]; + int n; + while ((n = in.read(buffer)) != -1) + if (n > 0) + out.write(buffer, 0, n); + } +} diff --git a/tools/gnu/classpath/tools/jarsigner/JarVerifier.java b/tools/gnu/classpath/tools/jarsigner/JarVerifier.java new file mode 100644 index 000000000..f80147dfa --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/JarVerifier.java @@ -0,0 +1,339 @@ +/* JarVerifier.java -- The verification handler of the gjarsigner 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.jarsigner; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.pkcs.PKCS7SignedData; +import gnu.java.security.pkcs.SignerInfo; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.ISignatureCodec; +import gnu.java.security.sig.dss.DSSSignature; +import gnu.java.security.sig.dss.DSSSignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5Signature; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; +import gnu.java.security.util.Util; +import gnu.java.util.jar.JarUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.logging.Logger; +import java.util.zip.ZipException; + +/** + * The JAR verification handler of the gjarsigner tool. + */ +public class JarVerifier +{ + private static final Logger log = Logger.getLogger(JarVerifier.class.getName()); + /** The owner tool of this handler. */ + private Main main; + private HashUtils util = new HashUtils(); + /** The JAR file to verify. */ + private JarFile jarFile; + /** Map of jar entry names to their hash. */ + private Map entryHashes = new HashMap(); + + JarVerifier(Main main) + { + super(); + + this.main = main; + } + + void start() throws Exception + { + log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$ + + String jarFileName = main.getJarFileName(); + jarFile = new JarFile(jarFileName); + + // 1. find all signature (.SF) files + List sfFiles = new ArrayList(); + for (Enumeration e = jarFile.entries(); e.hasMoreElements(); ) + { + JarEntry je = (JarEntry) e.nextElement(); + String jeName = je.getName(); + if (! (jeName.startsWith(JarUtils.META_INF) + && jeName.endsWith(JarUtils.SF_SUFFIX))) + continue; + + // only interested in .SF files in, and not deeper than, META-INF + String[] jeNameParts = jeName.split("/"); //$NON-NLS-1$ + if (jeNameParts.length != 2) + continue; + + String sfName = jeNameParts[1]; + String sigFileName = sfName.substring(0, sfName.length() - 3); + sfFiles.add(sigFileName); + } + + // 2. verify each one + if (sfFiles.isEmpty()) + System.out.println(Messages.getString("JarVerifier.2")); //$NON-NLS-1$ + else + { + int limit = sfFiles.size(); + int count = 0; + for (Iterator it = sfFiles.iterator(); it.hasNext(); ) + { + String alias = (String) it.next(); + if (verifySF(alias)) + if (verifySFEntries(alias)) + count++; + } + + if (count == 0) + System.out.println(Messages.getString("JarVerifier.3")); //$NON-NLS-1$ + else if (count != limit) + System.out.println(Messages.getFormattedString("JarVerifier.4", //$NON-NLS-1$ + new Integer[] {Integer.valueOf(count), + Integer.valueOf(limit)})); + else + System.out.println(Messages.getFormattedString("JarVerifier.7", //$NON-NLS-1$ + Integer.valueOf(limit))); + } + + log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$ + } + + /** + * @param sigFileName the name of the signature file; i.e. the name to use for + * both the .SF and .DSA files. + * @return true if the designated file-name (usually a key-store + * alias name) has been successfully checked as the signer of the + * corresponding .SF file. Returns false otherwise. + * @throws IOException + * @throws ZipException + * @throws CertificateException + * @throws CRLException + */ + private boolean verifySF(String sigFileName) throws CRLException, + CertificateException, ZipException, IOException + { + log.entering(this.getClass().getName(), "verifySF"); //$NON-NLS-1$ + log.finest("About to verify signature of " + sigFileName + "..."); //$NON-NLS-1$ //$NON-NLS-2$ + + // 1. find the corresponding .DSA file for this .SF file + JarEntry dsaEntry = jarFile.getJarEntry(JarUtils.META_INF + sigFileName + + JarUtils.DSA_SUFFIX); + if (dsaEntry == null) + throw new SecurityException(Messages.getFormattedString("JarVerifier.13", //$NON-NLS-1$ + sigFileName)); + // 2. read the .DSA file contents as a PKCS7 SignedData + InputStream in = jarFile.getInputStream(dsaEntry); + PKCS7SignedData pkcs7SignedData = new PKCS7SignedData(in); + + // 4. get the encrypted digest octet string from the first SignerInfo + // this octet string is the digital signature of the .SF file contents + Set signerInfos = pkcs7SignedData.getSignerInfos(); + if (signerInfos == null || signerInfos.isEmpty()) + throw new SecurityException(Messages.getString("JarVerifier.14")); //$NON-NLS-1$ + + SignerInfo signerInfo = (SignerInfo) signerInfos.iterator().next(); + byte[] encryptedDigest = signerInfo.getEncryptedDigest(); + if (encryptedDigest == null) + throw new SecurityException(Messages.getString("JarVerifier.16")); //$NON-NLS-1$ + + log.finest("\n" + Util.dumpString(encryptedDigest, "--- signedSFBytes ")); //$NON-NLS-1$ //$NON-NLS-2$ + + // 5. get the signer public key + Certificate cert = pkcs7SignedData.getCertificates()[0]; + PublicKey verifierKey = cert.getPublicKey(); + log.finest("--- verifier public key = " + verifierKey); //$NON-NLS-1$ + + // 6. verify the signature file signature + OID digestEncryptionAlgorithmOID = signerInfo.getDigestEncryptionAlgorithmId(); + ISignature signatureAlgorithm; + ISignatureCodec signatureCodec; + if (digestEncryptionAlgorithmOID.equals(Main.DSA_SIGNATURE_OID)) + { + signatureAlgorithm = new DSSSignature(); + signatureCodec = new DSSSignatureX509Codec(); + } + else + { + signatureAlgorithm = new RSAPKCS1V1_5Signature(Registry.MD5_HASH); + signatureCodec = new RSAPKCS1V1_5SignatureX509Codec(); + } + + Map signatureAttributes = new HashMap(); + signatureAttributes.put(ISignature.VERIFIER_KEY, verifierKey); + signatureAlgorithm.setupVerify(signatureAttributes); + + Object herSignature = signatureCodec.decodeSignature(encryptedDigest); + + // 7. verify the signature file contents + JarEntry sfEntry = jarFile.getJarEntry(JarUtils.META_INF + sigFileName + + JarUtils.SF_SUFFIX); + in = jarFile.getInputStream(sfEntry); + byte[] buffer = new byte[2048]; + int n; + while ((n = in.read(buffer)) != -1) + if (n > 0) + signatureAlgorithm.update(buffer, 0, n); + + boolean result = signatureAlgorithm.verify(herSignature); + log.finer("Signature block [" + sigFileName + "] is " //$NON-NLS-1$ //$NON-NLS-2$ + + (result ? "" : "NOT ") + "OK"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + log.exiting(this.getClass().getName(), "verifySF", Boolean.valueOf(result)); //$NON-NLS-1$ + return result; + } + + /** + * This method is called after at least one signer (usually a key-store + * alias name) was found to be trusted; i.e. his/her signature + * block in the corresponding .DSA file was successfully + * verified using his/her public key. + *

+ * This method, uses the contents of the corresponding .SF file + * to compute and verify the hashes of the manifest entries in the JAR file. + * + * @param alias the name of the signature file; i.e. the name to use for both + * the .SF and .DSA files. + * @return true if all the entries in the corresponding + * .SF file have the same hash values as their + * alter-ego in the manifest file of the JAR file inquestion. + * @throws IOException if an I/O related exception occurs during the process. + */ + private boolean verifySFEntries(String alias) throws IOException + { + log.entering(this.getClass().getName(), "verifySFEntries"); //$NON-NLS-1$ + + // 1. read the signature file + JarEntry jarEntry = jarFile.getJarEntry(JarUtils.META_INF + alias + + JarUtils.SF_SUFFIX); + InputStream in = jarFile.getInputStream(jarEntry); + Attributes attr = new Attributes(); + Map entries = new HashMap(); + JarUtils.readSFManifest(attr, entries, in); + + // 2. The .SF file by default includes a header containing a hash of the + // entire manifest file. When the header is present, then the verification + // can check to see whether or not the hash in the header indeed matches + // the hash of the manifest file. + boolean result = false; + String hash = attr.getValue(Main.DIGEST_MANIFEST_ATTR); + if (hash != null) + result = verifyManifest(hash); + + // A verification is still considered successful if none of the files that + // were in the JAR file when the signature was generated have been changed + // since then, which is the case if the hashes in the non-header sections + // of the .SF file equal the hashes of the corresponding sections in the + // manifest file. + // + // 3. Read each file in the JAR file that has an entry in the .SF file. + // While reading, compute the file's digest, and then compare the result + // with the digest for this file in the manifest section. The digests + // should be the same, or verification fails. + if (! result) + for (Iterator it = entries.keySet().iterator(); it.hasNext();) + { + Entry me = (Entry) it.next(); + String name = (String) me.getKey(); + attr = (Attributes) me.getValue(); + hash = attr.getValue(Main.DIGEST_ATTR); + result = verifySFEntry(name, hash); + if (! result) + break; + } + + log.exiting(this.getClass().getName(), "verifySFEntries", + Boolean.valueOf(result)); //$NON-NLS-1$ + return result; + } + + /** + * @param hash Base-64 encoded form of the manifest's digest. + * @return true if our computation of the manifest's hash + * matches the given value; false otherwise. + * @throws IOException if unable to acquire the JAR's manifest entry. + */ + private boolean verifyManifest(String hash) throws IOException + { + return verifySFEntry(JarFile.MANIFEST_NAME, hash); + } + + /** + * @param name the name of a JAR entry to verify. + * @param hash Base-64 encoded form of the designated entry's digest. + * @return true if our computation of the JAR entry's hash + * matches the given value; false otherwise. + * @throws IOException if an exception occurs while returning the entry's + * input stream. + */ + private boolean verifySFEntry(String name, String hash) throws IOException + { + String expectedValue = getEntryHash(JarFile.MANIFEST_NAME); + boolean result = expectedValue.equalsIgnoreCase(hash); + log.finest("Is " + name + " OK? " + result); //$NON-NLS-1$ //$NON-NLS-2$ + return result; + } + + private String getEntryHash(String entryName) throws IOException + { + String result = (String) entryHashes.get(entryName); + if (result == null) + { + JarEntry manifest = jarFile.getJarEntry(entryName); + InputStream in = jarFile.getInputStream(manifest); + result = util.hashStream(in); + entryHashes.put(entryName, result); + } + + return result; + } +} diff --git a/tools/gnu/classpath/tools/jarsigner/Main.java b/tools/gnu/classpath/tools/jarsigner/Main.java new file mode 100644 index 000000000..f460a96cc --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/Main.java @@ -0,0 +1,567 @@ +/* Main.java -- JAR signing and verification tool not unlike jarsigner + 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.jarsigner; + +import gnu.classpath.SystemProperties; +import gnu.classpath.tools.HelpPrinter; +import gnu.classpath.tools.common.CallbackUtil; +import gnu.classpath.tools.common.ProviderUtil; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.javax.security.auth.callback.ConsoleCallbackHandler; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Locale; +import java.util.jar.Attributes.Name; +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.UnsupportedCallbackException; + +/** + * The GNU Classpath implementation of the jarsigner tool. + *

+ * The jarsigner tool is used to sign and verify JAR (Java ARchive) + * files. + *

+ * 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()); + private static final String HELP_PATH = "jarsigner/jarsigner.txt"; //$NON-NLS-1$ + private static final Locale EN_US_LOCALE = new Locale("en", "US"); //$NON-NLS-1$ //$NON-NLS-2$ + static final String DIGEST = "SHA1-Digest"; //$NON-NLS-1$ + static final String DIGEST_MANIFEST = "SHA1-Digest-Manifest"; //$NON-NLS-1$ + static final Name DIGEST_ATTR = new Name(DIGEST); + static final Name DIGEST_MANIFEST_ATTR = new Name(DIGEST_MANIFEST); + static final OID DSA_SIGNATURE_OID = new OID(Registry.DSA_OID_STRING); + static final OID RSA_SIGNATURE_OID = new OID(Registry.RSA_OID_STRING); + + private boolean verify; + private String ksURL; + private String ksType; + private String password; + private String ksPassword; + private String sigFileName; + private String signedJarFileName; + private boolean verbose; + private boolean certs; + private boolean internalSF; + private boolean sectionsOnly; + private String providerClassName; + private String jarFileName; + private String alias; + + protected Provider provider; + private boolean providerInstalled; + private char[] ksPasswordChars; + private KeyStore store; + private char[] passwordChars; + private PrivateKey signerPrivateKey; + private Certificate[] signerCertificateChain; + /** The callback handler to use when needing to interact with user. */ + private CallbackHandler handler; + + 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.processArgs(args); + tool.start(); + } + catch (SecurityException x) + { + log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$ + System.err.println(Messages.getString("Main.7") + x.getMessage()); //$NON-NLS-1$ + } + catch (Exception x) + { + log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$ + System.err.println(Messages.getString("Main.9") + x); //$NON-NLS-1$ + } + + tool.teardown(); + + log.exiting(Main.class.getName(), "main"); //$NON-NLS-1$ + // System.exit(0); + } + + // helper methods ----------------------------------------------------------- + + /** + * Read the command line arguments setting the tool's parameters in + * preparation for the user desired action. + * + * @param args an array of options (strings). + * @throws Exception if an exceptio occurs during the process. + */ + private void processArgs(String[] args) throws Exception + { + log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$ + + HelpPrinter.checkHelpKey(args, HELP_PATH); + if (args == null || args.length == 0) + HelpPrinter.printHelpAndExit(HELP_PATH); + + int limit = args.length; + log.finest("args.length=" + limit); //$NON-NLS-1$ + int i = 0; + String opt; + while (i < limit) + { + opt = args[i++]; + log.finest("args[" + (i - 1) + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$ + if (opt == null || opt.length() == 0) + continue; + + if ("-verify".equals(opt)) // -verify //$NON-NLS-1$ + verify = true; + else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$ + ksURL = args[i++]; + else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$ + ksType = args[i++]; + else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$ + ksPassword = args[i++]; + else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$ + password = args[i++]; + else if ("-sigfile".equals(opt)) // -sigfile NAME //$NON-NLS-1$ + sigFileName = args[i++]; + else if ("-signedjar".equals(opt)) // -signedjar FILE_NAME //$NON-NLS-1$ + signedJarFileName = args[i++]; + else if ("-verbose".equals(opt)) // -verbose //$NON-NLS-1$ + verbose = true; + else if ("-certs".equals(opt)) // -certs //$NON-NLS-1$ + certs = true; + else if ("-internalsf".equals(opt)) // -internalsf //$NON-NLS-1$ + internalSF = true; + else if ("-sectionsonly".equals(opt)) // -sectionsonly //$NON-NLS-1$ + sectionsOnly = true; + else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$ + providerClassName = args[i++]; + else + { + jarFileName = opt; + if (! verify) + alias = args[i++]; + + break; + } + } + + if (i < limit) // more options than needed + log.fine("Last argument is assumed at index #" + (i - 1) //$NON-NLS-1$ + + ". Remaining arguments (" + args[i] //$NON-NLS-1$ + + "...) will be ignored"); //$NON-NLS-1$ + + setupCommonParams(); + if (verify) + { + log.finer("Will verify with the following parameters:"); //$NON-NLS-1$ + log.finer(" jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer("Options:"); //$NON-NLS-1$ + log.finer(" provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" verbose ? " + verbose); //$NON-NLS-1$ + log.finer(" certs ? " + certs); //$NON-NLS-1$ + log.finer(" internalsf ? " + internalSF); //$NON-NLS-1$ + log.finer(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$ + } + else // sign + { + setupSigningParams(); + + log.finer("Will sign with the following parameters:"); //$NON-NLS-1$ + log.finer(" jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" alias = '" + alias + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer("Options:"); //$NON-NLS-1$ + log.finer(" keystore = '" + ksURL + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" storetype = '" + ksType + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" storepass = '" + ksPassword + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" keypass = '" + password + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" sigfile = '" + sigFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" signedjar = '" + signedJarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + log.finer(" verbose ? " + verbose); //$NON-NLS-1$ + log.finer(" internalsf ? " + internalSF); //$NON-NLS-1$ + log.finer(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$ + } + + log.exiting(this.getClass().getName(), "processArgs"); //$NON-NLS-1$ + } + + /** + * Invokes the start() method of the concrete handler. + *

+ * Depending on the result of processing the command line arguments, this + * handler may be one for signing the jar, or verifying it. + * + * @throws Exception if an exception occurs during the process. + */ + private void start() throws Exception + { + log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$ + + if (verify) + { + JarVerifier jv = new JarVerifier(this); + jv.start(); + } + else + { + JarSigner js = new JarSigner(this); + js.start(); + } + + log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$ + } + + /** + * Ensures that the underlying JVM is left in the same state as we found it + * when we first launched the tool. Specifically, if we have installed a new + * security provider then now is the time to remove it. + *

+ * Note (rsn): this may not be necessary if we terminate the JVM; i.e. call + * {@link System#exit(int)} at the end of the tool's invocation. Nevertheless + * it's good practive to return the JVM to its initial state. + */ + private void teardown() + { + log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$ + + if (providerInstalled) + ProviderUtil.removeProvider(provider.getName()); + + log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$ + } + + /** + * After processing the command line arguments, this method is invoked to + * process the common parameters which may have been encountered among the + * actual arguments. + *

+ * Common parameters are those which are allowed in both signing and + * verification modes. + * + * @throws InstantiationException if a security provider class name is + * specified but that class name is that of either an interface or + * an abstract class. + * @throws IllegalAccessException if a security provider class name is + * specified but no 0-arguments constructor is defined for that + * class. + * @throws ClassNotFoundException if a security provider class name is + * specified but no such class was found in the classpath. + * @throws IOException if the JAR file name for signing, or verifying, does + * not exist, exists but denotes a directory, or is not readable. + */ + private void setupCommonParams() throws InstantiationException, + IllegalAccessException, ClassNotFoundException, IOException + { + log.entering(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$ + + if (jarFileName == null) + HelpPrinter.printHelpAndExit(HELP_PATH); + + File jar = new File(jarFileName); + if (! jar.exists()) + throw new FileNotFoundException(jarFileName); + + if (jar.isDirectory()) + throw new IOException(Messages.getFormattedString("Main.70", jarFileName)); //$NON-NLS-1$ + + if (! jar.canRead()) + throw new IOException(Messages.getFormattedString("Main.72", jarFileName)); //$NON-NLS-1$ //$NON-NLS-2$ + + if (providerClassName != null && providerClassName.length() > 0) + { + provider = (Provider) Class.forName(providerClassName).newInstance(); + // is it already installed? + String providerName = provider.getName(); + Provider installedProvider = Security.getProvider(providerName); + if (installedProvider != null) + log.finer("Provider " + providerName + " is already installed"); //$NON-NLS-1$ //$NON-NLS-2$ + else // install it + installNewProvider(); + } + + if (! verbose && certs) + { + log.fine("Option is set but is not. Ignored"); //$NON-NLS-1$ + certs = false; + } + + log.exiting(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$ + } + + /** + * Install the user defined security provider in the underlying JVM. + *

+ * Also record this fact so we can remove it when we exit the tool. + */ + private void installNewProvider() + { + log.entering(this.getClass().getName(), "installNewProvider"); //$NON-NLS-1$ + + providerInstalled = ProviderUtil.addProvider(provider) != -1; + + log.exiting(this.getClass().getName(), "installNewProvider"); //$NON-NLS-1$ + } + + /** + * After processing the command line arguments, this method is invoked to + * process the parameters which may have been encountered among the actual + * arguments, and which are specific to the signing action of the tool. + * + * @throws KeyStoreException if no implementation of the designated (or + * default type) of a key store is availabe. + * @throws IOException if an I/O related exception occurs during the process. + * @throws NoSuchAlgorithmException if an implementation of an algorithm used + * by the key store is not available. + * @throws CertificateException if an exception occurs while reading a + * certificate from the key store. + * @throws UnsupportedCallbackException if no implementation of a password + * callback is available. + * @throws UnrecoverableKeyException if the wrong password was used to unlock + * the key store. + * @throws SecurityException if the designated alias is not known to the key + * store or is not an Alias of a Key Entry. + */ + private void setupSigningParams() throws KeyStoreException, IOException, + NoSuchAlgorithmException, CertificateException, + UnsupportedCallbackException, UnrecoverableKeyException + { + log.entering(this.getClass().getName(), "setupSigningParams"); //$NON-NLS-1$ + + if (ksURL == null || ksURL.trim().length() == 0) + { + String userHome = SystemProperties.getProperty("user.home"); //$NON-NLS-1$ + if (userHome == null || userHome.trim().length() == 0) + throw new SecurityException(Messages.getString("Main.85")); //$NON-NLS-1$ + + ksURL = "file:" + userHome.trim() + "/.keystore"; //$NON-NLS-1$ //$NON-NLS-2$ + } + else + { + ksURL = ksURL.trim(); + if (ksURL.indexOf(":") == -1) //$NON-NLS-1$ + ksURL = "file:" + ksURL; //$NON-NLS-1$ + } + + if (ksType == null || ksType.trim().length() == 0) + ksType = KeyStore.getDefaultType(); + else + ksType = ksType.trim(); + + store = KeyStore.getInstance(ksType); + + if (ksPassword == null) + { + // ask the user to provide one + PasswordCallback pcb = new PasswordCallback(Messages.getString("Main.92"), //$NON-NLS-1$ + false); + getCallbackHandler().handle(new Callback[] { pcb }); + ksPasswordChars = pcb.getPassword(); + } + else + ksPasswordChars = ksPassword.toCharArray(); + + URL url = new URL(ksURL); + InputStream stream = url.openStream(); + store.load(stream, ksPasswordChars); + + if (alias == null) + HelpPrinter.printHelpAndExit(HELP_PATH); + + if (! store.containsAlias(alias)) + throw new SecurityException(Messages.getFormattedString("Main.6", alias)); //$NON-NLS-1$ + + if (! store.isKeyEntry(alias)) + throw new SecurityException(Messages.getFormattedString("Main.95", alias)); //$NON-NLS-1$ + + Key key; + if (password == null) + { + passwordChars = ksPasswordChars; + try + { + key = store.getKey(alias, passwordChars); + } + catch (UnrecoverableKeyException x) + { + // ask the user to provide one + String prompt = Messages.getFormattedString("Main.97", alias); //$NON-NLS-1$ + PasswordCallback pcb = new PasswordCallback(prompt, false); + getCallbackHandler().handle(new Callback[] { pcb }); + passwordChars = pcb.getPassword(); + // take 2 + key = store.getKey(alias, passwordChars); + } + } + else + { + passwordChars = password.toCharArray(); + key = store.getKey(alias, passwordChars); + } + + if (! (key instanceof PrivateKey)) + throw new SecurityException(Messages.getFormattedString("Main.99", alias)); //$NON-NLS-1$ + + signerPrivateKey = (PrivateKey) key; + signerCertificateChain = store.getCertificateChain(alias); + log.finest(String.valueOf(signerCertificateChain)); + + if (sigFileName == null) + sigFileName = alias; + + sigFileName = sigFileName.toUpperCase(EN_US_LOCALE); + if (sigFileName.length() > 8) + sigFileName = sigFileName.substring(0, 8); + + char[] chars = sigFileName.toCharArray(); + for (int i = 0; i < chars.length; i++) + { + char c = chars[i]; + if (! (Character.isLetter(c) + || Character.isDigit(c) + || c == '_' + || c == '-')) + chars[i] = '_'; + } + + sigFileName = new String(chars); + + if (signedJarFileName == null) + signedJarFileName = jarFileName; + + log.exiting(this.getClass().getName(), "setupSigningParams"); //$NON-NLS-1$ + } + + boolean isVerbose() + { + return verbose; + } + + boolean isCerts() + { + return certs; + } + + String getSigFileName() + { + return this.sigFileName; + } + + String getJarFileName() + { + return this.jarFileName; + } + + boolean isSectionsOnly() + { + return this.sectionsOnly; + } + + boolean isInternalSF() + { + return this.internalSF; + } + + PrivateKey getSignerPrivateKey() + { + return this.signerPrivateKey; + } + + Certificate[] getSignerCertificateChain() + { + return signerCertificateChain; + } + + String getSignedJarFileName() + { + return this.signedJarFileName; + } + + /** + * Return a CallbackHandler which uses the Console (System.in and System.out) + * for interacting with the user. + *

+ * 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. + *

+ * 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) + handler = CallbackUtil.getConsoleHandler(); + + return handler; + } +} diff --git a/tools/gnu/classpath/tools/jarsigner/Messages.java b/tools/gnu/classpath/tools/jarsigner/Messages.java new file mode 100644 index 000000000..284639115 --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/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.jarsigner; + +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. + *

+ * 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.jarsigner.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/jarsigner/SFHelper.java b/tools/gnu/classpath/tools/jarsigner/SFHelper.java new file mode 100644 index 000000000..b4e5cc193 --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/SFHelper.java @@ -0,0 +1,373 @@ +/* SFHelper -- A .SF file helper + 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.jarsigner; + +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; +import gnu.java.security.pkcs.PKCS7Data; +import gnu.java.security.pkcs.PKCS7SignedData; +import gnu.java.security.pkcs.SignerInfo; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.ISignatureCodec; +import gnu.java.security.sig.dss.DSSSignature; +import gnu.java.security.sig.dss.DSSSignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5Signature; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; +import gnu.java.security.util.Util; +import gnu.java.util.jar.JarUtils; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509CRL; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.RSAPrivateKey; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.logging.Logger; + +import javax.security.auth.x500.X500Principal; +import java.security.cert.X509Certificate; + +/** + * A helper class for the .SF file found in signed jars. + */ +public class SFHelper +{ + // Constants and fields + // -------------------------------------------------------------------------- + + private static final Logger log = Logger.getLogger(SFHelper.class.getName()); + private static final int READY = 0; + private static final int STARTED = 1; + private static final int FINISHED = 2; + private static final int SF_GENERATED = 3; + private static final int DSA_GENERATED = 4; + /** http://asn1.elibel.tm.fr/cgi-bin/oid/display?oid=1.3.14.3.2.26&action=display */ + private static final OID hashAlgorithmIdentifierSHA1 = new OID("1.3.14.3.2.26"); //$NON-NLS-1$ + + private int state; + private JarFile jar; + private Manifest manifest; + private Attributes sfMainAttributes; + private Map sfEntries; + private byte[] sfBytes; + private HashUtils util; + + // Constructor(s) + // -------------------------------------------------------------------------- + + /** + * @param jar the JAR archive the .SF file belongs to. + */ + public SFHelper(JarFile jar) + { + super(); + + this.jar = jar; + this.state = READY; + } + + // Class methods + // -------------------------------------------------------------------------- + + // Instance methods + // -------------------------------------------------------------------------- + + /** + * Writes the contents of the .SF file to the designated JAR + * output stream. Line-endings are platform-independent and consist of the + * 2-codepoint sequence 0x0D and 0x0A. + * + * @param jar the JAR output stream to write a .SF file to. + * @throws IOException if an I/O related exception occurs during the process. + */ + void writeSF(JarOutputStream jar) throws IOException + { + if (this.state != FINISHED) + throw new IllegalStateException(Messages.getString("SFHelper.1")); //$NON-NLS-1$ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + JarUtils.writeSFManifest(sfMainAttributes, sfEntries, baos); + sfBytes = baos.toByteArray(); + log.finest("\n" + Util.dumpString(sfBytes, "+++ sfBytes ")); //$NON-NLS-1$ //$NON-NLS-2$ + jar.write(sfBytes); + jar.flush(); + + this.state = SF_GENERATED; + } + + /** + * The contents of the .DSA file is the DER encoded form of a PKCS#7 + * ContentInfo of the type SignedData. + *

+ * The ContentInfo ASN.1 syntax is as described in the "PKCS#7 Cryptographic + * Message Syntax Standard" (RSA Labs) specifications: + *

+   * ContentInfo ::= SEQUENCE {
+   *   contentType     ContentType,
+   *   content     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+   * }
+   * 
+   * ContentType ::= OBJECT IDENTIFIER
+   * 
+ *

+ * The ContentType is an OID which determines the type of the contents field + * that follows it. For the .DSA file the OID is "1.2.840.113549.1.7.2", while + * the content field is the byte array representing the DER encoded form of a + * SignedData content-type. The ASN.1 syntax of the SignedData type is as + * follows: + *

+   * SignedData ::= SEQUENCE {
+   *   version          Version, -- always 1 for PKCS#7 1.5
+   *   digestAlgorithms DigestAlgorithmIdentifiers,
+   *   contentInfo      ContentInfo,
+   *   certificates [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
+   *   crls         [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+   *   signerInfos      SignerInfos
+   * }
+   * 
+   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+   * 
+   * SignerInfos ::= SET OF SignerInfo
+   * 
+ *

+ * Finally the SignerInfo is a per-signer structure. Its ASN.1 syntax looks + * like so: + *

+   * SignerInfo ::= SEQUENCE {
+   *   version                       Version, -- always 1 for PKCS#7 1.5
+   *   issuerAndSerialNumber         IssuerAndSerialNumber,
+   *   digestAlgorithm               DigestAlgorithmIdentifier,
+   *   authenticatedAttributes   [0] IMPLICIT Attributes OPTIONAL,
+   *   digestEncryptionAlgorithm     DigestEncryptionAlgorithmIdentifier,
+   *   encryptedDigest               EncryptedDigest,
+   *   unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+   * }
+   * 
+   * EncryptedDigest ::= OCTET STRING
+   * 
+ * + * @param jar the JAR output stream to write a .DSA file to. + * @param signerKey the private key to sign with. + * @param certificates the possibly null signer certificate chain. + * @param internalSF if true then include the .SF file contents + * in the signed .DSA file; otherwise don't. + * @throws IOException if an I/O related exception occurs during the process. + * @throws CRLException + * @throws CertificateEncodingException + */ + void writeDSA(JarOutputStream jar, PrivateKey signerKey, + Certificate[] certificates, boolean internalSF) + throws IOException, CertificateEncodingException, CRLException + { + if (this.state != SF_GENERATED) + throw new IllegalStateException(Messages.getString("SFHelper.4")); //$NON-NLS-1$ + + log.finest("+++ signer private key = " + signerKey); //$NON-NLS-1$ + ISignature signatureAlgorithm; + ISignatureCodec signatureCodec; + OID digestEncryptionAlgorithmOID; + if (signerKey instanceof DSAPrivateKey) + { + signatureAlgorithm = new DSSSignature(); + signatureCodec = new DSSSignatureX509Codec(); + digestEncryptionAlgorithmOID = Main.DSA_SIGNATURE_OID; + } + else if (signerKey instanceof RSAPrivateKey) + { + signatureAlgorithm = new RSAPKCS1V1_5Signature(Registry.MD5_HASH); + signatureCodec = new RSAPKCS1V1_5SignatureX509Codec(); + digestEncryptionAlgorithmOID = Main.RSA_SIGNATURE_OID; + } + else + throw new SecurityException(Messages.getString("SFHelper.6")); //$NON-NLS-1$ + + Map signatureAttributes = new HashMap(); + signatureAttributes.put(ISignature.SIGNER_KEY, signerKey); + signatureAlgorithm.setupSign(signatureAttributes); + signatureAlgorithm.update(sfBytes, 0, sfBytes.length); + Object signature = signatureAlgorithm.sign(); + byte[] signedSFBytes = signatureCodec.encodeSignature(signature); + log.finest("\n" + Util.dumpString(signedSFBytes, "+++ signedSFBytes ")); //$NON-NLS-1$ //$NON-NLS-2$ + + Set digestAlgorithms = new HashSet(); + List digestAlgorithm = new ArrayList(2); + DERValue derDigestAlgorithmOID = new DERValue(DER.OBJECT_IDENTIFIER, + hashAlgorithmIdentifierSHA1); + DERValue derDigestAlgorithmParams = new DERValue(DER.NULL, null); + digestAlgorithm.add(derDigestAlgorithmOID); + digestAlgorithm.add(derDigestAlgorithmParams); + DERValue derDigestAlgorithm = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + digestAlgorithm); + digestAlgorithms.add(derDigestAlgorithm); + + // TODO (rsn): test with internalsf == true + PKCS7Data data = internalSF ? new PKCS7Data(sfBytes) : null; + + X509CRL[] crls = null; + + Set signerInfos = new HashSet(); + X509Certificate cert = (X509Certificate) certificates[0]; + X500Principal issuer = cert.getIssuerX500Principal(); + BigInteger serialNumber = cert.getSerialNumber(); + byte[] authenticatedAttributes = null; + byte[] encryptedDigest = signedSFBytes; + byte[] unauthenticatedAttributes = null; + SignerInfo signerInfo = new SignerInfo(issuer, + serialNumber, + hashAlgorithmIdentifierSHA1, + authenticatedAttributes, + digestEncryptionAlgorithmOID, + encryptedDigest, + unauthenticatedAttributes); + signerInfos.add(signerInfo); + + PKCS7SignedData dsaContents = new PKCS7SignedData(digestAlgorithms, + data, + certificates, + crls, + signerInfos); + dsaContents.encode(jar); + + jar.flush(); + this.state = DSA_GENERATED; + } + + Manifest getManifest() + { + return this.manifest; + } + + // own methods -------------------------------------------------------------- + + void startSigning() throws IOException + { + if (this.state != READY) + throw new IllegalStateException(Messages.getString("SFHelper.9")); //$NON-NLS-1$ + + Manifest oldManifest = jar.getManifest(); + this.manifest = oldManifest == null ? new Manifest() + : new Manifest(oldManifest); + this.sfMainAttributes = new Attributes(); + this.sfEntries = new HashMap(); + util = new HashUtils(); + + this.state = STARTED; + } + + /** + * Hashes the designated JAR entry (the file itself); adds the resulting hash + * as an attribute to the manifest, and computes the hash of the added (to + * the Manifest) two headers and add the result as an attribute of the + * corresponding entry in the .SF file. + */ + void updateEntry(JarEntry entry) throws IOException + { + if (this.state != STARTED) + throw new IllegalStateException(Messages.getString("SFHelper.10")); //$NON-NLS-1$ + + String name = entry.getName(); + InputStream jeis = jar.getInputStream(entry); + String hash = util.hashStream(jeis); + log.finer("Hash of " + name + " = " + hash); //$NON-NLS-1$ //$NON-NLS-2$ + + Attributes mainfestAttributes = manifest.getAttributes(name); + if (mainfestAttributes == null) + { + mainfestAttributes = new Attributes(); + manifest.getEntries().put(name, mainfestAttributes); + } + + mainfestAttributes.putValue(Main.DIGEST, hash); + + // hash the newly added 2-header block and add it as an attribute to .SF + + String sfHash = util.hashManifestEntry(name, hash); + Attributes sfAttributes = (Attributes) sfEntries.get(name); + if (sfAttributes == null) + { + sfAttributes = new Attributes(); + sfEntries.put(name, sfAttributes); + } + + sfAttributes.putValue(Main.DIGEST, sfHash); + log.finest("Name: " + name); //$NON-NLS-1$ + log.finest(Main.DIGEST + ": " + sfHash); //$NON-NLS-1$ + log.finest(""); //$NON-NLS-1$ + } + + /** + * @param sectionsOnly whether to compute, in addition to the files, the hash + * of the mainfest itself (false) or not (true). + */ + void finishSigning(boolean sectionsOnly) throws IOException + { + if (state != STARTED) + throw new IllegalStateException(Messages.getString("SFHelper.10")); //$NON-NLS-1$ + + if (sectionsOnly) + return; + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + manifest.write(baos); + baos.flush(); + String manifestHash = util.hashByteArray(baos.toByteArray()); + log.fine("Hashed Manifest " + manifestHash); //$NON-NLS-1$ + sfMainAttributes.putValue(Main.DIGEST_MANIFEST, manifestHash); + + this.state = FINISHED; + } +} diff --git a/tools/gnu/classpath/tools/jarsigner/jarsigner.txt b/tools/gnu/classpath/tools/jarsigner/jarsigner.txt new file mode 100644 index 000000000..e615609c1 --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/jarsigner.txt @@ -0,0 +1,116 @@ +NAME + jarsigner - Java ARchive (JAR) file signing and verification tool + +SYNOPSIS + jarsigner [OPTION]... FILE ALIAS + jarsigner -verify [OPTION]... FILE + +DESCRIPTION + When the first form is used, the tool signs the designated JAR file. + The second form, on the other hand, is used to verify a previously + signed JAR file. + + FILE is the .JAR file to process; i.e. to sign if the first syntax form + is used, or to verify if the second syntax form is used instead. + + ALIAS must be a known Alias of a Key Entry in the designated key store. + The private key material associated with this Alias is then used for + signing the designated .JAR file. + +SIGNING OPTIONS + -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:". + + -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 which will be used to + unlock the key store. If this option is missing, the User will + be prompted to provide a password. + + -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. + + -sigfile NAME + Use this option to designate a literal that will be used to + construct file names for both the .SF and .DSA signature files. + These files will be generated, by the tool, and placed in the + META-INF directory of the signed JAR. Permissible characters + for NAME must be in the range "a-zA-Z0-9_-". All characters + will be converted to upper-case ones. + + If this option is missing, the first eight characters of the + ALIAS argument will be used. When this is the case, any + character in ALIAS that is outside the permissible range of + characters will be replaced by an underscore. + + -signedjar FILE_NAME + Use this option to specify the file name of the signed JAR. If + this option is omitted, then the signed JAR will be named the + same as FILE; i.e. the input JAR file will be replaced with the + signed copy. + +VERIFICATION OPTIONS + -verify + Use this option to indicate that the tool is to be used for + verification purposes. + + -certs This option is used in conjunction with the -verbose option. + When present, along with the -verbose option, the tool will + print more detailed information about the certificates of the + signer(s) being processed. + +COMMON OPTIONS + -verbose + Use this option to force the tool to generate more verbose + messages, during its processing. + + -internalsf + When present, the tool will include --which otherwise it does + not-- the .SF file in the .DSA generated file. + + -sectionsonly + When present, the tool will include in the .SF generated file + --which otherwise it does not-- a header containing a hash of + the whole manifest file. When that header is included, the + tool can quickly check, during verification, if the hash (in + the header) matches or not the manifest 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. + + -help Prints this help text. + +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/jarsigner/package.html b/tools/gnu/classpath/tools/jarsigner/package.html new file mode 100644 index 000000000..50574ddb7 --- /dev/null +++ b/tools/gnu/classpath/tools/jarsigner/package.html @@ -0,0 +1,60 @@ + + + + + + GNU Classpath - gnu.classpath.tools.jarsigner + + + +This package contains the classes that provide an implementation of the +Security Tool: jarsigner. The behaviour of these classes should +match that of the same tool provided in the RI version 1.4.2, except for the +following: + +
    +
  • The RI tool accepts -Jjavaoption options which it then passes to + the underlying JVM. This is because the RI tool acts as a wrapper + around the JVM launcher. +

    + This implementation DOES NOT support these options. +

  • +
+ + 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 -certreq keytool command handler is used to generate a Certificate + * Signing Request (CSR) in PKCS#10 format. + *

+ * The ASN.1 specification of a CSR, as stated in RFC-2986 is as follows: + *

+ *

+ * 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
+ * }
+ * 
+ * IMPORTANT: Some documentation (e.g. RSA examples) claims that the + * attributes field is OPTIONAL while RFC-2986 + * implies the opposite. This implementation considers this field, by default, + * as OPTIONAL, unless the option -attributes is included + * on the command line. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-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
+ * + *
-keypass PASSWORD
+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output. + *

+ * + *
-attributes
+ *
Use this option to force the tool to encode a NULL DER value in the + * CSR as the value of the Attributes field.
+ *
+ */ +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 NULL 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..a59614644 --- /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. + *

+ * 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 startIndex + 1, 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. + *

+ * The general contract of this method is that it is invoked with the + * startIndex argument pointing to the keyword argument that + * uniquelly identifies the command itself; e.g. -genkey or + * -list, 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 args to + * process. + * @return the index of the first unprocessed argument in args. + */ + abstract int processArgs(String[] args, int startIndex); + + /** + * Initialize this concrete command handler for later invocation of the + * {@link #start()} or {@link #doCommand()} methods. + *

+ * 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. + *

+ * The code in this (abstract) class throws a Not implemented yet + * 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 + * null, 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 gkr 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 + * null, then a default value of mykey + * 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 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 null 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 null 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... + *

+ * If the designated algorithm name is null 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 SHA1withDSA, otherwise if it is + * an RSA private key, then the signature algorithm will be + * MD5withRSA. 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 algorithm 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 + * null, a default value of 90 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. + * + *

+   *  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
+   *  }
+   * 
+ * + * @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. + * + *
+   *  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
+   *  }
+   * 
+ * + * IMPORTANT: 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 certificate. + */ + 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 System.out. + * + * @param certificate the certificate to process. + * @throws CertificateEncodingException if an exception occurs while obtaining + * the DER encoded form certificate. + */ + 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. + *

+ * 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. + *

+ * 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) + handler = 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 -delete keytool command handler is used to delete from the key + * store the entry associated with a designated alias. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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. + *

+ * Unlike in other keytool handlers, the default value (mykey) 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..c1c0d4f83 --- /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 -export 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. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-file FILE_NAME
+ *
The fully qualified path of the file where the certificate will be + * exported to. If omitted, STDOUT will be used instead. + *

+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-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.
+ *
+ */ +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 -genkey 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. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 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 KEY_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. + *

+ * + *
-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 this command. If this 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. + *

+ * 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 this option is omitted, the tool will prompt you to enter the + * information through the console. + *

+ * + *
-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
+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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; + +/** + * NOT IMPLEMENTED YET + *

+ * The -identitydb 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. + *

+ * Possible options for this command are: + *

+ *

+ *
-file FILE_NAME
+ *
The fully qualified path of the identity file to import. If this + * option is omitted, the tool will process STDIN. + *

+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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 -import 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. + *

+ * 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. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-file FILE_NAME
+ *
The fully qualified path of the file to read from. If omitted, the + * tool will process STDIN. + *

+ * + *
-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_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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 + * cacerts 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, alias MUST NOT yet exist + * in the key store. + *

+ * 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. + *

+ * If the -trustcacerts 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 JKS named cacerts and usually + * located in ${JAVA_HOME}/lib/security, where + * ${JAVA_HOME} is the root folder location of a Java runtime. + *

+ * 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 STDOUT, and the user is prompted to verify it, + * with the option of aborting the import operation. If however the option + * -noprompt 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. + *

+ * When importing a certificate reply, the reply is validated using trusted + * certificates from the key store, and optionally (if the option + * -trustcacerts was detected on the command line) certificates + * found in the key store, of type JKS named cacerts + * located in ${JAVA_HOME}/lib/security, where + * ${JAVA_HOME} 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. + *

+ * if promptUser is true, 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 promptUser + * parameter is false 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 true if the validation succeeds; or false + * 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 -keyclone 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. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-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_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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 -keypasswd keytool command handler is used to change the password + * protecting the private key associated to a designated alias. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-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_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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 null 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 -list keytool command handler is used to output one or all key + * store entries. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-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.
+ *
+ */ +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 + * v (for verbose) and rfc. + *

+ * If both flags are false, only the fingerprint is generated, + * otherwise, if the v flag is set, then a human readable output + * is generated. If rfc is set, then an RFC-1421 like output + * is generated. + *

Note that both v and rfc cannot both be + * true 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 v (for verbose) and rfc. + *

+ * If both flags are false, only a fingerprint is generated, + * otherwise, if the v flag is set, then a human readable output + * is generated. If rfc is set, then an RFC-1421 like output + * is generated. + *

Note that both v and rfc cannot both be + * true 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. + *

+ * Except for the -identitydb command, available for importing + * JDK 1.1 identities 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. + *

+ * 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 -printcert keytool command handler is used to read a certificate + * from a designated file, and print its contents in a human-readable format. + *

+ * Possible options for this command are: + *

+ *

+ *
-file FILE_NAME
+ *
The fully qualified path of the file to read the certificate from. + * If this option is omitted, the tool will process STDIN. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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 -selfcert keytool command handler is used to generate a self- + * signed X.509 version 1 certificate using key store credentials stored under a + * designated alias. + *

+ * Possible options for this command are: + *

+ *

+ *
-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 shall be used when this option is + * omitted from the command line. + *

+ * + *
-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. + *

+ * 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
+ *      
+ *

+ * + *
-validity DAY_COUNT
+ * + *
-keypass PASSWORD
+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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 -storepasswd keytool command handler is used to change the + * password which protects the integrity of the key store. + *

+ * Possible options for this command are: + *

+ *

+ *
-new PASSWORD
+ *
The new, and different, password which will be used to protect the + * designated key store. + *

+ * + *
-storetype STORE_TYP}
+ *
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 {@link java.security.KeyStore#getDefaultType()} + * static method. + *

+ * + *
-keystore URL
+ *
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 .keystore located in the path returned by the call to + * {@link 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:. + *

+ * + *
-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. + *

+ * + *
-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 removed this Security Provider before exiting. + *

+ * + *
-v
+ *
Use this option to enable more verbose output.
+ *
+ */ +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 @@ + + + + + +GNU Classpath - gnu.classpath.tools.keytool + + + +This package contains the classes that provide an implementation of the +Security Tool: keytool. The behaviour of these classes should +match that of the same tool provided in the RI version 1.4.2, except for the +following: + +
    +
  • The RI tool accepts -Jjavaoption options which it then passes to + the underlying JVM. This is because the RI tool acts as a wrapper + around the JVM launcher. +

    + This implementation DOES NOT support these options. +

  • + +
  • The RI tool is capable of importing JDK-1.1 style identities. +

    + This implementation does not offer this feature. +

  • +
+ + diff --git a/tools/gnu/classpath/tools/rmi/Persistent.java b/tools/gnu/classpath/tools/rmi/Persistent.java new file mode 100644 index 000000000..5cd1efe91 --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/Persistent.java @@ -0,0 +1,87 @@ +/* PersistentBidiHasthable.java -- Constants for the persistent tables. + 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.rmi; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * The static fields, shared by the multiple classes, implementing the + * persistent work. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public interface Persistent +{ + /** + * Sheduled termination task. + */ + static class ExitTask extends TimerTask + { + public void run() + { + System.exit(0); + } + } + + /** + * The timer, sheduling all disk database update events, shared by all + * instances. + */ + static Timer timer = new Timer(true); + + /** + * The longest time, in ms, after that the database content on the disk must + * be updated. The algorithm is written to avoid the very frequent writings to + * the disk. + */ + static long SAVE_AT_MOST_AFTER = 5000; + + /** + * States how long the database may stay not updated during the intensive + * operations, in ms. Otherwise the intensively used structure may never + * be stored to the disk. + */ + static long ALWAYS_UPDATE = 300000; + + /** + * Write the database content to the disk. + */ + void writeContent(); + +} diff --git a/tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java b/tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java new file mode 100644 index 000000000..94b5bcbee --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/PersistentBidiHashTable.java @@ -0,0 +1,268 @@ +/* PersistentBidiHasthable.java -- Bidirectional persistent hash table. + 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.rmi; + +import gnu.classpath.tools.rmi.rmid.ActivationSystemImpl; +import gnu.java.rmi.activation.BidiTable; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.TimerTask; + +/** + * The persistent bidirectional hash table, maps both a to b and b to a. The + * changes are written to dist after SAVE_AT_MOST_AFTER time from the latest + * database change or at most after ALWAYS_UPDATE, if the database is updated + * very frequently. To ensure that no information is lost, the shutdown method + * must be called before exit. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class PersistentBidiHashTable extends BidiTable implements + Persistent +{ + class WriteToDiskTask extends TimerTask + { + /** + * Save the database. + */ + public void run() + { + writeContent(); + sheduled = null; + } + } + + /** + * Replaces instances of ActivationSystemImpl into the currently active + * instance of the ActivationSystemImpl + */ + class AdaptedReader extends ObjectInputStream + { + AdaptedReader(InputStream in) throws IOException + { + super(in); + enableResolveObject(true); + } + + protected Object resolveObject(Object obj) throws IOException + { + if (obj instanceof ActivationSystemImpl) + return ActivationSystemImpl.singleton2; + else + return obj; + } + } + + /** + * The database file. + */ + File database; + + /** + * The currently sheduled write to disk task, null if none. + */ + WriteToDiskTask sheduled = null; + + /** + * The time, when the disk database was last updated. + */ + long lastUpdated; + + /** + * Create the unitialised instance that must be initalised when + * ActivationSystemImpl.singleton2 is assigned. + */ + public PersistentBidiHashTable() + { + // Do not initalise the table fields - the initalise method must be + // called later. + super(0); + } + + /** + * Create a new persistent table that stores its information into the given + * file. The ActivationSystemImpl.singleton2 must be assigned. + * + * @param file + * the file, where the table stores its information. + * @param coldStart + * if true, the existing file with this name will be erased and + * ignored. Otherwise, it will be assumed that the file contains the + * persistent table information. + */ + public void init(File file, boolean coldStart) + { + try + { + database = file; + if (database.exists()) + { + if (coldStart) + { + k2v = new Hashtable(); + v2k = new Hashtable(); + database.delete(); + } + else + { + FileInputStream fi = new FileInputStream(file); + BufferedInputStream b = new BufferedInputStream(fi); + ObjectInputStream oin = new AdaptedReader(b); + + k2v = (Map) oin.readObject(); + oin.close(); + + v2k = new Hashtable(k2v.size()); + + // Reguild v2k from k2v: + Iterator en = k2v.keySet().iterator(); + Object key; + while (en.hasNext()) + { + key = en.next(); + v2k.put(k2v.get(key), key); + } + } + } + else + { + k2v = new Hashtable(); + v2k = new Hashtable(); + } + } + catch (Exception ioex) + { + InternalError ierr = new InternalError("Unable to intialize with file " + + file); + ierr.initCause(ioex); + throw ierr; + } + } + + /** + * Write the database content to the disk. + */ + public synchronized void writeContent() + { + try + { + FileOutputStream fou = new FileOutputStream(database); + BufferedOutputStream b = new BufferedOutputStream(fou); + ObjectOutputStream oout = new ObjectOutputStream(b); + oout.writeObject(k2v); + oout.close(); + } + catch (Exception ioex) + { + InternalError ierr = new InternalError( + "Failed to write database to disk: " + + database); + ierr.initCause(ioex); + throw ierr; + } + } + + /** + * Mark the modified database as modified. The database will be written after + * several seconds, unless another modification occurs. + */ + public void markDirty() + { + if (System.currentTimeMillis() - lastUpdated > ALWAYS_UPDATE) + { + // Force storing to disk under intensive operation. + writeContent(); + lastUpdated = System.currentTimeMillis(); + if (sheduled != null) + { + sheduled.cancel(); + sheduled = null; + } + } + else + { + // Otherwise coalesce the disk database copy update events. + if (sheduled != null) + sheduled.cancel(); + sheduled = new WriteToDiskTask(); + timer.schedule(sheduled, SAVE_AT_MOST_AFTER); + } + } + + /** + * Save the current database state to the disk before exit. + */ + public void shutdown() + { + if (sheduled != null) + { + writeContent(); + sheduled = null; + } + } + + /** + * Update the memory maps and mark as should be written to the disk. + */ + public void put(Object key, Object value) + { + super.put(key, value); + markDirty(); + } + + /** + * Update the memory maps and mark as should be written to the disk. + */ + public void removeKey(Object key) + { + super.removeKey(key); + markDirty(); + } + +} diff --git a/tools/gnu/classpath/tools/rmi/PersistentHashTable.java b/tools/gnu/classpath/tools/rmi/PersistentHashTable.java new file mode 100644 index 000000000..925e829ff --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/PersistentHashTable.java @@ -0,0 +1,246 @@ +/* PersistentHasthable.java -- Persistent hash table. + 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.rmi; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Hashtable; +import java.util.Map; +import java.util.TimerTask; + +/** + * The persistent hash table. The changes are written to dist after + * SAVE_AT_MOST_AFTER time from the latest database change or at most after + * ALWAYS_UPDATE, if the database is updated very frequently. To ensure that no + * information is lost, the shutdown method must be called before exit. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class PersistentHashTable + extends Hashtable + implements Serializable, Persistent +{ + + /** + * Use serialVersionUID for interoperability + */ + private static final long serialVersionUID = 1; + + class WriteToDiskTask extends TimerTask + { + /** + * Save the database. + */ + public void run() + { + writeContent(); + sheduled = null; + } + } + + /** + * The database file. + */ + File database; + + /** + * The currently sheduled write to disk task, null if none. + */ + WriteToDiskTask sheduled = null; + + /** + * The time, when the disk database was last updated. + */ + long lastUpdated; + + /** + * Setting to false prevents the automated disk update. + * The initial value is true to prevent writing while reading and is set + * to false in createInstance. + */ + transient boolean ready; + + /** + * Use static method to obtain the instance. + */ + private PersistentHashTable(File file) + { + if (file == null) + throw new NullPointerException("Null file provided"); + database = file; + } + + /** + * Create a new persistent table that stores its information into the given + * file. + * + * @param file + * the file, where the table stores its information. + * @param coldStart + * if true, the existing file with this name will be erased and + * ignored. Otherwise, it will be assumed that the file contains the + * persistent table information. + */ + public static Map createInstance(File file, boolean coldStart) + { + try + { + PersistentHashTable k2v; + if (file.exists()) + { + if (coldStart) + { + file.delete(); + k2v = new PersistentHashTable(file); + } + else + { + FileInputStream fi = new FileInputStream(file); + BufferedInputStream b = new BufferedInputStream(fi); + ObjectInputStream oin = new ObjectInputStream(b); + + k2v = (PersistentHashTable) oin.readObject(); + oin.close(); + } + } + else + k2v = new PersistentHashTable(file); + + k2v.ready = true; + return k2v; + } + catch (Exception ioex) + { + InternalError ierr = new InternalError("Unable to intialize with file " + + file); + ierr.initCause(ioex); + throw ierr; + } + } + + + /** + * Write the database content to the disk. + */ + public synchronized void writeContent() + { + try + { + FileOutputStream fou = new FileOutputStream(database); + BufferedOutputStream b = new BufferedOutputStream(fou); + ObjectOutputStream oout = new ObjectOutputStream(b); + oout.writeObject(this); + oout.close(); + } + catch (Exception ioex) + { + InternalError ierr = new InternalError( + "Failed to write database to disk: "+ database); + ierr.initCause(ioex); + throw ierr; + } + } + + /** + * Mark the modified database as modified. The database will be written after + * several seconds, unless another modification occurs. + */ + public void markDirty() + { + if (System.currentTimeMillis() - lastUpdated > ALWAYS_UPDATE) + { + // Force storing to disk under intensive operation. + writeContent(); + lastUpdated = System.currentTimeMillis(); + if (sheduled != null) + { + sheduled.cancel(); + sheduled = null; + } + } + else + { + // Otherwise coalesce the disk database copy update events. + if (sheduled != null) + sheduled.cancel(); + sheduled = new WriteToDiskTask(); + timer.schedule(sheduled, SAVE_AT_MOST_AFTER); + } + } + + /** + * Save the current database state to the disk before exit. + */ + public void shutdown() + { + if (sheduled != null) + { + writeContent(); + sheduled = null; + } + } + + /** + * Update the memory maps and mark as should be written to the disk. + */ + public Object put(Object key, Object value) + { + super.put(key, value); + if (ready) + markDirty(); + return value; + } + + /** + * Update the memory maps and mark as should be written to the disk. + */ + public Object remove(Object key) + { + Object removed = super.remove(key); + if (ready) + markDirty(); + return removed; + } + +} diff --git a/tools/gnu/classpath/tools/rmi/REGISTRY.java b/tools/gnu/classpath/tools/rmi/REGISTRY.java new file mode 100644 index 000000000..63f633f99 --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/REGISTRY.java @@ -0,0 +1,165 @@ +/* REGISTY.java -- RMI registry starter. + 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.rmi; + +import gnu.classpath.tools.HelpPrinter; +import gnu.classpath.tools.rmi.registry.RegistryImpl; +import gnu.java.rmi.server.UnicastServerRef; + +import java.io.File; +import java.rmi.NotBoundException; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.ObjID; +import java.rmi.server.RMIServerSocketFactory; +import java.util.Hashtable; +import java.util.Map; + +/** + * The optionally persistent RMI registry implementation. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class REGISTRY +{ + /** + * The stop command. + */ + public static String STOP = "gnu.classpath.tools.rmi.registry.command.STOP"; + + /** + * If true, the registry prints registration events to console. + */ + public static boolean verbose = false; + + /** + * The RMI registry implementation entry point. + */ + public static void main(String[] args) + { + String HelpPath = "rmi/REGISTRY.txt"; + HelpPrinter.checkHelpKey(args, HelpPath); + + // Parse parameters: + String folder = "."; + boolean cold = false; + boolean trans = false; + boolean stop = false; + + int port = Registry.REGISTRY_PORT; + RMIServerSocketFactory ssf = null; + + for (int i = 0; i < args.length; i++) + { + String a = args[i]; + if (a.equals("-restart")) + cold = true; + else if (a.equals("-transient")) + trans = true; + else if (a.equals("-verbose")) + verbose = true; + else if (a.equals("-stop")) + stop = true; + else if (i < args.length - 1) + { + // The additional key parameter is possible. + if (a.equals("-port")) + port = Integer.parseInt(args[++i]); + else if (a.equals("-folder")) + folder = args[++i]; + } + } + + if (!stop) + { + Map table; + if (trans) + table = new Hashtable(); + else + { + // Start the system. + File dataFolder = new File(folder); + if (!dataFolder.exists()) + dataFolder.mkdirs(); + table = PersistentHashTable.createInstance( + new File(dataFolder, "rmiregistry.data"), cold); + } + + RegistryImpl system = new RegistryImpl(table); + + // We must export with the specific activation id that is only + // possible when going into the gnu.java.rmi + try + { + UnicastServerRef sref = new UnicastServerRef( + new ObjID(ObjID.REGISTRY_ID), port, ssf); + + sref.exportObject(system); + System.out.println("The RMI naming service is listening at " + port); + } + catch (Exception ex) + { + System.out.println("Failed to start RMI naming service at " + port); + } + } + else + { + // Stop the naming service. + try + { + Registry r = LocateRegistry.getRegistry(port); + // Search for this specific line will command to stop the registry. + + // Our service returns null, but any other service will thrown + // NotBoundException. + r.unbind(STOP); + } + catch (RemoteException e) + { + System.out.println("Failed to stop RMI naming service at " + port); + } + catch (NotBoundException e) + { + System.out.println("The naming service at port "+port+" is not a "+ + REGISTRY.class.getName()); + } + } + } +} diff --git a/tools/gnu/classpath/tools/rmi/REGISTRY.txt b/tools/gnu/classpath/tools/rmi/REGISTRY.txt new file mode 100644 index 000000000..7d8e19232 --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/REGISTRY.txt @@ -0,0 +1,28 @@ +The persistent RMI naming service, required for the remote method invocations +(packages java.rmi.*, java.rmi.Registry.*). + +Copyright 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. + +Please report bugs at http://www.gnu.org/software/classpath/bugs.html + +Usage: rmiregistry + + where includes: + -port N Start the registry on the given local port. If this key + is not specified, the service starts on the port 1099. + -verbose Log binding events to stdout. + -stop Stop the running naming service at the given port. + + -transient Start transient registry service that does not write any + data to the disk. Such service looses the stored bindings if + restarted. If this key is not specified, the + persistent naming service is started. + -restart "Cold start:, clear the persistent naming database, if any. + -folder Folder Store the persistent binding file in the given folder. If this + key is not specified, the file with persistent bindings is + stored into the current folder. + + + diff --git a/tools/gnu/classpath/tools/rmi/RMIC.java b/tools/gnu/classpath/tools/rmi/RMIC.java index 09021dd3f..c44453011 100644 --- a/tools/gnu/classpath/tools/rmi/RMIC.java +++ b/tools/gnu/classpath/tools/rmi/RMIC.java @@ -17,30 +17,13 @@ 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.rmi; import gnu.classpath.tools.HelpPrinter; import gnu.classpath.tools.giop.GRMIC; -import gnu.classpath.tools.giop.grmic.GiopRmicCompiler; import gnu.classpath.tools.rmi.rmic.RmicCompiler; import java.io.File; @@ -114,6 +97,10 @@ public class RMIC verbose = true; compiler.setVerbose(true); } + else if (c.equals("-force")) + { + compiler.setForce(true); + } else if (c.equals("-d")) { int f = i + 1; diff --git a/tools/gnu/classpath/tools/rmi/RMIC.txt b/tools/gnu/classpath/tools/rmi/RMIC.txt index df1de9ea6..7ec371e9a 100644 --- a/tools/gnu/classpath/tools/rmi/RMIC.txt +++ b/tools/gnu/classpath/tools/rmi/RMIC.txt @@ -16,6 +16,8 @@ Usage: rmic -help Print this help text -v Print version -verbose Verbose output + -force Try to generate code even if the input classes seem not + consistent with RMI specification. -1.2 Generate v 1.2 stubs (default)* diff --git a/tools/gnu/classpath/tools/rmi/RMID.java b/tools/gnu/classpath/tools/rmi/RMID.java new file mode 100644 index 000000000..81d09671a --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/RMID.java @@ -0,0 +1,189 @@ +/* RMID.java -- the RMI activation daemon. + 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.rmi; + +import gnu.classpath.tools.HelpPrinter; +import gnu.classpath.tools.rmi.rmid.ActivationSystemImpl; +import gnu.java.rmi.activation.ActivationSystemTransient; +import gnu.java.rmi.server.UnicastServerRef; + +import java.io.File; +import java.net.InetAddress; +import java.rmi.Remote; +import java.rmi.activation.ActivationSystem; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.ObjID; +import java.rmi.server.RMIServerSocketFactory; + + +/** + * The persistent RMI activation daemon. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class RMID +{ + /** + * The RMI server socket factory. + */ + static RMIServerSocketFactory ACTIVATION_REGISTY_SOCKET_FACTORY = null; + + /** + * The activation registry port. + */ + static int ACTIVATION_REGISTRY_PORT = ActivationSystem.SYSTEM_PORT; + + /** + * The activation system name. + */ + static String ACTIVATION_SYSTEM_NAME = "java.rmi.activation.ActivationSystem"; + + /** + * The RMI activation daemon entry point. + */ + public static void main(String[] args) + { + String HelpPath = "rmi/RMID.txt"; + HelpPrinter.checkHelpKey(args, HelpPath); + + // Parse parameters: + boolean stop = false; + String folder = "."; + boolean cold = false; + boolean trans = false; + + for (int i = 0; i < args.length; i++) + { + String a = args[i]; + if (a.equals("-verbose")) + ActivationSystemTransient.debug = true; + else if (a.equals("-stop")) + stop = true; + else if (a.equals("-restart")) + cold = true; + else if (a.equals("-transient")) + trans = true; + else if (i < args.length - 1) + { + // The additional key parameter is possible. + if (a.equals("-port")) + ACTIVATION_REGISTRY_PORT = Integer.parseInt(args[++i]); + else if (a.equals("-folder")) + folder = args[++i]; + } + } + + try + { + if (!stop) + { + // Start the system. + File dataFolder = new File(folder); + if (!dataFolder.exists()) + dataFolder.mkdirs(); + ActivationSystem system; + + if (trans) + system = ActivationSystemTransient.getInstance(); + else + system = ActivationSystemImpl.getInstance(dataFolder, cold); + + // We must export with the specific activation id that is only + // possible when going into the gnu.java.rmi.activation. + UnicastServerRef sref = new UnicastServerRef( + new ObjID(ObjID.ACTIVATOR_ID), ACTIVATION_REGISTRY_PORT, + ACTIVATION_REGISTY_SOCKET_FACTORY); + Remote systemStub = sref.exportObject(system); + + // Start the naming system on the activation system port + // (if not already running). + + Registry r; + try + { + // Expect the naming service running first. + // The local host may want to use the shared registry + r = LocateRegistry.getRegistry(ACTIVATION_REGISTRY_PORT); + r.rebind(ACTIVATION_SYSTEM_NAME, systemStub); + } + catch (Exception ex) + { + // The naming service is not running. Start it. + r = LocateRegistry.createRegistry(ACTIVATION_REGISTRY_PORT); + r.rebind(ACTIVATION_SYSTEM_NAME, systemStub); + } + String host = InetAddress.getLocalHost().getCanonicalHostName(); + System.out.println("The RMI daemon is listening on " + host + + " (port " + + ACTIVATION_REGISTRY_PORT + ")"); + + } + else + { + // Stop the activation system. + Registry r; + try + { + System.out.print("Stopping RMI daemon at " + + ACTIVATION_REGISTRY_PORT+" ... "); + // Expect the naming service running first. + // The local host may want to use the shared registry + r = LocateRegistry.getRegistry(ACTIVATION_REGISTRY_PORT); + ActivationSystem asys = + (ActivationSystem) r.lookup(ACTIVATION_SYSTEM_NAME); + asys.shutdown(); + System.out.println("OK."); + } + catch (Exception ex) + { + System.out.println("The RMI daemon seems not running at " + + ACTIVATION_REGISTRY_PORT); + if (ActivationSystemTransient.debug) + ex.printStackTrace(); + } + } + } + catch (Exception e) + { + System.out.println("Failed to start the RMI daemon."); + if (ActivationSystemTransient.debug) + e.printStackTrace(); + } + } +} diff --git a/tools/gnu/classpath/tools/rmi/RMID.txt b/tools/gnu/classpath/tools/rmi/RMID.txt new file mode 100644 index 000000000..a62613fd4 --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/RMID.txt @@ -0,0 +1,30 @@ +The persistent RMI activation daemon, support RMI object activation +(package java.rmi.activation.*). + +Copyright 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. + +Please report bugs at http://www.gnu.org/software/classpath/bugs.html + +Usage: rmid + + where includes: + -port N Start the service on the given local port. If this key + is not specified, the service starts on the port 1098. + -verbose Log registration events to stdout. + -stop Stop the running activation service at the given port. + + -transient Start transient activation service that does not write any + data to the disk. Such service looses the stored activation + descriptors, if restarted. If this key is not specified, the + persistent naming service is started. + -restart "Cold start:, clear the activation descriptor database, if any. + -folder Folder Store the persistent descriptor file in the given folder. If this + key is not specified, the file with persistent activation + information is stored into the current folder. + +All activation groups are activated on the same virtual machine, where the +daemon is running. For security reasons, all the classes, required for +activation, must be available in the classpath of that machine. + \ No newline at end of file diff --git a/tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java new file mode 100644 index 000000000..90bd3a6bd --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl.java @@ -0,0 +1,139 @@ +/* RegistryImpl.java -- the RMI registry implementation + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 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.rmi.registry; + +import gnu.classpath.tools.rmi.Persistent; +import gnu.classpath.tools.rmi.REGISTRY; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.Registry; +import java.util.ArrayList; +import java.util.Map; + +/** + * The optionally persistent registry implementation. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class RegistryImpl implements Registry +{ + /** + * The binding table. + */ + Map bindings; + + /** + * Create the registry implementation that uses the given bidirectinal + * table to keep the data. + */ + public RegistryImpl(Map aTable) + { + bindings = aTable; + } + + /** @inheritDoc */ + public Remote lookup(String name) throws RemoteException, NotBoundException, + AccessException + { + Object obj = bindings.get(name); + if (obj == null) + throw new NotBoundException(name); + return ((Remote) obj); + } + + /** @inheritDoc */ + public void bind(String name, Remote obj) throws RemoteException, + AlreadyBoundException, AccessException + { + if (REGISTRY.verbose) + System.out.println("Bind "+name); + if (bindings.containsKey(name)) + throw new AlreadyBoundException(name); + bindings.put(name, obj); + } + + /** @inheritDoc */ + public void unbind(String name) throws RemoteException, NotBoundException, + AccessException + { + if (name.equals(REGISTRY.STOP)) + { + if (bindings instanceof Persistent) + ((Persistent) bindings).writeContent(); + // Terminate in 10 seconds. + System.out.println("Shutdown command received. Will terminate in 10 s"); + Persistent.timer.schedule(new Persistent.ExitTask(), 10000); + } + else + { + if (REGISTRY.verbose) + System.out.println("Unbind "+name); + + if (!bindings.containsKey(name)) + throw new NotBoundException(name); + else + bindings.remove(name); + } + } + + /** @inheritDoc */ + public void rebind(String name, Remote obj) throws RemoteException, + AccessException + { + if (REGISTRY.verbose) + System.out.println("Rebind "+name); + bindings.put(name, obj); + } + + /** @inheritDoc */ + public String[] list() throws RemoteException, AccessException + { + // Create a separated array to prevent race conditions. + ArrayList keys = new ArrayList(bindings.keySet()); + int n = keys.size(); + String[] rt = new String[n]; + for (int i = 0; i < n; i++) + rt[i] = (String) keys.get(i); + return rt; + } +} diff --git a/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Skel.java b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Skel.java new file mode 100644 index 000000000..36b7d94a5 --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Skel.java @@ -0,0 +1,278 @@ +/* RegistryImpl_Skel.java + Copyright (C) 2002, 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.rmi.registry; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.rmi.MarshalException; +import java.rmi.Remote; +import java.rmi.UnmarshalException; +import java.rmi.server.Operation; +import java.rmi.server.RemoteCall; +import java.rmi.server.SkeletonMismatchException; + +/** + * This skeleton supports unlikely cases when the naming service is + * contacted from other interoperable java implementation that still uses + * the old style skeleton-dependent invocations. + */ +public final class RegistryImpl_Skel + implements java.rmi.server.Skeleton +{ + private static final long interfaceHash = 4905912898345647071L; + + /** + * Repeated multiple times. + */ + static final String EUM = "error unmarshalling arguments for Registry"; + + /** + * Repeated multiple times. + */ + static final String EMR = "error marshalling return from Registry"; + + private static final Operation[] operations = + { + new Operation("void bind(java.lang.String, Remote"), + new Operation("java.lang.String[] list("), + new Operation("Remote lookup(java.lang.String"), + new Operation("void rebind(java.lang.String, Remote"), + new Operation("void unbind(java.lang.String") + }; + + public Operation[] getOperations() + { + return ((Operation[]) operations.clone()); + } + + public void dispatch(Remote obj, RemoteCall call, + int opnum, long hash) throws java.lang.Exception + { + if (opnum < 0) + { + if (hash == 7583982177005850366L) + opnum = 0; + else if (hash == 2571371476350237748L) + opnum = 1; + else if (hash == -7538657168040752697L) + opnum = 2; + else if (hash == -8381844669958460146L) + opnum = 3; + else if (hash == 7305022919901907578L) + opnum = 4; + else + throw new SkeletonMismatchException("interface hash mismatch"); + } + else if (hash != interfaceHash) + throw new SkeletonMismatchException("interface hash mismatch"); + + RegistryImpl server = (RegistryImpl) obj; + switch (opnum) + { + case 0: + { + java.lang.String $param_0; + Remote $param_1; + try + { + ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String) in.readObject(); + $param_1 = (Remote) in.readObject(); + + } + catch (IOException e) + { + throw new UnmarshalException(EUM, e); + } + catch (java.lang.ClassCastException e) + { + throw new UnmarshalException(EUM, e); + } + finally + { + call.releaseInputStream(); + } + server.bind($param_0, $param_1); + try + { + ObjectOutput out = call.getResultStream(true); + } + catch (IOException e) + { + throw new MarshalException(EMR, e); + } + break; + } + + case 1: + { + try + { + ObjectInput in = call.getInputStream(); + + } + catch (IOException e) + { + throw new UnmarshalException(EUM, e); + } + finally + { + call.releaseInputStream(); + } + java.lang.String[] $result = server.list(); + try + { + ObjectOutput out = call.getResultStream(true); + out.writeObject($result); + } + catch (IOException e) + { + throw new MarshalException(EMR, e); + } + break; + } + + case 2: + { + java.lang.String $param_0; + try + { + ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String) in.readObject(); + + } + catch (IOException e) + { + throw new UnmarshalException(EUM, e); + } + catch (java.lang.ClassCastException e) + { + throw new UnmarshalException(EUM, e); + } + finally + { + call.releaseInputStream(); + } + Remote $result = server.lookup($param_0); + try + { + ObjectOutput out = call.getResultStream(true); + out.writeObject($result); + } + catch (IOException e) + { + throw new MarshalException(EMR, e); + } + break; + } + + case 3: + { + java.lang.String $param_0; + Remote $param_1; + try + { + ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String) in.readObject(); + $param_1 = (Remote) in.readObject(); + + } + catch (IOException e) + { + throw new UnmarshalException(EUM, e); + } + catch (java.lang.ClassCastException e) + { + throw new UnmarshalException(EUM, e); + } + finally + { + call.releaseInputStream(); + } + server.rebind($param_0, $param_1); + try + { + ObjectOutput out = call.getResultStream(true); + } + catch (IOException e) + { + throw new MarshalException(EMR, e); + } + break; + } + + case 4: + { + java.lang.String $param_0; + try + { + ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String) in.readObject(); + + } + catch (IOException e) + { + throw new UnmarshalException(EUM, e); + } + catch (java.lang.ClassCastException e) + { + throw new UnmarshalException(EUM, e); + } + finally + { + call.releaseInputStream(); + } + server.unbind($param_0); + try + { + ObjectOutput out = call.getResultStream(true); + } + catch (IOException e) + { + throw new MarshalException(EMR, e); + } + break; + } + + default: + throw new UnmarshalException("invalid method number"); + } + } +} diff --git a/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Stub.java b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Stub.java new file mode 100644 index 000000000..d8cac5bfc --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/registry/RegistryImpl_Stub.java @@ -0,0 +1,263 @@ +/* RegistryImpl_Stub.java -- Registry stub. + 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.rmi.registry; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.Registry; + +import java.lang.reflect.Method; +import java.rmi.server.RemoteRef; +import java.rmi.server.RemoteStub; +import java.rmi.UnexpectedException; + +/** + * This class delegates its method calls to the remote RMI object, referenced + * by {@link RemoteRef}. + * + * It is normally generated with rmic. + */ +public final class RegistryImpl_Stub + extends RemoteStub + implements Registry +{ + /** + * Use serialVersionUID for interoperability + */ + private static final long serialVersionUID = 3; + + /** + * The explaining message for {@ling UnexpectedException}. + */ + private static final String exception_message = + "undeclared checked exception"; + + /* All remote methods, invoked by this stub: */ + private static final Method met_list; + private static final Method met_rebind; + private static final Method met_unbind; + private static final Method met_lookup; + private static final Method met_bind; + private static final Object[] NO_ARGS = new Object[0]; + static + { + final Class[] NO_ARGSc = new Class[0]; + try + { + met_list = + Registry.class.getMethod("list", NO_ARGSc); + met_rebind = + Registry.class.getMethod("rebind", new Class[] + { + String.class, Remote.class + }); + met_unbind = + Registry.class.getMethod("unbind", new Class[] + { + String.class + }); + met_lookup = + Registry.class.getMethod("lookup", new Class[] + { + String.class + }); + met_bind = + Registry.class.getMethod("bind", new Class[] + { + String.class, Remote.class + }); + + } + catch (NoSuchMethodException nex) + { + NoSuchMethodError err = new NoSuchMethodError( + "RegistryImpl_Stub class initialization failed"); + err.initCause(nex); + throw err; + } + } + + /** + * Create the instance for _RegistryImpl_Stub that forwards method calls to the + * remote object. + * + * @para the reference to the remote object. + */ + public RegistryImpl_Stub(RemoteRef reference) + { + super(reference); + } + + /* Methods */ + /** @inheritDoc */ + public String [] list() + throws RemoteException, AccessException + { + try + { + Object result = ref.invoke(this, met_list, + NO_ARGS, + 2571371476350237748L); + return (String []) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void rebind(String p0, Remote p1) + throws RemoteException, AccessException + { + try + { + ref.invoke(this, met_rebind, + new Object[] {p0, p1}, + -8381844669958460146L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void unbind(String p0) + throws RemoteException, NotBoundException, AccessException + { + try + { + ref.invoke(this, met_unbind, + new Object[] {p0}, + 7305022919901907578L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public Remote lookup(String p0) + throws RemoteException, NotBoundException, AccessException + { + try + { + Object result = ref.invoke(this, met_lookup, + new Object[] {p0}, + -7538657168040752697L); + return (Remote) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void bind(String p0, Remote p1) + throws RemoteException, AlreadyBoundException, AccessException + { + try + { + ref.invoke(this, met_bind, + new Object[] {p0, p1}, + 7583982177005850366L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + +} diff --git a/tools/gnu/classpath/tools/rmi/registry/package.html b/tools/gnu/classpath/tools/rmi/registry/package.html new file mode 100644 index 000000000..71df83b61 --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/registry/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.classpath.tools.rmi.registry + + +

+ + + diff --git a/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java b/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java index 9b7f9358b..8da486571 100644 --- a/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java +++ b/tools/gnu/classpath/tools/rmi/rmic/RmiMethodGenerator.java @@ -22,18 +22,7 @@ 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.rmi.rmic; @@ -43,7 +32,6 @@ import gnu.java.rmi.server.RMIHashes; import java.lang.reflect.Method; import java.util.Properties; -import java.util.zip.Adler32; /** * Keeps information about the single method and generates the code fragments, diff --git a/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java b/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java index 498dff7b2..bc51aad38 100644 --- a/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java +++ b/tools/gnu/classpath/tools/rmi/rmic/RmicCompiler.java @@ -22,18 +22,7 @@ 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.rmi.rmic; diff --git a/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java b/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java index 6451a7074..8ee4fa5f2 100644 --- a/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java +++ b/tools/gnu/classpath/tools/rmi/rmic/WrapUnWrapper.java @@ -17,28 +17,11 @@ 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.rmi.rmic; -import java.lang.reflect.Method; public class WrapUnWrapper { diff --git a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav index 1069884b9..9aaf8f5ad 100644 --- a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav +++ b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12Method.jav @@ -19,7 +19,7 @@ catch (Exception e) { UnexpectedException uex = new UnexpectedException(exception_message); - uex.initCause(e); + uex.detail = e; throw uex; } } diff --git a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav index f67098a4f..860a93c84 100644 --- a/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav +++ b/tools/gnu/classpath/tools/rmi/rmic/templates/Stub_12MethodVoid.jav @@ -18,7 +18,7 @@ catch (Exception e) { UnexpectedException uex = new UnexpectedException(exception_message); - uex.initCause(e); + uex.detail = e; throw uex; } } diff --git a/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java b/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java new file mode 100644 index 000000000..dda40b06c --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl.java @@ -0,0 +1,244 @@ +/* ActivationSystemImpl.java -- implementation of the activation system. + 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.rmi.rmid; + +import gnu.classpath.tools.rmi.Persistent; +import gnu.classpath.tools.rmi.PersistentBidiHashTable; +import gnu.java.rmi.activation.ActivationSystemTransient; + +import java.io.File; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.rmi.MarshalledObject; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationGroupDesc; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.activation.ActivationInstantiator; +import java.rmi.activation.ActivationMonitor; +import java.rmi.activation.ActivationSystem; +import java.rmi.activation.Activator; +import java.rmi.activation.UnknownGroupException; +import java.rmi.activation.UnknownObjectException; + +/** + * Implements the rmid activation system. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class ActivationSystemImpl extends ActivationSystemTransient implements + ActivationSystem, Activator, ActivationMonitor, Serializable +{ + /** + * Use for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The singleton instance of this class. + */ + public static ActivationSystemImpl singleton2; + + /** + * Obtain the singleton instance of this class. + * + * @param folder the folder, where the activation system will keep its files. + * @param cold do the cold start if true, hot (usual) if false. + */ + public static ActivationSystem getInstance(File folder, boolean cold) + { + if (singleton2 == null) + singleton2 = new ActivationSystemImpl(folder, cold); + return singleton2; + } + + /** + * Creates the group with transient maps. + * + * @param folder + * the folder, where the activation system will keep its files. + * @param cold + * do the cold start if true, hot (usual) if false. + */ + protected ActivationSystemImpl(File folder, boolean cold) + { + super(new PersistentBidiHashTable(), new PersistentBidiHashTable()); + singleton2 = this; + ((PersistentBidiHashTable) groupDescs).init( + new File(folder, "asi_objects.data"), cold); + ((PersistentBidiHashTable) descriptions).init( + new File(folder, "asi_groups.data"), cold); + } + + /** @inheritDoc */ + public MarshalledObject activate(ActivationID id, boolean force) + throws ActivationException, UnknownObjectException, RemoteException + { + return super.activate(id, force); + } + + /** @inheritDoc */ + public ActivationMonitor activeGroup(ActivationGroupID id, + ActivationInstantiator group, + long incarnation) + throws UnknownGroupException, ActivationException, RemoteException + { + return super.activeGroup(id, group, incarnation); + } + + /** @inheritDoc */ + public void activeObject(ActivationID id, MarshalledObject obj) + throws UnknownObjectException, RemoteException + { + super.activeObject(id, obj); + } + + /** @inheritDoc */ + public ActivationDesc getActivationDesc(ActivationID id) + throws ActivationException, UnknownObjectException, RemoteException + { + return super.getActivationDesc(id); + } + + public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID groupId) + throws ActivationException, UnknownGroupException, RemoteException + { + return super.getActivationGroupDesc(groupId); + } + + /** @inheritDoc */ + public void inactiveGroup(ActivationGroupID groupId, long incarnation) + throws UnknownGroupException, RemoteException + { + super.inactiveGroup(groupId, incarnation); + } + + /** @inheritDoc */ + public void inactiveObject(ActivationID id) throws UnknownObjectException, + RemoteException + { + super.inactiveObject(id); + } + + /** @inheritDoc */ + public ActivationGroupID registerGroup(ActivationGroupDesc groupDesc) + throws ActivationException, RemoteException + { + return super.registerGroup(groupDesc); + } + + /** @inheritDoc */ + public ActivationID registerObject(ActivationDesc desc) + throws ActivationException, UnknownGroupException, RemoteException + { + return super.registerObject(desc); + } + + /** @inheritDoc */ + public ActivationDesc setActivationDesc(ActivationID id, ActivationDesc desc) + throws ActivationException, UnknownObjectException, + UnknownGroupException, RemoteException + { + return super.setActivationDesc(id, desc); + } + + /** @inheritDoc */ + public ActivationGroupDesc setActivationGroupDesc( + ActivationGroupID groupId, ActivationGroupDesc groupDesc) + throws ActivationException, UnknownGroupException, RemoteException + { + return super.setActivationGroupDesc(groupId, groupDesc); + } + + /** + * This method saves the state of the activation system and then + * terminates in 10 seconds. + */ + public void shutdown() throws RemoteException + { + super.shutdown(); + System.out.println("Shutdown command received. Will terminate in 10 s"); + Persistent.timer.schedule(new Persistent.ExitTask(), 10000); + } + + /** @inheritDoc */ + public void unregisterGroup(ActivationGroupID groupId) + throws ActivationException, UnknownGroupException, RemoteException + { + super.unregisterGroup(groupId); + } + + /** @inheritDoc */ + public void unregisterObject(ActivationID id) throws ActivationException, + UnknownObjectException, RemoteException + { + super.unregisterObject(id); + } + + /** + * Read the object from the input stream. + * + * @param in the stream to read from + * + * @throws IOException if thrown by the stream + * @throws ClassNotFoundException + */ + private void readObject(ObjectInputStream in) throws IOException, + ClassNotFoundException + { + // Read no fields. + } + + /** + * Write the object to the output stream. + * + * @param out the stream to write int + * @throws IOException if thrown by the stream + * @throws ClassNotFoundException + */ + private void writeObject(ObjectOutputStream out) throws IOException, + ClassNotFoundException + { + // Write no fields. + }; + +} diff --git a/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl_Stub.java b/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl_Stub.java new file mode 100644 index 000000000..22fa10e4b --- /dev/null +++ b/tools/gnu/classpath/tools/rmi/rmid/ActivationSystemImpl_Stub.java @@ -0,0 +1,556 @@ +/* ActivationSystemImpl.java -- implementation of the activation system. + 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.rmi.rmid; + +import java.rmi.MarshalledObject; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationGroupDesc; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.activation.ActivationInstantiator; +import java.rmi.activation.ActivationMonitor; +import java.rmi.activation.ActivationSystem; +import java.rmi.activation.Activator; +import java.rmi.activation.UnknownGroupException; +import java.rmi.activation.UnknownObjectException; + +import java.lang.reflect.Method; +import java.rmi.server.RemoteRef; +import java.rmi.server.RemoteStub; +import java.rmi.UnexpectedException; + +/** + * This class delegates its method calls to the remote RMI object, referenced + * by {@link RemoteRef}. + * + * It is normally generated with rmic. + */ +public final class ActivationSystemImpl_Stub + extends RemoteStub + implements ActivationMonitor, Activator, ActivationSystem +{ + /** + * Use serialVersionUID for interoperability + */ + private static final long serialVersionUID = 2; + + /** + * The explaining message for {@ling UnexpectedException}. + */ + private static final String exception_message = + "undeclared checked exception"; + + /* All remote methods, invoked by this stub: */ + private static final Method met_setActivationGroupDesc; + private static final Method met_inactiveGroup; + private static final Method met_unregisterObject; + private static final Method met_getActivationDesc; + private static final Method met_setActivationDesc; + private static final Method met_shutdown; + private static final Method met_activate; + private static final Method met_activeGroup; + private static final Method met_registerGroup; + private static final Method met_getActivationGroupDesc; + private static final Method met_activeObject; + private static final Method met_registerObject; + private static final Method met_inactiveObject; + private static final Method met_unregisterGroup; + private static final Object[] NO_ARGS = new Object[0]; + static + { + final Class[] NO_ARGSc = new Class[0]; + try + { + met_setActivationGroupDesc = + ActivationSystem.class.getMethod("setActivationGroupDesc", new Class[] + { + ActivationGroupID.class, ActivationGroupDesc.class + }); + met_inactiveGroup = + ActivationMonitor.class.getMethod("inactiveGroup", new Class[] + { + ActivationGroupID.class, long.class + }); + met_unregisterObject = + ActivationSystem.class.getMethod("unregisterObject", new Class[] + { + ActivationID.class + }); + met_getActivationDesc = + ActivationSystem.class.getMethod("getActivationDesc", new Class[] + { + ActivationID.class + }); + met_setActivationDesc = + ActivationSystem.class.getMethod("setActivationDesc", new Class[] + { + ActivationID.class, ActivationDesc.class + }); + met_shutdown = + ActivationSystem.class.getMethod("shutdown", NO_ARGSc); + met_activate = + Activator.class.getMethod("activate", new Class[] + { + ActivationID.class, boolean.class + }); + met_activeGroup = + ActivationSystem.class.getMethod("activeGroup", new Class[] + { + ActivationGroupID.class, ActivationInstantiator.class, long.class + }); + met_registerGroup = + ActivationSystem.class.getMethod("registerGroup", new Class[] + { + ActivationGroupDesc.class + }); + met_getActivationGroupDesc = + ActivationSystem.class.getMethod("getActivationGroupDesc", new Class[] + { + ActivationGroupID.class + }); + met_activeObject = + ActivationMonitor.class.getMethod("activeObject", new Class[] + { + ActivationID.class, MarshalledObject.class + }); + met_registerObject = + ActivationSystem.class.getMethod("registerObject", new Class[] + { + ActivationDesc.class + }); + met_inactiveObject = + ActivationMonitor.class.getMethod("inactiveObject", new Class[] + { + ActivationID.class + }); + met_unregisterGroup = + ActivationSystem.class.getMethod("unregisterGroup", new Class[] + { + ActivationGroupID.class + }); + + } + catch (NoSuchMethodException nex) + { + NoSuchMethodError err = new NoSuchMethodError( + "ActivationSystemImpl_Stub class initialization failed"); + err.initCause(nex); + throw err; + } + } + + /** + * Create the instance for _ActivationSystemImpl_Stub that forwards method calls to the + * remote object. + * + * @para the reference to the remote object. + */ + public ActivationSystemImpl_Stub(RemoteRef reference) + { + super(reference); + } + + /* Methods */ + /** @inheritDoc */ + public ActivationGroupDesc setActivationGroupDesc(ActivationGroupID p0, + ActivationGroupDesc p1) + throws ActivationException, UnknownGroupException, RemoteException + { + try + { + Object result = ref.invoke(this, met_setActivationGroupDesc, + new Object[] { p0, p1 }, + 1213918527826541191L); + return (ActivationGroupDesc) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void inactiveGroup(ActivationGroupID p0, long p1) + throws UnknownGroupException, RemoteException + { + try + { + ref.invoke(this, met_inactiveGroup, new Object[] { p0, new Long(p1) }, + -399287892768650944L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void unregisterObject(ActivationID p0) throws ActivationException, + UnknownObjectException, RemoteException + { + try + { + ref.invoke(this, met_unregisterObject, new Object[] { p0 }, + -6843850585331411084L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public ActivationDesc getActivationDesc(ActivationID p0) + throws ActivationException, UnknownObjectException, RemoteException + { + try + { + Object result = ref.invoke(this, met_getActivationDesc, + new Object[] { p0 }, 4830055440982622087L); + return (ActivationDesc) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public ActivationDesc setActivationDesc(ActivationID p0, ActivationDesc p1) + throws ActivationException, UnknownObjectException, + UnknownGroupException, RemoteException + { + try + { + Object result = ref.invoke(this, met_setActivationDesc, + new Object[] { p0, p1 }, + 7128043237057180796L); + return (ActivationDesc) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void shutdown() throws RemoteException + { + try + { + ref.invoke(this, met_shutdown, NO_ARGS, -7207851917985848402L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public MarshalledObject activate(ActivationID p0, boolean p1) + throws ActivationException, UnknownObjectException, RemoteException + { + try + { + Object result = ref.invoke(this, met_activate, + new Object[] { p0, new Boolean(p1) }, + -8767355154875805558L); + return (MarshalledObject) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public ActivationMonitor activeGroup(ActivationGroupID p0, + ActivationInstantiator p1, long p2) + throws UnknownGroupException, ActivationException, RemoteException + { + try + { + Object result = ref.invoke(this, met_activeGroup, + new Object[] { p0, p1, new Long(p2) }, + -4575843150759415294L); + return (ActivationMonitor) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public ActivationGroupID registerGroup(ActivationGroupDesc p0) + throws ActivationException, RemoteException + { + try + { + Object result = ref.invoke(this, met_registerGroup, + new Object[] { p0 }, 6921515268192657754L); + return (ActivationGroupID) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID p0) + throws ActivationException, UnknownGroupException, RemoteException + { + try + { + Object result = ref.invoke(this, met_getActivationGroupDesc, + new Object[] { p0 }, -8701843806548736528L); + return (ActivationGroupDesc) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void activeObject(ActivationID p0, MarshalledObject p1) + throws UnknownObjectException, RemoteException + { + try + { + ref.invoke(this, met_activeObject, new Object[] { p0, p1 }, + 2543984342209939736L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public ActivationID registerObject(ActivationDesc p0) + throws ActivationException, UnknownGroupException, RemoteException + { + try + { + Object result = ref.invoke(this, met_registerObject, + new Object[] { p0 }, -3006759798994351347L); + return (ActivationID) result; + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void inactiveObject(ActivationID p0) throws UnknownObjectException, + RemoteException + { + try + { + ref.invoke(this, met_inactiveObject, new Object[] { p0 }, + -4165404120701281807L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + /** @inheritDoc */ + public void unregisterGroup(ActivationGroupID p0) throws ActivationException, + UnknownGroupException, RemoteException + { + try + { + ref.invoke(this, met_unregisterGroup, new Object[] { p0 }, + 3768097077835970701L); + } + catch (RuntimeException e) + { + throw e; + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnexpectedException uex = new UnexpectedException(exception_message); + uex.detail = e; + throw uex; + } + } + + +} diff --git a/tools/jarsigner.in b/tools/jarsigner.in new file mode 100644 index 000000000..cea95a288 --- /dev/null +++ b/tools/jarsigner.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 jarsigner 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.jarsigner.Main $@ diff --git a/tools/keytool.in b/tools/keytool.in new file mode 100644 index 000000000..6c11dc407 --- /dev/null +++ b/tools/keytool.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 $@ -- cgit v1.2.1