summaryrefslogtreecommitdiff
path: root/tools/gnu/classpath
diff options
context:
space:
mode:
authorAndrew John Hughes <gnu_andrew@member.fsf.org>2006-03-26 20:08:09 +0000
committerAndrew John Hughes <gnu_andrew@member.fsf.org>2006-03-26 20:08:09 +0000
commitc7fc43440df4ee0406f8483ff717949056f81845 (patch)
treed1933cdedc07bb3dea4f9e8becfa47c46c928a7e /tools/gnu/classpath
parent7afa402d5269bad9cf422c4c2369c51ef76ded8b (diff)
downloadclasspath-c7fc43440df4ee0406f8483ff717949056f81845.tar.gz
2006-03-26 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge from Classpath HEAD --> generics for the period 2005/03/07 to the branch tag generics_merge_20050326.
Diffstat (limited to 'tools/gnu/classpath')
-rw-r--r--tools/gnu/classpath/tools/giop/GRMIC.java4
-rw-r--r--tools/gnu/classpath/tools/giop/GRMIC.txt3
-rw-r--r--tools/gnu/classpath/tools/giop/README3
-rw-r--r--tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java15
-rw-r--r--tools/gnu/classpath/tools/jarsigner/HashUtils.java122
-rw-r--r--tools/gnu/classpath/tools/jarsigner/JarSigner.java169
-rw-r--r--tools/gnu/classpath/tools/jarsigner/JarVerifier.java336
-rw-r--r--tools/gnu/classpath/tools/jarsigner/Main.java457
-rw-r--r--tools/gnu/classpath/tools/jarsigner/SFHelper.java373
-rw-r--r--tools/gnu/classpath/tools/jarsigner/jarsigner.txt101
-rw-r--r--tools/gnu/classpath/tools/rmi/RMIC.java4
-rw-r--r--tools/gnu/classpath/tools/rmi/RMIC.txt2
12 files changed, 1587 insertions, 2 deletions
diff --git a/tools/gnu/classpath/tools/giop/GRMIC.java b/tools/gnu/classpath/tools/giop/GRMIC.java
index 16ff96f56..bb0ef9cdc 100644
--- a/tools/gnu/classpath/tools/giop/GRMIC.java
+++ b/tools/gnu/classpath/tools/giop/GRMIC.java
@@ -105,6 +105,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 <options> <class names>
-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 <class names> 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/README b/tools/gnu/classpath/tools/giop/README
index f1be7b674..94fc2f158 100644
--- a/tools/gnu/classpath/tools/giop/README
+++ b/tools/gnu/classpath/tools/giop/README
@@ -9,7 +9,8 @@ The list of the currently available tools:
* GRMIC - RMI-IIOP stub and tie generator.
* NameService - GIOP transient naming service (this tool is called
tnameserv in Sun's package).
-* NameService - GIOP persistent naming service (this tool is called
+* NameServicePersistent
+ - GIOP persistent naming service (this tool is called
orbd in Sun's package).
* IorParser - Parses the stringified form of the interoperable
object references (IOR's).
diff --git a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
index c19f635c6..62456fd51 100644
--- a/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
+++ b/tools/gnu/classpath/tools/giop/grmic/GiopRmicCompiler.java
@@ -115,6 +115,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 +209,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 +488,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/jarsigner/HashUtils.java b/tools/gnu/classpath/tools/jarsigner/HashUtils.java
new file mode 100644
index 000000000..7591b3c57
--- /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 java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.logging.Logger;
+
+import gnu.java.security.hash.Sha160;
+import gnu.java.security.util.Base64;
+import gnu.java.util.jar.JarUtils;
+
+/**
+ * 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..8babdcc30
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/JarSigner.java
@@ -0,0 +1,169 @@
+/* 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.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+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 <code>gjarsigner</code> 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 IOException, CertificateEncodingException, CRLException
+ {
+ log.entering("JarSigner", "start");
+
+ 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(" signing: " + jeName);
+ }
+
+ sfHelper.finishSigning(main.isSectionsOnly());
+ if (main.isVerbose())
+ System.out.println(" updating: " + JarFile.MANIFEST_NAME);
+
+ // 2. write jar entries and manifest
+ File signedJarFile = File.createTempFile("gcp-", ".jar");
+ 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);
+ 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);
+ JarEntry sfEntry = new JarEntry(sfFileName);
+ sfEntry.setTime(System.currentTimeMillis());
+ outSignedJarFile.putNextEntry(sfEntry);
+ sfHelper.writeSF(outSignedJarFile);
+ log.info("Created .SF file");
+ if (main.isVerbose())
+ System.out.println(" adding: " + sfFileName);
+
+ // 4. create the .DSA file
+ String dsaFileName = JarUtils.META_INF + signaturesFileName
+ + JarUtils.DSA_SUFFIX;
+ log.finest("Processing " + dsaFileName);
+ JarEntry dsaEntry = new JarEntry(dsaFileName);
+ dsaEntry.setTime(System.currentTimeMillis());
+ outSignedJarFile.putNextEntry(dsaEntry);
+ sfHelper.writeDSA(outSignedJarFile,
+ main.getSignerPrivateKey(),
+ main.getSignerCertificateChain(),
+ main.isInternalSF());
+ log.info("Created .DSA file");
+ if (main.isVerbose())
+ System.out.println(" adding: " + dsaFileName);
+
+ // cleanup
+ outSignedJarFile.close();
+ fos.close();
+ signedJarFile.renameTo(new File(main.getSignedJarFileName()));
+ log.info("Renamed signed JAR file");
+ if (main.isVerbose())
+ System.out.println(SystemProperties.getProperty("line.separator")
+ + "jar signed.");
+
+ log.exiting("JarSigner", "start");
+ }
+
+ 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..06ebe64fe
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/JarVerifier.java
@@ -0,0 +1,336 @@
+/* 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 <code>gjarsigner</code> 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 IOException, CRLException, CertificateException
+ {
+ log.entering("JarVerifier", "start");
+
+ 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("/");
+ 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("jar is not signed.--no signature files found.");
+ 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("jar verification failed.");
+ else if (count != limit)
+ System.out.println("jar partially verified --" + count + " of "
+ + limit + " signers.");
+ else
+ System.out.println("jar verified --" + limit + " signer(s).");
+ }
+
+ log.exiting("JarVerifier", "start");
+ }
+
+ /**
+ * @param sigFileName the name of the signature file; i.e. the name to use for
+ * both the .SF and .DSA files.
+ * @return <code>true</code> if the designated file-name (usually a key-store
+ * <i>alias</i> name) has been successfully checked as the signer of the
+ * corresponding <code>.SF</code> file. Returns <code>false</code> otherwise.
+ * @throws IOException
+ * @throws ZipException
+ * @throws CertificateException
+ * @throws CRLException
+ */
+ private boolean verifySF(String sigFileName) throws CRLException,
+ CertificateException, ZipException, IOException
+ {
+ log.entering("JarVerifier", "verifySF");
+ log.finest("About to verify signature of " + sigFileName + "...");
+
+ // 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("Signature Block missing for " + 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("At least one SignerInfo element MUST be "
+ + "present in a Signature Block (.DSA file)");
+ SignerInfo signerInfo = (SignerInfo) signerInfos.iterator().next();
+ byte[] encryptedDigest = signerInfo.getEncryptedDigest();
+ if (encryptedDigest == null)
+ throw new SecurityException("Missing EncryptedDigest in Signature Block "
+ + "(.DSA file) first SignerInfo element");
+ log.finest("\n" + Util.dumpString(encryptedDigest, "--- signedSFBytes "));
+
+ // 5. get the signer public key
+ Certificate cert = pkcs7SignedData.getCertificates()[0];
+ PublicKey verifierKey = cert.getPublicKey();
+ log.finest("--- verifier public key = " + verifierKey);
+
+ // 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.info("Signature block [" + sigFileName + "] is "
+ + (result ? "" : "NOT ") + "OK");
+
+ log.exiting("JarVerifier", "verifySF", new Boolean(result));
+ return result;
+ }
+
+ /**
+ * This method is called after at least one signer (usually a key-store
+ * <code>alias</code> name) was found to be trusted; i.e. his/her signature
+ * block in the corresponding <code>.DSA</code> file was successfully
+ * verified using his/her public key.
+ * <p>
+ * This method, uses the contents of the corresponding <code>.SF</code> 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 <code>true</code> if all the entries in the corresponding
+ * <code>.SF</code> file have the same hash values as their
+ * alter-ego in the <i>manifest</i> 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("JarVerifier", "verifySFEntries");
+
+ // 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("JarVerifier", "verifySFEntries", new Boolean(result));
+ return result;
+ }
+
+ /**
+ * @param hash Base-64 encoded form of the manifest's digest.
+ * @return <code>true</code> if our computation of the manifest's hash
+ * matches the given value; <code>false</code> 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 <code>true</code> if our computation of the JAR entry's hash
+ * matches the given value; <code>false</code> 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);
+ 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..df5c3bb08
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/Main.java
@@ -0,0 +1,457 @@
+/* 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 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.UnrecoverableKeyException;
+import java.security.cert.CRLException;
+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;
+
+import gnu.classpath.SystemProperties;
+import gnu.java.security.OID;
+import gnu.java.security.Registry;
+import gnu.javax.security.auth.callback.ConsoleCallbackHandler;
+
+/**
+ * The GNU Classpath implementation of the <i>jarsigner</i> tool.
+ * <p>
+ * The <i>jarsigner</i> tool is used to sign and verify JAR (Java ARchive)
+ * files.
+ * <p>
+ * 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";
+ private static final Locale EN_US_LOCALE = new Locale("en", "US");
+ static final String DIGEST = "SHA1-Digest";
+ static final String DIGEST_MANIFEST = "SHA1-Digest-Manifest";
+ 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;
+
+ private Provider provider;
+ private char[] ksPasswordChars;
+ private KeyStore store;
+ private char[] passwordChars;
+ private PrivateKey signerPrivateKey;
+ private Certificate[] signerCertificateChain;
+
+ private Main(String[] args) throws KeyStoreException, InstantiationException,
+ IllegalAccessException, ClassNotFoundException, NoSuchAlgorithmException,
+ CertificateException, IOException, UnrecoverableKeyException,
+ UnsupportedCallbackException
+ {
+ super();
+
+ processArgs(args);
+ }
+
+ public static final void main(String[] args) throws IOException,
+ CRLException, CertificateException
+ {
+ log.entering("Main", "main", args);
+
+ Main tool;
+ try
+ {
+ tool = new Main(args);
+ tool.start();
+ }
+ catch (SecurityException x)
+ {
+ log.throwing("Main", "main", x);
+ System.err.println("jarsigner: " + x.getMessage());
+ }
+ catch (Exception x)
+ {
+ log.throwing("Main", "main", x);
+ System.err.println("jarsigner error: " + x);
+ }
+
+ log.exiting("Main", "main");
+ // System.exit(0);
+ }
+
+ // helper methods -----------------------------------------------------------
+
+ /**
+ * @param args
+ * @throws KeyStoreException
+ * @throws ClassNotFoundException
+ * @throws IllegalAccessException
+ * @throws InstantiationException
+ * @throws IOException
+ * @throws CertificateException
+ * @throws NoSuchAlgorithmException
+ * @throws UnsupportedCallbackException
+ * @throws UnrecoverableKeyException
+ */
+ private void processArgs(String[] args) throws KeyStoreException,
+ InstantiationException, IllegalAccessException, ClassNotFoundException,
+ NoSuchAlgorithmException, CertificateException, IOException,
+ UnrecoverableKeyException, UnsupportedCallbackException
+ {
+ log.entering("Main", "processArgs", args);
+
+ int limit = args.length;
+ log.finest("args.length=" + limit);
+ int i = 0;
+ String opt;
+ while (i < limit)
+ {
+ opt = args[i++];
+ log.finest("args[" + (i - 1) + "]=" + opt);
+ if (opt == null || opt.length() == 0)
+ continue;
+
+ if ("-verify".equals(opt)) // -verify
+ verify = true;
+ else if ("-keystore".equals(opt)) // -keystore URL
+ ksURL = args[i++];
+ else if ("-storetype".equals(opt)) // -storetype STORE_TYPE
+ ksType = args[i++];
+ else if ("-storepass".equals(opt)) // -storepass PASSWORD
+ ksPassword = args[i++];
+ else if ("-keypass".equals(opt)) // -keypass PASSWORD
+ password = args[i++];
+ else if ("-sigfile".equals(opt)) // -sigfile NAME
+ sigFileName = args[i++];
+ else if ("-signedjar".equals(opt)) // -signedjar FILE_NAME
+ signedJarFileName = args[i++];
+ else if ("-verbose".equals(opt)) // -verbose
+ verbose = true;
+ else if ("-certs".equals(opt)) // -certs
+ certs = true;
+ else if ("-internalsf".equals(opt)) // -internalsf
+ internalSF = true;
+ else if ("-sectionsonly".equals(opt)) // -sectionsonly
+ sectionsOnly = true;
+ else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME
+ providerClassName = args[i++];
+ else
+ {
+ jarFileName = opt;
+ if (! verify)
+ alias = args[i++];
+
+ break;
+ }
+ }
+
+ if (i < limit) // more options than needed
+ log.warning("Last argument is assumed at index #" + (i - 1)
+ + ". Remaining arguments (" + args[i]
+ + "...) will be ignored");
+
+ setupCommonParams();
+ if (verify)
+ {
+ log.info("Will verify with the following parameters:");
+ log.info(" jar-file = '" + jarFileName + "'");
+ log.info("Options:");
+ log.info(" provider = '" + providerClassName + "'");
+ log.info(" verbose ? " + verbose);
+ log.info(" certs ? " + certs);
+ log.info(" internalsf ? " + internalSF);
+ log.info(" sectionsonly ? " + sectionsOnly);
+ }
+ else // sign
+ {
+ setupSigningParams();
+
+ log.info("Will sign with the following parameters:");
+ log.info(" jar-file = '" + jarFileName + "'");
+ log.info(" alias = '" + alias + "'");
+ log.info("Options:");
+ log.info(" keystore = '" + ksURL + "'");
+ log.info(" storetype = '" + ksType + "'");
+ log.info(" storepass = '" + ksPassword + "'");
+ log.info(" keypass = '" + password + "'");
+ log.info(" sigfile = '" + sigFileName + "'");
+ log.info(" signedjar = '" + signedJarFileName + "'");
+ log.info(" provider = '" + providerClassName + "'");
+ log.info(" verbose ? " + verbose);
+ log.info(" internalsf ? " + internalSF);
+ log.info(" sectionsonly ? " + sectionsOnly);
+ }
+
+ log.exiting("Main", "processArgs");
+ }
+
+ private void start() throws IOException, CRLException, CertificateException
+ {
+ log.entering("Main", "start");
+
+ if (verify)
+ {
+ JarVerifier jv = new JarVerifier(this);
+ jv.start();
+ }
+ else
+ {
+ JarSigner js = new JarSigner(this);
+ js.start();
+ }
+
+ log.exiting("Main", "start");
+ }
+
+ private void setupCommonParams() throws InstantiationException,
+ IllegalAccessException, ClassNotFoundException, IOException
+ {
+ log.entering("Main", "setupCommonParams");
+
+ File jar = new File(jarFileName);
+ if (! jar.exists())
+ throw new FileNotFoundException(jarFileName);
+
+ if (jar.isDirectory())
+ throw new IOException("JAR file [" + jarFileName
+ + "] is NOT a file object");
+ if (! jar.canRead())
+ throw new IOException("JAR file [" + jarFileName + "] is NOT readable");
+
+ if (providerClassName != null && providerClassName.length() > 0)
+ provider = (Provider) Class.forName(providerClassName).newInstance();
+
+ if (! verbose && certs)
+ {
+ log.warning("Option <certs> is set but <verbose> is not. Ignored");
+ certs = false;
+ }
+
+ log.exiting("Main", "setupCommonParams");
+ }
+
+ private void setupSigningParams() throws KeyStoreException, IOException,
+ NoSuchAlgorithmException, CertificateException,
+ UnsupportedCallbackException, UnrecoverableKeyException
+ {
+ log.entering("Main", "setupSigningParams");
+
+ if (ksURL == null || ksURL.trim().length() == 0)
+ {
+ String userHome = SystemProperties.getProperty("user.home");
+ if (userHome == null || userHome.trim().length() == 0)
+ throw new SecurityException("Option '-keystore' is not defined or"
+ + " is an empty string, and 'user.home'"
+ + " is unknown");
+ ksURL = "file:" + userHome.trim() + "/.keystore";
+ }
+ else
+ {
+ ksURL = ksURL.trim();
+ if (ksURL.indexOf(":") == -1)
+ ksURL = "file:" + ksURL;
+ }
+
+ if (ksType == null || ksType.trim().length() == 0)
+ ksType = KeyStore.getDefaultType();
+ else
+ ksType = ksType.trim();
+
+ if (provider != null)
+ store = KeyStore.getInstance(ksType, provider);
+ else
+ store = KeyStore.getInstance(ksType);
+
+ if (ksPassword == null)
+ {
+ // ask the user to provide one
+ CallbackHandler handler = new ConsoleCallbackHandler();
+ PasswordCallback pcb = new PasswordCallback("Enter keystore password: ",
+ false);
+ handler.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 (! store.containsAlias(alias))
+ throw new SecurityException("Designated alias [" + alias
+ + "] MUST be known to the key store in use");
+ if (! store.isKeyEntry(alias))
+ throw new SecurityException("Designated alias [" + alias
+ + "] MUST be an Alias of a Key Entry");
+ Key key;
+ if (password == null)
+ {
+ passwordChars = ksPasswordChars;
+ try
+ {
+ key = store.getKey(alias, passwordChars);
+ }
+ catch (UnrecoverableKeyException x)
+ {
+ // ask the user to provide one
+ CallbackHandler handler = new ConsoleCallbackHandler();
+ PasswordCallback pcb = new PasswordCallback("Enter key password for "
+ + alias + ": ", false);
+ handler.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("Key associated with " + alias
+ + " MUST be a private key");
+ 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("Main", "setupSigningParams");
+ }
+
+ 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;
+ }
+}
diff --git a/tools/gnu/classpath/tools/jarsigner/SFHelper.java b/tools/gnu/classpath/tools/jarsigner/SFHelper.java
new file mode 100644
index 000000000..cbf5f356b
--- /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");
+
+ 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 <code>.SF</code> file to the designated JAR
+ * output stream. Line-endings are platform-independent and consist of the
+ * 2-codepoint sequence <code>0x0D</code> and <code>0x0A</code>.
+ *
+ * @param jar the JAR output stream to write a <code>.SF</code> 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("Helper is NOT finished");
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ JarUtils.writeSFManifest(sfMainAttributes, sfEntries, baos);
+ sfBytes = baos.toByteArray();
+ log.finest("\n" + Util.dumpString(sfBytes, "+++ sfBytes "));
+ 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.
+ * <p>
+ * The ContentInfo ASN.1 syntax is as described in the "PKCS#7 Cryptographic
+ * Message Syntax Standard" (RSA Labs) specifications:
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
+ * }
+ *
+ * ContentType ::= OBJECT IDENTIFIER
+ * </pre>
+ * <p>
+ * 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:
+ * <pre>
+ * 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
+ * </pre>
+ * <p>
+ * Finally the SignerInfo is a per-signer structure. Its ASN.1 syntax looks
+ * like so:
+ * <pre>
+ * 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
+ * </pre>
+ *
+ * @param jar the JAR output stream to write a <code>.DSA</code> file to.
+ * @param signerKey the private key to sign with.
+ * @param certificates the possibly null signer certificate chain.
+ * @param internalSF if <code>true</code> 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(".SF file has NOT been generated");
+
+ log.finest("+++ signer private key = " + signerKey);
+ 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("Unknown or unsupported private key algorithm");
+
+ 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 "));
+
+ 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("Helper is NOT ready");
+
+ 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("Helper is NOT started");
+
+ String name = entry.getName();
+ InputStream jeis = jar.getInputStream(entry);
+ String hash = util.hashStream(jeis);
+ log.finer("Hash of " + name + " = " + hash);
+
+ Attributes mainfestAttributes = manifest.getAttributes(name);
+ if (mainfestAttributes == null)
+ {
+ mainfestAttributes = new Attributes();
+ manifest.getEntries().put(name, mainfestAttributes);
+ }
+
+ mainfestAttributes.putValue(Main.DIGEST_ATTR, 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_ATTR, sfHash);
+ log.finest("Name: " + name);
+ log.finest(Main.DIGEST + ": " + sfHash);
+ log.finest("");
+ }
+
+ /**
+ * @param sectionsOnly whether to compute, in addition to the files, the hash
+ * of the mainfest itself (<code>false</code>) or not (<code>true</code>).
+ */
+ void finishSigning(boolean sectionsOnly) throws IOException
+ {
+ if (state != STARTED)
+ throw new IllegalStateException("Helper is NOT started");
+
+ if (sectionsOnly)
+ return;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ manifest.write(baos);
+ baos.flush();
+ String manifestHash = util.hashByteArray(baos.toByteArray());
+ log.fine("Hashed Manifest " + manifestHash);
+ sfMainAttributes.putValue(Main.DIGEST_MANIFEST_ATTR, 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..167f6301e
--- /dev/null
+++ b/tools/gnu/classpath/tools/jarsigner/jarsigner.txt
@@ -0,0 +1,101 @@
+Java ARchive (JAR) file signing and verification tool.
+
+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:
+ jarsigner [options] jar-file alias
+ jarsigner -verify [options] jar-file
+
+ 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.
+
+ The <jar-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> is the Keystore alias to use for signing the <jar-file>.
+
+
+ When the tool is used for signing a JAR file, the possible <options> include:
+ -keystore URL
+ Indicates to the tool that the Keystore located at the
+ designated <URL> must be used. When this option is missing,
+ the tool, by default, will look for a Keystore named
+ ".keystore" in the current User's home directory; i.e. the
+ value of the System property named "user.home".
+
+ If the <URL> is 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 Keystore --as if the
+ protocol was "file:".
+
+ -storetype STORE_TYPE
+ Designates the type of Keystore to expect. The default value
+ 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
+ Designates the <PASSWORD> to use when accessing the Keystore.
+ If this option is missing, the User will be prompted to provide
+ one.
+
+ -keypass PASSWORD
+ Designates the <PASSWORD> protecting the private key to use,
+ from the Keystore, for signing the JAR file. If this option is
+ missing, the User will be prompted to provide one.
+
+ -sigfile NAME
+ Designates a literal that will be used to construct file names
+ for the .SF and .DSA signature files which will be generated
+ and placed in the MET-INF directory of the signed JAR.
+ Permissible characters for <NAME> must be in the range
+ "a-zA-Z0-9_-". All characters will be converted by the tool 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
+ If present, <FILE_NAME> will be used as the name of the signed
+ JAR. If this option is not present, then the signed JAR will
+ be named the same as <jar-file>; i.e. the input JAR will be
+ replaced with the signed one.
+
+
+ When the tool is used for verifying a JAR file, the possible options include:
+ -verify Indicates 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.
+
+
+ Other options, common to both signing and verification include:
+ -verbose Specifies that the tool should generate more 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
+ Designates an implementation of the Provider interface to use
+ for obtaining cryptographic algorithm implementations required
+ by this tool to perform its functions; specifically the
+ implementation of the Security Provider capable of managing a
+ Key Store of the designated, or default, type.
+
diff --git a/tools/gnu/classpath/tools/rmi/RMIC.java b/tools/gnu/classpath/tools/rmi/RMIC.java
index 09021dd3f..ffcd0db0e 100644
--- a/tools/gnu/classpath/tools/rmi/RMIC.java
+++ b/tools/gnu/classpath/tools/rmi/RMIC.java
@@ -114,6 +114,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 <options> <class names>
-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)*