diff options
author | David Hook <dgh@cryptoworkshop.com> | 2013-06-01 03:08:23 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2013-06-01 03:08:23 +0400 |
commit | 9d86fa64cab222f265c18994eab1d7a5db786da7 (patch) | |
tree | d133f3cb8f4f335e38c4ca5d56a32a84dc470c86 /core/src/main/jdk1.1 | |
parent | 1f388cb05faef261ab0fc6d3b898d3a32c00e94a (diff) |
other jdk import
Diffstat (limited to 'core/src/main/jdk1.1')
109 files changed, 15863 insertions, 0 deletions
diff --git a/core/src/main/jdk1.1/java/lang/UnsupportedOperationException.java b/core/src/main/jdk1.1/java/lang/UnsupportedOperationException.java new file mode 100644 index 00000000..86529c82 --- /dev/null +++ b/core/src/main/jdk1.1/java/lang/UnsupportedOperationException.java @@ -0,0 +1,14 @@ + +package java.lang; + +public class UnsupportedOperationException extends RuntimeException +{ + public UnsupportedOperationException() + { + } + + public UnsupportedOperationException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/AlgorithmParameterGenerator.java b/core/src/main/jdk1.1/java/security/AlgorithmParameterGenerator.java new file mode 100644 index 00000000..04810849 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/AlgorithmParameterGenerator.java @@ -0,0 +1,96 @@ +package java.security; + +import java.security.spec.AlgorithmParameterSpec; + +public class AlgorithmParameterGenerator +{ + AlgorithmParameterGeneratorSpi spi; + Provider provider; + String algorithm; + + protected AlgorithmParameterGenerator( + AlgorithmParameterGeneratorSpi paramGenSpi, + Provider provider, + String algorithm) + { + this.spi = paramGenSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + public final AlgorithmParameters generateParameters() + { + return spi.engineGenerateParameters(); + } + + public final String getAlgorithm() + { + return algorithm; + } + + public static AlgorithmParameterGenerator getInstance(String algorithm) + throws NoSuchAlgorithmException + { + try + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("AlgorithmParameterGenerator", algorithm, null); + + if (imp != null) + { + return new AlgorithmParameterGenerator((AlgorithmParameterGeneratorSpi)imp.getEngine(), imp.getProvider(), algorithm); + } + + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + } + + public static AlgorithmParameterGenerator getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("AlgorithmParameterGenerator", algorithm, provider); + + if (imp != null) + { + return new AlgorithmParameterGenerator((AlgorithmParameterGeneratorSpi)imp.getEngine(), imp.getProvider(), algorithm); + } + + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + public final Provider getProvider() + { + return provider; + } + + public final void init( + AlgorithmParameterSpec genParamSpec) + throws InvalidAlgorithmParameterException + { + spi.engineInit(genParamSpec, new SecureRandom()); + } + + public final void init( + AlgorithmParameterSpec genParamSpec, + SecureRandom random) + throws InvalidAlgorithmParameterException + { + spi.engineInit(genParamSpec, random); + } + + public final void init( + int size) + { + spi.engineInit(size, new SecureRandom()); + } + + public final void init( + int size, + SecureRandom random) + { + spi.engineInit(size, random); + } +} diff --git a/core/src/main/jdk1.1/java/security/AlgorithmParameterGeneratorSpi.java b/core/src/main/jdk1.1/java/security/AlgorithmParameterGeneratorSpi.java new file mode 100644 index 00000000..446f53bd --- /dev/null +++ b/core/src/main/jdk1.1/java/security/AlgorithmParameterGeneratorSpi.java @@ -0,0 +1,16 @@ +package java.security; + +import java.security.spec.AlgorithmParameterSpec; + +public abstract class AlgorithmParameterGeneratorSpi +{ + public AlgorithmParameterGeneratorSpi() + { + } + + protected abstract AlgorithmParameters engineGenerateParameters(); + + protected abstract void engineInit(AlgorithmParameterSpec genParamSpec, SecureRandom random) throws InvalidAlgorithmParameterException; + + protected abstract void engineInit(int size, SecureRandom random); +} diff --git a/core/src/main/jdk1.1/java/security/AlgorithmParameters.java b/core/src/main/jdk1.1/java/security/AlgorithmParameters.java new file mode 100644 index 00000000..14f2a5ad --- /dev/null +++ b/core/src/main/jdk1.1/java/security/AlgorithmParameters.java @@ -0,0 +1,103 @@ + +package java.security; + +import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +public class AlgorithmParameters extends Object +{ + private AlgorithmParametersSpi spi; + private Provider provider; + private String algorithm; + + protected AlgorithmParameters( + AlgorithmParametersSpi paramSpi, + Provider provider, + String algorithm) + { + this.spi = paramSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + public final String getAlgorithm() + { + return algorithm; + } + + public final byte[] getEncoded() throws IOException + { + return spi.engineGetEncoded(); + } + + public final byte[] getEncoded(String format) throws IOException + { + return spi.engineGetEncoded(format); + } + + public static AlgorithmParameters getInstance(String algorithm) + throws NoSuchAlgorithmException + { + try + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("AlgorithmParameters", algorithm, null); + + if (imp != null) + { + return new AlgorithmParameters((AlgorithmParametersSpi)imp.getEngine(), imp.getProvider(), algorithm); + } + + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + } + + public static AlgorithmParameters getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("AlgorithmParameters", algorithm, provider); + + if (imp != null) + { + return new AlgorithmParameters((AlgorithmParametersSpi)imp.getEngine(), imp.getProvider(), algorithm); + } + + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + public final AlgorithmParameterSpec getParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + return spi.engineGetParameterSpec(paramSpec); + } + + public final Provider getProvider() + { + return provider; + } + + public final void init(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + spi.engineInit(paramSpec); + } + + public final void init(byte[] params) throws IOException + { + spi.engineInit(params); + } + + public final void init(byte[] params, String format) throws IOException + { + spi.engineInit(params, format); + } + + public final String toString() + { + return spi.engineToString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/AlgorithmParametersSpi.java b/core/src/main/jdk1.1/java/security/AlgorithmParametersSpi.java new file mode 100644 index 00000000..59519a34 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/AlgorithmParametersSpi.java @@ -0,0 +1,27 @@ + +package java.security; + +import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +public abstract class AlgorithmParametersSpi extends Object +{ + public AlgorithmParametersSpi() + { + } + + protected abstract byte[] engineGetEncoded() + throws IOException; + protected abstract byte[] engineGetEncoded(String format) + throws IOException; + protected abstract AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException; + protected abstract void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException; + protected abstract void engineInit(byte[] params) + throws IOException; + protected abstract void engineInit(byte[] params, String format) + throws IOException; + protected abstract String engineToString(); +} diff --git a/core/src/main/jdk1.1/java/security/GeneralSecurityException.java b/core/src/main/jdk1.1/java/security/GeneralSecurityException.java new file mode 100644 index 00000000..fb4a5f4d --- /dev/null +++ b/core/src/main/jdk1.1/java/security/GeneralSecurityException.java @@ -0,0 +1,14 @@ + +package java.security; + +public class GeneralSecurityException extends Exception +{ + public GeneralSecurityException() + { + } + + public GeneralSecurityException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/InvalidAlgorithmParameterException.java b/core/src/main/jdk1.1/java/security/InvalidAlgorithmParameterException.java new file mode 100644 index 00000000..e56228c2 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/InvalidAlgorithmParameterException.java @@ -0,0 +1,13 @@ + +package java.security; + +public class InvalidAlgorithmParameterException extends GeneralSecurityException { + public InvalidAlgorithmParameterException() + { + } + + public InvalidAlgorithmParameterException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/KeyFactory.java b/core/src/main/jdk1.1/java/security/KeyFactory.java new file mode 100644 index 00000000..320aac3f --- /dev/null +++ b/core/src/main/jdk1.1/java/security/KeyFactory.java @@ -0,0 +1,89 @@ + +package java.security; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +public class KeyFactory extends Object +{ + private KeyFactorySpi keyFacSpi; + private Provider provider; + private String algorithm; + + protected KeyFactory( + KeyFactorySpi keyFacSpi, + Provider provider, + String algorithm) + { + this.keyFacSpi = keyFacSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + public final PrivateKey generatePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGeneratePrivate(keySpec); + } + + public final PublicKey generatePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGeneratePublic(keySpec); + } + + public final String getAlgorithm() + { + return algorithm; + } + + public static KeyFactory getInstance(String algorithm) + throws NoSuchAlgorithmException + { + try + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("KeyFactory", algorithm, null); + + if (imp != null) + { + return new KeyFactory((KeyFactorySpi)imp.getEngine(), imp.getProvider(), algorithm); + } + + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + catch (NoSuchProviderException e) + { + throw new NoSuchAlgorithmException(algorithm + " not found"); + } + } + + public static KeyFactory getInstance(String algorithm, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("KeyFactory", algorithm, null); + + if (imp != null) + { + return new KeyFactory((KeyFactorySpi)imp.getEngine(), imp.getProvider(), algorithm); + } + + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + public final KeySpec getKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + return keyFacSpi.engineGetKeySpec(key, keySpec); + } + + public final Provider getProvider() + { + return provider; + } + + public final Key translateKey(Key key) + throws InvalidKeyException + { + return keyFacSpi.engineTranslateKey(key); + } +} diff --git a/core/src/main/jdk1.1/java/security/KeyFactorySpi.java b/core/src/main/jdk1.1/java/security/KeyFactorySpi.java new file mode 100644 index 00000000..6d160e7c --- /dev/null +++ b/core/src/main/jdk1.1/java/security/KeyFactorySpi.java @@ -0,0 +1,24 @@ + +package java.security; + +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +public abstract class KeyFactorySpi extends Object +{ + public KeyFactorySpi() + { + } + + protected abstract PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException; + + protected abstract PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException; + + protected abstract KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException; + + protected abstract Key engineTranslateKey(Key key) + throws InvalidKeyException; +} diff --git a/core/src/main/jdk1.1/java/security/KeyStore.java b/core/src/main/jdk1.1/java/security/KeyStore.java new file mode 100644 index 00000000..0ded759a --- /dev/null +++ b/core/src/main/jdk1.1/java/security/KeyStore.java @@ -0,0 +1,225 @@ + +package java.security; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Date; +import java.util.Enumeration; + +public class KeyStore extends Object +{ + private KeyStoreSpi keyStoreSpi; + private Provider provider; + private String type; + private boolean initialised; + + protected KeyStore( + KeyStoreSpi keyStoreSpi, + Provider provider, + String type) + { + this.keyStoreSpi = keyStoreSpi; + this.provider = provider; + this.type = type; + this.initialised = false; + } + + public final Enumeration aliases() throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineAliases(); + } + + public final boolean containsAlias(String alias) throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineContainsAlias(alias); + } + + public final void deleteEntry(String alias) throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + keyStoreSpi.engineDeleteEntry(alias); + } + + public final Certificate getCertificate(String alias) + throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineGetCertificate(alias); + } + + public final String getCertificateAlias(Certificate cert) + throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineGetCertificateAlias(cert); + } + + public final Certificate[] getCertificateChain(String alias) + throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineGetCertificateChain(alias); + } + + public final Date getCreationDate(String alias) throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineGetCreationDate(alias); + } + + public static final String getDefaultType() + { + return "JKS"; + } + + public static KeyStore getInstance(String type) throws KeyStoreException + { + try + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("KeyStore", type, null); + + if (imp != null) + { + return new KeyStore((KeyStoreSpi)imp.getEngine(), imp.getProvider(), type); + } + + throw new KeyStoreException("can't find type " + type); + } + catch (NoSuchProviderException e) + { + throw new KeyStoreException(type + " not found"); + } + } + + public static KeyStore getInstance(String type, String provider) + throws KeyStoreException, NoSuchProviderException + { + SecurityUtil.Implementation imp = SecurityUtil.getImplementation("KeyStore", type, provider); + + if (imp != null) + { + return new KeyStore((KeyStoreSpi)imp.getEngine(), imp.getProvider(), type); + } + + throw new KeyStoreException("can't find type " + type); + } + + public final Key getKey(String alias, char[] password) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineGetKey(alias, password); + } + + public final Provider getProvider() + { + return provider; + } + + public final String getType() + { + return type; + } + + public final boolean isCertificateEntry(String alias) + throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineIsCertificateEntry(alias); + } + + public final boolean isKeyEntry(String alias) throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineIsKeyEntry(alias); + } + + public final void load( + InputStream stream, + char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + keyStoreSpi.engineLoad(stream, password); + initialised = true; + } + + public final void setCertificateEntry(String alias, Certificate cert) + throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + keyStoreSpi.engineSetCertificateEntry(alias, cert); + } + + public final void setKeyEntry( + String alias, + Key key, + char[] password, + Certificate[] chain) + throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + keyStoreSpi.engineSetKeyEntry(alias, key, password, chain); + } + + public final void setKeyEntry( + String alias, + byte[] key, + Certificate[] chain) + throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + keyStoreSpi.engineSetKeyEntry(alias, key, chain); + } + + public final int size() throws KeyStoreException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + return keyStoreSpi.engineSize(); + } + + public final void store( + OutputStream stream, + char[] password) + throws KeyStoreException, IOException, NoSuchAlgorithmException, + CertificateException + { + if ( !initialised ) + throw new KeyStoreException("KeyStore not initialised."); + + keyStoreSpi.engineStore(stream, password); + } +} diff --git a/core/src/main/jdk1.1/java/security/KeyStoreException.java b/core/src/main/jdk1.1/java/security/KeyStoreException.java new file mode 100644 index 00000000..2e07503d --- /dev/null +++ b/core/src/main/jdk1.1/java/security/KeyStoreException.java @@ -0,0 +1,14 @@ + +package java.security; + +public class KeyStoreException extends GeneralSecurityException +{ + public KeyStoreException() + { + } + + public KeyStoreException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/KeyStoreSpi.java b/core/src/main/jdk1.1/java/security/KeyStoreSpi.java new file mode 100644 index 00000000..87c48452 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/KeyStoreSpi.java @@ -0,0 +1,59 @@ + +package java.security; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.util.Date; +import java.util.Enumeration; + +public abstract class KeyStoreSpi extends Object +{ + public KeyStoreSpi() + { + } + + public abstract Enumeration engineAliases(); + + public abstract boolean engineContainsAlias(String alias); + + public abstract void engineDeleteEntry(String alias) + throws KeyStoreException; + + public abstract Certificate engineGetCertificate(String alias); + + public abstract String engineGetCertificateAlias(Certificate cert); + + public abstract Certificate[] engineGetCertificateChain(String alias); + + public abstract Date engineGetCreationDate(String alias); + + public abstract Key engineGetKey(String alias, char[] password) + throws NoSuchAlgorithmException, UnrecoverableKeyException; + + public abstract boolean engineIsCertificateEntry(String alias); + + public abstract boolean engineIsKeyEntry(String alias); + + public abstract void engineLoad(InputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException; + + public abstract void engineSetCertificateEntry( + String alias, Certificate cert) + throws KeyStoreException; + + public abstract void engineSetKeyEntry( + String alias, Key key, char[] password, Certificate[] chain) + throws KeyStoreException; + + public abstract void engineSetKeyEntry( + String alias, byte[] key, Certificate[] chain) + throws KeyStoreException; + + public abstract int engineSize(); + + public abstract void engineStore(OutputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException; +} diff --git a/core/src/main/jdk1.1/java/security/SecurityUtil.java b/core/src/main/jdk1.1/java/security/SecurityUtil.java new file mode 100644 index 00000000..13c313cf --- /dev/null +++ b/core/src/main/jdk1.1/java/security/SecurityUtil.java @@ -0,0 +1,114 @@ +package java.security; + + +class SecurityUtil +{ + static class Implementation + { + Object engine; + Provider provider; + + Implementation( + Object engine, + Provider provider) + { + this.engine = engine; + this.provider = provider; + } + + Object getEngine() + { + return engine; + } + + Provider getProvider() + { + return provider; + } + } + + /** + * see if we can find an algorithm (or its alias and what it represents) in + * the property table for the given provider. + * + * @return null if no algorithm found, an Implementation if it is. + */ + static private Implementation getImplementation( + String baseName, + String algorithm, + Provider prov) + { + String alias; + + while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null) + { + algorithm = alias; + } + + String className = prov.getProperty(baseName + "." + algorithm); + + if (className != null) + { + try + { + return new Implementation(Class.forName(className).newInstance(), prov); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but no class found!"); + } + catch (Exception e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but class inaccessible!"); + } + } + + return null; + } + + /** + * return an implementation for a given algorithm/provider. + * If the provider is null, we grab the first avalaible who has the required algorithm. + * + * @return null if no algorithm found, an Implementation if it is. + * @exception NoSuchProviderException if a provider is specified and not found. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + String provider) + throws NoSuchProviderException + { + if (provider == null) + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + Implementation imp = getImplementation(baseName, algorithm, prov[i]); + if (imp != null) + { + return imp; + } + } + } + else + { + Provider prov = Security.getProvider(provider); + + if (prov == null) + { + throw new NoSuchProviderException("Provider " + provider + " not found"); + } + + return getImplementation(baseName, algorithm, prov); + } + + return null; + } +} diff --git a/core/src/main/jdk1.1/java/security/UnrecoverableKeyException.java b/core/src/main/jdk1.1/java/security/UnrecoverableKeyException.java new file mode 100644 index 00000000..7a1294a1 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/UnrecoverableKeyException.java @@ -0,0 +1,14 @@ + +package java.security; + +public class UnrecoverableKeyException extends GeneralSecurityException +{ + public UnrecoverableKeyException() + { + } + + public UnrecoverableKeyException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CRL.java b/core/src/main/jdk1.1/java/security/cert/CRL.java new file mode 100644 index 00000000..2eb219e0 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CRL.java @@ -0,0 +1,20 @@ + +package java.security.cert; + +public abstract class CRL +{ + private String type; + + protected CRL(String type) + { + this.type = type; + } + + public final String getType() + { + return type; + } + + public abstract boolean isRevoked(Certificate cert); + public abstract String toString(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/CRLException.java b/core/src/main/jdk1.1/java/security/cert/CRLException.java new file mode 100644 index 00000000..f079b8be --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CRLException.java @@ -0,0 +1,16 @@ + +package java.security.cert; + +import java.security.GeneralSecurityException; + +public class CRLException extends GeneralSecurityException +{ + public CRLException() + { + } + + public CRLException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CRLSelector.java b/core/src/main/jdk1.1/java/security/cert/CRLSelector.java new file mode 100644 index 00000000..2e4ff616 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CRLSelector.java @@ -0,0 +1,39 @@ +package java.security.cert; + +/** + * A selector that defines a set of criteria for selecting <code>CRL</code>s. + * Classes that implement this interface are often used to specify + * which <code>CRL</code>s should be retrieved from a <code>CertStore</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this interface are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CRL + * @see CertStore + * @see CertStore#getCRLs + **/ +public interface CRLSelector extends Cloneable +{ + /** + * Decides whether a <code>CRL</code> should be selected. + * + * @param crl the <code>CRL</code> to be checked + * + * @return <code>true</code> if the <code>CRL</code> should be selected, + * <code>false</code> otherwise + */ + public boolean match(CRL crl); + + /** + * Makes a copy of this <code>CRLSelector</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CRLSelector</code> + */ + public Object clone(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertPath.java b/core/src/main/jdk1.1/java/security/cert/CertPath.java new file mode 100644 index 00000000..ceb5cd18 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPath.java @@ -0,0 +1,283 @@ +package java.security.cert; + +import java.io.ByteArrayInputStream; +import java.io.NotSerializableException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +/** + * An immutable sequence of certificates (a certification path).<br /> + * <br /> + * This is an abstract class that defines the methods common to all + * CertPaths. Subclasses can handle different kinds of certificates + * (X.509, PGP, etc.).<br /> + * <br /> + * All CertPath objects have a type, a list of Certificates, and one + * or more supported encodings. Because the CertPath class is + * immutable, a CertPath cannot change in any externally visible way + * after being constructed. This stipulation applies to all public + * fields and methods of this class and any added or overridden by + * subclasses.<br /> + * <br /> + * The type is a String that identifies the type of Certificates in + * the certification path. For each certificate cert in a + * certification path certPath, + * cert.getType().equals(certPath.getType()) must be true.<br /> + * <br /> + * The list of Certificates is an ordered List of zero or more + * Certificates. This List and all of the Certificates contained in it + * must be immutable.<br /> + * <br /> + * Each CertPath object must support one or more encodings so that the + * object can be translated into a byte array for storage or + * transmission to other parties. Preferably, these encodings should + * be well-documented standards (such as PKCS#7). One of the encodings + * supported by a CertPath is considered the default encoding. This + * encoding is used if no encoding is explicitly requested (for the + * {@link #getEncoded()} method, for instance).<br /> + * <br /> + * All CertPath objects are also Serializable. CertPath objects are + * resolved into an alternate {@link CertPathRep} object during + * serialization. This allows a CertPath object to be serialized into + * an equivalent representation regardless of its underlying + * implementation.<br /> + * <br /> + * CertPath objects can be created with a CertificateFactory or they + * can be returned by other classes, such as a CertPathBuilder.<br /> + * <br /> + * By convention, X.509 CertPaths (consisting of X509Certificates), + * are ordered starting with the target certificate and ending with a + * certificate issued by the trust anchor. That is, the issuer of one + * certificate is the subject of the following one. The certificate + * representing the {@link TrustAnchor TrustAnchor} should not be included in the + * certification path. Unvalidated X.509 CertPaths may not follow + * these conventions. PKIX CertPathValidators will detect any + * departure from these conventions that cause the certification path + * to be invalid and throw a CertPathValidatorException.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * All CertPath objects must be thread-safe. That is, multiple threads + * may concurrently invoke the methods defined in this class on a + * single CertPath object (or more than one) with no ill effects. This + * is also true for the List returned by CertPath.getCertificates.<br /> + * <br /> + * Requiring CertPath objects to be immutable and thread-safe allows + * them to be passed around to various pieces of code without worrying + * about coordinating access. Providing this thread-safety is + * generally not difficult, since the CertPath and List objects in + * question are immutable. + * + * @see CertificateFactory + * @see CertPathBuilder + */ +public abstract class CertPath extends Object implements Serializable +{ + private String type; + + /** + * Alternate <code>CertPath</code> class for serialization. + **/ + protected static class CertPathRep + implements Serializable + { + private String type; + private byte[] data; + + /** + * Creates a <code>CertPathRep</code> with the specified + * type and encoded form of a certification path. + * + * @param type the standard name of a CertPath + * @param typedata the encoded form of the certification + * path + **/ + protected CertPathRep(String type, byte[] data) + { + this.type = type; + this.data = data; + } + + /** + * Returns a CertPath constructed from the type and data. + * + * @return the resolved CertPath object + * @exception ObjectStreamException if a CertPath could not be constructed + **/ + protected Object readResolve() + throws ObjectStreamException + { + try { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + CertificateFactory cf = CertificateFactory.getInstance(type); + return cf.generateCertPath(inStream); + } catch ( CertificateException ce ) { + throw new NotSerializableException(" java.security.cert.CertPath: " + type); + } + } + } + + /** + * Creates a CertPath of the specified type. + * This constructor is protected because most users should use + * a CertificateFactory to create CertPaths. + * @param type the standard name of the type of Certificatesin this path + **/ + protected CertPath(String type) + { + this.type = type; + } + + /** + * Returns the type of Certificates in this certification + * path. This is the same string that would be returned by + * {@link Certificate#getType() cert.getType()} for all + * Certificates in the certification path. + * + * @return the type of Certificates in this certification path (never null) + **/ + public String getType() + { + return type; + } + + /** + * Returns an iteration of the encodings supported by this + * certification path, with the default encoding + * first. Attempts to modify the returned Iterator via its + * remove method result in an UnsupportedOperationException. + * + * @return an Iterator over the names of the supported encodings (as Strings) + **/ + public abstract Iterator getEncodings(); + + /** + * Compares this certification path for equality with the + * specified object. Two CertPaths are equal if and only if + * their types are equal and their certificate Lists (and by + * implication the Certificates in those Lists) are equal. A + * CertPath is never equal to an object that is not a + * CertPath.<br /> + * <br /> + * This algorithm is implemented by this method. If it is + * overridden, the behavior specified here must be maintained. + * + * @param other the object to test for equality with this + * certification path + * + * @return true if the specified object is equal to this + * certification path, false otherwise + * + * @see Object#hashCode() Object.hashCode() + **/ + public boolean equals(Object other) + { + if (!( other instanceof CertPath ) ) + return false; + + CertPath otherCertPath = (CertPath)other; + if ( ! getType().equals(otherCertPath.getType()) ) + return false; + return getCertificates().equals(otherCertPath.getCertificates()); + } + + /** + * Returns the hashcode for this certification path. The hash + * code of a certification path is defined to be the result of + * the following calculation: + * <pre> + * hashCode = path.getType().hashCode(); + * hashCode = 31 * hashCode + path.getCertificates().hashCode(); + * </pre> + * This ensures that path1.equals(path2) implies that + * path1.hashCode()==path2.hashCode() for any two + * certification paths, path1 and path2, as required by the + * general contract of Object.hashCode. + * + * @return The hashcode value for this certification path + * + * @see #equals(Object) + **/ + public int hashCode() + { + return getType().hashCode() * 31 + getCertificates().hashCode(); + } + + /** + * Returns a string representation of this certification + * path. This calls the toString method on each of the + * Certificates in the path. + * + * @return a string representation of this certification path + **/ + public String toString() + { + StringBuffer s = new StringBuffer(); + List certs = getCertificates(); + ListIterator iter = certs.listIterator(); + s.append('\n').append(getType()).append(" Cert Path: length = ").append(certs.size()).append("\n[\n"); + while ( iter.hasNext() ) { + s.append("=========================================================Certificate ").append(iter.nextIndex()).append('\n'); + s.append(iter.next()).append('\n'); + s.append("========================================================Certificate end\n\n\n"); + } + s.append("\n]"); + return s.toString(); + } + + /** + * Returns the encoded form of this certification path, using + * the default encoding. + * + * @return the encoded bytes + * + * @exception CertificateEncodingException if an encoding error occurs + **/ + public abstract byte[] getEncoded() + throws CertificateEncodingException; + + /** + * Returns the encoded form of this certification path, using + * the specified encoding. + * + * @param encoding the name of the encoding to use + * + * @return the encoded bytes + * + * @exception CertificateEncodingException if an encoding error + * occurs or the encoding requested is not supported + **/ + public abstract byte[] getEncoded(String encoding) + throws CertificateEncodingException; + + /** + * Returns the list of certificates in this certification + * path. The List returned must be immutable and thread-safe. + * + * @return an immutable List of Certificates (may be empty, but not null) + **/ + public abstract List getCertificates(); + + /** + * Replaces the CertPath to be serialized with a CertPathRep + * object. + * + * @return the CertPathRep to be serialized + * + * @exception ObjectStreamException if a CertPathRep object + * representing this certification path could not be created + **/ + protected Object writeReplace() + throws ObjectStreamException + { + try { + return new CertPathRep( getType(), getEncoded() ); + } catch ( CertificateException ce ) { + throw new NotSerializableException( " java.security.cert.CertPath: " + getType() ); + } + } +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathBuilder.java b/core/src/main/jdk1.1/java/security/cert/CertPathBuilder.java new file mode 100644 index 00000000..b3adbf15 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathBuilder.java @@ -0,0 +1,243 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +/** + * A class for building certification paths (also known as certificate + * chains).<br /> + * <br /> + * This class uses a provider-based architecture, as described in the + * Java Cryptography Architecture. To create a + * <code>CertPathBuilder</code>, call one of the static + * <code>getInstance</code> methods, passing in the algorithm name of + * the CertPathBuilder desired and optionally the name of the provider + * desired.<br /> + * <br /> + * Once a <code>CertPathBuilder</code> object has been created, + * certification paths can be constructed by calling the + * {@link #build build} method and passing it an algorithm-specific set + * of parameters. If successful, the result (including the CertPath + * that was built) is returned in an object that implements the + * <code>CertPathBuilderResult</code> interface.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * The static methods of this class are guaranteed to be + * thread-safe. Multiple threads may concurrently invoke the static + * methods defined in this class with no ill effects.<br /> + * <br /> + * However, this is not true for the non-static methods defined by + * this class. Unless otherwise documented by a specific provider, + * threads that need to access a single <code>CertPathBuilder</code> + * instance concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating a + * different <code>CertPathBuilder</code> instance need not + * synchronize.<br /> + * <br /> + * Uses {@link CertUtil CertUtil} to actualiy load the SPI classes. + * + * @see CertUtil + **/ +public class CertPathBuilder extends Object +{ + private CertPathBuilderSpi builderSpi; + private Provider provider; + private String algorithm; + + /** + * Creates a CertPathBuilder object of the given algorithm, and + * encapsulates the given provider implementation (SPI object) + * in it. + * + * @param builderSpi the provider implementation + * @param provider the provider + * @param algorithm the algorithm name + **/ + protected CertPathBuilder(CertPathBuilderSpi builderSpi, + Provider provider, + String algorithm) + { + this.builderSpi = builderSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns a CertPathBuilder object that implements the + * specified algorithm.<br /> + * <br /> + * If the default provider package provides an implementation + * of the specified CertPathBuilder algorithm, an instance of + * CertPathBuilder containing that implementation is + * returned. If the requested algorithm is not available in + * the default package, other packages are searched.<br /> + * <br /> + * @param algorithm the name of the requested CertPathBuilder algorithm + * + * @return a CertPathBuilder object that implements the + * specified algorithm + * + * @exception NoSuchAlgorithmException if the requested + * algorithm is not available in the default provider package + * or any of the other provider packages that were searched + **/ + public static CertPathBuilder getInstance(String algorithm) + throws NoSuchAlgorithmException + { + try { + CertUtil.Implementation imp = + CertUtil.getImplementation("CertPathBuilder", algorithm, (String)null); + if (imp != null) + { + return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(), + imp.getProvider(), algorithm); + } + } catch ( NoSuchProviderException ex ) {} + throw new NoSuchAlgorithmException("can't find type " + algorithm); + } + + /** + * Returns a CertPathBuilder object that implements the + * specified algorithm, as supplied by the specified provider. + * + * @param algorithm the name of the requested CertPathBuilder + * algorithm + * @param provider the name of the provider + * + * @return a CertPathBuilder object that implements the + * specified algorithm, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException if the requested algorithm + * is not available from the specified provider + * @exception NoSuchProviderException if the provider has not + * been configured + * @exception IllegalArgumentException if the provider is null + **/ + public static CertPathBuilder getInstance(String algorithm, + String provider) + throws NoSuchAlgorithmException, + NoSuchProviderException + { + if ( provider == null ) + throw new IllegalArgumentException("provider must be non-null"); + CertUtil.Implementation imp = + CertUtil.getImplementation("CertPathBuilder", algorithm, provider); + + if (imp != null) + { + return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(), + imp.getProvider(), algorithm); + } + throw new NoSuchAlgorithmException("can't find type " + algorithm); + } + + /** + * Returns a CertPathBuilder object that implements the + * specified algorithm, as supplied by the specified + * provider. Note: the provider doesn't have to be registered. + * + * @param algorithm the name of the requested CertPathBuilder + * algorithm + * @param provider the provider + * @return a CertPathBuilder object that implements the + * specified algorithm, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException if the requested algorithm + * is not available from the specified provider + * @exception IllegalArgumentException if the provider is null. + **/ + public static CertPathBuilder getInstance(String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if ( provider == null ) + throw new IllegalArgumentException("provider must be non-null"); + CertUtil.Implementation imp = + CertUtil.getImplementation("CertPathBuilder", algorithm, provider); + + if (imp != null) + { + return new CertPathBuilder((CertPathBuilderSpi)imp.getEngine(), + provider, algorithm); + } + throw new NoSuchAlgorithmException("can't find type " + algorithm); + } + + /** + * Returns the provider of this <code>CertPathBuilder</code>. + * + * @return the provider of this <code>CertPathBuilder</code> + **/ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the name of the algorithm of this + * <code>CertPathBuilder</code>. + * + * @return the name of the algorithm of this <code>CertPathBuilder</code> + **/ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Attempts to build a certification path using the specified algorithm + * parameter set. + * + * @param params the algorithm parameters + * + * @return the result of the build algorithm + * + * @exception CertPathBuilderException if the builder is unable to construct + * a certification path that satisfies the specified parameters + * @exception InvalidAlgorithmParameterException if the specified parameters * are inappropriate for this <code>CertPathBuilder</code> + */ + public final CertPathBuilderResult build(CertPathParameters params) + throws CertPathBuilderException, + InvalidAlgorithmParameterException + { + return builderSpi.engineBuild(params); + } + + + /** + * Returns the default <code>CertPathBuilder</code> type as specified in + * the Java security properties file, or the string "PKIX" + * if no such property exists. The Java security properties file is + * located in the file named <JAVA_HOME>/lib/security/java.security, + * where <JAVA_HOME> refers to the directory where the SDK was + * installed.<br /> + * <br /> + * The default <code>CertPathBuilder</code> type can be used by + * applications that do not want to use a hard-coded type when calling one + * of the <code>getInstance</code> methods, and want to provide a default + * type in case a user does not specify its own.<br /> + * <br /> + * The default <code>CertPathBuilder</code> type can be changed by + * setting the value of the "certpathbuilder.type" security property + * (in the Java security properties file) to the desired type. + * + * @return the default <code>CertPathBuilder</code> type as specified + * in the Java security properties file, or the string "PKIX" + * if no such property exists. + */ + public static final String getDefaultType() + { + String defaulttype = null; + defaulttype = Security.getProperty("certpathbuilder.type"); + + if ( defaulttype == null || defaulttype.length() <= 0 ) + return "PKIX"; + else + return defaulttype; + } +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathBuilderException.java b/core/src/main/jdk1.1/java/security/cert/CertPathBuilderException.java new file mode 100644 index 00000000..13b60891 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathBuilderException.java @@ -0,0 +1,182 @@ +package java.security.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * An exception indicating one of a variety of problems encountered + * when building a certification path with a + * <code>CertPathBuilder</code>.<br /> + * <br /> + * A <code>CertPathBuilderException</code> provides support for + * wrapping exceptions. The {@link #getCause() getCause} method + * returns the throwable, if any, that caused this exception to be + * thrown.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are + * not thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathBuilder + **/ +public class CertPathBuilderException extends GeneralSecurityException +{ + private Throwable cause; + + /** + * Creates a <code>CertPathBuilderException</code> with <code>null</code> + * as its detail message. + */ + public CertPathBuilderException() + { + } + + /** + * Creates a <code>CertPathBuilderException</code> with the given detail + * message. The detail message is a <code>String</code> that describes + * this particular exception in more detail. + * + * @param msg + * the detail message + */ + public CertPathBuilderException(String message) + { + super(message); + } + + /** + * Creates a <code>CertPathBuilderException</code> that wraps the + * specified throwable. This allows any exception to be converted into a + * <code>CertPathBuilderException</code>, while retaining information + * about the wrapped exception, which may be useful for debugging. The + * detail message is set to + * <code>(cause==null ? null : cause.toString())</code> (which typically + * contains the class and detail message of cause). + * + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + */ + public CertPathBuilderException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + /** + * Creates a <code>CertPathBuilderException</code> with the specified + * detail message and cause. + * + * @param msg + * the detail message + * @param cause + * the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A null value is permitted, and + * indicates that the cause is nonexistent or unknown.) + */ + public CertPathBuilderException(Throwable cause) + { + this.cause = cause; + } + + /** + * Returns the internal (wrapped) cause, or null if the cause is nonexistent + * or unknown. + * + * @return the cause of this throwable or <code>null</code> if the cause + * is nonexistent or unknown. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Returns the detail message for this CertPathBuilderException. + * + * @return the detail message, or <code>null</code> if neither the message + * nor internal cause were specified + */ + public String getMessage() + { + String message = super.getMessage(); + + if (message == null && cause == null) + { + return null; + } + + if (cause != null) + { + return cause.getMessage(); + } + + return message; + } + + /** + * Returns a string describing this exception, including a description of + * the internal (wrapped) cause if there is one. + * + * @return a string representation of this + * <code>CertPathBuilderException</code> + */ + public String toString() + { + String message = getMessage(); + if (message == null) + { + return ""; + } + + return message; + } + + /** + * Prints a stack trace to <code>System.err</code>, including the + * backtrace of the cause, if any. + */ + public void printStackTrace() + { + printStackTrace(System.err); + } + + /** + * Prints a stack trace to a <code>PrintStream</code>, including the + * backtrace of the cause, if any. + * + * @param ps + * the <code>PrintStream</code> to use for output + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if (getCause() != null) + { + getCause().printStackTrace(ps); + } + } + + /** + * Prints a stack trace to a <code>PrintWriter</code>, including the + * backtrace of the cause, if any. + * + * @param ps + * the <code>PrintWriter</code> to use for output + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if (getCause() != null) + { + getCause().printStackTrace(pw); + } + } +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathBuilderResult.java b/core/src/main/jdk1.1/java/security/cert/CertPathBuilderResult.java new file mode 100644 index 00000000..c0482bc4 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathBuilderResult.java @@ -0,0 +1,38 @@ +package java.security.cert; + +/** + * A specification of the result of a certification path builder algorithm. + * All results returned by the {@link CertPathBuilder#build CertPathBuilder.build} method + * must implement this interface.<br /> + * <br /> + * At a minimum, a CertPathBuilderResult contains the CertPath built by the + * CertPathBuilder instance. Implementations of this interface may add methods + * to return implementation or algorithm specific information, such as + * debugging information or certification path validation results.<br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * Unless otherwise specified, the methods defined in this interface are not + * thread-safe. Multiple threads that need to access a single object + * concurrently should synchronize amongst themselves and provide the + * necessary locking. Multiple threads each manipulating separate objects + * need not synchronize. + **/ +public interface CertPathBuilderResult extends Cloneable +{ + /** + * Returns the built certification path. + * + * @return the certification path (never <code>null</code>) + */ + public CertPath getCertPath(); + + /** + * Makes a copy of this <code>CertPathBuilderResult</code>. + * Changes to the copy will not affect the original and vice + * versa. + * + * @return a copy of this CertPathBuilderResult + */ + public Object clone(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathBuilderSpi.java b/core/src/main/jdk1.1/java/security/cert/CertPathBuilderSpi.java new file mode 100644 index 00000000..be044fa3 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathBuilderSpi.java @@ -0,0 +1,50 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; + +/** + * The Service Provider Interface (SPI) for the CertPathBuilder + * class. All CertPathBuilder implementations must include a class + * (the SPI class) that extends this class (CertPathBuilderSpi) and + * implements all of its methods. In general, instances of this class + * should only be accessed through the CertPathBuilder class. For + * details, see the Java Cryptography Architecture.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Instances of this class need not be protected against concurrent + * access from multiple threads. Threads that need to access a single + * CertPathBuilderSpi instance concurrently should synchronize amongst + * themselves and provide the necessary locking before calling the + * wrapping CertPathBuilder object.<br /> + * <br /> + * However, implementations of CertPathBuilderSpi may still encounter + * concurrency issues, since multiple threads each manipulating a + * different CertPathBuilderSpi instance need not synchronize. + **/ +public abstract class CertPathBuilderSpi + extends Object +{ + /** + * The default constructor. + */ + public CertPathBuilderSpi() {} + + /** + * Attempts to build a certification path using the specified + * algorithm parameter set. + * + * @param params the algorithm parameters + * + * @return the result of the build algorithm + * + * @exception CertPathBuilderException if the builder is unable + * to construct a certification path that satisfies the + * specified + * @exception parametersInvalidAlgorithmParameterException if the + * specified parameters are inappropriate for this CertPathBuilder + */ + public abstract CertPathBuilderResult engineBuild( CertPathParameters params ) + throws CertPathBuilderException, + InvalidAlgorithmParameterException; +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathParameters.java b/core/src/main/jdk1.1/java/security/cert/CertPathParameters.java new file mode 100644 index 00000000..caff291a --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathParameters.java @@ -0,0 +1,18 @@ +package java.security.cert; + +/** + * A specification of certification path algorithm parameters. The purpose + * of this interface is to group (and provide type safety for) all CertPath + * parameter specifications. All <code>CertPath</code> parameter specifications must + * implement this interface. + **/ +public interface CertPathParameters extends Cloneable +{ + /** + * Makes a copy of this <code>CertPathParameters</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CertPathParameters</code> + **/ + public Object clone(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathValidator.java b/core/src/main/jdk1.1/java/security/cert/CertPathValidator.java new file mode 100644 index 00000000..aaddbf0e --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathValidator.java @@ -0,0 +1,250 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +/** + * A class for validating certification paths (also known as certificate + * chains).<br /> + * <br /> + * This class uses a provider-based architecture, as described in the Java + * Cryptography Architecture. To create a <code>CertPathValidator</code>, + * call one of the static <code>getInstance</code> methods, passing in the + * algorithm name of the <code>CertPathValidator</code> desired and + * optionally the name of the provider desired. <br /> + * <br /> + * Once a <code>CertPathValidator</code> object has been created, it can + * be used to validate certification paths by calling the {@link #validate + * validate} method and passing it the <code>CertPath</code> to be validated + * and an algorithm-specific set of parameters. If successful, the result is + * returned in an object that implements the + * <code>CertPathValidatorResult</code> interface.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * The static methods of this class are guaranteed to be thread-safe. + * Multiple threads may concurrently invoke the static methods defined in + * this class with no ill effects.<br /> + * <br /> + * However, this is not true for the non-static methods defined by this class. + * Unless otherwise documented by a specific provider, threads that need to + * access a single <code>CertPathValidator</code> instance concurrently should + * synchronize amongst themselves and provide the necessary locking. Multiple + * threads each manipulating a different <code>CertPathValidator</code> + * instance need not synchronize.<br /> + * <br /> + * Uses {@link CertUtil CertUtil} to actualiy load the SPI classes. + * + * @see CertPath + * @see CertUtil + **/ +public class CertPathValidator extends Object +{ + private CertPathValidatorSpi validatorSpi; + private Provider provider; + private String algorithm; + + /** + * Creates a <code>CertPathValidator</code> object of the given algorithm, + * and encapsulates the given provider implementation (SPI object) in it. + * + * @param validatorSpi the provider implementation + * @param provider the provider + * @param algorithm the algorithm name + */ + protected CertPathValidator( CertPathValidatorSpi validatorSpi, + Provider provider, + String algorithm) + { + this.validatorSpi = validatorSpi; + this.provider = provider; + this.algorithm = algorithm; + } + + /** + * Returns a <code>CertPathValidator</code> object that implements the + * specified algorithm.<br /> + * <br /> + * If the default provider package provides an implementation of the + * specified <code>CertPathValidator</code> algorithm, an instance of + * <code>CertPathValidator</code> containing that implementation is + * returned. If the requested algorithm is not available in the default + * package, other packages are searched. + * + * @param algorithm the name of the requested <code>CertPathValidator</code> + * algorithm + * + * @return a <code>CertPathValidator</code> object that implements the + * specified algorithm + * + * @exception NoSuchAlgorithmException if the requested algorithm + * is not available in the default provider package or any of the other + * provider packages that were searched + */ + public static CertPathValidator getInstance(String algorithm) + throws NoSuchAlgorithmException + { + try { + CertUtil.Implementation imp = + CertUtil.getImplementation("CertPathValidator", algorithm, (String)null ); + if (imp != null) + { + return new CertPathValidator((CertPathValidatorSpi)imp.getEngine(), imp.getProvider(), algorithm); + } + } catch (NoSuchProviderException ex ) {} + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + /** + * Returns a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider. + * + * @param algorithm the name of the requested <code>CertPathValidator</code> + * algorithm + * @param provider the name of the provider + * + * @return a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException if the requested algorithm + * is not available from the specified provider + * @exception NoSuchProviderException if the provider has not been + * configured + * @exception IllegalArgumentException if the <code>provider</code> is + * null + */ + public static CertPathValidator getInstance(String algorithm, + String provider) + throws NoSuchAlgorithmException, + NoSuchProviderException + { + if ( provider == null ) + throw new IllegalArgumentException("provider must be non-null"); + + CertUtil.Implementation imp = CertUtil.getImplementation("CertPathValidator", algorithm, provider ); + if (imp != null) + { + return new CertPathValidator((CertPathValidatorSpi)imp.getEngine(), imp.getProvider(), algorithm); + } + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + /** + * Returns a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider. + * Note: the <code>provider</code> doesn't have to be registered. + * + * @param algorithm the name of the requested + * <code>CertPathValidator</code> algorithm + * @param provider the provider + * + * @return a <code>CertPathValidator</code> object that implements the + * specified algorithm, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException if the requested algorithm + * is not available from the specified provider + * @exception IllegalArgumentException if the <code>provider</code> is + * null + */ + public static CertPathValidator getInstance(String algorithm, + Provider provider) + throws NoSuchAlgorithmException + { + if ( provider == null ) + throw new IllegalArgumentException("provider must be non-null"); + + CertUtil.Implementation imp = CertUtil.getImplementation("CertPathValidator", algorithm, provider ); + if (imp != null) + { + return new CertPathValidator((CertPathValidatorSpi)imp.getEngine(), provider, algorithm); + } + throw new NoSuchAlgorithmException("can't find algorithm " + algorithm); + } + + /** + * Returns the <code>Provider</code> of this + * <code>CertPathValidator</code>. + * + * @return the <code>Provider</code> of this <code>CertPathValidator</code> + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the algorithm name of this <code>CertPathValidator</code>. + * + * @return the algorithm name of this <code>CertPathValidator</code> + */ + public final String getAlgorithm() + { + return algorithm; + } + + /** + * Validates the specified certification path using the specified + * algorithm parameter set.<br /> + * <br /> + * The <code>CertPath</code> specified must be of a type that is + * supported by the validation algorithm, otherwise an + * <code>InvalidAlgorithmParameterException</code> will be thrown. For + * example, a <code>CertPathValidator</code> that implements the PKIX + * algorithm validates <code>CertPath</code> objects of type X.509. + * + * @param certPath the <code>CertPath</code> to be validated + * @param params the algorithm parameters + * + * @return the result of the validation algorithm + * + * @exception CertPathValidatorException if the <code>CertPath</code> + * does not validate + * @exception InvalidAlgorithmParameterException if the specified + * parameters or the type of the specified <code>CertPath</code> are + * inappropriate for this <code>CertPathValidator</code> + */ + public final CertPathValidatorResult validate( CertPath certPath, + CertPathParameters params) + throws CertPathValidatorException, + InvalidAlgorithmParameterException + { + return validatorSpi.engineValidate( certPath, params ); + } + + + /** + * Returns the default <code>CertPathValidator</code> type as specified in + * the Java security properties file, or the string "PKIX" + * if no such property exists. The Java security properties file is + * located in the file named <JAVA_HOME>/lib/security/java.security, + * where <JAVA_HOME> refers to the directory where the SDK was + * installed.<br /> + * <br /> + * The default <code>CertPathValidator</code> type can be used by + * applications that do not want to use a hard-coded type when calling one + * of the <code>getInstance</code> methods, and want to provide a default + * type in case a user does not specify its own.<br /> + * <br /> + * The default <code>CertPathValidator</code> type can be changed by + * setting the value of the "certpathvalidator.type" security property + * (in the Java security properties file) to the desired type. + * + * @return the default <code>CertPathValidator</code> type as specified + * in the Java security properties file, or the string "PKIX" + * if no such property exists. + */ + public static final String getDefaultType() + { + String defaulttype = null; + defaulttype = Security.getProperty("certpathvalidator.type"); + + if ( defaulttype == null || defaulttype.length() <= 0 ) + return "PKIX"; + else + return defaulttype; + } +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathValidatorException.java b/core/src/main/jdk1.1/java/security/cert/CertPathValidatorException.java new file mode 100644 index 00000000..2088ab1a --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathValidatorException.java @@ -0,0 +1,248 @@ +package java.security.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * An exception indicating one of a variety of problems encountered when + * validating a certification path. <br /> + * <br /> + * A <code>CertPathValidatorException</code> provides support for wrapping + * exceptions. The {@link #getCause getCause} method returns the throwable, + * if any, that caused this exception to be thrown. <br /> + * <br /> + * A <code>CertPathValidatorException</code> may also include the + * certification path that was being validated when the exception was thrown + * and the index of the certificate in the certification path that caused the + * exception to be thrown. Use the {@link #getCertPath getCertPath} and + * {@link #getIndex getIndex} methods to retrieve this information.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathValidator + **/ +public class CertPathValidatorException extends GeneralSecurityException +{ + private Throwable cause; + private CertPath certPath; + private int index = -1; + + /** + * Creates a <code>CertPathValidatorException</code> with + * no detail message. + */ + public CertPathValidatorException() + { + super(); + } + + /** + * Creates a <code>CertPathValidatorException</code> with the given + * detail message. A detail message is a <code>String</code> that + * describes this particular exception. + * + * @param messag the detail message + */ + public CertPathValidatorException(String message) + { + super(message); + } + + /** + * Creates a <code>CertPathValidatorException</code> with the specified + * detail message and cause. + * + * @param msg the detail message + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> value is + * permitted, and indicates that the cause is nonexistent or unknown.) + */ + public CertPathValidatorException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + /** + * Creates a <code>CertPathValidatorException</code> with the specified + * detail message, cause, certification path, and index. + * + * @param msg the detail message (or <code>null</code> if none) + * @param cause the cause (or <code>null</code> if none) + * @param certPath the certification path that was in the process of + * being validated when the error was encountered + * @param index the index of the certificate in the certification path + * that caused the error (or -1 if not applicable). Note that + * the list of certificates in a <code>CertPath</code> is zero based. + * + * @exception IndexOutOfBoundsException if the index is out of range + * <code>(index < -1 || (certPath != null && index >= + * certPath.getCertificates().size())</code> + * @exception IllegalArgumentException if <code>certPath</code> is + * <code>null</code> and <code>index</code> is not -1 + */ + public CertPathValidatorException(String message, Throwable cause, CertPath certPath, int index) + { + super( message ); + + if ( certPath == null && index != -1 ) + throw new IllegalArgumentException( "certPath = null and index != -1" ); + if ( index < -1 || ( certPath != null && index >= certPath.getCertificates().size() ) ) + throw new IndexOutOfBoundsException( " index < -1 or out of bound of certPath.getCertificates()" ); + + this.cause = cause; + this.certPath = certPath; + this.index = index; + } + + /** + * Creates a <code>CertPathValidatorException</code> that wraps the + * specified throwable. This allows any exception to be converted into a + * <code>CertPathValidatorException</code>, while retaining information + * about the wrapped exception, which may be useful for debugging. The + * detail message is set to (<code>cause==null ? null : cause.toString() + * </code>) (which typically contains the class and detail message of + * cause). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> value is + * permitted, and indicates that the cause is nonexistent or unknown.) + */ + public CertPathValidatorException(Throwable cause) + { + this.cause = cause; + } + + /** + * Returns the detail message for this + * <code>CertPathValidatorException</code>. + * + * @return the detail message, or <code>null</code> if neither the message + * nor cause were specified + */ + public String getMessage() + { + String message = super.getMessage(); + + if ( message == null && cause == null ) + return null; + + StringBuffer s = new StringBuffer(); + if ( message != null ) + { + s.append(message).append('\n'); + } + if ( cause != null ) + { + s.append("Cause:\n").append(cause.getMessage()).append('\n'); + } + return s.toString(); + } + + /** + * Returns the certification path that was being validated when + * the exception was thrown. + * + * @return the <code>CertPath</code> that was being validated when + * the exception was thrown (or <code>null</code> if not specified) + */ + public CertPath getCertPath() + { + return certPath; + } + + /** + * Returns the index of the certificate in the certification path + * that caused the exception to be thrown. Note that the list of + * certificates in a <code>CertPath</code> is zero based. If no + * index has been set, -1 is returned. + * + * @return the index that has been set, or -1 if none has been set + */ + public int getIndex() + { + return index; + } + + /** + * Returns the cause of this <code>CertPathValidatorException</code> or + * <code>null</code> if the cause is nonexistent or unknown. + * + * @return the cause of this throwable or <code>null</code> if the cause + * is nonexistent or unknown. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Returns a string describing this exception, including a description + * of the internal (wrapped) cause if there is one. + * + * @return a string representation of this + * <code>CertPathValidatorException</code> + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + String s = getMessage(); + if ( s != null ) + { + sb.append( s ); + } + if ( getIndex() >= 0 ) + { + sb.append("index in certpath: ").append(getIndex()).append('\n'); + sb.append(getCertPath()); + } + return sb.toString(); + } + + /** + * Prints a stack trace to <code>System.err</code>, including the backtrace + * of the cause, if any. + */ + public void printStackTrace() + { + printStackTrace(System.err); + } + + /** + * Prints a stack trace to a <code>PrintStream</code>, including the + * backtrace of the cause, if any. + * + * @param ps the <code>PrintStream</code> to use for output + */ + public void printStackTrace(PrintStream ps) + { + super.printStackTrace(ps); + if ( getCause() != null ) + { + getCause().printStackTrace(ps); + } + } + + /** + * Prints a stack trace to a <code>PrintWriter</code>, including the + * backtrace of the cause, if any. + * + * @param pw the <code>PrintWriter</code> to use for output + */ + public void printStackTrace(PrintWriter pw) + { + super.printStackTrace(pw); + if ( getCause() != null ) + { + getCause().printStackTrace(pw); + } + } +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathValidatorResult.java b/core/src/main/jdk1.1/java/security/cert/CertPathValidatorResult.java new file mode 100644 index 00000000..ec09641d --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathValidatorResult.java @@ -0,0 +1,22 @@ +package java.security.cert; + +/** + * A specification of the result of a certification path validator algorithm.<br /> + * <br /> + * The purpose of this interface is to group (and provide type safety + * for) all certification path validator results. All results returned + * by the {@link CertPathValidator#validate CertPathValidator.validate} + * method must implement this interface. + * + * @see CertPathValidator + **/ +public interface CertPathValidatorResult extends Cloneable +{ + /** + * Makes a copy of this <code>CertPathValidatorResult</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CertPathValidatorResult</code> + */ + public Object clone(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertPathValidatorSpi.java b/core/src/main/jdk1.1/java/security/cert/CertPathValidatorSpi.java new file mode 100644 index 00000000..c70bc47f --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertPathValidatorSpi.java @@ -0,0 +1,59 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; + +/** + * + * The <i>Service Provider Interface</i> (<b>SPI</b>) + * for the {@link CertPathValidator CertPathValidator} class. All + * <code>CertPathValidator</code> implementations must include a class (the + * SPI class) that extends this class (<code>CertPathValidatorSpi</code>) + * and implements all of its methods. In general, instances of this class + * should only be accessed through the <code>CertPathValidator</code> class. + * For details, see the Java Cryptography Architecture.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Instances of this class need not be protected against concurrent + * access from multiple threads. Threads that need to access a single + * <code>CertPathValidatorSpi</code> instance concurrently should synchronize + * amongst themselves and provide the necessary locking before calling the + * wrapping <code>CertPathValidator</code> object.<br /> + * <br /> + * However, implementations of <code>CertPathValidatorSpi</code> may still + * encounter concurrency issues, since multiple threads each + * manipulating a different <code>CertPathValidatorSpi</code> instance need not + * synchronize. + **/ +public abstract class CertPathValidatorSpi extends Object +{ + /** + * The default constructor. + */ + public CertPathValidatorSpi() {} + + /** + * Validates the specified certification path using the specified + * algorithm parameter set.<br /> + * <br /> + * The <code>CertPath</code> specified must be of a type that is + * supported by the validation algorithm, otherwise an + * <code>InvalidAlgorithmParameterException</code> will be thrown. For + * example, a <code>CertPathValidator</code> that implements the PKIX + * algorithm validates <code>CertPath</code> objects of type X.509. + * + * @param certPath the <code>CertPath</code> to be validated + * @param params the algorithm parameters + * + * @return the result of the validation algorithm + * + * @exception CertPathValidatorException if the <code>CertPath</code> + * does not validate + * @exception InvalidAlgorithmParameterException if the specified + * parameters or the type of the specified <code>CertPath</code> are + * inappropriate for this <code>CertPathValidator</code> + */ + public abstract CertPathValidatorResult engineValidate(CertPath certPath, CertPathParameters params) + throws CertPathValidatorException, + InvalidAlgorithmParameterException; +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertSelector.java b/core/src/main/jdk1.1/java/security/cert/CertSelector.java new file mode 100644 index 00000000..31bf9744 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertSelector.java @@ -0,0 +1,39 @@ +package java.security.cert; + +/** + * A selector that defines a set of criteria for selecting + * <code>Certificate</code>s. Classes that implement this interface + * are often used to specify which <code>Certificate</code>s should + * be retrieved from a <code>CertStore</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this interface are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see Certificate + * @see CertStore + * @see CertStore#getCertificates + */ +public interface CertSelector extends Cloneable +{ + /** + * Decides whether a <code>Certificate</code> should be selected. + * + * @param cert the <code>Certificate</code> to be checked + * @return <code>true</code> if the <code>Certificate</code> + * should be selected, <code>false</code> otherwise + */ + public boolean match(Certificate cert); + + /** + * Makes a copy of this <code>CertSelector</code>. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>CertSelector</code> + */ + public Object clone(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertStore.java b/core/src/main/jdk1.1/java/security/cert/CertStore.java new file mode 100644 index 00000000..0e2c6d2f --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertStore.java @@ -0,0 +1,352 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; +import java.util.Collection; + +/** + * A class for retrieving <code>Certificate</code>s and <code>CRL</code>s + * from a repository.<br /> + * <br /> + * This class uses a provider-based architecture, as described in the + * Java Cryptography Architecture. + * To create a <code>CertStore</code>, call one of the static + * <code>getInstance</code> methods, passing in the type of + * <code>CertStore</code> desired, any applicable initialization parameters + * and optionally the name of the provider desired. <br /> + * <br /> + * Once the <code>CertStore</code> has been created, it can be used to + * retrieve <code>Certificate</code>s and <code>CRL</code>s by calling its + * {@link #getCertificates(CertSelector selector) getCertificates} and + * {@link #getCRLs(CRLSelector selector) getCRLs} methods.<br /> + * <br /> + * Unlike a {@link java.security.KeyStore KeyStore}, which provides access + * to a cache of private keys and trusted certificates, a + * <code>CertStore</code> is designed to provide access to a potentially + * vast repository of untrusted certificates and CRLs. For example, an LDAP + * implementation of <code>CertStore</code> provides access to certificates + * and CRLs stored in one or more directories using the LDAP protocol and the + * schema as defined in the RFC service attribute. See Appendix A in the + * Java Certification Path API Programmer's Guide for more information about + * standard <code>CertStore</code> types.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * All public methods of <code>CertStore</code> objects must be thread-safe. + * That is, multiple threads may concurrently invoke these methods on a + * single <code>CertStore</code> object (or more than one) with no + * ill effects. This allows a <code>CertPathBuilder</code> to search for a + * CRL while simultaneously searching for further certificates, for instance.<br /> + * <br /> + * The static methods of this class are also guaranteed to be thread-safe. + * Multiple threads may concurrently invoke the static methods defined in + * this class with no ill effects.<br /> + * <br /> + * Uses {@link CertUtil CertUtil} to actualiy load the SPI classes. + * + * @see CertUtil + **/ +public class CertStore extends Object +{ + private CertStoreSpi storeSpi; + private Provider provider; + private String type; + private CertStoreParameters params; + + /** + * Creates a <code>CertStore</code> object of the given type, and + * encapsulates the given provider implementation (SPI object) in it. + * + * @param storeSpi the provider implementation + * @param provider the provider + * @param type the type + * @param params the initialization parameters (may be <code>null</code>) + */ + protected CertStore( CertStoreSpi storeSpi, + Provider provider, + String type, + CertStoreParameters params ) + { + this.storeSpi = storeSpi; + this.provider = provider; + this.type = type; + this.params = params; + } + + /** + * Returns a <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector. If no <code>Certificate</code>s + * match the selector, an empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>Certificate</code>s that match the selector. For instance, + * an LDAP <code>CertStore</code> may not search all entries in the + * directory. Instead, it may just search entries that are likely to + * contain the <code>Certificate</code>s it is looking for.<br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CertSelector</code> is provided that + * includes specific criteria that can be used to find the certificates. + * Issuer and/or subject names are especially useful criteria. + * + * @param selector A <code>CertSelector</code> used to select which + * <code>Certificate</code>s should be returned. Specify <code>null</code> + * to return all <code>Certificate</code>s (if supported). + * + * @return A <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector (never <code>null</code>) + * @exception CertStoreException if an exception occurs + */ + public final Collection getCertificates( CertSelector selector ) + throws CertStoreException + { + return storeSpi.engineGetCertificates( selector ); + } + + /** + * Returns a <code>Collection</code> of <code>CRL</code>s that + * match the specified selector. If no <code>CRL</code>s + * match the selector, an empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>CRL</code>s that match the selector. For instance, + * an LDAP <code>CertStore</code> may not search all entries in the + * directory. Instead, it may just search entries that are likely to + * contain the <code>CRL</code>s it is looking for.<br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CRLSelector</code> is provided that + * includes specific criteria that can be used to find the CRLs. + * Issuer names and/or the certificate to be checked are especially useful. + * + * @param selector A <code>CRLSelector</code> used to select which + * <code>CRL</code>s should be returned. Specify <code>null</code> + * to return all <code>CRL</code>s (if supported). + * + * @return A <code>Collection</code> of <code>CRL</code>s that + * match the specified selector (never <code>null</code>) + * + * @exception CertStoreException if an exception occurs + */ + public final Collection getCRLs( CRLSelector selector ) + throws CertStoreException + { + return storeSpi.engineGetCRLs( selector ); + } + + /** + * Returns a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type and is initialized with the specified + * parameters.<br /> + * <br /> + * If the default provider package provides an implementation + * of the specified <code>CertStore</code> type, an instance of + * <code>CertStore</code> containing that implementation is returned. + * If the requested type is not available in the default package, other + * packages are searched.<br /> + * <br /> + * The <code>CertStore</code> that is returned is initialized with the + * specified <code>CertStoreParameters</code>. The type of parameters + * needed may vary between different types of <code>CertStore</code>s. + * Note that the specified <code>CertStoreParameters</code> object is + * cloned. + * + * @param type the name of the requested <code>CertStore</code> type + * @param params the initialization parameters (may be <code>null</code>) + * + * @return a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type + * + * @exception NoSuchAlgorithmException if the requested type is not + * available in the default provider package or any of the other provider + * packages that were searched + * @exception InvalidAlgorithmParameterException if the specified + * initialization parameters are inappropriate for this + * <code>CertStore</code> + */ + public static CertStore getInstance( String type, + CertStoreParameters params) + throws InvalidAlgorithmParameterException, + NoSuchAlgorithmException + { + try { + CertUtil.Implementation imp = + CertUtil.getImplementation( "CertStore", type, (String)null, + new Class[] { CertStoreParameters.class }, + new Object[] { params } ); + if (imp != null) + { + return new CertStore((CertStoreSpi)imp.getEngine(), imp.getProvider(), type, params ); + } + } catch ( NoSuchProviderException ex ) {} + throw new NoSuchAlgorithmException("can't find type " + type); + } + + /** + * Returns a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type, as supplied by the specified provider + * and initialized with the specified parameters.<br /> + * <br /> + * The <code>CertStore</code> that is returned is initialized with the + * specified <code>CertStoreParameters</code>. The type of parameters + * needed may vary between different types of <code>CertStore</code>s. + * Note that the specified <code>CertStoreParameters</code> object is + * cloned. + * + * @param type the requested <code>CertStore</code> type + * @param params the initialization parameters (may be <code>null</code>) + * @param provider the name of the provider + * + * @return a <code>CertStore</code> object that implements the + * specified type, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException if the requested type is not + * available from the specified provider + * @exception InvalidAlgorithmParameterException if the specified + * initialization parameters are inappropriate for this + * <code>CertStore</code> + * @exception NoSuchProviderException if the provider has not been configured + * @exception IllegalArgumentException if the <code>provider</code> is + * null + */ + public static CertStore getInstance( String type, + CertStoreParameters params, + String provider) + throws InvalidAlgorithmParameterException, + NoSuchAlgorithmException, + NoSuchProviderException, + IllegalArgumentException + { + if ( provider == null ) + throw new IllegalArgumentException( "provider must be non-null" ); + + CertUtil.Implementation imp = + CertUtil.getImplementation( "CertStore", type, provider, + new Class[] { CertStoreParameters.class }, + new Object[] { params } ); + if (imp != null) + { + return new CertStore((CertStoreSpi)imp.getEngine(), imp.getProvider(), type, params ); + } + throw new NoSuchAlgorithmException("can't find type " + type); + } + + /** + * Returns a <code>CertStore</code> object that implements the specified + * <code>CertStore</code> type, as supplied by the specified provider and + * initialized with the specified parameters. + * Note: the <code>provider</code> doesn't have to be registered.<br /> + * <br /> + * The <code>CertStore</code> that is returned is initialized with the + * specified <code>CertStoreParameters</code>. The type of parameters + * needed may vary between different types of <code>CertStore</code>s. + * Note that the specified <code>CertStoreParameters</code> object is + * cloned. + * + * @param type the requested <code>CertStore</code> type + * @param params the initialization parameters (may be <code>null</code>) + * @param provider the provider + * + * @return a <code>CertStore</code> object that implements the + * specified type, as supplied by the specified provider + * + * @exception NoSuchAlgorithmException if the requested type is not + * available from the specified provider + * @exception InvalidAlgorithmParameterException if the specified + * initialization parameters are inappropriate for this + * <code>CertStore</code> + * @exception IllegalArgumentException if the <code>provider</code> is + * null + */ + public static CertStore getInstance( String type, + CertStoreParameters params, + Provider provider ) + throws NoSuchAlgorithmException, + InvalidAlgorithmParameterException, + IllegalArgumentException + { + if ( provider == null ) + throw new IllegalArgumentException( "provider must be non-null" ); + CertUtil.Implementation imp = + CertUtil.getImplementation( "CertStore", type, provider, + new Class[] { CertStoreParameters.class }, + new Object[] { params } ); + if (imp != null) + { + return new CertStore((CertStoreSpi)imp.getEngine(), provider, type, params ); + } + throw new NoSuchAlgorithmException("can't find type " + type); + } + + /** + * Returns the parameters used to initialize this <code>CertStore</code>. + * Note that the <code>CertStoreParameters</code> object is cloned before + * it is returned. + * + * @return the parameters used to initialize this <code>CertStore</code> + * (may be <code>null</code>) + */ + public final CertStoreParameters getCertStoreParameters() + { + return params; + } + + /** + * Returns the type of this <code>CertStore</code>. + * + * @return the type of this <code>CertStore</code> + */ + public final String getType() + { + return type; + } + + /** + * Returns the provider of this <code>CertStore</code>. + * + * @return the provider of this <code>CertStore</code> + */ + public final Provider getProvider() + { + return provider; + } + + /** + * Returns the default <code>CertStore</code> type as specified in the + * Java security properties file, or the string "LDAP" if no + * such property exists. The Java security properties file is located in + * the file named <JAVA_HOME>/lib/security/java.security, where + * <JAVA_HOME> refers to the directory where the SDK was installed.<br /> + * <br /> + * The default <code>CertStore</code> type can be used by applications + * that do not want to use a hard-coded type when calling one of the + * <code>getInstance</code> methods, and want to provide a default + * <code>CertStore</code> type in case a user does not specify its own.<br /> + * <br /> + * The default <code>CertStore</code> type can be changed by setting + * the value of the "certstore.type" security property (in the Java + * security properties file) to the desired type. + * + * @return the default <code>CertStore</code> type as specified in the + * Java security properties file, or the string "LDAP" + * if no such property exists. + */ + public static final String getDefaultType() + { + String defaulttype = null; + defaulttype = Security.getProperty("certstore.type"); + + if ( defaulttype == null || defaulttype.length() <= 0 ) + return "LDAP"; + else + return defaulttype; + } +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertStoreException.java b/core/src/main/jdk1.1/java/security/cert/CertStoreException.java new file mode 100644 index 00000000..a15bc3df --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertStoreException.java @@ -0,0 +1,172 @@ +package java.security.cert; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.security.GeneralSecurityException; + +/** + * An exception indicating one of a variety of problems retrieving + * certificates and CRLs from a <code>CertStore</code>.<br /> + * <br /> + * A <code>CertStoreException</code> provides support for wrapping + * exceptions. The {@link #getCause getCause} method returns the throwable, + * if any, that caused this exception to be thrown.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertStore + **/ +public class CertStoreException extends GeneralSecurityException +{ + private Throwable cause; + + /** + * Creates a <code>CertStoreException</code> with <code>null</code> as + * its detail message. + */ + public CertStoreException() + { + super(); + } + + /** + * Creates a <code>CertStoreException</code> with the given detail + * message. A detail message is a <code>String</code> that describes this + * particular exception. + * + * @param messag the detail message + */ + public CertStoreException(String message) + { + super(message); + } + + /** + * Creates a <code>CertStoreException</code> with the specified detail + * message and cause. + * + * @param messag the detail message + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> value is + * permitted, and indicates that the cause is nonexistent or unknown.) + */ + public CertStoreException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + /** + * Creates a <code>CertStoreException</code> that wraps the specified + * throwable. This allows any exception to be converted into a + * <code>CertStoreException</code>, while retaining information about the + * cause, which may be useful for debugging. The detail message is + * set to (<code>cause==null ? null : cause.toString()</code>) (which + * typically contains the class and detail message of cause). + * + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause getCause()} method). (A <code>null</code> value is + * permitted, and indicates that the cause is nonexistent or unknown.) + */ + public CertStoreException(Throwable cause) + { + this.cause = cause; + } + + /** + * Returns the detail message for this <code>CertStoreException</code>. + * + * @return the detail message, or <code>null</code> if neither the message + * nor cause were specified + */ + public String getMessage() + { + String message = super.getMessage(); + + if ( message == null && cause == null ) + return null; + + StringBuffer s = new StringBuffer(); + if ( message != null ) + { + s.append(message).append('\n'); + } + if ( cause != null ) + { + s.append("Cause:\n").append(cause.getMessage()); + } + return s.toString(); + } + + /** + * Returns the cause of this <code>CertStoreException</code> or + * <code>null</code> if the cause is nonexistent or unknown. + * + * @return the cause of this throwable or <code>null</code> if the cause + * is nonexistent or unknown. + */ + public Throwable getCause() + { + return cause; + } + + /** + * Returns a string describing this exception, including a description + * of the internal (wrapped) cause if there is one. + * + * @return a string representation of this + * <code>CertStoreException</code> + */ + public String toString() + { + String message = getMessage(); + if ( message == null ) + return ""; + + return message; + } + + /** + * Prints a stack trace to <code>System.err</code>, including the backtrace + * of the cause, if any. + */ + public void printStackTrace() { + printStackTrace(System.err); + } + + /** + * Prints a stack trace to a <code>PrintStream</code>, including the + * backtrace of the cause, if any. + * + * @param ps the <code>PrintStream</code> to use for output + */ + public void printStackTrace(PrintStream ps) { + super.printStackTrace(ps); + if ( cause != null ) { + cause.printStackTrace(ps); + } + } + + /** + * Prints a stack trace to a <code>PrintWriter</code>, including the + * backtrace of the cause, if any. + * + * @param pw the <code>PrintWriter</code> to use for output + */ + public void printStackTrace(PrintWriter pw) { + if ( cause != null ) { + cause.printStackTrace(pw); + } + super.printStackTrace(pw); + if ( cause != null ) { + cause.printStackTrace(pw); + } + } +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertStoreParameters.java b/core/src/main/jdk1.1/java/security/cert/CertStoreParameters.java new file mode 100644 index 00000000..58a70b37 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertStoreParameters.java @@ -0,0 +1,52 @@ +package java.security.cert; + +/** + * A specification of <code>CertStore</code> parameters.<br /> + * <br /> + * The purpose of this interface is to group (and provide type safety for) + * all <code>CertStore</code> parameter specifications. All + * <code>CertStore</code> parameter specifications must implement this + * interface. <br /> + * <br /> + * Typically, a <code>CertStoreParameters</code> object is passed as a parameter + * to one of the {@link CertStore#getInstance CertStore.getInstance} methods. + * The <code>getInstance</code> method returns a <code>CertStore</code> that + * is used for retrieving <code>Certificate</code>s and <code>CRL</code>s. The + * <code>CertStore</code> that is returned is initialized with the specified + * parameters. The type of parameters needed may vary between different types + * of <code>CertStore</code>s. + * + * @see CertStore#getInstance + **/ +public interface CertStoreParameters extends Cloneable +{ + /** + * Makes a copy of this <code>CertStoreParameters</code>.<br /> + * <br /> + * The precise meaning of "copy" may depend on the class of + * the <code>CertStoreParameters</code> object. A typical implementation + * performs a "deep copy" of this object, but this is not an absolute + * requirement. Some implementations may perform a "shallow copy" of some + * or all of the fields of this object.<br /> + * <br /> + * Note that the <code>CertStore.getInstance</code> methods make a copy + * of the specified <code>CertStoreParameters</code>. A deep copy + * implementation of <code>clone</code> is safer and more robust, as it + * prevents the caller from corrupting a shared <code>CertStore</code> by + * subsequently modifying the contents of its initialization parameters. + * However, a shallow copy implementation of <code>clone</code> is more + * appropriate for applications that need to hold a reference to a + * parameter contained in the <code>CertStoreParameters</code>. For example, + * a shallow copy clone allows an application to release the resources of + * a particular <code>CertStore</code> initialization parameter immediately, + * rather than waiting for the garbage collection mechanism. This should + * be done with the utmost care, since the <code>CertStore</code> may still + * be in use by other threads.<br /> + * <br /> + * Each subclass should state the precise behavior of this method so + * that users and developers know what to expect. + * + * @return a copy of this <code>CertStoreParameters</code> + */ + public Object clone(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertStoreSpi.java b/core/src/main/jdk1.1/java/security/cert/CertStoreSpi.java new file mode 100644 index 00000000..b92cf4aa --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertStoreSpi.java @@ -0,0 +1,104 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.util.Collection; + +/** + * The <i>Service Provider Interface</i> (<b>SPI</b>) + * for the {@link CertStore CertStore} class. All <code>CertStore</code> + * implementations must include a class (the SPI class) that extends + * this class (<code>CertStoreSpi</code>), provides a constructor with + * a single argument of type <code>CertStoreParameters</code>, and implements + * all of its methods. In general, instances of this class should only be + * accessed through the <code>CertStore</code> class. + * For details, see the Java Cryptography Architecture.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * The public methods of all <code>CertStoreSpi</code> objects must be + * thread-safe. That is, multiple threads may concurrently invoke these + * methods on a single <code>CertStoreSpi</code> object (or more than one) + * with no ill effects. This allows a <code>CertPathBuilder</code> to search + * for a CRL while simultaneously searching for further certificates, for + * instance.<br /> + * <br /> + * Simple <code>CertStoreSpi</code> implementations will probably ensure + * thread safety by adding a <code>synchronized</code> keyword to their + * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods. + * More sophisticated ones may allow truly concurrent access. + **/ +public abstract class CertStoreSpi + extends Object +{ + + /** + * The sole constructor. + * + * @param params the initialization parameters (may be <code>null</code>) + * @exception InvalidAlgorithmParameterException if the initialization + * parameters are inappropriate for this <code>CertStoreSpi</code> + */ + public CertStoreSpi( CertStoreParameters params ) + throws InvalidAlgorithmParameterException {} + + /** + * Returns a <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector. If no <code>Certificate</code>s + * match the selector, an empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>Certificate</code>s that match the selector. For instance, + * an LDAP <code>CertStore</code> may not search all entries in the + * directory. Instead, it may just search entries that are likely to + * contain the <code>Certificate</code>s it is looking for.<br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CertSelector</code> is provided that includes + * specific criteria that can be used to find the certificates. Issuer + * and/or subject names are especially useful criteria. + * + * @param selector A <code>CertSelector</code> used to select which + * <code>Certificate</code>s should be returned. Specify <code>null</code> + * to return all <code>Certificate</code>s (if supported). + * + * @return A <code>Collection</code> of <code>Certificate</code>s that + * match the specified selector (never <code>null</code>) + * + * @exception CertStoreException if an exception occurs + */ + public abstract Collection engineGetCertificates( CertSelector selector ) + throws CertStoreException; + + /** + * Returns a <code>Collection</code> of <code>CRL</code>s that + * match the specified selector. If no <code>CRL</code>s + * match the selector, an empty <code>Collection</code> will be returned.<br /> + * <br /> + * For some <code>CertStore</code> types, the resulting + * <code>Collection</code> may not contain <b>all</b> of the + * <code>CRL</code>s that match the selector. For instance, + * an LDAP <code>CertStore</code> may not search all entries in the + * directory. Instead, it may just search entries that are likely to + * contain the <code>CRL</code>s it is looking for. <br /> + * <br /> + * Some <code>CertStore</code> implementations (especially LDAP + * <code>CertStore</code>s) may throw a <code>CertStoreException</code> + * unless a non-null <code>CRLSelector</code> is provided that includes + * specific criteria that can be used to find the CRLs. Issuer names + * and/or the certificate to be checked are especially useful. + * + * @param selector A <code>CRLSelector</code> used to select which + * <code>CRL</code>s should be returned. Specify <code>null</code> + * to return all <code>CRL</code>s (if supported). + * + * @return A <code>Collection</code> of <code>CRL</code>s that + * match the specified selector (never <code>null</code>) + * + * @exception CertStoreException if an exception occurs + */ + public abstract Collection engineGetCRLs( CRLSelector selector ) + throws CertStoreException; +} + diff --git a/core/src/main/jdk1.1/java/security/cert/CertUtil.java b/core/src/main/jdk1.1/java/security/cert/CertUtil.java new file mode 100644 index 00000000..c390efa9 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertUtil.java @@ -0,0 +1,556 @@ +package java.security.cert; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; + +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DEROutputStream; +import org.bouncycastle.asn1.OIDTokenizer; +import org.bouncycastle.asn1.x509.X509Name; +import org.bouncycastle.util.Strings; + +class CertUtil +{ + static class Implementation + { + Object engine; + Provider provider; + + Implementation( + Object engine, + Provider provider) + { + this.engine = engine; + this.provider = provider; + } + + Object getEngine() + { + return engine; + } + + Provider getProvider() + { + return provider; + } + } + + /** + * see if we can find an algorithm (or its alias and what it represents) in + * the property table for the given provider. + * + * @return null if no algorithm found, an Implementation if it is. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + Provider prov) + { + if (prov == null) + { + Provider[] provider = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != provider.length; i++) + { + Implementation imp = getImplementation(baseName, algorithm, provider[i]); + if (imp != null) + { + return imp; + } + } + + return null; + } + + String alias; + + while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null) + { + algorithm = alias; + } + + String className = prov.getProperty(baseName + "." + algorithm); + + if (className != null) + { + try + { + return new Implementation(Class.forName(className).newInstance(), prov); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but no class found!"); + } + catch (Exception e) + { + throw new IllegalStateException( + "algorithm " + algorithm + " in provider " + prov.getName() + " but class inaccessible: " + e.toString()); + } + } + + return null; + } + + /** + * return an implementation for a given algorithm/provider. + * If the provider is null, we grab the first avalaible who has the required algorithm. + * + * @return null if no algorithm found, an Implementation if it is. + * @exception NoSuchProviderException if a provider is specified and not found. + */ + static Implementation getImplementation( + String baseName, + String algorithm, + String provider) + throws NoSuchProviderException + { + if (provider == null) + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + Implementation imp = getImplementation(baseName, algorithm, prov[i]); + if (imp != null) + { + return imp; + } + } + } + else + { + Provider prov = Security.getProvider(provider); + + if (prov == null) + { + throw new NoSuchProviderException("Provider " + provider + " not found"); + } + + return getImplementation(baseName, algorithm, prov); + } + + return null; + } + + /** + * see if we can find an algorithm (or its alias and what it represents) in + * the property table for the given provider. + * + * @return null if no algorithm found, an Implementation if it is. + */ + static Implementation getImplementation(String baseName, String algorithm, + Provider prov, Class[] ctorparamtype, Object[] ctorparam) + throws InvalidAlgorithmParameterException + { + String alias; + + while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + + algorithm)) != null) + { + algorithm = alias; + } + + String className = prov.getProperty(baseName + "." + algorithm); + + if (className != null) + { + try + { + return new Implementation(Class.forName(className) + .getConstructor(ctorparamtype).newInstance(ctorparam), + prov); + } + catch (ClassNotFoundException e) + { + throw new IllegalStateException("algorithm " + algorithm + + " in provider " + prov.getName() + + " but no class found!"); + } + catch (Exception e) + { + if (e instanceof InvalidAlgorithmParameterException) + { + throw (InvalidAlgorithmParameterException)e; + } + + throw new IllegalStateException("algorithm " + algorithm + + " in provider " + prov.getName() + + " but class inaccessible!"); + } + } + + return null; + } + + /** + * return an implementation for a given algorithm/provider. If the provider + * is null, we grab the first avalaible who has the required algorithm. + * + * @return null if no algorithm found, an Implementation if it is. + * + * @exception NoSuchProviderException + * if a provider is specified and not found. + */ + static Implementation getImplementation(String baseName, String algorithm, + String provider, Class[] ctorparamtype, Object[] ctorparam) + throws NoSuchProviderException, InvalidAlgorithmParameterException + { + if (provider == null) + { + Provider[] prov = Security.getProviders(); + + // + // search every provider looking for the algorithm we want. + // + for (int i = 0; i != prov.length; i++) + { + Implementation imp = getImplementation(baseName, algorithm, + prov[i], ctorparamtype, ctorparam); + if (imp != null) + { + return imp; + } + } + } + else + { + Provider prov = Security.getProvider(provider); + + if (prov == null) + { + throw new NoSuchProviderException("Provider " + provider + + " not found"); + } + + return getImplementation(baseName, algorithm, prov, ctorparamtype, + ctorparam); + } + + return null; + } + + static byte[] parseGeneralName(int type, String data) throws IOException + { + byte[] encoded = null; + + switch (type) + { + case 0: + throw new IOException( + "unable to parse OtherName String representation"); + case 1: + encoded = parseRfc822(data.trim()); + break; + case 2: + encoded = parseDNSName(data.trim()); + break; + case 3: + throw new IOException( + "unable to parse ORAddress String representation"); + case 4: + encoded = parseX509Name(data.trim()); + break; + case 5: + throw new IOException( + "unable to parse EDIPartyName String representation"); + case 6: + encoded = parseURI(data.trim()); + break; + case 7: + encoded = parseIP(data.trim()); + break; + case 8: + encoded = parseOID(data.trim()); + break; + default: + throw new IOException( + "unable to parse unkown type String representation"); + } + return encoded; + } + + /** + * Check the format of an OID.<br /> + * Throw an IOException if the first component is not 0, 1 or 2 or the + * second component is greater than 39.<br /> + * <br /> + * User {@link org.bouncycastle.asn1.OIDTokenizer OIDTokenizer} + * + * @param the + * OID to be checked. + * + * @exception IOException + * if the first component is not 0, 1 or 2 or the second + * component is greater than 39. + */ + static byte[] parseOID(String oid) throws IOException + { + OIDTokenizer tokenizer = new OIDTokenizer(oid); + String token; + if (!tokenizer.hasMoreTokens()) + { + throw new IOException("OID contains no tokens"); + } + token = tokenizer.nextToken(); + if (token == null) + { + throw new IOException("OID contains no tokens"); + } + try + { + int test = (Integer.valueOf(token)).intValue(); + if (test < 0 || test > 2) + { + throw new IOException("first token is not >= 0 and <=2"); + } + if (!tokenizer.hasMoreTokens()) + { + throw new IOException("OID contains only one token"); + } + token = tokenizer.nextToken(); + if (token == null) + { + throw new IOException("OID contains only one token"); + } + test = (Integer.valueOf(token)).intValue(); + if (test < 0 || test > 39) + { + throw new IOException("secon token is not >= 0 and <=39"); + } + } + catch (NumberFormatException ex) + { + throw new IOException("token: " + token + ": " + ex.toString()); + } + ASN1Object derData = new ASN1ObjectIdentifier(oid); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given IPv4 or IPv6 into DER encoded byte array representation. + * + * @param the + * IP in well known String format + * + * @return the IP as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseIP(String data) throws IOException + { + byte[] encoded = parseIPv4(data); + + if (encoded == null) + { + encoded = parseIPv6(data); + } + + if (encoded == null) + { + throw new IOException( + "unable to parse IP to DER encoded byte array"); + } + + return encoded; + } + + /** + * Parse the given IPv4 into DER encoded byte array representation. + * + * @param the + * IP in well known String format + * + * @return the IP as byte array or <code>null</code> if not parseable + */ + private static byte[] parseIPv4(String data) + { + if (data.length() == 0) + { + return null; + } + + int octet; + int octets = 0; + byte[] dst = new byte[4]; + + int pos = 0; + int start = 0; + while (start < data.length() + && (pos = data.indexOf('.', start)) > start && pos - start > 3) + { + try + { + octet = (Integer.valueOf(data.substring(start, pos - start))) + .intValue(); + } + catch (NumberFormatException ex) + { + return null; + } + if (octet < 0 || octet > 255) + { + return null; + } + dst[octets++] = (byte)(octet & 0xff); + + start = pos + 1; + } + + if (octets < 4) + { + return null; + } + + return dst; + } + + /** + * Parse the given IPv6 into DER encoded byte array representation.<br /> + * <br /> + * <b>TODO: implement this</b> + * + * @param the + * IP in well known String format + * + * @return the IP as byte array or <code>null</code> if not parseable + */ + private static byte[] parseIPv6(String data) + { + return null; + } + + /** + * Parse the given URI into DER encoded byte array representation. + * + * @param the + * URI in well known String format + * + * @return the URI as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseURI(String data) throws IOException + { + // TODO do parsing test + ASN1Object derData = new DERIA5String(data); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given rfc822 addr-spec into DER encoded byte array + * representation. + * + * @param the + * rfc822 addr-spec in well known String format + * + * @return the rfc822 addr-spec as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseRfc822(String data) throws IOException + { + int tmpInt = data.indexOf('@'); + if (tmpInt < 0 || tmpInt >= data.length() - 1) + { + throw new IOException("wrong format of rfc822Name:" + data); + } + // TODO more test for illegal charateers + ASN1Object derData = new DERIA5String(data); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given DNS name into DER encoded byte array representation. The + * String must be in den preffered name syntax as defined in RFC 1034. + * + * @param the + * DNS name in well known String format + * + * @return the DNS name as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseDNSName(String data) throws IOException + { + // TODO more test for illegal charateers + ASN1Object derData = new DERIA5String(data); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Parse the given X.509 name into DER encoded byte array representation. + * + * @param the + * X.509 name in well known String format + * + * @return the X.509 name as byte array + * + * @exception IOException + * if the String could not be parsed + */ + private static byte[] parseX509Name(String data) throws IOException + { + // TODO more test for illegal charateers + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(new X509Name(trimX509Name(data))); + derOutStream.close(); + return outStream.toByteArray(); + } + + /** + * Returns the given name converted to upper case and all multi spaces squezed + * to one space. + **/ + static String trimX509Name(String name) + { + String data = Strings.toUpperCase(name.trim()); + int pos; + while ((pos = data.indexOf(" ")) >= 0) + { + data = data.substring(0, pos) + data.substring(pos + 1); + } + while ((pos = data.indexOf(" =")) >= 0) + { + data = data.substring(0, pos) + data.substring(pos + 1); + } + while ((pos = data.indexOf("= ")) >= 0) + { + data = data.substring(0, pos + 1) + data.substring(pos + 2); + } + return data; + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/Certificate.java b/core/src/main/jdk1.1/java/security/cert/Certificate.java new file mode 100644 index 00000000..201e209a --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/Certificate.java @@ -0,0 +1,80 @@ + +package java.security.cert; + +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.SignatureException; + +public abstract class Certificate extends Object +{ + private String type; + + protected Certificate(String type) + { + this.type = type; + } + + public boolean equals(Object other) + { + if ( !(other instanceof Certificate) ) + return false; + + if ( other == this ) + return true; + + try + { + byte[] enc1 = getEncoded(); + byte[] enc2 = ((Certificate)other).getEncoded(); + + return MessageDigest.isEqual(enc1, enc2); + } + catch (CertificateEncodingException e) + { + return false; + } + } + + public final String getType() + { + return type; + } + + // XXX + public int hashCode() + { + try + { + byte[] enc1 = getEncoded(); + int hc = 0; + for (int i = 0; i < enc1.length; i++) + { + hc += enc1[i]; + } + + return hc; + } + catch (CertificateEncodingException e) + { + return 0; + } + } + + public abstract byte[] getEncoded() + throws CertificateEncodingException; + + public abstract PublicKey getPublicKey(); + + public abstract String toString(); + + public abstract void verify(PublicKey key) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException; + + public abstract void verify(PublicKey key, String sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException; +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertificateEncodingException.java b/core/src/main/jdk1.1/java/security/cert/CertificateEncodingException.java new file mode 100644 index 00000000..47545a5c --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertificateEncodingException.java @@ -0,0 +1,14 @@ + +package java.security.cert; + +public class CertificateEncodingException extends CertificateException +{ + public CertificateEncodingException() + { + } + + public CertificateEncodingException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertificateException.java b/core/src/main/jdk1.1/java/security/cert/CertificateException.java new file mode 100644 index 00000000..644c6249 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertificateException.java @@ -0,0 +1,16 @@ + +package java.security.cert; + +import java.security.GeneralSecurityException; + +public class CertificateException extends GeneralSecurityException +{ + public CertificateException() + { + } + + public CertificateException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertificateExpiredException.java b/core/src/main/jdk1.1/java/security/cert/CertificateExpiredException.java new file mode 100644 index 00000000..1a9062aa --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertificateExpiredException.java @@ -0,0 +1,14 @@ + +package java.security.cert; + +public class CertificateExpiredException extends CertificateException +{ + public CertificateExpiredException() + { + } + + public CertificateExpiredException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertificateFactory.java b/core/src/main/jdk1.1/java/security/cert/CertificateFactory.java new file mode 100644 index 00000000..e86cd3a0 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertificateFactory.java @@ -0,0 +1,183 @@ + +package java.security.cert; + +import java.io.InputStream; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +/** + * Uses {@link CertUtil CertUtil} to actualiy load the SPI classes. + * + * @see CertUtil + **/ +public class CertificateFactory +{ + private CertificateFactorySpi certFacSpi; + private Provider provider; + private String type; + + protected CertificateFactory( + CertificateFactorySpi certFacSpi, + Provider provider, + String type) + { + this.certFacSpi = certFacSpi; + this.provider = provider; + this.type = type; + } + + public final CRL generateCRL(InputStream inStream) + throws CRLException + { + return certFacSpi.engineGenerateCRL(inStream); + } + + public final Collection generateCRLs(InputStream inStream) + throws CRLException + { + return certFacSpi.engineGenerateCRLs(inStream); + } + + public final Certificate generateCertificate(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertificate(inStream); + } + + public final /*Sk13 Vector*/ Collection generateCertificates(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertificates(inStream); + } + + /** + * Returns an iteration of the <code>CertPath</code> encodings supported + * by this certificate factory, with the default encoding first. See + * Appendix A in the + * Java Certification Path API Programmer's Guide for information about + * standard encoding names and their formats.<br /> + * <br /> + * Attempts to modify the returned <code>Iterator</code> via its + * <code>remove</code> method result in an + * <code>UnsupportedOperationException</code>. + * + * @return an <code>Iterator</code> over the names of the supported + * <code>CertPath</code> encodings (as <code>String</code>s) + */ + public final Iterator getCertPathEncodings() + { + return certFacSpi.engineGetCertPathEncodings(); + } + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the default encoding. The name of the default + * encoding is the first element of the <code>Iterator</code> returned by + * the {@link #getCertPathEncodings getCertPathEncodings} method. + * + * @param inStream an <code>InputStream</code> containing the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding + */ + public final CertPath generateCertPath(InputStream inStream) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(inStream); + } + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the specified encoding. See Appendix A in the + * <a href="../../../../guide/security/certpath/CertPathProgGuide.html#AppA"> + * Java Certification Path API Programmer's Guide</a> + * for information about standard encoding names and their formats. + * + * @param inStream an <code>InputStream</code> containing the data + * @param encoding the encoding used for the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding or + * the encoding requested is not supported + */ + public final CertPath generateCertPath(InputStream inStream, String encoding) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath(inStream, encoding); + } + + /** + * Generates a <code>CertPath</code> object and initializes it with + * a <code>List</code> of <code>Certificate</code>s.<br /> + * <br /> + * The certificates supplied must be of a type supported by the + * <code>CertificateFactory</code>. They will be copied out of the supplied + * <code>List</code> object. + * + * @param certificates a <code>List</code> of <code>Certificate</code>s + * + * @return a <code>CertPath</code> initialized with the supplied list of + * certificates + * + * @exception CertificateException if an exception occurs + */ + public final CertPath generateCertPath(List certificates) + throws CertificateException + { + return certFacSpi.engineGenerateCertPath( certificates ); + } + + public static final CertificateFactory getInstance(String type) + throws CertificateException + { + try + { + CertUtil.Implementation imp = CertUtil.getImplementation("CertificateFactory", type, (String)null); + + if (imp != null) + { + return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type); + } + + throw new CertificateException("can't find type " + type); + } + catch (NoSuchProviderException e) + { + throw new CertificateException(type + " not found"); + } + } + + public static final CertificateFactory getInstance( + String type, + String provider) + throws CertificateException, NoSuchProviderException + { + CertUtil.Implementation imp = CertUtil.getImplementation("CertificateFactory", type, provider); + + if (imp != null) + { + return new CertificateFactory((CertificateFactorySpi)imp.getEngine(), imp.getProvider(), type); + } + + throw new CertificateException("can't find type " + type); + } + + public final Provider getProvider() + { + return provider; + } + + public final String getType() + { + return type; + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertificateFactorySpi.java b/core/src/main/jdk1.1/java/security/cert/CertificateFactorySpi.java new file mode 100644 index 00000000..8cc06fc2 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertificateFactorySpi.java @@ -0,0 +1,111 @@ + +package java.security.cert; + +import java.io.InputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public abstract class CertificateFactorySpi +{ + public CertificateFactorySpi() + { + } + + public abstract CRL engineGenerateCRL(InputStream inStream) + throws CRLException; + + public abstract Collection engineGenerateCRLs(InputStream inStream) + throws CRLException; + + public abstract Certificate engineGenerateCertificate(InputStream inStream) + throws CertificateException; + + public abstract /*SK13 Vector*/ Collection engineGenerateCertificates(InputStream inStream) + throws CertificateException; + + /** + * Returns an iteration of the <code>CertPath</code> encodings supported + * by this certificate factory, with the default encoding first. See + * Appendix A in the + * Java Certification Path API Programmer's Guide + * for information about standard encoding names.<br /> + * <br /> + * Attempts to modify the returned <code>Iterator</code> via its + * <code>remove</code> method result in an + * <code>UnsupportedOperationException</code>.<br /> + * <br /> + * This method was added to version 1.4 of the Java 2 Platform + * Standard Edition. In order to maintain backwards compatibility with + * existing service providers, this method cannot be <code>abstract</code> + * and by default throws an <code>UnsupportedOperationException</code>. + * + * @return an <code>Iterator</code> over the names of the supported + * <code>CertPath</code> encodings (as <code>String</code>s) + * + * @exception UnsupportedOperationException if the method is not supported + */ + public abstract Iterator engineGetCertPathEncodings(); + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the default encoding. + * + * @param inStream an <code>InputStream</code> containing the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding + */ + public abstract CertPath engineGenerateCertPath(InputStream inStream) + throws CertificateException; + + /** + * Generates a <code>CertPath</code> object and initializes it with + * the data read from the <code>InputStream</code> inStream. The data + * is assumed to be in the specified encoding.<br /> + * <br /> + * This method was added to version 1.4 of the Java 2 Platform + * Standard Edition. In order to maintain backwards compatibility with + * existing service providers, this method cannot be <code>abstract</code> + * and by default throws an <code>UnsupportedOperationException</code>. + * + * @param inStream an <code>InputStream</code> containing the data + * @param encoding the encoding used for the data + * + * @return a <code>CertPath</code> initialized with the data from the + * <code>InputStream</code> + * + * @exception CertificateException if an exception occurs while decoding or + * the encoding requested is not supported + * @exception UnsupportedOperationException if the method is not supported + */ + public abstract CertPath engineGenerateCertPath(InputStream inStream, String encoding) + throws CertificateException; + + /** + * Generates a <code>CertPath</code> object and initializes it with + * a <code>List</code> of <code>Certificate</code>s.<br /> + * <br /> + * The certificates supplied must be of a type supported by the + * <code>CertificateFactory</code>. They will be copied out of the supplied + * <code>List</code> object.<br /> + * <br /> + * This method was added to version 1.4 of the Java 2 Platform + * Standard Edition. In order to maintain backwards compatibility with + * existing service providers, this method cannot be <code>abstract</code> + * and by default throws an <code>UnsupportedOperationException</code>. + * + * @param certificates a <code>List</code> of <code>Certificate</code>s + * + * @return a <code>CertPath</code> initialized with the supplied list of + * certificates + * + * @exception CertificateException if an exception occurs + * @exception UnsupportedOperationException if the method is not supported + */ + public abstract CertPath engineGenerateCertPath(List certificates) + throws CertificateException; +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertificateNotYetValidException.java b/core/src/main/jdk1.1/java/security/cert/CertificateNotYetValidException.java new file mode 100644 index 00000000..ec8d46a3 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertificateNotYetValidException.java @@ -0,0 +1,14 @@ + +package java.security.cert; + +public class CertificateNotYetValidException extends CertificateException +{ + public CertificateNotYetValidException() + { + } + + public CertificateNotYetValidException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CertificateParsingException.java b/core/src/main/jdk1.1/java/security/cert/CertificateParsingException.java new file mode 100644 index 00000000..a9f18aae --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CertificateParsingException.java @@ -0,0 +1,14 @@ + +package java.security.cert; + +public class CertificateParsingException extends CertificateException +{ + public CertificateParsingException() + { + } + + public CertificateParsingException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/CollectionCertStoreParameters.java b/core/src/main/jdk1.1/java/security/cert/CollectionCertStoreParameters.java new file mode 100644 index 00000000..7c31e7b5 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/CollectionCertStoreParameters.java @@ -0,0 +1,117 @@ +package java.security.cert; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Parameters used as input for the Collection <code>CertStore</code> + * algorithm.<br /> + * <br /> + * This class is used to provide necessary configuration parameters + * to implementations of the Collection <code>CertStore</code> + * algorithm. The only parameter included in this class is the + * <code>Collection</code> from which the <code>CertStore</code> will + * retrieve certificates and CRLs.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see java.util.Collection + * @see CertStore + **/ +public class CollectionCertStoreParameters implements CertStoreParameters +{ + private Collection collection; + + /** + * Creates an instance of <code>CollectionCertStoreParameters</code> + * which will allow certificates and CRLs to be retrieved from the + * specified <code>Collection</code>. If the specified + * <code>Collection</code> contains an object that is not a + * <code>Certificate</code> or <code>CRL</code>, that object will be + * ignored by the Collection <code>CertStore</code>.<br /> + * <br /> + * The <code>Collection</code> is <b>not</b> copied. Instead, a + * reference is used. This allows the caller to subsequently add or + * remove <code>Certificates</code> or <code>CRL</code>s from the + * <code>Collection</code>, thus changing the set of + * <code>Certificates</code> or <code>CRL</code>s available to the + * Collection <code>CertStore</code>. The Collection <code>CertStore</code> + * will not modify the contents of the <code>Collection</code>.<br /> + * <br /> + * If the <code>Collection</code> will be modified by one thread while + * another thread is calling a method of a Collection <code>CertStore</code> + * that has been initialized with this <code>Collection</code>, the + * <code>Collection</code> must have fail-fast iterators. + * + * @param collection a <code>Collection</code> of + * <code>Certificate</code>s and <code>CRL</code>s + * + * @exception NullPointerException if <code>collection</code> is + * <code>null</code> + */ + public CollectionCertStoreParameters(Collection collection) + { + if ( collection == null ) + throw new NullPointerException("collection must be non-null"); + this.collection = collection; + } + + /** + * Creates an instance of <code>CollectionCertStoreParameters</code> with + * the an empty Collection. + */ + public CollectionCertStoreParameters() + { + collection = new ArrayList(); + } + + /** + * Returns the <code>Collection</code> from which <code>Certificate</code>s + * and <code>CRL</code>s are retrieved. This is <b>not</b> a copy of the + * <code>Collection</code>, it is a reference. This allows the caller to + * subsequently add or remove <code>Certificates</code> or + * <code>CRL</code>s from the <code>Collection</code>. + * + * @return the <code>Collection</code> (never null) + */ + public Collection getCollection() + { + return collection; + } + + /** + * Returns a copy of this object. Note that only a reference to the + * <code>Collection</code> is copied, and not the contents. + * + * @return the copy + */ + public Object clone() + { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("CollectionCertStoreParameters: [\n collections:\n"); + s.append( getCollection()); + s.append("\n]" ); + return s.toString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/LDAPCertStoreParameters.java b/core/src/main/jdk1.1/java/security/cert/LDAPCertStoreParameters.java new file mode 100644 index 00000000..2e466997 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/LDAPCertStoreParameters.java @@ -0,0 +1,130 @@ +package java.security.cert; + +/** + * Parameters used as input for the LDAP <code>CertStore</code> algorithm.<br /> + * <br /> + * This class is used to provide necessary configuration parameters (server + * name and port number) to implementations of the LDAP <code>CertStore</code> + * algorithm.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertStore + **/ +public class LDAPCertStoreParameters implements CertStoreParameters +{ + private static final int LDAP_DEFAULT_PORT = 389; + + /** + * the port number of the LDAP server + */ + private String serverName; + + /** + * the DNS name of the LDAP server + */ + private int port; + + /** + * Creates an instance of <code>LDAPCertStoreParameters</code> with the + * default parameter values (server name "localhost", port 389). + */ + public LDAPCertStoreParameters() + { + this("localhost", LDAP_DEFAULT_PORT); + } + + /** + * Creates an instance of <code>LDAPCertStoreParameters</code> with the + * specified server name and a default port of 389. + * + * @param serverName the DNS name of the LDAP server + * + * @exception NullPointerException if <code>serverName</code> is + * <code>null</code> + */ + public LDAPCertStoreParameters(String serverName) + { + this(serverName, LDAP_DEFAULT_PORT); + } + + /** + * Creates an instance of <code>LDAPCertStoreParameters</code> with the + * specified parameter values. + * + * @param serverName the DNS name of the LDAP server + * @param port the port number of the LDAP server + * + * @exception NullPointerException if <code>serverName</code> is + * <code>null</code> + */ + public LDAPCertStoreParameters(String serverName, int port) + { + if (serverName == null) + throw new NullPointerException("serverName must be non-null"); + this.serverName = serverName; + this.port = port; + } + + /** + * Returns the DNS name of the LDAP server. + * + * @return the name (not <code>null</code>) + */ + public String getServerName() + { + return serverName; + } + + /** + * Returns the port number of the LDAP server. + * + * @return the port number + */ + public int getPort() + { + return port; + } + + /** + * Returns a copy of this object. Changes to the copy will not affect + * the original and vice versa.<br /> + * <br /> + * Note: this method currently performs a shallow copy of the object + * (simply calls <code>Object.clone()</code>). This may be changed in a + * future revision to perform a deep copy if new parameters are added + * that should not be shared. + * + * @return the copy + */ + public Object clone() + { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("LDAPCertStoreParameters: [\n"); + sb.append(" serverName: ").append(serverName).append('\n'); + sb.append(" port: ").append(port).append('\n'); + sb.append(']'); + return sb.toString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/PKIXBuilderParameters.java b/core/src/main/jdk1.1/java/security/cert/PKIXBuilderParameters.java new file mode 100644 index 00000000..b4f7aceb --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/PKIXBuilderParameters.java @@ -0,0 +1,179 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.util.Set; + +/** + * Parameters used as input for the PKIX <code>CertPathBuilder</code> + * algorithm.<br /> + * <br /> + * A PKIX <code>CertPathBuilder</code> uses these parameters to {@link + * CertPathBuilder#build build} a <code>CertPath</code> which has been + * validated according to the PKIX certification path validation algorithm.<br /> + * <br /> + * To instantiate a <code>PKIXBuilderParameters</code> object, an + * application must specify one or more <i>most-trusted CAs</i> as defined by + * the PKIX certification path validation algorithm. The most-trusted CA + * can be specified using one of two constructors. An application + * can call {@link #PKIXBuilderParameters(Set, CertSelector) + * PKIXBuilderParameters(Set, CertSelector)}, specifying a + * <code>Set</code> of <code>TrustAnchor</code> objects, each of which + * identifies a most-trusted CA. Alternatively, an application can call + * {@link #PKIXBuilderParameters(KeyStore, CertSelector) + * PKIXBuilderParameters(KeyStore, CertSelector)}, specifying a + * <code>KeyStore</code> instance containing trusted certificate entries, each + * of which will be considered as a most-trusted CA.<br /> + * <br /> + * In addition, an application must specify constraints on the target + * certificate that the <code>CertPathBuilder</code> will attempt + * to build a path to. The constraints are specified as a + * <code>CertSelector</code> object. These constraints should provide the + * <code>CertPathBuilder</code> with enough search criteria to find the target + * certificate. Minimal criteria for an <code>X509Certificate</code> usually + * include the subject name and/or one or more subject alternative names. + * If enough criteria is not specified, the <code>CertPathBuilder</code> + * may throw a <code>CertPathBuilderException</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathBuilder + **/ +public class PKIXBuilderParameters extends PKIXParameters +{ + private int maxPathLength = 5; + + /** + * Creates an instance of <code>PKIXBuilderParameters</code> with + * the specified <code>Set</code> of most-trusted CAs. + * Each element of the set is a {@link TrustAnchor TrustAnchor}.<br /> + * <br /> + * Note that the <code>Set</code> is copied to protect against + * subsequent modifications. + * + * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s + * @param targetConstraints a <code>CertSelector</code> specifying the + * constraints on the target certificate + * + * @exception InvalidAlgorithmParameterException if <code>trustAnchors</code> + * is empty <code>(trustAnchors.isEmpty() == true)</code> + * @exception NullPointerException if <code>trustAnchors</code> is + * <code>null</code> + * @exception ClassCastException if any of the elements of + * <code>trustAnchors</code> are not of type + * <code>java.security.cert.TrustAnchor</code> + */ + public PKIXBuilderParameters( + Set trustAnchors, + CertSelector targetConstraints) + throws InvalidAlgorithmParameterException + { + super( trustAnchors ); + setTargetCertConstraints( targetConstraints ); + } + + /** + * Creates an instance of <code>PKIXBuilderParameters</code> that + * populates the set of most-trusted CAs from the trusted + * certificate entries contained in the specified <code>KeyStore</code>. + * Only keystore entries that contain trusted <code>X509Certificate</code>s + * are considered; all other certificate types are ignored. + * + * @param keystore a <code>KeyStore</code> from which the set of + * most-trusted CAs will be populated + * @param targetConstraints a <code>CertSelector</code> specifying the + * constraints on the target certificate + * + * @exception KeyStoreException if <code>keystore</code> has not been + * initialized + * @exception InvalidAlgorithmParameterException if <code>keystore</code> does + * not contain at least one trusted certificate entry + * @exception NullPointerException if <code>keystore</code> is + * <code>null</code> + */ + public PKIXBuilderParameters(KeyStore keystore, + CertSelector targetConstraints) + throws KeyStoreException, + InvalidAlgorithmParameterException + { + super( keystore ); + setTargetCertConstraints( targetConstraints ); + } + + /** + * Sets the value of the maximum number of non-self-issued intermediate + * certificates that may exist in a certification path. A certificate + * is self-issued if the DNs that appear in the subject and issuer + * fields are identical and are not empty. Note that the last certificate + * in a certification path is not an intermediate certificate, and is not + * included in this limit. Usually the last certificate is an end entity + * certificate, but it can be a CA certificate. A PKIX + * <code>CertPathBuilder</code> instance must not build + * paths longer than the length specified.<br /> + * <br /> + * A value of 0 implies that the path can only contain + * a single certificate. A value of -1 implies that the + * path length is unconstrained (i.e. there is no maximum). + * The default maximum path length, if not specified, is 5. + * Setting a value less than -1 will cause an exception to be thrown.<br /> + * <br /> + * If any of the CA certificates contain the + * <code>BasicConstraintsExtension</code>, the value of the + * <code>pathLenConstraint</code> field of the extension overrides + * the maximum path length parameter whenever the result is a + * certification path of smaller length. + * + * @param maxPathLength the maximum number of non-self-issued intermediate + * certificates that may exist in a certification path + * + * @exception InvalidParameterException if <code>maxPathLength</code> is set + * to a value less than -1 + * + * @see #getMaxPathLength + */ + public void setMaxPathLength(int maxPathLength) + { + if ( maxPathLength < -1 ) + throw new InvalidParameterException("the maximum path length parameter can not be less than -1"); + this.maxPathLength = maxPathLength; + } + + /** + * Returns the value of the maximum number of intermediate non-self-issued + * certificates that may exist in a certification path. See + * the {@link #setMaxPathLength} method for more details. + * + * @return the maximum number of non-self-issued intermediate certificates + * that may exist in a certification path, or -1 if there is no limit + * + * @see #setMaxPathLength + */ + public int getMaxPathLength() + { + return maxPathLength; + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append( "PKIXBuilderParameters [\n" ); + s.append( super.toString() ); + s.append( " Maximum Path Length: " ); + s.append( getMaxPathLength() ); + s.append( "\n]\n" ); + return s.toString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/PKIXCertPathBuilderResult.java b/core/src/main/jdk1.1/java/security/cert/PKIXCertPathBuilderResult.java new file mode 100644 index 00000000..2ac79182 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/PKIXCertPathBuilderResult.java @@ -0,0 +1,93 @@ +package java.security.cert; + +import java.security.PublicKey; + +/** + * This class represents the successful result of the PKIX certification + * path builder algorithm. All certification paths that are built and + * returned using this algorithm are also validated according to the PKIX + * certification path validation algorithm.<br /> + * <br /> + * Instances of <code>PKIXCertPathBuilderResult</code> are returned by + * the <code>build</code> method of <code>CertPathBuilder</code> + * objects implementing the PKIX algorithm.<br /> + * <br /> + * All <code>PKIXCertPathBuilderResult</code> objects contain the + * certification path constructed by the build algorithm, the + * valid policy tree and subject public key resulting from the build + * algorithm, and a <code>TrustAnchor</code> describing the certification + * authority (CA) that served as a trust anchor for the certification path.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathBuilderResult + * + **/ +public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult + implements CertPathBuilderResult +{ + private CertPath certPath; + + /** + * Creates an instance of <code>PKIXCertPathBuilderResult</code> + * containing the specified parameters. + * + * @param certPath the validated <code>CertPath</code> + * @param trustAnchor a <code>TrustAnchor</code> describing the CA that + * served as a trust anchor for the certification path + * @param policyTree the immutable valid policy tree, or <code>null</code> + * if there are no valid policies + * @param subjectPublicKey the public key of the subject + * + * @exception NullPointerException if the <code>certPath</code>, + * <code>trustAnchor</code> or <code>subjectPublicKey</code> parameters + * are <code>null</code> + */ + public PKIXCertPathBuilderResult(CertPath certPath, TrustAnchor trustAnchor, + PolicyNode policyTree, PublicKey subjectPublicKey) + { + super(trustAnchor, policyTree, subjectPublicKey); + if ( certPath == null ) + throw new NullPointerException( "certPath must be non-null" ); + this.certPath = certPath; + } + + /** + * Returns the built and validated certification path. The + * <code>CertPath</code> object does not include the trust anchor. + * Instead, use the {@link #getTrustAnchor() getTrustAnchor()} method to + * obtain the <code>TrustAnchor</code> that served as the trust anchor + * for the certification path. + * + * @return the built and validated <code>CertPath</code> (never + * <code>null</code>) + */ + public CertPath getCertPath() + { + return certPath; + } + + /** + * Return a printable representation of this + * <code>PKIXCertPathBuilderResult</code>. + * + * @return a <code>String</code> describing the contents of this + * <code>PKIXCertPathBuilderResult</code> + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append( "PKIXCertPathBuilderResult: [\n" ); + s.append( " Certification Path: ").append(getCertPath()).append('\n' ); + s.append( " Trust Anchor: ").append(getTrustAnchor()).append('\n' ); + s.append( " Policy Tree: ").append(getPolicyTree()).append('\n' ); + s.append( " Subject Public Key: ").append(getPublicKey()).append("\n]"); + return s.toString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/PKIXCertPathChecker.java b/core/src/main/jdk1.1/java/security/cert/PKIXCertPathChecker.java new file mode 100644 index 00000000..14dec806 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/PKIXCertPathChecker.java @@ -0,0 +1,155 @@ +package java.security.cert; + +import java.util.Collection; +import java.util.Set; + +/** + * An abstract class that performs one or more checks on an + * <code>X509Certificate</code>. <br /> + * <br /> + * A concrete implementation of the <code>PKIXCertPathChecker</code> class + * can be created to extend the PKIX certification path validation algorithm. + * For example, an implementation may check for and process a critical private + * extension of each certificate in a certification path.<br /> + * <br /> + * Instances of <code>PKIXCertPathChecker</code> are passed as parameters + * using the {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} + * or {@link PKIXParameters#addCertPathChecker addCertPathChecker} methods + * of the <code>PKIXParameters</code> and <code>PKIXBuilderParameters</code> + * class. Each of the <code>PKIXCertPathChecker</code>s {@link #check check} + * methods will be called, in turn, for each certificate processed by a PKIX + * <code>CertPathValidator</code> or <code>CertPathBuilder</code> + * implementation.<br /> + * <br /> + * A <code>PKIXCertPathChecker</code> may be called multiple times on + * successive certificates in a certification path. Concrete subclasses + * are expected to maintain any internal state that may be necessary to + * check successive certificates. The {@link #init init} method is used + * to initialize the internal state of the checker so that the certificates + * of a new certification path may be checked. A stateful implementation + * <b>must</b> override the {@link #clone clone} method if necessary in + * order to allow a PKIX <code>CertPathBuilder</code> to efficiently + * backtrack and try other paths. In these situations, the + * <code>CertPathBuilder</code> is able to restore prior path validation + * states by restoring the cloned <code>PKIXCertPathChecker</code>s.<br /> + * <br /> + * The order in which the certificates are presented to the + * <code>PKIXCertPathChecker</code> may be either in the forward direction + * (from target to most-trusted CA) or in the reverse direction (from + * most-trusted CA to target). A <code>PKIXCertPathChecker</code> implementation + * <b>must</b> support reverse checking (the ability to perform its checks when + * it is presented with certificates in the reverse direction) and <b>may</b> + * support forward checking (the ability to perform its checks when it is + * presented with certificates in the forward direction). The + * {@link #isForwardCheckingSupported isForwardCheckingSupported} method + * indicates whether forward checking is supported.<br /> + * <br /> + * Additional input parameters required for executing the check may be + * specified through constructors of concrete implementations of this class.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see PKIXParameters + * @see PKIXBuilderParameters + **/ +public abstract class PKIXCertPathChecker implements Cloneable +{ + + /** + * Default constructor. + */ + protected PKIXCertPathChecker() {} + + /** + * Initializes the internal state of this <code>PKIXCertPathChecker</code>. + * <p> + * The <code>forward</code> flag specifies the order that + * certificates will be passed to the {@link #check check} method + * (forward or reverse). A <code>PKIXCertPathChecker</code> <b>must</b> + * support reverse checking and <b>may</b> support forward checking. + * + * @param forward the order that certificates are presented to + * the <code>check</code> method. If <code>true</code>, certificates + * are presented from target to most-trusted CA (forward); if + * <code>false</code>, from most-trusted CA to target (reverse). + * @exception CertPathValidatorException if this + * <code>PKIXCertPathChecker</code> is unable to check certificates in + * the specified order; it should never be thrown if the forward flag + * is false since reverse checking must be supported + */ + public abstract void init(boolean forward) + throws CertPathValidatorException; + + /** + * Indicates if forward checking is supported. Forward checking refers + * to the ability of the <code>PKIXCertPathChecker</code> to perform + * its checks when certificates are presented to the <code>check</code> + * method in the forward direction (from target to most-trusted CA). + * + * @return <code>true</code> if forward checking is supported, + * <code>false</code> otherwise + */ + public abstract boolean isForwardCheckingSupported(); + + /** + * Returns an immutable <code>Set</code> of X.509 certificate extensions + * that this <code>PKIXCertPathChecker</code> supports (i.e. recognizes, is + * able to process), or <code>null</code> if no extensions are supported. + * <p> + * Each element of the set is a <code>String</code> representing the + * Object Identifier (OID) of the X.509 extension that is supported. + * The OID is represented by a set of nonnegative integers separated by + * periods. + * <p> + * All X.509 certificate extensions that a <code>PKIXCertPathChecker</code> + * might possibly be able to process should be included in the set. + * + * @return an immutable <code>Set</code> of X.509 extension OIDs (in + * <code>String</code> format) supported by this + * <code>PKIXCertPathChecker</code>, or <code>null</code> if no + * extensions are supported + */ + public abstract Set getSupportedExtensions(); + + /** + * Performs the check(s) on the specified certificate using its internal + * state and removes any critical extensions that it processes from the + * specified collection of OID strings that represent the unresolved + * critical extensions. The certificates are presented in the order + * specified by the <code>init</code> method. + * + * @param cert the <code>Certificate</code> to be checked + * @param unresolvedCritExts a <code>Collection</code> of OID strings + * representing the current set of unresolved critical extensions + * @exception CertPathValidatorException if the specified certificate does + * not pass the check + */ + public abstract void check( + Certificate cert, + Collection unresolvedCritExts) + throws CertPathValidatorException; + + /** + * Returns a clone of this object. Calls the <code>Object.clone()</code> + * method. + * All subclasses which maintain state must support and + * override this method, if necessary. + * + * @return a copy of this <code>PKIXCertPathChecker</code> + */ + public Object clone() + { + try { + return super.clone(); + } catch ( CloneNotSupportedException ex ) { + /* Cannot happen */ + throw new InternalError( ex.toString() ); + } + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/PKIXCertPathValidatorResult.java b/core/src/main/jdk1.1/java/security/cert/PKIXCertPathValidatorResult.java new file mode 100644 index 00000000..8ffa2555 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/PKIXCertPathValidatorResult.java @@ -0,0 +1,136 @@ +package java.security.cert; + +import java.security.PublicKey; + +/** + * This class represents the successful result of the PKIX certification + * path validation algorithm. <br /> + * <br /> + * Instances of <code>PKIXCertPathValidatorResult</code> are returned by the + * {@link CertPathValidator#validate validate} method of + * <code>CertPathValidator</code> objects implementing the PKIX algorithm.<br /> + * <br /> + * All <code>PKIXCertPathValidatorResult</code> objects contain the + * valid policy tree and subject public key resulting from the + * validation algorithm, as well as a <code>TrustAnchor</code> describing + * the certification authority (CA) that served as a trust anchor for the + * certification path.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathValidatorResult + **/ +public class PKIXCertPathValidatorResult implements CertPathValidatorResult +{ + private TrustAnchor trustAnchor; + private PolicyNode policyTree; + private PublicKey subjectPublicKey; + + /** + * Creates an instance of <code>PKIXCertPathValidatorResult</code> + * containing the specified parameters. + * + * @param trustAnchor a <code>TrustAnchor</code> describing the CA that + * served as a trust anchor for the certification path + * @param policyTree the immutable valid policy tree, or <code>null</code> + * if there are no valid policies + * @param subjectPublicKey the public key of the subject + * + * @exception NullPointerException if the <code>subjectPublicKey</code> or + * <code>trustAnchor</code> parameters are <code>null</code> + */ + public PKIXCertPathValidatorResult(TrustAnchor trustAnchor, + PolicyNode policyTree, + PublicKey subjectPublicKey) + { + if ( subjectPublicKey == null ) + throw new NullPointerException( "subjectPublicKey must be non-null" ); + if ( trustAnchor == null ) + throw new NullPointerException( "trustAnchor must be non-null" ); + + this.trustAnchor = trustAnchor; + this.policyTree = policyTree; + this.subjectPublicKey = subjectPublicKey; + } + + /** + * Returns the <code>TrustAnchor</code> describing the CA that served + * as a trust anchor for the certification path. + * + * @return the <code>TrustAnchor</code> (never <code>null</code>) + */ + public TrustAnchor getTrustAnchor() + { + return trustAnchor; + } + + /** + * Returns the root node of the valid policy tree resulting from the + * PKIX certification path validation algorithm. The + * <code>PolicyNode</code> object that is returned and any objects that + * it returns through public methods are immutable.<br /> + * <br /> + * Most applications will not need to examine the valid policy tree. + * They can achieve their policy processing goals by setting the + * policy-related parameters in <code>PKIXParameters</code>. However, more + * sophisticated applications, especially those that process policy + * qualifiers, may need to traverse the valid policy tree using the + * {@link PolicyNode#getParent PolicyNode.getParent} and + * {@link PolicyNode#getChildren PolicyNode.getChildren} methods. + * + * @return the root node of the valid policy tree, or <code>null</code> + * if there are no valid policies + */ + public PolicyNode getPolicyTree() + { + return policyTree; + } + + /** + * Returns the public key of the subject (target) of the certification + * path, including any inherited public key parameters if applicable. + * + * @return the public key of the subject (never <code>null</code>) + */ + public PublicKey getPublicKey() + { + return subjectPublicKey; + } + + /** + * Returns a copy of this object. + * + * @return the copy + */ + public Object clone() + { + try { + return super.clone(); + } catch ( CloneNotSupportedException ex ) { + throw new InternalError( ex.toString() ); + } + } + + /** + * Return a printable representation of this + * <code>PKIXCertPathValidatorResult</code>. + * + * @return a <code>String</code> describing the contents of this + * <code>PKIXCertPathValidatorResult</code> + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append( "PKIXCertPathValidatorResult: [ \n" ); + s.append( " Trust Anchor: ").append(getTrustAnchor()).append('\n' ); + s.append( " Policy Tree: ").append(getPolicyTree()).append('\n' ); + s.append( " Subject Public Key: ").append(getPublicKey()).append("\n]" ); + return s.toString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/PKIXParameters.java b/core/src/main/jdk1.1/java/security/cert/PKIXParameters.java new file mode 100644 index 00000000..3c55d7e4 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/PKIXParameters.java @@ -0,0 +1,770 @@ +package java.security.cert; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * Parameters used as input for the PKIX CertPathValidator algorithm.<br /> + * <br /> + * A PKIX <code>CertPathValidator</code> uses these parameters to validate a + * <code>CertPath</code> according to the PKIX certification path validation + * algorithm.<br /> + * <br /> + * To instantiate a <code>PKIXParameters</code> object, an application must specify + * one or more <i>most-trusted CAs</i> as defined by the PKIX certification + * path validation algorithm. The most-trusted CAs can be specified + * using one of two constructors. An application can call + * {@link #PKIXParameters(Set)}, specifying a Set of <code>TrustAnchor</code> objects, each + * of which identify a most-trusted CA. Alternatively, an application + * can call {@link #PKIXParameters(KeyStore)}, specifying a <code>KeyStore</code> instance + * containing trusted certificate entries, each of which will be + * considered as a most-trusted CA.<br /> + * <br /> + * Once a <code>PKIXParameters</code> object has been created, other parameters can + * be specified (by calling {@link #setInitialPolicies} or {@link #setDate}, for + * instance) and then the <code>PKIXParameters</code> is passed along with the + * <code>CertPath</code> to be validated to {@link CertPathValidator#validate}.<br /> + * <br /> + * Any parameter that is not set (or is set to null) will be set to the + * default value for that parameter. The default value for the date + * parameter is null, which indicates the current time when the path is + * validated. The default for the remaining parameters is the least + * constrained.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are + * not thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize. + * + * @see CertPathValidator + **/ +public class PKIXParameters implements CertPathParameters { + private Set trustAnchors; + private Set initialPolicies = new HashSet(); + private List certStores = new ArrayList(); + private CertSelector certSelector; + private List certPathCheckers = new ArrayList(); + private boolean revocationEnabled = true; + private boolean explicitPolicyRequired = false; + private boolean policyMappingInhibited = false; + private boolean anyPolicyInhibited = false; + private boolean policyQualifiersRejected = true; + private Date date; + private String sigProvider; + + /** + * Creates an instance of PKIXParameters with the specified + * Set of most-trusted CAs. Each element of the set is a + * TrustAnchor.<br /> + * <br /> + * Note that the Set is copied to protect against subsequent + * modifications. + * + * @param trustAnchors a Set of TrustAnchors + * + * @exception InvalidAlgorithmParameterException if the + * specified Set is empty <code>(trustAnchors.isEmpty() == true)</code> + * @exception NullPointerException if the specified Set is <code>null</code> + * @exception ClassCastException if any of the elements in the + * Set are not of type + * <code>java.security.cert.TrustAnchor</code> + **/ + public PKIXParameters(Set trustAnchors) + throws InvalidAlgorithmParameterException + { + setTrustAnchors( trustAnchors ); + } + + /** + * Creates an instance of PKIXParameters that populates the + * set of most-trusted CAs from the trusted certificate + * entries contained in the specified KeyStore. Only keystore + * entries that contain trusted X509Certificates are + * considered; all other certificate types are ignored. + * + * @param keystore a KeyStore from which the set of + * most-trusted CAs will be populated + * + * @exception KeyStoreException if the keystore has not been + * initialized + * @exception InvalidAlgorithmParameterException if the keystore + * does not contain at least one trusted certificate entry + * @exception NullPointerException if the keystore is null + **/ + public PKIXParameters(KeyStore keystore) + throws KeyStoreException, + InvalidAlgorithmParameterException + { + if ( keystore == null ) + throw new NullPointerException( "the keystore parameter must be non-null" ); + + Set trustAnchors = new HashSet(); + String alias; + Certificate cert; + Enumeration enum = keystore.aliases(); + while ( enum.hasMoreElements() ) { + alias = (String)enum.nextElement(); + if ( keystore.isCertificateEntry( alias ) ) { + cert = keystore.getCertificate( alias ); + if ( cert instanceof X509Certificate ) + trustAnchors.add( new TrustAnchor( (X509Certificate)cert, null ) ); + } + } + setTrustAnchors( trustAnchors ); + } + + /** + * Returns an immutable Set of the most-trusted CAs. + * + * @return an immutable <code>Set</code> of + * <code>TrustAnchors</code> (never <code>null</code>) + * + * @see #setTrustAnchors + **/ + public Set getTrustAnchors() + { + return Collections.unmodifiableSet(trustAnchors); + } + + /** + * Sets the Set of most-trusted CAs.<br /> + * <br /> + * Note that the Set is copied to protect against subsequent + * modifications.<br /> + * <br /> + * @param trustAnchors a Set of TrustAnchors + * + * @exception InvalidAlgorithmParameterException if the specified Set is empty <code>(trustAnchors.isEmpty() == true)</code> + * @exception NullPointerException if the specified Set is <code>null</code> + * @exception ClassCastException if any of the elements in + * the set are not of type java.security.cert.TrustAnchor + * + * @see #getTrustAnchors + **/ + public void setTrustAnchors(Set trustAnchors) + throws InvalidAlgorithmParameterException + { + if ( trustAnchors == null ) + throw new NullPointerException("the trustAnchors parameter must be non-null"); + if ( trustAnchors.isEmpty() ) + throw new InvalidAlgorithmParameterException("the trustAnchors parameter must be non-empty"); + + Iterator iter = trustAnchors.iterator(); + TrustAnchor obj; + this.trustAnchors = new HashSet(); + while( iter.hasNext() ) { + obj = (TrustAnchor)iter.next(); + if ( obj != null ) { + this .trustAnchors.add( obj ); + } + } + } + + /** + * Returns an immutable Set of initial policy identifiers (OID + * strings), indicating that any one of these policies would + * be acceptable to the certificate user for the purposes of + * certification path processing. The default return value is + * an empty <code>Set</code>, which is interpreted as meaning that any + * policy would be acceptable. + * + * @return an immutable <code>Set</code> of initial policy + * OIDs in String format, or an empty <code>Set</code> (implying any policy + * is acceptable). Never returns <code>null</code>. + * + * @see #setInitialPolicies(java.util.Set) + **/ + public Set getInitialPolicies() + { + Set returnSet = initialPolicies; + if ( initialPolicies == null ) + returnSet = new HashSet(); + + return Collections.unmodifiableSet( returnSet ); + } + + /** + * Sets the <code>Set</code> of initial policy identifiers (OID strings), + * indicating that any one of these policies would be + * acceptable to the certificate user for the purposes of + * certification path processing. By default, any policy is + * acceptable (i.e. all policies), so a user that wants to + * allow any policy as acceptable does not need to call this + * method, or can call it with an empty <code>Set</code> (or <code>null</code>).<br /> + * <br /> + * Note that the Set is copied to protect against subsequent + * modifications.<br /> + * <br /> + * @param initialPolicies a Set of initial policy OIDs in String format (or <code>null</code>) + * + * @exception ClassCastException if any of the elements in the + * set are not of type String + * + * @see #getInitialPolicies() + **/ + public void setInitialPolicies(Set initialPolicies) + { + if ( initialPolicies == null || initialPolicies.isEmpty() ) + { + this.initialPolicies = null; + } + else + { + Iterator iter = initialPolicies.iterator(); + this.initialPolicies = new HashSet(); + String obj; + while ( iter.hasNext() ) + { + obj = (String)iter.next(); + if ( obj != null ) { + this.initialPolicies.add( obj ); + } + } + } + } + + /** + * Sets the list of CertStores to be used in finding + * certificates and CRLs. May be null, in which case no + * CertStores will be used. The first CertStores in the list + * may be preferred to those that appear later.<br /> + * <br /> + * Note that the List is copied to protect against subsequent + * modifications.<br /> + * <br /> + * @param stores a List of CertStores (or <code>null</code>) + * + * @exception ClassCastException if any of the elements in the + * list are not of type <code>java.security.cert.CertStore</code> + * + * @see #getCertStores() + **/ + public void setCertStores(List stores) + { + certStores = new ArrayList(); + if ( stores != null && ! stores.isEmpty() ) + { + Iterator iter = stores.iterator(); + CertStore obj; + while ( iter.hasNext() ) + { + obj = (CertStore)iter.next(); + if ( obj != null ) + { + certStores.add( obj ); + } + } + } + } + + /** + * Adds a CertStore to the end of the list of CertStores used + * in finding certificates and CRLs. + * + * @param store the <code>CertStore</code> to add. If + * <code>null</code<, the store is ignored (not added to + * list). + **/ + public void addCertStore(CertStore store) + { + if ( store != null ) + certStores.add( store ); + } + + /** + * Returns an immutable List of CertStores that are used to + * find certificates and CRLs. + * + * @return an immutable List of CertStores (may be empty, but never <code>null</code>) + * + * @see #setCertStores(java.util.List) + **/ + public List getCertStores() + { + return Collections.unmodifiableList(certStores); + } + + /** + * Sets the RevocationEnabled flag. If this flag is true, the default + * revocation checking mechanism of the underlying PKIX service provider + * will be used. If this flag is false, the default revocation checking + * mechanism will be disabled (not used).<br /> + * <br /> + * When a <code>PKIXParameters</code> object is created, this flag is set + * to true. This setting reflects the most common strategy for checking + * revocation, since each service provider must support revocation + * checking to be PKIX compliant. Sophisticated applications should set + * this flag to false when it is not practical to use a PKIX service + * provider's default revocation checking mechanism or when an alternative + * revocation checking mechanism is to be substituted (by also calling the + * {@link #addCertPathChecker addCertPathChecker} or {@link + * #setCertPathCheckers setCertPathCheckers} methods). + * + * @param val the new value of the RevocationEnabled flag + **/ + public void setRevocationEnabled(boolean val) + { + revocationEnabled = val; + } + + /** + * Checks the RevocationEnabled flag. If this flag is true, + * the default revocation checking mechanism of the underlying + * PKIX service provider will be used. If this flag is false, + * the default revocation checking mechanism will be disabled + * (not used). See the setRevocationEnabled method for more + * details on setting the value of this flag. + * + * @return the current value of the RevocationEnabled flag + **/ + public boolean isRevocationEnabled() + { + return revocationEnabled; + } + + /** + * Sets the ExplicitPolicyRequired flag. If this flag is true, + * an acceptable policy needs to be explicitly identified in + * every certificate. By default, the ExplicitPolicyRequired + * flag is false. + * + * @param val true if explicit policy is to be required, false + * otherwise + **/ + public void setExplicitPolicyRequired(boolean val) + { + explicitPolicyRequired = val; + } + + /** + * Checks if explicit policy is required. If this flag is + * true, an acceptable policy needs to be explicitly + * identified in every certificate. By default, the + * ExplicitPolicyRequired flag is false. + * + * @return true if explicit policy is required, false otherwise + **/ + public boolean isExplicitPolicyRequired() + { + return explicitPolicyRequired; + } + + /** + * Sets the PolicyMappingInhibited flag. If this flag is true, + * policy mapping is inhibited. By default, policy mapping is + * not inhibited (the flag is false). + * + * @param val true if policy mapping is to be inhibited, false otherwise + **/ + public void setPolicyMappingInhibited(boolean val) + { + policyMappingInhibited = val; + } + + /** + * Checks if policy mapping is inhibited. If this flag is + * true, policy mapping is inhibited. By default, policy + * mapping is not inhibited (the flag is false). + * + * @return true if policy mapping is inhibited, false otherwise + **/ + public boolean isPolicyMappingInhibited() + { + return policyMappingInhibited; + } + + /** + * Sets state to determine if the any policy OID should be + * processed if it is included in a certificate. By default, + * the any policy OID is not inhibited ({@link #isAnyPolicyInhibited()} + * returns false). + * + * @return val - <code>true</code> if the any policy OID is to be inhibited, <code>false</code> otherwise + **/ + public void setAnyPolicyInhibited(boolean val) + { + anyPolicyInhibited = val; + } + + /** + * Checks whether the any policy OID should be processed if it + * is included in a certificate. + * + * @return <code>true</code> if the any policy OID is inhibited, <code>false</code> otherwise + **/ + public boolean isAnyPolicyInhibited() + { + return anyPolicyInhibited; + } + + /** + * Sets the PolicyQualifiersRejected flag. If this flag is + * true, certificates that include policy qualifiers in a + * certificate policies extension that is marked critical are + * rejected. If the flag is false, certificates are not + * rejected on this basis.<br /> + * <br /> + * When a <code>PKIXParameters</code> object is created, this flag is set + * to true. This setting reflects the most common (and + * simplest) strategy for processing policy + * qualifiers. Applications that want to use a more + * sophisticated policy must set this flag to false.<br /> + * <br /> + * Note that the PKIX certification path validation algorithm + * specifies that any policy qualifier in a certificate + * policies extension that is marked critical must be + * processed and validated. Otherwise the certification path + * must be rejected. If the policyQualifiersRejected flag is + * set to false, it is up to the application to validate all + * policy qualifiers in this manner in order to be PKIX + * compliant. + * + * @param qualifiersRejected the new value of the PolicyQualifiersRejected flag + * + * @see #getPolicyQualifiersRejected() + * @see PolicyQualifierInfo + **/ + public void setPolicyQualifiersRejected(boolean qualifiersRejected) + { + policyQualifiersRejected = qualifiersRejected; + } + + /** + * Gets the PolicyQualifiersRejected flag. If this flag is + * true, certificates that include policy qualifiers in a + * certificate policies extension that is marked critical are + * rejected. If the flag is false, certificates are not + * rejected on this basis.<br /> + * <br /> + * When a PKIXParameters object is created, this flag is set to + * true. This setting reflects the most common (and simplest) + * strategy for processing policy qualifiers. Applications that + * want to use a more sophisticated policy must set this flag + * to false. + * + * @return the current value of the PolicyQualifiersRejected flag + * + * @see #setPolicyQualifiersRejected(boolean) + **/ + public boolean getPolicyQualifiersRejected() + { + return policyQualifiersRejected; + } + + /** + * Returns the time for which the validity of the + * certification path should be determined. If null, the + * current time is used.<br /> + * <br /> + * Note that the Date returned is copied to protect against + * subsequent modifications. + * + * @return the Date, or <code>null</code> if not set + * + * @see #setDate(java.util.Date) + **/ + public Date getDate() + { + if ( date == null ) + return null; + + return new Date( date.getTime() ); + } + + /** + * Sets the time for which the validity of the certification + * path should be determined. If null, the current time is + * used.<br /> + * <br /> + * Note that the Date supplied here is copied to protect + * against subsequent modifications. + * + * @param date the Date, or <code>null</code> for the current time + * + * @see #getDate() + **/ + public void setDate(Date date) + { + if ( date == null ) + this.date = null; + else + this.date = new Date( date.getTime() ); + } + + /** + * Sets a <code>List</code> of additional certification path checkers. If + * the specified List contains an object that is not a + * PKIXCertPathChecker, it is ignored.<br /> + * <br /> + * Each <code>PKIXCertPathChecker</code> specified implements additional + * checks on a certificate. Typically, these are checks to + * process and verify private extensions contained in + * certificates. Each <code>PKIXCertPathChecker</code> should be + * instantiated with any initialization parameters needed to + * execute the check.<br /> + * <br /> + * This method allows sophisticated applications to extend a + * PKIX <code>CertPathValidator</code> or <code>CertPathBuilder</code>. Each of the + * specified PKIXCertPathCheckers will be called, in turn, by + * a PKIX <code>CertPathValidator</code> or <code>CertPathBuilder</code> for each + * certificate processed or validated.<br /> + * <br /> + * Regardless of whether these additional PKIXCertPathCheckers + * are set, a PKIX <code>CertPathValidator</code> or <code>CertPathBuilder</code> must + * perform all of the required PKIX checks on each + * certificate. The one exception to this rule is if the + * RevocationEnabled flag is set to false (see the + * {@link #setRevocationEnabled(boolean) setRevocationEnabled} method).<br /> + * <br /> + * Note that the List supplied here is copied and each + * PKIXCertPathChecker in the list is cloned to protect against + * subsequent modifications. + * + * @param checkers a List of PKIXCertPathCheckers. May be + * null, in which case no additional checkers will be used. + * @exception ClassCastException if any of the elements in the + * list are not of type + * <code>java.security.cert.PKIXCertPathChecker</code> + * @see #getCertPathCheckers() + **/ + public void setCertPathCheckers(List checkers) + { + certPathCheckers = new ArrayList(); + if ( checkers == null ) + return; + Iterator iter = checkers.iterator(); + while ( iter.hasNext() ) + certPathCheckers.add( (PKIXCertPathChecker)((PKIXCertPathChecker)iter.next()).clone() ); + } + + /** + * Returns the List of certification path checkers. The + * returned List is immutable, and each PKIXCertPathChecker in + * the List is cloned to protect against subsequent + * modifications. + * + * @return an immutable List of PKIXCertPathCheckers (may be empty, but not <code>null</code>) + * + * @see #setCertPathCheckers(java.util.List) + **/ + public List getCertPathCheckers() + { + List checkers = new ArrayList(); + Iterator iter = certPathCheckers.iterator(); + while ( iter.hasNext() ) + { + checkers.add( (PKIXCertPathChecker)((PKIXCertPathChecker)iter.next()).clone() ); + } + return Collections.unmodifiableList(checkers); + } + + /** + * Adds a PKIXCertPathChecker to the list of certification + * path checkers. See the {@link #setCertPathCheckers} method for more + * details.<br /> + * <br /> + * Note that the <code>PKIXCertPathChecker</code> is cloned to protect + * against subsequent modifications. + * + * @param checker a <code>PKIXCertPathChecker</code> to add + * to the list of checks. If <code>null</code>, the checker is + * ignored (not added to list). + **/ + public void addCertPathChecker( PKIXCertPathChecker checker ) + { + if ( checker != null ) + { + certPathCheckers.add( checker.clone() ); + } + } + + /** + * Returns the signature provider's name, or <code>null</code> if not set. + * + * @return the signature provider's name (or <code>null</code>) + * + * @see #setSigProvider(java.lang.String) + **/ + public String getSigProvider() + { + return sigProvider; + } + + /** + * Sets the signature provider's name. The specified provider + * will be preferred when creating Signature objects. If null + * or not set, the first provider found supporting the + * algorithm will be used. + * + * @param sigProvider the signature provider's name (or <code>null</code>) + * + * @see #getSigProvider() + **/ + public void setSigProvider(String sigProvider) + { + this.sigProvider = sigProvider; + } + + /** + * Returns the required constraints on the target + * certificate. The constraints are returned as an instance of + * CertSelector. If <code>null</code>, no constraints are defined.<br /> + * <br /> + * Note that the CertSelector returned is cloned to protect + * against subsequent modifications. + * + * @return a CertSelector specifying the constraints on the target certificate (or <code>null</code>) + * + * @see #setTargetCertConstraints(java.security.cert.CertSelector) + **/ + public CertSelector getTargetCertConstraints() + { + if ( certSelector == null ) + return null; + + return (CertSelector)certSelector.clone(); + } + + /** + * Sets the required constraints on the target + * certificate. The constraints are specified as an instance + * of CertSelector. If null, no constraints are defined.<br /> + * <br /> + * Note that the CertSelector specified is cloned to protect + * against subsequent modifications. + * + * @param selector a CertSelector specifying the constraints + * on the target certificate (or <code>null</code>) + * + * @see #getTargetCertConstraints() + **/ + public void setTargetCertConstraints(CertSelector selector) + { + if ( selector == null ) + certSelector = null; + else + certSelector = (CertSelector)selector.clone(); + } + + /** + * Makes a copy of this PKIXParameters object. Changes to the + * copy will not affect the original and vice versa. + * + * @return a copy of this <code>PKIXParameters</code> object + **/ + public Object clone() + { + try { + PKIXParameters obj = (PKIXParameters)super.clone(); + obj.certStores = new ArrayList( certStores ); + Iterator iter = certPathCheckers.iterator(); + obj.certPathCheckers = new ArrayList(); + while ( iter.hasNext() ) + { + obj.certPathCheckers.add( ((PKIXCertPathChecker)iter.next()).clone() ); + } + if ( initialPolicies != null ) + { + obj.initialPolicies = new HashSet( initialPolicies ); + } + if ( trustAnchors != null ) + { + obj.trustAnchors = new HashSet( trustAnchors ); + } + if ( certSelector != null ) + { + obj.certSelector = (CertSelector)certSelector.clone(); + } + return obj; + } catch ( CloneNotSupportedException ex ) { + throw new InternalError(); + } + } + + /** + * Returns a formatted string describing the parameters. + * + * @return a formatted string describing the parameters. + **/ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("[\n"); + if ( trustAnchors != null ) + { + s.append(" Trust Anchors: ").append(trustAnchors).append('\n'); + } + if ( initialPolicies != null ) + { + if ( initialPolicies.isEmpty() ) + { + s.append(" Initial Policy OIDs: any\n" ); + } + else + { + s.append(" Initial Policy OIDs: [").append(initialPolicies).append("]\n"); + } + } + s.append(" Validity Date: "); + if ( date != null ) + s.append(date); + else + s.append("null"); + s.append('\n'); + + s.append(" Signature Provider: "); + if ( sigProvider != null ) + s.append(sigProvider); + else + s.append("null"); + s.append('\n'); + + s.append(" Default Revocation Enabled: "); + s.append(revocationEnabled); + s.append('\n' ); + + s.append(" Explicit Policy Required: "); + s.append(explicitPolicyRequired); + s.append('\n'); + + s.append(" Policy Mapping Inhibited: "); + s.append(policyMappingInhibited); + s.append('\n'); + + s.append(" Any Policy Inhibited: "); + s.append(anyPolicyInhibited); + s.append('\n'); + + s.append(" Policy Qualifiers Rejected: "); + s.append(policyQualifiersRejected); + s.append('\n'); + + s.append(" Target Cert Constraints: "); + s.append(certSelector); + s.append('\n'); + + s.append(" Certification Path Checkers: ["); + s.append(certPathCheckers); + s.append( "}\n"); + + s.append(" CertStores: ["); + s.append(certStores); + s.append("}\n"); + + s.append("]\n"); + + return s.toString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/PolicyNode.java b/core/src/main/jdk1.1/java/security/cert/PolicyNode.java new file mode 100644 index 00000000..cdae4520 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/PolicyNode.java @@ -0,0 +1,107 @@ +package java.security.cert; + +import java.util.Iterator; +import java.util.Set; + +/** + * An immutable valid policy tree node as defined by the PKIX certification + * path validation algorithm.<br /> + * <br /> + * One of the outputs of the PKIX certification path validation + * algorithm is a valid policy tree, which includes the policies that + * were determined to be valid, how this determination was reached, + * and any policy qualifiers encountered. This tree is of depth + * <i>n</i>, where <i>n</i> is the length of the certification + * path that has been validated.<br /> + * <br /> + * Most applications will not need to examine the valid policy tree. + * They can achieve their policy processing goals by setting the + * policy-related parameters in <code>PKIXParameters</code>. However, + * the valid policy tree is available for more sophisticated applications, + * especially those that process policy qualifiers.<br /> + * <br /> + * {@link PKIXCertPathValidatorResult#getPolicyTree() + * PKIXCertPathValidatorResult.getPolicyTree} returns the root node of the + * valid policy tree. The tree can be traversed using the + * {@link #getChildren getChildren} and {@link #getParent getParent} methods. + * Data about a particular node can be retrieved using other methods of + * <code>PolicyNode</code>.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * All <code>PolicyNode</code> objects must be immutable and + * thread-safe. Multiple threads may concurrently invoke the methods defined + * in this class on a single <code>PolicyNode</code> object (or more than one) + * with no ill effects. This stipulation applies to all public fields and + * methods of this class and any added or overridden by subclasses. + **/ +public interface PolicyNode +{ + + /** + * Returns the parent of this node, or <code>null</code> if this is the + * root node. + * + * @return the parent of this node, or <code>null</code> if this is the + * root node + */ + public PolicyNode getParent(); + + /** + * Returns an iterator over the children of this node. Any attempts to + * modify the children of this node through the + * <code>Iterator</code>'s remove method must throw an + * <code>UnsupportedOperationException</code>. + * + * @return an iterator over the children of this node + */ + public Iterator getChildren(); + + /** + * Returns the depth of this node in the valid policy tree. + * + * @return the depth of this node (0 for the root node, 1 for its + * children, and so on) + */ + public int getDepth(); + + /** + * Returns the valid policy represented by this node. + * + * @return the <code>String</code> OID of the valid policy + * represented by this node, or the special value "any-policy". For + * the root node, this method always returns the special value "any-policy". + */ + public String getValidPolicy(); + + /** + * Returns the set of policy qualifiers associated with the + * valid policy represented by this node. + * + * @return an immutable <code>Set</code> of + * <code>PolicyQualifierInfo</code>s. For the root node, this + * is always an empty <code>Set</code>. + */ + public Set getPolicyQualifiers(); + + /** + * Returns the set of expected policies that would satisfy this + * node's valid policy in the next certificate to be processed. + * + * @return an immutable <code>Set</code> of expected policy + * <code>String</code> OIDs, or an immutable <code>Set</code> with + * the single special value "any-policy". For the root node, this method + * always returns a <code>Set</code> with the single value "any-policy". + */ + public Set getExpectedPolicies(); + + /** + * Returns the criticality indicator of the certificate policy extension + * in the most recently processed certificate. + * + * @return <code>true</code> if extension marked critical, + * <code>false</code> otherwise. For the root node, <code>false</code> + * is always returned. + */ + public boolean isCritical(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/PolicyQualifierInfo.java b/core/src/main/jdk1.1/java/security/cert/PolicyQualifierInfo.java new file mode 100644 index 00000000..5073669e --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/PolicyQualifierInfo.java @@ -0,0 +1,196 @@ +package java.security.cert; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DEROutputStream; +import org.bouncycastle.asn1.util.ASN1Dump; + +/** + * An immutable policy qualifier represented by the ASN.1 PolicyQualifierInfo + * structure.<br /> + * <br /> + * The ASN.1 definition is as follows:<br /> + * <br /> + * + * <pre> + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * </pre> + * + * <br /> + * <br /> + * A certificate policies extension, if present in an X.509 version 3 + * certificate, contains a sequence of one or more policy information terms, + * each of which consists of an object identifier (OID) and optional qualifiers. + * In an end-entity certificate, these policy information terms indicate the + * policy under which the certificate has been issued and the purposes for which + * the certificate may be used. In a CA certificate, these policy information + * terms limit the set of policies for certification paths which include this + * certificate.<br /> + * <br /> + * A <code>Set</code> of <code>PolicyQualifierInfo</code> objects are + * returned by the + * {@link PolicyNode#getPolicyQualifiers PolicyNode.getPolicyQualifiers} method. + * This allows applications with specific policy requirements to process and + * validate each policy qualifier. Applications that need to process policy + * qualifiers should explicitly set the <code>policyQualifiersRejected</code> + * flag to false (by calling the + * {@link PKIXParameters#setPolicyQualifiersRejected + * PKIXParameters.setPolicyQualifiersRejected} method) before validating a + * certification path.<br /> + * <br /> + * Note that the PKIX certification path validation algorithm specifies that any + * policy qualifier in a certificate policies extension that is marked critical + * must be processed and validated. Otherwise the certification path must be + * rejected. If the <code>policyQualifiersRejected</code> flag is set to + * false, it is up to the application to validate all policy qualifiers in this + * manner in order to be PKIX compliant.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * All <code>PolicyQualifierInfo</code> objects must be immutable and + * thread-safe. That is, multiple threads may concurrently invoke the methods + * defined in this class on a single <code>PolicyQualifierInfo</code> object + * (or more than one) with no ill effects. Requiring + * <code>PolicyQualifierInfo</code> objects to be immutable and thread-safe + * allows them to be passed around to various pieces of code without worrying + * about coordinating access.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.bouncycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object} + */ +public final class PolicyQualifierInfo +{ + private String id; + + private byte[] encoded; + + private byte[] qualifier; + + /** + * Creates an instance of <code>PolicyQualifierInfo</code> from the + * encoded bytes. The encoded byte array is copied on construction.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.bouncycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier} and + * {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream} + * + * @param encoded + * a byte array containing the qualifier in DER encoding + * + * @exception IOException + * thrown if the byte array does not represent a valid and + * parsable policy qualifier + */ + public PolicyQualifierInfo(byte[] encoded) throws IOException + { + this.encoded = (byte[])encoded.clone(); + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + this.encoded); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Sequence obj = (ASN1Sequence)derInStream.readObject(); + id = ((ASN1ObjectIdentifier)obj.getObjectAt(0)).getId(); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + + derOutStream.writeObject(obj.getObjectAt(1)); + derOutStream.close(); + + qualifier = outStream.toByteArray(); + } + catch (Exception ex) + { + throw new IOException("parsing exception : " + ex.toString()); + } + } + + /** + * Returns the <code>policyQualifierId</code> field of this + * <code>PolicyQualifierInfo</code>. The <code>policyQualifierId</code> + * is an Object Identifier (OID) represented by a set of nonnegative + * integers separated by periods. + * + * @return the OID (never <code>null</code>) + */ + public String getPolicyQualifierId() + { + return id; + } + + /** + * Returns the ASN.1 DER encoded form of this + * <code>PolicyQualifierInfo</code>. + * + * @return the ASN.1 DER encoded bytes (never <code>null</code>). Note + * that a copy is returned, so the data is cloned each time this + * method is called. + */ + public byte[] getEncoded() + { + return (byte[])encoded.clone(); + } + + /** + * Returns the ASN.1 DER encoded form of the <code>qualifier</code> field + * of this <code>PolicyQualifierInfo</code>. + * + * @return the ASN.1 DER encoded bytes of the <code>qualifier</code> + * field. Note that a copy is returned, so the data is cloned each + * time this method is called. + */ + public byte[] getPolicyQualifier() + { + if (qualifier == null) + { + return null; + } + + return (byte[])qualifier.clone(); + } + + /** + * Return a printable representation of this + * <code>PolicyQualifierInfo</code>.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object} + * + * @return a <code>String</code> describing the contents of this + * <code>PolicyQualifierInfo</code> + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("PolicyQualifierInfo: [\n"); + s.append("qualifierID: ").append(id).append('\n'); + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(qualifier); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + s + .append(" qualifier:\n").append(ASN1Dump.dumpAsString(derObject)) + .append('\n'); + } + catch (IOException ex) + { + s.append(ex.getMessage()); + } + s.append("qualifier: ").append(id).append('\n'); + s.append(']'); + return s.toString(); + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/TrustAnchor.java b/core/src/main/jdk1.1/java/security/cert/TrustAnchor.java new file mode 100644 index 00000000..23ced2f7 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/TrustAnchor.java @@ -0,0 +1,293 @@ +package java.security.cert; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.PublicKey; +import java.security.cert.X509Certificate; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Sequence; + +/** + * A trust anchor or most-trusted Certification Authority (CA). <br /> + * <br /> + * This class represents a "most-trusted CA", which is used as a trust anchor + * for validating X.509 certification paths. A most-trusted CA includes the + * public key of the CA, the CA's name, and any constraints upon the set of + * paths which may be validated using this key. These parameters can be + * specified in the form of a trusted X509Certificate or as individual + * parameters. <br /> + * <br /> + * <strong>Concurrent Access</strong><br /> + * <br /> + * All TrustAnchor objects must be immutable and thread-safe. That is, multiple + * threads may concurrently invoke the methods defined in this class on a + * single TrustAnchor object (or more than one) with no ill effects. Requiring + * TrustAnchor objects to be immutable and thread-safe allows them to be passed + * around to various pieces of code without worrying about coordinating access. + * This stipulation applies to all public fields and methods of this class and + * any added or overridden by subclasses.<br /> + * <br /> + * <b>TODO: implement better nameConstraints testing.</b> + **/ +public class TrustAnchor +{ + private X509Certificate trustCert = null; + + private PublicKey trustPublicKey = null; + + private String trustName = null; + + private byte[] nameConstraints = null; + + /** + * Creates an instance of TrustAnchor with the specified X509Certificate and + * optional name constraints, which are intended to be used as additional + * constraints when validating an X.509 certification path.<br /> + * <br /> + * The name constraints are specified as a byte array. This byte array + * should contain the DER encoded form of the name constraints, as they + * would appear in the NameConstraints structure defined in RFC 2459 and + * X.509. The ASN.1 definition of this structure appears below.<br /> + * <br /> + * + * <pre> + * NameConstraints ::= SEQUENCE { + * permittedSubtrees [0] GeneralSubtrees OPTIONAL, + * excludedSubtrees [1] GeneralSubtrees OPTIONAL } + * + * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + * + * GeneralSubtree ::= SEQUENCE { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL } + * + * BaseDistance ::= INTEGER (0..MAX) + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * </pre> + * + * <br /> + * <br /> + * Note that the name constraints byte array supplied is cloned to protect + * against subsequent modifications. + * + * @param trustedCert + * a trusted X509Certificate + * @param nameConstraints + * a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension to be used for checking name + * constraints. Only the value of the extension is included, not + * the OID or criticality flag. Specify null to omit the + * parameter. + * + * @exception IllegalArgumentException + * if the name constraints cannot be decoded + * @exception NullPointerException + * if the specified X509Certificate is null + */ + public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) + { + if (trustedCert == null) + { + throw new NullPointerException("trustedCert must be non-null"); + } + + this.trustCert = trustedCert; + if (nameConstraints != null) + { + this.nameConstraints = (byte[])nameConstraints.clone(); + checkNameConstraints(this.nameConstraints); + } + } + + /** + * Creates an instance of <code>TrustAnchor</code> where the most-trusted + * CA is specified as a distinguished name and public key. Name constraints + * are an optional parameter, and are intended to be used as additional + * constraints when validating an X.509 certification path. + * + * The name constraints are specified as a byte array. This byte array + * contains the DER encoded form of the name constraints, as they would + * appear in the NameConstraints structure defined in RFC 2459 and X.509. + * The ASN.1 notation for this structure is supplied in the documentation + * for {@link #TrustAnchor(X509Certificate trustedCert, byte[] + * nameConstraints) TrustAnchor(X509Certificate trustedCert, byte[] + * nameConstraints) }. + * + * Note that the name constraints byte array supplied here is cloned to + * protect against subsequent modifications. + * + * @param caName + * the X.500 distinguished name of the most-trusted CA in RFC + * 2253 String format + * @param pubKey + * the public key of the most-trusted CA + * @param nameConstraints + * a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension to be used for checking name + * constraints. Only the value of the extension is included, not + * the OID or criticality flag. Specify null to omit the + * parameter. + * + * @exception IllegalArgumentException + * if the specified caName parameter is empty (<code>caName.length() == 0</code>) + * or incorrectly formatted or the name constraints cannot be + * decoded + * @exception NullPointerException + * if the specified caName or pubKey parameter is null + */ + public TrustAnchor(String caName, PublicKey pubKey, byte[] nameConstraints) + { + if (caName == null) + { + throw new NullPointerException("caName must be non-null"); + } + if (pubKey == null) + { + throw new NullPointerException("pubKey must be non-null"); + } + if (caName.length() == 0) + { + throw new IllegalArgumentException( + "caName can not be an empty string"); + } + + this.trustName = caName; + this.trustPublicKey = pubKey; + if (nameConstraints != null) + { + this.nameConstraints = (byte[])nameConstraints.clone(); + checkNameConstraints(this.nameConstraints); + } + } + + /** + * Returns the most-trusted CA certificate. + * + * @return a trusted <code>X509Certificate</code> or <code>null</code> + * if the trust anchor was not specified as a trusted certificate + */ + public final X509Certificate getTrustedCert() + { + return trustCert; + } + + /** + * Returns the name of the most-trusted CA in RFC 2253 String format. + * + * @return the X.500 distinguished name of the most-trusted CA, or + * <code>null</code> if the trust anchor was not specified as a + * trusted public key and name pair + */ + public final String getCAName() + { + return trustName; + } + + /** + * Returns the public key of the most-trusted CA. + * + * @return the public key of the most-trusted CA, or null if the trust + * anchor was not specified as a trusted public key and name pair + */ + public final PublicKey getCAPublicKey() + { + return trustPublicKey; + } + + /** + * Returns the name constraints parameter. The specified name constraints + * are associated with this trust anchor and are intended to be used as + * additional constraints when validating an X.509 certification path.<br /> + * <br /> + * The name constraints are returned as a byte array. This byte array + * contains the DER encoded form of the name constraints, as they would + * appear in the NameConstraints structure defined in RFC 2459 and X.509. + * The ASN.1 notation for this structure is supplied in the documentation + * for <code>TrustAnchor(X509Certificate trustedCert, byte[] + * nameConstraints)</code>.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications. + * + * @return a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension used for checking name constraints, or + * <code>null</code> if not set. + */ + public final byte[] getNameConstraints() + { + return (byte[])nameConstraints.clone(); + } + + /** + * Returns a formatted string describing the <code>TrustAnchor</code>. + * + * @return a formatted string describing the <code>TrustAnchor</code> + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("[\n"); + if (getCAPublicKey() != null) + { + sb.append(" Trusted CA Public Key: ").append(getCAPublicKey()).append('\n'); + sb.append(" Trusted CA Issuer Name: ").append(getCAName()).append('\n'); + } + else + { + sb.append(" Trusted CA cert: ").append(getTrustedCert()).append('\n'); + } + if (nameConstraints != null) + { + sb.append(" Name Constraints: ").append(nameConstraints).append('\n'); + } + return sb.toString(); + } + + /** + * Check given DER encoded nameConstraints for correct decoding. Currently + * only basic DER decoding test.<br /> + * <br /> + * <b>TODO: implement more testing.</b> + * + * @param data + * the DER encoded nameConstrains to be checked or + * <code>null</code> + * @exception IllegalArgumentException + * if the check failed. + */ + private void checkNameConstraints(byte[] data) + { + if (data != null) + { + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + if (!(derObject instanceof ASN1Sequence)) + { + throw new IllegalArgumentException( + "nameConstraints parameter decoding error"); + } + } + catch (IOException ex) + { + throw new IllegalArgumentException( + "nameConstraints parameter decoding error: " + ex); + } + } + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/X509CRL.java b/core/src/main/jdk1.1/java/security/cert/X509CRL.java new file mode 100644 index 00000000..cf65ed0b --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/X509CRL.java @@ -0,0 +1,77 @@ + +package java.security.cert; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.SignatureException; +import java.util.Date; +import java.util.Set; + +public abstract class X509CRL extends CRL implements X509Extension +{ + protected X509CRL() + { + super("X.509"); + } + + public boolean equals(Object other) + { + if ( this == other ) + return true; + + if ( !(other instanceof X509CRL) ) + return false; + + try + { + byte[] enc1 = getEncoded(); + byte[] enc2 = ((X509CRL)other).getEncoded(); + + return MessageDigest.isEqual(enc1, enc2); + } + catch (CRLException e) + { + return false; + } + } + + public int hashCode() + { + int hashcode = 0; + + try + { + byte[] encoded = getEncoded(); + for (int i = 1; i < encoded.length; i++) + { + hashcode += encoded[i] * i; + } + } + catch (CRLException ce) + { + return(hashcode); + } + + return(hashcode); + } + + public abstract byte[] getEncoded() throws CRLException; + public abstract Principal getIssuerDN(); + public abstract Date getNextUpdate(); + public abstract X509CRLEntry getRevokedCertificate(BigInteger serialNumber); + public abstract Set getRevokedCertificates(); + public abstract String getSigAlgName(); + public abstract String getSigAlgOID(); + public abstract byte[] getSigAlgParams(); + public abstract byte[] getSignature(); + public abstract byte[] getTBSCertList() throws CRLException; + public abstract Date getThisUpdate(); + public abstract int getVersion(); + public abstract void verify(PublicKey key) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException; + public abstract void verify(PublicKey key, String sigProvider) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException; +} diff --git a/core/src/main/jdk1.1/java/security/cert/X509CRLEntry.java b/core/src/main/jdk1.1/java/security/cert/X509CRLEntry.java new file mode 100644 index 00000000..bb0d7807 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/X509CRLEntry.java @@ -0,0 +1,56 @@ + +package java.security.cert; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.util.Date; + +public abstract class X509CRLEntry implements X509Extension +{ + public boolean equals(Object other) + { + if ( this == other ) + return true; + + if ( !(other instanceof X509CRLEntry) ) + return false; + + try + { + byte[] enc1 = getEncoded(); + byte[] enc2 = ((X509CRLEntry)other).getEncoded(); + + return MessageDigest.isEqual(enc1, enc2); + } + catch (CRLException e) + { + return false; + } + } + + public int hashCode() + { + int hashcode = 0; + + try + { + byte[] encoded = getEncoded(); + for (int i = 1; i < encoded.length; i++) + { + hashcode += encoded[i] * i; + } + } + catch (CRLException ce) + { + return(hashcode); + } + + return(hashcode); + } + + public abstract byte[] getEncoded() throws CRLException; + public abstract Date getRevocationDate(); + public abstract BigInteger getSerialNumber(); + public abstract boolean hasExtensions(); + public abstract String toString(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/X509CRLSelector.java b/core/src/main/jdk1.1/java/security/cert/X509CRLSelector.java new file mode 100644 index 00000000..8da7bbe6 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/X509CRLSelector.java @@ -0,0 +1,717 @@ +package java.security.cert; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRL; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERInteger; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.asn1.x509.X509Name; +import org.bouncycastle.jce.PrincipalUtil; + +/** + * A <code>CRLSelector</code> that selects <code>X509CRLs</code> that match + * all specified criteria. This class is particularly useful when selecting CRLs + * from a <code>CertStore</code> to check revocation status of a particular + * certificate.<br /> + * <br /> + * When first constructed, an <code>X509CRLSelector</code> has no criteria + * enabled and each of the <code>get</code> methods return a default value (<code>null</code>). + * Therefore, the {@link #match match} method would return <code>true</code> + * for any <code>X509CRL</code>. Typically, several criteria are enabled (by + * calling {@link #setIssuerNames setIssuerNames} or + * {@link #setDateAndTime setDateAndTime}, for instance) and then the + * <code>X509CRLSelector</code> is passed to + * {@link CertStore#getCRLs CertStore.getCRLs} or some similar method.<br /> + * <br /> + * Please refer to RFC 2459 for definitions of the X.509 CRL fields and + * extensions mentioned below.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are not + * thread-safe. Multiple threads that need to access a single object + * concurrently should synchronize amongst themselves and provide the necessary + * locking. Multiple threads each manipulating separate objects need not + * synchronize.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.bouncycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object}, + * {@link org.bouncycastle.asn1.x509.X509Name X509Name} + * + * @see CRLSelector + * @see X509CRL + */ +public class X509CRLSelector implements CRLSelector +{ + private Set issuerNames = null; + + private Set issuerNamesX509 = null; + + private BigInteger minCRL = null; + + private BigInteger maxCRL = null; + + private Date dateAndTime = null; + + private X509Certificate certChecking = null; + + /** + * Creates an <code>X509CRLSelector</code>. Initially, no criteria are + * set so any <code>X509CRL</code> will match. + */ + public X509CRLSelector() + { + } + + /** + * Sets the issuerNames criterion. The issuer distinguished name in the + * <code>X509CRL</code> must match at least one of the specified + * distinguished names. If <code>null</code>, any issuer distinguished + * name will do.<br /> + * <br /> + * This method allows the caller to specify, with a single method call, the + * complete set of issuer names which <code>X509CRLs</code> may contain. + * The specified value replaces the previous value for the issuerNames + * criterion.<br /> + * <br /> + * The <code>names</code> parameter (if not <code>null</code>) is a + * <code>Collection</code> of names. Each name is a <code>String</code> + * or a byte array representing a distinguished name (in RFC 2253 or ASN.1 + * DER encoded form, respectively). If <code>null</code> is supplied as + * the value for this argument, no issuerNames check will be performed.<br /> + * <br /> + * Note that the <code>names</code> parameter can contain duplicate + * distinguished names, but they may be removed from the + * <code>Collection</code> of names returned by the + * {@link #getIssuerNames getIssuerNames} method.<br /> + * <br /> + * If a name is specified as a byte array, it should contain a single DER + * encoded distinguished name, as defined in X.501. The ASN.1 notation for + * this structure is as follows. + * + * <pre><code> + * Name ::= CHOICE { + * RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RDN + * + * RDN ::= + * SET SIZE (1 .. MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * .... + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1.. MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + * </code></pre> + * + * <br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @param names + * a <code>Collection</code> of names (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs + * + * @see #getIssuerNames + */ + public void setIssuerNames(Collection names) throws IOException + { + if (names == null || names.isEmpty()) + { + issuerNames = null; + issuerNamesX509 = null; + } + else + { + Object item; + Iterator iter = names.iterator(); + while (iter.hasNext()) + { + item = iter.next(); + if (item instanceof String) + { + addIssuerName((String)item); + } + else if (item instanceof byte[]) + { + addIssuerName((byte[])item); + } + else + { + throw new IOException("name not byte[]or String: " + + item.toString()); + } + } + } + } + + /** + * Adds a name to the issuerNames criterion. The issuer distinguished name + * in the <code>X509CRL</code> must match at least one of the specified + * distinguished names.<br /> + * <br /> + * This method allows the caller to add a name to the set of issuer names + * which <code>X509CRLs</code> may contain. The specified name is added to + * any previous value for the issuerNames criterion. If the specified name + * is a duplicate, it may be ignored.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for parsing the + * name + * + * @param name + * the name in RFC 2253 form + * + * @exception IOException + * if a parsing error occurs + */ + public void addIssuerName(String name) throws IOException + { + if (issuerNames == null) + { + issuerNames = new HashSet(); + issuerNamesX509 = new HashSet(); + } + X509Name nameX509; + try + { + nameX509 = new X509Name(name); + } + catch (IllegalArgumentException ex) + { + throw new IOException(ex.getMessage()); + } + issuerNamesX509.add(nameX509); + issuerNames.add(name); + } + + /** + * Adds a name to the issuerNames criterion. The issuer distinguished name + * in the <code>X509CRL</code> must match at least one of the specified + * distinguished names.<br /> + * <br /> + * This method allows the caller to add a name to the set of issuer names + * which <code>X509CRLs</code> may contain. The specified name is added to + * any previous value for the issuerNames criterion. If the specified name + * is a duplicate, it may be ignored. If a name is specified as a byte + * array, it should contain a single DER encoded distinguished name, as + * defined in X.501. The ASN.1 notation for this structure is as follows.<br /> + * <br /> + * The name is provided as a byte array. This byte array should contain a + * single DER encoded distinguished name, as defined in X.501. The ASN.1 + * notation for this structure appears in the documentation for + * {@link #setIssuerNames setIssuerNames(Collection names)}.<br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for parsing the + * name, {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object} and + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence} + * + * @param name + * a byte array containing the name in ASN.1 DER encoded form + * + * @exception IOException + * if a parsing error occurs + */ + public void addIssuerName(byte[] name) throws IOException + { + if (issuerNames == null) + { + issuerNames = new HashSet(); + issuerNamesX509 = new HashSet(); + } + + ByteArrayInputStream inStream = new ByteArrayInputStream(name); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object obj = derInStream.readObject(); + if (obj instanceof ASN1Sequence) + { + issuerNamesX509.add(new X509Name((ASN1Sequence)obj)); + } + else + { + throw new IOException("parsing error"); + } + issuerNames.add(name.clone()); + } + + /** + * Sets the minCRLNumber criterion. The <code>X509CRL</code> must have a + * CRL number extension whose value is greater than or equal to the + * specified value. If <code>null</code>, no minCRLNumber check will be + * done. + * + * @param minCRL + * the minimum CRL number accepted (or <code>null</code>) + */ + public void setMinCRLNumber(BigInteger minCRL) + { + this.minCRL = minCRL; + } + + /** + * Sets the maxCRLNumber criterion. The <code>X509CRL</code> must have a + * CRL number extension whose value is less than or equal to the specified + * value. If <code>null</code>, no maxCRLNumber check will be done. + * + * @param maxCRL + * the maximum CRL number accepted (or <code>null</code>) + */ + public void setMaxCRLNumber(BigInteger maxCRL) + { + this.maxCRL = maxCRL; + } + + /** + * Sets the dateAndTime criterion. The specified date must be equal to or + * later than the value of the thisUpdate component of the + * <code>X509CRL</code> and earlier than the value of the nextUpdate + * component. There is no match if the <code>X509CRL</code> does not + * contain a nextUpdate component. If <code>null</code>, no dateAndTime + * check will be done.<br /> + * <br /> + * Note that the <code>Date</code> supplied here is cloned to protect + * against subsequent modifications. + * + * @param dateAndTime + * the <code>Date</code> to match against (or <code>null</code>) + * + * @see #getDateAndTime + */ + public void setDateAndTime(Date dateAndTime) + { + if (dateAndTime == null) + { + this.dateAndTime = null; + } + else + { + this.dateAndTime = new Date(dateAndTime.getTime()); + } + } + + /** + * Sets the certificate being checked. This is not a criterion. Rather, it + * is optional information that may help a <code>CertStore</code> find + * CRLs that would be relevant when checking revocation for the specified + * certificate. If <code>null</code> is specified, then no such optional + * information is provided. + * + * @param cert + * the <code>X509Certificate</code> being checked (or + * <code>null</code>) + * + * @see #getCertificateChecking + */ + public void setCertificateChecking(X509Certificate cert) + { + certChecking = cert; + } + + /** + * Returns a copy of the issuerNames criterion. The issuer distinguished + * name in the <code>X509CRL</code> must match at least one of the + * specified distinguished names. If the value returned is <code>null</code>, + * any issuer distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a + * <code>Collection</code> of names. Each name is a <code>String</code> + * or a byte array representing a distinguished name (in RFC 2253 or ASN.1 + * DER encoded form, respectively). Note that the <code>Collection</code> + * returned may contain duplicate names.<br /> + * <br /> + * If a name is specified as a byte array, it should contain a single DER + * encoded distinguished name, as defined in X.501. The ASN.1 notation for + * this structure is given in the documentation for + * {@link #setIssuerNames setIssuerNames(Collection names)}.<br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @return a <code>Collection</code> of names (or <code>null</code>) + * @see #setIssuerNames + */ + public Collection getIssuerNames() + { + if (issuerNames == null) + { + return null; + } + + Collection set = new HashSet(); + Iterator iter = issuerNames.iterator(); + Object item; + while (iter.hasNext()) + { + item = iter.next(); + if (item instanceof String) + { + set.add(new String((String)item)); + } + else if (item instanceof byte[]) + { + set.add(((byte[])item).clone()); + } + } + return set; + } + + /** + * Returns the minCRLNumber criterion. The <code>X509CRL</code> must have + * a CRL number extension whose value is greater than or equal to the + * specified value. If <code>null</code>, no minCRLNumber check will be + * done. + * + * @return the minimum CRL number accepted (or <code>null</code>) + */ + public BigInteger getMinCRL() + { + return minCRL; + } + + /** + * Returns the maxCRLNumber criterion. The <code>X509CRL</code> must have + * a CRL number extension whose value is less than or equal to the specified + * value. If <code>null</code>, no maxCRLNumber check will be done. + * + * @return the maximum CRL number accepted (or <code>null</code>) + */ + public BigInteger getMaxCRL() + { + return maxCRL; + } + + /** + * Returns the dateAndTime criterion. The specified date must be equal to or + * later than the value of the thisUpdate component of the + * <code>X509CRL</code> and earlier than the value of the nextUpdate + * component. There is no match if the <code>X509CRL</code> does not + * contain a nextUpdate component. If <code>null</code>, no dateAndTime + * check will be done.<br /> + * <br /> + * Note that the <code>Date</code> returned is cloned to protect against + * subsequent modifications. + * + * @return the <code>Date</code> to match against (or <code>null</code>) + * + * @see #setDateAndTime + */ + public Date getDateAndTime() + { + if (dateAndTime == null) + { + return null; + } + + return new Date(dateAndTime.getTime()); + } + + /** + * Returns the certificate being checked. This is not a criterion. Rather, + * it is optional information that may help a <code>CertStore</code> find + * CRLs that would be relevant when checking revocation for the specified + * certificate. If the value returned is <code>null</code>, then no such + * optional information is provided. + * + * @return the certificate being checked (or <code>null</code>) + * + * @see #setCertificateChecking + */ + public X509Certificate getCertificateChecking() + { + return certChecking; + } + + /** + * Returns a printable representation of the <code>X509CRLSelector</code>.<br /> + * <br /> + * Uses + * {@link org.bouncycastle.asn1.x509.X509Name#toString X509Name.toString} to + * format the output + * + * @return a <code>String</code> describing the contents of the + * <code>X509CRLSelector</code>. + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append("X509CRLSelector: [\n"); + if (issuerNamesX509 != null) + { + s.append(" IssuerNames:\n"); + Iterator iter = issuerNamesX509.iterator(); + while (iter.hasNext()) + { + s.append(" ").append(iter.next()).append('\n'); + } + } + if (minCRL != null) + { + s.append(" minCRLNumber: ").append(minCRL).append('\n'); + } + if (maxCRL != null) + { + s.append(" maxCRLNumber: ").append(maxCRL).append('\n'); + } + if (dateAndTime != null) + { + s.append(" dateAndTime: ").append(dateAndTime).append('\n'); + } + if (certChecking != null) + { + s.append(" Certificate being checked: ").append(certChecking).append('\n'); + } + s.append(']'); + return s.toString(); + } + + /** + * Decides whether a <code>CRL</code> should be selected.<br /> + * <br /> + * Uses + * {@link org.bouncycastle.asn1.x509.X509Name#toString X509Name.toString} to + * parse and to compare the crl parameter issuer and + * {@link org.bouncycastle.asn1.x509.X509Extensions#CRLNumber CRLNumber} to + * access the CRL number extension. + * + * @param crl + * the <code>CRL</code> to be checked + * + * @return <code>true</code> if the <code>CRL</code> should be selected, + * <code>false</code> otherwise + */ + public boolean match(CRL crl) + { + if (!(crl instanceof X509CRL)) + { + return false; + } + + X509CRL crlX509 = (X509CRL)crl; + boolean test; + + if (issuerNamesX509 != null) + { + Iterator iter = issuerNamesX509.iterator(); + test = false; + X509Name crlIssuer = null; + try + { + crlIssuer = PrincipalUtil.getIssuerX509Principal(crlX509); + } + catch (Exception ex) + { + + return false; + } + + while (iter.hasNext()) + { + if (crlIssuer.equals(iter.next(), true)) + { + test = true; + break; + } + } + if (!test) + { + return false; + } + } + + byte[] data = crlX509.getExtensionValue(X509Extensions.CRLNumber + .getId()); + if (data != null) + { + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + BigInteger crlNumber = ((DERInteger)derInputStream.readObject()) + .getPositiveValue(); + if (minCRL != null && minCRL.compareTo(crlNumber) > 0) + { + return false; + } + if (maxCRL != null && maxCRL.compareTo(crlNumber) < 0) + { + return false; + } + } + catch (IOException ex) + { + return false; + } + } + else if (minCRL != null || maxCRL != null) + { + return false; + } + + if (dateAndTime != null) + { + Date check = crlX509.getThisUpdate(); + if (check == null) + { + return false; + } + else if (dateAndTime.before(check)) + { + return false; + } + + check = crlX509.getNextUpdate(); + if (check == null) + { + return false; + } + else if (!dateAndTime.before(check)) + { + return false; + } + } + + return true; + } + + /** + * Returns a copy of this object. + * + * @return the copy + */ + public Object clone() + { + try + { + X509CRLSelector copy = (X509CRLSelector)super.clone(); + if (issuerNames != null) + { + copy.issuerNames = new HashSet(); + Iterator iter = issuerNames.iterator(); + Object obj; + while (iter.hasNext()) + { + obj = iter.next(); + if (obj instanceof byte[]) + { + copy.issuerNames.add(((byte[])obj).clone()); + } + else + { + copy.issuerNames.add(obj); + } + } + copy.issuerNamesX509 = new HashSet(issuerNamesX509); + } + return copy; + } + catch (CloneNotSupportedException e) + { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } + + /** + * Decides whether a <code>CRL</code> should be selected. + * + * @param crl + * the <code>CRL</code> to be checked + * + * @return <code>true</code> if the <code>CRL</code> should be selected, + * <code>false</code> otherwise + */ + public boolean equals(Object obj) + { + if (!(obj instanceof X509CRLSelector)) + { + return false; + } + + X509CRLSelector equalsCRL = (X509CRLSelector)obj; + + if (!equals(dateAndTime, equalsCRL.dateAndTime)) + { + return false; + } + + if (!equals(minCRL, equalsCRL.minCRL)) + { + return false; + } + + if (!equals(maxCRL, equalsCRL.maxCRL)) + { + return false; + } + + if (!equals(issuerNamesX509, equalsCRL.issuerNamesX509)) + { + return false; + } + + if (!equals(certChecking, equalsCRL.certChecking)) + { + return false; + } + + return true; + } + + /** + * Return <code>true</code> if two Objects are unequal. + * This means that one is <code>null</code> and the other is + * not or <code>obj1.equals(obj2)</code> returns + * <code>false</code>. + **/ + private boolean equals(Object obj1, Object obj2) + { + if (obj1 == null) + { + if (obj2 != null) + { + return true; + } + } + else if (!obj1.equals(obj2)) + { + return true; + } + return false; + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/X509CertSelector.java b/core/src/main/jdk1.1/java/security/cert/X509CertSelector.java new file mode 100644 index 00000000..d5c783a6 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/X509CertSelector.java @@ -0,0 +1,2461 @@ +package java.security.cert; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DEROutputStream; +import org.bouncycastle.asn1.util.ASN1Dump; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.ExtendedKeyUsage; +import org.bouncycastle.asn1.x509.KeyPurposeId; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.asn1.x509.X509Name; +import org.bouncycastle.jce.PrincipalUtil; +import org.bouncycastle.util.Integers; + +/** + * A <code>CertSelector</code> that selects + * <code>X509Certificates that match all + * specified criteria. This class is particularly useful when + * selecting certificates from a CertStore to build a PKIX-compliant + * certification path.<br /> + * <br /> + * When first constructed, an <code>X509CertSelector</code> has no criteria enabled + * and each of the get methods return a default value (<code>null</code>, or -1 for + * the {@link #getBasicConstraints} method). Therefore, the {@link #match} method would + * return true for any <code>X509Certificate</code>. Typically, several criteria + * are enabled (by calling {@link #setIssuer} or {@link #setKeyUsage}, for instance) and + * then the <code>X509CertSelector</code> is passed to {@link CertStore#getCertificates} or + * some similar method.<br /> + * <br /> + * Several criteria can be enabled (by calling {@link #setIssuer} and + * {@link #setSerialNumber}, for example) such that the match method usually + * uniquely matches a single <code>X509Certificate</code>. We say usually, since it + * is possible for two issuing CAs to have the same distinguished name + * and each issue a certificate with the same serial number. Other + * unique combinations include the issuer, subject, + * subjectKeyIdentifier and/or the subjectPublicKey criteria.<br /> + * <br /> + * Please refer to RFC 2459 for definitions of the X.509 certificate + * extensions mentioned below.<br /> + * <br /> + * <b>Concurrent Access</b><br /> + * <br /> + * Unless otherwise specified, the methods defined in this class are + * not thread-safe. Multiple threads that need to access a single + * object concurrently should synchronize amongst themselves and + * provide the necessary locking. Multiple threads each manipulating + * separate objects need not synchronize.<br /> + * <br /> + * <b>TODO: implement name constraints</b> + * <b>TODO: implement match check for path to names</b><br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.bouncycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object}, + * {@link org.bouncycastle.asn1.OIDTokenizer OIDTokenizer}, + * {@link org.bouncycastle.asn1.x509.X509Name X509Name}, + * {@link org.bouncycastle.asn1.x509.X509Extensions X509Extensions}, + * {@link org.bouncycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage}, + * {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId}, + * {@link org.bouncycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo}, + * {@link org.bouncycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier} + */ +public class X509CertSelector implements CertSelector +{ + private static final Hashtable keyPurposeIdMap = new Hashtable(); + static + { + keyPurposeIdMap.put(KeyPurposeId.id_kp_serverAuth.getId(), + KeyPurposeId.id_kp_serverAuth); + keyPurposeIdMap.put(KeyPurposeId.id_kp_clientAuth.getId(), + KeyPurposeId.id_kp_clientAuth); + keyPurposeIdMap.put(KeyPurposeId.id_kp_codeSigning.getId(), + KeyPurposeId.id_kp_codeSigning); + keyPurposeIdMap.put(KeyPurposeId.id_kp_emailProtection.getId(), + KeyPurposeId.id_kp_emailProtection); + keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecEndSystem.getId(), + KeyPurposeId.id_kp_ipsecEndSystem); + keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecTunnel.getId(), + KeyPurposeId.id_kp_ipsecTunnel); + keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecUser.getId(), + KeyPurposeId.id_kp_ipsecUser); + keyPurposeIdMap.put(KeyPurposeId.id_kp_timeStamping.getId(), + KeyPurposeId.id_kp_timeStamping); + } + + private X509Certificate x509Cert = null; + + private BigInteger serialNumber = null; + + private Object issuerDN = null; + + private X509Name issuerDNX509 = null; + + private Object subjectDN = null; + + private X509Name subjectDNX509 = null; + + private byte[] subjectKeyID = null; + + private byte[] authorityKeyID = null; + + private Date certValid = null; + + private Date privateKeyValid = null; + + private ASN1ObjectIdentifier subjectKeyAlgID = null; + + private PublicKey subjectPublicKey = null; + + private byte[] subjectPublicKeyByte = null; + + private boolean[] keyUsage = null; + + private Set keyPurposeSet = null; + + private boolean matchAllSubjectAltNames = true; + + private Set subjectAltNames = null; + + private Set subjectAltNamesByte = null; + + private int minMaxPathLen = -1; + + private Set policy = null; + + private Set policyOID = null; + + private Set pathToNames = null; + + private Set pathToNamesByte = null; + + /** + * Creates an <code>X509CertSelector</code>. Initially, no criteria are + * set so any <code>X509Certificate</code> will match. + */ + public X509CertSelector() + { + } + + /** + * Sets the certificateEquals criterion. The specified + * <code>X509Certificate</code> must be equal to the + * <code>X509Certificate</code> passed to the match method. If + * <code>null</code>, then this check is not applied.<br /> + * <br /> + * This method is particularly useful when it is necessary to match a single + * certificate. Although other criteria can be specified in conjunction with + * the certificateEquals criterion, it is usually not practical or + * necessary. + * + * @param cert + * the X509Certificate to match (or <code>null</code>) + * + * @see #getCertificate() + */ + public void setCertificate(X509Certificate cert) + { + x509Cert = cert; + } + + /** + * Sets the serialNumber criterion. The specified serial number must match + * the certificate serial number in the <code>X509Certificate</code>. If + * <code>null</code>, any certificate serial number will do. + * + * @param serial + * the certificate serial number to match (or <code>null</code>) + * + * @see #getSerialNumber() + */ + public void setSerialNumber(BigInteger serial) + { + serialNumber = serial; + } + + /** + * Sets the issuer criterion. The specified distinguished name must match + * the issuer distinguished name in the <code>X509Certificate</code>. If + * <code>null</code>, any issuer distinguished name will do.<br /> + * <br /> + * If <code>issuerDN</code> is not <code>null</code>, it should contain + * a distinguished name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for parsing the + * issuerDN. + * + * @param issuerDN + * a distinguished name in RFC 2253 format (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs (incorrect form for DN) + */ + public void setIssuer(String issuerDN) throws IOException + { + if (issuerDN == null) + { + this.issuerDN = null; + this.issuerDNX509 = null; + } + else + { + X509Name nameX509; + try + { + nameX509 = new X509Name(issuerDN); + } + catch (IllegalArgumentException ex) + { + throw new IOException(ex.getMessage()); + } + this.issuerDNX509 = nameX509; + this.issuerDN = issuerDN; + } + } + + /** + * Sets the issuer criterion. The specified distinguished name must match + * the issuer distinguished name in the <code>X509Certificate</code>. If + * null is specified, the issuer criterion is disabled and any issuer + * distinguished name will do.<br /> + * <br /> + * If <code>issuerDN</code> is not <code>null</code>, it should contain + * a single DER encoded distinguished name, as defined in X.501. The ASN.1 + * notation for this structure is as follows.<br /> + * <br /> + * + * <pre> + * Name ::= CHOICE { + * RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RDN + * + * RDN ::= + * SET SIZE (1 .. MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * .... + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1.. MAX)), + * bmpString BMPString (SIZE (1..MAX)) } + * </pre> + * + * <br /> + * <br /> + * Note that the byte array specified here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object}, + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.bouncycastle.asn1.x509.X509Name X509Name} + * + * @param issuerDN - + * a byte array containing the distinguished name in ASN.1 DER + * encoded form (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs (incorrect form for DN) + */ + public void setIssuer(byte[] issuerDN) throws IOException + { + if (issuerDN == null) + { + this.issuerDN = null; + this.issuerDNX509 = null; + } + else + { + ByteArrayInputStream inStream = new ByteArrayInputStream(issuerDN); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object obj = derInStream.readObject(); + if (obj instanceof ASN1Sequence) + { + this.issuerDNX509 = new X509Name((ASN1Sequence)obj); + } + else + { + throw new IOException("parsing error"); + } + this.issuerDN = (byte[])issuerDN.clone(); + } + } + + /** + * Sets the subject criterion. The specified distinguished name must match + * the subject distinguished name in the <code>X509Certificate</code>. If + * null, any subject distinguished name will do.<br /> + * <br /> + * If <code>subjectDN</code> is not <code>null</code>, it should + * contain a distinguished name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for parsing the + * subjectDN. + * + * @param subjectDN + * a distinguished name in RFC 2253 format (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs (incorrect form for DN) + */ + public void setSubject(String subjectDN) throws IOException + { + if (subjectDN == null) + { + this.subjectDN = null; + this.subjectDNX509 = null; + } + else + { + X509Name nameX509; + try + { + nameX509 = new X509Name(subjectDN); + } + catch (IllegalArgumentException ex) + { + throw new IOException(ex.getMessage()); + } + + this.subjectDNX509 = nameX509; + this.subjectDN = subjectDN; + } + } + + /** + * Sets the subject criterion. The specified distinguished name must match + * the subject distinguished name in the <code>X509Certificate</code>. If + * null, any subject distinguished name will do.<br /> + * <br /> + * If <code>subjectDN</code> is not <code>null</code>, it should + * contain a single DER encoded distinguished name, as defined in X.501. For + * the ASN.1 notation for this structure, see + * {@link #setIssuer(byte []) setIssuer(byte [] issuerDN)}.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object}, + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.bouncycastle.asn1.x509.X509Name X509Name} + * + * @param subjectDN + * a byte array containing the distinguished name in ASN.1 DER + * format (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs (incorrect form for DN) + */ + public void setSubject(byte[] subjectDN) throws IOException + { + if (subjectDN == null) + { + this.subjectDN = null; + this.subjectDNX509 = null; + } + else + { + ByteArrayInputStream inStream = new ByteArrayInputStream(subjectDN); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object obj = derInStream.readObject(); + + if (obj instanceof ASN1Sequence) + { + this.subjectDNX509 = new X509Name((ASN1Sequence)obj); + } + else + { + throw new IOException("parsing error"); + } + this.subjectDN = (byte[])subjectDN.clone(); + } + } + + /** + * Sets the subjectKeyIdentifier criterion. The <code>X509Certificate</code> + * must contain a SubjectKeyIdentifier extension for which the contents of + * the extension matches the specified criterion value. If the criterion + * value is null, no subjectKeyIdentifier check will be done.<br /> + * <br /> + * If <code>subjectKeyID</code> is not <code>null</code>, it should + * contain a single DER encoded value corresponding to the contents of the + * extension value (not including the object identifier, criticality + * setting, and encapsulating OCTET STRING) for a SubjectKeyIdentifier + * extension. The ASN.1 notation for this structure follows.<br /> + * <br /> + * + * <pre> + * SubjectKeyIdentifier ::= KeyIdentifier + * + * KeyIdentifier ::= OCTET STRING + * </pre> + * + * <br /> + * <br /> + * Since the format of subject key identifiers is not mandated by any + * standard, subject key identifiers are not parsed by the + * <code>X509CertSelector</code>. Instead, the values are compared using + * a byte-by-byte comparison.<br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications. + * + * @param subjectKeyID - + * the subject key identifier (or <code>null</code>) + * + * @see #getSubjectKeyIdentifier() + */ + public void setSubjectKeyIdentifier(byte[] subjectKeyID) + { + if (subjectKeyID == null) + { + this.subjectKeyID = null; + } + else + { + this.subjectKeyID = (byte[])subjectKeyID.clone(); + } + } + + /** + * Sets the authorityKeyIdentifier criterion. The + * <code>X509Certificate</code> must contain an AuthorityKeyIdentifier + * extension for which the contents of the extension value matches the + * specified criterion value. If the criterion value is <code>null</code>, + * no authorityKeyIdentifier check will be done.<br /> + * <br /> + * If <code>authorityKeyID</code> is not <code>null</code>, it should + * contain a single DER encoded value corresponding to the contents of the + * extension value (not including the object identifier, criticality + * setting, and encapsulating OCTET STRING) for an AuthorityKeyIdentifier + * extension. The ASN.1 notation for this structure follows.<br /> + * <br /> + * + * <pre> + * AuthorityKeyIdentifier ::= SEQUENCE { + * keyIdentifier [0] KeyIdentifier OPTIONAL, + * authorityCertIssuer [1] GeneralNames OPTIONAL, + * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + * + * KeyIdentifier ::= OCTET STRING + * </pre> + * + * <br /> + * <br /> + * Authority key identifiers are not parsed by the + * <code>X509CertSelector</code>. Instead, the values are compared using + * a byte-by-byte comparison.<br /> + * <br /> + * When the <code>keyIdentifier</code> field of + * <code>AuthorityKeyIdentifier</code> is populated, the value is usually + * taken from the SubjectKeyIdentifier extension in the issuer's + * certificate. Note, however, that the result of + * X509Certificate.getExtensionValue(<SubjectKeyIdentifier Object + * Identifier>) on the issuer's certificate may NOT be used directly as the + * input to setAuthorityKeyIdentifier. This is because the + * SubjectKeyIdentifier contains only a KeyIdentifier OCTET STRING, and not + * a SEQUENCE of KeyIdentifier, GeneralNames, and CertificateSerialNumber. + * In order to use the extension value of the issuer certificate's + * SubjectKeyIdentifier extension, it will be necessary to extract the value + * of the embedded KeyIdentifier OCTET STRING, then DER encode this OCTET + * STRING inside a SEQUENCE. For more details on SubjectKeyIdentifier, see + * {@link #setSubjectKeyIdentifier(byte[]) setSubjectKeyIdentifier(byte[] subjectKeyID }).<br /> + * <br /> + * Note also that the byte array supplied here is cloned to protect against + * subsequent modifications. + * + * @param authorityKeyID + * the authority key identifier (or <code>null</code>) + * + * @see #getAuthorityKeyIdentifier() + */ + public void setAuthorityKeyIdentifier(byte[] authorityKeyID) + { + if (authorityKeyID == null) + { + this.authorityKeyID = null; + } + else + { + this.authorityKeyID = (byte[])authorityKeyID.clone(); + } + } + + /** + * Sets the certificateValid criterion. The specified date must fall within + * the certificate validity period for the X509Certificate. If + * <code>null</code>, no certificateValid check will be done.<br /> + * <br /> + * Note that the Date supplied here is cloned to protect against subsequent + * modifications. + * + * @param certValid + * the Date to check (or <code>null</code>) + * + * @see #getCertificateValid() + */ + public void setCertificateValid(Date certValid) + { + if (certValid == null) + { + this.certValid = null; + } + else + { + this.certValid = new Date(certValid.getTime()); + } + } + + /** + * Sets the privateKeyValid criterion. The specified date must fall within + * the private key validity period for the X509Certificate. If + * <code>null</code>, no privateKeyValid check will be done.<br /> + * <br /> + * Note that the Date supplied here is cloned to protect against subsequent + * modifications. + * + * @param privateKeyValid + * the Date to check (or <code>null</code>) + * + * @see #getPrivateKeyValid() + */ + public void setPrivateKeyValid(Date privateKeyValid) + { + if (privateKeyValid == null) + { + this.privateKeyValid = null; + } + else + { + this.privateKeyValid = new Date(privateKeyValid.getTime()); + } + } + + /** + * Sets the subjectPublicKeyAlgID criterion. The X509Certificate must + * contain a subject public key with the specified algorithm. If + * <code>null</code>, no subjectPublicKeyAlgID check will be done. + * + * @param oid + * The object identifier (OID) of the algorithm to check for (or + * <code>null</code>). An OID is represented by a set of + * nonnegative integers separated by periods. + * + * @exception IOException + * if the OID is invalid, such as the first component being + * not 0, 1 or 2 or the second component being greater than + * 39. + * + * @see #getSubjectPublicKeyAlgID() + */ + public void setSubjectPublicKeyAlgID(String oid) throws IOException + { + CertUtil.parseOID(oid); + subjectKeyAlgID = new ASN1ObjectIdentifier(oid); + } + + /** + * Sets the subjectPublicKey criterion. The X509Certificate must contain the + * specified subject public key. If null, no subjectPublicKey check will be + * done. + * + * @param key + * the subject public key to check for (or null) + * + * @see #getSubjectPublicKey() + */ + public void setSubjectPublicKey(PublicKey key) + { + if (key == null) + { + subjectPublicKey = null; + subjectPublicKeyByte = null; + } + else + { + subjectPublicKey = key; + subjectPublicKeyByte = key.getEncoded(); + } + } + + /** + * Sets the subjectPublicKey criterion. The <code>X509Certificate</code> + * must contain the specified subject public key. If <code>null</code>, + * no subjectPublicKey check will be done.<br /> + * <br /> + * Because this method allows the public key to be specified as a byte + * array, it may be used for unknown key types.<br /> + * <br /> + * If key is not <code>null</code>, it should contain a single DER + * encoded SubjectPublicKeyInfo structure, as defined in X.509. The ASN.1 + * notation for this structure is as follows.<br /> + * <br /> + * + * <pre> + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * -- contains a value of the type + * -- registered for use with the + * -- algorithm object identifier value + * </pre> + * + * <br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications. + * + * @param key + * a byte array containing the subject public key in ASN.1 DER + * form (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs (incorrect form for subject + * public key) + * + * @see #getSubjectPublicKey() + */ + public void setSubjectPublicKey(byte[] key) throws IOException + { + if (key == null) + { + subjectPublicKey = null; + subjectPublicKeyByte = null; + } + else + { + subjectPublicKey = null; + subjectPublicKeyByte = (byte[])key.clone(); + // TODO + // try to generyte PublicKey Object from subjectPublicKeyByte + } + } + + /** + * Sets the keyUsage criterion. The X509Certificate must allow the specified + * keyUsage values. If null, no keyUsage check will be done. Note that an + * X509Certificate that has no keyUsage extension implicitly allows all + * keyUsage values.<br /> + * <br /> + * Note that the boolean array supplied here is cloned to protect against + * subsequent modifications. + * + * @param keyUsage + * a boolean array in the same format as the boolean array + * returned by X509Certificate.getKeyUsage(). Or + * <code>null</code>. + * + * @see #getKeyUsage() + */ + public void setKeyUsage(boolean[] keyUsage) + { + if (keyUsage == null) + { + this.keyUsage = null; + } + else + { + this.keyUsage = (boolean[])keyUsage.clone(); + } + } + + /** + * Sets the extendedKeyUsage criterion. The <code>X509Certificate</code> + * must allow the specified key purposes in its extended key usage + * extension. If <code>keyPurposeSet</code> is empty or <code>null</code>, + * no extendedKeyUsage check will be done. Note that an + * <code>X509Certificate</code> that has no extendedKeyUsage extension + * implicitly allows all key purposes.<br /> + * <br /> + * Note that the Set is cloned to protect against subsequent modifications.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId} + * + * @param keyPurposeSet + * a <code>Set</code> of key purpose OIDs in string format (or + * <code>null</code>). Each OID is represented by a set of + * nonnegative integers separated by periods. + * + * @exception IOException + * if the OID is invalid, such as the first component being + * not 0, 1 or 2 or the second component being greater than + * 39. + * + * @see #getExtendedKeyUsage() + */ + public void setExtendedKeyUsage(Set keyPurposeSet) throws IOException + { + if (keyPurposeSet == null || keyPurposeSet.isEmpty()) + { + this.keyPurposeSet = keyPurposeSet; + } + else + { + this.keyPurposeSet = new HashSet(); + Iterator iter = keyPurposeSet.iterator(); + Object obj; + KeyPurposeId purposeID; + while (iter.hasNext()) + { + obj = iter.next(); + if (obj instanceof String) + { + purposeID = (KeyPurposeId)keyPurposeIdMap.get((String)obj); + if (purposeID == null) + { + throw new IOException("unknown purposeID " + + (String)obj); + } + this.keyPurposeSet.add(purposeID); + } + } + } + } + + /** + * Enables/disables matching all of the subjectAlternativeNames specified in + * the {@link #setSubjectAlternativeNames setSubjectAlternativeNames} or + * {@link #addSubjectAlternativeName addSubjectAlternativeName} methods. If + * enabled, the <code>X509Certificate</code> must contain all of the + * specified subject alternative names. If disabled, the X509Certificate + * must contain at least one of the specified subject alternative names.<br /> + * <br /> + * The matchAllNames flag is <code>true</code> by default. + * + * @param matchAllNames + * if <code>true</code>, the flag is enabled; if + * <code>false</code>, the flag is disabled. + * + * @see #getMatchAllSubjectAltNames() + */ + public void setMatchAllSubjectAltNames(boolean matchAllNames) + { + matchAllSubjectAltNames = matchAllNames; + } + + /** + * Sets the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br /> + * <br /> + * This method allows the caller to specify, with a single method call, the + * complete set of subject alternative names for the subjectAlternativeNames + * criterion. The specified value replaces the previous value for the + * subjectAlternativeNames criterion.<br /> + * <br /> + * The <code>names</code> parameter (if not <code>null</code>) is a + * <code>Collection</code> with one entry for each name to be included in + * the subject alternative name criterion. Each entry is a <code>List</code> + * whose first entry is an <code>Integer</code> (the name type, 0-8) and + * whose second entry is a <code>String</code> or a byte array (the name, + * in string or ASN.1 DER encoded form, respectively). There can be multiple + * names of the same type. If <code>null</code> is supplied as the value + * for this argument, no subjectAlternativeNames check will be performed.<br /> + * <br /> + * Each subject alternative name in the <code>Collection</code> may be + * specified either as a <code>String</code> or as an ASN.1 encoded byte + * array. For more details about the formats used, see + * {@link #addSubjectAlternativeName(int, String) addSubjectAlternativeName(int type, String name)} + * and + * {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name}).<br /> + * <br /> + * Note that the <code>names</code> parameter can contain duplicate names + * (same name and name type), but they may be removed from the + * <code>Collection</code> of names returned by the + * {@link #getSubjectAlternativeNames} method.<br /> + * <br /> + * Note that a deep copy is performed on the Collection to protect against + * subsequent modifications. + * + * @param names - + * a Collection of names (or null) + * + * @exception IOException + * if a parsing error occurs + * + * @see #getSubjectAlternativeNames() + */ + public void setSubjectAlternativeNames(Collection names) throws IOException + { + try + { + if (names == null || names.isEmpty()) + { + subjectAltNames = null; + subjectAltNamesByte = null; + } + else + { + subjectAltNames = new HashSet(); + subjectAltNamesByte = new HashSet(); + Iterator iter = names.iterator(); + List item; + int type; + Object data; + while (iter.hasNext()) + { + item = (List)iter.next(); + type = ((Integer)item.get(0)).intValue(); + data = item.get(1); + if (data instanceof String) + { + addSubjectAlternativeName(type, (String)data); + } + else if (data instanceof byte[]) + { + addSubjectAlternativeName(type, (byte[])data); + } + else + { + throw new IOException( + "parsing error: unknown data type"); + } + } + } + } + catch (Exception ex) + { + throw new IOException("parsing exception:\n" + ex.toString()); + } + } + + /** + * Adds a name to the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br /> + * <br /> + * This method allows the caller to add a name to the set of subject + * alternative names. The specified name is added to any previous value for + * the subjectAlternativeNames criterion. If the specified name is a + * duplicate, it may be ignored.<br /> + * <br /> + * The name is provided in string format. RFC 822, DNS, and URI names use + * the well-established string formats for those types (subject to the + * restrictions included in RFC 2459). IPv4 address names are supplied using + * dotted quad notation. OID address names are represented as a series of + * nonnegative integers separated by periods. And directory names + * (distinguished names) are supplied in RFC 2253 format. No standard string + * format is defined for otherNames, X.400 names, EDI party names, IPv6 + * address names, or any other type of names. They should be specified using + * the + * {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name)} + * method. + * + * @param type + * the name type (0-8, as specified in RFC 2459, section 4.2.1.7) + * @param name - + * the name in string form (not null) + * + * @exception IOException + * if a parsing error occurs + */ + public void addSubjectAlternativeName(int type, String name) + throws IOException + { + // TODO full implementation of CertUtil.parseGeneralName + byte[] encoded = CertUtil.parseGeneralName(type, name); + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name); + subjectAltNames.add(tmpList); + tmpList.set(1, encoded); + subjectAltNamesByte.add(tmpList); + } + + /** + * Adds a name to the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br /> + * <br /> + * This method allows the caller to add a name to the set of subject + * alternative names. The specified name is added to any previous value for + * the subjectAlternativeNames criterion. If the specified name is a + * duplicate, it may be ignored.<br /> + * <br /> + * The name is provided as a byte array. This byte array should contain the + * DER encoded name, as it would appear in the GeneralName structure defined + * in RFC 2459 and X.509. The encoded byte array should only contain the + * encoded value of the name, and should not include the tag associated with + * the name in the GeneralName structure. The ASN.1 definition of this + * structure appears below.<br /> + * <br /> + * + * <pre> + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * </pre> + * + * <br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: check encoded format</b> + * + * @param type + * the name type (0-8, as listed above) + * @param name + * a byte array containing the name in ASN.1 DER encoded form + * + * @exception IOException + * if a parsing error occurs + */ + public void addSubjectAlternativeName(int type, byte[] name) + throws IOException + { + // TODO check encoded format + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name.clone()); + subjectAltNames.add(tmpList); + subjectAltNamesByte.add(tmpList); + } + + /** + * Sets the name constraints criterion. The <code>X509Certificate</code> + * must have subject and subject alternative names that meet the specified + * name constraints.<br /> + * <br /> + * The name constraints are specified as a byte array. This byte array + * should contain the DER encoded form of the name constraints, as they + * would appear in the NameConstraints structure defined in RFC 2459 and + * X.509. The ASN.1 definition of this structure appears below.<br /> + * <br /> + * + * <pre> + * NameConstraints ::= SEQUENCE { + * permittedSubtrees [0] GeneralSubtrees OPTIONAL, + * excludedSubtrees [1] GeneralSubtrees OPTIONAL } + * + * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + * + * GeneralSubtree ::= SEQUENCE { + * base GeneralName, + * minimum [0] BaseDistance DEFAULT 0, + * maximum [1] BaseDistance OPTIONAL } + * + * BaseDistance ::= INTEGER (0..MAX) + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER} + * </pre> + * + * <br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: implement this</b> + * + * @param bytes + * a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension to be used for checking name + * constraints. Only the value of the extension is included, not + * the OID or criticality flag. Can be <code>null</code>, in + * which case no name constraints check will be performed + * + * @exception IOException + * if a parsing error occurs + * @exception UnsupportedOperationException + * because this method is not supported + * @see #getNameConstraints() + */ + public void setNameConstraints(byte[] bytes) throws IOException + { + throw new UnsupportedOperationException(); + } + + /** + * Sets the basic constraints constraint. If the value is greater than or + * equal to zero, <code>X509Certificates</code> must include a + * basicConstraints extension with a pathLen of at least this value. If the + * value is -2, only end-entity certificates are accepted. If the value is + * -1, no check is done.<br /> + * <br /> + * This constraint is useful when building a certification path forward + * (from the target toward the trust anchor. If a partial path has been + * built, any candidate certificate must have a maxPathLen value greater + * than or equal to the number of certificates in the partial path. + * + * @param minMaxPathLen + * the value for the basic constraints constraint + * + * @exception IllegalArgumentException + * if the value is less than -2 + * + * @see #getBasicConstraints() + */ + public void setBasicConstraints(int minMaxPathLen) + { + if (minMaxPathLen < -2) + { + throw new IllegalArgumentException("minMaxPathLen must be >= -2"); + } + + this.minMaxPathLen = minMaxPathLen; + } + + /** + * Sets the policy constraint. The X509Certificate must include at least one + * of the specified policies in its certificate policies extension. If + * certPolicySet is empty, then the X509Certificate must include at least + * some specified policy in its certificate policies extension. If + * certPolicySet is null, no policy check will be performed.<br /> + * <br /> + * Note that the Set is cloned to protect against subsequent modifications.<br /> + * <br /> + * <b>TODO: implement match check for this</b> + * + * @param certPolicySet + * a Set of certificate policy OIDs in string format (or null). + * Each OID is represented by a set of nonnegative integers + * separated by periods. + * + * @exception IOException + * if a parsing error occurs on the OID such as the first + * component is not 0, 1 or 2 or the second component is + * greater than 39. + * + * @see #getPolicy() + */ + public void setPolicy(Set certPolicySet) throws IOException + { + if (certPolicySet == null) + { + policy = null; + policyOID = null; + } + else + { + policyOID = new HashSet(); + Iterator iter = certPolicySet.iterator(); + Object item; + while (iter.hasNext()) + { + item = iter.next(); + if (item instanceof String) + { + CertUtil.parseOID((String)item); + policyOID.add(new ASN1ObjectIdentifier((String)item)); + } + else + { + throw new IOException( + "certPolicySet contains null values or non String objects"); + } + } + policy = new HashSet(certPolicySet); + } + } + + /** + * Sets the pathToNames criterion. The <code>X509Certificate</code> must + * not include name constraints that would prohibit building a path to the + * specified names.<br /> + * <br /> + * This method allows the caller to specify, with a single method call, the + * complete set of names which the <code>X509Certificates</code>'s name + * constraints must permit. The specified value replaces the previous value + * for the pathToNames criterion.<br /> + * <br /> + * This constraint is useful when building a certification path forward + * (from the target toward the trust anchor. If a partial path has been + * built, any candidate certificate must not include name constraints that + * would prohibit building a path to any of the names in the partial path.<br /> + * <br /> + * The names parameter (if not <code>null</code>) is a + * <code>Collection</code> with one entry for each name to be included in + * the pathToNames criterion. Each entry is a <code>List</code> whose + * first entry is an Integer (the name type, 0-8) and whose second entry is + * a <code>String</code> or a byte array (the name, in string or ASN.1 DER + * encoded form, respectively). There can be multiple names of the same + * type. If <code>null</code> is supplied as the value for this argument, + * no pathToNames check will be performed.<br /> + * <br /> + * Each name in the Collection may be specified either as a String or as an + * ASN.1 encoded byte array. For more details about the formats used, see + * {@link #addPathToName(int, String) addPathToName(int type, String name)} + * and + * {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)}.<br /> + * <br /> + * Note that the names parameter can contain duplicate names (same name and + * name type), but they may be removed from the Collection of names returned + * by the {@link #getPathToNames} method.<br /> + * <br /> + * Note that a deep copy is performed on the Collection to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: implement this match check for this</b> + * + * @param names + * a Collection with one entry per name (or <code>null</code>) + * + * @exception IOException + * if a parsing error occurs + * @exception UnsupportedOperationException + * because this method is not supported + * + * @see #getPathToNames() + */ + public void setPathToNames(Collection names) throws IOException + { + try + { + if (names == null || names.isEmpty()) + { + pathToNames = null; + pathToNamesByte = null; + } + else + { + pathToNames = new HashSet(); + pathToNamesByte = new HashSet(); + Iterator iter = names.iterator(); + List item; + int type; + Object data; + + while (iter.hasNext()) + { + item = (List)iter.next(); + type = ((Integer)item.get(0)).intValue(); + data = item.get(1); + if (data instanceof String) + { + addPathToName(type, (String)data); + } + else if (data instanceof byte[]) + { + addPathToName(type, (byte[])data); + } + else + { + throw new IOException( + "parsing error: unknown data type"); + } + } + } + } + catch (Exception ex) + { + throw new IOException("parsing exception:\n" + ex.toString()); + } + } + + /** + * Adds a name to the pathToNames criterion. The + * <code>X509Certificate</code> must not include name constraints that + * would prohibit building a path to the specified name.<br /> + * <br /> + * This method allows the caller to add a name to the set of names which the + * <code>X509Certificates</code>'s name constraints must permit. The + * specified name is added to any previous value for the pathToNames + * criterion. If the name is a duplicate, it may be ignored.<br /> + * <br /> + * The name is provided in string format. RFC 822, DNS, and URI names use + * the well-established string formats for those types (subject to the + * restrictions included in RFC 2459). IPv4 address names are supplied using + * dotted quad notation. OID address names are represented as a series of + * nonnegative integers separated by periods. And directory names + * (distinguished names) are supplied in RFC 2253 format. No standard string + * format is defined for otherNames, X.400 names, EDI party names, IPv6 + * address names, or any other type of names. They should be specified using + * the + * {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)} + * method.<br /> + * <br /> + * <b>TODO: implement this match check for this</b> + * + * @param type + * the name type (0-8, as specified in RFC 2459, section 4.2.1.7) + * @param name + * the name in string form + * + * @exceptrion IOException if a parsing error occurs + */ + public void addPathToName(int type, String name) throws IOException + { + // TODO full implementation of CertUtil.parseGeneralName + byte[] encoded = CertUtil.parseGeneralName(type, name); + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name); + pathToNames.add(tmpList); + tmpList.set(1, encoded); + pathToNamesByte.add(tmpList); + throw new UnsupportedOperationException(); + } + + /** + * Adds a name to the pathToNames criterion. The + * <code>X509Certificate</code> must not include name constraints that + * would prohibit building a path to the specified name.<br /> + * <br /> + * This method allows the caller to add a name to the set of names which the + * <code>X509Certificates</code>'s name constraints must permit. The + * specified name is added to any previous value for the pathToNames + * criterion. If the name is a duplicate, it may be ignored.<br /> + * <br /> + * The name is provided as a byte array. This byte array should contain the + * DER encoded name, as it would appear in the GeneralName structure defined + * in RFC 2459 and X.509. The ASN.1 definition of this structure appears in + * the documentation for + * {@link #addSubjectAlternativeName(int,byte[]) addSubjectAlternativeName(int type, byte[] name)}.<br /> + * <br /> + * Note that the byte array supplied here is cloned to protect against + * subsequent modifications.<br /> + * <br /> + * <b>TODO: implement this match check for this</b> + * + * @param type + * the name type (0-8, as specified in RFC 2459, section 4.2.1.7) + * @param name + * a byte array containing the name in ASN.1 DER encoded form + * + * @exception IOException + * if a parsing error occurs + */ + public void addPathToName(int type, byte[] name) throws IOException + { + // TODO check encoded format + List tmpList = new ArrayList(); + tmpList.add(Integers.valueOf(type)); + tmpList.add(name.clone()); + pathToNames.add(tmpList); + pathToNamesByte.add(tmpList); + } + + /** + * Returns the certificateEquals criterion. The specified + * <code>X509Certificate</code> must be equal to the + * <code>X509Certificate</code> passed to the match method. If + * <code>null</code>, this check is not applied. + * + * @retrun the <code>X509Certificate</code> to match (or <code>null</code>) + * + * @see #setCertificate(java.security.cert.X509Certificate) + */ + public X509Certificate getCertificate() + { + return x509Cert; + } + + /** + * Returns the serialNumber criterion. The specified serial number must + * match the certificate serial number in the <code>X509Certificate</code>. + * If <code>null</code>, any certificate serial number will do. + * + * @return the certificate serial number to match (or <code>null</code>) + * + * @see #setSerialNumber(java.math.BigInteger) + */ + public BigInteger getSerialNumber() + { + return serialNumber; + } + + /** + * Returns the issuer criterion as a String. This distinguished name must + * match the issuer distinguished name in the <code>X509Certificate</code>. + * If <code>null</code>, the issuer criterion is disabled and any issuer + * distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a distinguished + * name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for formatiing + * byte[] issuerDN to String. + * + * @return the required issuer distinguished name in RFC 2253 format (or + * <code>null</code>) + */ + public String getIssuerAsString() + { + if (issuerDN instanceof String) + { + return new String((String)issuerDN); + } + else if (issuerDNX509 != null) + { + return issuerDNX509.toString(); + } + + return null; + } + + /** + * Returns the issuer criterion as a byte array. This distinguished name + * must match the issuer distinguished name in the + * <code>X509Certificate</code>. If <code>null</code>, the issuer + * criterion is disabled and any issuer distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a byte array + * containing a single DER encoded distinguished name, as defined in X.501. + * The ASN.1 notation for this structure is supplied in the documentation + * for {@link #setIssuer(byte[]) setIssuer(byte [] issuerDN)}.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.bouncycastle.asn1.x509.X509Name X509Name} to gnerate byte[] + * output for String issuerDN. + * + * @return a byte array containing the required issuer distinguished name in + * ASN.1 DER format (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs + */ + public byte[] getIssuerAsBytes() throws IOException + { + if (issuerDN instanceof byte[]) + { + return (byte[])((byte[])issuerDN).clone(); + } + else if (issuerDNX509 != null) + { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + + derOutStream.writeObject(issuerDNX509.toASN1Primitive()); + derOutStream.close(); + + return outStream.toByteArray(); + } + + return null; + } + + /** + * Returns the subject criterion as a String. This distinguished name must + * match the subject distinguished name in the <code>X509Certificate</code>. + * If <code>null</code>, the subject criterion is disabled and any + * subject distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a distinguished + * name, in RFC 2253 format.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name} for formatiing + * byte[] subjectDN to String. + * + * @return the required subject distinguished name in RFC 2253 format (or + * <code>null</code>) + */ + public String getSubjectAsString() + { + if (subjectDN instanceof String) + { + return new String((String)subjectDN); + } + else if (subjectDNX509 != null) + { + return subjectDNX509.toString(); + } + + return null; + } + + /** + * Returns the subject criterion as a byte array. This distinguished name + * must match the subject distinguished name in the + * <code>X509Certificate</code>. If <code>null</code>, the subject + * criterion is disabled and any subject distinguished name will do.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a byte array + * containing a single DER encoded distinguished name, as defined in X.501. + * The ASN.1 notation for this structure is supplied in the documentation + * for {@link #setSubject(byte [] subjectDN) setSubject(byte [] subjectDN)}.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications.<br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream}, + * {@link org.bouncycastle.asn1.x509.X509Name X509Name} to gnerate byte[] + * output for String subjectDN. + * + * @return a byte array containing the required subject distinguished name + * in ASN.1 DER format (or <code>null</code>) + * + * @exception IOException + * if an encoding error occurs + */ + public byte[] getSubjectAsBytes() throws IOException + { + if (subjectDN instanceof byte[]) + { + return (byte[])((byte[])subjectDN).clone(); + } + else if (subjectDNX509 != null) + { + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + DEROutputStream derOutStream = new DEROutputStream(outStream); + + derOutStream.writeObject(subjectDNX509.toASN1Primitive()); + derOutStream.close(); + + return outStream.toByteArray(); + } + + return null; + } + + /** + * Returns the subjectKeyIdentifier criterion. The + * <code>X509Certificate</code> must contain a SubjectKeyIdentifier + * extension with the specified value. If <code>null</code>, no + * subjectKeyIdentifier check will be done.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications. + * + * @return the key identifier (or <code>null</code>) + * + * @see #setSubjectKeyIdentifier + */ + public byte[] getSubjectKeyIdentifier() + { + if (subjectKeyID != null) + { + return (byte[])subjectKeyID.clone(); + } + + return null; + } + + /** + * Returns the authorityKeyIdentifier criterion. The + * <code>X509Certificate</code> must contain a AuthorityKeyIdentifier + * extension with the specified value. If <code>null</code>, no + * authorityKeyIdentifier check will be done.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications. + * + * @return the key identifier (or <code>null</code>) + * + * @see #setAuthorityKeyIdentifier + */ + public byte[] getAuthorityKeyIdentifier() + { + if (authorityKeyID != null) + { + return (byte[])authorityKeyID.clone(); + } + + return null; + } + + /** + * Returns the certificateValid criterion. The specified date must fall + * within the certificate validity period for the + * <code>X509Certificate</code>. If <code>null</code>, no + * certificateValid check will be done.<br /> + * <br /> + * Note that the <code>Date</code> returned is cloned to protect against + * subsequent modifications. + * + * @return the <code>Date</code> to check (or <code>null</code>) + * + * @see #setCertificateValid + */ + public Date getCertificateValid() + { + if (certValid != null) + { + return new Date(certValid.getTime()); + } + + return null; + } + + /** + * Returns the privateKeyValid criterion. The specified date must fall + * within the private key validity period for the + * <code>X509Certificate</code>. If <code>null</code>, no + * privateKeyValid check will be done.<br /> + * <br /> + * Note that the <code>Date</code> returned is cloned to protect against + * subsequent modifications. + * + * @return the <code>Date</code> to check (or <code>null</code>) + * + * @see #setPrivateKeyValid + */ + public Date getPrivateKeyValid() + { + if (privateKeyValid != null) + { + return new Date(privateKeyValid.getTime()); + } + + return null; + } + + /** + * Returns the subjectPublicKeyAlgID criterion. The + * <code>X509Certificate</code> must contain a subject public key with the + * specified algorithm. If <code>null</code>, no subjectPublicKeyAlgID + * check will be done. + * + * @return the object identifier (OID) of the signature algorithm to check + * for (or <code>null</code>). An OID is represented by a set of + * nonnegative integers separated by periods. + * + * @see #setSubjectPublicKeyAlgID + */ + public String getSubjectPublicKeyAlgID() + { + if (subjectKeyAlgID != null) + { + return subjectKeyAlgID.toString(); + } + + return null; + } + + /** + * Returns the subjectPublicKey criterion. The <code>X509Certificate</code> + * must contain the specified subject public key. If <code>null</code>, + * no subjectPublicKey check will be done. + * + * @return the subject public key to check for (or <code>null</code>) + * + * @see #setSubjectPublicKey + */ + public PublicKey getSubjectPublicKey() + { + return subjectPublicKey; + } + + /** + * Returns the keyUsage criterion. The <code>X509Certificate</code> must + * allow the specified keyUsage values. If null, no keyUsage check will be + * done.<br /> + * <br /> + * Note that the boolean array returned is cloned to protect against + * subsequent modifications. + * + * @return a boolean array in the same format as the boolean array returned + * by + * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}. + * Or <code>null</code>. + * + * @see #setKeyUsage + */ + public boolean[] getKeyUsage() + { + if (keyUsage != null) + { + return (boolean[])keyUsage.clone(); + } + + return null; + } + + /** + * Returns the extendedKeyUsage criterion. The <code>X509Certificate</code> + * must allow the specified key purposes in its extended key usage + * extension. If the <code>keyPurposeSet</code> returned is empty or + * <code>null</code>, no extendedKeyUsage check will be done. Note that + * an <code>X509Certificate</code> that has no extendedKeyUsage extension + * implicitly allows all key purposes. + * + * @return an immutable <code>Set</code> of key purpose OIDs in string + * format (or <code>null</code>) + * @see #setExtendedKeyUsage + */ + public Set getExtendedKeyUsage() + { + if (keyPurposeSet == null || keyPurposeSet.isEmpty()) + { + return keyPurposeSet; + } + + Set returnSet = new HashSet(); + Iterator iter = keyPurposeSet.iterator(); + while (iter.hasNext()) + { + returnSet.add(iter.next().toString()); + } + + return Collections.unmodifiableSet(returnSet); + } + + /** + * Indicates if the <code>X509Certificate</code> must contain all or at + * least one of the subjectAlternativeNames specified in the + * {@link #setSubjectAlternativeNames setSubjectAlternativeNames} or + * {@link #addSubjectAlternativeName addSubjectAlternativeName} methods. If + * <code>true</code>, the <code>X509Certificate</code> must contain all + * of the specified subject alternative names. If <code>false</code>, the + * <code>X509Certificate</code> must contain at least one of the specified + * subject alternative names. + * + * @return <code>true</code> if the flag is enabled; <code>false</code> + * if the flag is disabled. The flag is <code>true</code> by + * default. + * + * @see #setMatchAllSubjectAltNames + */ + public boolean getMatchAllSubjectAltNames() + { + return matchAllSubjectAltNames; + } + + /** + * Returns a copy of the subjectAlternativeNames criterion. The + * <code>X509Certificate</code> must contain all or at least one of the + * specified subjectAlternativeNames, depending on the value of the + * matchAllNames flag (see {@link #getMatchAllSubjectAltNames + * getMatchAllSubjectAltNames}). If the value returned is <code>null</code>, + * no subjectAlternativeNames check will be performed.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a + * <code>Collection</code> with one entry for each name to be included in + * the subject alternative name criterion. Each entry is a <code>List</code> + * whose first entry is an <code>Integer</code> (the name type, 0-8) and + * whose second entry is a <code>String</code> or a byte array (the name, + * in string or ASN.1 DER encoded form, respectively). There can be multiple + * names of the same type. Note that the <code>Collection</code> returned + * may contain duplicate names (same name and name type).<br /> + * <br /> + * Each subject alternative name in the <code>Collection</code> may be + * specified either as a <code>String</code> or as an ASN.1 encoded byte + * array. For more details about the formats used, see + * {@link #addSubjectAlternativeName(int type, String name) + * addSubjectAlternativeName(int type, String name)} and + * {@link #addSubjectAlternativeName(int type, byte [] name) + * addSubjectAlternativeName(int type, byte [] name)}.<br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @return a <code>Collection</code> of names (or <code>null</code>) + * + * @see #setSubjectAlternativeNames + */ + public Collection getSubjectAlternativeNames() + { + if (subjectAltNames != null) + { + return null; + } + + Set returnAltNames = new HashSet(); + List returnList; + Iterator iter = subjectAltNames.iterator(); + List obj; + while (iter.hasNext()) + { + obj = (List)iter.next(); + returnList = new ArrayList(); + returnList.add(obj.get(0)); + if (obj.get(1) instanceof byte[]) + { + returnList.add(((byte[])obj.get(1)).clone()); + } + else + { + returnList.add(obj.get(1)); + } + returnAltNames.add(returnList); + } + + return returnAltNames; + } + + /** + * Returns the name constraints criterion. The <code>X509Certificate</code> + * must have subject and subject alternative names that meet the specified + * name constraints.<br /> + * <br /> + * The name constraints are returned as a byte array. This byte array + * contains the DER encoded form of the name constraints, as they would + * appear in the NameConstraints structure defined in RFC 2459 and X.509. + * The ASN.1 notation for this structure is supplied in the documentation + * for + * {@link #setNameConstraints(byte [] bytes) setNameConstraints(byte [] bytes)}.<br /> + * <br /> + * Note that the byte array returned is cloned to protect against subsequent + * modifications.<br /> + * <br /> + * <b>TODO: implement this</b> + * + * @return a byte array containing the ASN.1 DER encoding of a + * NameConstraints extension used for checking name constraints. + * <code>null</code> if no name constraints check will be + * performed. + * + * @exception UnsupportedOperationException + * because this method is not supported + * + * @see #setNameConstraints + */ + public byte[] getNameConstraints() + { + throw new UnsupportedOperationException(); + } + + /** + * Returns the basic constraints constraint. If the value is greater than or + * equal to zero, the <code>X509Certificates</code> must include a + * basicConstraints extension with a pathLen of at least this value. If the + * value is -2, only end-entity certificates are accepted. If the value is + * -1, no basicConstraints check is done. + * + * @return the value for the basic constraints constraint + * + * @see #setBasicConstraints + */ + public int getBasicConstraints() + { + return minMaxPathLen; + } + + /** + * Returns the policy criterion. The <code>X509Certificate</code> must + * include at least one of the specified policies in its certificate + * policies extension. If the <code>Set</code> returned is empty, then the + * <code>X509Certificate</code> must include at least some specified + * policy in its certificate policies extension. If the <code>Set</code> + * returned is <code>null</code>, no policy check will be performed. + * + * @return an immutable <code>Set</code> of certificate policy OIDs in + * string format (or <code>null</code>) + * + * @see #setPolicy + */ + public Set getPolicy() + { + if (policy == null) + { + return null; + } + + return Collections.unmodifiableSet(policy); + } + + /** + * Returns a copy of the pathToNames criterion. The + * <code>X509Certificate</code> must not include name constraints that + * would prohibit building a path to the specified names. If the value + * returned is <code>null</code>, no pathToNames check will be performed.<br /> + * <br /> + * If the value returned is not <code>null</code>, it is a + * <code>Collection</code> with one entry for each name to be included in + * the pathToNames criterion. Each entry is a <code>List</code> whose + * first entry is an <code>Integer</code> (the name type, 0-8) and whose + * second entry is a <code>String</code> or a byte array (the name, in + * string or ASN.1 DER encoded form, respectively). There can be multiple + * names of the same type. Note that the <code>Collection</code> returned + * may contain duplicate names (same name and name type).<br /> + * <br /> + * Each name in the <code>Collection</code> may be specified either as a + * <code>String</code> or as an ASN.1 encoded byte array. For more details + * about the formats used, see {@link #addPathToName(int type, String name) + * addPathToName(int type, String name)} and + * {@link #addPathToName(int type, byte [] name) addPathToName(int type, + * byte [] name)}.<br /> + * <br /> + * Note that a deep copy is performed on the <code>Collection</code> to + * protect against subsequent modifications. + * + * @return a <code>Collection</code> of names (or <code>null</code>) + * + * @see #setPathToNames + */ + public Collection getPathToNames() + { + if (pathToNames == null) + { + return null; + } + + Set returnPathToNames = new HashSet(); + List returnList; + Iterator iter = pathToNames.iterator(); + List obj; + + while (iter.hasNext()) + { + obj = (List)iter.next(); + returnList = new ArrayList(); + returnList.add(obj.get(0)); + if (obj.get(1) instanceof byte[]) + { + returnList.add(((byte[])obj.get(1)).clone()); + } + else + { + returnList.add(obj.get(1)); + } + returnPathToNames.add(returnList); + } + + return returnPathToNames; + } + + /** + * Return a printable representation of the <code>CertSelector</code>.<br /> + * <br /> + * <b>TODO: implement output for currently unsupported options(name + * constraints)</b><br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object}, + * {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId} + * + * @return a <code>String</code> describing the contents of the + * <code>CertSelector</code> + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("X509CertSelector: [\n"); + if (x509Cert != null) + { + sb.append(" Certificate: ").append(x509Cert).append('\n'); + } + if (serialNumber != null) + { + sb.append(" Serial Number: ").append(serialNumber).append('\n'); + } + if (issuerDN != null) + { + sb.append(" Issuer: ").append(getIssuerAsString()).append('\n'); + } + if (subjectDN != null) + { + sb.append(" Subject: ").append(getSubjectAsString()).append('\n'); + } + try + { + if (subjectKeyID != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + subjectKeyID); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Subject Key Identifier: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + if (authorityKeyID != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + authorityKeyID); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Authority Key Identifier: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + } + catch (IOException ex) + { + sb.append(ex.getMessage()).append('\n'); + } + if (certValid != null) + { + sb.append(" Certificate Valid: ").append(certValid).append('\n'); + } + if (privateKeyValid != null) + { + sb.append(" Private Key Valid: ").append(privateKeyValid) + .append('\n'); + } + if (subjectKeyAlgID != null) + { + sb.append(" Subject Public Key AlgID: ") + .append(subjectKeyAlgID).append('\n'); + } + if (subjectPublicKey != null) + { + sb.append(" Subject Public Key: ").append(subjectPublicKey) + .append('\n'); + } + if (keyUsage != null) + { + sb.append(" Key Usage: ").append(keyUsage).append('\n'); + } + if (keyPurposeSet != null) + { + sb.append(" Extended Key Usage: ").append(keyPurposeSet) + .append('\n'); + } + if (policy != null) + { + sb.append(" Policy: ").append(policy).append('\n'); + } + sb.append(" matchAllSubjectAltNames flag: ") + .append(matchAllSubjectAltNames).append('\n'); + if (subjectAltNamesByte != null) + { + sb.append(" SubjectAlternativNames: \n["); + Iterator iter = subjectAltNamesByte.iterator(); + List obj; + try + { + while (iter.hasNext()) + { + obj = (List)iter.next(); + ByteArrayInputStream inStream = new ByteArrayInputStream( + (byte[])obj.get(1)); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Type: ").append(obj.get(0)).append(" Data: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + } + catch (IOException ex) + { + sb.append(ex.getMessage()).append('\n'); + } + sb.append("]\n"); + } + if (pathToNamesByte != null) + { + sb.append(" PathToNamesNames: \n["); + Iterator iter = pathToNamesByte.iterator(); + List obj; + try + { + while (iter.hasNext()) + { + obj = (List)iter.next(); + ByteArrayInputStream inStream = new ByteArrayInputStream( + (byte[])obj.get(1)); + ASN1InputStream derInStream = new ASN1InputStream(inStream); + ASN1Object derObject = derInStream.readObject(); + sb.append(" Type: ").append(obj.get(0)).append(" Data: ") + .append(ASN1Dump.dumpAsString(derObject)).append('\n'); + } + } + catch (IOException ex) + { + sb.append(ex.getMessage()).append('\n'); + } + sb.append("]\n"); + } + sb.append(']'); + return sb.toString(); + } + + /** + * Decides whether a <code>Certificate</code> should be selected.<br /> + * <br /> + * <b>TODO: implement missing tests (name constraints and path to names)</b><br /> + * <br /> + * Uses {@link org.bouncycastle.asn1.ASN1InputStream ASN1InputStream}, + * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence}, + * {@link org.bouncycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier}, + * {@link org.bouncycastle.asn1.ASN1Object ASN1Object}, + * {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime}, + * {@link org.bouncycastle.asn1.x509.X509Name X509Name}, + * {@link org.bouncycastle.asn1.x509.X509Extensions X509Extensions}, + * {@link org.bouncycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage}, + * {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId}, + * {@link org.bouncycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo}, + * {@link org.bouncycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier} + * to access X509 extensions + * + * @param cert + * the <code>Certificate</code> to be checked + * + * @return <code>true</code> if the <code>Certificate</code> should be + * selected, <code>false</code> otherwise + */ + public boolean match(Certificate cert) + { + boolean[] booleanArray; + List tempList; + Iterator tempIter; + + if (!(cert instanceof X509Certificate)) + { + return false; + } + X509Certificate certX509 = (X509Certificate)cert; + + if (x509Cert != null && !x509Cert.equals(certX509)) + { + return false; + } + if (serialNumber != null + && !serialNumber.equals(certX509.getSerialNumber())) + { + return false; + } + try + { + if (issuerDNX509 != null) + { + if (!issuerDNX509.equals(PrincipalUtil + .getIssuerX509Principal(certX509), true)) + { + return false; + } + } + if (subjectDNX509 != null) + { + if (!subjectDNX509.equals(PrincipalUtil + .getSubjectX509Principal(certX509), true)) + { + return false; + } + } + } + catch (Exception ex) + { + return false; + } + if (subjectKeyID != null) + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.SubjectKeyIdentifier + .getId()); + if (data == null) + { + return false; + } + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + byte[] testData = ((ASN1OctetString)derInputStream.readObject()) + .getOctets(); + if (!Arrays.equals(subjectKeyID, testData)) + { + return false; + } + } + catch (IOException ex) + { + return false; + } + } + if (authorityKeyID != null) + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.AuthorityKeyIdentifier + .getId()); + if (data == null) + { + return false; + } + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + byte[] testData = ((ASN1OctetString)derInputStream.readObject()) + .getOctets(); + if (!Arrays.equals(authorityKeyID, testData)) + { + return false; + } + } + catch (IOException ex) + { + return false; + } + } + if (certValid != null) + { + if (certX509.getNotAfter() != null + && certValid.after(certX509.getNotAfter())) + { + return false; + } + if (certX509.getNotBefore() != null + && certValid.before(certX509.getNotBefore())) + { + return false; + } + } + if (privateKeyValid != null) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.PrivateKeyUsagePeriod + .getId()); + if (data != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + // TODO fix this, Sequence contains tagged objects + ASN1Sequence derObject = (ASN1Sequence)derInputStream + .readObject(); + DERGeneralizedTime derDate = DERGeneralizedTime + .getInstance(derObject.getObjectAt(0)); + SimpleDateFormat dateF = new SimpleDateFormat( + "yyyyMMddHHmmssZ"); + if (privateKeyValid.before(dateF.parse(derDate.getTime()))) + { + return false; + } + derDate = DERGeneralizedTime.getInstance(derObject + .getObjectAt(1)); + if (privateKeyValid.after(dateF.parse(derDate.getTime()))) + { + return false; + } + } + } + catch (Exception ex) + { + return false; + } + } + if (subjectKeyAlgID != null) + { + try + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + certX509.getPublicKey().getEncoded()); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo( + (ASN1Sequence)derInputStream.readObject()); + AlgorithmIdentifier algInfo = publicKeyInfo.getAlgorithmId(); + if (!algInfo.getObjectId().equals(subjectKeyAlgID)) + { + return false; + } + } + catch (Exception ex) + { + return false; + } + } + if (subjectPublicKeyByte != null) + { + if (!Arrays.equals(subjectPublicKeyByte, certX509.getPublicKey() + .getEncoded())) + { + return false; + } + } + if (subjectPublicKey != null) + { + if (!subjectPublicKey.equals(certX509.getPublicKey())) + { + return false; + } + } + if (keyUsage != null) + { + booleanArray = certX509.getKeyUsage(); + if (booleanArray != null) + { + for (int i = 0; i < keyUsage.length; i++) + { + if (keyUsage[i] + && (booleanArray.length <= i || !booleanArray[i])) + { + return false; + } + } + } + } + if (keyPurposeSet != null && !keyPurposeSet.isEmpty()) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.ExtendedKeyUsage + .getId()); + if (data != null) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + ExtendedKeyUsage extendedKeyUsage = ExtendedKeyUsage.getInstance( + (ASN1Sequence)derInputStream.readObject()); + tempIter = keyPurposeSet.iterator(); + while (tempIter.hasNext()) + { + if (!extendedKeyUsage + .hasKeyPurposeId((KeyPurposeId)tempIter.next())) + { + return false; + } + } + } + } + catch (Exception ex) + { + return false; + } + } + if (minMaxPathLen != -1) + { + if (minMaxPathLen == -2 && certX509.getBasicConstraints() != -1) + { + return false; + } + if (minMaxPathLen >= 0 + && certX509.getBasicConstraints() < minMaxPathLen) + { + return false; + } + } + if (policyOID != null) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.CertificatePolicies + .getId()); + if (data == null) + { + return false; + } + if (!policyOID.isEmpty()) + { + ByteArrayInputStream inStream = new ByteArrayInputStream( + data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + Enumeration policySequence = ((ASN1Sequence)derInputStream + .readObject()).getObjects(); + ASN1Sequence policyObject; + boolean test = false; + while (policySequence.hasMoreElements() && !test) + { + policyObject = (ASN1Sequence)policySequence + .nextElement(); + if (policyOID.contains(policyObject.getObjectAt(0))) + { + test = true; + } + } + if (!test) + { + return false; + } + } + } + catch (Exception ex) + { + ex.printStackTrace(); + return false; + } + } + if (subjectAltNamesByte != null) + { + try + { + byte[] data = certX509 + .getExtensionValue(X509Extensions.SubjectAlternativeName + .getId()); + if (data == null) + { + return false; + } + ByteArrayInputStream inStream = new ByteArrayInputStream(data); + ASN1InputStream derInputStream = new ASN1InputStream(inStream); + inStream = new ByteArrayInputStream( + ((ASN1OctetString)derInputStream.readObject()) + .getOctets()); + derInputStream = new ASN1InputStream(inStream); + Enumeration altNamesSequence = ((ASN1Sequence)derInputStream + .readObject()).getObjects(); + ASN1TaggedObject altNameObject; + boolean test = false; + Set testSet = new HashSet(subjectAltNamesByte); + List testList; + ASN1Object derData; + ByteArrayOutputStream outStream; + DEROutputStream derOutStream; + while (altNamesSequence.hasMoreElements() && !test) + { + altNameObject = (ASN1TaggedObject)altNamesSequence + .nextElement(); + testList = new ArrayList(2); + testList.add(Integers.valueOf(altNameObject.getTagNo())); + derData = altNameObject.getObject(); + outStream = new ByteArrayOutputStream(); + derOutStream = new DEROutputStream(outStream); + derOutStream.writeObject(derData); + derOutStream.close(); + testList.add(outStream.toByteArray()); + + if (testSet.remove(testList)) + { + test = true; + } + + if (matchAllSubjectAltNames && !testSet.isEmpty()) + { + test = false; + } + } + if (!test) + { + return false; + } + } + catch (Exception ex) + { + ex.printStackTrace(); + return false; + } + } + + return true; + } + + /** + * Returns a copy of this object. + * + * @return the copy + */ + public Object clone() + { + try + { + X509CertSelector copy = (X509CertSelector)super.clone(); + if (issuerDN instanceof byte[]) + { + copy.issuerDN = ((byte[])issuerDN).clone(); + } + if (subjectDN instanceof byte[]) + { + copy.subjectDN = ((byte[])subjectDN).clone(); + } + if (subjectKeyID != null) + { + copy.subjectKeyID = (byte[])subjectKeyID.clone(); + } + if (authorityKeyID != null) + { + copy.authorityKeyID = (byte[])authorityKeyID.clone(); + } + if (subjectPublicKeyByte != null) + { + copy.subjectPublicKeyByte = (byte[])subjectPublicKeyByte + .clone(); + } + if (keyUsage != null) + { + copy.keyUsage = (boolean[])keyUsage.clone(); + } + if (keyPurposeSet != null) + { + copy.keyPurposeSet = new HashSet(keyPurposeSet); + } + if (policy != null) + { + copy.policy = new HashSet(policy); + copy.policyOID = new HashSet(); + Iterator iter = policyOID.iterator(); + while (iter.hasNext()) + { + copy.policyOID.add(new ASN1ObjectIdentifier( + ((ASN1ObjectIdentifier)iter.next()).getId())); + } + } + if (subjectAltNames != null) + { + copy.subjectAltNames = new HashSet(getSubjectAlternativeNames()); + Iterator iter = subjectAltNamesByte.iterator(); + List obj; + List cloneObj; + while (iter.hasNext()) + { + obj = (List)iter.next(); + cloneObj = new ArrayList(); + cloneObj.add(obj.get(0)); + cloneObj.add(((byte[])obj.get(1)).clone()); + copy.subjectAltNamesByte.add(cloneObj); + } + } + if (pathToNames != null) + { + copy.pathToNames = new HashSet(getPathToNames()); + Iterator iter = pathToNamesByte.iterator(); + List obj; + List cloneObj; + while (iter.hasNext()) + { + obj = (List)iter.next(); + cloneObj = new ArrayList(); + cloneObj.add(obj.get(0)); + cloneObj.add(((byte[])obj.get(1)).clone()); + copy.pathToNamesByte.add(cloneObj); + } + } + return copy; + } + catch (CloneNotSupportedException e) + { + /* Cannot happen */ + throw new InternalError(e.toString()); + } + } +} diff --git a/core/src/main/jdk1.1/java/security/cert/X509Certificate.java b/core/src/main/jdk1.1/java/security/cert/X509Certificate.java new file mode 100644 index 00000000..d56f1c6f --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/X509Certificate.java @@ -0,0 +1,33 @@ + +package java.security.cert; + +import java.math.BigInteger; +import java.security.Principal; +import java.util.Date; + +public abstract class X509Certificate extends Certificate +implements X509Extension +{ + protected X509Certificate() + { + super("X.509"); + } + + public abstract void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException; + public abstract void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException; + public abstract int getBasicConstraints(); + public abstract Principal getIssuerDN(); + public abstract boolean[] getIssuerUniqueID(); + public abstract boolean[] getKeyUsage(); + public abstract Date getNotAfter(); + public abstract Date getNotBefore(); + public abstract BigInteger getSerialNumber(); + public abstract String getSigAlgName(); + public abstract String getSigAlgOID(); + public abstract byte[] getSigAlgParams(); + public abstract byte[] getSignature(); + public abstract Principal getSubjectDN(); + public abstract boolean[] getSubjectUniqueID(); + public abstract byte[] getTBSCertificate() throws CertificateEncodingException; + public abstract int getVersion(); +} diff --git a/core/src/main/jdk1.1/java/security/cert/X509Extension.java b/core/src/main/jdk1.1/java/security/cert/X509Extension.java new file mode 100644 index 00000000..20855be1 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/cert/X509Extension.java @@ -0,0 +1,12 @@ + +package java.security.cert; + +import java.util.Set; + +public interface X509Extension +{ + public abstract Set getCriticalExtensionOIDs(); + public abstract byte[] getExtensionValue(String oid); + public abstract Set getNonCriticalExtensionOIDs(); + public abstract boolean hasUnsupportedCriticalExtension(); +} diff --git a/core/src/main/jdk1.1/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/core/src/main/jdk1.1/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java new file mode 100644 index 00000000..0fbb0fb1 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java @@ -0,0 +1,67 @@ + +package java.security.interfaces; + +import java.math.BigInteger; +import java.security.spec.RSAOtherPrimeInfo; + +/** + * The interface to an RSA multi-prime private key, as defined in the + * PKCS#1 v2.1, using the Chinese Remainder Theorem (CRT) information values. + * + * @since 1.4 + * @see RSAPrivateKeySpec, RSAMultiPrimePrivateCrtKeySpec, RSAPrivateKey, + * RSAPrivateCrtKey + */ +public interface RSAMultiPrimePrivateCrtKey +extends RSAPrivateKey +{ + /** + * Returns the public exponent. + * + * @returns the public exponent. + */ + public BigInteger getPublicExponent(); + + /** + * Returns the primeP. + * + * @returns the primeP. + */ + public BigInteger getPrimeP(); + + /** + * Returns the primeQ. + * + * @returns the primeQ. + */ + public BigInteger getPrimeQ(); + + /** + * Returns the primeExponentP. + * + * @returns the primeExponentP. + */ + public BigInteger getPrimeExponentP(); + + /** + * Returns the primeExponentQ. + * + * @returns the primeExponentQ. + */ + public BigInteger getPrimeExponentQ(); + + /** + * Returns the crtCoefficient. + * + * @returns the crtCoefficient. + */ + public BigInteger getCrtCoefficient(); + + /** + * Returns the otherPrimeInfo or null if there are only two prime + * factors (p and q). + * + * @returns the otherPrimeInfo. + */ + public RSAOtherPrimeInfo[] getOtherPrimeInfo(); +} diff --git a/core/src/main/jdk1.1/java/security/interfaces/RSAPrivateCrtKey.java b/core/src/main/jdk1.1/java/security/interfaces/RSAPrivateCrtKey.java new file mode 100644 index 00000000..81855907 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/interfaces/RSAPrivateCrtKey.java @@ -0,0 +1,16 @@ + +package java.security.interfaces; + +import java.math.BigInteger; + +public interface RSAPrivateCrtKey extends RSAPrivateKey +{ + public static final long serialVersionUID = 6034044314589513430L; + + public abstract BigInteger getCrtCoefficient(); + public abstract BigInteger getPrimeExponentP(); + public abstract BigInteger getPrimeExponentQ(); + public abstract BigInteger getPrimeP(); + public abstract BigInteger getPrimeQ(); + public abstract BigInteger getPublicExponent(); +} diff --git a/core/src/main/jdk1.1/java/security/interfaces/RSAPrivateKey.java b/core/src/main/jdk1.1/java/security/interfaces/RSAPrivateKey.java new file mode 100644 index 00000000..9b37eef9 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/interfaces/RSAPrivateKey.java @@ -0,0 +1,13 @@ + +package java.security.interfaces; + +import java.math.BigInteger; +import java.security.PrivateKey; + +public interface RSAPrivateKey extends PrivateKey +{ + public static final long serialVersionUID = 6034044314589513430L; + + public abstract BigInteger getModulus(); + public abstract BigInteger getPrivateExponent(); +} diff --git a/core/src/main/jdk1.1/java/security/interfaces/RSAPublicKey.java b/core/src/main/jdk1.1/java/security/interfaces/RSAPublicKey.java new file mode 100644 index 00000000..6ae00ec2 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/interfaces/RSAPublicKey.java @@ -0,0 +1,13 @@ + +package java.security.interfaces; + +import java.math.BigInteger; +import java.security.PublicKey; + +public interface RSAPublicKey extends PublicKey +{ + public static final long serialVersionUID = 7187392471159151072L; + + public abstract BigInteger getModulus(); + public abstract BigInteger getPublicExponent(); +} diff --git a/core/src/main/jdk1.1/java/security/spec/AlgorithmParameterSpec.java b/core/src/main/jdk1.1/java/security/spec/AlgorithmParameterSpec.java new file mode 100644 index 00000000..37a03e9b --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/AlgorithmParameterSpec.java @@ -0,0 +1,6 @@ + +package java.security.spec; + +public interface AlgorithmParameterSpec +{ +} diff --git a/core/src/main/jdk1.1/java/security/spec/DSAParameterSpec.java b/core/src/main/jdk1.1/java/security/spec/DSAParameterSpec.java new file mode 100644 index 00000000..a3897f8a --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/DSAParameterSpec.java @@ -0,0 +1,34 @@ + +package java.security.spec; + +import java.math.BigInteger; +import java.security.interfaces.DSAParams; + +public class DSAParameterSpec implements AlgorithmParameterSpec, DSAParams +{ + private BigInteger p; + private BigInteger q; + private BigInteger g; + + public DSAParameterSpec(BigInteger p, BigInteger q, BigInteger g) + { + this.p = p; + this.q = q; + this.g = g; + } + + public BigInteger getG() + { + return g; + } + + public BigInteger getP() + { + return p; + } + + public BigInteger getQ() + { + return q; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/DSAPrivateKeySpec.java b/core/src/main/jdk1.1/java/security/spec/DSAPrivateKeySpec.java new file mode 100644 index 00000000..ff5febef --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/DSAPrivateKeySpec.java @@ -0,0 +1,40 @@ + +package java.security.spec; + +import java.math.BigInteger; + +public class DSAPrivateKeySpec implements KeySpec +{ + private BigInteger x; + private BigInteger p; + private BigInteger q; + private BigInteger g; + + public DSAPrivateKeySpec(BigInteger x, BigInteger p, BigInteger q, BigInteger g) + { + this.x = x; + this.p = p; + this.q = q; + this.g = g; + } + + public BigInteger getG() + { + return g; + } + + public BigInteger getP() + { + return p; + } + + public BigInteger getQ() + { + return q; + } + + public BigInteger getX() + { + return x; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/DSAPublicKeySpec.java b/core/src/main/jdk1.1/java/security/spec/DSAPublicKeySpec.java new file mode 100644 index 00000000..f8ca3679 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/DSAPublicKeySpec.java @@ -0,0 +1,40 @@ + +package java.security.spec; + +import java.math.BigInteger; + +public class DSAPublicKeySpec implements KeySpec +{ + private BigInteger y; + private BigInteger p; + private BigInteger q; + private BigInteger g; + + public DSAPublicKeySpec(BigInteger y, BigInteger p, BigInteger q, BigInteger g) + { + this.y = y; + this.p = p; + this.q = q; + this.g = g; + } + + public BigInteger getG() + { + return g; + } + + public BigInteger getP() + { + return p; + } + + public BigInteger getQ() + { + return q; + } + + public BigInteger getY() + { + return y; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/EncodedKeySpec.java b/core/src/main/jdk1.1/java/security/spec/EncodedKeySpec.java new file mode 100644 index 00000000..7295460f --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/EncodedKeySpec.java @@ -0,0 +1,19 @@ + +package java.security.spec; + +public abstract class EncodedKeySpec implements KeySpec +{ + private byte[] encodedKey; + + public EncodedKeySpec(byte[] encodedKey) + { + this.encodedKey = (byte[])encodedKey.clone(); + } + + public byte[] getEncoded() + { + return (byte[])encodedKey.clone(); + } + + public abstract String getFormat(); +} diff --git a/core/src/main/jdk1.1/java/security/spec/InvalidKeySpecException.java b/core/src/main/jdk1.1/java/security/spec/InvalidKeySpecException.java new file mode 100644 index 00000000..cb29aee3 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/InvalidKeySpecException.java @@ -0,0 +1,16 @@ + +package java.security.spec; + +import java.security.GeneralSecurityException; + +public class InvalidKeySpecException extends GeneralSecurityException +{ + public InvalidKeySpecException() + { + } + + public InvalidKeySpecException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/InvalidParameterSpecException.java b/core/src/main/jdk1.1/java/security/spec/InvalidParameterSpecException.java new file mode 100644 index 00000000..c8303edd --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/InvalidParameterSpecException.java @@ -0,0 +1,16 @@ + +package java.security.spec; + +import java.security.GeneralSecurityException; + +public class InvalidParameterSpecException extends GeneralSecurityException +{ + public InvalidParameterSpecException() + { + } + + public InvalidParameterSpecException(String msg) + { + super(msg); + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/KeySpec.java b/core/src/main/jdk1.1/java/security/spec/KeySpec.java new file mode 100644 index 00000000..cfa7cb92 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/KeySpec.java @@ -0,0 +1,6 @@ + +package java.security.spec; + +public interface KeySpec +{ +} diff --git a/core/src/main/jdk1.1/java/security/spec/PKCS8EncodedKeySpec.java b/core/src/main/jdk1.1/java/security/spec/PKCS8EncodedKeySpec.java new file mode 100644 index 00000000..10c5f66c --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/PKCS8EncodedKeySpec.java @@ -0,0 +1,20 @@ + +package java.security.spec; + +public class PKCS8EncodedKeySpec extends EncodedKeySpec +{ + public PKCS8EncodedKeySpec(byte[] encodedKey) + { + super(encodedKey); + } + + public byte[] getEncoded() + { + return super.getEncoded(); + } + + public final String getFormat() + { + return "PKCS#8"; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/PSSParameterSpec.java b/core/src/main/jdk1.1/java/security/spec/PSSParameterSpec.java new file mode 100644 index 00000000..c4b4989c --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/PSSParameterSpec.java @@ -0,0 +1,45 @@ + +package java.security.spec; + +/** + * This class specifies a parameter spec for RSA PSS encoding scheme, + * as defined in the PKCS#1 v2.1. + * + * @since 1.4 + * @see AlgorithmParameterSpec, Signature + */ +public class PSSParameterSpec + extends Object + implements AlgorithmParameterSpec +{ + private int saltLen; + + /** + * Creates a new PSSParameterSpec given the salt length as defined + * in PKCS#1. + * + * @param saltLen - the length of salt in bits to be used in PKCS#1 + * PSS encoding. + * @throws IllegalArgumentException - if saltLen is less than 0. + */ + public PSSParameterSpec(int saltLen) + { + if ( saltLen < 0 ) + { + throw new IllegalArgumentException("Salt length must be >= 0"); + } + + this.saltLen = saltLen; + } + + /** + * Returns the salt length in bits. + * + * @returns the salt length. + */ + public int getSaltLength() + { + return saltLen; + } +} + diff --git a/core/src/main/jdk1.1/java/security/spec/RSAKeyGenParameterSpec.java b/core/src/main/jdk1.1/java/security/spec/RSAKeyGenParameterSpec.java new file mode 100644 index 00000000..756c6c0f --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/RSAKeyGenParameterSpec.java @@ -0,0 +1,35 @@ +package java.security.spec; + +import java.math.BigInteger; + +/** + * specifies parameters to be used for the generation of + * a RSA key pair. + */ +public class RSAKeyGenParameterSpec + implements AlgorithmParameterSpec +{ + static BigInteger F0 = BigInteger.valueOf(3); + static BigInteger F4 = BigInteger.valueOf(65537); + + private int keysize; + private BigInteger publicExponent; + + public RSAKeyGenParameterSpec( + int keysize, + BigInteger publicExponent) + { + this.keysize = keysize; + this.publicExponent = publicExponent; + } + + public int getKeysize() + { + return keysize; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java b/core/src/main/jdk1.1/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java new file mode 100644 index 00000000..53c3a8a5 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java @@ -0,0 +1,159 @@ + +package java.security.spec; + +import java.math.BigInteger; + +/** + * This class specifies an RSA multi-prime private key, as defined in + * the PKCS#1 v2.1, using the Chinese Remainder Theorem (CRT) information + * values for efficiency. + * + * @since 1.4 + * @see Key, KeyFactory, KeySpec, PKCS8EncodedKeySpec, RSAPrivateKeySpec, + * RSAPublicKeySpec, RSAOtherPrimeInfo + */ +public class RSAMultiPrimePrivateCrtKeySpec + extends RSAPrivateKeySpec +{ + private BigInteger publicExponent; + private BigInteger privateExponent; + private BigInteger primeP; + private BigInteger primeQ; + private BigInteger primeExponentP; + private BigInteger primeExponentQ; + private BigInteger crtCoefficient; + private RSAOtherPrimeInfo[] otherPrimeInfo; + + /** + * Creates a new RSAMultiPrimePrivateCrtKeySpec given the modulus, + * publicExponent, privateExponent, primeP, primeQ, primeExponentP, + * primeExponentQ, crtCoefficient, and otherPrimeInfo as defined in + * PKCS#1 v2.1. + * + * Note that otherPrimeInfo is cloned when constructing this object. + * + * @param modulus - the modulus n. + * @param publicExponent - the public exponent e. + * @param privateExponent - the private exponent d. + * @param primeP - the prime factor p of n. + * @param primeQ - the prime factor q of n. + * @param primeExponentP - this is d mod (p-1). + * @param primeExponentQ - this is d mod (q-1). + * @param crtCoefficient - the Chinese Remainder Theorem coefficient q-1 + * mod p. + * @param otherPrimeInfo - triplets of the rest of primes, null can be + * specified if there are only two prime factors (p and q). + * @throws NullPointerException - if any of the parameters, i.e. modulus, + * publicExponent, privateExponent, primeP, primeQ, primeExponentP, + * primeExponentQ, crtCoefficient, is null. + * @throws IllegalArgumentException - if an empty, i.e. 0-length, + * otherPrimeInfo is specified. + */ + public RSAMultiPrimePrivateCrtKeySpec( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger primeP, + BigInteger primeQ, + BigInteger primeExponentP, + BigInteger primeExponentQ, + BigInteger crtCoefficient, + RSAOtherPrimeInfo[] otherPrimeInfo) + { + super(modulus, privateExponent); + + if ( publicExponent == null || primeP == null || primeQ == null + || primeExponentP == null || primeExponentQ == null + || crtCoefficient == null ) + { + throw new NullPointerException("Invalid null argument"); + } + + if ( otherPrimeInfo != null ) + { + if ( otherPrimeInfo.length == 0 ) + { + throw new IllegalArgumentException("Invalid length for otherPrimeInfo"); + } + + this.otherPrimeInfo = (RSAOtherPrimeInfo[])otherPrimeInfo.clone(); + } + } + + /** + * Returns the public exponent. + * + * @returns the public exponent. + */ + public BigInteger getPublicExponent() + { + return publicExponent; + } + + /** + * Returns the primeP. + * + * @returns the primeP. + */ + public BigInteger getPrimeP() + { + return primeP; + } + + /** + * Returns the primeQ. + * + * @returns the primeQ. + */ + public BigInteger getPrimeQ() + { + return primeQ; + } + + /** + * Returns the primeExponentP. + * + * @returns the primeExponentP. + */ + public BigInteger getPrimeExponentP() + { + return primeExponentP; + } + + /** + * Returns the primeExponentQ. + * + * @returns the primeExponentQ. + */ + public BigInteger getPrimeExponentQ() + { + return primeExponentQ; + } + + /** + * Returns the crtCofficient. + * + * @returns the crtCofficient. + */ + public BigInteger getCrtCoefficient() + { + return crtCoefficient; + } + + /** + * Returns a copy of the otherPrimeInfo or null if there are only + * two prime factors (p and q). + * + * @returns the otherPrimeInfo. + */ + public RSAOtherPrimeInfo[] getOtherPrimeInfo() + { + if ( otherPrimeInfo != null ) + { + return (RSAOtherPrimeInfo[])otherPrimeInfo.clone(); + } + + return null; + } +} + diff --git a/core/src/main/jdk1.1/java/security/spec/RSAOtherPrimeInfo.java b/core/src/main/jdk1.1/java/security/spec/RSAOtherPrimeInfo.java new file mode 100644 index 00000000..4d0e1468 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/RSAOtherPrimeInfo.java @@ -0,0 +1,80 @@ + +package java.security.spec; + +import java.math.BigInteger; + +/** + * This class represents the triplet (prime, exponent, and coefficient) + * inside RSA's OtherPrimeInfo structure, as defined in the PKCS#1 v2.1. + * The ASN.1 syntax of RSA's OtherPrimeInfo is as follows: + * + * <pre> + * OtherPrimeInfo ::= SEQUENCE { + * prime INTEGER, + * exponent INTEGER, + * coefficient INTEGER + * } + * </pre> + */ +public class RSAOtherPrimeInfo +extends Object +{ + private BigInteger prime; + private BigInteger primeExponent; + private BigInteger crtCoefficient; + + /** + * Creates a new RSAOtherPrimeInfo given the prime, primeExponent, + * and crtCoefficient as defined in PKCS#1. + * + * @param prime - the prime factor of n. + * @param primeExponent - the exponent. + * @param crtCoefficient - the Chinese Remainder Theorem coefficient. + * @throws NullPointerException - if any of the parameters, i.e. prime, + * primeExponent, crtCoefficient, is null. + */ + public RSAOtherPrimeInfo( + BigInteger prime, + BigInteger primeExponent, + BigInteger crtCoefficient) + { + if ( prime == null || primeExponent == null || crtCoefficient == null ) + { + throw new NullPointerException("Null parameter"); + } + + this.prime = prime; + this.primeExponent = primeExponent; + this.crtCoefficient = crtCoefficient; + } + + /** + * Returns the prime. + * + * @returns the prime. + */ + public final BigInteger getPrime() + { + return prime; + } + + /** + * Returns the prime's exponent. + * + * @returns the primeExponent. + */ + public final BigInteger getExponent() + { + return primeExponent; + } + + /** + * Returns the prime's crtCoefficient. + * + * @returns the crtCoefficient. + */ + public final BigInteger getCrtCoefficient() + { + return crtCoefficient; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/RSAPrivateCrtKeySpec.java b/core/src/main/jdk1.1/java/security/spec/RSAPrivateCrtKeySpec.java new file mode 100644 index 00000000..b9d450ad --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/RSAPrivateCrtKeySpec.java @@ -0,0 +1,64 @@ + +package java.security.spec; + +import java.math.BigInteger; + +public class RSAPrivateCrtKeySpec extends RSAPrivateKeySpec +{ + private BigInteger publicExponent; + private BigInteger primeP; + private BigInteger primeQ; + private BigInteger primeExponentP; + private BigInteger primeExponentQ; + private BigInteger crtCoefficient; + + public RSAPrivateCrtKeySpec( + BigInteger modulus, + BigInteger publicExponent, + BigInteger privateExponent, + BigInteger primeP, + BigInteger primeQ, + BigInteger primeExponentP, + BigInteger primeExponentQ, + BigInteger crtCoefficient) + { + super(modulus, privateExponent); + + this.publicExponent = publicExponent; + this.primeP = primeP; + this.primeQ = primeQ; + this.primeExponentP = primeExponentP; + this.primeExponentQ = primeExponentQ; + this.crtCoefficient = crtCoefficient; + } + + public BigInteger getCrtCoefficient() + { + return crtCoefficient; + } + + public BigInteger getPrimeExponentP() + { + return primeExponentP; + } + + public BigInteger getPrimeExponentQ() + { + return primeExponentQ; + } + + public BigInteger getPrimeP() + { + return primeP; + } + + public BigInteger getPrimeQ() + { + return primeQ; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/RSAPrivateKeySpec.java b/core/src/main/jdk1.1/java/security/spec/RSAPrivateKeySpec.java new file mode 100644 index 00000000..88dc4c15 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/RSAPrivateKeySpec.java @@ -0,0 +1,28 @@ + +package java.security.spec; + +import java.math.BigInteger; + +public class RSAPrivateKeySpec extends Object implements KeySpec +{ + private BigInteger modulus; + private BigInteger privateExponent; + + public RSAPrivateKeySpec( + BigInteger modulus, + BigInteger privateExponent) + { + this.modulus = modulus; + this.privateExponent = privateExponent; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPrivateExponent() + { + return privateExponent; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/RSAPublicKeySpec.java b/core/src/main/jdk1.1/java/security/spec/RSAPublicKeySpec.java new file mode 100644 index 00000000..b3a367e7 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/RSAPublicKeySpec.java @@ -0,0 +1,28 @@ + +package java.security.spec; + +import java.math.BigInteger; + +public class RSAPublicKeySpec extends Object implements KeySpec +{ + private BigInteger modulus; + private BigInteger publicExponent; + + public RSAPublicKeySpec( + BigInteger modulus, + BigInteger publicExponent) + { + this.modulus = modulus; + this.publicExponent = publicExponent; + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPublicExponent() + { + return publicExponent; + } +} diff --git a/core/src/main/jdk1.1/java/security/spec/X509EncodedKeySpec.java b/core/src/main/jdk1.1/java/security/spec/X509EncodedKeySpec.java new file mode 100644 index 00000000..1d095b11 --- /dev/null +++ b/core/src/main/jdk1.1/java/security/spec/X509EncodedKeySpec.java @@ -0,0 +1,20 @@ + +package java.security.spec; + +public class X509EncodedKeySpec extends EncodedKeySpec +{ + public X509EncodedKeySpec(byte[] encodedKey) + { + super(encodedKey); + } + + public byte[] getEncoded() + { + return super.getEncoded(); + } + + public final String getFormat() + { + return "X.509"; + } +} diff --git a/core/src/main/jdk1.1/java/util/AbstractCollection.java b/core/src/main/jdk1.1/java/util/AbstractCollection.java new file mode 100644 index 00000000..0ea61b77 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/AbstractCollection.java @@ -0,0 +1,242 @@ +package java.util; + +import java.lang.reflect.Array; +/** + * Title: + * Description: + * Copyright: Copyright (c) 2001 + * Company: + * @version 1.0 + */ + + +public abstract class AbstractCollection implements Collection + { + protected AbstractCollection() + { + } + + public abstract Iterator iterator(); + + public abstract int size(); + + public boolean isEmpty() + { + return size()==0; + } + + public boolean contains(Object o) + { + Iterator it=iterator(); + while(it.hasNext()) + { + Object e=it.next(); + if(o==null) + { + if(e==null) + return true; + } + else + { + if(o.equals(e)) + return true; + } + } + return false; + } + + public Object[] toArray() + { + Object[] arObjects=new Object[size()]; + Iterator it=iterator(); + int i=0; + while(it.hasNext()) + { + arObjects[i++]=it.next(); + } + return arObjects; + } + + public Object[] toArray(Object[] a) throws NullPointerException,ArrayStoreException + //TODO: Check if this is realy compatible to SUN!!! + { + if(a==null) + throw new NullPointerException(); + + if (isEmpty()) return a; + Object[] arObjects=null; + int size=size(); + if(a.length<size) + { + Iterator it=iterator(); + Object o=it.next(); + if(o==null) //no object or object is null + throw new ArrayStoreException(); //correct ? + arObjects=(Object[])Array.newInstance(o.getClass(),size); + } + else + { + arObjects=a; + if(a.length>size) + arObjects[size]=null; + + } + + Iterator it=iterator(); + int i=0; + while(it.hasNext()) + { + Object o=it.next(); + arObjects[i++]=o; + } + return arObjects; + } + + public boolean add(Object o) throws UnsupportedOperationException,NullPointerException,ClassCastException,IllegalArgumentException + { + throw new UnsupportedOperationException(); + } + + public boolean remove(Object o) throws UnsupportedOperationException + { + Iterator it=iterator(); + while(it.hasNext()) + { + Object e=it.next(); + if(o==null) + { + if(e==null) + { + try + { + it.remove(); + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + return true; + } + } + else + { + if(o.equals(e)) + { + try + { + it.remove(); + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + return true; + } + } + } + return false; + } + + public boolean containsAll(Collection c) + { + Iterator it=c.iterator(); + while(it.hasNext()) + { + if(!contains(it.next())) + return false; + } + return true; + } + + public boolean addAll(Collection c) throws UnsupportedOperationException + { + Iterator it=c.iterator(); + boolean ret=false; + while(it.hasNext()) + { + try + { + ret|=add(it.next()); + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + } + return ret; + } + + public boolean removeAll(Collection c) throws UnsupportedOperationException + { + Iterator it=iterator(); + boolean ret=false; + while(it.hasNext()) + { + if(c.contains(it.next())) + try + { + it.remove(); + ret=true; + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + } + return ret; + } + + public boolean retainAll(Collection c) throws UnsupportedOperationException + { + Iterator it=iterator(); + boolean ret=false; + while(it.hasNext()) + { + if(!c.contains(it.next())) + try + { + it.remove(); + ret=true; + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + } + return ret; + } + + public void clear() throws UnsupportedOperationException + { + Iterator it=iterator(); + while(it.hasNext()) + { + try + { + it.next(); + it.remove(); + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + } + } + + public String toString() + { + String ret="["; + Iterator it=iterator(); + if(it.hasNext()) + ret+=String.valueOf(it.next()); + while(it.hasNext()) + { + ret+=", "; + ret+=String.valueOf(it.next()); + + } + ret+="]"; + return ret; + } + +} diff --git a/core/src/main/jdk1.1/java/util/AbstractList.java b/core/src/main/jdk1.1/java/util/AbstractList.java new file mode 100644 index 00000000..363b57ae --- /dev/null +++ b/core/src/main/jdk1.1/java/util/AbstractList.java @@ -0,0 +1,281 @@ +package java.util; + +/** + * Title: + * Description: + * Copyright: Copyright (c) 2001 + * Company: + * @version 1.0 + */ + +public abstract class AbstractList extends AbstractCollection implements List + +{ + protected AbstractList al = this; + + + protected AbstractList() + { + } + + public boolean add(Object o) throws UnsupportedOperationException, ClassCastException, IllegalArgumentException + { + try + { + add(size(),o); + return true; + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + } + + public abstract Object get(int index) throws IndexOutOfBoundsException; + + public Object set(int index,Object element) throws UnsupportedOperationException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException + { + throw new UnsupportedOperationException(); + } + + public void add(int index,Object element) throws UnsupportedOperationException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException + { + throw new UnsupportedOperationException(); + } + + public Object remove(int index) throws UnsupportedOperationException, IndexOutOfBoundsException + { + Object o = get(index); + + removeRange(index,index+1); + return o; + } + + public int indexOf(Object o) + { + ListIterator li = listIterator(); + Object e; + while(li.hasNext()) + { + int index=li.nextIndex(); + e=li.next(); + System.out.println(e); + if(o==null) + { + if(e==null) + return index; + } + else + { + if(o.equals(e)) + return index; + } + } + return -1; + } + + public int lastIndexOf(Object o) + { + ListIterator li=listIterator(size()); + while(li.hasPrevious()) + { + int index=li.previousIndex(); + Object e=li.previous(); + if(o==null) + { + if(e==null) + return index; + } + else + { + if(o.equals(e)) + return index; + } + } + return -1; + } + + public void clear() throws UnsupportedOperationException + { + try + { + removeRange(0,size()); + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + } + + public boolean addAll(int index,Collection c) throws UnsupportedOperationException, ClassCastException, IllegalArgumentException, IndexOutOfBoundsException + { + Iterator it=c.iterator(); + boolean ret=false; + while(it.hasNext()) + { + try + { + add(index++,it.next()); + ret=true; + } + catch(UnsupportedOperationException ue) + { + throw ue; + } + } + return ret; + } + + public Iterator iterator() + { + return new AbstractListIterator(this,0); + } + + public ListIterator listIterator() + { + return listIterator(0); + } + + public ListIterator listIterator(int index) throws IndexOutOfBoundsException + { + if(index<0||index>size()) throw new IndexOutOfBoundsException(); + return new AbstractListListIterator(this,index); + } + + public List subList(int fromIndex,int toIndex) throws IndexOutOfBoundsException,IllegalArgumentException + { + if(fromIndex < 0 || toIndex > size()) + throw new IndexOutOfBoundsException(); + if(fromIndex>toIndex) + throw new IllegalArgumentException(); + return (List) new Sublist(this,fromIndex,toIndex); + } + + public boolean equals(Object o) + { + if(o==this) + return true; + if(!(o instanceof List)) + return false; + Iterator it1=iterator(); + Iterator it2=((List)o).iterator(); + while(it1.hasNext()) + { + if(!it2.hasNext()) + return false; + Object e1=it1.next(); + Object e2=it2.next(); + if(e1==null) + { + if(e2!=null) + return false; + } + if(!e1.equals(e2)) + return false; + } + return true; + } + + public int hashCode() + { + int hashCode = 1; + Iterator it = iterator(); + while (it.hasNext()) + { + Object o = it.next(); + hashCode = 31*hashCode + (o==null ? 0 : o.hashCode()); + } + return hashCode; + } + + protected void removeRange(int fromIndex,int toIndex) + { + System.out.println("breakpoint 1"); + if(fromIndex==toIndex) return; + System.out.println("breakpoint 2"); + ListIterator li=listIterator(fromIndex); + System.out.println("breakpoint 3"); + int i=fromIndex; + do + { + li.next(); + li.remove(); + i++; + }while(li.hasNext()&&i<toIndex); + } + +//////////////////////////////////////////////////////////// +/////////////innere Klasse AbstractIterator///////////////// +//////////////////////////////////////////////////////////// + +private class AbstractListIterator implements Iterator + { + AbstractList m_al=null; + int m_nextIndex=0; + public AbstractListIterator(AbstractList al,int index) + { + m_al=al; + m_nextIndex=index; + } + + public boolean hasNext() + { + return m_nextIndex < m_al.size(); + } + + public Object next() + { + return m_al.get(m_nextIndex++); + } + + public void remove() + { + m_al.remove(m_nextIndex - 1); + } + } + +/////////////////////////////////////////////////////////////////////////////// +//////////// innere Klasse AbstraktListListIterator +/////////////////////////////////////////////////////////////////////////////// + + +private class AbstractListListIterator extends AbstractListIterator implements ListIterator + { + public AbstractListListIterator(AbstractList al,int index) + { + super(al,index); + } + + public boolean hasPrevious() + { + return m_nextIndex>0; + } + + public Object previous()// throws NoSuchElementException; + { + return m_al.get(--m_nextIndex); + } + + public int nextIndex() + { + return m_nextIndex; + } + + public int previousIndex() + { + return m_nextIndex-1; + } + + public void set(Object o) //throws UnsupportedOperationException, ClassCastException, IllegalArgumentException,IllegalStateException; + { + m_al.set(m_nextIndex-1,o); + } + + public void add(Object o)// throws UnsupportedOperationException, ClassCastException, IllegalArgumentException; + { + m_al.add(m_nextIndex-1,o); + } + } + + +} diff --git a/core/src/main/jdk1.1/java/util/AbstractMap.java b/core/src/main/jdk1.1/java/util/AbstractMap.java new file mode 100644 index 00000000..d5b2e02e --- /dev/null +++ b/core/src/main/jdk1.1/java/util/AbstractMap.java @@ -0,0 +1,164 @@ +package java.util; + +/************* + * Title: + * Description: + * Copyright: Copyright (c) 2001 + * Company: + * @version 1.0 + */ + +public abstract class AbstractMap implements Map{ + + protected AbstractMap() + { + } + + public int size() + { + return entrySet().size(); + } + + public boolean isEmpty() + { + return size()==0; + } + + public boolean containsValue(Object value) + { + Iterator it=entrySet().iterator(); + while(it.hasNext()) + { + Map.Entry v=(Map.Entry)it.next(); + if(value==null) + { + if(v.getValue()==null) + return true; + } + else + { + if(value.equals(v.getValue())) + return true; + } + } + return false; + } + + public boolean containsKey(Object key) throws ClassCastException,NullPointerException + { + Iterator it=entrySet().iterator(); + while(it.hasNext()) + { + Map.Entry v=(Map.Entry)it.next(); + if(key==null) + { + if(v.getKey()==null) + return true; + } + else + { + if(key.equals(v.getKey())) + return true; + } + } + return false; + } + + public Object get(Object key)throws ClassCastException,NullPointerException + { + Iterator it=entrySet().iterator(); + while(it.hasNext()) + { + Map.Entry v=(Map.Entry)it.next(); + if(key==null) + { + if(v.getKey()==null) + return v.getValue(); + } + else + { + if(key.equals(v.getKey())) + return v.getValue(); + } + } + return null; + } + + public Object put(Object key,Object value) throws UnsupportedOperationException + { + throw new UnsupportedOperationException(); + } + + public Object remove(Object key) + { + Iterator it=entrySet().iterator(); + Object o=null; + while(it.hasNext()) + { + Map.Entry v=(Map.Entry)it.next(); + if(key==null) + { + if(v.getKey()==null) + { + o=v.getValue(); + it.remove(); + return o; + } + } + else + { + if(key.equals(v.getKey())) + { + o=v.getValue(); + it.remove(); + return o; + } + } + } + return null; + } + + public void putAll(Map t) + { + Iterator it=t.entrySet().iterator(); + while(it.hasNext()) + { + Map.Entry v=(Map.Entry)it.next(); + put(v.getKey(),v.getValue()); + } + } + + public void clear() + { + entrySet().clear(); + } + + public Set keySet() + { + throw new UnsupportedOperationException("no keySet in AbstractMap()"); + } + + public Collection values() + { + throw new UnsupportedOperationException("no values in AbstractMap()"); + } + + public abstract Set entrySet(); + + public boolean equals(Object o) + { + throw new UnsupportedOperationException("no equals in AbstractMap()"); + } + + public int hashCode() + { + throw new UnsupportedOperationException("no hashCode in AbstractMap()"); + } + + public String toString() + { + throw new UnsupportedOperationException("no toString in AbstractMap()"); + } + + +} diff --git a/core/src/main/jdk1.1/java/util/AbstractSet.java b/core/src/main/jdk1.1/java/util/AbstractSet.java new file mode 100644 index 00000000..45bbb22f --- /dev/null +++ b/core/src/main/jdk1.1/java/util/AbstractSet.java @@ -0,0 +1,42 @@ +package java.util; + +/** + * Title: + * Description: + * Copyright: Copyright (c) 2001 + * Company: + * @version 1.0 + */ + +public abstract class AbstractSet extends AbstractCollection implements Set + { + protected AbstractSet() + { + } + + public boolean equals(Object o) + { + if(this==o) + return true; + if(o==null) + return false; + if(!(o instanceof Set)) + return false; + if(((Set)o).size()!=size()) + return false; + return containsAll((Collection)o); + } + + public int hashCode() + { + int hashCode=0; + Iterator it=iterator(); + while(it.hasNext()) + { + Object o=it.next(); + if(o!=null) + hashCode+=o.hashCode(); + } + return hashCode; + } + } diff --git a/core/src/main/jdk1.1/java/util/ArrayList.java b/core/src/main/jdk1.1/java/util/ArrayList.java new file mode 100644 index 00000000..7e3cbbc3 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/ArrayList.java @@ -0,0 +1,107 @@ +package java.util; + +public class ArrayList extends AbstractList + implements List + { + Vector m_Vector=null; + + public ArrayList() + { + m_Vector=new Vector(); + } + + public ArrayList(Collection c) + { + m_Vector=new Vector((int)(c.size()*1.1)); + addAll(c); + } + + public ArrayList(int initialCapacity) + { + m_Vector=new Vector(initialCapacity); + } + + public void trimToSize() + { + m_Vector.trimToSize(); + } + + public void ensureCapacity(int minCapacity) + { + m_Vector.ensureCapacity(minCapacity); + } + + public int size() + { + return m_Vector.size(); + } + + public boolean contains(Object elem) + { + return m_Vector.contains(elem); + } + + public int indexOf(Object elem) + { + return m_Vector.indexOf(elem); + } + + public int lastIndexOf(Object elem) + { + return m_Vector.lastIndexOf(elem); + } + + public Object clone() + { + ArrayList al=new ArrayList(); + al.m_Vector=(Vector)m_Vector.clone(); + return al; + } + + public Object[] toArray() + { + Object[] o=new Object[m_Vector.size()]; + m_Vector.copyInto(o); + return o; + } + + public Object get(int index) + { + return m_Vector.elementAt(index); + } + + public Object set(int index,Object elem) + { + Object o=m_Vector.elementAt(index); + m_Vector.setElementAt(elem,index); + return o; + } + + public boolean add(Object o) + { + m_Vector.addElement(o); + return true; + } + + public void add(int index,Object elem) + { + m_Vector.insertElementAt(elem,index); + } + + public Object remove(int index) + { + Object o=m_Vector.elementAt(index); + m_Vector.removeElementAt(index); + return o; + } + + public void clear() + { + m_Vector.removeAllElements(); + } + + + + + + } diff --git a/core/src/main/jdk1.1/java/util/Arrays.java b/core/src/main/jdk1.1/java/util/Arrays.java new file mode 100644 index 00000000..0591e8d7 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/Arrays.java @@ -0,0 +1,90 @@ +package java.util; + +public class Arrays +{ + + private Arrays() {} + + public static void fill(byte[] ret, byte v) + { + for (int i = 0; i != ret.length; i++) + { + ret[i] = v; + } + } + + public static boolean equals(byte[] a, byte[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + for (int i=0; i<length; i++) + if (a[i] != a2[i]) + return false; + + return true; + } + public static List asList(Object[] a) { + return new ArrayList(a); + } + + private static class ArrayList extends AbstractList implements java.io.Serializable + { + private Object[] a; + + ArrayList(Object[] array) + { + a = array; + } + + public int size() + { + return a.length; + } + + public Object[] toArray() + { + return (Object[]) a.clone(); + } + + public Object get(int index) + { + return a[index]; + } + + public Object set(int index, Object element) + { + Object oldValue = a[index]; + a[index] = element; + return oldValue; + } + + public int indexOf(Object o) + { + if (o==null) + { + for (int i=0; i<a.length; i++) + if (a[i]==null) + return i; + } + else + { + for (int i=0; i<a.length; i++) + if (o.equals(a[i])) + return i; + } + return -1; + } + + public boolean contains(Object o) + { + return indexOf(o) != -1; + } + } + +} diff --git a/core/src/main/jdk1.1/java/util/Collection.java b/core/src/main/jdk1.1/java/util/Collection.java new file mode 100644 index 00000000..650eeb85 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/Collection.java @@ -0,0 +1,21 @@ + +package java.util; + +public interface Collection + { + public boolean add(Object o) throws UnsupportedOperationException,ClassCastException,IllegalArgumentException; + public boolean addAll(Collection c) throws UnsupportedOperationException,ClassCastException,IllegalArgumentException; + public void clear() throws UnsupportedOperationException; + public boolean contains(Object o); + public boolean containsAll(Collection c); + public boolean equals(Object o); + public int hashCode(); + public boolean isEmpty(); + public Iterator iterator(); + public /*SK13*/boolean remove(Object o) throws UnsupportedOperationException; + public boolean removeAll(Collection c) throws UnsupportedOperationException; + public boolean retainAll(Collection c) throws UnsupportedOperationException; + public int size(); + public Object[] toArray(); + public Object[] toArray(Object[] a) throws ArrayStoreException; + } diff --git a/core/src/main/jdk1.1/java/util/Collections.java b/core/src/main/jdk1.1/java/util/Collections.java new file mode 100644 index 00000000..1b7f2e93 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/Collections.java @@ -0,0 +1,376 @@ +package java.util; + +import java.io.Serializable; + +public class Collections +{ + public static List EMPTY_LIST = new ArrayList(); + + private Collections() + { + } + + public static Collection unmodifiableCollection(Collection c) + { + return new UnmodifiableCollection(c); + } + + static class UnmodifiableCollection + implements Collection, Serializable + { + Collection c; + + UnmodifiableCollection(Collection c) + { + this.c = c; + } + + public int size() + { + return c.size(); + } + + public boolean isEmpty() + { + return c.isEmpty(); + } + + public boolean contains(Object o) + { + return c.contains(o); + } + + public Object[] toArray() + { + return c.toArray(); + } + + public Object[] toArray(Object[] a) + { + return c.toArray(a); + } + + public Iterator iterator() + { + return new Iterator() + { + Iterator i = c.iterator(); + + public boolean hasNext() + { + return i.hasNext(); + } + + public Object next() + { + return i.next(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + + public boolean add(Object o) + { + throw new UnsupportedOperationException(); + } + + public boolean remove(Object o) + { + throw new UnsupportedOperationException(); + } + + public boolean containsAll(Collection coll) + { + return c.containsAll(coll); + } + + public boolean addAll(Collection coll) + { + throw new UnsupportedOperationException(); + } + + public boolean removeAll(Collection coll) + { + throw new UnsupportedOperationException(); + } + + public boolean retainAll(Collection coll) + { + throw new UnsupportedOperationException(); + } + + public void clear() + { + throw new UnsupportedOperationException(); + } + + public String toString() + { + return c.toString(); + } + } + + public static Set unmodifiableSet(Set s) + { + return new UnmodifiableSet(s); + } + + static class UnmodifiableSet + extends UnmodifiableCollection + implements Set, Serializable + { + UnmodifiableSet(Set s) + { + super(s); + } + + public boolean equals(Object o) + { + return c.equals(o); + } + + public int hashCode() + { + return c.hashCode(); + } + } + + public static List unmodifiableList(List list) + { + return new UnmodifiableList(list); + } + + static class UnmodifiableList + extends UnmodifiableCollection + implements List + { + private List list; + + UnmodifiableList(List list) + { + super(list); + this.list = list; + } + + public boolean equals(Object o) + { + return list.equals(o); + } + + public int hashCode() + { + return list.hashCode(); + } + + public Object get(int index) + { + return list.get(index); + } + + public Object set(int index, Object element) + { + throw new UnsupportedOperationException(); + } + + public void add(int index, Object element) + { + throw new UnsupportedOperationException(); + } + + public Object remove(int index) + { + throw new UnsupportedOperationException(); + } + + public int indexOf(Object o) + { + return list.indexOf(o); + } + + public int lastIndexOf(Object o) + { + return list.lastIndexOf(o); + } + + public boolean addAll(int index, Collection c) + { + throw new UnsupportedOperationException(); + } + + public ListIterator listIterator() + { + return listIterator(0); + } + + public ListIterator listIterator(final int index) + { + return new ListIterator() + { + ListIterator i = list.listIterator(index); + + public boolean hasNext() + { + return i.hasNext(); + } + + public Object next() + { + return i.next(); + } + + public boolean hasPrevious() + { + return i.hasPrevious(); + } + + public Object previous() + { + return i.previous(); + } + + public int nextIndex() + { + return i.nextIndex(); + } + + public int previousIndex() + { + return i.previousIndex(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + + public void set(Object o) + { + throw new UnsupportedOperationException(); + } + + public void add(Object o) + { + throw new UnsupportedOperationException(); + } + }; + } + + public List subList(int fromIndex, int toIndex) + { + return new UnmodifiableList(list.subList(fromIndex, toIndex)); + } + } + + public static Enumeration enumeration(final Collection c) + { + return new Enumeration() + { + Iterator i = c.iterator(); + + public boolean hasMoreElements() + { + return i.hasNext(); + } + + public Object nextElement() + { + return i.next(); + } + }; + } + + public static Map unmodifiableMap(Map s) + { + return new UnmodifiableMap(s); + } + + static class UnmodifiableMap + implements Map + { + private Map c; + + UnmodifiableMap(Map map) + { + this.c = map; + } + + public int size() + { + return c.size(); + } + + public boolean isEmpty() + { + return c.isEmpty(); + } + + public boolean containsKey(Object o) + { + return c.containsKey(o); + } + + public boolean containsValue(Object o) + { + return c.containsValue(o); + } + + public Object get(Object o) + { + return c.get(o); + } + + public Object put(Object o, Object o2) + { + throw new UnsupportedOperationException(); + } + + public Object remove(Object o) + { + throw new UnsupportedOperationException(); + } + + public void putAll(Map map) + { + throw new UnsupportedOperationException(); + } + + public void clear() + { + throw new UnsupportedOperationException(); + } + + public Set keySet() + { + return Collections.unmodifiableSet(c.keySet()); + } + + public Collection values() + { + return new UnmodifiableCollection(c.values()); + } + + public Set entrySet() + { + return Collections.unmodifiableSet(c.entrySet()); + } + + public boolean equals(Object o) + { + return c.equals(o); + } + + public int hashCode() + { + return c.hashCode(); + } + + public String toString() + { + return c.toString(); + } + } +} diff --git a/core/src/main/jdk1.1/java/util/HashMap.java b/core/src/main/jdk1.1/java/util/HashMap.java new file mode 100644 index 00000000..e9bdbda5 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/HashMap.java @@ -0,0 +1,285 @@ +package java.util; + + +public class HashMap extends AbstractMap{ + + ////////////////////////////////////////////////////////////// + ///// innere Klasse Null //////////////////////////////////// + ////////////////////////////////////////////////////////////// +public class Null extends Object + { + public Null() + { + + } + + public String toString() + { + return "Nullobject"; + } + } + + + ////////////////////////////////////////////////////////////// + ///// innere Klasse innerSet //////////////////////////////////// + ////////////////////////////////////////////////////////////// + + class ISet extends AbstractSet implements java.util.Set + { + + Vector vec = null; + + public ISet() + { + + vec = new Vector(); + + } + + public boolean add(Object o) + { + vec.addElement(o); + return true; + } + + public int size() + { + return vec.size(); + } + + public Iterator iterator() + { + return new IIterator(vec); + } + } + + ////////////////////////////////////////////////////////////// + ///// innere Klasse Iterator //////////////////////////////////// + ////////////////////////////////////////////////////////////// + class IIterator implements java.util.Iterator + { + int index = 0; + Vector vec = null; + public IIterator(Vector ve) + { + vec = ve; + } + + public boolean hasNext() + { + if (vec.size() > index) return true; + return false; + } + + public Object next() + { + Object o = vec.elementAt(index); + if (o==Nullobject) o=null; + index++; + return o; + + } + + public void remove() + { + index--; + vec.removeElementAt(index); + } + + } + + ////////////////////////////////////////////////////////////// + ///// innere Klasse Entry //////////////////////////////////// + ////////////////////////////////////////////////////////////// + + + class Entry implements Map.Entry + { + public Object key=null; + public Object value=null; + + public Entry(Object ke,Object valu) + { + key = ke; + value = valu; + } + public boolean equals(Object o) + { + if (value == ((Entry)o).value && key == ((Entry)o).key ) return true; + else return false; + + } + + public Object getValue() + { + return value; + } + + public Object getKey() + { + return (Object)key; + } + + public int hashCode() + { + return value.hashCode() + key.hashCode(); + + } + + public Object setValue(Object valu) + { + value = (String)valu; + return this; + } + } + + //////////////////////////////////////////////////////////////////// + + private Hashtable m_HashTable=null; + private Null Nullobject = null; + + public HashMap() + { + Nullobject = new Null(); + m_HashTable=new Hashtable(); + } + + public HashMap(int initialCapacity) + { + Nullobject = new Null(); + m_HashTable=new Hashtable(initialCapacity); + } + + public HashMap(int initialCapacity, float loadFactor) + { + Nullobject = new Null(); + m_HashTable=new Hashtable(initialCapacity, loadFactor); + } + + public HashMap(Map t) + { + Nullobject = new Null(); + m_HashTable=new Hashtable(); + this.putAll(t); + } + + public void clear() + { + m_HashTable.clear(); + } + + public Object clone() + { + HashMap hm=new HashMap(); + hm.m_HashTable=(Hashtable)m_HashTable.clone(); + return hm; + } + + public boolean containsKey(Object key) + { + if (key == null) key = Nullobject; + boolean b = m_HashTable.containsKey(key); + return b; + + } + + public boolean containsValue(Object value) + { + if (value == null ) value = Nullobject; + boolean b = m_HashTable.contains(value); + return b; + } + + public Set entrySet() + { + + Object Key = null; + ISet s = new ISet(); + Enumeration enum = m_HashTable.keys(); + while (enum.hasMoreElements()) + { + Key = enum.nextElement(); + s.add(new Entry(Key,m_HashTable.get(Key))); + } + return s; + } + + public Object get(Object key) + { + + if (key==null) key= Nullobject; + + Object o = m_HashTable.get(key); + + if (o == Nullobject) o=null; + + return o; + } + + public boolean isEmpty() + { + return m_HashTable.isEmpty(); + } + + public Set keySet() + { + ISet s=new ISet(); + Enumeration enum = m_HashTable.keys(); + + while (enum.hasMoreElements()) + { + s.add(enum.nextElement()); + } + + return s; + } + + public Object put(Object key, Object value) + { + if (key==null) key=Nullobject; + if (value==null) value = Nullobject; + return m_HashTable.put(key,value); + } + + public void putAll(Map m) + { + Iterator it = m.entrySet().iterator(); + Object key=null; + Object value=null; + + while (it.hasNext()) + { + Map.Entry me = (Map.Entry)it.next(); + if (me.getKey() == null) key = Nullobject; + else key= me.getKey(); + if (me.getValue()==null) value = Nullobject; + else value = me.getValue(); + m_HashTable.put(key,value); + } + } + + public Object remove(Object key) + { + return m_HashTable.remove(key); + } + + public int size() + { + return m_HashTable.size(); + } + + public Collection values() + { + + ISet s=new ISet(); + Enumeration enum = m_HashTable.keys(); + + while (enum.hasMoreElements()) + { + Object Key = enum.nextElement(); + //s.add(((Map.Entry)m_HashTable.get(Key)).getValue()); + s.add(m_HashTable.get(Key)); + } + return s; + } +} diff --git a/core/src/main/jdk1.1/java/util/HashSet.java b/core/src/main/jdk1.1/java/util/HashSet.java new file mode 100644 index 00000000..5721cd20 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/HashSet.java @@ -0,0 +1,83 @@ +package java.util; + +import java.io.*; +///*sk13*/import java.util.Hashtable; + +public class HashSet extends /*sk13*/AbstractSet + /*sk13*/ /*extends Hashmap*/ + +{ + private HashMap m_HashMap=null; + + public HashSet() + { + m_HashMap=new HashMap(); + + } + + public HashSet(Collection c) + { + m_HashMap=new HashMap(Math.max(11,c.size()*2)); + addAll(c); + + } + + public HashSet(int initialCapacity, float loadFactor) + { + m_HashMap=new HashMap(initialCapacity,loadFactor); + + } + + public HashSet(int initialCapacity) + { + m_HashMap=new HashMap(initialCapacity); + + } + + public Iterator iterator() + { + return (m_HashMap.keySet()).iterator(); + } + + public int size() + { + return m_HashMap.size(); + } + + public boolean contains(Object o) + { + return m_HashMap.containsKey(o); + } + + public boolean add(Object o) + { + if (!m_HashMap.containsValue(o)) + { + m_HashMap.put(o, o); + + return true; + + } + + return false; + } + + public boolean remove(Object o) + { + return (m_HashMap.remove(o)!=null); + } + + public void clear() + { + m_HashMap.clear(); + } + + + public Object clone() + { + HashSet hs=new HashSet(); + hs.m_HashMap=(HashMap)m_HashMap.clone(); + return hs; + } + +} diff --git a/core/src/main/jdk1.1/java/util/Iterator.java b/core/src/main/jdk1.1/java/util/Iterator.java new file mode 100644 index 00000000..9f977fe8 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/Iterator.java @@ -0,0 +1,9 @@ + +package java.util; + +public interface Iterator +{ + public abstract boolean hasNext(); + public abstract Object next() throws NoSuchElementException; + public abstract void remove() throws UnsupportedOperationException,IllegalStateException; +} diff --git a/core/src/main/jdk1.1/java/util/List.java b/core/src/main/jdk1.1/java/util/List.java new file mode 100644 index 00000000..ee5896ea --- /dev/null +++ b/core/src/main/jdk1.1/java/util/List.java @@ -0,0 +1,15 @@ +package java.util; + +public interface List extends Collection + { + void add(int index, Object element)throws UnsupportedOperationException,ClassCastException,IllegalArgumentException,IndexOutOfBoundsException; + boolean addAll(int index, Collection c) throws UnsupportedOperationException,ClassCastException,IllegalArgumentException,IndexOutOfBoundsException; + Object get(int index) throws IndexOutOfBoundsException; + int indexOf(Object o); + int lastIndexOf(Object o); + ListIterator listIterator(); + ListIterator listIterator(int index)throws IndexOutOfBoundsException; + Object remove(int index)throws UnsupportedOperationException,IndexOutOfBoundsException; + Object set(int index, Object element) throws UnsupportedOperationException,ClassCastException,IllegalArgumentException,IndexOutOfBoundsException; + List subList(int fromIndex, int toIndex) throws IndexOutOfBoundsException; + } diff --git a/core/src/main/jdk1.1/java/util/ListIterator.java b/core/src/main/jdk1.1/java/util/ListIterator.java new file mode 100644 index 00000000..15e17896 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/ListIterator.java @@ -0,0 +1,19 @@ +package java.util; + +/** + * Title: + * Description: + * Copyright: Copyright (c) 2001 + * Company: + * @version 1.0 + */ + +public interface ListIterator extends Iterator + { + public boolean hasPrevious(); + public Object previous() throws NoSuchElementException; + public int nextIndex(); + public int previousIndex(); + public void set(Object o) throws UnsupportedOperationException, ClassCastException, IllegalArgumentException,IllegalStateException; + public void add(Object o) throws UnsupportedOperationException, ClassCastException, IllegalArgumentException; + } diff --git a/core/src/main/jdk1.1/java/util/Map.java b/core/src/main/jdk1.1/java/util/Map.java new file mode 100644 index 00000000..e0040a38 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/Map.java @@ -0,0 +1,37 @@ +package java.util; + +/** + * Title: + * Description: + * Copyright: Copyright (c) 2001 + * Company: + * @version 1.0 + */ + +public interface Map { + + public static interface Entry + { + public Object getKey(); + public Object getValue(); + public Object setValue(Object value) throws UnsupportedOperationException, ClassCastException,IllegalArgumentException,NullPointerException; + public boolean equals(Object o); + public int hashCode(); + }; + + public int size(); + public boolean isEmpty(); + public boolean containsKey(Object Key) throws ClassCastException,NullPointerException; + public boolean containsValue(Object value); + public Object get(Object key)throws ClassCastException,NullPointerException; + public Object put(Object key,Object value)throws UnsupportedOperationException, ClassCastException,IllegalArgumentException,NullPointerException; + public Object remove(Object key)throws UnsupportedOperationException; + public void putAll(Map t)throws UnsupportedOperationException, ClassCastException,IllegalArgumentException,NullPointerException; + public void clear()throws UnsupportedOperationException; + public Set keySet(); + public Collection values(); + public Set entrySet(); + public boolean equals(Object o); + public int hashCode(); + + } diff --git a/core/src/main/jdk1.1/java/util/Set.java b/core/src/main/jdk1.1/java/util/Set.java new file mode 100644 index 00000000..e312d6b8 --- /dev/null +++ b/core/src/main/jdk1.1/java/util/Set.java @@ -0,0 +1,26 @@ + +package java.util; + +public interface Set extends Collection + { + + public int size(); + public boolean isEmpty(); + public boolean contains(Object o); + public Iterator iterator(); + public Object[] toArray(); + public Object[] toArray(Object[] a); + public boolean add(Object o); + public boolean remove(Object o); + public boolean containsAll(Collection c); + public boolean addAll(Collection c); + public boolean retainAll(Collection c); + public boolean removeAll(Collection c); + public void clear(); + public boolean equals(Object o); + public int hashCode(); + + + + + } diff --git a/core/src/main/jdk1.1/java/util/Sublist.java b/core/src/main/jdk1.1/java/util/Sublist.java new file mode 100644 index 00000000..3f1a4a1b --- /dev/null +++ b/core/src/main/jdk1.1/java/util/Sublist.java @@ -0,0 +1,125 @@ +package java.util; + +/** + * Title: + * Description: + * Copyright: Copyright (c) 2001 + * Company: + * @version 1.0 + */ + +public class Sublist extends AbstractList + + { + AbstractList m_al=null; + int m_fromIndex=0; + int m_toIndex=0; + int size=0; + + public Sublist(AbstractList ali,int fromIndex,int toIndex) + { + m_al=ali; + m_toIndex=toIndex; + m_fromIndex=fromIndex; + size = size(); + } + public Object set(int index,Object o) + { + if (index < size) + { + o = m_al.set(index+m_fromIndex,o); + if (o != null) + { + size++; + m_toIndex++; + } + return o; + } + else throw new IndexOutOfBoundsException(); + } + + public Object get(int index) throws IndexOutOfBoundsException + { + if (index < size) return m_al.get(index+m_fromIndex); + else throw new IndexOutOfBoundsException(); + } + + public void add (int index,Object o) + { + + if (index <= size) + { + m_al.add(index + m_fromIndex,o); + m_toIndex++; + size++; + + } + else throw new IndexOutOfBoundsException(); + + } + + public Object remove(int index,Object o) + { + if (index < size) + { + Object ob = m_al.remove(index + m_fromIndex); + if (ob !=null) + { + m_toIndex--; + size--; + } + return ob; + } + else throw new IndexOutOfBoundsException(); + } + + public boolean addAll(int index, Collection c) + { + if (index < size) + { + boolean bool = m_al.addAll(index + m_fromIndex,c); + if (bool) + { + int lange = c.size(); + m_toIndex = m_toIndex + lange; + size = size + lange; + } + return bool; + } + else throw new IndexOutOfBoundsException(); + } + + public boolean addAll(Collection c) + { + boolean bool = m_al.addAll(m_toIndex,c); + if (bool) + { + int lange = c.size(); + m_toIndex = m_toIndex + lange; + size = size + lange; + } + return bool; + } + + public void removeRange (int from,int to) + { + if ((from <= to) && (from <= size) && (to <= size)) + { + m_al.removeRange(from,to); + int lange = to - from; + m_toIndex = m_toIndex - lange; + size = size - lange; + } + else + { + if (from > to) throw new IllegalArgumentException(); + else throw new IndexOutOfBoundsException(); + } + } + + public int size() + { + return (m_toIndex - m_fromIndex); + } + +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/asn1/ASN1InputStream.java b/core/src/main/jdk1.1/org/bouncycastle/asn1/ASN1InputStream.java new file mode 100644 index 00000000..cec37898 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/asn1/ASN1InputStream.java @@ -0,0 +1,466 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.util.io.Streams; + +/** + * a general purpose ASN.1 decoder - note: this class differs from the + * others in that it returns null after it has read the last object in + * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is + * returned. + */ +public class ASN1InputStream + extends FilterInputStream + implements BERTags +{ + private int limit; + private boolean lazyEvaluate; + + private byte[][] tmpBuffers; + + public ASN1InputStream( + InputStream is) + { + this(is, StreamUtil.findLimit(is)); + } + + /** + * Create an ASN1InputStream based on the input byte array. The length of DER objects in + * the stream is automatically limited to the length of the input array. + * + * @param input array containing ASN.1 encoded data. + */ + public ASN1InputStream( + byte[] input) + { + this(new ByteArrayInputStream(input), input.length); + } + + /** + * Create an ASN1InputStream based on the input byte array. The length of DER objects in + * the stream is automatically limited to the length of the input array. + * + * @param input array containing ASN.1 encoded data. + * @param lazyEvaluate true if parsing inside constructed objects can be delayed. + */ + public ASN1InputStream( + byte[] input, + boolean lazyEvaluate) + { + this(new ByteArrayInputStream(input), input.length, lazyEvaluate); + } + + /** + * Create an ASN1InputStream where no DER object will be longer than limit. + * + * @param input stream containing ASN.1 encoded data. + * @param limit maximum size of a DER encoded object. + */ + public ASN1InputStream( + InputStream input, + int limit) + { + this(input, limit, false); + } + + /** + * Create an ASN1InputStream where no DER object will be longer than limit, and constructed + * objects such as sequences will be parsed lazily. + * + * @param input stream containing ASN.1 encoded data. + * @param lazyEvaluate true if parsing inside constructed objects can be delayed. + */ + public ASN1InputStream( + InputStream input, + boolean lazyEvaluate) + { + this(input, StreamUtil.findLimit(input), lazyEvaluate); + } + + /** + * Create an ASN1InputStream where no DER object will be longer than limit, and constructed + * objects such as sequences will be parsed lazily. + * + * @param input stream containing ASN.1 encoded data. + * @param limit maximum size of a DER encoded object. + * @param lazyEvaluate true if parsing inside constructed objects can be delayed. + */ + public ASN1InputStream( + InputStream input, + int limit, + boolean lazyEvaluate) + { + super(input); + this.limit = limit; + this.lazyEvaluate = lazyEvaluate; + this.tmpBuffers = new byte[11][]; + } + + int getLimit() + { + return limit; + } + + protected int readLength() + throws IOException + { + return readLength(this, limit); + } + + protected void readFully( + byte[] bytes) + throws IOException + { + if (Streams.readFully(this, bytes) != bytes.length) + { + throw new EOFException("EOF encountered in middle of object"); + } + } + + /** + * build an object given its tag and the number of bytes to construct it from. + */ + protected ASN1Primitive buildObject( + int tag, + int tagNo, + int length) + throws IOException + { + boolean isConstructed = (tag & CONSTRUCTED) != 0; + + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length); + + if ((tag & APPLICATION) != 0) + { + return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + } + + if ((tag & TAGGED) != 0) + { + return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo); + } + + if (isConstructed) + { + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagNo) + { + case OCTET_STRING: + // + // yes, people actually do this... + // + ASN1EncodableVector v = buildDEREncodableVector(defIn); + ASN1OctetString[] strings = new ASN1OctetString[v.size()]; + + for (int i = 0; i != strings.length; i++) + { + strings[i] = (ASN1OctetString)v.get(i); + } + + return new BEROctetString(strings); + case SEQUENCE: + if (lazyEvaluate) + { + return new LazyEncodedSequence(defIn.toByteArray()); + } + else + { + return DERFactory.createSequence(buildDEREncodableVector(defIn)); + } + case SET: + return DERFactory.createSet(buildDEREncodableVector(defIn)); + case EXTERNAL: + return new DERExternal(buildDEREncodableVector(defIn)); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } + + return createPrimitiveDERObject(tagNo, defIn, tmpBuffers); + } + + ASN1EncodableVector buildEncodableVector() + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1Primitive o; + + while ((o = readObject()) != null) + { + v.add(o); + } + + return v; + } + + ASN1EncodableVector buildDEREncodableVector( + DefiniteLengthInputStream dIn) throws IOException + { + return new ASN1InputStream(dIn).buildEncodableVector(); + } + + public ASN1Primitive readObject() + throws IOException + { + int tag = read(); + if (tag <= 0) + { + if (tag == 0) + { + throw new IOException("unexpected end-of-contents marker"); + } + + return null; + } + + // + // calculate tag number + // + int tagNo = readTagNumber(this, tag); + + boolean isConstructed = (tag & CONSTRUCTED) != 0; + + // + // calculate length + // + int length = readLength(); + + if (length < 0) // indefinite length method + { + if (!isConstructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit); + ASN1StreamParser sp = new ASN1StreamParser(indIn, limit); + + if ((tag & APPLICATION) != 0) + { + return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject(); + } + + if ((tag & TAGGED) != 0) + { + return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject(); + } + + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagNo) + { + case OCTET_STRING: + return new BEROctetStringParser(sp).getLoadedObject(); + case SEQUENCE: + return new BERSequenceParser(sp).getLoadedObject(); + case SET: + return new BERSetParser(sp).getLoadedObject(); + case EXTERNAL: + return new DERExternalParser(sp).getLoadedObject(); + default: + throw new IOException("unknown BER object encountered"); + } + } + else + { + try + { + return buildObject(tag, tagNo, length); + } + catch (IllegalArgumentException e) + { + throw new ASN1Exception("corrupted stream detected", e); + } + } + } + + static int readTagNumber(InputStream s, int tag) + throws IOException + { + int tagNo = tag & 0x1f; + + // + // with tagged object tag number is bottom 5 bits, or stored at the start of the content + // + if (tagNo == 0x1f) + { + tagNo = 0; + + int b = s.read(); + + // X.690-0207 8.1.2.4.2 + // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." + if ((b & 0x7f) == 0) // Note: -1 will pass + { + throw new IOException("corrupted stream - invalid high tag number found"); + } + + while ((b >= 0) && ((b & 0x80) != 0)) + { + tagNo |= (b & 0x7f); + tagNo <<= 7; + b = s.read(); + } + + if (b < 0) + { + throw new EOFException("EOF found inside tag value."); + } + + tagNo |= (b & 0x7f); + } + + return tagNo; + } + + static int readLength(InputStream s, int limit) + throws IOException + { + int length = s.read(); + if (length < 0) + { + throw new EOFException("EOF found when length expected"); + } + + if (length == 0x80) + { + return -1; // indefinite-length encoding + } + + if (length > 127) + { + int size = length & 0x7f; + + // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here + if (size > 4) + { + throw new IOException("DER length more than 4 bytes: " + size); + } + + length = 0; + for (int i = 0; i < size; i++) + { + int next = s.read(); + + if (next < 0) + { + throw new EOFException("EOF found reading length"); + } + + length = (length << 8) + next; + } + + if (length < 0) + { + throw new IOException("corrupted stream - negative length found"); + } + + if (length >= limit) // after all we must have read at least 1 byte + { + throw new IOException("corrupted stream - out of bounds length found"); + } + } + + return length; + } + + private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers) + throws IOException + { + int len = defIn.getRemaining(); + if (defIn.getRemaining() < tmpBuffers.length) + { + byte[] buf = tmpBuffers[len]; + + if (buf == null) + { + buf = tmpBuffers[len] = new byte[len]; + } + + Streams.readFully(defIn, buf); + + return buf; + } + else + { + return defIn.toByteArray(); + } + } + + private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn) + throws IOException + { + int len = defIn.getRemaining() / 2; + char[] buf = new char[len]; + int totalRead = 0; + while (totalRead < len) + { + int ch1 = defIn.read(); + if (ch1 < 0) + { + break; + } + int ch2 = defIn.read(); + if (ch2 < 0) + { + break; + } + buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff)); + } + + return buf; + } + + static ASN1Primitive createPrimitiveDERObject( + int tagNo, + DefiniteLengthInputStream defIn, + byte[][] tmpBuffers) + throws IOException + { + switch (tagNo) + { + case BIT_STRING: + return DERBitString.fromInputStream(defIn.getRemaining(), defIn); + case BMP_STRING: + return new DERBMPString(getBMPCharBuffer(defIn)); + case BOOLEAN: + return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers)); + case ENUMERATED: + return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers)); + case GENERALIZED_TIME: + return new ASN1GeneralizedTime(defIn.toByteArray()); + case GENERAL_STRING: + return new DERGeneralString(defIn.toByteArray()); + case IA5_STRING: + return new DERIA5String(defIn.toByteArray()); + case INTEGER: + return new ASN1Integer(defIn.toByteArray()); + case NULL: + return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?) + case NUMERIC_STRING: + return new DERNumericString(defIn.toByteArray()); + case OBJECT_IDENTIFIER: + return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers)); + case OCTET_STRING: + return new DEROctetString(defIn.toByteArray()); + case PRINTABLE_STRING: + return new DERPrintableString(defIn.toByteArray()); + case T61_STRING: + return new DERT61String(defIn.toByteArray()); + case UNIVERSAL_STRING: + return new DERUniversalString(defIn.toByteArray()); + case UTC_TIME: + return new ASN1UTCTime(defIn.toByteArray()); + case UTF8_STRING: + return new DERUTF8String(defIn.toByteArray()); + case VISIBLE_STRING: + return new DERVisibleString(defIn.toByteArray()); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/asn1/ASN1StreamParser.java b/core/src/main/jdk1.1/org/bouncycastle/asn1/ASN1StreamParser.java new file mode 100644 index 00000000..8ef5f3e6 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/asn1/ASN1StreamParser.java @@ -0,0 +1,247 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ASN1StreamParser +{ + private InputStream _in; + private int _limit; + private byte[][] tmpBuffers; + + public ASN1StreamParser( + InputStream in) + { + this(in, StreamUtil.findLimit(in)); + } + + public ASN1StreamParser( + InputStream in, + int limit) + { + this._in = in; + this._limit = limit; + + this.tmpBuffers = new byte[11][]; + } + + public ASN1StreamParser( + byte[] encoding) + { + this(new ByteArrayInputStream(encoding), encoding.length); + } + + ASN1Encodable readIndef(int tagValue) throws IOException + { + // Note: INDEF => CONSTRUCTED + + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagValue) + { + case BERTags.EXTERNAL: + return new DERExternalParser(this); + case BERTags.OCTET_STRING: + return new BEROctetStringParser(this); + case BERTags.SEQUENCE: + return new BERSequenceParser(this); + case BERTags.SET: + return new BERSetParser(this); + default: + throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue)); + } + } + + ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException + { + if (_in instanceof IndefiniteLengthInputStream) + { + if (!constructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + return readIndef(tag); + } + + if (constructed) + { + switch (tag) + { + case BERTags.SET: + return new DERSetParser(this); + case BERTags.SEQUENCE: + return new DERSequenceParser(this); + case BERTags.OCTET_STRING: + return new BEROctetStringParser(this); + } + } + else + { + switch (tag) + { + case BERTags.SET: + throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)"); + case BERTags.SEQUENCE: + throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)"); + case BERTags.OCTET_STRING: + return new DEROctetStringParser((DefiniteLengthInputStream)_in); + } + } + + // TODO ASN1Exception + throw new RuntimeException("implicit tagging not implemented"); + } + + ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException + { + if (!constructed) + { + // Note: !CONSTRUCTED => IMPLICIT + DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in; + return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray())); + } + + ASN1EncodableVector v = readVector(); + + if (_in instanceof IndefiniteLengthInputStream) + { + return v.size() == 1 + ? new BERTaggedObject(true, tag, v.get(0)) + : new BERTaggedObject(false, tag, BERFactory.createSequence(v)); + } + + return v.size() == 1 + ? new DERTaggedObject(true, tag, v.get(0)) + : new DERTaggedObject(false, tag, DERFactory.createSequence(v)); + } + + public ASN1Encodable readObject() + throws IOException + { + int tag = _in.read(); + if (tag == -1) + { + return null; + } + + // + // turn of looking for "00" while we resolve the tag + // + set00Check(false); + + // + // calculate tag number + // + int tagNo = ASN1InputStream.readTagNumber(_in, tag); + + boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0; + + // + // calculate length + // + int length = ASN1InputStream.readLength(_in, _limit); + + if (length < 0) // indefinite length method + { + if (!isConstructed) + { + throw new IOException("indefinite length primitive encoding encountered"); + } + + IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit); + ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit); + + if ((tag & BERTags.APPLICATION) != 0) + { + return new BERApplicationSpecificParser(tagNo, sp); + } + + if ((tag & BERTags.TAGGED) != 0) + { + return new BERTaggedObjectParser(true, tagNo, sp); + } + + return sp.readIndef(tagNo); + } + else + { + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); + + if ((tag & BERTags.APPLICATION) != 0) + { + return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + } + + if ((tag & BERTags.TAGGED) != 0) + { + return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn)); + } + + if (isConstructed) + { + // TODO There are other tags that may be constructed (e.g. BIT_STRING) + switch (tagNo) + { + case BERTags.OCTET_STRING: + // + // yes, people actually do this... + // + return new BEROctetStringParser(new ASN1StreamParser(defIn)); + case BERTags.SEQUENCE: + return new DERSequenceParser(new ASN1StreamParser(defIn)); + case BERTags.SET: + return new DERSetParser(new ASN1StreamParser(defIn)); + case BERTags.EXTERNAL: + return new DERExternalParser(new ASN1StreamParser(defIn)); + default: + throw new IOException("unknown tag " + tagNo + " encountered"); + } + } + + // Some primitive encodings can be handled by parsers too... + switch (tagNo) + { + case BERTags.OCTET_STRING: + return new DEROctetStringParser(defIn); + } + + try + { + return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers); + } + catch (IllegalArgumentException e) + { + throw new ASN1Exception("corrupted stream detected", e); + } + } + } + + private void set00Check(boolean enabled) + { + if (_in instanceof IndefiniteLengthInputStream) + { + ((IndefiniteLengthInputStream)_in).setEofOn00(enabled); + } + } + + ASN1EncodableVector readVector() throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + ASN1Encodable obj; + while ((obj = readObject()) != null) + { + if (obj instanceof InMemoryRepresentable) + { + v.add(((InMemoryRepresentable)obj).getLoadedObject()); + } + else + { + v.add(obj.toASN1Primitive()); + } + } + + return v; + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/asn1/DERApplicationSpecific.java b/core/src/main/jdk1.1/org/bouncycastle/asn1/DERApplicationSpecific.java new file mode 100644 index 00000000..2726d6e9 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/asn1/DERApplicationSpecific.java @@ -0,0 +1,276 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * Base class for an application specific object + */ +public class DERApplicationSpecific + extends ASN1Primitive +{ + private boolean isConstructed; + private int tag; + private byte[] octets; + + DERApplicationSpecific( + boolean isConstructed, + int tag, + byte[] octets) + { + this.isConstructed = isConstructed; + this.tag = tag; + this.octets = octets; + } + + public DERApplicationSpecific( + int tag, + byte[] octets) + { + this(false, tag, octets); + } + + public DERApplicationSpecific( + int tag, + ASN1Encodable object) + throws IOException + { + this(true, tag, object); + } + + public DERApplicationSpecific( + boolean explicit, + int tag, + ASN1Encodable object) + throws IOException + { + ASN1Primitive primitive = object.toASN1Primitive(); + + byte[] data = primitive.getEncoded(ASN1Encoding.DER); + + this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence); + this.tag = tag; + + if (explicit) + { + this.octets = data; + } + else + { + int lenBytes = getLengthOfHeader(data); + byte[] tmp = new byte[data.length - lenBytes]; + System.arraycopy(data, lenBytes, tmp, 0, tmp.length); + this.octets = tmp; + } + } + + public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec) + { + this.tag = tagNo; + this.isConstructed = true; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + for (int i = 0; i != vec.size(); i++) + { + try + { + bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER)); + } + catch (IOException e) + { + throw new ASN1ParsingException("malformed object: " + e, e); + } + } + this.octets = bOut.toByteArray(); + } + + public static DERApplicationSpecific getInstance(Object obj) + { + if (obj == null || obj instanceof DERApplicationSpecific) + { + return (DERApplicationSpecific)obj; + } + else if (obj instanceof byte[]) + { + try + { + return DERApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct object from byte[]: " + e.getMessage()); + } + } + else if (obj instanceof ASN1Encodable) + { + ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); + + if (primitive instanceof ASN1Sequence) + { + return (DERApplicationSpecific)primitive; + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + private int getLengthOfHeader(byte[] data) + { + int length = data[1] & 0xff; // TODO: assumes 1 byte tag + + if (length == 0x80) + { + return 2; // indefinite-length encoding + } + + if (length > 127) + { + int size = length & 0x7f; + + // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here + if (size > 4) + { + throw new IllegalStateException("DER length more than 4 bytes: " + size); + } + + return size + 2; + } + + return 2; + } + + public boolean isConstructed() + { + return isConstructed; + } + + public byte[] getContents() + { + return octets; + } + + public int getApplicationTag() + { + return tag; + } + + /** + * Return the enclosed object assuming explicit tagging. + * + * @return the resulting object + * @throws IOException if reconstruction fails. + */ + public ASN1Primitive getObject() + throws IOException + { + return new ASN1InputStream(getContents()).readObject(); + } + + /** + * Return the enclosed object assuming implicit tagging. + * + * @param derTagNo the type tag that should be applied to the object's contents. + * @return the resulting object + * @throws IOException if reconstruction fails. + */ + public ASN1Primitive getObject(int derTagNo) + throws IOException + { + if (derTagNo >= 0x1f) + { + throw new IOException("unsupported tag number"); + } + + byte[] orig = this.getEncoded(); + byte[] tmp = replaceTagNumber(derTagNo, orig); + + if ((orig[0] & BERTags.CONSTRUCTED) != 0) + { + tmp[0] |= BERTags.CONSTRUCTED; + } + + return new ASN1InputStream(tmp).readObject(); + } + + int encodedLength() + throws IOException + { + return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length; + } + + /* (non-Javadoc) + * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream) + */ + void encode(ASN1OutputStream out) throws IOException + { + int classBits = BERTags.APPLICATION; + if (isConstructed) + { + classBits |= BERTags.CONSTRUCTED; + } + + out.writeEncoded(classBits, tag, octets); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERApplicationSpecific)) + { + return false; + } + + DERApplicationSpecific other = (DERApplicationSpecific)o; + + return isConstructed == other.isConstructed + && tag == other.tag + && Arrays.areEqual(octets, other.octets); + } + + public int hashCode() + { + return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets); + } + + private byte[] replaceTagNumber(int newTag, byte[] input) + throws IOException + { + int tagNo = input[0] & 0x1f; + int index = 1; + // + // with tagged object tag number is bottom 5 bits, or stored at the start of the content + // + if (tagNo == 0x1f) + { + tagNo = 0; + + int b = input[index++] & 0xff; + + // X.690-0207 8.1.2.4.2 + // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." + if ((b & 0x7f) == 0) // Note: -1 will pass + { + throw new ASN1ParsingException("corrupted stream - invalid high tag number found"); + } + + while ((b >= 0) && ((b & 0x80) != 0)) + { + tagNo |= (b & 0x7f); + tagNo <<= 7; + b = input[index++] & 0xff; + } + + tagNo |= (b & 0x7f); + } + + byte[] tmp = new byte[input.length - index + 1]; + + System.arraycopy(input, index, tmp, 1, tmp.length - 1); + + tmp[0] = (byte)newTag; + + return tmp; + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/agreement/jpake/JPAKEParticipant.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/agreement/jpake/JPAKEParticipant.java new file mode 100644 index 00000000..30808802 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/agreement/jpake/JPAKEParticipant.java @@ -0,0 +1,573 @@ +package org.bouncycastle.crypto.agreement.jpake; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.util.Arrays; + +/** + * A participant in a Password Authenticated Key Exchange by Juggling (J-PAKE) exchange. + * <p/> + * <p/> + * The J-PAKE exchange is defined by Feng Hao and Peter Ryan in the paper + * <a href="http://grouper.ieee.org/groups/1363/Research/contributions/hao-ryan-2008.pdf"> + * "Password Authenticated Key Exchange by Juggling, 2008."</a> + * <p/> + * <p/> + * The J-PAKE protocol is symmetric. + * There is no notion of a <i>client</i> or <i>server</i>, but rather just two <i>participants</i>. + * An instance of {@link JPAKEParticipant} represents one participant, and + * is the primary interface for executing the exchange. + * <p/> + * <p/> + * To execute an exchange, construct a {@link JPAKEParticipant} on each end, + * and call the following 7 methods + * (once and only once, in the given order, for each participant, sending messages between them as described): + * <ol> + * <li>{@link #createRound1PayloadToSend()} - and send the payload to the other participant</li> + * <li>{@link #validateRound1PayloadReceived(JPAKERound1Payload)} - use the payload received from the other participant</li> + * <li>{@link #createRound2PayloadToSend()} - and send the payload to the other participant</li> + * <li>{@link #validateRound2PayloadReceived(JPAKERound2Payload)} - use the payload received from the other participant</li> + * <li>{@link #calculateKeyingMaterial()}</li> + * <li>{@link #createRound3PayloadToSend(BigInteger)} - and send the payload to the other participant</li> + * <li>{@link #validateRound3PayloadReceived(JPAKERound3Payload, BigInteger)} - use the payload received from the other participant</li> + * </ol> + * <p/> + * <p/> + * Each side should derive a session key from the keying material returned by {@link #calculateKeyingMaterial()}. + * The caller is responsible for deriving the session key using a secure key derivation function (KDF). + * <p/> + * <p/> + * Round 3 is an optional key confirmation process. + * If you do not execute round 3, then there is no assurance that both participants are using the same key. + * (i.e. if the participants used different passwords, then their session keys will differ.) + * <p/> + * <p/> + * If the round 3 validation succeeds, then the keys are guaranteed to be the same on both sides. + * <p/> + * <p/> + * The symmetric design can easily support the asymmetric cases when one party initiates the communication. + * e.g. Sometimes the round1 payload and round2 payload may be sent in one pass. + * Also, in some cases, the key confirmation payload can be sent together with the round2 payload. + * These are the trivial techniques to optimize the communication. + * <p/> + * <p/> + * The key confirmation process is implemented as specified in + * <a href="http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf">NIST SP 800-56A Revision 1</a>, + * Section 8.2 Unilateral Key Confirmation for Key Agreement Schemes. + * <p/> + * <p/> + * This class is stateful and NOT threadsafe. + * Each instance should only be used for ONE complete J-PAKE exchange + * (i.e. a new {@link JPAKEParticipant} should be constructed for each new J-PAKE exchange). + * <p/> + * <p/> + * See {@link JPAKEExample} for example usage. + */ +public class JPAKEParticipant +{ + /* + * Possible internal states. Used for state checking. + */ + + public static final int STATE_INITIALIZED = 0; + public static final int STATE_ROUND_1_CREATED = 10; + public static final int STATE_ROUND_1_VALIDATED = 20; + public static final int STATE_ROUND_2_CREATED = 30; + public static final int STATE_ROUND_2_VALIDATED = 40; + public static final int STATE_KEY_CALCULATED = 50; + public static final int STATE_ROUND_3_CREATED = 60; + public static final int STATE_ROUND_3_VALIDATED = 70; + + /** + * Unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + */ + private String participantId; + + /** + * Shared secret. This only contains the secret between construction + * and the call to {@link #calculateKeyingMaterial()}. + * <p/> + * i.e. When {@link #calculateKeyingMaterial()} is called, this buffer overwritten with 0's, + * and the field is set to null. + */ + private char[] password; + + /** + * Digest to use during calculations. + */ + private Digest digest; + + /** + * Source of secure random data. + */ + private SecureRandom random; + + private BigInteger p; + private BigInteger q; + private BigInteger g; + + /** + * The participantId of the other participant in this exchange. + */ + private String partnerParticipantId; + + /** + * Alice's x1 or Bob's x3. + */ + private BigInteger x1; + /** + * Alice's x2 or Bob's x4. + */ + private BigInteger x2; + /** + * Alice's g^x1 or Bob's g^x3. + */ + private BigInteger gx1; + /** + * Alice's g^x2 or Bob's g^x4. + */ + private BigInteger gx2; + /** + * Alice's g^x3 or Bob's g^x1. + */ + private BigInteger gx3; + /** + * Alice's g^x4 or Bob's g^x2. + */ + private BigInteger gx4; + /** + * Alice's B or Bob's A. + */ + private BigInteger b; + + /** + * The current state. + * See the <tt>STATE_*</tt> constants for possible values. + */ + private int state; + + /** + * Convenience constructor for a new {@link JPAKEParticipant} that uses + * the {@link JPAKEPrimeOrderGroups#NIST_3072} prime order group, + * a SHA-256 digest, and a default {@link SecureRandom} implementation. + * <p/> + * After construction, the {@link #getState() state} will be {@link #STATE_INITIALIZED}. + * + * @param participantId unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + * @param password shared secret. + * A defensive copy of this array is made (and cleared once {@link #calculateKeyingMaterial()} is called). + * Caller should clear the input password as soon as possible. + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if password is empty + */ + public JPAKEParticipant( + String participantId, + char[] password) + { + this( + participantId, + password, + JPAKEPrimeOrderGroups.NIST_3072); + } + + + /** + * Convenience constructor for a new {@link JPAKEParticipant} that uses + * a SHA-256 digest and a default {@link SecureRandom} implementation. + * <p/> + * After construction, the {@link #getState() state} will be {@link #STATE_INITIALIZED}. + * + * @param participantId unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + * @param password shared secret. + * A defensive copy of this array is made (and cleared once {@link #calculateKeyingMaterial()} is called). + * Caller should clear the input password as soon as possible. + * @param group prime order group. + * See {@link JPAKEPrimeOrderGroups} for standard groups + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if password is empty + */ + public JPAKEParticipant( + String participantId, + char[] password, + JPAKEPrimeOrderGroup group) + { + this( + participantId, + password, + group, + new SHA256Digest(), + new SecureRandom()); + } + + + /** + * Construct a new {@link JPAKEParticipant}. + * <p/> + * After construction, the {@link #getState() state} will be {@link #STATE_INITIALIZED}. + * + * @param participantId unique identifier of this participant. + * The two participants in the exchange must NOT share the same id. + * @param password shared secret. + * A defensive copy of this array is made (and cleared once {@link #calculateKeyingMaterial()} is called). + * Caller should clear the input password as soon as possible. + * @param group prime order group. + * See {@link JPAKEPrimeOrderGroups} for standard groups + * @param digest digest to use during zero knowledge proofs and key confirmation (SHA-256 or stronger preferred) + * @param random source of secure random data for x1 and x2, and for the zero knowledge proofs + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if password is empty + */ + public JPAKEParticipant( + String participantId, + char[] password, + JPAKEPrimeOrderGroup group, + Digest digest, + SecureRandom random) + { + JPAKEUtil.validateNotNull(participantId, "participantId"); + JPAKEUtil.validateNotNull(password, "password"); + JPAKEUtil.validateNotNull(group, "p"); + JPAKEUtil.validateNotNull(digest, "digest"); + JPAKEUtil.validateNotNull(random, "random"); + if (password.length == 0) + { + throw new IllegalArgumentException("Password must not be empty."); + } + + this.participantId = participantId; + + /* + * Create a defensive copy so as to fully encapsulate the password. + * + * This array will contain the password for the lifetime of this + * participant BEFORE {@link #calculateKeyingMaterial()} is called. + * + * i.e. When {@link #calculateKeyingMaterial()} is called, the array will be cleared + * in order to remove the password from memory. + * + * The caller is responsible for clearing the original password array + * given as input to this constructor. + */ + this.password = Arrays.copyOf(password, password.length); + + this.p = group.getP(); + this.q = group.getQ(); + this.g = group.getG(); + + this.digest = digest; + this.random = random; + + this.state = STATE_INITIALIZED; + } + + /** + * Gets the current state of this participant. + * See the <tt>STATE_*</tt> constants for possible values. + */ + public int getState() + { + return this.state; + } + + /** + * Creates and returns the payload to send to the other participant during round 1. + * <p/> + * <p/> + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_1_CREATED}. + */ + public JPAKERound1Payload createRound1PayloadToSend() + { + if (this.state >= STATE_ROUND_1_CREATED) + { + throw new IllegalStateException("Round1 payload already created for " + participantId); + } + + this.x1 = JPAKEUtil.generateX1(q, random); + this.x2 = JPAKEUtil.generateX2(q, random); + + this.gx1 = JPAKEUtil.calculateGx(p, g, x1); + this.gx2 = JPAKEUtil.calculateGx(p, g, x2); + BigInteger[] knowledgeProofForX1 = JPAKEUtil.calculateZeroKnowledgeProof(p, q, g, gx1, x1, participantId, digest, random); + BigInteger[] knowledgeProofForX2 = JPAKEUtil.calculateZeroKnowledgeProof(p, q, g, gx2, x2, participantId, digest, random); + + this.state = STATE_ROUND_1_CREATED; + + return new JPAKERound1Payload(participantId, gx1, gx2, knowledgeProofForX1, knowledgeProofForX2); + } + + /** + * Validates the payload received from the other participant during round 1. + * <p/> + * <p/> + * Must be called prior to {@link #createRound2PayloadToSend()}. + * <p/> + * <p/> + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_1_VALIDATED}. + * + * @throws CryptoException if validation fails. + * @throws IllegalStateException if called multiple times. + */ + public void validateRound1PayloadReceived(JPAKERound1Payload round1PayloadReceived) + throws CryptoException + { + if (this.state >= STATE_ROUND_1_VALIDATED) + { + throw new IllegalStateException("Validation already attempted for round1 payload for" + participantId); + } + this.partnerParticipantId = round1PayloadReceived.getParticipantId(); + this.gx3 = round1PayloadReceived.getGx1(); + this.gx4 = round1PayloadReceived.getGx2(); + + BigInteger[] knowledgeProofForX3 = round1PayloadReceived.getKnowledgeProofForX1(); + BigInteger[] knowledgeProofForX4 = round1PayloadReceived.getKnowledgeProofForX2(); + + JPAKEUtil.validateParticipantIdsDiffer(participantId, round1PayloadReceived.getParticipantId()); + JPAKEUtil.validateGx4(gx4); + JPAKEUtil.validateZeroKnowledgeProof(p, q, g, gx3, knowledgeProofForX3, round1PayloadReceived.getParticipantId(), digest); + JPAKEUtil.validateZeroKnowledgeProof(p, q, g, gx4, knowledgeProofForX4, round1PayloadReceived.getParticipantId(), digest); + + this.state = STATE_ROUND_1_VALIDATED; + } + + /** + * Creates and returns the payload to send to the other participant during round 2. + * <p/> + * <p/> + * {@link #validateRound1PayloadReceived(JPAKERound1Payload)} must be called prior to this method. + * <p/> + * <p/> + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_2_CREATED}. + * + * @throws IllegalStateException if called prior to {@link #validateRound1PayloadReceived(JPAKERound1Payload)}, or multiple times + */ + public JPAKERound2Payload createRound2PayloadToSend() + { + if (this.state >= STATE_ROUND_2_CREATED) + { + throw new IllegalStateException("Round2 payload already created for " + this.participantId); + } + if (this.state < STATE_ROUND_1_VALIDATED) + { + throw new IllegalStateException("Round1 payload must be validated prior to creating Round2 payload for " + this.participantId); + } + BigInteger gA = JPAKEUtil.calculateGA(p, gx1, gx3, gx4); + BigInteger s = JPAKEUtil.calculateS(password); + BigInteger x2s = JPAKEUtil.calculateX2s(q, x2, s); + BigInteger A = JPAKEUtil.calculateA(p, q, gA, x2s); + BigInteger[] knowledgeProofForX2s = JPAKEUtil.calculateZeroKnowledgeProof(p, q, gA, A, x2s, participantId, digest, random); + + this.state = STATE_ROUND_2_CREATED; + + return new JPAKERound2Payload(participantId, A, knowledgeProofForX2s); + } + + /** + * Validates the payload received from the other participant during round 2. + * <p/> + * <p/> + * Note that this DOES NOT detect a non-common password. + * The only indication of a non-common password is through derivation + * of different keys (which can be detected explicitly by executing round 3 and round 4) + * <p/> + * <p/> + * Must be called prior to {@link #calculateKeyingMaterial()}. + * <p/> + * <p/> + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_2_VALIDATED}. + * + * @throws CryptoException if validation fails. + * @throws IllegalStateException if called prior to {@link #validateRound1PayloadReceived(JPAKERound1Payload)}, or multiple times + */ + public void validateRound2PayloadReceived(JPAKERound2Payload round2PayloadReceived) + throws CryptoException + { + if (this.state >= STATE_ROUND_2_VALIDATED) + { + throw new IllegalStateException("Validation already attempted for round2 payload for" + participantId); + } + if (this.state < STATE_ROUND_1_VALIDATED) + { + throw new IllegalStateException("Round1 payload must be validated prior to validating Round2 payload for " + this.participantId); + } + BigInteger gB = JPAKEUtil.calculateGA(p, gx3, gx1, gx2); + this.b = round2PayloadReceived.getA(); + BigInteger[] knowledgeProofForX4s = round2PayloadReceived.getKnowledgeProofForX2s(); + + JPAKEUtil.validateParticipantIdsDiffer(participantId, round2PayloadReceived.getParticipantId()); + JPAKEUtil.validateParticipantIdsEqual(this.partnerParticipantId, round2PayloadReceived.getParticipantId()); + JPAKEUtil.validateGa(gB); + JPAKEUtil.validateZeroKnowledgeProof(p, q, gB, b, knowledgeProofForX4s, round2PayloadReceived.getParticipantId(), digest); + + this.state = STATE_ROUND_2_VALIDATED; + } + + /** + * Calculates and returns the key material. + * A session key must be derived from this key material using a secure key derivation function (KDF). + * The KDF used to derive the key is handled externally (i.e. not by {@link JPAKEParticipant}). + * <p/> + * <p/> + * The keying material will be identical for each participant if and only if + * each participant's password is the same. i.e. If the participants do not + * share the same password, then each participant will derive a different key. + * Therefore, if you immediately start using a key derived from + * the keying material, then you must handle detection of incorrect keys. + * If you want to handle this detection explicitly, you can optionally perform + * rounds 3 and 4. See {@link JPAKEParticipant} for details on how to execute + * rounds 3 and 4. + * <p/> + * <p/> + * The keying material will be in the range <tt>[0, p-1]</tt>. + * <p/> + * <p/> + * {@link #validateRound2PayloadReceived(JPAKERound2Payload)} must be called prior to this method. + * <p/> + * <p/> + * As a side effect, the internal {@link #password} array is cleared, since it is no longer needed. + * <p/> + * <p/> + * After execution, the {@link #getState() state} will be {@link #STATE_KEY_CALCULATED}. + * + * @throws IllegalStateException if called prior to {@link #validateRound2PayloadReceived(JPAKERound2Payload)}, + * or if called multiple times. + */ + public BigInteger calculateKeyingMaterial() + { + if (this.state >= STATE_KEY_CALCULATED) + { + throw new IllegalStateException("Key already calculated for " + participantId); + } + if (this.state < STATE_ROUND_2_VALIDATED) + { + throw new IllegalStateException("Round2 payload must be validated prior to creating key for " + participantId); + } + BigInteger s = JPAKEUtil.calculateS(password); + + /* + * Clear the password array from memory, since we don't need it anymore. + * + * Also set the field to null as a flag to indicate that the key has already been calculated. + */ + Arrays.fill(password, (char)0); + this.password = null; + + BigInteger keyingMaterial = JPAKEUtil.calculateKeyingMaterial(p, q, gx4, x2, s, b); + + /* + * Clear the ephemeral private key fields as well. + * Note that we're relying on the garbage collector to do its job to clean these up. + * The old objects will hang around in memory until the garbage collector destroys them. + * + * If the ephemeral private keys x1 and x2 are leaked, + * the attacker might be able to brute-force the password. + */ + this.x1 = null; + this.x2 = null; + this.b = null; + + /* + * Do not clear gx* yet, since those are needed by round 3. + */ + + this.state = STATE_KEY_CALCULATED; + + return keyingMaterial; + } + + + /** + * Creates and returns the payload to send to the other participant during round 3. + * <p/> + * <p/> + * See {@link JPAKEParticipant} for more details on round 3. + * <p/> + * <p/> + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_3_CREATED}. + * + * @param keyingMaterial The keying material as returned from {@link #calculateKeyingMaterial()}. + * @throws IllegalStateException if called prior to {@link #calculateKeyingMaterial()}, or multiple times + */ + public JPAKERound3Payload createRound3PayloadToSend(BigInteger keyingMaterial) + { + if (this.state >= STATE_ROUND_3_CREATED) + { + throw new IllegalStateException("Round3 payload already created for " + this.participantId); + } + if (this.state < STATE_KEY_CALCULATED) + { + throw new IllegalStateException("Keying material must be calculated prior to creating Round3 payload for " + this.participantId); + } + + BigInteger macTag = JPAKEUtil.calculateMacTag( + this.participantId, + this.partnerParticipantId, + this.gx1, + this.gx2, + this.gx3, + this.gx4, + keyingMaterial, + this.digest); + + this.state = STATE_ROUND_3_CREATED; + + return new JPAKERound3Payload(participantId, macTag); + } + + /** + * Validates the payload received from the other participant during round 3. + * <p/> + * <p/> + * See {@link JPAKEParticipant} for more details on round 3. + * <p/> + * <p/> + * After execution, the {@link #getState() state} will be {@link #STATE_ROUND_3_VALIDATED}. + * + * @param keyingMaterial The keying material as returned from {@link #calculateKeyingMaterial()}. + * @throws CryptoException if validation fails. + * @throws IllegalStateException if called prior to {@link #calculateKeyingMaterial()}, or multiple times + */ + public void validateRound3PayloadReceived(JPAKERound3Payload round3PayloadReceived, BigInteger keyingMaterial) + throws CryptoException + { + if (this.state >= STATE_ROUND_3_VALIDATED) + { + throw new IllegalStateException("Validation already attempted for round3 payload for" + participantId); + } + if (this.state < STATE_KEY_CALCULATED) + { + throw new IllegalStateException("Keying material must be calculated validated prior to validating Round3 payload for " + this.participantId); + } + JPAKEUtil.validateParticipantIdsDiffer(participantId, round3PayloadReceived.getParticipantId()); + JPAKEUtil.validateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.getParticipantId()); + + JPAKEUtil.validateMacTag( + this.participantId, + this.partnerParticipantId, + this.gx1, + this.gx2, + this.gx3, + this.gx4, + keyingMaterial, + this.digest, + round3PayloadReceived.getMacTag()); + + + /* + * Clear the rest of the fields. + */ + this.gx1 = null; + this.gx2 = null; + this.gx3 = null; + this.gx4 = null; + + this.state = STATE_ROUND_3_VALIDATED; + } + +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java new file mode 100644 index 00000000..5a2f4022 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java @@ -0,0 +1,122 @@ +package org.bouncycastle.crypto.agreement.jpake; + +import java.math.BigInteger; + +/** + * A pre-computed prime order group for use during a J-PAKE exchange. + * <p/> + * <p/> + * Typically a Schnorr group is used. In general, J-PAKE can use any prime order group + * that is suitable for public key cryptography, including elliptic curve cryptography. + * <p/> + * <p/> + * See {@link JPAKEPrimeOrderGroups} for convenient standard groups. + * <p/> + * <p/> + * NIST <a href="http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/DSA2_All.pdf">publishes</a> + * many groups that can be used for the desired level of security. + */ +public class JPAKEPrimeOrderGroup +{ + private BigInteger p; + private BigInteger q; + private BigInteger g; + + /** + * Constructs a new {@link JPAKEPrimeOrderGroup}. + * <p/> + * <p/> + * In general, you should use one of the pre-approved groups from + * {@link JPAKEPrimeOrderGroups}, rather than manually constructing one. + * <p/> + * <p/> + * The following basic checks are performed: + * <ul> + * <li>p-1 must be evenly divisible by q</li> + * <li>g must be in [2, p-1]</li> + * <li>g^q mod p must equal 1</li> + * <li>p must be prime (within reasonably certainty)</li> + * <li>q must be prime (within reasonably certainty)</li> + * </ul> + * <p/> + * <p/> + * The prime checks are performed using {@link BigInteger#isProbablePrime(int)}, + * and are therefore subject to the same probability guarantees. + * <p/> + * <p/> + * These checks prevent trivial mistakes. + * However, due to the small uncertainties if p and q are not prime, + * advanced attacks are not prevented. + * Use it at your own risk. + * + * @throws NullPointerException if any argument is null + * @throws IllegalArgumentException if any of the above validations fail + */ + public JPAKEPrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g) + { + /* + * Don't skip the checks on user-specified groups. + */ + this(p, q, g, false); + } + + /** + * Internal package-private constructor used by the pre-approved + * groups in {@link JPAKEPrimeOrderGroups}. + * These pre-approved groups can avoid the expensive checks. + */ + JPAKEPrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g, boolean skipChecks) + { + JPAKEUtil.validateNotNull(p, "p"); + JPAKEUtil.validateNotNull(q, "q"); + JPAKEUtil.validateNotNull(g, "g"); + + if (!skipChecks) + { + if (!p.subtract(JPAKEUtil.ONE).mod(q).equals(JPAKEUtil.ZERO)) + { + throw new IllegalArgumentException("p-1 must be evenly divisible by q"); + } + if (g.compareTo(BigInteger.valueOf(2)) == -1 || g.compareTo(p.subtract(JPAKEUtil.ONE)) == 1) + { + throw new IllegalArgumentException("g must be in [2, p-1]"); + } + if (!g.modPow(q, p).equals(JPAKEUtil.ONE)) + { + throw new IllegalArgumentException("g^q mod p must equal 1"); + } + /* + * Note that these checks do not guarantee that p and q are prime. + * We just have reasonable certainty that they are prime. + */ + if (!p.isProbablePrime(20)) + { + throw new IllegalArgumentException("p must be prime"); + } + if (!q.isProbablePrime(20)) + { + throw new IllegalArgumentException("q must be prime"); + } + } + + this.p = p; + this.q = q; + this.g = g; + } + + public BigInteger getP() + { + return p; + } + + public BigInteger getQ() + { + return q; + } + + public BigInteger getG() + { + return g; + } + +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java new file mode 100644 index 00000000..e4a8750f --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/encodings/PKCS1Encoding.java @@ -0,0 +1,238 @@ +package org.bouncycastle.crypto.encodings; + +import org.bouncycastle.crypto.AsymmetricBlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ParametersWithRandom; + +import java.security.SecureRandom; + +/** + * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this + * depends on your application - see PKCS1 Version 2 for details. + */ +public class PKCS1Encoding + implements AsymmetricBlockCipher +{ + /** + * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to + * work with one of these set the system property org.bouncycastle.pkcs1.strict to false. + * <p> + * The system property is checked during construction of the encoding object, it is set to + * true by default. + * </p> + */ + public static final String STRICT_LENGTH_ENABLED_PROPERTY = "org.bouncycastle.pkcs1.strict"; + + private static final int HEADER_LENGTH = 10; + + private SecureRandom random; + private AsymmetricBlockCipher engine; + private boolean forEncryption; + private boolean forPrivateKey; + private boolean useStrictLength; + + /** + * Basic constructor. + * @param cipher + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher) + { + this.engine = cipher; + this.useStrictLength = useStrict(); + } + + // + // for J2ME compatibility + // + private boolean useStrict() + { + String strict = System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY); + + return strict == null || strict.equals("true"); + } + + public AsymmetricBlockCipher getUnderlyingCipher() + { + return engine; + } + + public void init( + boolean forEncryption, + CipherParameters param) + { + AsymmetricKeyParameter kParam; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + this.random = rParam.getRandom(); + kParam = (AsymmetricKeyParameter)rParam.getParameters(); + } + else + { + this.random = new SecureRandom(); + kParam = (AsymmetricKeyParameter)param; + } + + engine.init(forEncryption, param); + + this.forPrivateKey = kParam.isPrivate(); + this.forEncryption = forEncryption; + } + + public int getInputBlockSize() + { + int baseBlockSize = engine.getInputBlockSize(); + + if (forEncryption) + { + return baseBlockSize - HEADER_LENGTH; + } + else + { + return baseBlockSize; + } + } + + public int getOutputBlockSize() + { + int baseBlockSize = engine.getOutputBlockSize(); + + if (forEncryption) + { + return baseBlockSize; + } + else + { + return baseBlockSize - HEADER_LENGTH; + } + } + + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (forEncryption) + { + return encodeBlock(in, inOff, inLen); + } + else + { + return decodeBlock(in, inOff, inLen); + } + } + + private byte[] encodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (inLen > getInputBlockSize()) + { + throw new IllegalArgumentException("input data too large"); + } + + byte[] block = new byte[engine.getInputBlockSize()]; + + if (forPrivateKey) + { + block[0] = 0x01; // type code 1 + + for (int i = 1; i != block.length - inLen - 1; i++) + { + block[i] = (byte)0xFF; + } + } + else + { + random.nextBytes(block); // random fill + + block[0] = 0x02; // type code 2 + + // + // a zero byte marks the end of the padding, so all + // the pad bytes must be non-zero. + // + for (int i = 1; i != block.length - inLen - 1; i++) + { + while (block[i] == 0) + { + block[i] = (byte)random.nextInt(); + } + } + } + + block[block.length - inLen - 1] = 0x00; // mark the end of the padding + System.arraycopy(in, inOff, block, block.length - inLen, inLen); + + return engine.processBlock(block, 0, block.length); + } + + /** + * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format. + */ + private byte[] decodeBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] block = engine.processBlock(in, inOff, inLen); + + if (block.length < getOutputBlockSize()) + { + throw new InvalidCipherTextException("block truncated"); + } + + byte type = block[0]; + + if (type != 1 && type != 2) + { + throw new InvalidCipherTextException("unknown block type"); + } + + if (useStrictLength && block.length != engine.getOutputBlockSize()) + { + throw new InvalidCipherTextException("block incorrect size"); + } + + // + // find and extract the message block. + // + int start; + + for (start = 1; start != block.length; start++) + { + byte pad = block[start]; + + if (pad == 0) + { + break; + } + if (type == 1 && pad != (byte)0xff) + { + throw new InvalidCipherTextException("block padding incorrect"); + } + } + + start++; // data should start at the next byte + + if (start > block.length || start < HEADER_LENGTH) + { + throw new InvalidCipherTextException("no data in block"); + } + + byte[] result = new byte[block.length - start]; + + System.arraycopy(block, start, result, 0, result.length); + + return result; + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java new file mode 100644 index 00000000..3cbe9182 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/params/DSAParameterGenerationParameters.java @@ -0,0 +1,80 @@ +package org.bouncycastle.crypto.params; + +import java.security.SecureRandom; + +public class DSAParameterGenerationParameters +{ + public static final int DIGITAL_SIGNATURE_USAGE = 1; + public static final int KEY_ESTABLISHMENT_USAGE = 2; + + private int l; + private int n; + private int usageIndex; + private int certainty; + private SecureRandom random; + + /** + * Construct without a usage index, this will do a random construction of G. + * + * @param L desired length of prime P in bits (the effective key size). + * @param N desired length of prime Q in bits. + * @param certainty certainty level for prime number generation. + * @param random the source of randomness to use. + */ + public DSAParameterGenerationParameters( + int L, + int N, + int certainty, + SecureRandom random) + { + this(L, N, certainty, random, -1); + } + + /** + * Construct for a specific usage index - this has the effect of using verifiable canonical generation of G. + * + * @param L desired length of prime P in bits (the effective key size). + * @param N desired length of prime Q in bits. + * @param certainty certainty level for prime number generation. + * @param random the source of randomness to use. + * @param usageIndex a valid usage index. + */ + public DSAParameterGenerationParameters( + int L, + int N, + int certainty, + SecureRandom random, + int usageIndex) + { + this.l = L; + this.n = N; + this.certainty = certainty; + this.usageIndex = usageIndex; + this.random = random; + } + + public int getL() + { + return l; + } + + public int getN() + { + return n; + } + + public int getCertainty() + { + return certainty; + } + + public SecureRandom getRandom() + { + return random; + } + + public int getUsageIndex() + { + return usageIndex; + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/params/HKDFParameters.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/params/HKDFParameters.java new file mode 100644 index 00000000..0f41955a --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/params/HKDFParameters.java @@ -0,0 +1,123 @@ +package org.bouncycastle.crypto.params; + +import org.bouncycastle.crypto.DerivationParameters; +import org.bouncycastle.util.Arrays; + +/** + * Parameter class for the HKDFBytesGenerator class. + */ +public class HKDFParameters + implements DerivationParameters +{ + private byte[] ikm; + private boolean skipExpand; + private byte[] salt; + private byte[] info; + + private HKDFParameters(final byte[] ikm, final boolean skip, + final byte[] salt, final byte[] info) + { + if (ikm == null) + { + throw new IllegalArgumentException( + "IKM (input keying material) should not be null"); + } + + this.ikm = Arrays.clone(ikm); + + this.skipExpand = skip; + + if (salt == null || salt.length == 0) + { + this.salt = null; + } + else + { + this.salt = Arrays.clone(salt); + } + + if (info == null) + { + this.info = new byte[0]; + } + else + { + this.info = Arrays.clone(info); + } + } + + /** + * Generates parameters for HKDF, specifying both the optional salt and + * optional info. Step 1: Extract won't be skipped. + * + * @param ikm the input keying material or seed + * @param salt the salt to use, may be null for a salt for hashLen zeros + * @param info the info to use, may be null for an info field of zero bytes + */ + public HKDFParameters(final byte[] ikm, final byte[] salt, final byte[] info) + { + this(ikm, false, salt, info); + } + + /** + * Factory method that makes the HKDF skip the extract part of the key + * derivation function. + * + * @param ikm the input keying material or seed, directly used for step 2: + * Expand + * @param info the info to use, may be null for an info field of zero bytes + * @return HKDFParameters that makes the implementation skip step 1 + */ + public static HKDFParameters skipExtractParameters(final byte[] ikm, + final byte[] info) + { + + return new HKDFParameters(ikm, true, null, info); + } + + public static HKDFParameters defaultParameters(final byte[] ikm) + { + return new HKDFParameters(ikm, false, null, null); + } + + /** + * Returns the input keying material or seed. + * + * @return the keying material + */ + public byte[] getIKM() + { + return Arrays.clone(ikm); + } + + /** + * Returns if step 1: extract has to be skipped or not + * + * @return true for skipping, false for no skipping of step 1 + */ + public boolean skipExtract() + { + return skipExpand; + } + + /** + * Returns the salt, or null if the salt should be generated as a byte array + * of HashLen zeros. + * + * @return the salt, or null + */ + public byte[] getSalt() + { + return Arrays.clone(salt); + } + + /** + * Returns the info field, which may be empty (null is converted to empty). + * + * @return the info field, never null + */ + public byte[] getInfo() + { + return Arrays.clone(info); + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java new file mode 100644 index 00000000..ded87a71 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/prng/BasicEntropySourceProvider.java @@ -0,0 +1,57 @@ +package org.bouncycastle.crypto.prng; + +import java.security.SecureRandom; + +/** + * An EntropySourceProvider where entropy generation is based on a SecureRandom output using SecureRandom.generateSeed(). + */ +public class BasicEntropySourceProvider + implements EntropySourceProvider +{ + private SecureRandom _sr; + private boolean _predictionResistant; + + /** + * Create a entropy source provider based on the passed in SecureRandom. + * + * @param random the SecureRandom to base EntropySource construction on. + * @param isPredictionResistant boolean indicating if the SecureRandom is based on prediction resistant entropy or not (true if it is). + */ + public BasicEntropySourceProvider(SecureRandom random, boolean isPredictionResistant) + { + _sr = random; + _predictionResistant = isPredictionResistant; + } + + /** + * Return an entropy source that will create bitsRequired bits of entropy on + * each invocation of getEntropy(). + * + * @param bitsRequired size (in bits) of entropy to be created by the provided source. + * @return an EntropySource that generates bitsRequired bits of entropy on each call to its getEntropy() method. + */ + public EntropySource get(final int bitsRequired) + { + return new EntropySource() + { + public boolean isPredictionResistant() + { + return _predictionResistant; + } + + public byte[] getEntropy() + { + byte[] rv = new byte[(bitsRequired + 7) / 8]; + + _sr.nextBytes(rv); + + return rv; + } + + public int entropySize() + { + return bitsRequired; + } + }; + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java new file mode 100644 index 00000000..d7027f63 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java @@ -0,0 +1,249 @@ +package org.bouncycastle.crypto.prng; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.prng.drbg.CTRSP800DRBG; +import org.bouncycastle.crypto.prng.drbg.DualECSP800DRBG; +import org.bouncycastle.crypto.prng.drbg.HMacSP800DRBG; +import org.bouncycastle.crypto.prng.drbg.HashSP800DRBG; +import org.bouncycastle.crypto.prng.drbg.SP80090DRBG; + +/** + * Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG). + */ +public class SP800SecureRandomBuilder +{ + private SecureRandom random; + private EntropySourceProvider entropySourceProvider; + + private byte[] personalizationString; + private int securityStrength = 256; + private int entropyBitsRequired = 256; + + /** + * Basic constructor, creates a builder using an EntropySourceProvider based on the default SecureRandom with + * predictionResistant set to false. + * <p> + * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if + * the default SecureRandom does for its generateSeed() call. + * </p> + */ + public SP800SecureRandomBuilder() + { + this(new SecureRandom(), false); + } + + /** + * Construct a builder with an EntropySourceProvider based on the passed in SecureRandom and the passed in value + * for prediction resistance. + * <p> + * Any SecureRandom created from a builder constructed like this will make use of input passed to SecureRandom.setSeed() if + * the passed in SecureRandom does for its generateSeed() call. + * </p> + * @param entropySource + * @param predictionResistant + */ + public SP800SecureRandomBuilder(SecureRandom entropySource, boolean predictionResistant) + { + this.random = entropySource; + this.entropySourceProvider = new BasicEntropySourceProvider(random, predictionResistant); + } + + /** + * Create a builder which makes creates the SecureRandom objects from a specified entropy source provider. + * <p> + * <b>Note:</b> If this constructor is used any calls to setSeed() in the resulting SecureRandom will be ignored. + * </p> + * @param entropySourceProvider a provider of EntropySource objects. + */ + public SP800SecureRandomBuilder(EntropySourceProvider entropySourceProvider) + { + this.random = null; + this.entropySourceProvider = entropySourceProvider; + } + + /** + * Set the personalization string for DRBG SecureRandoms created by this builder + * @param personalizationString the personalisation string for the underlying DRBG. + * @return the current builder. + */ + public SP800SecureRandomBuilder setPersonalizationString(byte[] personalizationString) + { + this.personalizationString = personalizationString; + + return this; + } + + /** + * Set the security strength required for DRBGs used in building SecureRandom objects. + * + * @param securityStrength the security strength (in bits) + * @return the current builder. + */ + public SP800SecureRandomBuilder setSecurityStrength(int securityStrength) + { + this.securityStrength = securityStrength; + + return this; + } + + /** + * Set the amount of entropy bits required for seeding and reseeding DRBGs used in building SecureRandom objects. + * + * @param entropyBitsRequired the number of bits of entropy to be requested from the entropy source on each seed/reseed. + * @return the current builder. + */ + public SP800SecureRandomBuilder setEntropyBitsRequired(int entropyBitsRequired) + { + this.entropyBitsRequired = entropyBitsRequired; + + return this; + } + + /** + * Build a SecureRandom based on a SP 800-90A Hash DRBG. + * + * @param digest digest algorithm to use in the DRBG underneath the SecureRandom. + * @param nonce nonce value to use in DRBG construction. + * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes. + * @return a SecureRandom supported by a Hash DRBG. + */ + public SP800SecureRandom buildHash(Digest digest, byte[] nonce, boolean predictionResistant) + { + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new HashDRBGProvider(digest, nonce, personalizationString, securityStrength), predictionResistant); + } + + /** + * Build a SecureRandom based on a SP 800-90A CTR DRBG. + * + * @param cipher the block cipher to base the DRBG on. + * @param keySizeInBits key size in bits to be used with the block cipher. + * @param nonce nonce value to use in DRBG construction. + * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes. + * @return a SecureRandom supported by a CTR DRBG. + */ + public SP800SecureRandom buildCTR(BlockCipher cipher, int keySizeInBits, byte[] nonce, boolean predictionResistant) + { + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new CTRDRBGProvider(cipher, keySizeInBits, nonce, personalizationString, securityStrength), predictionResistant); + } + + /** + * Build a SecureRandom based on a SP 800-90A HMAC DRBG. + * + * @param hMac HMAC algorithm to use in the DRBG underneath the SecureRandom. + * @param nonce nonce value to use in DRBG construction. + * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes. + * @return a SecureRandom supported by a HMAC DRBG. + */ + public SP800SecureRandom buildHMAC(Mac hMac, byte[] nonce, boolean predictionResistant) + { + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new HMacDRBGProvider(hMac, nonce, personalizationString, securityStrength), predictionResistant); + } + + /** + * Build a SecureRandom based on a SP 800-90A Dual EC DRBG. + * + * @param digest digest algorithm to use in the DRBG underneath the SecureRandom. + * @param nonce nonce value to use in DRBG construction. + * @param predictionResistant specify whether the underlying DRBG in the resulting SecureRandom should reseed on each request for bytes. + * @return a SecureRandom supported by a Dual EC DRBG. + */ + public SP800SecureRandom buildDualEC(Digest digest, byte[] nonce, boolean predictionResistant) + { + return new SP800SecureRandom(random, entropySourceProvider.get(entropyBitsRequired), new DualECDRBGProvider(digest, nonce, personalizationString, securityStrength), predictionResistant); + } + + private static class HashDRBGProvider + implements DRBGProvider + { + private final Digest digest; + private final byte[] nonce; + private final byte[] personalizationString; + private final int securityStrength; + + public HashDRBGProvider(Digest digest, byte[] nonce, byte[] personalizationString, int securityStrength) + { + this.digest = digest; + this.nonce = nonce; + this.personalizationString = personalizationString; + this.securityStrength = securityStrength; + } + + public SP80090DRBG get(EntropySource entropySource) + { + return new HashSP800DRBG(digest, securityStrength, entropySource, personalizationString, nonce); + } + } + + private static class DualECDRBGProvider + implements DRBGProvider + { + private final Digest digest; + private final byte[] nonce; + private final byte[] personalizationString; + private final int securityStrength; + + public DualECDRBGProvider(Digest digest, byte[] nonce, byte[] personalizationString, int securityStrength) + { + this.digest = digest; + this.nonce = nonce; + this.personalizationString = personalizationString; + this.securityStrength = securityStrength; + } + + public SP80090DRBG get(EntropySource entropySource) + { + return new DualECSP800DRBG(digest, securityStrength, entropySource, personalizationString, nonce); + } + } + + private static class HMacDRBGProvider + implements DRBGProvider + { + private final Mac hMac; + private final byte[] nonce; + private final byte[] personalizationString; + private final int securityStrength; + + public HMacDRBGProvider(Mac hMac, byte[] nonce, byte[] personalizationString, int securityStrength) + { + this.hMac = hMac; + this.nonce = nonce; + this.personalizationString = personalizationString; + this.securityStrength = securityStrength; + } + + public SP80090DRBG get(EntropySource entropySource) + { + return new HMacSP800DRBG(hMac, securityStrength, entropySource, personalizationString, nonce); + } + } + + private static class CTRDRBGProvider + implements DRBGProvider + { + + private final BlockCipher blockCipher; + private final int keySizeInBits; + private final byte[] nonce; + private final byte[] personalizationString; + private final int securityStrength; + + public CTRDRBGProvider(BlockCipher blockCipher, int keySizeInBits, byte[] nonce, byte[] personalizationString, int securityStrength) + { + this.blockCipher = blockCipher; + this.keySizeInBits = keySizeInBits; + this.nonce = nonce; + this.personalizationString = personalizationString; + this.securityStrength = securityStrength; + } + + public SP80090DRBG get(EntropySource entropySource) + { + return new CTRSP800DRBG(blockCipher, keySizeInBits, securityStrength, entropySource, personalizationString, nonce); + } + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/DTLSReassembler.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/DTLSReassembler.java new file mode 100644 index 00000000..2d3cf267 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/DTLSReassembler.java @@ -0,0 +1,136 @@ +package org.bouncycastle.crypto.tls; + +import java.util.Vector; + +class DTLSReassembler +{ + + private short msg_type; + private byte[] body; + + private Vector missing = new Vector(); + + DTLSReassembler(short msg_type, int length) + { + this.msg_type = msg_type; + this.body = new byte[length]; + this.missing.addElement(new Range(0, length)); + } + + short getType() + { + return msg_type; + } + + byte[] getBodyIfComplete() + { + return missing.isEmpty() ? body : null; + } + + void contributeFragment(short msg_type, int length, byte[] buf, int off, int fragment_offset, + int fragment_length) + { + + int fragment_end = fragment_offset + fragment_length; + + if (this.msg_type != msg_type || this.body.length != length || fragment_end > length) + { + return; + } + + if (fragment_length == 0) + { + // NOTE: Empty messages still require an empty fragment to complete it + if (fragment_offset == 0 && !missing.isEmpty()) + { + Range firstRange = (Range)missing.firstElement(); + if (firstRange.getEnd() == 0) + { + missing.removeElementAt(0); + } + } + return; + } + + for (int i = 0; i < missing.size(); ++i) + { + Range range = (Range)missing.elementAt(i); + if (range.getStart() >= fragment_end) + { + break; + } + if (range.getEnd() > fragment_offset) + { + + int copyStart = Math.max(range.getStart(), fragment_offset); + int copyEnd = Math.min(range.getEnd(), fragment_end); + int copyLength = copyEnd - copyStart; + + System.arraycopy(buf, off + copyStart - fragment_offset, body, copyStart, + copyLength); + + if (copyStart == range.getStart()) + { + if (copyEnd == range.getEnd()) + { + missing.removeElementAt(i--); + } + else + { + range.setStart(copyEnd); + } + } + else + { + if (copyEnd == range.getEnd()) + { + range.setEnd(copyStart); + } + else + { + missing.insertElementAt(new Range(copyEnd, range.getEnd()), ++i); + range.setEnd(copyStart); + } + } + } + } + } + + void reset() + { + this.missing.removeAllElements(); + this.missing.addElement(new Range(0, body.length)); + } + + private static class Range + { + + private int start, end; + + Range(int start, int end) + { + this.start = start; + this.end = end; + } + + public int getStart() + { + return start; + } + + public void setStart(int start) + { + this.start = start; + } + + public int getEnd() + { + return end; + } + + public void setEnd(int end) + { + this.end = end; + } + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java new file mode 100644 index 00000000..adb91584 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java @@ -0,0 +1,432 @@ +package org.bouncycastle.crypto.tls; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.util.Integers; + +class DTLSReliableHandshake +{ + + private final static int MAX_RECEIVE_AHEAD = 10; + + private DTLSRecordLayer recordLayer; + + private TlsHandshakeHash hash = new DeferredHash(); + + private Hashtable currentInboundFlight = new Hashtable(); + private Hashtable previousInboundFlight = null; + private Vector outboundFlight = new Vector(); + private boolean sending = true; + + private int message_seq = 0, next_receive_seq = 0; + + DTLSReliableHandshake(TlsContext context, DTLSRecordLayer transport) + { + this.recordLayer = transport; + this.hash.init(context); + } + + void notifyHelloComplete() + { + this.hash = this.hash.commit(); + } + + byte[] getCurrentHash() + { + TlsHandshakeHash copyOfHash = hash.fork(); + byte[] result = new byte[copyOfHash.getDigestSize()]; + copyOfHash.doFinal(result, 0); + return result; + } + + void sendMessage(short msg_type, byte[] body) + throws IOException + { + + if (!sending) + { + checkInboundFlight(); + sending = true; + outboundFlight.removeAllElements(); + } + + Message message = new Message(message_seq++, msg_type, body); + + outboundFlight.addElement(message); + + writeMessage(message); + updateHandshakeMessagesDigest(message); + } + + Message receiveMessage() + throws IOException + { + + if (sending) + { + sending = false; + prepareInboundFlight(); + } + + // Check if we already have the next message waiting + { + DTLSReassembler next = (DTLSReassembler)currentInboundFlight.get(Integers.valueOf(next_receive_seq)); + if (next != null) + { + byte[] body = next.getBodyIfComplete(); + if (body != null) + { + previousInboundFlight = null; + return updateHandshakeMessagesDigest(new Message(next_receive_seq++, next.getType(), body)); + } + } + } + + byte[] buf = null; + + // TODO Check the conditions under which we should reset this + int readTimeoutMillis = 1000; + + for (; ; ) + { + + int receiveLimit = recordLayer.getReceiveLimit(); + if (buf == null || buf.length < receiveLimit) + { + buf = new byte[receiveLimit]; + } + + // TODO Handle records containing multiple handshake messages + + try + { + for (; ; ) + { + int received = recordLayer.receive(buf, 0, receiveLimit, readTimeoutMillis); + if (received < 0) + { + break; + } + if (received < 12) + { + continue; + } + int fragment_length = TlsUtils.readUint24(buf, 9); + if (received != (fragment_length + 12)) + { + continue; + } + int seq = TlsUtils.readUint16(buf, 4); + if (seq > (next_receive_seq + MAX_RECEIVE_AHEAD)) + { + continue; + } + short msg_type = TlsUtils.readUint8(buf, 0); + int length = TlsUtils.readUint24(buf, 1); + int fragment_offset = TlsUtils.readUint24(buf, 6); + if (fragment_offset + fragment_length > length) + { + continue; + } + + if (seq < next_receive_seq) + { + /* + * NOTE: If we receive the previous flight of incoming messages in full + * again, retransmit our last flight + */ + if (previousInboundFlight != null) + { + DTLSReassembler reassembler = (DTLSReassembler)previousInboundFlight.get(Integers + .valueOf(seq)); + if (reassembler != null) + { + + reassembler.contributeFragment(msg_type, length, buf, 12, fragment_offset, + fragment_length); + + if (checkAll(previousInboundFlight)) + { + + resendOutboundFlight(); + + /* + * TODO[DTLS] implementations SHOULD back off handshake packet + * size during the retransmit backoff. + */ + readTimeoutMillis = Math.min(readTimeoutMillis * 2, 60000); + + resetAll(previousInboundFlight); + } + } + } + } + else + { + + DTLSReassembler reassembler = (DTLSReassembler)currentInboundFlight.get(Integers.valueOf(seq)); + if (reassembler == null) + { + reassembler = new DTLSReassembler(msg_type, length); + currentInboundFlight.put(Integers.valueOf(seq), reassembler); + } + + reassembler.contributeFragment(msg_type, length, buf, 12, fragment_offset, fragment_length); + + if (seq == next_receive_seq) + { + byte[] body = reassembler.getBodyIfComplete(); + if (body != null) + { + previousInboundFlight = null; + return updateHandshakeMessagesDigest(new Message(next_receive_seq++, + reassembler.getType(), body)); + } + } + } + } + } + catch (IOException e) + { + // NOTE: Assume this is a timeout for the moment + } + + resendOutboundFlight(); + + /* + * TODO[DTLS] implementations SHOULD back off handshake packet size during the + * retransmit backoff. + */ + readTimeoutMillis = Math.min(readTimeoutMillis * 2, 60000); + } + } + + void finish() + { + DTLSHandshakeRetransmit retransmit = null; + if (!sending) + { + checkInboundFlight(); + } + else if (currentInboundFlight != null) + { + /* + * RFC 6347 4.2.4. In addition, for at least twice the default MSL defined for [TCP], + * when in the FINISHED state, the node that transmits the last flight (the server in an + * ordinary handshake or the client in a resumed handshake) MUST respond to a retransmit + * of the peer's last flight with a retransmit of the last flight. + */ + retransmit = new DTLSHandshakeRetransmit() + { + public void receivedHandshakeRecord(int epoch, byte[] buf, int off, int len) + throws IOException + { + /* + * TODO Need to handle the case where the previous inbound flight contains + * messages from two epochs. + */ + if (len < 12) + { + return; + } + int fragment_length = TlsUtils.readUint24(buf, off + 9); + if (len != (fragment_length + 12)) + { + return; + } + int seq = TlsUtils.readUint16(buf, off + 4); + if (seq >= next_receive_seq) + { + return; + } + + short msg_type = TlsUtils.readUint8(buf, off); + + // TODO This is a hack that only works until we try to support renegotiation + int expectedEpoch = msg_type == HandshakeType.finished ? 1 : 0; + if (epoch != expectedEpoch) + { + return; + } + + int length = TlsUtils.readUint24(buf, off + 1); + int fragment_offset = TlsUtils.readUint24(buf, off + 6); + if (fragment_offset + fragment_length > length) + { + return; + } + + DTLSReassembler reassembler = (DTLSReassembler)currentInboundFlight.get(Integers.valueOf(seq)); + if (reassembler != null) + { + reassembler.contributeFragment(msg_type, length, buf, off + 12, fragment_offset, + fragment_length); + if (checkAll(currentInboundFlight)) + { + resendOutboundFlight(); + resetAll(currentInboundFlight); + } + } + } + }; + } + + recordLayer.handshakeSuccessful(retransmit); + } + + void resetHandshakeMessagesDigest() + { + hash.reset(); + } + + /** + * Check that there are no "extra" messages left in the current inbound flight + */ + private void checkInboundFlight() + { + Enumeration e = currentInboundFlight.keys(); + while (e.hasMoreElements()) + { + Integer key = (Integer)e.nextElement(); + if (key.intValue() >= next_receive_seq) + { + // TODO Should this be considered an error? + } + } + } + + private void prepareInboundFlight() + { + resetAll(currentInboundFlight); + previousInboundFlight = currentInboundFlight; + currentInboundFlight = new Hashtable(); + } + + private void resendOutboundFlight() + throws IOException + { + recordLayer.resetWriteEpoch(); + for (int i = 0; i < outboundFlight.size(); ++i) + { + writeMessage((Message)outboundFlight.elementAt(i)); + } + } + + private Message updateHandshakeMessagesDigest(Message message) + throws IOException + { + if (message.getType() != HandshakeType.hello_request) + { + byte[] body = message.getBody(); + byte[] buf = new byte[12]; + TlsUtils.writeUint8(message.getType(), buf, 0); + TlsUtils.writeUint24(body.length, buf, 1); + TlsUtils.writeUint16(message.getSeq(), buf, 4); + TlsUtils.writeUint24(0, buf, 6); + TlsUtils.writeUint24(body.length, buf, 9); + hash.update(buf, 0, buf.length); + hash.update(body, 0, body.length); + } + return message; + } + + private void writeMessage(Message message) + throws IOException + { + + int sendLimit = recordLayer.getSendLimit(); + int fragmentLimit = sendLimit - 12; + + // TODO Support a higher minimum fragment size? + if (fragmentLimit < 1) + { + // TODO Should we be throwing an exception here? + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + int length = message.getBody().length; + + // NOTE: Must still send a fragment if body is empty + int fragment_offset = 0; + do + { + int fragment_length = Math.min(length - fragment_offset, fragmentLimit); + writeHandshakeFragment(message, fragment_offset, fragment_length); + fragment_offset += fragment_length; + } + while (fragment_offset < length); + } + + private void writeHandshakeFragment(Message message, int fragment_offset, int fragment_length) + throws IOException + { + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + TlsUtils.writeUint8(message.getType(), buf); + TlsUtils.writeUint24(message.getBody().length, buf); + TlsUtils.writeUint16(message.getSeq(), buf); + TlsUtils.writeUint24(fragment_offset, buf); + TlsUtils.writeUint24(fragment_length, buf); + buf.write(message.getBody(), fragment_offset, fragment_length); + + byte[] fragment = buf.toByteArray(); + + recordLayer.send(fragment, 0, fragment.length); + } + + private static boolean checkAll(Hashtable inboundFlight) + { + Enumeration e = inboundFlight.elements(); + while (e.hasMoreElements()) + { + if (((DTLSReassembler)e.nextElement()).getBodyIfComplete() == null) + { + return false; + } + } + return true; + } + + private static void resetAll(Hashtable inboundFlight) + { + Enumeration e = inboundFlight.elements(); + while (e.hasMoreElements()) + { + ((DTLSReassembler)e.nextElement()).reset(); + } + } + + static class Message + { + + private final int message_seq; + private final short msg_type; + private final byte[] body; + + private Message(int message_seq, short msg_type, byte[] body) + { + this.message_seq = message_seq; + this.msg_type = msg_type; + this.body = body; + } + + public int getSeq() + { + return message_seq; + } + + public short getType() + { + return msg_type; + } + + public byte[] getBody() + { + return body; + } + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/UDPTransport.java b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/UDPTransport.java new file mode 100644 index 00000000..f65468e5 --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/crypto/tls/UDPTransport.java @@ -0,0 +1,107 @@ +package org.bouncycastle.crypto.tls; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; + +public class UDPTransport + implements DatagramTransport +{ + + private final static int MIN_IP_OVERHEAD = 20; + private final static int MAX_IP_OVERHEAD = MIN_IP_OVERHEAD + 64; + private final static int UDP_OVERHEAD = 8; + + private final DatagramSocket socket; + private final int receiveLimit, sendLimit; + + public UDPTransport(DatagramSocket socket, int mtu) + throws IOException + { + // + // In 1.3 and earlier sockets were bound and connected during creation + // + //if (!socket.isBound() || !socket.isConnected()) + //{ + // throw new IllegalArgumentException("'socket' must be bound and connected"); + //} + + this.socket = socket; + + // NOTE: As of JDK 1.6, can use NetworkInterface.getMTU + + this.receiveLimit = mtu - MIN_IP_OVERHEAD - UDP_OVERHEAD; + this.sendLimit = mtu - MAX_IP_OVERHEAD - UDP_OVERHEAD; + } + + public int getReceiveLimit() + { + return receiveLimit; + } + + public int getSendLimit() + { + // TODO[DTLS] Implement Path-MTU discovery? + return sendLimit; + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + socket.setSoTimeout(waitMillis); + + if (off == 0) + { + DatagramPacket packet = new DatagramPacket(buf, len); + socket.receive(packet); + + return packet.getLength(); + } + else + { + byte[] rv = new byte[len]; + + DatagramPacket packet = new DatagramPacket(rv, len); + socket.receive(packet); + + System.arraycopy(rv, 0, buf, off, packet.getLength()); + + return packet.getLength(); + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (len > getSendLimit()) + { + /* + * RFC 4347 4.1.1. "If the application attempts to send a record larger than the MTU, + * the DTLS implementation SHOULD generate an error, thus avoiding sending a packet + * which will be fragmented." + */ + // TODO Exception + } + + if (off == 0) + { + DatagramPacket packet = new DatagramPacket(buf, len); + socket.send(packet); + } + else + { + byte[] data = new byte[len]; + + System.arraycopy(buf, off, data, 0, len); + + DatagramPacket packet = new DatagramPacket(data, len); + socket.send(packet); + } + } + + public void close() + throws IOException + { + socket.close(); + } +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/i18n/LocalizedMessage.java b/core/src/main/jdk1.1/org/bouncycastle/i18n/LocalizedMessage.java new file mode 100644 index 00000000..c1c4c58a --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/i18n/LocalizedMessage.java @@ -0,0 +1,464 @@ +package org.bouncycastle.i18n; + +import org.bouncycastle.i18n.filter.Filter; +import org.bouncycastle.i18n.filter.TrustedInput; +import org.bouncycastle.i18n.filter.UntrustedInput; +import org.bouncycastle.i18n.filter.UntrustedUrlInput; + +import java.io.UnsupportedEncodingException; +import java.text.DateFormat; +import java.text.Format; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.TimeZone; + +public class LocalizedMessage +{ + protected static final int NO_FILTER = 0; + protected static final int FILTER = 1; + protected static final int FILTER_URL = 2; + + protected String id; + protected String resource; + + // ISO-8859-1 is the default encoding + public static final String DEFAULT_ENCODING = "ISO-8859-1"; + protected String encoding = DEFAULT_ENCODING; + + protected FilteredArguments arguments; + protected FilteredArguments extraArgs = null; + + protected Filter filter = null; + + protected ClassLoader loader = null; + + /** + * Constructs a new LocalizedMessage using <code>resource</code> as the base name for the + * RessourceBundle and <code>id</code> as the message bundle id the resource file. + * @param resource base name of the resource file + * @param id the id of the corresponding bundle in the resource file + * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code> + */ + public LocalizedMessage(String resource,String id) throws NullPointerException + { + if (resource == null || id == null) + { + throw new NullPointerException(); + } + this.id = id; + this.resource = resource; + arguments = new FilteredArguments(); + } + + /** + * Constructs a new LocalizedMessage using <code>resource</code> as the base name for the + * RessourceBundle and <code>id</code> as the message bundle id the resource file. + * @param resource base name of the resource file + * @param id the id of the corresponding bundle in the resource file + * @param encoding the encoding of the resource file + * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code> + * @throws UnsupportedEncodingException if the encoding is not supported + */ + public LocalizedMessage(String resource,String id, String encoding) throws NullPointerException, UnsupportedEncodingException + { + if (resource == null || id == null) + { + throw new NullPointerException(); + } + this.id = id; + this.resource = resource; + arguments = new FilteredArguments(); + this.encoding = encoding; + } + + /** + * Constructs a new LocalizedMessage using <code>resource</code> as the base name for the + * RessourceBundle and <code>id</code> as the message bundle id the resource file. + * @param resource base name of the resource file + * @param id the id of the corresponding bundle in the resource file + * @param arguments an array containing the arguments for the message + * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code> + */ + public LocalizedMessage(String resource, String id, Object[] arguments) throws NullPointerException + { + if (resource == null || id == null || arguments == null) + { + throw new NullPointerException(); + } + this.id = id; + this.resource = resource; + this.arguments = new FilteredArguments(arguments); + } + + /** + * Constructs a new LocalizedMessage using <code>resource</code> as the base name for the + * RessourceBundle and <code>id</code> as the message bundle id the resource file. + * @param resource base name of the resource file + * @param id the id of the corresponding bundle in the resource file + * @param encoding the encoding of the resource file + * @param arguments an array containing the arguments for the message + * @throws NullPointerException if <code>resource</code> or <code>id</code> is <code>null</code> + * @throws UnsupportedEncodingException if the encoding is not supported + */ + public LocalizedMessage(String resource, String id, String encoding, Object[] arguments) throws NullPointerException, UnsupportedEncodingException + { + if (resource == null || id == null || arguments == null) + { + throw new NullPointerException(); + } + this.id = id; + this.resource = resource; + this.arguments = new FilteredArguments(arguments); + this.encoding = encoding; + } + + /** + * Reads the entry <code>id + "." + key</code> from the resource file and returns a + * formated message for the given Locale and TimeZone. + * @param key second part of the entry id + * @param loc the used {@link Locale} + * @param timezone the used {@link TimeZone} + * @return a Strng containing the localized message + * @throws MissingEntryException if the resource file is not available or the entry does not exist. + */ + public String getEntry(String key,Locale loc, TimeZone timezone) throws MissingEntryException + { + String entry = id; + if (key != null) + { + entry += "." + key; + } + + try + { + ResourceBundle bundle; + if (loader == null) + { + bundle = ResourceBundle.getBundle(resource,loc); + } + else + { + bundle = ResourceBundle.getBundle(resource, loc); + } + String result = bundle.getString(entry); + if (!encoding.equals(DEFAULT_ENCODING)) + { + result = new String(result.getBytes(DEFAULT_ENCODING), encoding); + } + if (!arguments.isEmpty()) + { + result = formatWithTimeZone(result,arguments.getFilteredArgs(loc),loc,timezone); + } + result = addExtraArgs(result, loc); + return result; + } + catch (MissingResourceException mre) + { + throw new MissingEntryException("Can't find entry " + entry + " in resource file " + resource + ".", + resource, + entry, + loc, + loader != null ? loader : this.getClassLoader()); + } + catch (UnsupportedEncodingException use) + { + // should never occur - cause we already test this in the constructor + throw new RuntimeException(use.toString()); + } + } + + protected String formatWithTimeZone( + String template, + Object[] arguments, + Locale locale, + TimeZone timezone) + { + MessageFormat mf = new MessageFormat(" "); + mf.setLocale(locale); + mf.applyPattern(template); + if (!timezone.equals(TimeZone.getDefault())) + { + Format[] formats = mf.getFormats(); + for (int i = 0; i < formats.length; i++) + { + if (formats[i] instanceof DateFormat) + { + DateFormat temp = (DateFormat) formats[i]; + temp.setTimeZone(timezone); + mf.setFormat(i,temp); + } + } + } + return mf.format(arguments); + } + + protected String addExtraArgs(String msg, Locale locale) + { + if (extraArgs != null) + { + StringBuffer sb = new StringBuffer(msg); + Object[] filteredArgs = extraArgs.getFilteredArgs(locale); + for (int i = 0; i < filteredArgs.length; i++) + { + sb.append(filteredArgs[i]); + } + msg = sb.toString(); + } + return msg; + } + + /** + * Sets the {@link Filter} that is used to filter the arguments of this message + * @param filter the {@link Filter} to use. <code>null</code> to disable filtering. + */ + public void setFilter(Filter filter) + { + arguments.setFilter(filter); + if (extraArgs != null) + { + extraArgs.setFilter(filter); + } + this.filter = filter; + } + + /** + * Returns the current filter. + * @return the current filter + */ + public Filter getFilter() + { + return filter; + } + + /** + * Set the {@link ClassLoader} which loads the resource files. If it is set to <code>null</code> + * then the default {@link ClassLoader} is used. + * @param loader the {@link ClassLoader} which loads the resource files + */ + public void setClassLoader(ClassLoader loader) + { + this.loader = loader; + } + + /** + * Returns the {@link ClassLoader} which loads the resource files or <code>null</code> + * if the default ClassLoader is used. + * @return the {@link ClassLoader} which loads the resource files + */ + public ClassLoader getClassLoader() + { + return loader; + } + + /** + * Returns the id of the message in the resource bundle. + * @return the id of the message + */ + public String getId() + { + return id; + } + + /** + * Returns the name of the resource bundle for this message + * @return name of the resource file + */ + public String getResource() + { + return resource; + } + + /** + * Returns an <code>Object[]</code> containing the message arguments. + * @return the message arguments + */ + public Object[] getArguments() + { + return arguments.getArguments(); + } + + /** + * + * @param extraArg + */ + public void setExtraArgument(Object extraArg) + { + setExtraArguments(new Object[] {extraArg}); + } + + /** + * + * @param extraArgs + */ + public void setExtraArguments(Object[] extraArgs) + { + if (extraArgs != null) + { + this.extraArgs = new FilteredArguments(extraArgs); + this.extraArgs.setFilter(filter); + } + else + { + this.extraArgs = null; + } + } + + /** + * + * @return + */ + public Object[] getExtraArgs() + { + return (extraArgs == null) ? null : extraArgs.getArguments(); + } + + protected class FilteredArguments + { + + protected Filter filter = null; + + protected boolean[] isLocaleSpecific; + protected int[] argFilterType; + protected Object[] arguments; + protected Object[] unpackedArgs; + protected Object[] filteredArgs; + + FilteredArguments() + { + this(new Object[0]); + } + + FilteredArguments(Object[] args) + { + this.arguments = args; + this.unpackedArgs = new Object[args.length]; + this.filteredArgs = new Object[args.length]; + this.isLocaleSpecific = new boolean[args.length]; + this.argFilterType = new int[args.length]; + for (int i = 0; i < args.length; i++) + { + if (args[i] instanceof TrustedInput) + { + this.unpackedArgs[i] = ((TrustedInput) args[i]).getInput(); + argFilterType[i] = NO_FILTER; + } + else if (args[i] instanceof UntrustedInput) + { + this.unpackedArgs[i] = ((UntrustedInput) args[i]).getInput(); + if (args[i] instanceof UntrustedUrlInput) + { + argFilterType[i] = FILTER_URL; + } + else + { + argFilterType[i] = FILTER; + } + } + else + { + this.unpackedArgs[i] = args[i]; + argFilterType[i] = FILTER; + } + + // locale specific + this.isLocaleSpecific[i] = (this.unpackedArgs[i] instanceof LocaleString); + } + } + + public boolean isEmpty() + { + return unpackedArgs.length == 0; + } + + public Object[] getArguments() + { + return arguments; + } + + public Object[] getFilteredArgs(Locale locale) + { + Object[] result = new Object[unpackedArgs.length]; + for (int i = 0; i < unpackedArgs.length; i++) + { + Object arg; + if (filteredArgs[i] != null) + { + arg = filteredArgs[i]; + } + else + { + arg = unpackedArgs[i]; + if (isLocaleSpecific[i]) + { + // get locale + arg = ((LocaleString) arg).getLocaleString(locale); + arg = filter(argFilterType[i], arg); + } + else + { + arg = filter(argFilterType[i], arg); + filteredArgs[i] = arg; + } + } + result[i] = arg; + } + return result; + } + + private Object filter(int type, Object obj) + { + if (filter != null) + { + Object o = (null == obj) ? "null" : obj; + switch (type) + { + case NO_FILTER: + return o; + case FILTER: + return filter.doFilter(o.toString()); + case FILTER_URL: + return filter.doFilterUrl(o.toString()); + default: + return null; + } + } + else + { + return obj; + } + } + + public Filter getFilter() + { + return filter; + } + + public void setFilter(Filter filter) + { + if (filter != this.filter) + { + for (int i = 0; i < unpackedArgs.length; i++) + { + filteredArgs[i] = null; + } + } + this.filter = filter; + } + + } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("Resource: \"").append(resource); + sb.append("\" Id: \"").append(id).append("\""); + sb.append(" Arguments: ").append(arguments.getArguments().length).append(" normal, ") + .append(extraArgs.getArguments().length).append(" extra"); + sb.append(" Encoding: ").append(encoding); + sb.append(" ClassLoader: ").append(loader); + return sb.toString(); + } + +} diff --git a/core/src/main/jdk1.1/org/bouncycastle/i18n/MissingEntryException.java b/core/src/main/jdk1.1/org/bouncycastle/i18n/MissingEntryException.java new file mode 100644 index 00000000..1400338f --- /dev/null +++ b/core/src/main/jdk1.1/org/bouncycastle/i18n/MissingEntryException.java @@ -0,0 +1,63 @@ +package org.bouncycastle.i18n; + +import java.net.URL; +import java.util.Locale; + +public class MissingEntryException extends RuntimeException +{ + + protected final String resource; + protected final String key; + protected final ClassLoader loader; + protected final Locale locale; + + private String debugMsg; + + public MissingEntryException(String message, String resource, String key, Locale locale, ClassLoader loader) + { + super(message); + this.resource = resource; + this.key = key; + this.locale = locale; + this.loader = loader; + } + + public MissingEntryException(String message, Throwable cause, String resource, String key, Locale locale, ClassLoader loader) + { + super(message + ": " + cause); + this.resource = resource; + this.key = key; + this.locale = locale; + this.loader = loader; + } + + public String getKey() + { + return key; + } + + public String getResource() + { + return resource; + } + + public ClassLoader getClassLoader() + { + return loader; + } + + public Locale getLocale() + { + return locale; + } + + public String getDebugMsg() + { + if (debugMsg == null) + { + debugMsg = "Can not find entry " + key + " in resource file " + resource + " for the locale " + locale + "."; + } + return debugMsg; + } + +} |