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
This commit is contained in:
committed by
Michael Koch
parent
505b0fd661
commit
43905ff30b
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 + " ]";
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user