aboutsummaryrefslogtreecommitdiff
path: root/libjava/gnu/java/security
diff options
context:
space:
mode:
authorMichael Koch <konqueror@gmx.de>2003-04-30 07:23:42 +0000
committerMichael Koch <mkoch@gcc.gnu.org>2003-04-30 07:23:42 +0000
commit43905ff30b187d8d1d1dee50e722f47fd8a93144 (patch)
tree89373f6e7f4c07ae0c9c6eeebf05fcb7bbcdfa36 /libjava/gnu/java/security
parent505b0fd661e21182856cfcf73ed6f39c707ac28b (diff)
downloadgcc-43905ff30b187d8d1d1dee50e722f47fd8a93144.zip
gcc-43905ff30b187d8d1d1dee50e722f47fd8a93144.tar.gz
gcc-43905ff30b187d8d1d1dee50e722f47fd8a93144.tar.bz2
Engine.java, [...]: New files from classpath.
2003-04-30 Michael Koch <konqueror@gmx.de> * gnu/java/security/Engine.java, gnu/java/security/OID.java, gnu/java/security/der/BitString.java, gnu/java/security/der/DER.java, gnu/java/security/der/DERReader.java, gnu/java/security/der/DERValue.java, gnu/java/security/der/DERWriter.java, gnu/java/security/provider/DSAKeyFactory.java, gnu/java/security/provider/X509CertificateFactory.java, gnu/java/security/x509/X500DistinguishedName.java, gnu/java/security/x509/X509CRL.java, gnu/java/security/x509/X509CRLEntry.java, gnu/java/security/x509/X509Certificate.java, java/security/cert/CRLSelector.java, java/security/cert/CertPathBuilder.java, java/security/cert/CertPathBuilderResult.java, java/security/cert/CertPathBuilderSpi.java, java/security/cert/CertPathParameters.java, java/security/cert/CertPathValidator.java, java/security/cert/CertPathValidatorResult.java, java/security/cert/CertPathValidatorSpi.java, java/security/cert/CertSelector.java, java/security/cert/CertStore.java, java/security/cert/CertStoreParameters.java, java/security/cert/CertStoreSpi.java, java/security/cert/CollectionCertStoreParameters.java, java/security/cert/LDAPCertStoreParameters.java, java/security/cert/PKIXBuilderParameters.java, java/security/cert/PKIXCertPathBuilderResult.java, java/security/cert/PKIXCertPathChecker.java, java/security/cert/PKIXCertPathValidatorResult.java, java/security/cert/PKIXParameters.java, java/security/cert/PolicyNode.java, java/security/cert/PolicyQualifierInfo.java, java/security/cert/TrustAnchor.java, javax/security/auth/x500/X500Principal.java: New files from classpath. * gnu/java/io/ASN1ParsingException.java, gnu/java/io/Base64InputStream.java, gnu/java/security/der/DEREncodingException.java, gnu/java/security/provider/DSAParameters.java, gnu/java/security/provider/DSASignature.java, gnu/java/security/provider/Gnu.java, gnu/java/security/provider/GnuDSAPrivateKey.java, gnu/java/security/provider/GnuDSAPublicKey.java, java/security/AlgorithmParameterGenerator.java, java/security/AlgorithmParameters.java, java/security/KeyFactory.java, java/security/KeyPairGenerator.java, java/security/KeyStore.java, java/security/MessageDigest.java, java/security/SecureClassLoader.java, java/security/SecureRandom.java, java/security/Security.java, java/security/Signature.java, java/security/cert/Certificate.java, java/security/cert/CertificateFactory.java, java/security/cert/CertificateFactorySpi.java, java/security/cert/X509CRL.java, java/security/cert/X509Certificate.java, java/security/spec/DSAPublicKeySpec.java: New versions from classpath. * gnu/java/security/provider/DERReader.java, gnu/java/security/provider/DERWriter.java, java/security/Engine.java: Removed. * Makefile.am (java_source_files, javax_source_files): Added new files. * Makefile.in: Regenerated. From-SVN: r66283
Diffstat (limited to 'libjava/gnu/java/security')
-rw-r--r--libjava/gnu/java/security/Engine.java237
-rw-r--r--libjava/gnu/java/security/OID.java511
-rw-r--r--libjava/gnu/java/security/der/BitString.java317
-rw-r--r--libjava/gnu/java/security/der/DER.java90
-rw-r--r--libjava/gnu/java/security/der/DEREncodingException.java7
-rw-r--r--libjava/gnu/java/security/der/DERReader.java382
-rw-r--r--libjava/gnu/java/security/der/DERValue.java168
-rw-r--r--libjava/gnu/java/security/der/DERWriter.java324
-rw-r--r--libjava/gnu/java/security/provider/DERReader.java152
-rw-r--r--libjava/gnu/java/security/provider/DERWriter.java142
-rw-r--r--libjava/gnu/java/security/provider/DSAKeyFactory.java134
-rw-r--r--libjava/gnu/java/security/provider/DSAParameters.java54
-rw-r--r--libjava/gnu/java/security/provider/DSASignature.java40
-rw-r--r--libjava/gnu/java/security/provider/Gnu.java27
-rw-r--r--libjava/gnu/java/security/provider/GnuDSAPrivateKey.java6
-rw-r--r--libjava/gnu/java/security/provider/GnuDSAPublicKey.java8
-rw-r--r--libjava/gnu/java/security/provider/X509CertificateFactory.java269
-rw-r--r--libjava/gnu/java/security/x509/X500DistinguishedName.java824
-rw-r--r--libjava/gnu/java/security/x509/X509CRL.java404
-rw-r--r--libjava/gnu/java/security/x509/X509CRLEntry.java236
-rw-r--r--libjava/gnu/java/security/x509/X509Certificate.java693
21 files changed, 4694 insertions, 331 deletions
diff --git a/libjava/gnu/java/security/Engine.java b/libjava/gnu/java/security/Engine.java
new file mode 100644
index 0000000..9f6568c
--- /dev/null
+++ b/libjava/gnu/java/security/Engine.java
@@ -0,0 +1,237 @@
+/* Engine -- generic getInstance method.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+
+/**
+ * Generic implementation of the getInstance methods in the various
+ * engine classes in java.security.
+ * <p>
+ * These classes ({@link java.security.Signature} for example) can be
+ * thought of as the "chrome, upholstery, and steering wheel", and the SPI
+ * (service provider interface, e.g. {@link java.security.SignatureSpi})
+ * classes can be thought of as the "engine" -- providing the actual
+ * functionality of whatever cryptographic algorithm the instance
+ * represents.
+ *
+ * @see Provider
+ * @author Casey Marshall
+ */
+public final class Engine
+{
+
+ // Constants.
+ // ------------------------------------------------------------------------
+
+ /** Prefix for aliases. */
+ private static final String ALG_ALIAS = "Alg.Alias.";
+
+ /** Maximum number of aliases to try. */
+ private static final int MAX_ALIASES = 5;
+
+ /** Argument list for no-argument constructors. */
+ private static final Object[] NO_ARGS = new Object[0];
+
+ // Constructor.
+ // ------------------------------------------------------------------------
+
+ /** This class cannot be instantiated. */
+ private Engine() { }
+
+ // Class method.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get the implementation for <i>algorithm</i> for service
+ * <i>service</i> from <i>provider</i>. The service is e.g.
+ * "Signature", and the algorithm "DSA".
+ *
+ * @param service The service name.
+ * @param algorithm The name of the algorithm to get.
+ * @param provider The provider to get the implementation from.
+ * @return The engine class for the specified algorithm; the object
+ * returned is typically a subclass of the SPI class for that
+ * service, but callers should check that this is so.
+ * @throws NoSuchAlgorithmException If the implementation cannot be
+ * found or cannot be instantiated.
+ * @throws InvocationTargetException If the SPI class's constructor
+ * throws an exception.
+ * @throws IllegalArgumentException If any of the three arguments are null.
+ */
+ public static Object getInstance(String service, String algorithm,
+ Provider provider)
+ throws InvocationTargetException, NoSuchAlgorithmException
+ {
+ return getInstance(service, algorithm, provider, NO_ARGS);
+ }
+
+ /**
+ * Get the implementation for <i>algorithm</i> for service
+ * <i>service</i> from <i>provider</i>, passing <i>initArgs</i> to the
+ * SPI class's constructor (which cannot be null; pass a zero-length
+ * array if the SPI takes no arguments). The service is e.g.
+ * "Signature", and the algorithm "DSA".
+ *
+ * @param service The service name.
+ * @param algorithm The name of the algorithm to get.
+ * @param provider The provider to get the implementation from.
+ * @param initArgs The arguments to pass to the SPI class's
+ * constructor (cannot be null).
+ * @return The engine class for the specified algorithm; the object
+ * returned is typically a subclass of the SPI class for that
+ * service, but callers should check that this is so.
+ * @throws NoSuchAlgorithmException If the implementation cannot be
+ * found or cannot be instantiated.
+ * @throws InvocationTargetException If the SPI class's constructor
+ * throws an exception.
+ * @throws IllegalArgumentException If any of the four arguments are null.
+ */
+ public static Object getInstance(String service, String algorithm,
+ Provider provider, Object[] initArgs)
+ throws InvocationTargetException, NoSuchAlgorithmException
+ {
+ if (service == null || algorithm == null
+ || provider == null || initArgs == null)
+ throw new IllegalArgumentException();
+
+ // If there is no property "service.algorithm"
+ if (provider.getProperty(service + "." + algorithm) == null)
+ {
+ // Iterate through aliases, until we find the class name or resolve
+ // too many aliases.
+ String alias = null;
+ int count = 0;
+ while ((alias = provider.getProperty(
+ ALG_ALIAS + service + "." + algorithm)) != null)
+ {
+ if (algorithm.equals(alias)) // Refers to itself!
+ break;
+ algorithm = alias;
+ if (count++ > MAX_ALIASES)
+ throw new NoSuchAlgorithmException("too many aliases");
+ }
+ if (provider.getProperty(service + "." + algorithm) == null)
+ throw new NoSuchAlgorithmException(algorithm);
+ }
+
+ // Find and instantiate the implementation.
+ Class clazz = null;
+ ClassLoader loader = provider.getClass().getClassLoader();
+ Constructor constructor = null;
+ String error = algorithm;
+
+ try
+ {
+ if (loader != null)
+ clazz = loader.loadClass(provider.getProperty(service+"."+algorithm));
+ else
+ clazz = Class.forName(provider.getProperty(service+"."+algorithm));
+ constructor = getCompatibleConstructor(clazz, initArgs);
+ return constructor.newInstance(initArgs);
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ error = "class not found: " + algorithm;
+ }
+ catch (IllegalAccessException iae)
+ {
+ error = "illegal access: " + iae.getMessage();
+ }
+ catch (InstantiationException ie)
+ {
+ error = "instantiation exception: " + ie.getMessage();
+ }
+ catch (ExceptionInInitializerError eiie)
+ {
+ error = "exception in initializer: " + eiie.getMessage();
+ }
+ catch (SecurityException se)
+ {
+ error = "security exception: " + se.getMessage();
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ error = "no appropriate constructor found";
+ }
+
+ throw new NoSuchAlgorithmException(error);
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Find a constructor in the given class that can take the specified
+ * argument list, allowing any of which to be null.
+ *
+ * @param clazz The class from which to get the constructor.
+ * @param initArgs The argument list to be passed to the constructor.
+ * @return The constructor.
+ * @throws NoSuchMethodException If no constructor of the given class
+ * can take the specified argument array.
+ */
+ private static Constructor getCompatibleConstructor(Class clazz,
+ Object[] initArgs)
+ throws NoSuchMethodException
+ {
+ Constructor[] c = clazz.getConstructors();
+ outer:for (int i = 0; i < c.length; i++)
+ {
+ Class[] argTypes = c[i].getParameterTypes();
+ if (argTypes.length != initArgs.length)
+ continue;
+ for (int j = 0; j < argTypes.length; j++)
+ {
+ if (initArgs[j] != null &&
+ !argTypes[j].isAssignableFrom(initArgs[j].getClass()))
+ continue outer;
+ }
+ // If we reach this point, we know this constructor (c[i]) has
+ // the same number of parameters as the target parameter list,
+ // and all our parameters are either (1) null, or (2) assignable
+ // to the target parameter type.
+ return c[i];
+ }
+ throw new NoSuchMethodException();
+ }
+}
diff --git a/libjava/gnu/java/security/OID.java b/libjava/gnu/java/security/OID.java
new file mode 100644
index 0000000..c27ec92
--- /dev/null
+++ b/libjava/gnu/java/security/OID.java
@@ -0,0 +1,511 @@
+/* OID.java -- numeric representation of an object identifier
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.util.StringTokenizer;
+
+import gnu.java.security.der.DEREncodingException;
+
+/**
+ * This immutable class represents an object identifier, or OID.
+ *
+ * <p>OIDs are represented as a series of hierarcical tokens, each of
+ * which is usually represented as a single, unsigned integer. The
+ * hierarchy works so that later tokens are considered within the group
+ * of earlier tokens. Thus, the OID for the Serpent block cipher,
+ * 1.3.6.1.4.1.11591.13.2, is maintained by the GNU project, whose OID
+ * is 1.3.6.1.4.1.11591 (which is, in turn, part of bigger, more general
+ * bodies; the topmost, 1, stands for the OIDs assigned by the
+ * International Standards Organization, ISO).
+ *
+ * <p>OIDs can be represented in a variety of ways, including the
+ * dotted-decimal form we use here.
+ *
+ * <p>OIDs may be relative, in which case the first two elements of the
+ * OID are omitted.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class OID implements Cloneable, Comparable, java.io.Serializable
+{
+
+ // Fields.
+ // ------------------------------------------------------------------------
+
+ /**
+ * The numeric ID structure.
+ */
+ private int[] components;
+
+ /**
+ * The string representation of this OID, in dotted-decimal format.
+ */
+ private transient String strRep;
+
+ /**
+ * The DER encoding of this OID.
+ */
+ private transient byte[] der;
+
+ /**
+ * Whether or not this OID is relative.
+ */
+ private boolean relative;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new OID from the given byte array. The argument (which can
+ * neither be null nor zero-length) is copied to prevent subsequent
+ * modification.
+ *
+ * @param components The numeric IDs.
+ * @throws IllegalArgumentException If <i>components</i> is null or empty.
+ */
+ public OID(int[] components)
+ {
+ this(components, false);
+ }
+
+ /**
+ * Create a new OID from the given byte array. The argument (which can
+ * neither be null nor zero-length) is copied to prevent subsequent
+ * modification.
+ *
+ * @param components The numeric IDs.
+ * @param relative The relative flag.
+ * @throws IllegalArgumentException If <i>components</i> is null or empty.
+ */
+ public OID(int[] components, boolean relative)
+ {
+ if (components == null || components.length == 0)
+ throw new IllegalArgumentException();
+ this.components = (int[]) components.clone();
+ this.relative = relative;
+ }
+
+ /**
+ * Create a new OID from the given dotted-decimal representation.
+ *
+ * @param strRep The string representation of the OID.
+ * @throws IllegalArgumentException If the string does not contain at
+ * least one integer.
+ * @throws NumberFormatException If the string does not contain only
+ * numbers and periods ('.').
+ */
+ public OID(String strRep)
+ {
+ this(strRep, false);
+ }
+
+ /**
+ * Create a new OID from the given dotted-decimal representation.
+ *
+ * @param strRep The string representation of the OID.
+ * @param relative The relative flag.
+ * @throws IllegalArgumentException If the string does not contain at
+ * least one integer.
+ * @throws NumberFormatException If the string does not contain only
+ * numbers and periods ('.').
+ */
+ public OID(String strRep, boolean relative)
+ {
+ this.relative = relative;
+ this.strRep = strRep;
+ components = fromString(strRep);
+ }
+
+ /**
+ * Construct a new OID from the DER bytes in an input stream. This method
+ * does not read the tag or the length field from the input stream, so
+ * the caller must supply the number of octets in this OID's encoded
+ * form.
+ *
+ * @param derIn The DER input stream.
+ * @param len The number of bytes in the encoded form.
+ * @throws IOException If an error occurs reading the OID.
+ */
+ public OID(InputStream derIn, int len) throws IOException
+ {
+ this(derIn, len, false);
+ }
+
+ /**
+ * Construct a new OID from the DER bytes in an input stream. This method
+ * does not read the tag or the length field from the input stream, so
+ * the caller must supply the number of octets in this OID's encoded
+ * form.
+ *
+ * @param derIn The DER input stream.
+ * @param len The number of bytes in the encoded form.
+ * @param relative The relative flag.
+ * @throws IOException If an error occurs reading the OID.
+ */
+ public OID(InputStream derIn, int len, boolean relative) throws IOException
+ {
+ der = new byte[len];
+ derIn.read(der);
+ this.relative = relative;
+ try
+ {
+ components = fromDER(der, relative);
+ }
+ catch (ArrayIndexOutOfBoundsException aioobe)
+ {
+ aioobe.printStackTrace();
+ throw aioobe;
+ }
+ }
+
+ /**
+ * Construct a new OID from the given DER bytes.
+ *
+ * @param encoded The DER encoded OID.
+ * @throws IOException If an error occurs reading the OID.
+ */
+ public OID(byte[] encoded) throws IOException
+ {
+ this(encoded, false);
+ }
+
+ /**
+ * Construct a new OID from the given DER bytes.
+ *
+ * @param root The root OID.
+ * @param encoded The encoded relative OID.
+ * @param relative The relative flag.
+ */
+ public OID(byte[] encoded, boolean relative) throws IOException
+ {
+ der = (byte[]) encoded.clone();
+ this.relative = relative;
+ try
+ {
+ components = fromDER(der, relative);
+ }
+ catch (ArrayIndexOutOfBoundsException aioobe)
+ {
+ aioobe.printStackTrace();
+ throw aioobe;
+ }
+ }
+
+ /**
+ * Our private constructor.
+ */
+ private OID()
+ {
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Return the numeric IDs of this OID. The value returned is copied to
+ * prevent modification.
+ *
+ * @return The IDs in a new integer array.
+ */
+ public int[] getIDs()
+ {
+ return (int[]) components.clone();
+ }
+
+ /**
+ * Get the DER encoding of this OID, minus the tag and length fields.
+ *
+ * @return The DER bytes.
+ */
+ public byte[] getDER()
+ {
+ if (der == null)
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ int i = 0;
+ if (!relative)
+ {
+ int b = components[i++] * 40 + (components.length > 1
+ ? components[i++] : 0);
+ encodeSubID(bout, b);
+ }
+ for ( ; i < components.length; i++)
+ encodeSubID(bout, components[i]);
+ der = bout.toByteArray();
+ }
+ return (byte[]) der.clone();
+ }
+
+ /**
+ * Get the parent OID of this OID. That is, if this OID is "1.2.3.4",
+ * then the parent OID will be "1.2.3". If this OID is a top-level
+ * OID, this method returns null.
+ *
+ * @return The parent OID, or null.
+ */
+ public OID getParent()
+ {
+ if (components.length == 1)
+ return null;
+ int[] parent = new int[components.length - 1];
+ System.arraycopy(components, 0, parent, 0, parent.length);
+ return new OID(parent);
+ }
+
+ public OID getChild(int id)
+ {
+ int[] child = new int[components.length + 1];
+ System.arraycopy(components, 0, child, 0, components.length);
+ child[child.length - 1] = id;
+ return new OID(child);
+ }
+
+ /**
+ * Get the root OID of this OID. That is, the first two components.
+ *
+ * @return The root OID.
+ */
+ public OID getRoot()
+ {
+ if (components.length <= 2)
+ return this;
+ int[] root = new int[2];
+ root[0] = components[0];
+ root[1] = components[1];
+ return new OID(root);
+ }
+
+ public boolean isRelative()
+ {
+ return relative;
+ }
+
+ /**
+ * Returns a copy of this OID.
+ *
+ * @return The copy.
+ */
+ public Object clone()
+ {
+ OID oid = new OID();
+ oid.components = this.components;
+ oid.strRep = this.strRep;
+ return oid;
+ }
+
+ /* Nice idea, but possibly too expensive for whatever benefit it
+ * provides.
+
+ public String getShortName()
+ {
+ return OIDTable.getShortName(this);
+ }
+
+ public String getLongName()
+ {
+ return OIDTable.getLongName(this);
+ }
+
+ */
+
+ /**
+ * Returns the value of this OID in dotted-decimal format.
+ *
+ * @return The string representation.
+ */
+ public String toString()
+ {
+ if (strRep != null)
+ return strRep;
+ else
+ {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < components.length; i++)
+ {
+ buf.append((long) components[i] & 0xFFFFFFFFL);
+ if (i < components.length - 1)
+ buf.append('.');
+ }
+ return (strRep = buf.toString());
+ }
+ }
+
+ /**
+ * Computes a hash code for this OID.
+ *
+ * @return The hash code.
+ */
+ public int hashCode()
+ {
+ int ret = 0;
+ for (int i = 0; i < components.length; i++)
+ ret += components[i] << (i & 31);
+ return ret;
+ }
+
+ /**
+ * Tests whether or not this OID equals another.
+ *
+ * @return Whether or not this OID equals the other.
+ */
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+ return java.util.Arrays.equals(components, ((OID) o).components);
+ }
+
+ /**
+ * Compares this OID to another. The comparison is essentially
+ * lexicographic, where the two OIDs are compared until their
+ * first difference, then that difference is returned. If one OID is
+ * shorter, but all elements equal between the two for the shorter
+ * length, then the shorter OID is lesser than the longer.
+ *
+ * @param o The object to compare.
+ * @return An integer less than, equal to, or greater than zero if
+ * this object is less than, equal to, or greater than the
+ * argument.
+ * @throws ClassCastException If <i>o</i> is not an OID.
+ */
+ public int compareTo(Object o)
+ {
+ if (o == this)
+ return 0;
+ int[] components2 = ((OID) o).components;
+ int len = Math.min(components.length, components2.length);
+ for (int i = 0; i < len; i++)
+ {
+ if (components[i] != components2[i])
+ return (components[i] < components2[i]) ? -1 : 1;
+ }
+ if (components.length == components2.length)
+ return 0;
+ return (components.length < components2.length) ? -1 : 1;
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private static int[] fromDER(byte[] der, boolean relative)
+ throws DEREncodingException
+ {
+ // cannot be longer than this.
+ int[] components = new int[der.length + 1];
+ int count = 0;
+ int i = 0;
+ if (!relative && i < der.length)
+ {
+ // Non-relative OIDs have the first two arcs coded as:
+ //
+ // i = first_arc * 40 + second_arc;
+ //
+ int j = (der[i] & 0xFF);
+ components[count++] = j / 40;
+ components[count++] = j % 40;
+ i++;
+ }
+ while (i < der.length)
+ {
+ int j = 0;
+ do
+ {
+ j = der[i++] & 0xFF;
+ components[count] <<= 7;
+ components[count] |= j & 0x7F;
+ if (i >= der.length && (j & 0x80) != 0)
+ throw new DEREncodingException("malformed OID");
+ }
+ while ((j & 0x80) != 0);
+ count++;
+ }
+ if (count == components.length)
+ return components;
+ int[] ret = new int[count];
+ System.arraycopy(components, 0, ret, 0, count);
+ return ret;
+ }
+
+ private static int[] fromString(String strRep) throws NumberFormatException
+ {
+ if (strRep.startsWith("OID.") || strRep.startsWith("oid."))
+ strRep = strRep.substring(4);
+ StringTokenizer tok = new StringTokenizer(strRep, ".");
+ if (tok.countTokens() == 0)
+ throw new IllegalArgumentException();
+ int[] components = new int[tok.countTokens()];
+ int i = 0;
+ while (tok.hasMoreTokens())
+ {
+ components[i++] = Integer.parseInt(tok.nextToken());
+ }
+ return components;
+ }
+
+ private static void encodeSubID(ByteArrayOutputStream out, int id)
+ {
+ if (id < 128)
+ {
+ out.write(id);
+ }
+ else if (id < 16384)
+ {
+ out.write((id >>> 7) | 0x80);
+ out.write(id & 0x7F);
+ }
+ else if (id < 2097152)
+ {
+ out.write((id >>> 14) | 0x80);
+ out.write(((id >>> 7) | 0x80) & 0xFF);
+ out.write(id & 0x7F);
+ }
+ else if (id < 268435456)
+ {
+ out.write( (id >>> 21) | 0x80);
+ out.write(((id >>> 14) | 0x80) & 0xFF);
+ out.write(((id >>> 7) | 0x80) & 0xFF);
+ out.write(id & 0x7F);
+ }
+ }
+}
diff --git a/libjava/gnu/java/security/der/BitString.java b/libjava/gnu/java/security/der/BitString.java
new file mode 100644
index 0000000..c4c2d9a
--- /dev/null
+++ b/libjava/gnu/java/security/der/BitString.java
@@ -0,0 +1,317 @@
+/* BitString.java -- Java representation of the BIT STRING type.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.der;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+/**
+ * Immutable representation of a bit string, which is equivalent to a
+ * byte array except some number of the rightmost bits are ignored. For
+ * example, this could be the bit string:
+ *
+ * <pre> 00010101 11101101 11010xxx</pre>
+ *
+ * <p>Where the "xxx" represents three bits that should be ignored, and
+ * can have any value.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class BitString implements Cloneable, Comparable, java.io.Serializable
+{
+
+ // Fields.
+ // ------------------------------------------------------------------------
+
+ /** The bits themselves. */
+ private final byte[] bytes;
+
+ /**
+ * The exportable byte array. This array has the ignored bits
+ * removed.
+ */
+ private transient byte[] externBytes;
+
+ /** The number of bits ignored at the end of the byte array. */
+ private final int ignoredBits;
+
+ /** This bit string as a boolean array. */
+ private transient boolean[] boolVal;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new bit string, shifting the given byte array if needed.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param ignoredBits The number of bits to ignore.
+ * @param doShift Pass true in this parameter if the byte array has
+ * not yet been shifted left by <i>ignoredBits</i>.
+ * @throws IllegalArgumentException If <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> is null.
+ */
+ public BitString(byte[] bytes, int ignoredBits, boolean doShift)
+ {
+ this(bytes, 0, bytes.length, ignoredBits, doShift);
+ }
+
+ /**
+ * Create a new bit string, shifting the given byte array if needed.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param offset The offset where the meaningful bytes begin.
+ * @param length The number of meaningful bytes.
+ * @param ignoredBits The number of bits to ignore.
+ * @param doShift Pass true in this parameter if the byte array has
+ * not yet been shifted left by <i>ignoredBits</i>.
+ * @throws IllegalArgumentException If <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> is null.
+ */
+ public BitString(byte[] bytes, int offset, int length,
+ int ignoredBits, boolean doShift)
+ {
+ if (ignoredBits < 0 || ignoredBits > 7)
+ throw new IllegalArgumentException();
+ if (bytes == null)
+ throw new NullPointerException();
+ if (doShift && ignoredBits > 0)
+ {
+ this.externBytes = new byte[length];
+ System.arraycopy(bytes, offset, externBytes, 0, length);
+ this.bytes = new BigInteger(externBytes).shiftLeft(ignoredBits)
+ .toByteArray();
+ }
+ else
+ {
+ this.bytes = new byte[length];
+ System.arraycopy(bytes, offset, this.bytes, 0, length);
+ }
+ this.ignoredBits = ignoredBits;
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param offset The offset where the meaningful bytes begin.
+ * @param length The number of meaningful bytes.
+ * @param ignoredBits The number of bits to ignore.
+ * @throws IllegalArgumentException If <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> is null.
+ */
+ public BitString(byte[] bytes, int offset, int length, int ignoredBits)
+ {
+ this(bytes, offset, length, ignoredBits, false);
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param ignoredBits The number of bits to ignore.
+ * @throws IllegalArgumentException If <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> is null.
+ */
+ public BitString(byte[] bytes, int ignoredBits)
+ {
+ this(bytes, 0, bytes.length, ignoredBits, false);
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @param offset The offset where the meaningful bytes begin.
+ * @param length The number of meaningful bytes.
+ * @throws NullPointerException If <i>bytes</i> is null.
+ */
+ public BitString(byte[] bytes, int offset, int length)
+ {
+ this(bytes, offset, length, 0, false);
+ }
+
+ /**
+ * Create a new bit string.
+ *
+ * @param bytes The byte array holding the bit string.
+ * @throws NullPointerException If <i>bytes</i> is null.
+ */
+ public BitString(byte[] bytes)
+ {
+ this(bytes, 0, bytes.length, 0, false);
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Return this bit string as a byte array, with the ignored bits
+ * trimmed off. The byte array is cloned every time this method is
+ * called to prevent modification.
+ *
+ * @return The trimmed byte array.
+ */
+ public byte[] toByteArray()
+ {
+ if (ignoredBits == 0)
+ return (byte[]) bytes.clone();
+ if (externBytes == null)
+ externBytes = new BigInteger(bytes).shiftRight(ignoredBits).toByteArray();
+ return (byte[]) externBytes.clone();
+ }
+
+ /**
+ * Returns this bit string as a byte array, with the ignored bits
+ * present. The byte array is cloned every time this method is
+ * called to prevent modification.
+ *
+ * @return The byte array.
+ */
+ public byte[] getShiftedByteArray()
+ {
+ return (byte[]) bytes.clone();
+ }
+
+ /**
+ * Returns the number of ignored bits.
+ *
+ * @return The number of ignored bits.
+ */
+ public int getIgnoredBits()
+ {
+ return ignoredBits;
+ }
+
+ /**
+ * Returns the size, in bits, of this bit string.
+ *
+ * @return The size of this bit string.
+ */
+ public int size()
+ {
+ return (bytes.length << 3) - ignoredBits;
+ }
+
+ /**
+ * Return this bit string as a boolean array. The value returned is of
+ * size {@link #size()}, and each <code>true</code> value
+ * corresponding to each "1" in this bit string. The boolean array is
+ * cloned before it is returned.
+ *
+ * @return The boolean array.
+ */
+ public boolean[] toBooleanArray()
+ {
+ if (boolVal == null)
+ {
+ boolVal = new boolean[size()];
+ for (int i = 0, j = 7, k = 0; i < boolVal.length; i++)
+ {
+ boolVal[i] = (bytes[k] & 1 << j--) != 0;
+ if (j < 0)
+ {
+ j = 7;
+ k++;
+ }
+ }
+ }
+ return (boolean[]) boolVal.clone();
+ }
+
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException cce)
+ {
+ throw new InternalError(cce.getMessage());
+ }
+ }
+
+ public int compareTo(Object o)
+ {
+ BitString that = (BitString) o;
+ if (this.equals(that))
+ return 0;
+ if (this.bytes.length != that.bytes.length)
+ return (this.bytes.length < that.bytes.length) ? -1 : 1;
+ if (this.ignoredBits != that.ignoredBits)
+ return (this.ignoredBits < that.ignoredBits) ? -1 : 1;
+ for (int i = 0; i < this.bytes.length; i++)
+ if (this.bytes[i] != that.bytes[i])
+ return (this.bytes[i] < that.bytes[i]) ? -1 : 1;
+ return 0; // not reached.
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+ BitString that = (BitString) o;
+ // True for cloned instances.
+ if (this.bytes == that.bytes && this.ignoredBits == that.ignoredBits)
+ return true;
+ if (this.ignoredBits == that.ignoredBits)
+ return Arrays.equals(this.bytes, that.bytes);
+ return false;
+ }
+
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0, j = 7, k = 0; i < size(); i++)
+ {
+ sb.append((bytes[k] & 1 << j) != 0 ? "1" : "0");
+ j--;
+ if (j < 0)
+ {
+ j = 7;
+ k++;
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/libjava/gnu/java/security/der/DER.java b/libjava/gnu/java/security/der/DER.java
new file mode 100644
index 0000000..9435366
--- /dev/null
+++ b/libjava/gnu/java/security/der/DER.java
@@ -0,0 +1,90 @@
+/* DER.java -- Basic constants in DER sequences.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.der;
+
+/**
+ * The set of tags for DER types.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public interface DER
+{
+
+ // Constants.
+ // ------------------------------------------------------------------------
+
+ public static final int UNIVERSAL = 0x00;
+ public static final int APPLICATION = 0x40;
+ public static final int CONTEXT = 0x80;
+ public static final int PRIVATE = 0xC0;
+
+ public static final int CONSTRUCTED = 0x20;
+
+ public static final int ANY = 0x00;
+ public static final int BOOLEAN = 0x01;
+ public static final int INTEGER = 0x02;
+ public static final int BIT_STRING = 0x03;
+ public static final int OCTET_STRING = 0x04;
+ public static final int NULL = 0x05;
+ public static final int OBJECT_IDENTIFIER = 0x06;
+ public static final int REAL = 0x09;
+ public static final int ENUMERATED = 0x0a;
+ public static final int RELATIVE_OID = 0x0d;
+
+ public static final int SEQUENCE = 0x10;
+ public static final int SET = 0x11;
+
+ public static final Object CONSTRUCTED_VALUE = new Object();
+
+ public static final int NUMERIC_STRING = 0x12;
+ public static final int PRINTABLE_STRING = 0x13;
+ public static final int T61_STRING = 0x14;
+ public static final int VIDEOTEX_STRING = 0x15;
+ public static final int IA5_STRING = 0x16;
+ public static final int GRAPHIC_STRING = 0x19;
+ public static final int ISO646_STRING = 0x1A;
+ public static final int GENERAL_STRING = 0x1B;
+
+ public static final int UTF8_STRING = 0x0C;
+ public static final int UNIVERSAL_STRING = 0x1C;
+ public static final int BMP_STRING = 0x1E;
+
+ public static final int UTC_TIME = 0x17;
+ public static final int GENERALIZED_TIME = 0x18;
+}
diff --git a/libjava/gnu/java/security/der/DEREncodingException.java b/libjava/gnu/java/security/der/DEREncodingException.java
index eea40b8..385fbac 100644
--- a/libjava/gnu/java/security/der/DEREncodingException.java
+++ b/libjava/gnu/java/security/der/DEREncodingException.java
@@ -1,5 +1,5 @@
/* DEREncodingException.java --- DER Encoding Exception
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999,2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,9 +38,10 @@ exception statement from your version. */
package gnu.java.security.der;
-public class DEREncodingException extends Exception
-{
+import java.io.IOException;
+public class DEREncodingException extends IOException
+{
public DEREncodingException()
{
super ();
diff --git a/libjava/gnu/java/security/der/DERReader.java b/libjava/gnu/java/security/der/DERReader.java
new file mode 100644
index 0000000..3020b8b
--- /dev/null
+++ b/libjava/gnu/java/security/der/DERReader.java
@@ -0,0 +1,382 @@
+/* DERReader.java -- parses ASN.1 DER sequences
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.der;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import gnu.java.security.OID;
+
+/**
+ * This class decodes DER sequences into Java objects. The methods of
+ * this class do not have knowledge of higher-levels of structure in the
+ * DER stream -- such as ASN.1 constructions -- and it is therefore up
+ * to the calling application to determine if the data are structured
+ * properly by inspecting the {@link DERValue} that is returned.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class DERReader implements DER
+{
+
+ // Fields.
+ // ------------------------------------------------------------------------
+
+ protected InputStream in;
+
+ protected final ByteArrayOutputStream encBuf;
+
+ // Constructor.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new DER reader from a byte array.
+ *
+ * @param in The encoded bytes.
+ */
+ public DERReader(byte[] in)
+ {
+ this(new ByteArrayInputStream(in));
+ }
+
+ /**
+ * Create a new DER readed from an input stream.
+ *
+ * @param in The encoded bytes.
+ */
+ public DERReader(InputStream in)
+ {
+ if (!in.markSupported())
+ this.in = new BufferedInputStream(in, 16384);
+ else
+ this.in = in;
+ encBuf = new ByteArrayOutputStream(2048);
+ }
+
+ // Class methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Convenience method for reading a single primitive value from the
+ * given byte array.
+ *
+ * @param encoded The encoded bytes.
+ * @throws IOException If the bytes do not represent an encoded
+ * object.
+ */
+ public static DERValue read(byte[] encoded) throws IOException
+ {
+ return new DERReader(encoded).read();
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Decode a single value from the input stream, returning it in a new
+ * {@link DERValue}. By "single value" we mean any single type in its
+ * entirety -- including constructed types such as SEQUENCE and all
+ * the values they contain. Usually it is sufficient to call this
+ * method once to parse and return the top-level structure, then to
+ * inspect the returned value for the proper contents.
+ *
+ * @return The parsed DER structure.
+ * @throws IOException If an error occurs reading from the input
+ * stream.
+ * @throws DEREncodingException If the input does not represent a
+ * valid DER stream.
+ */
+ public DERValue read() throws IOException
+ {
+ int tag = in.read();
+ if (tag == -1)
+ throw new EOFException();
+ encBuf.write(tag);
+ int len = readLength();
+ DERValue value = null;
+ if ((tag & CONSTRUCTED) == CONSTRUCTED)
+ {
+ in.mark(2048);
+ byte[] encoded = new byte[len];
+ in.read(encoded);
+ encBuf.write(encoded);
+ value = new DERValue(tag, len, CONSTRUCTED_VALUE, encBuf.toByteArray());
+ in.reset();
+ encBuf.reset();
+ return value;
+ }
+ switch (tag & 0xC0)
+ {
+ case UNIVERSAL:
+ value = new DERValue(tag, len, readUniversal(tag, len),
+ encBuf.toByteArray());
+ encBuf.reset();
+ break;
+ case CONTEXT:
+ byte[] encoded = new byte[len];
+ in.read(encoded);
+ encBuf.write(encoded);
+ value = new DERValue(tag, len, encoded, encBuf.toByteArray());
+ encBuf.reset();
+ break;
+ case APPLICATION:
+ // This should not be reached, since (I think) APPLICATION is
+ // always constructed.
+ throw new DEREncodingException("non-constructed APPLICATION data");
+ default:
+ throw new DEREncodingException("PRIVATE class not supported");
+ }
+ return value;
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private Object readUniversal(int tag, int len) throws IOException
+ {
+ byte[] value = new byte[len];
+ in.read(value);
+ encBuf.write(value);
+ switch (tag & 0x1F)
+ {
+ case BOOLEAN:
+ if (value.length != 1)
+ throw new DEREncodingException();
+ return Boolean.valueOf(value[0] != 0);
+ case NULL:
+ if (len != 0)
+ throw new DEREncodingException();
+ return null;
+ case INTEGER:
+ case ENUMERATED:
+ return new BigInteger(value);
+ case BIT_STRING:
+ byte[] bits = new byte[len - 1];
+ System.arraycopy(value, 1, bits, 0, bits.length);
+ return new BitString(bits, value[0] & 0xFF);
+ case OCTET_STRING:
+ return value;
+ case NUMERIC_STRING:
+ case PRINTABLE_STRING:
+ case T61_STRING:
+ case VIDEOTEX_STRING:
+ case IA5_STRING:
+ case GRAPHIC_STRING:
+ case ISO646_STRING:
+ case GENERAL_STRING:
+ case UNIVERSAL_STRING:
+ case BMP_STRING:
+ case UTF8_STRING:
+ return makeString(tag, value);
+ case UTC_TIME:
+ case GENERALIZED_TIME:
+ return makeTime(tag, value);
+ case OBJECT_IDENTIFIER:
+ return new OID(value);
+ case RELATIVE_OID:
+ return new OID(value, true);
+ default:
+ throw new DEREncodingException("unknown tag " + tag);
+ }
+ }
+
+ private int readLength() throws IOException
+ {
+ int i = in.read();
+ if (i == -1)
+ throw new EOFException();
+ encBuf.write(i);
+ if ((i & ~0x7F) == 0)
+ {
+ return i;
+ }
+ else if (i < 0xFF)
+ {
+ byte[] octets = new byte[i & 0x7F];
+ in.read(octets);
+ encBuf.write(octets);
+ return new BigInteger(1, octets).intValue();
+ }
+ throw new DEREncodingException();
+ }
+
+ private String makeString(int tag, byte[] value)
+ throws IOException
+ {
+ Charset charset = null;
+ switch (tag & 0x1F)
+ {
+ case NUMERIC_STRING:
+ case PRINTABLE_STRING:
+ case T61_STRING:
+ case VIDEOTEX_STRING:
+ case IA5_STRING:
+ case GRAPHIC_STRING:
+ case ISO646_STRING:
+ case GENERAL_STRING:
+ charset = Charset.forName("ISO-8859-1");
+ break;
+ case UNIVERSAL_STRING:
+ // XXX The docs say UniversalString is encoded in four bytes
+ // per character, but Java has no support (yet) for UTF-32.
+ //return new String(buf, "UTF-32");
+ case BMP_STRING:
+ charset = Charset.forName("UTF-16BE");
+ break;
+ case UTF8_STRING:
+ charset = Charset.forName("UTF-8");
+ break;
+ default:
+ throw new DEREncodingException("unknown string tag");
+ }
+ if (charset == null)
+ throw new DEREncodingException("no decoder");
+ CharsetDecoder decoder = charset.newDecoder();
+ CharBuffer result = decoder.decode(ByteBuffer.wrap(value));
+ char[] buf = new char[result.remaining()];
+ result.get(buf);
+ return new String(buf);
+ }
+
+ private Date makeTime(int tag, byte[] value) throws IOException
+ {
+ Calendar calendar = Calendar.getInstance();
+ String str = makeString(PRINTABLE_STRING, value);
+
+ // Classpath's SimpleDateFormat does not work for parsing these
+ // types of times, so we do this by hand.
+ String date = str;
+ String tz = "";
+ if (str.indexOf("+") > 0)
+ {
+ date = str.substring(0, str.indexOf("+"));
+ tz = str.substring(str.indexOf("+"));
+ }
+ else if (str.indexOf("-") > 0)
+ {
+ date = str.substring(0, str.indexOf("-"));
+ tz = str.substring(str.indexOf("-"));
+ }
+ else if (str.endsWith("Z"))
+ {
+ date = str.substring(0, str.length()-2);
+ tz = "Z";
+ }
+ if (!tz.equals("Z") && tz.length() > 0)
+ calendar.setTimeZone(TimeZone.getTimeZone(tz));
+ else
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ if ((tag & 0x1F) == UTC_TIME)
+ {
+ if (date.length() < 10) // must be at least 10 chars long
+ throw new DEREncodingException("cannot parse date");
+ // UTCTime is of the form "yyMMddHHmm[ss](Z|(+|-)hhmm)"
+ try
+ {
+ int year = Integer.parseInt(str.substring(0, 2));
+ if (year < 50)
+ year += 2000;
+ else
+ year += 1900;
+ calendar.set(year,
+ Integer.parseInt(str.substring( 2, 4))-1, // month
+ Integer.parseInt(str.substring( 4, 6)), // day
+ Integer.parseInt(str.substring( 6, 8)), // hour
+ Integer.parseInt(str.substring( 8, 10))); // minute
+ if (date.length() == 12);
+ calendar.set(calendar.SECOND,
+ Integer.parseInt(str.substring(10, 12)));
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw new DEREncodingException("cannot parse date");
+ }
+ }
+ else
+ {
+ if (date.length() < 10) // must be at least 10 chars long
+ throw new DEREncodingException("cannot parse date");
+ // GeneralTime is of the form "yyyyMMddHH[mm[ss[(.|,)SSSS]]]"
+ // followed by "Z" or "(+|-)hh[mm]"
+ try
+ {
+ calendar.set(
+ Integer.parseInt(date.substring(0, 4)), // year
+ Integer.parseInt(date.substring(4, 6))-1, // month
+ Integer.parseInt(date.substring(6, 8)), // day
+ Integer.parseInt(date.substring(8, 10)), 0); // hour, min
+ switch (date.length())
+ {
+ case 19:
+ case 18:
+ case 17:
+ case 16:
+ calendar.set(calendar.MILLISECOND,
+ Integer.parseInt(date.substring(15)));
+ case 14:
+ calendar.set(calendar.SECOND,
+ Integer.parseInt(date.substring(12, 14)));
+ case 12:
+ calendar.set(calendar.MINUTE,
+ Integer.parseInt(date.substring(10, 12)));
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw new DEREncodingException("cannot parse date");
+ }
+ }
+ return calendar.getTime();
+ }
+}
diff --git a/libjava/gnu/java/security/der/DERValue.java b/libjava/gnu/java/security/der/DERValue.java
new file mode 100644
index 0000000..dd8afc4
--- /dev/null
+++ b/libjava/gnu/java/security/der/DERValue.java
@@ -0,0 +1,168 @@
+/* DERValue.java -- a value read or written to a DER encoding.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.der;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class DERValue implements DER
+{
+
+ // Fields.
+ // ------------------------------------------------------------------------
+
+ private final int tagClass;
+
+ private final boolean constructed;
+
+ private final int tag;
+
+ private int length;
+
+ private final Object value;
+
+ private byte[] encoded;
+
+ // Constructor.
+ // ------------------------------------------------------------------------
+
+ public DERValue(int tag, int length, Object value, byte[] encoded)
+ {
+ tagClass = tag & 0xC0;
+ this.tag = tag & 0x1F;
+ constructed = (tag & CONSTRUCTED) == CONSTRUCTED;
+ this.length = length;
+ this.value = value;
+ if (encoded != null)
+ this.encoded = (byte[]) encoded.clone();
+ }
+
+ public DERValue(int tag, Object value)
+ {
+ this(tag, 0, value, null);
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ public int getExternalTag()
+ {
+ return tagClass | tag | (constructed ? 0x20 : 0x00);
+ }
+
+ public int getTag()
+ {
+ return tag;
+ }
+
+ public int getTagClass()
+ {
+ return tagClass;
+ }
+
+ public boolean isConstructed()
+ {
+ return constructed;
+ }
+
+ public int getLength()
+ {
+ if (encoded == null)
+ {
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ length = DERWriter.write(out, this);
+ encoded = out.toByteArray();
+ }
+ catch (IOException ioe)
+ {
+ encoded = new byte[0];
+ }
+ }
+ return length;
+ }
+
+ public Object getValue()
+ {
+ return value;
+ }
+
+ public byte[] getEncoded()
+ {
+ if (encoded == null)
+ {
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ length = DERWriter.write(out, this);
+ encoded = out.toByteArray();
+ }
+ catch (IOException ioe)
+ {
+ encoded = new byte[0];
+ }
+ }
+ return (byte[]) encoded.clone();
+ }
+
+ public int getEncodedLength()
+ {
+ if (encoded == null)
+ {
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ length = DERWriter.write(out, this);
+ encoded = out.toByteArray();
+ }
+ catch (IOException ioe)
+ {
+ encoded = new byte[0];
+ }
+ }
+ return encoded.length;
+ }
+
+ public String toString()
+ {
+ return "DERValue [ tag=" + tag + ", class=" + tagClass + ", constructed="
+ + constructed + ", value=" + value + " ]";
+ }
+}
diff --git a/libjava/gnu/java/security/der/DERWriter.java b/libjava/gnu/java/security/der/DERWriter.java
new file mode 100644
index 0000000..ec3e3df
--- /dev/null
+++ b/libjava/gnu/java/security/der/DERWriter.java
@@ -0,0 +1,324 @@
+/* DERWriter.java -- write Java types in DER format.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.der;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+
+import java.text.SimpleDateFormat;
+
+import java.util.BitSet;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+
+import gnu.java.security.OID;
+
+/**
+ * Methods that allow various Java types to be written as a DER
+ * (Distinguished Encoding Rules) stream to the specified output stream.
+ * DER is used to encode ASN.1 constructions, but this class provides no
+ * methods for interacting with ASN.1. Rather, callers should construct
+ * their output objects properly for whatever ASN.1 construct is being
+ * output.
+ *
+ * <p>This class only defines static methods; there are no instance
+ * variables needed.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class DERWriter implements DER
+{
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ /** This class only has static methods. */
+ private DERWriter()
+ {
+ }
+
+ // Class methods.
+ // ------------------------------------------------------------------------
+
+ public static int write(OutputStream out, DERValue object)
+ throws IOException
+ {
+ out.write(object.getExternalTag());
+ Object value = object.getValue();
+ if (value == null)
+ {
+ writeLength(out, 0);
+ return 0;
+ }
+ if (value instanceof Boolean)
+ return writeBoolean(out, (Boolean) value);
+ else if (value instanceof BigInteger)
+ return writeInteger(out, (BigInteger) value);
+ else if (value instanceof Date)
+ return writeDate(out, object.getExternalTag(), (Date) value);
+ else if (value instanceof String)
+ return writeString(out, object.getExternalTag(), (String) value);
+ else if (value instanceof List)
+ return writeSequence(out, (List) value);
+ else if (value instanceof Set)
+ return writeSet(out, (Set) value);
+ else if (value instanceof BitString)
+ return writeBitString(out, (BitString) value);
+ else if (value instanceof OID)
+ return writeOID(out, (OID) value);
+ else if (value instanceof byte[])
+ {
+ writeLength(out, ((byte[]) value).length);
+ out.write((byte[]) value);
+ return ((byte[]) value).length;
+ }
+ else if (value instanceof DERValue)
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ write(bout, (DERValue) value);
+ byte[] buf = bout.toByteArray();
+ writeLength(out, buf.length);
+ out.write(buf);
+ return buf.length;
+ }
+ else
+ throw new DEREncodingException("cannot encode " + value.getClass().getName());
+ }
+
+ public static int definiteEncodingSize(int length)
+ {
+ if (length < 128)
+ return 1;
+ else if (length < 256)
+ return 2;
+ else if (length < 65536)
+ return 3;
+ else if (length < 16777216)
+ return 4;
+ else
+ return 5;
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Write a BOOLEAN type to the given output stream.
+ *
+ * @param out The sink output stream.
+ * @param b The boolean value to write.
+ */
+ private static int writeBoolean(OutputStream out, Boolean b)
+ throws IOException
+ {
+ writeLength(out, 1);
+ if (b.booleanValue())
+ out.write(0xFF);
+ else
+ out.write(0);
+ return 1;
+ }
+
+ /**
+ * Write an INTEGER type to the given output stream.
+ *
+ * @param out The sink output stream.
+ * @param integer The integer to write.
+ */
+ private static int writeInteger(OutputStream out, BigInteger integer)
+ throws IOException
+ {
+ byte[] bytes = integer.toByteArray();
+ writeLength(out, bytes.length);
+ out.write(bytes);
+ return bytes.length;
+ }
+
+ private static int writeSequence(OutputStream out, List sequence)
+ throws IOException
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ for (Iterator i = sequence.iterator(); i.hasNext(); )
+ {
+ write(bout, (DERValue) i.next());
+ }
+ byte[] buf = bout.toByteArray();
+ writeLength(out, buf.length);
+ out.write(buf);
+ return buf.length;
+ }
+
+ private static int writeSet(OutputStream out, Set set)
+ throws IOException
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ for (Iterator i = set.iterator(); i.hasNext(); )
+ {
+ write(bout, (DERValue) i.next());
+ }
+ byte[] buf = bout.toByteArray();
+ writeLength(out, buf.length);
+ out.write(buf);
+ return buf.length;
+ }
+
+ private static int writeOID(OutputStream out, OID oid)
+ throws IOException
+ {
+ byte[] der = oid.getDER();
+ writeLength(out, der.length);
+ out.write(der);
+ return der.length;
+ }
+
+ private static int writeBitString(OutputStream out, BitString bs)
+ throws IOException
+ {
+ byte[] buf = bs.getShiftedByteArray();
+ out.write(buf.length + 1);
+ out.write(bs.getIgnoredBits());
+ out.write(buf);
+ return buf.length;
+ }
+
+ private static int writeString(OutputStream out, int tag, String str)
+ throws IOException
+ {
+ Charset charset = null;
+ byte[] b = null;
+ switch (tag & 0x1F)
+ {
+ case NUMERIC_STRING:
+ case PRINTABLE_STRING:
+ case T61_STRING:
+ case VIDEOTEX_STRING:
+ case IA5_STRING:
+ case GRAPHIC_STRING:
+ case ISO646_STRING:
+ case GENERAL_STRING:
+ charset = Charset.forName("ISO-8859-1");
+ break;
+ case UNIVERSAL_STRING:
+ case BMP_STRING:
+ charset = Charset.forName("UTF-16BE");
+ break;
+ case UTF8_STRING:
+ default:
+ charset = Charset.forName("UTF-8");
+ break;
+ }
+ if (charset == null)
+ throw new DEREncodingException("no charset");
+ CharsetEncoder encoder = charset.newEncoder();
+ ByteBuffer result = encoder.encode(CharBuffer.wrap(str));
+ if (result.hasArray())
+ {
+ b = result.array();
+ }
+ else
+ {
+ b = new byte[result.remaining()];
+ result.get(b);
+ }
+ writeLength(out, b.length);
+ out.write(b);
+ return b.length;
+ }
+
+ private static int writeDate(OutputStream out, int tag, Date date)
+ throws IOException
+ {
+ SimpleDateFormat sdf = null;
+ if ((tag & 0x1F) == UTC_TIME)
+ sdf = new SimpleDateFormat("yyMMddHHmmss'Z'");
+ else
+ sdf = new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'");
+ sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+ byte[] b = sdf.format(date).getBytes("ISO-8859-1");
+ writeLength(out, b.length);
+ out.write(b);
+ return b.length;
+ }
+
+ // Package method.
+ // ------------------------------------------------------------------------
+
+ static void writeLength(OutputStream out, int len) throws IOException
+ {
+ if (len < 128)
+ out.write(len);
+ else if (len < 256)
+ {
+ out.write(0x81);
+ out.write(len);
+ }
+ else if (len < 65536)
+ {
+ out.write(0x82);
+ out.write(len >> 8);
+ out.write(len);
+ }
+ else if (len < 16777216)
+ {
+ out.write(0x83);
+ out.write(len >> 16);
+ out.write(len >> 8);
+ out.write(len);
+ }
+ else
+ {
+ out.write(0x84);
+ out.write(len >> 24);
+ out.write(len >> 16);
+ out.write(len >> 8);
+ out.write(len);
+ }
+ }
+}
diff --git a/libjava/gnu/java/security/provider/DERReader.java b/libjava/gnu/java/security/provider/DERReader.java
deleted file mode 100644
index 0f6e492..0000000
--- a/libjava/gnu/java/security/provider/DERReader.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/* DERReader.java
- Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 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.java.security.provider;
-
-import java.math.BigInteger;
-import gnu.java.security.der.DEREncodingException;
-
-public class DERReader
-{
- byte source[];
- int pos;
-
- static final int UNIVERSAL = 1;
- static final int APPLICATION = 2;
- static final int CONTEXT_SPECIFIC = 3;
- static final int PRIVATE = 4;
-
-
- public DERReader()
- {
- source = null;
- pos = 0;
- }
-
- public DERReader( byte source[] )
- {
- init( source );
- }
-
- public void init( String source )
- {
- init( source.getBytes() );
- }
-
- public void init( byte source[] )
- {
- this.source = source;
- pos = 0;
- }
-
- public BigInteger getBigInteger() throws DEREncodingException
- {
- return new BigInteger( getPrimitive() );
- }
-
- //Reads Primitive, definite-length method
- private byte[] getPrimitive() throws DEREncodingException
- {
- int tmp = pos;
-
- //Read Identifier
- byte identifier = source[tmp++];
- if( (0x20 & identifier) != 0)
- throw new DEREncodingException();
- int type = translateLeadIdentifierByte(identifier);
- //System.out.println("Type: " + type);
-
- //get tag
- int tag = (0x1f & identifier);
- //if( tag == 0x1f)
- // tag = getIdentifier(tmp);
- //System.out.println("Tag: " + tag);
-
- //get length
- byte len = source[tmp]; //may be length of length parameter
- long length = 0x7f & len;
- int i;
- if( (0x80 & len) != 0 ) {
- //System.out.println("Extra Long Length");
- len &= 0x7f;
- //System.out.println("Length of Length: " + len);
- //get length here
- length = 0;
- for( i = 0; i < len; i++ ) {
- tmp++;
- length <<= 8;
- length += (source[tmp] < 0 ) ?
- (256 + source[tmp]) :
- source[tmp];
- //System.out.println("Length of Length: " + length);
- }
- tmp++;
- } else
- tmp++;
-
- /*System.out.println("Position: " + tmp);
- System.out.println("Length: " + length);
- for( i = 0; i < 10; i++)
- System.out.print(source[tmp + i] + " ");
- System.out.println();*/
-
- byte tmpb[] = new byte[ (int)length ];
- System.arraycopy( source, tmp, tmpb, 0, (int)length);
- pos = (int)(tmp + length);
- return tmpb;
- }
-
- private int translateLeadIdentifierByte(byte b)
- {
- if( (0x3f & b ) == b)
- return UNIVERSAL;
- else if( (0x7f & b ) == b)
- return APPLICATION;
- else if( (0xbf & b ) == b)
- return CONTEXT_SPECIFIC;
- else
- return PRIVATE;
- }
-
- private int getIdentifier(int tpos)
- {
- while( (0x80 & source[tpos]) != 0)
- tpos++;
- return tpos;
- }
-}
diff --git a/libjava/gnu/java/security/provider/DERWriter.java b/libjava/gnu/java/security/provider/DERWriter.java
deleted file mode 100644
index 4add119..0000000
--- a/libjava/gnu/java/security/provider/DERWriter.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/* DERWriter.java
- Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 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.java.security.provider;
-
-import java.math.BigInteger;
-
-public class DERWriter
-{
- static final int UNIVERSAL = 1;
- static final int APPLICATION = 2;
- static final int CONTEXT_SPECIFIC = 3;
- static final int PRIVATE = 4;
-
- public DERWriter()
- {}
-
- public byte[] writeBigInteger( BigInteger i)
- {
- return writePrimitive( 0x02, UNIVERSAL, (int)Math.ceil((double)i.bitLength() / 8), i.toByteArray() );
- }
-
- private byte[] writePrimitive( int identifier, int identifierencoding,
- int length, byte contents[])
- {
- return joinarrays( generateIdentifier( identifier, identifierencoding ), generateLength( length ), contents);
- }
-
- public byte[] joinarrays( byte a[], byte b[])
- {
- byte d[] = new byte[ a.length + b.length];
- System.arraycopy( a, 0, d, 0, a.length);
- System.arraycopy( b, 0, d, a.length, b.length);
- return d;
- }
-
- public byte[] joinarrays( byte a[], byte b[], byte c[])
- {
- byte d[] = new byte[ a.length + b.length + c.length];
- System.arraycopy( a, 0, d, 0, a.length);
- System.arraycopy( b, 0, d, a.length, b.length);
- System.arraycopy( c, 0, d, a.length + b.length, c.length);
- return d;
- }
-
- private byte[] generateIdentifier(int identifier,
- int identifierencoding)
- {
- byte b[];
- if( identifier > 31 ) {
- int count = (int)(Math.log( identifier ) / Math.log( 256 ));
- b = new byte[ count + 1 ];
- b[0] = (byte)(translateLeadIdentifierByte(identifierencoding)
- | 0x1f);
- int i;
- for( i = 1; i < (count + 1); i++) {
- b[i] = (byte)(0x7f & ( identifier >> (7 * (count - i)) ));
- b[i] |= 0x80;
- }
- b[i - 1] ^= 0x80;
- //System.out.println("Identifier1: " + b[0]);
- return b;
- } else {
- b = new byte[1];
- b[0] = (byte)((translateLeadIdentifierByte(identifierencoding)
- | (byte)( identifier & 0x1f )) & 0xdf);
- //System.out.println("Identifier2: " + b[0]);
- return b;
- }
- }
-
- private byte translateLeadIdentifierByte(int b)
- {
- if( b == UNIVERSAL)
- return (byte)0x3f;
- else if( b == APPLICATION)
- return (byte)0x7f;
- else if( b == CONTEXT_SPECIFIC)
- return (byte)0xbf;
- else
- return (byte)0xC0;
- }
-
- private byte[] generateLength( int length )
- {
- byte b[];
- if( length > 127 ) {
- int count = (int)Math.ceil(Math.log( length ) / Math.log( 256 ));
- //System.out.println("Length byte count: " + count);
- b = new byte[ count + 1 ];
- b[0] = (byte)((count & 0x7f) | 0x80);
- for( int i = 1; i < (count + 1); i++) {
- b[i] = (byte)( length >>> (8 * ( count - i) ));
- //System.out.println("Length1 byte1: " + (length >>> (8 * ( count - i) )));
- //System.out.println("Length1 byte2: " + b[i]);
- }
-
- //System.out.println("Length1: " + length);
- return b;
- } else {
- b = new byte[1];
- b[0] = (byte)( length & 0x7f );
- //System.out.println("Length2: " + length);
- return b;
- }
- }
-}
diff --git a/libjava/gnu/java/security/provider/DSAKeyFactory.java b/libjava/gnu/java/security/provider/DSAKeyFactory.java
new file mode 100644
index 0000000..3414f42
--- /dev/null
+++ b/libjava/gnu/java/security/provider/DSAKeyFactory.java
@@ -0,0 +1,134 @@
+/* DSAKeyFactory.java -- DSA key factory.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.provider;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+/**
+ * DSA key factory.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class DSAKeyFactory extends KeyFactorySpi
+{
+
+ // Constructor.
+ // ------------------------------------------------------------------------
+
+ public DSAKeyFactory()
+ {
+ super();
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (!(keySpec instanceof DSAPrivateKeySpec))
+ throw new InvalidKeySpecException();
+ return new GnuDSAPrivateKey(
+ ((DSAPrivateKeySpec) keySpec).getX(),
+ ((DSAPrivateKeySpec) keySpec).getP(),
+ ((DSAPrivateKeySpec) keySpec).getQ(),
+ ((DSAPrivateKeySpec) keySpec).getG());
+ }
+
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (!(keySpec instanceof DSAPublicKeySpec))
+ throw new InvalidKeySpecException();
+ return new GnuDSAPublicKey(
+ ((DSAPublicKeySpec) keySpec).getY(),
+ ((DSAPublicKeySpec) keySpec).getP(),
+ ((DSAPublicKeySpec) keySpec).getQ(),
+ ((DSAPublicKeySpec) keySpec).getG());
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if ((key instanceof DSAPublicKey) &&
+ keySpec.isAssignableFrom(DSAPublicKeySpec.class))
+ {
+ return new DSAPublicKeySpec(((DSAPublicKey) key).getY(),
+ ((DSAPublicKey) key).getParams().getP(),
+ ((DSAPublicKey) key).getParams().getQ(),
+ ((DSAPublicKey) key).getParams().getG());
+ }
+ if ((key instanceof DSAPrivateKey) &&
+ keySpec.isAssignableFrom(DSAPrivateKeySpec.class))
+ {
+ return new DSAPrivateKeySpec(((DSAPrivateKey) key).getX(),
+ ((DSAPrivateKey) key).getParams().getP(),
+ ((DSAPrivateKey) key).getParams().getQ(),
+ ((DSAPrivateKey) key).getParams().getG());
+ }
+ throw new InvalidKeySpecException();
+ }
+
+ protected Key engineTranslateKey(Key key) throws InvalidKeyException
+ {
+ if ((key instanceof GnuDSAPublicKey) || (key instanceof GnuDSAPrivateKey))
+ return key;
+ if (key instanceof DSAPublicKey)
+ return new GnuDSAPublicKey(((DSAPublicKey) key).getY(),
+ ((DSAPublicKey) key).getParams().getP(),
+ ((DSAPublicKey) key).getParams().getQ(),
+ ((DSAPublicKey) key).getParams().getG());
+ if (key instanceof DSAPrivateKey)
+ return new GnuDSAPrivateKey(((DSAPrivateKey) key).getX(),
+ ((DSAPrivateKey) key).getParams().getP(),
+ ((DSAPrivateKey) key).getParams().getQ(),
+ ((DSAPrivateKey) key).getParams().getG());
+ throw new InvalidKeyException();
+ }
+}
diff --git a/libjava/gnu/java/security/provider/DSAParameters.java b/libjava/gnu/java/security/provider/DSAParameters.java
index a8f998b..31c0d5e 100644
--- a/libjava/gnu/java/security/provider/DSAParameters.java
+++ b/libjava/gnu/java/security/provider/DSAParameters.java
@@ -1,5 +1,5 @@
/* DSAParameters.java --- DSA Parameters Implementation
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999,2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,15 +38,28 @@ exception statement from your version. */
package gnu.java.security.provider;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+
import java.math.BigInteger;
+
import java.security.AlgorithmParametersSpi;
import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.DSAParameterSpec;
import java.security.spec.InvalidParameterSpecException;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
+
+import gnu.java.io.ASN1ParsingException;
+import gnu.java.security.der.DER;
import gnu.java.security.der.DEREncodingException;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
import gnu.java.security.util.Prime;
@@ -76,7 +89,7 @@ public void engineInit(AlgorithmParameterSpec paramSpec)
DSAParameterSpec dsaParamSpec = (DSAParameterSpec)paramSpec;
p = dsaParamSpec.getP();
q = dsaParamSpec.getQ();
- q = dsaParamSpec.getG();
+ g = dsaParamSpec.getG();
}
else
throw new InvalidParameterSpecException("Only accepts DSAParameterSpec");
@@ -85,16 +98,20 @@ public void engineInit(AlgorithmParameterSpec paramSpec)
public void engineInit(byte[] params)
throws IOException
{
- DERReader reader = new DERReader( params );
- try {
-
- p = reader.getBigInteger();
- q = reader.getBigInteger();
- g = reader.getBigInteger();
-
- } catch ( DEREncodingException DERee) {
- throw new IOException("Invalid Format: Only accepts ASN.1");
- }
+ DERReader in = new DERReader(params);
+ DERValue val = in.read();
+ if (val.getValue() != DER.CONSTRUCTED_VALUE)
+ throw new ASN1ParsingException("badly formed parameters");
+ try
+ {
+ p = (BigInteger) in.read().getValue();
+ q = (BigInteger) in.read().getValue();
+ g = (BigInteger) in.read().getValue();
+ }
+ catch (Exception x)
+ {
+ throw new ASN1ParsingException("badly formed parameters");
+ }
}
public void engineInit(byte[] params, String format)
@@ -117,10 +134,13 @@ public AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec)
public byte[] engineGetEncoded()
throws IOException
{
- DERWriter writer = new DERWriter();
- return writer.joinarrays( writer.writeBigInteger(p),
- writer.writeBigInteger(q),
- writer.writeBigInteger(g) );
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ ArrayList seq = new ArrayList(3);
+ seq.add(new DERValue(DER.INTEGER, p));
+ seq.add(new DERValue(DER.INTEGER, q));
+ seq.add(new DERValue(DER.INTEGER, g));
+ DERWriter.write(bout, new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, seq));
+ return bout.toByteArray();
}
@@ -135,7 +155,7 @@ public byte[] engineGetEncoded(String format)
public String engineToString()
{
String lineSeparator = System.getProperty("line.seperator");
- return ("q: " + q + lineSeparator + "p: " + p + lineSeparator + "g:" + g);
+ return ("q: " + q + " p: " + p + " g: " + g);
}
}
diff --git a/libjava/gnu/java/security/provider/DSASignature.java b/libjava/gnu/java/security/provider/DSASignature.java
index f33f048..7da1c7d 100644
--- a/libjava/gnu/java/security/provider/DSASignature.java
+++ b/libjava/gnu/java/security/provider/DSASignature.java
@@ -1,5 +1,5 @@
/* DSASignature.java
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999,2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,7 +37,12 @@ exception statement from your version. */
package gnu.java.security.provider;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
import java.math.BigInteger;
+
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
@@ -52,8 +57,17 @@ import java.security.SignatureSpi;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
+
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
+
+import gnu.java.io.ASN1ParsingException;
+import gnu.java.security.der.DER;
import gnu.java.security.der.DEREncodingException;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
public class DSASignature extends SignatureSpi
{
@@ -157,9 +171,14 @@ public class DSASignature extends SignatureSpi
BigInteger s = sha.add( x.multiply( r ) );
s = s.multiply( k.modInverse(q) ).mod( q );
- DERWriter writer = new DERWriter();
- return writer.joinarrays( writer.writeBigInteger( r ), writer.writeBigInteger( s ) );
-
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ ArrayList seq = new ArrayList(2);
+ seq.set(0, new DERValue(DER.INTEGER, r));
+ seq.set(1, new DERValue(DER.INTEGER, s));
+ DERWriter.write(bout, new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, seq));
+ return bout.toByteArray();
+ } catch (IOException ioe) {
+ throw new SignatureException();
} catch ( ArithmeticException ae ) {
throw new SignatureException();
}
@@ -180,9 +199,12 @@ public class DSASignature extends SignatureSpi
{
//Decode sigBytes from ASN.1 DER encoding
try {
- DERReader reader = new DERReader( sigBytes );
- BigInteger r = reader.getBigInteger();
- BigInteger s = reader.getBigInteger();
+ DERReader in = new DERReader(sigBytes);
+ DERValue val = in.read();
+ if (!val.isConstructed())
+ throw new SignatureException("badly formed signature");
+ BigInteger r = (BigInteger) in.read().getValue();
+ BigInteger s = (BigInteger) in.read().getValue();
BigInteger g = publicKey.getParams().getG();
BigInteger p = publicKey.getParams().getP();
@@ -206,8 +228,8 @@ public class DSASignature extends SignatureSpi
return true;
else
return false;
- } catch ( DEREncodingException deree ) {
- throw new SignatureException();
+ } catch (IOException ioe) {
+ throw new SignatureException("badly formed signature");
}
}
diff --git a/libjava/gnu/java/security/provider/Gnu.java b/libjava/gnu/java/security/provider/Gnu.java
index c556107..70a7d1d 100644
--- a/libjava/gnu/java/security/provider/Gnu.java
+++ b/libjava/gnu/java/security/provider/Gnu.java
@@ -1,5 +1,5 @@
/* Gnu.java --- Gnu provider main class
- Copyright (C) 1999, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -43,7 +43,7 @@ public final class Gnu extends Provider
{
public Gnu()
{
- super( "GNU", 1.0, "GNU provider v1.0 implementing SHA-1, MD5, DSA");
+ super("GNU", 1.0, "GNU provider v1.0 implementing SHA-1, MD5, DSA, X.509 Certificates");
// Note that all implementation class names are referenced by using
// Class.getName(). That way when we staticly link the Gnu provider
@@ -51,7 +51,7 @@ public final class Gnu extends Provider
// Signature
put("Signature.SHA1withDSA",
- gnu.java.security.provider.DSASignature.class.getName());
+ gnu.java.security.provider.DSASignature.class.getName());
put("Alg.Alias.Signature.DSS", "SHA1withDSA");
put("Alg.Alias.Signature.DSA", "SHA1withDSA");
@@ -68,12 +68,20 @@ public final class Gnu extends Provider
// Key Pair Generator
put("KeyPairGenerator.DSA",
- gnu.java.security.provider.DSAKeyPairGenerator.class.getName());
+ gnu.java.security.provider.DSAKeyPairGenerator.class.getName());
put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSA");
put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSA");
put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSA");
+ // Key Factory
+ put("KeyFactory.DSA",
+ gnu.java.security.provider.DSAKeyFactory.class.getName());
+
+ put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSA");
+ put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA");
+ put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA");
+
// Message Digests
put("MessageDigest.SHA", gnu.java.security.provider.SHA.class.getName());
put("MessageDigest.MD5", gnu.java.security.provider.MD5.class.getName());
@@ -84,15 +92,20 @@ public final class Gnu extends Provider
// Algorithm Parameters
put("AlgorithmParameters.DSA",
- gnu.java.security.provider.DSAParameters.class.getName());
+ gnu.java.security.provider.DSAParameters.class.getName());
// Algorithm Parameter Generator
put("AlgorithmParameterGenerator.DSA",
- gnu.java.security.provider.DSAParameterGenerator.class.getName());
+ gnu.java.security.provider.DSAParameterGenerator.class.getName());
// SecureRandom
put("SecureRandom.SHA1PRNG",
- gnu.java.security.provider.SHA1PRNG.class.getName());
+ gnu.java.security.provider.SHA1PRNG.class.getName());
+
+ // CertificateFactory
+ put("CertificateFactory.X.509",
+ gnu.java.security.provider.X509CertificateFactory.class.getName());
+ put("Alg.Alias.CertificateFactory.X509", "X.509");
}
}
diff --git a/libjava/gnu/java/security/provider/GnuDSAPrivateKey.java b/libjava/gnu/java/security/provider/GnuDSAPrivateKey.java
index 45446c7..4eceb00 100644
--- a/libjava/gnu/java/security/provider/GnuDSAPrivateKey.java
+++ b/libjava/gnu/java/security/provider/GnuDSAPrivateKey.java
@@ -82,4 +82,10 @@ public class GnuDSAPrivateKey implements DSAPrivateKey
{
return x;
}
+
+ public String toString()
+ {
+ return "GnuDSAPrivateKey: x=" + x.toString(16) + " p=" + p.toString(16)
+ + " q=" + q.toString(16) + " g=" + g.toString(16);
+ }
}
diff --git a/libjava/gnu/java/security/provider/GnuDSAPublicKey.java b/libjava/gnu/java/security/provider/GnuDSAPublicKey.java
index 2f23abb..91d6b56 100644
--- a/libjava/gnu/java/security/provider/GnuDSAPublicKey.java
+++ b/libjava/gnu/java/security/provider/GnuDSAPublicKey.java
@@ -1,5 +1,5 @@
/* GnuDSAPublicKey.java --- Gnu DSA Public Key
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999,2003 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -82,4 +82,10 @@ public class GnuDSAPublicKey implements DSAPublicKey
{
return y;
}
+
+ public String toString()
+ {
+ return "GnuDSAPublicKey: y=" + y.toString(16) + " p=" + p.toString(16)
+ + " q=" + q.toString(16) + " g=" + g.toString(16);
+ }
}
diff --git a/libjava/gnu/java/security/provider/X509CertificateFactory.java b/libjava/gnu/java/security/provider/X509CertificateFactory.java
new file mode 100644
index 0000000..62d3d38
--- /dev/null
+++ b/libjava/gnu/java/security/provider/X509CertificateFactory.java
@@ -0,0 +1,269 @@
+/* X509CertificateFactory.java -- generates X.509 certificates.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.provider;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import gnu.java.io.Base64InputStream;
+import gnu.java.security.x509.X509Certificate;
+import gnu.java.security.x509.X509CRL;
+
+public class X509CertificateFactory extends CertificateFactorySpi
+{
+
+ // Constants.
+ // ------------------------------------------------------------------------
+
+ public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----";
+ public static final String END_CERTIFICATE = "-----END CERTIFICATE-----";
+ public static final String BEGIN_X509_CRL = "-----BEGIN X509 CRL-----";
+ public static final String END_X509_CRL = "-----END X509 CRL-----";
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ public X509CertificateFactory()
+ {
+ super();
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ public Certificate engineGenerateCertificate(InputStream inStream)
+ throws CertificateException
+ {
+ try
+ {
+ return generateCert(inStream);
+ }
+ catch (IOException ioe)
+ {
+ throw new CertificateException(ioe.toString());
+ }
+ }
+
+ public Collection engineGenerateCertificates(InputStream inStream)
+ throws CertificateException
+ {
+ LinkedList certs = new LinkedList();
+ while (true)
+ {
+ try
+ {
+ certs.add(generateCert(inStream));
+ }
+ catch (EOFException eof)
+ {
+ break;
+ }
+ catch (IOException ioe)
+ {
+ throw new CertificateException(ioe.toString());
+ }
+ }
+ return certs;
+ }
+
+ public CRL engineGenerateCRL(InputStream inStream) throws CRLException
+ {
+ try
+ {
+ return generateCRL(inStream);
+ }
+ catch (IOException ioe)
+ {
+ throw new CRLException(ioe.toString());
+ }
+ }
+
+ public Collection engineGenerateCRLs(InputStream inStream)
+ throws CRLException
+ {
+ LinkedList crls = new LinkedList();
+ while (true)
+ {
+ try
+ {
+ crls.add(generateCRL(inStream));
+ }
+ catch (EOFException eof)
+ {
+ break;
+ }
+ catch (IOException ioe)
+ {
+ throw new CRLException(ioe.toString());
+ }
+ }
+ return crls;
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private X509Certificate generateCert(InputStream inStream)
+ throws IOException, CertificateException
+ {
+ if (!inStream.markSupported())
+ inStream = new BufferedInputStream(inStream, 8192);
+ inStream.mark(20);
+ int i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+
+ // If the input is in binary DER format, the first byte MUST be
+ // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the
+ // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set.
+ //
+ // So if we do not see 0x30 here we will assume it is in Base-64.
+ if (i != 0x30)
+ {
+ inStream.reset();
+ StringBuffer line = new StringBuffer(80);
+ do
+ {
+ line.setLength(0);
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ }
+ while (!line.toString().equals(BEGIN_CERTIFICATE));
+ X509Certificate ret = new X509Certificate(
+ new BufferedInputStream(new Base64InputStream(inStream), 8192));
+ line.setLength(0);
+ line.append('-'); // Base64InputStream will eat this.
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ // XXX ???
+ if (!line.toString().equals(END_CERTIFICATE))
+ throw new CertificateException("no end-of-certificate marker");
+ return ret;
+ }
+ else
+ {
+ inStream.reset();
+ return new X509Certificate(inStream);
+ }
+ }
+
+ private X509CRL generateCRL(InputStream inStream)
+ throws IOException, CRLException
+ {
+ if (!inStream.markSupported())
+ inStream = new BufferedInputStream(inStream, 8192);
+ inStream.mark(20);
+ int i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+
+ // If the input is in binary DER format, the first byte MUST be
+ // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the
+ // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set.
+ //
+ // So if we do not see 0x30 here we will assume it is in Base-64.
+ if (i != 0x30)
+ {
+ inStream.reset();
+ StringBuffer line = new StringBuffer(80);
+ do
+ {
+ line.setLength(0);
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ }
+ while (!line.toString().startsWith(BEGIN_X509_CRL));
+ X509CRL ret = new X509CRL(
+ new BufferedInputStream(new Base64InputStream(inStream), 8192));
+ line.setLength(0);
+ line.append('-'); // Base64InputStream will eat this.
+ do
+ {
+ i = inStream.read();
+ if (i == -1)
+ throw new EOFException();
+ if (i != '\n' && i != '\r')
+ line.append((char) i);
+ }
+ while (i != '\n' && i != '\r');
+ // XXX ???
+ if (!line.toString().startsWith(END_X509_CRL))
+ throw new CRLException("no end-of-CRL marker");
+ return ret;
+ }
+ else
+ {
+ inStream.reset();
+ return new X509CRL(inStream);
+ }
+ }
+
+}
diff --git a/libjava/gnu/java/security/x509/X500DistinguishedName.java b/libjava/gnu/java/security/x509/X500DistinguishedName.java
new file mode 100644
index 0000000..5284385
--- /dev/null
+++ b/libjava/gnu/java/security/x509/X500DistinguishedName.java
@@ -0,0 +1,824 @@
+/* X500DistinguishedName.java -- X.500 name.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+
+import java.security.Principal;
+
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import gnu.java.io.ASN1ParsingException;
+import gnu.java.security.OID;
+import gnu.java.security.der.DER;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+
+/**
+ * A X.500 distinguished name. Distinguished names are sequences of
+ * ATTRIB=VALUE pairs, where ATTRIB is one of the following:
+ *
+ * <table cellpadding="0" cellspacing="0" border="0">
+ * <tr>
+ * <th bgcolor="#CCCCFF" align="left">Name</th>
+ * <th bgcolor="#CCCCFF" align="left">X.500 AttributeType</th>
+ * <th bgcolor="#CCCCFF" align="left">ObjectIdentifier</th>
+ * </tr>
+ * <tr>
+ * <td align="left">CN</td>
+ * <td align="left">commonName</td>
+ * <td align="left">2.5.4.3</td>
+ * </tr>
+ * <tr>
+ * <td align="left">C</td>
+ * <td align="left">countryName</td>
+ * <td align="left">2.5.4.6</td>
+ * </tr>
+ * <tr>
+ * <td align="left">L</td>
+ * <td align="left">localityName</td>
+ * <td align="left">2.5.4.7</td>
+ * </tr>
+ * <tr>
+ * <td align="left">ST</td>
+ * <td align="left">stateOrProvinceName</td>
+ * <td align="left">2.5.4.8</td>
+ * </tr>
+ * <tr>
+ * <td align="left">STREET</td>
+ * <td align="left">streetAddress</td>
+ * <td align="left">2.5.4.9</td>
+ * </tr>
+ * <tr>
+ * <td align="left">O</td>
+ * <td align="left">organizationName</td>
+ * <td align="left">2.5.4.10</td>
+ * </tr>
+ * <tr>
+ * <td align="left">OU</td>
+ * <td align="left">organizationUnitName</td>
+ * <td align="left">2.5.4.11</td>
+ * </tr>
+ * <tr>
+ * <td align="left">DC</td>
+ * <td align="left">domainComponent</td>
+ * <td align="left">0.9.2342.19200300.100.1.25</td>
+ * </tr>
+ * <tr>
+ * <td align="left">UID</td>
+ * <td align="left">userid</td>
+ * <td align="left"0.9.2342.19200300.100.1.1></td>
+ * </tr>
+ * <tr>
+ * <td align="left">DNQ or DNQUALIFIER(*)</td>
+ * <td align="left">domainNameQualifier</td>
+ * <td align="left">2.5.4.46</td>
+ * </tr>
+ * <tr>
+ * <td align="left">SURNAME(*)</td>
+ * <td align="left">name</td>
+ * <td align="left">2.5.4.41</td>
+ * </tr>
+ * <tr>
+ * <td align="left">GIVENNAME(*)</td>
+ * <td align="left">givenName</td>
+ * <td align="left">2.5.4.42</td>
+ * </tr>
+ * <tr>
+ * <td align="left">INITIALS(*)</td>
+ * <td align="left">initials</td>
+ * <td align="left">2.5.4.43</td>
+ * </tr>
+ * <tr>
+ * <td align="left">EMAILADDRESS(*)</td>
+ * <td align="left">emailAddress</td>
+ * <td align="left">2.5.4.44</td>
+ * </tr>
+ * </table>
+ *
+ * <p><i>(*) = attributes not specified in RFC1779 or RFC2253, but
+ * recognized anyway.</i>
+ *
+ * <p>Distinguished names of this form are used in the lightweight
+ * directory access protocol (LDAP) and in the issuer and subject fields
+ * of X.509 certificates.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ * @see javax.security.auth.x500.X500Principal
+ * @status DER decoding/encoding works, RFC1779 and RFC2253 need to be
+ * made more robust.
+ */
+public class X500DistinguishedName
+{
+
+ // Constants and fields.
+ // ------------------------------------------------------------------------
+
+ public static final OID CN = new OID("2.5.4.3");
+ public static final OID C = new OID("2.5.4.6");
+ public static final OID L = new OID("2.5.4.7");
+ public static final OID ST = new OID("2.5.4.8");
+ public static final OID STREET = new OID("2.5.4.9");
+ public static final OID O = new OID("2.5.4.10");
+ public static final OID OU = new OID("2.5.4.11");
+ public static final OID T = new OID("2.5.4.12");
+ public static final OID DNQ = new OID("2.5.4.46");
+ public static final OID NAME = new OID("2.5.4.41");
+ public static final OID GIVENNAME = new OID("2.5.4.42");
+ public static final OID INITIALS = new OID("2.5.4.43");
+ public static final OID GENERATION = new OID("2.5.4.44");
+ public static final OID EMAIL = new OID("1.2.840.113549.1.9.1");
+ public static final OID DC = new OID("0.9.2342.19200300.100.1.25");
+ public static final OID UID = new OID("0.9.2342.19200300.100.1.1");
+
+ private String commonName;
+ private String country;
+ private String locality;
+ private String orgUnit;
+ private String organization;
+ private String street;
+ private String state;
+ private String title;
+ private String dnQualifier;
+ private String surname;
+ private String givenName;
+ private String initials;
+ private String generation;
+ private String email;
+ private String domainComponent;
+ private String userid;
+
+ private String nameRFC1779;
+ private String nameRFC2253;
+ private String nameCanonical;
+
+ private transient byte[] encoded;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new X500DistinguishedName from the RFC1779 or RFC2253
+ * encoded form.
+ *
+ * @param name The encoded name.
+ * @throws IllegalArgumentException If the name cannot be parsed.
+ */
+ public X500DistinguishedName(String name)
+ {
+ if (name == null)
+ throw new NullPointerException();
+ try
+ {
+ parseDN(name, true);
+ }
+ catch (Exception e)
+ {
+ parseDN(name, false);
+ }
+ }
+
+ /**
+ * Create a new X500DistinguishedName from the DER encoded bytes.
+ *
+ * @param encoded The encoded form.
+ * @throws IOException If the bytes are not a valid DER construct.
+ */
+ public X500DistinguishedName(byte[] encoded) throws IOException
+ {
+ this(new ByteArrayInputStream(encoded));
+ }
+
+ /**
+ * Create a new X500DistinguishedName from the DER encoded bytes.
+ *
+ * @param encoded The encoded form.
+ * @throws IOException If the bytes are not a valid DER construct.
+ */
+ public X500DistinguishedName(InputStream encoded) throws IOException
+ {
+ parseDER(encoded);
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ public boolean equals(Object o)
+ {
+ return
+ (commonName != null &&
+ commonName.equals(((X500DistinguishedName) o).commonName)) &&
+ (country != null &&
+ country.equals(((X500DistinguishedName) o).country)) &&
+ (locality != null &&
+ locality.equals(((X500DistinguishedName) o).locality)) &&
+ (orgUnit != null &&
+ orgUnit.equals(((X500DistinguishedName) o).orgUnit)) &&
+ (organization != null &&
+ organization.equals(((X500DistinguishedName) o).organization)) &&
+ (street != null &&
+ street.equals(((X500DistinguishedName) o).street)) &&
+ (state != null &&
+ state.equals(((X500DistinguishedName) o).state)) &&
+ (domainComponent != null &&
+ domainComponent.equals(((X500DistinguishedName) o).domainComponent)) &&
+ (title != null &&
+ title.equals(((X500DistinguishedName) o).title)) &&
+ (dnQualifier != null &&
+ dnQualifier.equals(((X500DistinguishedName) o).dnQualifier)) &&
+ (surname != null &&
+ surname.equals(((X500DistinguishedName) o).surname)) &&
+ (givenName != null &&
+ givenName.equals(((X500DistinguishedName) o).givenName)) &&
+ (initials != null &&
+ initials.equals(((X500DistinguishedName) o).initials)) &&
+ (generation != null &&
+ generation.equals(((X500DistinguishedName) o).generation)) &&
+ (email != null &&
+ email.equals(((X500DistinguishedName) o).email)) &&
+ (userid != null &&
+ userid.equals(((X500DistinguishedName) o).userid));
+ }
+
+ public byte[] getEncoded()
+ {
+ if (encoded == null)
+ encoded = encodeDER();
+ return (byte[]) encoded.clone();
+ }
+
+ private static String quote(String str)
+ {
+ if (str.indexOf(" ") > 0 || str.indexOf("\f") > 0 ||
+ str.indexOf("\n") > 0 || str.indexOf("\r") > 0 ||
+ str.indexOf("\t") > 0)
+ str = '"' + str + '"';
+ // XXX needs regex
+ //return str.replaceAll("([,+\"\\<>;])", "\\\1");
+ return str;
+ }
+
+ public String toRFC1779()
+ {
+ if (nameRFC1779 != null)
+ return nameRFC1779;
+ StringBuffer buf = new StringBuffer();
+ if (commonName != null)
+ buf.append("CN=").append(quote(commonName)).append(", ");
+ if (country != null)
+ buf.append("C=").append(quote(country)).append(", ");
+ if (locality != null)
+ buf.append("L=").append(quote(locality)).append(", ");
+ if (orgUnit != null)
+ buf.append("OU=").append(quote(orgUnit)).append(", ");
+ if (organization != null)
+ buf.append("O=").append(quote(organization)).append(", ");
+ if (street != null)
+ buf.append("STREET=").append(quote(street)).append(", ");
+ if (state != null)
+ buf.append("ST=").append(quote(state)).append(", ");
+ if (title != null)
+ buf.append(T).append("=").append(quote(title)).append(", ");
+ if (dnQualifier != null)
+ buf.append(DNQ).append("=").append(quote(dnQualifier)).append(", ");
+ if (surname != null)
+ buf.append(NAME).append("=").append(quote(surname)).append(", ");
+ if (givenName != null)
+ buf.append(GIVENNAME).append("=").append(quote(givenName)).append(", ");
+ if (initials != null)
+ buf.append(INITIALS).append("=").append(quote(initials)).append(", ");
+ if (generation != null)
+ buf.append(GENERATION).append("=").append(quote(generation)).append(", ");
+ if (email != null)
+ buf.append(EMAIL).append("=").append(quote(email)).append(", ");
+ if (domainComponent != null)
+ buf.append(DC).append("=").append(quote(domainComponent)).append(", ");
+ if (userid != null)
+ buf.append(UID).append("=").append(quote(userid)).append(", ");
+ // XXX escapes
+ return (nameRFC1779 = buf.substring(0, buf.length()-2));
+ }
+
+ public String toRFC2253()
+ {
+ if (nameRFC2253 != null)
+ return nameRFC2253;
+ StringBuffer buf = new StringBuffer();
+ if (commonName != null)
+ buf.append("CN=").append(quote(commonName)).append(",");
+ if (country != null)
+ buf.append("C=").append(quote(country)).append(",");
+ if (locality != null)
+ buf.append("L=").append(quote(locality)).append(",");
+ if (orgUnit != null)
+ buf.append("OU=").append(quote(orgUnit)).append(",");
+ if (organization != null)
+ buf.append("O=").append(quote(organization)).append(",");
+ if (street != null)
+ buf.append("STREET=").append(quote(street)).append(",");
+ if (state != null)
+ buf.append("ST=").append(quote(state)).append(",");
+ if (title != null)
+ buf.append(T).append("=").append(quote(title)).append(",");
+ if (dnQualifier != null)
+ buf.append(DNQ).append("=").append(quote(dnQualifier)).append(",");
+ if (surname != null)
+ buf.append(NAME).append("=").append(quote(surname)).append(",");
+ if (givenName != null)
+ buf.append(GIVENNAME).append("=").append(quote(givenName)).append(",");
+ if (initials != null)
+ buf.append(INITIALS).append("=").append(quote(initials)).append(",");
+ if (generation != null)
+ buf.append(GENERATION).append("=").append(quote(generation)).append(",");
+ if (email != null)
+ buf.append(EMAIL).append("=").append(quote(email)).append(",");
+ if (domainComponent != null)
+ buf.append(DC).append("=").append(quote(domainComponent)).append(",");
+ if (userid != null)
+ buf.append(UID).append("=").append(quote(userid)).append(",");
+ // XXX escapes.
+ return (nameRFC2253 = buf.substring(0, buf.length()-1));
+ }
+
+ public String toCanonical()
+ {
+ if (nameCanonical != null)
+ return nameCanonical;
+ nameCanonical = toRFC2253();
+ return nameCanonical; // XXX canonicalize
+ }
+
+ public String getCommonName()
+ {
+ return commonName;
+ }
+
+ public String getCountry()
+ {
+ return country;
+ }
+
+ public String getLocality()
+ {
+ return locality;
+ }
+
+ public String getOrganizationalUnit()
+ {
+ return orgUnit;
+ }
+
+ public String getOrganization()
+ {
+ return organization;
+ }
+
+ public String getStreet()
+ {
+ return street;
+ }
+
+ public String getState()
+ {
+ return state;
+ }
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public String getDNQualifier()
+ {
+ return dnQualifier;
+ }
+
+ public String getSurname()
+ {
+ return surname;
+ }
+
+ public String getGivenName()
+ {
+ return givenName;
+ }
+
+ public String getInitials()
+ {
+ return initials;
+ }
+
+ public String getGeneration()
+ {
+ return generation;
+ }
+
+ public String getEmail()
+ {
+ return email;
+ }
+
+ public String getDomain()
+ {
+ return domainComponent;
+ }
+
+ public String getUserID()
+ {
+ return userid;
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private static String unquote(String str)
+ {
+ if (str.startsWith("\"") && str.endsWith("\""))
+ str = str.substring(1, str.length()-1);
+ // XXX needs regex
+ //return str.replaceAll("\\([,+\"\\<>;])", "\1");
+ return str;
+ }
+
+ private void parseDN(String name, boolean rfc2253)
+ {
+ if (name.length() == 0)
+ throw new IllegalArgumentException("zero-length distinguished name");
+ StreamTokenizer parse = new StreamTokenizer(new StringReader(name));
+ parse.resetSyntax();
+ parse.wordChars('\000', '~');
+ parse.ordinaryChar('#');
+ parse.ordinaryChar(',');
+ parse.ordinaryChar('=');
+ parse.ordinaryChar('<');
+ parse.ordinaryChar('>');
+ parse.ordinaryChar(';');
+ parse.ordinaryChar('\\');
+ parse.quoteChar('"');
+ String attrib = null;
+ String value = null;
+ int token, lastToken = ',';
+ while (true)
+ {
+ try
+ {
+ token = parse.nextToken();
+ }
+ catch (IOException ioe)
+ {
+ throw new IllegalArgumentException();
+ }
+ switch (token)
+ {
+ case StreamTokenizer.TT_WORD:
+ if (lastToken == ',' || lastToken == '+' ||
+ (!rfc2253 && lastToken == ';'))
+ attrib = parse.sval.trim();
+ else if (lastToken == '=')
+ value = unquote(parse.sval.trim());
+ else
+ throw new IllegalArgumentException();
+ break;
+ case '"':
+ if (lastToken == '=')
+ value = parse.sval;
+ else
+ throw new IllegalArgumentException();
+ break;
+ case ';':
+ if (rfc2253)
+ throw new IllegalArgumentException();
+ case ',':
+ case '+':
+ if (attrib == null || value == null)
+ throw new IllegalArgumentException("extraneous separator");
+ try
+ {
+ setAttribute(new OID(attrib), value);
+ }
+ catch (Exception x)
+ {
+ setAttribute(attrib, value);
+ }
+ attrib = null;
+ value = null;
+ break;
+ case '=':
+ break;
+ case StreamTokenizer.TT_EOF:
+ return;
+ default:
+ throw new IllegalArgumentException("unknown token " + (char)token
+ + " (" + token + ")");
+ }
+ lastToken = token;
+ }
+ }
+
+ private void parseDER(InputStream in) throws IOException
+ {
+ DERReader der = new DERReader(in);
+ DERValue name = der.read();
+ if (!name.isConstructed())
+ throw new ASN1ParsingException("badly formed Name");
+ int len = 0;
+ while (len < name.getLength())
+ {
+ DERValue rdn = der.read();
+ if (rdn.getValue() != DER.CONSTRUCTED_VALUE)
+ throw new ASN1ParsingException("badly formed RDNSequence");
+ int len2 = 0;
+ while (len2 < rdn.getLength())
+ {
+ DERValue atav = der.read();
+ if (atav.getValue() != DER.CONSTRUCTED_VALUE)
+ throw new ASN1ParsingException(
+ "badly formed AttributeTypeAndValue");
+ OID atype = (OID) der.read().getValue();
+ String aval = (String) der.read().getValue();
+ setAttribute(atype, aval);
+ len2 += 1 + atav.getLength()
+ + DERWriter.definiteEncodingSize(atav.getLength());
+ }
+ len += len2 + 1 + DERWriter.definiteEncodingSize(name.getLength());
+ }
+ }
+
+ private byte[] encodeDER()
+ {
+ try
+ {
+ LinkedList name = new LinkedList();
+ if (commonName != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, CN));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, commonName));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (country != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, C));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, country));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (locality != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, L));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, locality));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (orgUnit != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, OU));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, orgUnit));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (organization != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, O));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, organization));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (street != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, STREET));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, street));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (state != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, ST));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, state));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (title != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, T));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, title));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (dnQualifier != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, DNQ));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, dnQualifier));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (surname != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, NAME));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, surname));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (givenName != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, GIVENNAME));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, givenName));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (initials != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, INITIALS));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, initials));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (generation != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, GENERATION));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, generation));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (email != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, EMAIL));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, email));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (domainComponent != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, DC));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, domainComponent));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ if (userid != null)
+ {
+ HashSet rdn = new HashSet();
+ LinkedList atav = new LinkedList();
+ atav.add(new DERValue(DER.OBJECT_IDENTIFIER, UID));
+ atav.add(new DERValue(DER.PRINTABLE_STRING, userid));
+ rdn.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, atav));
+ name.add(new DERValue(DER.CONSTRUCTED | DER.SET, rdn));
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ DERWriter.write(out, new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, name));
+ return out.toByteArray();
+ }
+ catch (IOException ioe)
+ {
+ throw new Error(ioe);
+ }
+ }
+
+ private void setAttribute(String atype, String aval)
+ {
+ if (atype.equals("CN"))
+ commonName = aval;
+ else if (atype.equals("C"))
+ country = aval;
+ else if (atype.equals("L"))
+ locality = aval;
+ else if (atype.equals("ST"))
+ state = aval;
+ else if (atype.equals("STREET"))
+ street = aval;
+ else if (atype.equals("O"))
+ organization = aval;
+ else if (atype.equals("OU"))
+ orgUnit = aval;
+ else if (atype.equals("T"))
+ title = aval;
+ else if (atype.equals("DNQ") || atype.equals("DNQUALIFIER"))
+ dnQualifier = aval;
+ else if (atype.equals("SURNAME"))
+ surname = aval;
+ else if (atype.equals("GIVENNAME"))
+ givenName = aval;
+ else if (atype.equals("INITIALS"))
+ initials = aval;
+ else if (atype.equals("GENERATION"))
+ generation = aval;
+ else if (atype.equals("EMAILADDRESS"))
+ email = aval;
+ else if (atype.equals("DC"))
+ domainComponent = aval;
+ else if (atype.equals("UID"))
+ userid = aval;
+ else
+ throw new IllegalArgumentException("unknown attribute " + atype);
+ }
+
+ private void setAttribute(OID atype, String aval)
+ {
+ if (atype.equals(CN))
+ commonName = aval;
+ else if (atype.equals(C))
+ country = aval;
+ else if (atype.equals(L))
+ locality = aval;
+ else if (atype.equals(ST))
+ state = aval;
+ else if (atype.equals(STREET))
+ street = aval;
+ else if (atype.equals(O))
+ organization = aval;
+ else if (atype.equals(OU))
+ orgUnit = aval;
+ else if (atype.equals(T))
+ title = aval;
+ else if (atype.equals(DNQ))
+ dnQualifier = aval;
+ else if (atype.equals(NAME))
+ surname = aval;
+ else if (atype.equals(GIVENNAME))
+ givenName = aval;
+ else if (atype.equals(INITIALS))
+ initials = aval;
+ else if (atype.equals(GENERATION))
+ generation = aval;
+ else if (atype.equals(EMAIL))
+ email = aval;
+ else if (atype.equals(DC))
+ domainComponent = aval;
+ else if (atype.equals(UID))
+ userid = aval;
+ else
+ throw new IllegalArgumentException("unknown attribute " + atype);
+ }
+}
diff --git a/libjava/gnu/java/security/x509/X509CRL.java b/libjava/gnu/java/security/x509/X509CRL.java
new file mode 100644
index 0000000..6205c0f
--- /dev/null
+++ b/libjava/gnu/java/security/x509/X509CRL.java
@@ -0,0 +1,404 @@
+/* X509CRL.java -- X.509 certificate revocation list.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.x509;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.math.BigInteger;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.Set;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Principal;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+
+import javax.security.auth.x500.X500Principal;
+
+import gnu.java.io.ASN1ParsingException;
+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;
+
+/**
+ * X.509 certificate revocation lists.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class X509CRL extends java.security.cert.X509CRL
+{
+
+ // Constants and fields.
+ // ------------------------------------------------------------------------
+
+ private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
+ private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
+ private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
+ private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
+ private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
+ private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
+
+ private byte[] encoded;
+
+ private byte[] tbsCRLBytes;
+ private int version;
+ private OID algId;
+ private byte[] algParams;
+ private Date thisUpdate;
+ private Date nextUpdate;
+ private X500Principal issuerDN;
+ private HashMap revokedCerts;
+ private HashMap extensions;
+ private HashSet critOids;
+ private HashSet nonCritOids;
+
+ private OID sigAlg;
+ private byte[] sigAlgParams;
+ private byte[] rawSig;
+ private byte[] signature;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new X.509 CRL.
+ *
+ * @param encoded The DER encoded CRL.
+ * @throws CRLException If the input bytes are incorrect.
+ * @throws IOException If the input bytes cannot be read.
+ */
+ public X509CRL(InputStream encoded) throws CRLException, IOException
+ {
+ super();
+ revokedCerts = new HashMap();
+ extensions = new HashMap();
+ critOids = new HashSet();
+ nonCritOids = new HashSet();
+ try
+ {
+ parse(encoded);
+ }
+ catch (IOException ioe)
+ {
+ ioe.printStackTrace();
+ throw ioe;
+ }
+ catch (Exception x)
+ {
+ x.printStackTrace();
+ throw new CRLException(x.toString());
+ }
+ }
+
+ // X509CRL methods.
+ // ------------------------------------------------------------------------
+
+ public boolean equals(Object o)
+ {
+ return ((X509CRL) o).revokedCerts.equals(revokedCerts);
+ }
+
+ public int hashCode()
+ {
+ return revokedCerts.hashCode();
+ }
+
+ public byte[] getEncoded() throws CRLException
+ {
+ return (byte[]) encoded.clone();
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException
+ {
+ Signature sig = Signature.getInstance(sigAlg.toString());
+ doVerify(sig, key);
+ }
+
+ public void verify(PublicKey key, String provider)
+ throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException
+ {
+ Signature sig = Signature.getInstance(sigAlg.toString(), provider);
+ doVerify(sig, key);
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public Principal getIssuerDN()
+ {
+ return issuerDN;
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ return issuerDN;
+ }
+
+ public Date getThisUpdate()
+ {
+ return (Date) thisUpdate.clone();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (nextUpdate != null)
+ return (Date) nextUpdate.clone();
+ return null;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNo)
+ {
+ return (X509CRLEntry) revokedCerts.get(serialNo);
+ }
+
+ public Set getRevokedCertificates()
+ {
+ return Collections.unmodifiableSet(new HashSet(revokedCerts.values()));
+ }
+
+ public byte[] getTBSCertList() throws CRLException
+ {
+ return (byte[]) tbsCRLBytes.clone();
+ }
+
+ public byte[] getSignature()
+ {
+ return (byte[]) rawSig.clone();
+ }
+
+ public String getSigAlgName()
+ {
+ if (sigAlg.equals(ID_DSA_WITH_SHA1))
+ return "SHA1withDSA";
+ if (sigAlg.equals(ID_RSA_WITH_MD2))
+ return "MD2withRSA";
+ if (sigAlg.equals(ID_RSA_WITH_MD5))
+ return "MD5withRSA";
+ if (sigAlg.equals(ID_RSA_WITH_SHA1))
+ return "SHA1withRSA";
+ return "unknown";
+ }
+
+ public String getSigAlgOID()
+ {
+ return sigAlg.toString();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ return (byte[]) sigAlgParams.clone();
+ return null;
+ }
+
+ // X509Extension methods.
+ // ------------------------------------------------------------------------
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ return false; // XXX
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return Collections.unmodifiableSet(critOids);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return Collections.unmodifiableSet(nonCritOids);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ byte[] ext = (byte[]) extensions.get(oid);
+ if (ext != null)
+ return (byte[]) ext.clone();
+ return null;
+ }
+
+ // CRL methods.
+ // ------------------------------------------------------------------------
+
+ public String toString()
+ {
+ return gnu.java.security.x509.X509CRL.class.getName();
+ }
+
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!(cert instanceof java.security.cert.X509Certificate))
+ throw new IllegalArgumentException("not a X.509 certificate");
+ BigInteger certSerial =
+ ((java.security.cert.X509Certificate) cert).getSerialNumber();
+ X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial);
+ if (ent == null)
+ return false;
+ return ent.getRevocationDate().compareTo(new Date()) < 0;
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private void doVerify(Signature sig, PublicKey key)
+ throws CRLException, InvalidKeyException, SignatureException
+ {
+ sig.initVerify(key);
+ sig.update(tbsCRLBytes);
+ if (!sig.verify(signature))
+ throw new CRLException("signature not verified");
+ }
+
+ private void parse(InputStream in) throws Exception
+ {
+ DERReader der = new DERReader(in);
+ DERValue val = der.read();
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed CertificateList");
+ encoded = val.getEncoded();
+
+ val = der.read();
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed TBSCertList");
+ tbsCRLBytes = val.getEncoded();
+
+ val = der.read();
+ if (val.getValue() instanceof BigInteger)
+ {
+ version = ((BigInteger) val.getValue()).intValue() + 1;
+ val = der.read();
+ }
+ else
+ version = 1;
+
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed AlgorithmIdentifier");
+ DERValue algIdVal = der.read();
+ algId = (OID) algIdVal.getValue();
+ if (val.getLength() > algIdVal.getEncodedLength())
+ {
+ val = der.read();
+ algParams = val.getEncoded();
+ if (val.isConstructed())
+ in.skip(val.getLength());
+ }
+
+ issuerDN = new X500Principal(in);
+
+ thisUpdate = (Date) der.read().getValue();
+
+ val = der.read();
+ if (val.getValue() instanceof Date)
+ {
+ nextUpdate = (Date) val.getValue();
+ val = der.read();
+ }
+ if (val.getTag() != 0)
+ {
+ int len = 0;
+ while (len < val.getLength())
+ {
+ X509CRLEntry entry =
+ new gnu.java.security.x509.X509CRLEntry(version, in);
+ revokedCerts.put(entry.getSerialNumber(), entry);
+ len += entry.getEncoded().length;
+ }
+ }
+ if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0)
+ {
+ val = der.read();
+ int len = 0;
+ while (len < val.getLength())
+ {
+ DERValue ext = der.read();
+ OID extId = (OID) der.read().getValue();
+ DERValue val2 = der.read();
+ Boolean crit = Boolean.valueOf(false);
+ if (val2.getValue() instanceof Boolean)
+ {
+ crit = (Boolean) val2.getValue();
+ val2 = der.read();
+ }
+ byte[] extVal = (byte[]) val2.getValue();
+ extensions.put(extId.toString(), extVal);
+ if (crit.booleanValue())
+ critOids.add(extId.toString());
+ else
+ nonCritOids.add(extId.toString());
+ len += ext.getEncodedLength();
+ }
+ }
+
+ val = der.read();
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed AlgorithmIdentifier");
+ DERValue sigAlgVal = der.read();
+ sigAlg = (OID) sigAlgVal.getValue();
+ if (val.getLength() > sigAlgVal.getEncodedLength())
+ {
+ val = der.read();
+ sigAlgParams = (byte[]) val.getEncoded();
+ if (val.isConstructed())
+ in.skip(val.getLength());
+ }
+ val = der.read();
+ rawSig = val.getEncoded();
+ signature = ((BitString) val.getValue()).toByteArray();
+ }
+}
diff --git a/libjava/gnu/java/security/x509/X509CRLEntry.java b/libjava/gnu/java/security/x509/X509CRLEntry.java
new file mode 100644
index 0000000..4057c60
--- /dev/null
+++ b/libjava/gnu/java/security/x509/X509CRLEntry.java
@@ -0,0 +1,236 @@
+/* X509CRLEntry.java -- entry in a X.509 CRL.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.x509;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import java.math.BigInteger;
+
+import java.security.cert.CRLException;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import gnu.java.io.ASN1ParsingException;
+import gnu.java.security.OID;
+import gnu.java.security.der.DERReader;
+import gnu.java.security.der.DERValue;
+import gnu.java.security.der.DERWriter;
+
+/**
+ * A single entry in a X.509 certificate revocation list.
+ *
+ * @see X509CRL
+ * @author Casey Marshall
+ */
+class X509CRLEntry extends java.security.cert.X509CRLEntry
+{
+
+ // Constants and fields.
+ // ------------------------------------------------------------------------
+
+ /** The DER encoded form of this CRL entry. */
+ private byte[] encoded;
+
+ /** The revoked certificate's serial number. */
+ private BigInteger serialNo;
+
+ /** The date the certificate was revoked. */
+ private Date revocationDate;
+
+ /** The encoded extensions. */
+ private HashMap extensions;
+
+ /** The set of critical extension OIDs. */
+ private HashSet critOids;
+
+ /** the set of non-critical extension OIDs. */
+ private HashSet nonCritOids;
+
+ // Constructor.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new X.509 certificate revocation list entry from the given
+ * input stream and CRL version number.
+ *
+ * @param version The CRL version.
+ * @param encoded The stream of DER bytes.
+ * @throws CRLException If the ASN.1 structure is invalid.
+ * @throws IOException If the bytes cannot be read.
+ */
+ X509CRLEntry(int version, InputStream encoded)
+ throws CRLException, IOException
+ {
+ super();
+ extensions = new HashMap();
+ critOids = new HashSet();
+ nonCritOids = new HashSet();
+ try
+ {
+ parse(version, encoded);
+ }
+ catch (IOException ioe)
+ {
+ throw ioe;
+ }
+ catch (Exception x)
+ {
+ throw new CRLException(x.toString());
+ }
+ }
+
+ // X509CRLEntry methods.
+ // ------------------------------------------------------------------------
+
+ public boolean equals(Object o)
+ {
+ return ((X509CRLEntry) o).serialNo.equals(serialNo) &&
+ ((X509CRLEntry) o).revocationDate.equals(revocationDate);
+ }
+
+ public int hashCode()
+ {
+ return serialNo.hashCode();
+ }
+
+ public byte[] getEncoded() throws CRLException
+ {
+ return (byte[]) encoded.clone();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return serialNo;
+ }
+
+ public Date getRevocationDate()
+ {
+ return (Date) revocationDate.clone();
+ }
+
+ public boolean hasExtensions()
+ {
+ return ! extensions.isEmpty();
+ }
+
+ public String toString()
+ {
+ return "X509CRLEntry serial=" + serialNo + " revocation date="
+ + revocationDate + " critExt=" + critOids + " ext=" + nonCritOids;
+ }
+
+ // X509Extension methods.
+ // ------------------------------------------------------------------------
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ return false; // XXX
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return Collections.unmodifiableSet(critOids);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return Collections.unmodifiableSet(nonCritOids);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ byte[] ext = (byte[]) extensions.get(oid);
+ if (ext != null)
+ return (byte[]) ext.clone();
+ return null;
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ private void parse(int version, InputStream in) throws Exception
+ {
+ DERReader der = new DERReader(in);
+ DERValue entry = der.read();
+ if (!entry.isConstructed())
+ throw new ASN1ParsingException("malformed revokedCertificate");
+ encoded = entry.getEncoded();
+ int len = 0;
+ DERValue val = der.read();
+ serialNo = (BigInteger) val.getValue();
+ len += DERWriter.definiteEncodingSize(val.getLength())
+ + val.getLength() + 1;
+ val = der.read();
+ revocationDate = (Date) val.getValue();
+ len += DERWriter.definiteEncodingSize(val.getLength())
+ + val.getLength() + 1;
+
+ if (len < entry.getLength())
+ {
+ if (version < 2)
+ throw new ASN1ParsingException("extra data in CRL entry");
+ while (len < entry.getLength())
+ {
+ val = der.read();
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed Extension");
+ OID extOid = (OID) der.read().getValue();
+ Boolean critical = Boolean.valueOf(false);
+ DERValue val2 = der.read();
+ if (val2.getValue() instanceof Boolean)
+ {
+ critical = (Boolean) val2.getValue();
+ val2 = der.read();
+ }
+ byte[] ext = (byte[]) val2.getValue();
+ extensions.put(extOid.toString(), ext);
+ if (critical.booleanValue())
+ critOids.add(extOid.toString());
+ else
+ nonCritOids.add(extOid.toString());
+ len += val.getEncodedLength();
+ }
+ }
+ }
+}
diff --git a/libjava/gnu/java/security/x509/X509Certificate.java b/libjava/gnu/java/security/x509/X509Certificate.java
new file mode 100644
index 0000000..bb66f2e
--- /dev/null
+++ b/libjava/gnu/java/security/x509/X509Certificate.java
@@ -0,0 +1,693 @@
+/* X509Certificate.java -- X.509 certificate.
+ Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.java.security.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Serializable;
+
+import java.math.BigInteger;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import gnu.java.io.ASN1ParsingException;
+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;
+
+/**
+ * An implementation of X.509 certificates.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public class X509Certificate extends java.security.cert.X509Certificate
+ implements Serializable
+{
+
+ // Constants and fields.
+ // ------------------------------------------------------------------------
+
+ private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
+ private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
+ private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
+ private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
+ private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
+ private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
+
+ private static final OID ID_EXTENSION = new OID("2.5.29");
+ private static final OID ID_KEY_USAGE = ID_EXTENSION.getChild(15);
+ private static final OID ID_BASIC_CONSTRAINTS = ID_EXTENSION.getChild(19);
+ private static final OID ID_EXT_KEY_USAGE = ID_EXTENSION.getChild(37);
+
+ private static final int OTHER_NAME = 0;
+ private static final int RFC882_NAME = 1;
+ private static final int DNS_NAME = 2;
+ private static final int X400_ADDRESS = 3;
+ private static final int DIRECTORY_NAME = 4;
+ private static final int EDI_PARTY_NAME = 5;
+ private static final int URI = 6;
+ private static final int IP_ADDRESS = 7;
+ private static final int REGISTERED_ID = 8;
+
+ // This object SHOULD be serialized with an instance of
+ // java.security.cert.Certificate.CertificateRep, thus all fields are
+ // transient.
+
+ // The encoded certificate.
+ private transient byte[] encoded;
+
+ // TBSCertificate part.
+ private transient byte[] tbsCertBytes;
+ private transient int version;
+ private transient BigInteger serialNo;
+ private transient OID algId;
+ private transient byte[] algVal;
+ private transient X500Principal issuer;
+ private transient Date notBefore;
+ private transient Date notAfter;
+ private transient X500Principal subject;
+ private transient PublicKey subjectKey;
+ private transient BitString issuerUniqueId;
+ private transient BitString subjectUniqueId;
+ private transient HashMap extensions;
+ private transient HashSet critOids;
+ private transient HashSet nonCritOids;
+
+ private transient BitString keyUsage;
+ private transient int basicConstraints = -1;
+
+ // Signature.
+ private transient OID sigAlgId;
+ private transient byte[] sigAlgVal;
+ private transient byte[] signature;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new X.509 certificate from the encoded data. The input
+ * data are expected to be the ASN.1 DER encoding of the certificate.
+ *
+ * @param encoded The encoded certificate data.
+ * @throws IOException If the certificate cannot be read, possibly
+ * from a formatting error.
+ * @throws CertificateException If the data read is not an X.509
+ * certificate.
+ */
+ public X509Certificate(InputStream encoded)
+ throws CertificateException, IOException
+ {
+ super();
+ extensions = new HashMap();
+ critOids = new HashSet();
+ nonCritOids = new HashSet();
+ try
+ {
+ parse(encoded);
+ }
+ catch (IOException ioe)
+ {
+ throw ioe;
+ }
+ catch (Exception e)
+ {
+ throw new CertificateException(e.toString());
+ }
+ }
+
+ // X509Certificate methods.
+ // ------------------------------------------------------------------------
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ checkValidity(new Date());
+ }
+
+ public void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.compareTo(notBefore) < 0)
+ throw new CertificateNotYetValidException();
+ if (date.compareTo(notAfter) > 0)
+ throw new CertificateExpiredException();
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return serialNo;
+ }
+
+ public Principal getIssuerDN()
+ {
+ return getIssuerX500Principal();
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ return issuer;
+ }
+
+ public Principal getSubjectDN()
+ {
+ return getSubjectX500Principal();
+ }
+
+ public X500Principal getSubjectX500Principal()
+ {
+ return subject;
+ }
+
+ public Date getNotBefore()
+ {
+ return (Date) notBefore.clone();
+ }
+
+ public Date getNotAfter()
+ {
+ return (Date) notAfter.clone();
+ }
+
+ public byte[] getTBSCertificate() throws CertificateEncodingException
+ {
+ return (byte[]) tbsCertBytes.clone();
+ }
+
+ public byte[] getSignature()
+ {
+ return (byte[]) signature.clone();
+ }
+
+ public String getSigAlgName()
+ {
+ if (sigAlgId.equals(ID_DSA_WITH_SHA1))
+ return "SHA1withDSA";
+ if (sigAlgId.equals(ID_RSA_WITH_MD2 ))
+ return "MD2withRSA";
+ if (sigAlgId.equals(ID_RSA_WITH_MD5 ))
+ return "MD5withRSA";
+ if (sigAlgId.equals(ID_RSA_WITH_SHA1 ))
+ return "SHA1withRSA";
+ return "unknown";
+ // return sigAlgId.getShortName();
+ }
+
+ public String getSigAlgOID()
+ {
+ return sigAlgId.toString();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ return (byte[]) sigAlgVal.clone();
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ if (issuerUniqueId != null)
+ return issuerUniqueId.toBooleanArray();
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ if (subjectUniqueId != null)
+ return subjectUniqueId.toBooleanArray();
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ if (keyUsage != null)
+ return keyUsage.toBooleanArray();
+ return null;
+ }
+
+ public List getExtendedKeyUsage() throws CertificateParsingException
+ {
+ byte[] ext = (byte[]) extensions.get("2.5.29.37");
+ if (ext == null)
+ return null;
+ LinkedList usages = new LinkedList();
+ try
+ {
+ DERReader der = new DERReader(new ByteArrayInputStream(ext));
+ DERValue seq = der.read();
+ if (!seq.isConstructed())
+ throw new CertificateParsingException();
+ int len = 0;
+ while (len < seq.getLength())
+ {
+ DERValue oid = der.read();
+ if (!(oid.getValue() instanceof OID))
+ throw new CertificateParsingException();
+ usages.add(oid.getValue().toString());
+ len += DERWriter.definiteEncodingSize(oid.getLength())
+ + oid.getLength() + 1;
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new CertificateParsingException();
+ }
+ return usages;
+ }
+
+ public int getBasicConstraints()
+ {
+ return basicConstraints;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ byte[] ext = getExtensionValue("2.5.29.17");
+ if (ext == null)
+ return null;
+ return getAltNames(ext);
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ byte[] ext = getExtensionValue("2.5.29.18");
+ if (ext == null)
+ return null;
+ return getAltNames(ext);
+ }
+
+ // X509Extension methods.
+ // ------------------------------------------------------------------------
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ for (Iterator it = critOids.iterator(); it.hasNext(); )
+ {
+ String oid = (String) it.next();
+ if (!oid.equals("2.5.29.15") && !oid.equals("2.5.29.17") &&
+ !oid.equals("2.5.29.18") && !oid.equals("2.5.29.19") &&
+ !oid.equals("2.5.29.37"))
+ return true;
+ }
+ return false;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return Collections.unmodifiableSet(critOids);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return Collections.unmodifiableSet(nonCritOids);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ byte[] ext = (byte[]) extensions.get(oid);
+ if (ext != null)
+ return (byte[]) ext.clone();
+ return null;
+ }
+
+ // Certificate methods.
+ // ------------------------------------------------------------------------
+
+ public byte[] getEncoded() throws CertificateEncodingException
+ {
+ return (byte[]) encoded.clone();
+ }
+
+ public void verify(PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature sig = Signature.getInstance(sigAlgId.toString());
+ doVerify(sig, key);
+ }
+
+ public void verify(PublicKey key, String provider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature sig = Signature.getInstance(sigAlgId.toString(), provider);
+ doVerify(sig, key);
+ }
+
+ public String toString()
+ {
+ // XXX say more than this.
+ return gnu.java.security.x509.X509Certificate.class.getName();
+ }
+
+ public PublicKey getPublicKey()
+ {
+ return subjectKey;
+ }
+
+ public Object writeReplace() throws java.io.ObjectStreamException
+ {
+ return super.writeReplace();
+ }
+
+ // Own methods.
+ // ------------------------------------------------------------------------
+
+ /**
+ * Verify this certificate's signature.
+ */
+ private void doVerify(Signature sig, PublicKey key)
+ throws CertificateException, InvalidKeyException, SignatureException
+ {
+ sig.initVerify(key);
+ sig.update(tbsCertBytes);
+ if (!sig.verify(signature))
+ throw new CertificateException("signature not validated");
+ }
+
+ /**
+ * Read a GeneralNames structure.
+ */
+ private List getAltNames(byte[] encoded)
+ throws CertificateParsingException
+ {
+ LinkedList names = new LinkedList();
+ try
+ {
+ ByteArrayInputStream in = new ByteArrayInputStream(encoded);
+ DERReader der = new DERReader(in);
+ DERValue seq = der.read();
+ if (!seq.isConstructed())
+ throw new CertificateParsingException();
+ int len = 0;
+ while (len < seq.getLength())
+ {
+ DERValue name = der.read();
+ ArrayList pair = new ArrayList(2);
+ Object nameVal = null;
+ switch (name.getTag())
+ {
+ case RFC882_NAME:
+ case DNS_NAME:
+ case URI:
+ nameVal = new String((byte[]) name.getValue());
+ break;
+ case IP_ADDRESS:
+ nameVal = java.net.InetAddress.getByAddress(
+ (byte[]) name.getValue()).getHostAddress();
+ break;
+ case REGISTERED_ID:
+ nameVal = new OID((byte[]) name.getValue());
+ break;
+ case OTHER_NAME:
+ case X400_ADDRESS:
+ case DIRECTORY_NAME:
+ case EDI_PARTY_NAME:
+ nameVal = name.getEncoded();
+ break;
+ default:
+ throw new CertificateParsingException();
+ }
+ pair.add(new Integer(name.getTag()));
+ pair.add(nameVal);
+ names.add(pair);
+ if (name.isConstructed())
+ in.skip(name.getLength());
+ len += name.getEncodedLength();
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new CertificateParsingException(ioe.toString());
+ }
+ return Collections.unmodifiableList(names);
+ }
+
+ /**
+ * Parse a DER stream into an X.509 certificate.
+ *
+ * @param encoded The encoded bytes.
+ */
+ private void parse(InputStream encoded) throws Exception
+ {
+ DERReader der = new DERReader(encoded);
+
+ // Certificate ::= SEQUENCE {
+ DERValue cert = der.read();
+ this.encoded = cert.getEncoded();
+ if (!cert.isConstructed())
+ throw new ASN1ParsingException("malformed Certificate");
+
+ // TBSCertificate ::= SEQUENCE {
+ DERValue tbsCert = der.read();
+ if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE)
+ throw new ASN1ParsingException("malformed TBSCertificate");
+ tbsCertBytes = tbsCert.getEncoded();
+
+ DERValue val = der.read();
+ if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0)
+ {
+ // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) }
+ version = ((BigInteger) der.read().getValue()).intValue() + 1;
+ val = der.read();
+ }
+ else
+ {
+ version = 1;
+ }
+ // SerialNumber ::= INTEGER
+ serialNo = (BigInteger) val.getValue();
+
+ // AlgorithmIdentifier ::= SEQUENCE {
+ val = der.read();
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed AlgorithmIdentifier");
+ int certAlgLen = val.getLength();
+ val = der.read();
+ algId = (OID) val.getValue();
+ if (certAlgLen > val.getEncodedLength())
+ {
+ val = der.read();
+ if (val == null)
+ algVal = null;
+ else
+ algVal = val.getEncoded();
+ if (val.isConstructed())
+ encoded.skip(val.getLength());
+ }
+
+ issuer = new X500Principal(encoded);
+
+ if (!der.read().isConstructed())
+ throw new ASN1ParsingException("malformed Validity");
+ notBefore = (Date) der.read().getValue();
+ notAfter = (Date) der.read().getValue();
+
+ subject = new X500Principal(encoded);
+
+ if (!der.read().isConstructed())
+ throw new ASN1ParsingException("malformed SubjectPublicKeyInfo");
+
+ val = der.read();
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed AlgorithmIdentifier");
+ int keyAlgLen = val.getLength();
+ val = der.read();
+ OID keyID = (OID) val.getValue();
+ byte[] keyParams = null;
+ if (keyAlgLen > val.getEncodedLength())
+ {
+ val = der.read();
+ keyParams = val.getEncoded();
+ if (algVal == null)
+ algVal = keyParams;
+ if (val.isConstructed())
+ encoded.skip(val.getLength());
+ }
+ val = der.read();
+ byte[] keyVal = ((BitString) val.getValue()).toByteArray();
+
+ if (keyID.equals(ID_DSA))
+ {
+ AlgorithmParameters params = AlgorithmParameters.getInstance("DSA");
+ params.init(keyParams, "ASN.1");
+ KeyFactory keyFac = KeyFactory.getInstance("DSA");
+ DSAParameterSpec spec = (DSAParameterSpec)
+ params.getParameterSpec(DSAParameterSpec.class);
+ subjectKey = keyFac.generatePublic(new DSAPublicKeySpec(
+ (BigInteger) new DERReader(keyVal).read().getValue(),
+ spec.getP(), spec.getQ(), spec.getG()));
+ }
+ else if (keyID.equals(ID_RSA))
+ {
+ KeyFactory keyFac = KeyFactory.getInstance("RSA");
+ DERReader rsaKey = new DERReader(keyVal);
+ if (!rsaKey.read().isConstructed())
+ throw new ASN1ParsingException("malformed RSAPublicKey");
+ subjectKey = keyFac.generatePublic(new RSAPublicKeySpec(
+ (BigInteger) rsaKey.read().getValue(),
+ (BigInteger) rsaKey.read().getValue()));
+ }
+ else
+ throw new ASN1ParsingException("unknown key algorithm " + keyID);
+
+ if (version > 1)
+ val = der.read();
+ if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1)
+ {
+ byte[] b = (byte[]) val.getValue();
+ issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
+ val = der.read();
+ }
+ if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2)
+ {
+ byte[] b = (byte[]) val.getValue();
+ subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF);
+ val = der.read();
+ }
+ if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3)
+ {
+ val = der.read();
+ int len = 0;
+ while (len < val.getLength())
+ {
+ DERValue ext = der.read();
+ OID extId = (OID) der.read().getValue();
+ DERValue val2 = der.read();
+ Boolean crit = Boolean.valueOf(false);
+ if (val2.getValue() instanceof Boolean)
+ {
+ crit = (Boolean) val2.getValue();
+ val2 = der.read();
+ }
+ byte[] extVal = (byte[]) val2.getValue();
+ extensions.put(extId.toString(), extVal);
+ if (crit.booleanValue())
+ critOids.add(extId.toString());
+ else
+ nonCritOids.add(extId.toString());
+ if (extId.equals(ID_KEY_USAGE))
+ {
+ keyUsage = (BitString) DERReader.read(extVal).getValue();
+ }
+ else if (extId.equals(ID_BASIC_CONSTRAINTS))
+ {
+ DERReader bc = new DERReader(extVal);
+ DERValue constraints = bc.read();
+ if (!constraints.isConstructed())
+ throw new ASN1ParsingException("malformed BasicConstraints");
+ if (constraints.getLength() > 0)
+ {
+ boolean ca = false;
+ int constr = -1;
+ val2 = bc.read();
+ if (val2.getValue() instanceof Boolean)
+ {
+ ca = ((Boolean) val2.getValue()).booleanValue();
+ if (constraints.getLength() > val2.getEncodedLength())
+ val2 = bc.read();
+ }
+ if (val2.getValue() instanceof BigInteger)
+ constr = ((BigInteger) val2.getValue()).intValue();
+ basicConstraints = constr;
+ }
+ }
+ len += ext.getEncodedLength();
+ }
+ }
+
+ val = der.read();
+ if (!val.isConstructed())
+ throw new ASN1ParsingException("malformed AlgorithmIdentifier");
+ int sigAlgLen = val.getLength();
+ val = der.read();
+ sigAlgId = (OID) val.getValue();
+ if (sigAlgLen > val.getEncodedLength())
+ {
+ val = der.read();
+ if (val.getValue() == null)
+ sigAlgVal = keyParams;
+ else
+ sigAlgVal = (byte[]) val.getEncoded();
+ if (val.isConstructed())
+ encoded.skip(val.getLength());
+ }
+ signature = ((BitString) der.read().getValue()).toByteArray();
+ }
+}