Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'prov/src/main/jdk1.3/org/spongycastle')
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java201
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java428
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java397
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java379
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java134
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java293
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java556
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java858
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java125
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java1636
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java1031
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jcajce/util/ProviderJcaJceHelper.java106
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java229
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java51
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java583
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java41
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java296
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java255
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java182
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java38
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java50
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java18
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java276
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java271
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java22
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java59
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java41
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java382
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java187
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java52
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java104
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java556
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java183
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java99
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java124
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java138
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java190
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java103
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java163
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java150
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java844
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java107
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java196
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java293
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java717
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java2469
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java12
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html5
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java29
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java30
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java1417
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java104
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java146
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java557
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java643
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java85
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java155
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java395
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java431
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java169
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java72
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java2582
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java293
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java556
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java858
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java44
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java406
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java211
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java210
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java647
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java486
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java330
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java86
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java397
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java341
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java430
-rw-r--r--prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java491
77 files changed, 28231 insertions, 0 deletions
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 00000000..390708bc
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,201 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+
+public abstract class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class OAEP
+ extends AlgorithmParametersSpi
+ {
+ AlgorithmParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+ */
+ protected byte[] engineGetEncoded()
+ {
+ return null;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ this.currentSpec = paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+ throw new IOException("Operation not supported");
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "OAEP Parameters";
+ }
+ }
+
+ public static class PSS
+ extends AlgorithmParametersSpi
+ {
+ /**
+ * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+ */
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ RSASSAPSSparams pssP = new RSASSAPSSparams(RSASSAPSSparams.DEFAULT_HASH_ALGORITHM, RSASSAPSSparams.DEFAULT_MASK_GEN_FUNCTION, new ASN1Integer(20), RSASSAPSSparams.DEFAULT_TRAILER_FIELD);
+
+ dOut.writeObject(pssP);
+ dOut.close();
+
+ return bOut.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ throw new InvalidParameterSpecException("Not implemented");
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "PSS Parameters";
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
new file mode 100644
index 00000000..be4083e3
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
@@ -0,0 +1,428 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+
+public class PSSSignatureSpi
+ extends Signature
+{
+ private AlgorithmParameters engineParams;
+ private AsymmetricBlockCipher signer;
+ private Digest contentDigest;
+ private Digest mgfDigest;
+ private int saltLength;
+ private byte trailer;
+ private boolean isRaw;
+ private ByteArrayOutputStream bOut;
+ private org.spongycastle.crypto.signers.PSSSigner pss;
+ private CipherParameters sigParams;
+
+ private byte getTrailer(
+ int trailerField)
+ {
+ if (trailerField == 1)
+ {
+ return org.spongycastle.crypto.signers.PSSSigner.TRAILER_IMPLICIT;
+ }
+
+ throw new IllegalArgumentException("unknown trailer field");
+ }
+
+ private void setupContentDigest()
+ {
+ if (isRaw)
+ {
+ this.contentDigest = new NullPssDigest(mgfDigest);
+ }
+ else
+ {
+ this.contentDigest = mgfDigest;
+ }
+ }
+
+ protected PSSSignatureSpi(
+ String name,
+ AsymmetricBlockCipher signer,
+ Digest digest)
+ {
+ super(name);
+
+ this.signer = signer;
+ this.mgfDigest = digest;
+
+ if (digest != null)
+ {
+ this.saltLength = digest.getDigestSize();
+ }
+ else
+ {
+ this.saltLength = 20;
+ }
+
+ this.isRaw = false;
+
+ setupContentDigest();
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected PSSSignatureSpi(
+ String name,
+ AsymmetricBlockCipher signer,
+ Digest digest,
+ boolean isRaw)
+ {
+ super(name);
+
+ this.signer = signer;
+ this.mgfDigest = digest;
+
+ if (digest != null)
+ {
+ this.saltLength = digest.getDigestSize();
+ }
+ else
+ {
+ this.saltLength = 20;
+ }
+
+ this.isRaw = isRaw;
+
+ setupContentDigest();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance");
+ }
+
+ sigParams = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ if (isRaw)
+ {
+ bOut = new ByteArrayOutputStream();
+ }
+ else
+ {
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(false,
+ sigParams);
+ }
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ sigParams = new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random);
+
+ if (isRaw)
+ {
+ bOut = new ByteArrayOutputStream();
+ }
+ else
+ {
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, sigParams);
+ }
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ sigParams = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ if (isRaw)
+ {
+ bOut = new ByteArrayOutputStream();
+ }
+ else
+ {
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, sigParams);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ if (isRaw)
+ {
+ bOut.write(b);
+ }
+ else
+ {
+ pss.update(b);
+ }
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ if (isRaw)
+ {
+ bOut.write(b, off, len);
+ }
+ else
+ {
+ pss.update(b, off, len);
+ }
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ if (isRaw)
+ {
+ byte[] hash = bOut.toByteArray();
+ contentDigest = mgfDigest = guessDigest(hash.length);
+ saltLength = contentDigest.getDigestSize();
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, new NullPssDigest(contentDigest), mgfDigest, saltLength);
+
+ pss.init(true, sigParams);
+ }
+ return pss.generateSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new SignatureException(e.getMessage());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ if (isRaw)
+ {
+ byte[] hash = bOut.toByteArray();
+ contentDigest = mgfDigest = guessDigest(hash.length);
+ saltLength = contentDigest.getDigestSize();
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, new NullPssDigest(contentDigest), mgfDigest, saltLength);
+
+ pss.init(false, sigParams);
+
+ pss.update(hash, 0, hash.length);
+ }
+ return pss.verifySignature(sigBytes);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ throws InvalidParameterException
+ {
+ throw new InvalidParameterException("Only PSSParameterSpec supported");
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return engineParams;
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineGetParameter unsupported");
+ }
+
+ private Digest guessDigest(int size)
+ {
+ switch (size)
+ {
+ case 20:
+ return new SHA1Digest();
+ case 28:
+ return new SHA224Digest();
+ case 32:
+ return new SHA256Digest();
+ case 48:
+ return new SHA384Digest();
+ case 64:
+ return new SHA512Digest();
+ }
+
+ return null;
+ }
+
+ static public class nonePSS
+ extends PSSSignatureSpi
+ {
+ public nonePSS()
+ {
+ super("NONEwithRSAandMGF1", new RSABlindedEngine(), null, true);
+ }
+ }
+
+ static public class PSSwithRSA
+ extends PSSSignatureSpi
+ {
+ public PSSwithRSA()
+ {
+ super("SHA1withRSAandMGF1", new RSABlindedEngine(), null);
+ }
+ }
+
+ static public class SHA1withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA1withRSA()
+ {
+ super("SHA1withRSAandMGF1", new RSABlindedEngine(), new SHA1Digest());
+ }
+ }
+
+ static public class SHA224withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA224withRSA()
+ {
+ super("SHA224withRSAandMGF1", new RSABlindedEngine(), new SHA224Digest());
+ }
+ }
+
+ static public class SHA256withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA256withRSA()
+ {
+ super("SHA256withRSAandMGF1", new RSABlindedEngine(), new SHA256Digest());
+ }
+ }
+
+ static public class SHA384withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA384withRSA()
+ {
+ super("SHA384withRSAandMGF1", new RSABlindedEngine(), new SHA384Digest());
+ }
+ }
+
+ static public class SHA512withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA512withRSA()
+ {
+ super("SHA512withRSAandMGF1", new RSABlindedEngine(), new SHA512Digest());
+ }
+ }
+
+ private class NullPssDigest
+ implements Digest
+ {
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ private Digest baseDigest;
+ private boolean oddTime = true;
+
+ public NullPssDigest(Digest mgfDigest)
+ {
+ this.baseDigest = mgfDigest;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "NULL";
+ }
+
+ public int getDigestSize()
+ {
+ return baseDigest.getDigestSize();
+ }
+
+ public void update(byte in)
+ {
+ bOut.write(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ bOut.write(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] res = bOut.toByteArray();
+
+ if (oddTime)
+ {
+ System.arraycopy(res, 0, out, outOff, res.length);
+ }
+ else
+ {
+ baseDigest.update(res, 0, res.length);
+
+ baseDigest.doFinal(out, outOff);
+ }
+
+ reset();
+
+ oddTime = !oddTime;
+
+ return res.length;
+ }
+
+ public void reset()
+ {
+ bOut.reset();
+ baseDigest.reset();
+ }
+
+ public int getByteLength()
+ {
+ return 0;
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
new file mode 100644
index 00000000..467893f3
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -0,0 +1,397 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import org.spongycastle.jce.cert.CertPath;
+import java.security.cert.CertificateException;
+import org.spongycastle.jce.cert.CertificateFactorySpi;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.jce.provider.X509CRLObject;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class for dealing with X509 certificates.
+ * <p>
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+public class CertificateFactory
+ extends CertificateFactorySpi
+{
+ private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
+ private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private ASN1Set sCrlData = null;
+ private int sCrlDataObjectCount = 0;
+ private InputStream currentCrlStream = null;
+
+ private java.security.cert.Certificate readDERCertificate(
+ ASN1InputStream dIn)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+ return getCertificate();
+ }
+ }
+
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ private java.security.cert.Certificate getCertificate()
+ throws CertificateParsingException
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.size())
+ {
+ Object obj = sData.getObjectAt(sDataObjectCount++);
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private java.security.cert.Certificate readPEMCertificate(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509CertificateObject(
+ Certificate.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ protected CRL createCRL(CertificateList c)
+ throws CRLException
+ {
+ return new X509CRLObject(c);
+ }
+
+ private CRL readPEMCRL(
+ InputStream in)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ private CRL readDERCRL(
+ ASN1InputStream aIn)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = (ASN1Sequence)aIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+
+ return getCRL();
+ }
+ }
+
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ private CRL getCRL()
+ throws CRLException
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size())
+ {
+ return null;
+ }
+
+ return createCRL(
+ CertificateList.getInstance(
+ sCrlData.getObjectAt(sCrlDataObjectCount++)));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public java.security.cert.Certificate engineGenerateCertificate(
+ InputStream in)
+ throws CertificateException
+ {
+ if (currentStream == null)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != in) // reset if input stream has changed
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCertificate();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(in);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCertificate(pis);
+ }
+ else
+ {
+ return readDERCertificate(new ASN1InputStream(pis));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExCertificateException(e);
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public Collection engineGenerateCertificates(
+ InputStream inStream)
+ throws CertificateException
+ {
+ java.security.cert.Certificate cert;
+ List certs = new ArrayList();
+
+ while ((cert = engineGenerateCertificate(inStream)) != null)
+ {
+ certs.add(cert);
+ }
+
+ return certs;
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public CRL engineGenerateCRL(
+ InputStream inStream)
+ throws CRLException
+ {
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.size())
+ {
+ return getCRL();
+ }
+ else
+ {
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(inStream);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCRL(pis);
+ }
+ else
+ { // lazy evaluate to help processing of large CRLs
+ return readDERCRL(new ASN1InputStream(pis, true));
+ }
+ }
+ catch (CRLException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only signficant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public Collection engineGenerateCRLs(
+ InputStream inStream)
+ throws CRLException
+ {
+ CRL crl;
+ List crls = new ArrayList();
+
+ while ((crl = engineGenerateCRL(inStream)) != null)
+ {
+ crls.add(crl);
+ }
+
+ return crls;
+ }
+
+ public Iterator engineGetCertPathEncodings()
+ {
+ return null; // TODO: PKIXCertPath.certPathEncodings.iterator();
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream)
+ throws CertificateException
+ {
+ return engineGenerateCertPath(inStream, "PkiPath");
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ return new PKIXCertPath(inStream, encoding);
+ }
+
+ public CertPath engineGenerateCertPath(
+ List certificates)
+ throws CertificateException
+ {
+ Iterator iter = certificates.iterator();
+ Object obj;
+ while (iter.hasNext())
+ {
+ obj = iter.next();
+ if (obj != null)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString());
+ }
+ }
+ }
+ return new PKIXCertPath(certificates);
+ }
+
+ private class ExCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public ExCertificateException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ public ExCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
new file mode 100644
index 00000000..0bc93832
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
@@ -0,0 +1,379 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.security.NoSuchProviderException;
+import org.spongycastle.jce.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.SignedData;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.io.pem.PemObject;
+import org.spongycastle.util.io.pem.PemWriter;
+
+/**
+ * CertPath implementation for X.509 certificates.
+ * <br />
+ **/
+public class PKIXCertPath
+ extends CertPath
+{
+ static final List certPathEncodings;
+
+ static
+ {
+ List encodings = new ArrayList();
+ encodings.add("PkiPath");
+ encodings.add("PEM");
+ encodings.add("PKCS7");
+ certPathEncodings = Collections.unmodifiableList(encodings);
+ }
+
+ private List certificates;
+
+ /**
+ * @param certs
+ */
+ private List sortCerts(
+ List certs)
+ {
+ try
+ {
+ if (certs.size() < 2)
+ {
+ return certs;
+ }
+
+ X509Principal issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(0)));
+ boolean okay = true;
+
+ for (int i = 1; i != certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+
+ if (issuer.equals(PrincipalUtil.getSubjectX509Principal(cert)))
+ {
+ issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)certs.get(i)));
+ }
+ else
+ {
+ okay = false;
+ break;
+ }
+ }
+
+ if (okay)
+ {
+ return certs;
+ }
+
+ // find end-entity cert
+ List retList = new ArrayList(certs.size());
+ List orig = new ArrayList(certs);
+
+ for (int i = 0; i < certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+ boolean found = false;
+
+ X509Principal subject = PrincipalUtil.getSubjectX509Principal(cert);
+
+ for (int j = 0; j != certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (PrincipalUtil.getIssuerX509Principal(c).equals(subject))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ retList.add(cert);
+ certs.remove(i);
+ }
+ }
+
+ // can only have one end entity cert - something's wrong, give up.
+ if (retList.size() > 1)
+ {
+ return orig;
+ }
+
+ for (int i = 0; i != retList.size(); i++)
+ {
+ issuer = PrincipalUtil.getIssuerX509Principal(((X509Certificate)retList.get(i)));
+
+ for (int j = 0; j < certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (issuer.equals(PrincipalUtil.getSubjectX509Principal(c)))
+ {
+ retList.add(c);
+ certs.remove(j);
+ break;
+ }
+ }
+ }
+
+ // make sure all certificates are accounted for.
+ if (certs.size() > 0)
+ {
+ return orig;
+ }
+
+ return retList;
+ }
+ catch (Exception e)
+ {
+ return certs;
+ }
+ }
+
+ PKIXCertPath(List certificates)
+ {
+ super("X.509");
+ this.certificates = sortCerts(new ArrayList(certificates));
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ **/
+ PKIXCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ super("X.509");
+ try
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Primitive derObject = derInStream.readObject();
+ if (!(derObject instanceof ASN1Sequence))
+ {
+ throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+ }
+ Enumeration e = ((ASN1Sequence)derObject).getObjects();
+ certificates = new ArrayList();
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ while (e.hasMoreElements())
+ {
+ ASN1Encodable element = (ASN1Encodable)e.nextElement();
+ byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ certificates.add(0, certFactory.generateCertificate(
+ new ByteArrayInputStream(encoded)));
+ }
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM"))
+ {
+ inStream = new BufferedInputStream(inStream);
+ certificates = new ArrayList();
+ CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ Certificate cert;
+ while ((cert = certFactory.generateCertificate(inStream)) != null)
+ {
+ certificates.add(cert);
+ }
+ }
+ else
+ {
+ throw new CertificateException("unsupported encoding: " + encoding);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString());
+ }
+ catch (NoSuchProviderException ex)
+ {
+ throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
+ }
+
+ this.certificates = sortCerts(certificates);
+ }
+
+ /**
+ * 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 Iterator getEncodings()
+ {
+ return certPathEncodings.iterator();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the default encoding.
+ *
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error occurs
+ **/
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ Iterator iter = getEncodings();
+ if (iter.hasNext())
+ {
+ Object enc = iter.next();
+ if (enc instanceof String)
+ {
+ return getEncoded((String)enc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 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 java.security.cert.CertificateEncodingException if an encoding error
+ * occurs or the encoding requested is not supported
+ *
+ **/
+ public byte[] getEncoded(String encoding)
+ throws CertificateEncodingException
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ ListIterator iter = certificates.listIterator(certificates.size());
+ while (iter.hasPrevious())
+ {
+ v.add(toASN1Object((X509Certificate)iter.previous()));
+ }
+
+ return toDEREncoded(new DERSequence(v));
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7"))
+ {
+ ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ v.add(toASN1Object((X509Certificate)certificates.get(i)));
+ }
+
+ SignedData sd = new SignedData(
+ new ASN1Integer(1),
+ new DERSet(),
+ encInfo,
+ new DERSet(v),
+ null,
+ new DERSet());
+
+ return toDEREncoded(new ContentInfo(
+ PKCSObjectIdentifiers.signedData, sd));
+ }
+ else if (encoding.equalsIgnoreCase("PEM"))
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
+
+ try
+ {
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
+ }
+
+ pWrt.close();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+ }
+
+ return bOut.toByteArray();
+ }
+ else
+ {
+ throw new CertificateEncodingException("unsupported encoding: " + encoding);
+ }
+ }
+
+ /**
+ * 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 List getCertificates()
+ {
+ return Collections.unmodifiableList(new ArrayList(certificates));
+ }
+
+ /**
+ * Return a DERObject containing the encoded certificate.
+ *
+ * @param cert the X509Certificate object to be encoded
+ *
+ * @return the DERObject
+ **/
+ private ASN1Primitive toASN1Object(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return new ASN1InputStream(cert.getEncoded()).readObject();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString());
+ }
+ }
+
+ private byte[] toDEREncoded(ASN1Encodable obj)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("Exception thrown: " + e);
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
new file mode 100644
index 00000000..96a1529c
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
@@ -0,0 +1,134 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+
+class SignatureUtil
+{
+ private static final ASN1Null derNull = new DERNull();
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params.toASN1Primitive()))
+ {
+ try
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider().getName());
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SignatureException("cannot find provider: " + e.getMessage());
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
+ }
+ if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+ {
+ ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+
+ return getDigestAlgName((ASN1ObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.getAlgorithm().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ ASN1ObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
new file mode 100644
index 00000000..dac30008
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
@@ -0,0 +1,293 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+import org.spongycastle.jce.X509Principal;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+class X509CRLEntryObject extends X509CRLEntry
+{
+ private TBSCertList.CRLEntry c;
+
+ private X500Name certificateIssuer;
+ private int hashValue;
+ private boolean isHashValueSet;
+
+ public X509CRLEntryObject(TBSCertList.CRLEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = null;
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+ * is <code>false</code> {@link #getCertificateIssuer()} will always
+ * return <code>null</code>, <code>previousCertificateIssuer</code> is
+ * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+ * has no certificate issuer CRL entry extension
+ * <code>previousCertificateIssuer</code> is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TBSCertList.CRLEntry object.
+ * @param isIndirect
+ * <code>true</code> if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CRLEntry.
+ */
+ public X509CRLEntryObject(
+ TBSCertList.CRLEntry c,
+ boolean isIndirect,
+ X500Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+ }
+
+ /**
+ * Will return true if any extensions are present and marked as critical as
+ * we currently don't handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId());
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.getInstance(
+ X509ExtensionUtil.fromExtensionValue(ext)).getNames();
+ for (int i = 0; i < names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ return X500Name.getInstance(names[i].getName());
+ }
+ }
+ return null;
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ X509Principal getCertificateIssuer()
+ {
+ if (certificateIssuer == null)
+ {
+ return null;
+ }
+ try
+ {
+ return new X509Principal(certificateIssuer.getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e.toString());
+ }
+ }
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Cache the hashCode value - calculating it with the standard method.
+ * @return calculated hashCode.
+ */
+ public int hashCode()
+ {
+ if (!isHashValueSet)
+ {
+ hashValue = super.hashCode();
+ isHashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getUserCertificate().getValue();
+ }
+
+ public Date getRevocationDate()
+ {
+ return c.getRevocationDate().getDate();
+ }
+
+ public boolean hasExtensions()
+ {
+ return c.getExtensions() != null;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl);
+
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+ if (e.hasMoreElements())
+ {
+ buf.append(" crlEntryExtensions:").append(nl);
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.reasonCode))
+ {
+ buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl);
+ }
+ else if (oid.equals(X509Extension.certificateIssuer))
+ {
+ buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
new file mode 100644
index 00000000..f2b5f5d8
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
@@ -0,0 +1,556 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLNumber;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ public X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs != null)
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ for (int i = 0; i < certs.length; i++)
+ {
+ if (isIndirect && certs[i].hasExtensions())
+ {
+ Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (certs[i].getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ try
+ {
+ issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
new file mode 100644
index 00000000..aa83e65d
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
@@ -0,0 +1,858 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.misc.NetscapeRevocationURL;
+import org.spongycastle.asn1.misc.VerisignCzagExtension;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.encoders.Hex;
+
+class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private org.spongycastle.asn1.x509.Certificate c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ public String getSigAlgName()
+ {
+ Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ if (prov != null)
+ {
+ String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ Provider[] provs = Security.getProviders();
+
+ //
+ // search every provider looking for a real algorithm
+ //
+ for (int i = 0; i != provs.length; i++)
+ {
+ String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ return this.getSigAlgOID();
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getExtnValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ String oidId = oid.getId();
+
+ if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+ || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+ || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+ || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+ || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+ || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+ || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+ {
+ continue;
+ }
+
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.keyUsage))
+ {
+ buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return null;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getEncoded());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+ list.add(addrBytes);
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(list);
+ }
+ if (temp.size() == 0)
+ {
+ return null;
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
new file mode 100644
index 00000000..e74ced7f
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -0,0 +1,125 @@
+package org.spongycastle.jcajce.provider.asymmetric.x509;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.SignatureException;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Null;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+
+class X509SignatureUtil
+{
+ private static final ASN1Null derNull = new DERNull();
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params))
+ {
+ /*
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.getDERObject().getDEREncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ try
+ {
+ signature.setParameters(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ */
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ ASN1ObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
new file mode 100644
index 00000000..9875bd14
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -0,0 +1,1636 @@
+package org.spongycastle.jcajce.provider.keystore.pkcs12;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.BEROctetString;
+import org.spongycastle.asn1.BEROutputStream;
+import org.spongycastle.asn1.DERBMPString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.DERSet;
+import org.spongycastle.asn1.pkcs.AuthenticatedSafe;
+import org.spongycastle.asn1.pkcs.CertBag;
+import org.spongycastle.asn1.pkcs.ContentInfo;
+import org.spongycastle.asn1.pkcs.EncryptedData;
+import org.spongycastle.asn1.pkcs.MacData;
+import org.spongycastle.asn1.pkcs.PBES2Parameters;
+import org.spongycastle.asn1.pkcs.PBKDF2Params;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.Pfx;
+import org.spongycastle.asn1.pkcs.SafeBag;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.SubjectKeyIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.util.SecretKeyUtil;
+import org.spongycastle.jce.interfaces.BCKeyStore;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Strings;
+import org.spongycastle.util.encoders.Hex;
+
+public class PKCS12KeyStoreSpi
+ extends KeyStoreSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+ private static final int SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final Provider bcProvider = new BouncyCastleProvider();
+
+ private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private Hashtable localIds = new Hashtable();
+ private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private Hashtable chainCerts = new Hashtable();
+ private Hashtable keyCerts = new Hashtable();
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected SecureRandom random = new SecureRandom();
+
+ // use of final causes problems with JDK 1.2 compiler
+ private CertificateFactory certFact;
+ private ASN1ObjectIdentifier keyAlgorithm;
+ private ASN1ObjectIdentifier certAlgorithm;
+
+ private class CertId
+ {
+ byte[] id;
+
+ CertId(
+ PublicKey key)
+ {
+ this.id = createSubjectKeyId(key).getKeyIdentifier();
+ }
+
+ CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(id);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof CertId))
+ {
+ return false;
+ }
+
+ CertId cId = (CertId)o;
+
+ return Arrays.areEqual(id, cId.id);
+ }
+ }
+
+ public PKCS12KeyStoreSpi(
+ Provider provider,
+ ASN1ObjectIdentifier keyAlgorithm,
+ ASN1ObjectIdentifier certAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+
+ try
+ {
+ if (provider != null)
+ {
+ certFact = CertificateFactory.getInstance("X.509", provider.getName());
+ }
+ else
+ {
+ certFact = CertificateFactory.getInstance("X.509");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+ }
+ }
+
+ private SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+
+ return new SubjectKeyIdentifier(getDigest(info));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error creating key");
+ }
+ }
+
+ private static byte[] getDigest(SubjectPublicKeyInfo spki)
+ {
+ Digest digest = new SHA1Digest();
+ byte[] resBuf = new byte[digest.getDigestSize()];
+
+ byte[] bytes = spki.getPublicKeyData().getBytes();
+ digest.update(bytes, 0, bytes.length);
+ digest.doFinal(resBuf, 0);
+ return resBuf;
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (certs.get(alias) != null || keys.get(alias) != null);
+ }
+
+ /**
+ * this is not quite complete - we should follow up on the chain, a bit
+ * tricky if a certificate appears in more than one chain...
+ */
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Key k = (Key)keys.remove(alias);
+
+ Certificate c = (Certificate)certs.remove(alias);
+
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+
+ if (k != null)
+ {
+ String id = (String)localIds.remove(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.remove(id);
+ }
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+ }
+ }
+
+ /**
+ * simply return the cert for the private key
+ */
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificate.");
+ }
+
+ Certificate c = (Certificate)certs.get(alias);
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ String id = (String)localIds.get(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.get(id);
+ }
+ else
+ {
+ c = (Certificate)keyCerts.get(alias);
+ }
+ }
+
+ return c;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration c = certs.elements();
+ Enumeration k = certs.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ c = keyCerts.elements();
+ k = keyCerts.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+ }
+
+ if (!engineIsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ Certificate c = engineGetCertificate(alias);
+
+ if (c != null)
+ {
+ Vector cs = new Vector();
+
+ while (c != null)
+ {
+ X509Certificate x509c = (X509Certificate)c;
+ Certificate nextC = null;
+
+ byte[] bytes = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId());
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+ byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+ aIn = new ASN1InputStream(authBytes);
+
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject());
+ if (id.getKeyIdentifier() != null)
+ {
+ nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+ }
+
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ Principal i = x509c.getIssuerDN();
+ Principal s = x509c.getSubjectDN();
+
+ if (!i.equals(s))
+ {
+ Enumeration e = chainCerts.keys();
+
+ while (e.hasMoreElements())
+ {
+ X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+ Principal sub = crt.getSubjectDN();
+ if (sub.equals(i))
+ {
+ try
+ {
+ x509c.verify(crt.getPublicKey());
+ nextC = crt;
+ break;
+ }
+ catch (Exception ex)
+ {
+ // continue
+ }
+ }
+ }
+ }
+ }
+
+ cs.addElement(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ Certificate[] certChain = new Certificate[cs.size()];
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ certChain[i] = (Certificate)cs.elementAt(i);
+ }
+
+ return certChain;
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ if (alias == null)
+ {
+ throw new NullPointerException("alias == null");
+ }
+ if (keys.get(alias) == null && certs.get(alias) == null)
+ {
+ return null;
+ }
+ return new Date();
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getKey.");
+ }
+
+ return (Key)keys.get(alias);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ return (certs.get(alias) != null && keys.get(alias) == null);
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ return (keys.get(alias) != null);
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ if (keys.get(alias) != null)
+ {
+ throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+ }
+
+ certs.put(alias, cert);
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ throw new RuntimeException("operation not supported");
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if (!(key instanceof PrivateKey))
+ {
+ throw new KeyStoreException("PKCS12 does not support non-PrivateKeys");
+ }
+
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ if (keys.get(alias) != null)
+ {
+ engineDeleteEntry(alias);
+ }
+
+ keys.put(alias, key);
+ if (chain != null)
+ {
+ certs.put(alias, chain[0]);
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+ }
+ }
+ }
+
+ public int engineSize()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.size();
+ }
+
+ protected PrivateKey unwrapKey(
+ AlgorithmIdentifier algId,
+ byte[] data,
+ char[] password,
+ boolean wrongPKCS12Zero)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
+ try
+ {
+ if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
+ {
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2))
+ {
+ PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
+ PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
+
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider);
+
+ SecretKey k = keyFact.generateSecret(new PBEKeySpec(password, func.getSalt(), func.getIterationCount().intValue(), SecretKeyUtil.getKeySize(alg.getEncryptionScheme().getAlgorithm())));
+
+ Cipher cipher = Cipher.getInstance(alg.getEncryptionScheme().getAlgorithm().getId(), bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, new IvParameterSpec(ASN1OctetString.getInstance(alg.getEncryptionScheme().getParameters()).getOctets()));
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception unwrapping private key - " + e.toString());
+ }
+
+ throw new IOException("exception unwrapping private key - cannot recognise: " + algorithm);
+ }
+
+ protected byte[] wrapKey(
+ String algorithm,
+ Key key,
+ PKCS12PBEParams pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] cryptData(
+ boolean forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ boolean wrongPKCS12Zero,
+ byte[] data)
+ throws IOException
+ {
+ String algorithm = algId.getAlgorithm().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+
+ key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+ int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+ cipher.init(mode, key, defParams);
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30)
+ {
+ throw new IOException("stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+ try
+ {
+ byte[] res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ if (password.length > 0)
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getAlgorithm(), salt, itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data))
+ {
+ bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++)
+ {
+ if (c[i].getContentType().equals(data))
+ {
+ ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ }
+ else if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else
+ {
+ System.out.println("extra in data " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else if (c[i].getContentType().equals(encryptedData))
+ {
+ EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+ byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+ password, wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else if (b.getBagId().equals(keyBag))
+ {
+ org.spongycastle.asn1.pkcs.PrivateKeyInfo kInfo = org.spongycastle.asn1.pkcs.PrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ keys.put(alias, privKey);
+ }
+ else if (aOid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ System.out.println("extra in encryptedData " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ System.out.println("extra " + c[i].getContentType().getId());
+ System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ for (int i = 0; i != chain.size(); i++)
+ {
+ SafeBag b = (SafeBag)chain.elementAt(i);
+ CertBag cb = CertBag.getInstance(b.getBagValue());
+
+ if (!cb.getCertId().equals(x509Certificate))
+ {
+ throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+ }
+
+ Certificate cert;
+
+ try
+ {
+ ByteArrayInputStream cIn = new ByteArrayInputStream(
+ ((ASN1OctetString)cb.getCertValue()).getOctets());
+ cert = certFact.generateCertificate(cIn);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+
+ //
+ // set the attributes
+ //
+ ASN1OctetString localId = null;
+ String alias = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ Enumeration e = b.getBagAttributes().getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence sq = (ASN1Sequence)e.nextElement();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
+ ASN1Primitive attr = (ASN1Primitive)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
+ PKCS12BagAttributeCarrier bagAttr = null;
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+ if (existing != null)
+ {
+ // OK, but the value has to be the same
+ if (!existing.toASN1Primitive().equals(attr))
+ {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ }
+ else
+ {
+ bagAttr.setBagAttribute(oid, attr);
+ }
+ }
+
+ if (oid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ }
+ else if (oid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.isEmpty())
+ {
+ String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+ keyCerts.put(name, cert);
+ keys.put(name, keys.remove("unmarked"));
+ }
+ }
+ else
+ {
+ //
+ // the local key id needs to override the friendly name
+ //
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ keyCerts.put(name, cert);
+ }
+ if (alias != null)
+ {
+ certs.put(alias, cert);
+ }
+ }
+ }
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ doStore(stream, password, false);
+ }
+
+ private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
+ throws IOException
+ {
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ //
+ // handle the key
+ //
+ ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+
+ Enumeration ks = keys.keys();
+
+ while (ks.hasMoreElements())
+ {
+ byte[] kSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(kSalt);
+
+ String name = (String)ks.nextElement();
+ PrivateKey privKey = (PrivateKey)keys.get(name);
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.spongycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+ boolean attrSet = false;
+ ASN1EncodableVector kName = new ASN1EncodableVector();
+
+ if (privKey instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ Certificate ct = engineGetCertificate(name);
+
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+ kSeq.add(oid);
+ kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+ attrSet = true;
+
+ kName.add(new DERSequence(kSeq));
+ }
+ }
+
+ if (!attrSet)
+ {
+ //
+ // set a default friendly name (from the key id) and local id
+ //
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+ Certificate ct = engineGetCertificate(name);
+
+ kSeq.add(pkcs_9_at_localKeyId);
+ kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+ kName.add(new DERSequence(kSeq));
+
+ kSeq = new ASN1EncodableVector();
+
+ kSeq.add(pkcs_9_at_friendlyName);
+ kSeq.add(new DERSet(new DERBMPString(name)));
+
+ kName.add(new DERSequence(kSeq));
+ }
+
+ SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
+ keyS.add(kBag);
+ }
+
+ byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
+ BEROctetString keyString = new BEROctetString(keySEncoded);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(cSalt);
+
+ ASN1EncodableVector certSeq = new ASN1EncodableVector();
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ Hashtable doneCerts = new Hashtable();
+
+ Enumeration cs = keys.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String name = (String)cs.nextElement();
+ Certificate cert = engineGetCertificate(name);
+ boolean cAttrSet = false;
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_localKeyId);
+ fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+ fName.add(new DERSequence(fSeq));
+
+ fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(name)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = certs.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String certId = (String)cs.nextElement();
+ Certificate cert = (Certificate)certs.get(certId);
+ boolean cAttrSet = false;
+
+ if (keys.get(certId) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(certId))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(certId)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = chainCerts.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ CertId certId = (CertId)cs.nextElement();
+ Certificate cert = (Certificate)chainCerts.get(certId);
+
+ if (doneCerts.get(cert) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+ }
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
+ byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+ EncryptedData cInfo = new EncryptedData(data, cAlgId, new BEROctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(data, keyString),
+ new ContentInfo(encryptedData, cInfo.toASN1Primitive())
+ };
+
+ AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream asn1Out;
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(bOut);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(bOut);
+ }
+
+ asn1Out.writeObject(auth);
+
+ byte[] pkg = bOut.toByteArray();
+
+ ContentInfo mainInfo = new ContentInfo(data, new BEROctetString(pkg));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ int itCount = MIN_ITERATIONS;
+
+ random.nextBytes(mSalt);
+
+ byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+ MacData mData;
+
+ try
+ {
+ byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
+
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, DERNull.INSTANCE);
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(stream);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(stream);
+ }
+
+ asn1Out.writeObject(pfx);
+ }
+
+ private static byte[] calculatePbeMac(
+ ASN1ObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ boolean wrongPkcs12Zero,
+ byte[] data)
+ throws Exception
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
+ key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
+
+ Mac mac = Mac.getInstance(oid.getId(), bcProvider);
+ mac.init(key, defParams);
+ mac.update(data);
+ return mac.doFinal();
+ }
+
+ public static class BCPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class BCPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public BCPKCS12KeyStore3DES()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ public static class DefPKCS12KeyStore3DES
+ extends PKCS12KeyStoreSpi
+ {
+ public DefPKCS12KeyStore3DES()
+ {
+ super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ }
+ }
+
+ private static class IgnoresCaseHashtable
+ {
+ private Hashtable orig = new Hashtable();
+ private Hashtable keys = new Hashtable();
+
+ public void put(String key, Object value)
+ {
+ String lower = (key == null) ? null : Strings.toLowerCase(key);
+ String k = (String)keys.get(lower);
+ if (k != null)
+ {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ public Enumeration keys()
+ {
+ return orig.keys();
+ }
+
+ public Object remove(String alias)
+ {
+ String k = (String)keys.remove(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ public Object get(String alias)
+ {
+ String k = (String)keys.get(alias == null ? null : Strings.toLowerCase(alias));
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ public Enumeration elements()
+ {
+ return orig.elements();
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
new file mode 100644
index 00000000..d188bf69
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -0,0 +1,1031 @@
+package org.spongycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Method;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+
+import org.spongycastle.asn1.cms.GCMParameters;
+import org.spongycastle.crypto.BlockCipher;
+import org.spongycastle.crypto.BufferedBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DataLengthException;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.OutputLengthException;
+import org.spongycastle.crypto.modes.AEADBlockCipher;
+import org.spongycastle.crypto.modes.CBCBlockCipher;
+import org.spongycastle.crypto.modes.CCMBlockCipher;
+import org.spongycastle.crypto.modes.CFBBlockCipher;
+import org.spongycastle.crypto.modes.CTSBlockCipher;
+import org.spongycastle.crypto.modes.EAXBlockCipher;
+import org.spongycastle.crypto.modes.GCFBBlockCipher;
+import org.spongycastle.crypto.modes.GCMBlockCipher;
+import org.spongycastle.crypto.modes.GOFBBlockCipher;
+import org.spongycastle.crypto.modes.OCBBlockCipher;
+import org.spongycastle.crypto.modes.OFBBlockCipher;
+import org.spongycastle.crypto.modes.OpenPGPCFBBlockCipher;
+import org.spongycastle.crypto.modes.PGPCFBBlockCipher;
+import org.spongycastle.crypto.modes.SICBlockCipher;
+import org.spongycastle.crypto.paddings.BlockCipherPadding;
+import org.spongycastle.crypto.paddings.ISO10126d2Padding;
+import org.spongycastle.crypto.paddings.ISO7816d4Padding;
+import org.spongycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.spongycastle.crypto.paddings.TBCPadding;
+import org.spongycastle.crypto.paddings.X923Padding;
+import org.spongycastle.crypto.paddings.ZeroBytePadding;
+import org.spongycastle.crypto.params.AEADParameters;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.params.ParametersWithSBox;
+import org.spongycastle.crypto.params.RC2Parameters;
+import org.spongycastle.crypto.params.RC5Parameters;
+import org.spongycastle.jcajce.spec.GOST28147ParameterSpec;
+import org.spongycastle.jcajce.spec.RepeatedSecretKeySpec;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class BaseBlockCipher
+ extends BaseWrapCipher
+ implements PBE
+{
+ private static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
+
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ RC2ParameterSpec.class,
+ RC5ParameterSpec.class,
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ GOST28147ParameterSpec.class,
+ gcmSpecClass
+ };
+
+ private BlockCipher baseEngine;
+ private BlockCipherProvider engineProvider;
+ private GenericBlockCipher cipher;
+ private ParametersWithIV ivParam;
+ private AEADParameters aeadParams;
+
+ private int ivLength = 0;
+
+ private boolean padded;
+
+ private PBEParameterSpec pbeSpec = null;
+ private String pbeAlgorithm = null;
+
+ private String modeName = null;
+
+ private static Class lookup(String className)
+ {
+ try
+ {
+ Class def = BaseBlockCipher.class.getClassLoader().loadClass(className);
+
+ return def;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ protected BaseBlockCipher(
+ BlockCipher engine)
+ {
+ baseEngine = engine;
+
+ cipher = new BufferedGenericBlockCipher(engine);
+ }
+
+ protected BaseBlockCipher(
+ BlockCipherProvider provider)
+ {
+ baseEngine = provider.get();
+ engineProvider = provider;
+
+ cipher = new BufferedGenericBlockCipher(provider.get());
+ }
+
+ protected BaseBlockCipher(
+ AEADBlockCipher engine)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(engine);
+ }
+
+ protected BaseBlockCipher(
+ org.spongycastle.crypto.BlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine;
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected BaseBlockCipher(
+ BufferedBlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return baseEngine.getBlockSize();
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (ivParam != null) ? ivParam.getIV() : null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length * 8;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return cipher.getOutputSize(inputLen);
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (pbeSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(pbeSpec);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ else if (ivParam != null)
+ {
+ String name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+ if (name.indexOf('/') >= 0)
+ {
+ name = name.substring(0, name.indexOf('/'));
+ }
+
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(ivParam.getIV());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ else if (aeadParams != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("GCM", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize()).getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("ECB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(baseEngine);
+ }
+ else if (modeName.equals("CBC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new CBCBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("CFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("PGP"))
+ {
+ boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new PGPCFBBlockCipher(baseEngine, inlineIV));
+ }
+ else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(
+ new OpenPGPCFBBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("SIC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (ivLength < 16)
+ {
+ throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
+ }
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTR"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("GOFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new GOFBBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("GCFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new GCFBBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTS"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CCM"))
+ {
+ ivLength = 13; // CCM nonce 7..13 bytes
+ cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OCB"))
+ {
+ if (engineProvider != null)
+ {
+ /*
+ * RFC 7253 4.2. Nonce is a string of no more than 120 bits
+ */
+ ivLength = 15;
+ cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+ else if (modeName.startsWith("EAX"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("GCM"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ if (paddingName.equals("NOPADDING"))
+ {
+ if (cipher.wrapOnNoPadding())
+ {
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ }
+ else if (paddingName.equals("WITHCTS"))
+ {
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ else
+ {
+ padded = true;
+
+ if (isAEADModeName(modeName))
+ {
+ throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (paddingName.equals("ZEROBYTEPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+ }
+ else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+ }
+ else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+ }
+ else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+ }
+ else if (paddingName.equals("TBCPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+ }
+ else
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ this.pbeSpec = null;
+ this.pbeAlgorithm = null;
+ this.engineParams = null;
+ this.aeadParams = null;
+
+ //
+ // basic key check
+ //
+ if (!(key instanceof SecretKey))
+ {
+ throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
+ }
+
+ //
+ // for RC5-64 we must have some default parameters
+ //
+ if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+ {
+ throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+ }
+
+ //
+ // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+ //
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getOID() != null)
+ {
+ pbeAlgorithm = k.getOID().getId();
+ }
+ else
+ {
+ pbeAlgorithm = k.getAlgorithm();
+ }
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ if (params instanceof IvParameterSpec)
+ {
+ IvParameterSpec iv = (IvParameterSpec)params;
+
+ param = new ParametersWithIV(param, iv.getIV());
+ }
+ else if (params instanceof GOST28147ParameterSpec)
+ {
+ // need to pick up IV and SBox.
+ GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+ param = new ParametersWithSBox(param, gost28147Param.getSbox());
+
+ if (gost28147Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, gost28147Param.getIV());
+ }
+ }
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ pbeSpec = (PBEParameterSpec)params;
+ param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+
+ if (param instanceof ParametersWithIV)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ if (ivLength != 0)
+ {
+ IvParameterSpec p = (IvParameterSpec)params;
+
+ if (p.getIV().length != ivLength && !isAEADModeName(modeName))
+ {
+ throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+ }
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = new ParametersWithIV(null, p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else
+ {
+ if (modeName != null && modeName.equals("ECB"))
+ {
+ throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+ }
+
+ param = new KeyParameter(key.getEncoded());
+ }
+ }
+ else if (params instanceof GOST28147ParameterSpec)
+ {
+ GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+
+ param = new ParametersWithSBox(
+ new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+
+ if (gost28147Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, gost28147Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params instanceof RC2ParameterSpec)
+ {
+ RC2ParameterSpec rc2Param = (RC2ParameterSpec)params;
+
+ param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+
+ if (rc2Param.getIV() != null && ivLength != 0)
+ {
+ param = new ParametersWithIV(param, rc2Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params instanceof RC5ParameterSpec)
+ {
+ RC5ParameterSpec rc5Param = (RC5ParameterSpec)params;
+
+ param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+ if (baseEngine.getAlgorithmName().startsWith("RC5"))
+ {
+ if (baseEngine.getAlgorithmName().equals("RC5-32"))
+ {
+ if (rc5Param.getWordSize() != 32)
+ {
+ throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+ }
+ }
+ else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+ {
+ if (rc5Param.getWordSize() != 64)
+ {
+ throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+ }
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+ }
+ if ((rc5Param.getIV() != null) && (ivLength != 0))
+ {
+ param = new ParametersWithIV(param, rc5Param.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (gcmSpecClass != null && gcmSpecClass.isInstance(params))
+ {
+ if (!isAEADModeName(modeName) && !(cipher instanceof AEADGenericBlockCipher))
+ {
+ throw new InvalidAlgorithmParameterException("GCMParameterSpec can only be used with AEAD modes.");
+ }
+
+ try
+ {
+ Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
+ Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+ }
+ else
+ {
+ param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ if ((ivLength != 0) && !(param instanceof ParametersWithIV) && !(param instanceof AEADParameters))
+ {
+ SecureRandom ivRandom = random;
+
+ if (ivRandom == null)
+ {
+ ivRandom = new SecureRandom();
+ }
+
+ if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
+ {
+ byte[] iv = new byte[ivLength];
+
+ ivRandom.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ ivParam = (ParametersWithIV)param;
+ }
+ else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ if (random != null && padded)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ try
+ {
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ for (int i = 0; i != availableSpecs.length; i++)
+ {
+ if (availableSpecs[i] == null)
+ {
+ continue;
+ }
+
+ try
+ {
+ paramSpec = params.getParameterSpec(availableSpecs[i]);
+ break;
+ }
+ catch (Exception e)
+ {
+ // try again if possible
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineInit(opmode, key, paramSpec, random);
+
+ engineParams = params;
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+
+ protected void engineUpdateAAD(byte[] input, int offset, int length)
+ {
+ cipher.updateAAD(input, offset, length);
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ int length = cipher.getUpdateOutputSize(inputLen);
+
+ if (length > 0)
+ {
+ byte[] out = new byte[length];
+
+ int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+ if (len == 0)
+ {
+ return null;
+ }
+ else if (len != out.length)
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(out, 0, tmp, 0, len);
+
+ return tmp;
+ }
+
+ return out;
+ }
+
+ cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ try
+ {
+ return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+ catch (DataLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ int len = 0;
+ byte[] tmp = new byte[engineGetOutputSize(inputLen)];
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+ }
+
+ try
+ {
+ len += cipher.doFinal(tmp, len);
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ if (len == tmp.length)
+ {
+ return tmp;
+ }
+
+ byte[] out = new byte[len];
+
+ System.arraycopy(tmp, 0, out, 0, len);
+
+ return out;
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+ {
+ try
+ {
+ int len = 0;
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ return (len + cipher.doFinal(output, outputOffset + len));
+ }
+ catch (OutputLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ private boolean isAEADModeName(
+ String modeName)
+ {
+ return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName) || "OCB".equals(modeName);
+ }
+
+ /*
+ * The ciphers that inherit from us.
+ */
+
+ static private interface GenericBlockCipher
+ {
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ public boolean wrapOnNoPadding();
+
+ public String getAlgorithmName();
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher();
+
+ public int getOutputSize(int len);
+
+ public int getUpdateOutputSize(int len);
+
+ public void updateAAD(byte[] input, int offset, int length);
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException;
+ }
+
+ private static class BufferedGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private BufferedBlockCipher cipher;
+
+ BufferedGenericBlockCipher(BufferedBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ BufferedGenericBlockCipher(org.spongycastle.crypto.BlockCipher cipher)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher);
+ }
+
+ BufferedGenericBlockCipher(org.spongycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return !(cipher instanceof CTSBlockCipher);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public void updateAAD(byte[] input, int offset, int length)
+ {
+ throw new UnsupportedOperationException("AAD is not supported in the current mode.");
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+
+ private static class AEADGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private AEADBlockCipher cipher;
+
+ AEADGenericBlockCipher(AEADBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return false;
+ }
+
+ public org.spongycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public void updateAAD(byte[] input, int offset, int length)
+ {
+ cipher.processAADBytes(input, offset, length);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jcajce/util/ProviderJcaJceHelper.java b/prov/src/main/jdk1.3/org/spongycastle/jcajce/util/ProviderJcaJceHelper.java
new file mode 100644
index 00000000..5f211dbe
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jcajce/util/ProviderJcaJceHelper.java
@@ -0,0 +1,106 @@
+package org.spongycastle.jcajce.util;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+import org.spongycastle.jcajce.util.JcaJceHelper;
+
+public class ProviderJcaJceHelper
+ implements JcaJceHelper
+{
+ protected final Provider provider;
+
+ public ProviderJcaJceHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException
+ {
+ return Cipher.getInstance(algorithm, provider.getName());
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Mac.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyAgreement.getInstance(algorithm, provider.getName());
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm, provider.getName());
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameters.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyGenerator.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyFactory.getInstance(algorithm, provider.getName());
+ }
+
+ public SecretKeyFactory createSecretKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return SecretKeyFactory.getInstance(algorithm, provider.getName());
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyPairGenerator.getInstance(algorithm, provider.getName());
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return MessageDigest.getInstance(algorithm, provider.getName());
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Signature.getInstance(algorithm, provider.getName());
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException
+ {
+ return CertificateFactory.getInstance(algorithm, provider.getName());
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java
new file mode 100644
index 00000000..c2343e10
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/ECKeyUtil.java
@@ -0,0 +1,229 @@
+package org.spongycastle.jce;
+
+import java.io.UnsupportedEncodingException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X962Parameters;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * Utility class to allow conversion of EC key parameters to explicit from named
+ * curves and back (where possible).
+ */
+public class ECKeyUtil
+{
+ /**
+ * Convert a passed in public EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param providerName provider name to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ */
+ public static PublicKey publicToExplicitParameters(PublicKey key, String providerName)
+ throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ Provider provider = Security.getProvider(providerName);
+
+ if (provider == null)
+ {
+ throw new NoSuchProviderException("cannot find provider: " + providerName);
+ }
+
+ return publicToExplicitParameters(key, provider);
+ }
+
+ /**
+ * Convert a passed in public EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param provider provider to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ */
+ public static PublicKey publicToExplicitParameters(PublicKey key, Provider provider)
+ throws IllegalArgumentException, NoSuchAlgorithmException
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded()));
+
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ throw new IllegalArgumentException("cannot convert GOST key to explicit parameters.");
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ X9ECParameters curveParams;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+ curveParams = ECUtil.getNamedCurveByOid(oid);
+ // ignore seed value due to JDK bug
+ curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH());
+ }
+ else
+ {
+ return key; // already explicit
+ }
+
+ params = new X962Parameters(curveParams);
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.getPublicKeyData().getBytes());
+
+ KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider.getName());
+
+ return keyFact.generatePublic(new X509EncodedKeySpec(info.getEncoded()));
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ { // shouldn't really happen...
+ throw new UnexpectedException(e);
+ }
+ }
+
+ /**
+ * Convert a passed in private EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param providerName provider name to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ * @throws NoSuchProviderException
+ */
+ public static PrivateKey privateToExplicitParameters(PrivateKey key, String providerName)
+ throws IllegalArgumentException, NoSuchAlgorithmException, NoSuchProviderException
+ {
+ Provider provider = Security.getProvider(providerName);
+
+ if (provider == null)
+ {
+ throw new NoSuchProviderException("cannot find provider: " + providerName);
+ }
+
+ return privateToExplicitParameters(key, provider);
+ }
+
+ /**
+ * Convert a passed in private EC key to have explicit parameters. If the key
+ * is already using explicit parameters it is returned.
+ *
+ * @param key key to be converted
+ * @param provider provider to be used.
+ * @return the equivalent key with explicit curve parameters
+ * @throws IllegalArgumentException
+ * @throws NoSuchAlgorithmException
+ */
+ public static PrivateKey privateToExplicitParameters(PrivateKey key, Provider provider)
+ throws IllegalArgumentException, NoSuchAlgorithmException
+ {
+ try
+ {
+ PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded()));
+
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ throw new UnsupportedEncodingException("cannot convert GOST key to explicit parameters.");
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ X9ECParameters curveParams;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+
+ curveParams = ECUtil.getNamedCurveByOid(oid);
+ // ignore seed value due to JDK bug
+ curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH());
+ }
+ else
+ {
+ return key; // already explicit
+ }
+
+ params = new X962Parameters(curveParams);
+
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), info.parsePrivateKey());
+
+ KeyFactory keyFact = KeyFactory.getInstance(key.getAlgorithm(), provider.getName());
+
+ return keyFact.generatePrivate(new PKCS8EncodedKeySpec(info.getEncoded()));
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw e;
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ { // shouldn't really happen
+ throw new UnexpectedException(e);
+ }
+ }
+
+ private static class UnexpectedException
+ extends RuntimeException
+ {
+ private Throwable cause;
+
+ UnexpectedException(Throwable cause)
+ {
+ super(cause.toString());
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java
new file mode 100644
index 00000000..42f46648
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/MultiCertStoreParameters.java
@@ -0,0 +1,51 @@
+package org.spongycastle.jce;
+
+import org.spongycastle.jce.cert.CertStoreParameters;
+import java.util.Collection;
+
+public class MultiCertStoreParameters
+ implements CertStoreParameters
+{
+ private Collection certStores;
+ private boolean searchAllStores;
+
+ /**
+ * Create a parameters object which specifies searching of all the passed in stores.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ */
+ public MultiCertStoreParameters(Collection certStores)
+ {
+ this(certStores, true);
+ }
+
+ /**
+ * Create a parameters object which can be to used to make a multi store made up
+ * of the passed in CertStores. If the searchAllStores parameter is false, any search on
+ * the multi-store will terminate as soon as a search query produces a result.
+ *
+ * @param certStores CertStores making up the multi CertStore
+ * @param searchAllStores true if all CertStores should be searched on request, false if a result
+ * should be returned on the first successful CertStore query.
+ */
+ public MultiCertStoreParameters(Collection certStores, boolean searchAllStores)
+ {
+ this.certStores = certStores;
+ this.searchAllStores = searchAllStores;
+ }
+
+ public Collection getCertStores()
+ {
+ return certStores;
+ }
+
+ public boolean getSearchAllStores()
+ {
+ return searchAllStores;
+ }
+
+ public Object clone()
+ {
+ return this;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java b/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java
new file mode 100644
index 00000000..b9bc6e52
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/PKCS10CertificationRequest.java
@@ -0,0 +1,583 @@
+package org.spongycastle.jce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Set;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.CertificationRequest;
+import org.spongycastle.asn1.pkcs.CertificationRequestInfo;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+/**
+ * A class for verifying and creating PKCS10 Certification requests.
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ * signature BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version INTEGER { v1(0) } (v1,...),
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ * attributes [0] Attributes{{ CRIAttributes }}
+ * }
+ *
+ * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
+ *
+ * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
+ * type ATTRIBUTE.&id({IOSet}),
+ * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
+ * }
+ * </pre>
+ * @deprecated use classes in org.spongycastle.pkcs.
+ */
+public class PKCS10CertificationRequest
+ extends CertificationRequest
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Hashtable keyAlgorithms = new Hashtable();
+ private static Hashtable oids = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD2WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"));
+ algorithms.put("MD5WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("MD5WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("RSAWITHMD5", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
+ algorithms.put("SHA1WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("SHA1WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", new ASN1ObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("DSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.10040.4.3"));
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // reverse mappings
+ //
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+ oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+ oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+
+ //
+ // key types
+ //
+ keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull());
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
+ params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull());
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull());
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ private static ASN1Sequence toDERSequence(
+ byte[] bytes)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+
+ return (ASN1Sequence)dIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("badly encoded request");
+ }
+ }
+
+ /**
+ * construct a PKCS10 certification request from a DER encoded
+ * byte stream.
+ */
+ public PKCS10CertificationRequest(
+ byte[] bytes)
+ {
+ super(toDERSequence(bytes));
+ }
+
+ public PKCS10CertificationRequest(
+ ASN1Sequence sequence)
+ {
+ super(sequence);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the BC provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, subject, key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+
+ /**
+ * create a PKCS10 certfication request using the named provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ String algorithmName = Strings.toUpperCase(signatureAlgorithm);
+ ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName);
+
+ if (sigOID == null)
+ {
+ try
+ {
+ sigOID = new ASN1ObjectIdentifier(algorithmName);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+ }
+
+ if (subject == null)
+ {
+ throw new IllegalArgumentException("subject must not be null");
+ }
+
+ if (key == null)
+ {
+ throw new IllegalArgumentException("public key must not be null");
+ }
+
+ if (noParams.contains(sigOID))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID);
+ }
+ else if (params.containsKey(algorithmName))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
+ }
+
+ try
+ {
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded());
+ this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo(seq), attributes);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't encode public key");
+ }
+
+ Signature sig;
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+
+ sig.initSign(signingKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("exception encoding TBS cert request - " + e);
+ }
+
+ this.sigBits = new DERBitString(sig.sign());
+ }
+
+ /**
+ * return the public key associated with the certification request -
+ * the public key is created using the BC provider.
+ */
+ public PublicKey getPublicKey()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
+ {
+ return getPublicKey(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public PublicKey getPublicKey(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException
+ {
+ SubjectPublicKeyInfo subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
+
+
+ try
+ {
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
+ AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithm();
+ try
+ {
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlg.getAlgorithm().getId()).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), provider).generatePublic(xspec);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (keyAlgorithms.get(keyAlg.getObjectId()) != null)
+ {
+ String keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId());
+
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlgorithm).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec);
+ }
+ }
+
+ throw e;
+ }
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ }
+
+ /**
+ * verify the request using the BC provider.
+ */
+ public boolean verify()
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ /**
+ * verify the request using the passed in provider.
+ */
+ public boolean verify(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(this.getPublicKey(provider), provider);
+ }
+
+ /**
+ * verify the request using the passed in public key and the provider..
+ */
+ public boolean verify(
+ PublicKey pubKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ try
+ {
+ if (provider == null)
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId));
+ }
+ else
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId), provider);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getObjectId()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId());
+
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ setSignatureParameters(sig, sigAlgId.getParameters(), provider);
+
+ sig.initVerify(pubKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("exception encoding TBS cert request - " + e);
+ }
+
+ return sig.verify(sigBits.getBytes());
+ }
+
+ /**
+ * return a DER encoded byte array representing this object
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ return this.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ private void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), provider);
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ private static String getDigestAlgName(
+ ASN1ObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ {
+ return "SHA224";
+ }
+ else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
+ {
+ return "SHA256";
+ }
+ else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
+ {
+ return "SHA384";
+ }
+ else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
+ {
+ return "SHA512";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
+ {
+ return "RIPEMD128";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
+ {
+ return "RIPEMD160";
+ }
+ else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
+ {
+ return "RIPEMD256";
+ }
+ else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
+ {
+ return "GOST3411";
+ }
+ else
+ {
+ return digestAlgOID.getId();
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java
new file mode 100644
index 00000000..0cafff5c
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CRLSelector.java
@@ -0,0 +1,41 @@
+package org.spongycastle.jce.cert;
+
+import java.security.cert.CRL;
+
+/**
+ * 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java
new file mode 100644
index 00000000..34f9c628
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPath.java
@@ -0,0 +1,296 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+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 java.security.cert.Certificate#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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java
new file mode 100644
index 00000000..54585689
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilder.java
@@ -0,0 +1,255 @@
+package org.spongycastle.jce.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 />
+ */
+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 &quot;PKIX&quot; if no
+ * such property exists. The Java security properties file is located in the
+ * file named &lt;JAVA_HOME&gt;/lib/security/java.security, where
+ * &lt;JAVA_HOME&gt; 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 &quot;PKIX&quot;
+ * 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java
new file mode 100644
index 00000000..1dce8758
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderException.java
@@ -0,0 +1,182 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java
new file mode 100644
index 00000000..a1518cba
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderResult.java
@@ -0,0 +1,38 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java
new file mode 100644
index 00000000..bb08d99a
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathBuilderSpi.java
@@ -0,0 +1,50 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java
new file mode 100644
index 00000000..96978bd7
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathParameters.java
@@ -0,0 +1,18 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java
new file mode 100644
index 00000000..d2e59931
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidator.java
@@ -0,0 +1,276 @@
+package org.spongycastle.jce.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 />
+ * @see CertPath
+ **/
+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 &quot;PKIX&quot; if no
+ * such property exists. The Java security properties file is located in the
+ * file named &lt;JAVA_HOME&gt;/lib/security/java.security, where
+ * &lt;JAVA_HOME&gt; 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 &quot;PKIX&quot;
+ * 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java
new file mode 100644
index 00000000..bcd67a4a
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorException.java
@@ -0,0 +1,271 @@
+package org.spongycastle.jce.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)
+ {
+ return message;
+ }
+
+ if (cause != null)
+ {
+ return cause.getMessage();
+ }
+
+ return null;
+ }
+
+ /**
+ * 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java
new file mode 100644
index 00000000..e31b23f2
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorResult.java
@@ -0,0 +1,22 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java
new file mode 100644
index 00000000..39f706d2
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertPathValidatorSpi.java
@@ -0,0 +1,59 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java
new file mode 100644
index 00000000..2f2b0b46
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertSelector.java
@@ -0,0 +1,41 @@
+package org.spongycastle.jce.cert;
+
+import java.security.cert.Certificate;
+
+/**
+ * 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java
new file mode 100644
index 00000000..8a284262
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStore.java
@@ -0,0 +1,382 @@
+package org.spongycastle.jce.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 />
+ **/
+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 &quot;LDAP&quot; if no such
+ * property exists. The Java security properties file is located in the file
+ * named &lt;JAVA_HOME&gt;/lib/security/java.security, where
+ * &lt;JAVA_HOME&gt; 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 &quot;LDAP&quot; 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java
new file mode 100644
index 00000000..56c9fcfd
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreException.java
@@ -0,0 +1,187 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java
new file mode 100644
index 00000000..0ec14ede
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreParameters.java
@@ -0,0 +1,52 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java
new file mode 100644
index 00000000..fd9fe6a3
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertStoreSpi.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java
new file mode 100644
index 00000000..60c5e8b0
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertUtil.java
@@ -0,0 +1,556 @@
+package org.spongycastle.jce.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.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.OIDTokenizer;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.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.spongycastle.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;
+ }
+} \ No newline at end of file
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java
new file mode 100644
index 00000000..a1ead1a6
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactory.java
@@ -0,0 +1,183 @@
+package org.spongycastle.jce.cert;
+
+import java.io.InputStream;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ **/
+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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java
new file mode 100644
index 00000000..1bed7721
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CertificateFactorySpi.java
@@ -0,0 +1,99 @@
+package org.spongycastle.jce.cert;
+
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class CertificateFactorySpi
+ extends java.security.cert.CertificateFactorySpi
+{
+ public CertificateFactorySpi()
+ {
+ }
+
+ /**
+ * 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java
new file mode 100644
index 00000000..1692fefa
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/CollectionCertStoreParameters.java
@@ -0,0 +1,124 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java
new file mode 100644
index 00000000..306c6661
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/LDAPCertStoreParameters.java
@@ -0,0 +1,138 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java
new file mode 100644
index 00000000..79136ad3
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXBuilderParameters.java
@@ -0,0 +1,190 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java
new file mode 100644
index 00000000..0288b850
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathBuilderResult.java
@@ -0,0 +1,103 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java
new file mode 100644
index 00000000..07c71ca2
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathChecker.java
@@ -0,0 +1,163 @@
+package org.spongycastle.jce.cert;
+
+import java.security.cert.Certificate;
+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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java
new file mode 100644
index 00000000..aa9b530f
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXCertPathValidatorResult.java
@@ -0,0 +1,150 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java
new file mode 100644
index 00000000..a9d2d383
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PKIXParameters.java
@@ -0,0 +1,844 @@
+package org.spongycastle.jce.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+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(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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java
new file mode 100644
index 00000000..ae9199b3
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyNode.java
@@ -0,0 +1,107 @@
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java
new file mode 100644
index 00000000..97e9c5fa
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/PolicyQualifierInfo.java
@@ -0,0 +1,196 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier} and
+ * {@link org.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.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();
+ }
+} \ No newline at end of file
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java
new file mode 100644
index 00000000..68a9abf3
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/TrustAnchor.java
@@ -0,0 +1,293 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.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);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java
new file mode 100644
index 00000000..4a377ed3
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CRLSelector.java
@@ -0,0 +1,717 @@
+package org.spongycastle.jce.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.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.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.spongycastle.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.spongycastle.asn1.x509.X509Name X509Name} for parsing the
+ * name, {@link org.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object} and
+ * {@link org.spongycastle.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.spongycastle.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.spongycastle.asn1.x509.X509Name#toString X509Name.toString} to
+ * parse and to compare the crl parameter issuer and
+ * {@link org.spongycastle.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 = ((ASN1Integer)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;
+ }
+} \ No newline at end of file
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java
new file mode 100644
index 00000000..0b288faa
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java
@@ -0,0 +1,2469 @@
+package org.spongycastle.jce.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.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.ExtendedKeyUsage;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.OIDTokenizer OIDTokenizer},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name},
+ * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions},
+ * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId},
+ * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
+ * {@link org.spongycastle.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.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.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.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.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
+ {
+ if (oid != null)
+ {
+ CertUtil.parseOID(oid);
+ subjectKeyAlgID = new ASN1ObjectIdentifier(oid);
+ }
+ else
+ {
+ subjectKeyAlgID = null;
+ }
+ }
+
+ /**
+ * 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.spongycastle.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.spongycastle.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.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.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.spongycastle.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.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.DERGeneralizedTime DERGeneralizedTime},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name},
+ * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions},
+ * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId},
+ * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
+ * {@link org.spongycastle.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();
+ ASN1GeneralizedTime derDate = ASN1GeneralizedTime
+ .getInstance(derObject.getObjectAt(0));
+ SimpleDateFormat dateF = new SimpleDateFormat(
+ "yyyyMMddHHmmssZ");
+ if (privateKeyValid.before(dateF.parse(derDate.getTime())))
+ {
+ return false;
+ }
+ derDate = ASN1GeneralizedTime.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(
+ 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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java
new file mode 100644
index 00000000..f2c7e199
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509Extension.java
@@ -0,0 +1,12 @@
+
+package org.spongycastle.jce.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/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html
new file mode 100644
index 00000000..c5cd3f6a
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/cert/package.html
@@ -0,0 +1,5 @@
+<html>
+<body bgcolor="#ffffff">
+Compatibility API for the JDK 1.4 CertPath API.
+</body>
+</html>
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
new file mode 100644
index 00000000..b238580f
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathBuilderException.java
@@ -0,0 +1,29 @@
+package org.spongycastle.jce.exception;
+
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathBuilderException;
+
+public class ExtCertPathBuilderException
+ extends CertPathBuilderException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtCertPathBuilderException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathBuilderException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
new file mode 100644
index 00000000..ec2b667d
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/exception/ExtCertPathValidatorException.java
@@ -0,0 +1,30 @@
+package org.spongycastle.jce.exception;
+
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+
+public class ExtCertPathValidatorException
+ extends CertPathValidatorException
+ implements ExtException
+{
+
+ private Throwable cause;
+
+ public ExtCertPathValidatorException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathValidatorException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause, certPath, index);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 00000000..40bf81da
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,1417 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.PolicyQualifierInfo;
+import org.spongycastle.jce.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import org.spongycastle.jce.cert.X509CRLSelector;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509Store;
+
+public class CertPathValidatorUtilities
+{
+ protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+ protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+ protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+ protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+ protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+ protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+ protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+ protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+ protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+ protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+ protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+ protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+ protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ protected static final String ANY_POLICY = "2.5.29.32.0";
+
+ protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+ protected static final int CRL_SIGN = 6;
+
+ protected static final String[] crlReasons = new String[]{
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the default provider
+ * for signature verification.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws AnnotatedException
+ {
+ return findTrustAnchor(cert, trustAnchors, null);
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the specified
+ * provider for signature verification, or the default provider
+ * if null.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @param sigProvider the provider to use for signature verification
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors,
+ String sigProvider)
+ throws AnnotatedException
+ {
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+ X509Principal certIssuer = getEncodedIssuerPrincipal(cert);
+
+ try
+ {
+ certSelectX509.setSubject(certIssuer.getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
+ }
+
+ Iterator iter = trustAnchors.iterator();
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X509Principal caName = new X509Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ verifyX509Certificate(cert, trustPublicKey, sigProvider);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ trustPublicKey = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ protected static void addAdditionalStoresFromAltNames(
+ X509Certificate cert,
+ ExtendedPKIXParameters pkixParams)
+ throws CertificateParsingException
+ {
+ // if in the IssuerAltName extension an URI
+ // is given, add an additinal X.509 store
+/*
+ if (cert.getIssuerAlternativeNames() != null)
+ {
+ Iterator it = cert.getIssuerAlternativeNames().iterator();
+ while (it.hasNext())
+ {
+ // look for URI
+ List list = (List)it.next();
+ if (list.get(0).equals(new Integer(GeneralName.uniformResourceIdentifier)))
+ {
+ // found
+ String temp = (String)list.get(1);
+ CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
+ }
+ }
+ }
+*/
+ }
+
+ /**
+ * Returns the issuer of an attribute certificate or certificate.
+ *
+ * @param cert The attribute certificate or certificate.
+ * @return The issuer as <code>X509Principal</code>.
+ */
+ protected static X509Principal getEncodedIssuerPrincipal(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+try
+{
+ return PrincipalUtil.getIssuerX509Principal((X509Certificate)cert);
+}
+catch (Exception e)
+{
+throw new IllegalStateException(e.toString());
+}
+ }
+ else
+ {
+ return (X509Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
+ }
+ }
+
+ protected static Date getValidDate(PKIXParameters paramsPKIX)
+ {
+ Date validDate = paramsPKIX.getDate();
+
+ if (validDate == null)
+ {
+ validDate = new Date();
+ }
+
+ return validDate;
+ }
+
+ protected static X509Principal getSubjectPrincipal(X509Certificate cert)
+ {
+try
+{
+ return PrincipalUtil.getSubjectX509Principal(cert);
+}
+catch (Exception e)
+{
+throw new IllegalStateException(e.toString());
+}
+ }
+
+ protected static boolean isSelfIssued(X509Certificate cert)
+ {
+ return cert.getSubjectDN().equals(cert.getIssuerDN());
+ }
+
+
+ /**
+ * Extract the value of the given extension, if it exists.
+ *
+ * @param ext The extension object.
+ * @param oid The object identifier to obtain.
+ * @throws AnnotatedException if the extension cannot be read.
+ */
+ protected static ASN1Primitive getExtensionValue(
+ java.security.cert.X509Extension ext,
+ String oid)
+ throws AnnotatedException
+ {
+ byte[] bytes = ext.getExtensionValue(oid);
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ return getObject(oid, bytes);
+ }
+
+ private static ASN1Primitive getObject(
+ String oid,
+ byte[] ext)
+ throws AnnotatedException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ext);
+ ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+ aIn = new ASN1InputStream(octs.getOctets());
+ return aIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("exception processing extension " + oid, e);
+ }
+ }
+
+ protected static X509Principal getIssuerPrincipal(X509CRL crl)
+ {
+try
+{
+ return PrincipalUtil.getIssuerX509Principal(crl);
+}
+catch (Exception e)
+{
+ throw new IllegalStateException(e.toString());
+}
+ }
+
+ protected static AlgorithmIdentifier getAlgorithmIdentifier(
+ PublicKey key)
+ throws CertPathValidatorException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ return info.getAlgorithmId();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
+ }
+ }
+
+ // crl checking
+
+
+ //
+ // policy checking
+ //
+
+ protected static final Set getQualifierSet(ASN1Sequence qualifiers)
+ throws CertPathValidatorException
+ {
+ Set pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = qualifiers.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+ }
+ catch (IOException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+ }
+
+ bOut.reset();
+ }
+
+ return pq;
+ }
+
+ protected static PKIXPolicyNode removePolicyNode(
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.removeChild(_node);
+ removePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private static void removePolicyNodeRecurse(
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ policyNodes[_node.getDepth()].remove(_node);
+
+ if (_node.hasChildren())
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+ removePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+
+ protected static boolean processCertD1i(
+ int index,
+ List[] policyNodes,
+ ASN1ObjectIdentifier pOid,
+ Set pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+ Set expectedPolicies = node.getExpectedPolicies();
+
+ if (expectedPolicies.contains(pOid.getId()))
+ {
+ Set childExpectedPolicies = new HashSet();
+ childExpectedPolicies.add(pOid.getId());
+
+ PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.getId(),
+ false);
+ node.addChild(child);
+ policyNodes[index].add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected static void processCertD1ii(
+ int index,
+ List[] policyNodes,
+ ASN1ObjectIdentifier _poid,
+ Set _pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Set _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.add(_poid.getId());
+
+ PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.getId(),
+ false);
+ _node.addChild(_child);
+ policyNodes[index].add(_child);
+ return;
+ }
+ }
+ }
+
+ protected static void prepareNextCertB1(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ Map m_idp,
+ X509Certificate cert
+ )
+ throws AnnotatedException, CertPathValidatorException
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Certificate policies cannot be decoded.", e);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new AnnotatedException("Policy information cannot be decoded.", ex);
+ }
+ if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be built.", ex);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(
+ new ArrayList(), i,
+ (Set)m_idp.get(id_p),
+ p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode prepareNextCertB2(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ PKIXPolicyNode validPolicyTree)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return validPolicyTree;
+ }
+
+ protected static boolean isAnyPolicy(
+ Set policySet)
+ {
+ return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty();
+ }
+
+ protected static void addAdditionalStoreFromLocation(String location,
+ ExtendedPKIXParameters pkixParams)
+ {
+ }
+
+ /**
+ * Return a Collection of all certificates or attribute certificates found
+ * in the X509Store's that are matching the certSelect criteriums.
+ *
+ * @param certSelect a {@link Selector} object that will be used to select
+ * the certificates
+ * @param certStores a List containing only {@link X509Store} objects. These
+ * are used to search for certificates.
+ * @return a Collection of all found {@link X509Certificate} or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} objects.
+ * May be empty but never <code>null</code>.
+ */
+ protected static Collection findCertificates(X509CertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ else
+ {
+ CertStore certStore = (CertStore)obj;
+
+ try
+ {
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+ catch (CertStoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from certificate store.",
+ e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect,
+ List certStores)
+ throws AnnotatedException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store certStore = (X509Store)obj;
+ try
+ {
+ certs.addAll(certStore.getMatches(certSelect));
+ }
+ catch (StoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from X.509 store.", e);
+ }
+ }
+ }
+ return certs;
+ }
+
+ protected static void addAdditionalStoresFromCRLDistributionPoint(
+ CRLDistPoint crldp, ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Distribution points could not be read.", e);
+ }
+ for (int i = 0; i < dps.length; i++)
+ {
+ DistributionPointName dpn = dps[i].getDistributionPoint();
+ // look for URIs in fullName
+ if (dpn != null)
+ {
+ if (dpn.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(
+ dpn.getName()).getNames();
+ // look for an URI
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String location = DERIA5String.getInstance(
+ genNames[j].getName()).getString();
+ CertPathValidatorUtilities
+ .addAdditionalStoreFromLocation(location,
+ pkixParams);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Add the CRL issuers from the cRLIssuer field of the distribution point or
+ * from the certificate if not given to the issuer criterion of the
+ * <code>selector</code>.
+ * <p/>
+ * The <code>issuerPrincipals</code> are a collection with a single
+ * <code>X509Principal</code> for <code>X509Certificate</code>s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * <code>X509Principal</code>.
+ *
+ * @param dp The distribution point.
+ * @param issuerPrincipals The issuers of the certificate or attribute
+ * certificate which contains the distribution point.
+ * @param selector The CRL selector.
+ * @param pkixParams The PKIX parameters containing the cert stores.
+ * @throws AnnotatedException if an exception occurs while processing.
+ * @throws ClassCastException if <code>issuerPrincipals</code> does not
+ * contain only <code>X509Principal</code>s.
+ */
+ protected static void getCRLIssuersFromDistributionPoint(
+ DistributionPoint dp,
+ Collection issuerPrincipals,
+ X509CRLSelector selector,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ List issuers = new ArrayList();
+ // indirect CRL
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ // look for a DN
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ issuers.add(new X509Principal(genNames[j].getName()
+ .toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.",
+ e);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * certificate issuer is CRL issuer, distributionPoint field MUST be
+ * present.
+ */
+ if (dp.getDistributionPoint() == null)
+ {
+ throw new AnnotatedException(
+ "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+ }
+ // add and check issuer principals
+ for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); )
+ {
+ issuers.add((X509Principal)it.next());
+ }
+ }
+ // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+ // distributionPoint
+// if (dp.getDistributionPoint() != null)
+// {
+// // look for nameRelativeToCRLIssuer
+// if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+// {
+// // append fragment to issuer, only one
+// // issuer can be there, if this is given
+// if (issuers.size() != 1)
+// {
+// throw new AnnotatedException(
+// "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+// }
+// ASN1Encodable relName = dp.getDistributionPoint().getName();
+// Iterator it = issuers.iterator();
+// List issuersTemp = new ArrayList(issuers.size());
+// while (it.hasNext())
+// {
+// Enumeration e = null;
+// try
+// {
+// e = ASN1Sequence.getInstance(
+// new ASN1InputStream(((X500Principal) it.next())
+// .getEncoded()).readObject()).getObjects();
+// }
+// catch (IOException ex)
+// {
+// throw new AnnotatedException(
+// "Cannot decode CRL issuer information.", ex);
+// }
+// ASN1EncodableVector v = new ASN1EncodableVector();
+// while (e.hasMoreElements())
+// {
+// v.add((ASN1Encodable) e.nextElement());
+// }
+// v.add(relName);
+// issuersTemp.add(new X500Principal(new DERSequence(v)
+// .getDEREncoded()));
+// }
+// issuers.clear();
+// issuers.addAll(issuersTemp);
+// }
+// }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ selector.addIssuerName(((X509Principal)it.next()).getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Cannot decode CRL issuer information.", ex);
+ }
+ }
+ }
+
+ private static BigInteger getSerialNumber(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getSerialNumber();
+ }
+ else
+ {
+ return ((X509AttributeCertificate)cert).getSerialNumber();
+ }
+ }
+
+ protected static void getCertStatus(
+ Date validDate,
+ X509CRL crl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ X509CRLEntry crl_entry = null;
+
+ boolean isIndirect;
+ try
+ {
+ isIndirect = X509CRLObject.isIndirectCRL(crl);
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed check for indirect CRL.", exception);
+ }
+
+ if (isIndirect)
+ {
+ if (!(crl instanceof X509CRLObject))
+ {
+ try
+ {
+ crl = new X509CRLObject(CertificateList.getInstance(crl.getEncoded()));
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed to recode indirect CRL.", exception);
+ }
+ }
+
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+
+ X509Principal certIssuer = ((X509CRLEntryObject)crl_entry).getCertificateIssuer();
+
+ if (certIssuer == null)
+ {
+ certIssuer = getIssuerPrincipal(crl);
+ }
+
+ if (!getEncodedIssuerPrincipal(cert).equals(certIssuer))
+ {
+ return;
+ }
+ }
+ else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl)))
+ {
+ return; // not for our issuer, ignore
+ }
+ else
+ {
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+ }
+
+ ASN1Enumerated reasonCode = null;
+ if (crl_entry.hasExtensions())
+ {
+ try
+ {
+ reasonCode = ASN1Enumerated
+ .getInstance(CertPathValidatorUtilities
+ .getExtensionValue(crl_entry,
+ X509Extension.reasonCode.getId()));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Reason code CRL entry extension could not be decoded.",
+ e);
+ }
+ }
+
+ // for reason keyCompromise, caCompromise, aACompromise or
+ // unspecified
+ if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
+ || reasonCode == null
+ || reasonCode.getValue().intValue() == 0
+ || reasonCode.getValue().intValue() == 1
+ || reasonCode.getValue().intValue() == 2
+ || reasonCode.getValue().intValue() == 8)
+ {
+
+ // (i) or (j) (1)
+ if (reasonCode != null)
+ {
+ certStatus.setCertStatus(reasonCode.getValue().intValue());
+ }
+ // (i) or (j) (2)
+ else
+ {
+ certStatus.setCertStatus(CRLReason.unspecified);
+ }
+ certStatus.setRevocationDate(crl_entry.getRevocationDate());
+ }
+ }
+
+ /**
+ * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+ *
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @param completeCRL The complete CRL the delta CRL is for.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the delta
+ * CRLs.
+ */
+ protected static Set getDeltaCRLs(Date currentDate,
+ ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
+ throws AnnotatedException
+ {
+
+ X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
+
+ // 5.2.4 (a)
+ try
+ {
+ deltaSelect.addIssuerName(CertPathValidatorUtilities
+ .getIssuerPrincipal(completeCRL).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL.", e);
+ }
+
+ BigInteger completeCRLNumber = null;
+ try
+ {
+ ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
+ CRL_NUMBER);
+ if (derObject != null)
+ {
+ completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "CRL number extension could not be extracted from CRL.", e);
+ }
+
+ // 5.2.4 (b)
+ byte[] idp = null;
+ try
+ {
+ idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension value could not be read.",
+ e);
+ }
+
+ // 5.2.4 (d)
+
+ deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
+ .add(BigInteger.valueOf(1)));
+
+ deltaSelect.setIssuingDistributionPoint(idp);
+ deltaSelect.setIssuingDistributionPointEnabled(true);
+
+ // 5.2.4 (c)
+ deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
+
+ // find delta CRLs
+ Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate);
+
+ Set result = new HashSet();
+
+ for (Iterator it = temp.iterator(); it.hasNext(); )
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (isDeltaCRL(crl))
+ {
+ result.add(crl);
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean isDeltaCRL(X509CRL crl)
+ {
+ Set critical = crl.getCriticalExtensionOIDs();
+
+ if (critical == null)
+ {
+ return false;
+ }
+
+ return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ }
+
+ /**
+ * Fetches complete CRLs according to RFC 3280.
+ *
+ * @param dp The distribution point for which the complete CRL
+ * @param cert The <code>X509Certificate</code> or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} for
+ * which the CRL should be searched.
+ * @param currentDate The date for which the delta CRLs must be valid.
+ * @param paramsPKIX The extended PKIX parameters.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+ * CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the CRLs
+ * or no CRLs are found.
+ */
+ protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
+ Date currentDate, ExtendedPKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ try
+ {
+ Set issuers = new HashSet();
+ if (cert instanceof X509AttributeCertificate)
+ {
+ issuers.add(((X509AttributeCertificate)cert)
+ .getIssuer().getPrincipals()[0]);
+ }
+ else
+ {
+ issuers.add(getEncodedIssuerPrincipal(cert));
+ }
+ CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Could not get issuer information from distribution point.", e);
+ }
+ if (cert instanceof X509Certificate)
+ {
+ crlselect.setCertificateChecking((X509Certificate)cert);
+ }
+ else if (cert instanceof X509AttributeCertificate)
+ {
+ crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert);
+ }
+
+
+ crlselect.setCompleteCRLEnabled(true);
+
+ Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ if (crls.isEmpty())
+ {
+ if (cert instanceof X509AttributeCertificate)
+ {
+ X509AttributeCertificate aCert = (X509AttributeCertificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\"");
+ }
+ else
+ {
+ X509Certificate xCert = (X509Certificate)cert;
+
+ throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerDN() + "\"");
+ }
+ }
+ return crls;
+ }
+
+ protected static Date getValidCertDateFromValidityModel(
+ ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index)
+ throws AnnotatedException
+ {
+ if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ // if end cert use given signing/encryption/... time
+ if (index <= 0)
+ {
+ return CertPathValidatorUtilities.getValidDate(paramsPKIX);
+ // else use time when previous cert was created
+ }
+ else
+ {
+ if (index - 1 == 0)
+ {
+ ASN1GeneralizedTime dateOfCertgen = null;
+ try
+ {
+ byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId());
+ if (extBytes != null)
+ {
+ dateOfCertgen = ASN1GeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ if (dateOfCertgen != null)
+ {
+ try
+ {
+ return dateOfCertgen.getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new AnnotatedException(
+ "Date from date of cert gen extension could not be parsed.",
+ e);
+ }
+ }
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ else
+ {
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ }
+ }
+ else
+ {
+ return getValidDate(paramsPKIX);
+ }
+ }
+
+ /**
+ * Return the next working key inheriting DSA parameters if necessary.
+ * <p>
+ * This methods inherits DSA parameters from the indexed certificate or
+ * previous certificates in the certificate chain to the returned
+ * <code>PublicKey</code>. The list is searched upwards, meaning the end
+ * certificate is at position 0 and previous certificates are following.
+ * </p>
+ * <p>
+ * If the indexed certificate does not contain a DSA key this method simply
+ * returns the public key. If the DSA key already contains DSA parameters
+ * the key is also only returned.
+ * </p>
+ *
+ * @param certs The certification path.
+ * @param index The index of the certificate which contains the public key
+ * which should be extended with DSA parameters.
+ * @return The public key of the certificate in list position
+ * <code>index</code> extended with DSA parameters if applicable.
+ * @throws AnnotatedException if DSA parameters cannot be inherited.
+ */
+ protected static PublicKey getNextWorkingKey(List certs, int index)
+ throws CertPathValidatorException
+ {
+ Certificate cert = (Certificate)certs.get(index);
+ PublicKey pubKey = cert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ return pubKey;
+ }
+ DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
+ if (dsaPubKey.getParams() != null)
+ {
+ return dsaPubKey;
+ }
+ for (int i = index + 1; i < certs.size(); i++)
+ {
+ X509Certificate parentCert = (X509Certificate)certs.get(i);
+ pubKey = parentCert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ throw new CertPathValidatorException(
+ "DSA parameters cannot be inherited from previous certificate.");
+ }
+ DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
+ if (prevDSAPubKey.getParams() == null)
+ {
+ continue;
+ }
+ DSAParams dsaParams = prevDSAPubKey.getParams();
+ DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+ dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+ try
+ {
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+ return keyFactory.generatePublic(dsaPubKeySpec);
+ }
+ catch (Exception exception)
+ {
+ throw new RuntimeException(exception.getMessage());
+ }
+ }
+ throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ /**
+ * Find the issuer certificates of a given certificate.
+ *
+ * @param cert The certificate for which an issuer should be found.
+ * @param pkixParams
+ * @return A <code>Collection</code> object containing the issuer
+ * <code>X509Certificate</code>s. Never <code>null</code>.
+ * @throws AnnotatedException if an error occurs.
+ */
+ protected static Collection findIssuerCerts(
+ X509Certificate cert,
+ ExtendedPKIXBuilderParameters pkixParams)
+ throws AnnotatedException
+ {
+ X509CertStoreSelector certSelect = new X509CertStoreSelector();
+ Set certs = new HashSet();
+ try
+ {
+ certSelect.setSubject(PrincipalUtil.getSubjectX509Principal(cert).getEncoded());
+ }
+ catch (Exception ex)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+ }
+
+ Iterator iter;
+
+ try
+ {
+ List matches = new ArrayList();
+
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores()));
+ matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores()));
+
+ iter = matches.iterator();
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate cannot be searched.", e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext())
+ {
+ issuer = (X509Certificate)iter.next();
+ // issuer cannot be verified because possible DSA inheritance
+ // parameters are missing
+ certs.add(issuer);
+ }
+ return certs;
+ }
+
+ protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
+ String sigProvider)
+ throws GeneralSecurityException
+ {
+ if (sigProvider == null)
+ {
+ cert.verify(publicKey);
+ }
+ else
+ {
+ cert.verify(publicKey, sigProvider);
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
new file mode 100644
index 00000000..a894cf84
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/CertStoreCollectionSpi.java
@@ -0,0 +1,104 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import org.spongycastle.jce.cert.CRLSelector;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStoreException;
+import org.spongycastle.jce.cert.CertStoreParameters;
+import org.spongycastle.jce.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+public class CertStoreCollectionSpi extends CertStoreSpi
+{
+ private CollectionCertStoreParameters params;
+
+ public CertStoreCollectionSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof CollectionCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (CollectionCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(
+ CertSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof Certificate)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof Certificate) && selector.match((Certificate)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+
+
+ public Collection engineGetCRLs(
+ CRLSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof CRL)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof CRL) && selector.match((CRL)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java
new file mode 100644
index 00000000..53c9d66e
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCEPBEKey.java
@@ -0,0 +1,146 @@
+package org.spongycastle.jce.provider;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.PBEParametersGenerator;
+import org.spongycastle.crypto.params.KeyParameter;
+import org.spongycastle.crypto.params.ParametersWithIV;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+
+public class JCEPBEKey
+ implements SecretKey
+{
+ String algorithm;
+ ASN1ObjectIdentifier oid;
+ int type;
+ int digest;
+ int keySize;
+ int ivSize;
+ CipherParameters param;
+ PBEKeySpec pbeKeySpec;
+ boolean tryWrong = false;
+
+ /**
+ * @param param
+ */
+ public JCEPBEKey(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ int type,
+ int digest,
+ int keySize,
+ int ivSize,
+ PBEKeySpec pbeKeySpec,
+ CipherParameters param)
+ {
+ this.algorithm = algorithm;
+ this.oid = oid;
+ this.type = type;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ this.pbeKeySpec = pbeKeySpec;
+ this.param = param;
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "RAW";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (param != null)
+ {
+ KeyParameter kParam;
+
+ if (param instanceof ParametersWithIV)
+ {
+ kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ kParam = (KeyParameter)param;
+ }
+
+ return kParam.getKey();
+ }
+ else
+ {
+ if (type == PBE.PKCS12)
+ {
+ return PBEParametersGenerator.PKCS12PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ else
+ {
+ return PBEParametersGenerator.PKCS5PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ }
+ }
+
+ int getType()
+ {
+ return type;
+ }
+
+ int getDigest()
+ {
+ return digest;
+ }
+
+ int getKeySize()
+ {
+ return keySize;
+ }
+
+ int getIvSize()
+ {
+ return ivSize;
+ }
+
+ CipherParameters getParam()
+ {
+ return param;
+ }
+
+ /**
+ * these should never be called.
+ */
+ int getIterationCount()
+ {
+ return 0;
+ }
+
+ byte[] getSalt()
+ {
+ return null;
+ }
+
+ /**
+ * Return the object identifier associated with this algorithm
+ *
+ * @return the oid for this PBE key
+ */
+ public ASN1ObjectIdentifier getOID()
+ {
+ return oid;
+ }
+
+ void setTryWrongPKCS12Zero(boolean tryWrong)
+ {
+ this.tryWrong = tryWrong;
+ }
+
+ boolean shouldTryWrongPKCS12()
+ {
+ return tryWrong;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java
new file mode 100644
index 00000000..b1c358b9
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JCESecretKeyFactory.java
@@ -0,0 +1,557 @@
+package org.spongycastle.jce.provider;
+
+import java.lang.reflect.Constructor;
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.DESedeKeySpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.spongycastle.jcajce.provider.symmetric.util.PBE;
+
+public class JCESecretKeyFactory
+ extends SecretKeyFactorySpi
+ implements PBE
+{
+ protected String algName;
+ protected ASN1ObjectIdentifier algOid;
+
+ protected JCESecretKeyFactory(
+ String algName,
+ ASN1ObjectIdentifier algOid)
+ {
+ this.algName = algName;
+ this.algOid = algOid;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof SecretKeySpec)
+ {
+ return (SecretKey)keySpec;
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ try
+ {
+ Class[] parameters = { byte[].class };
+
+ Constructor c = keySpec.getConstructor(parameters);
+ Object[] p = new Object[1];
+
+ p[0] = key.getEncoded();
+
+ return (KeySpec)c.newInstance(p);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ protected SecretKey engineTranslateKey(
+ SecretKey key)
+ throws InvalidKeyException
+ {
+ if (key == null)
+ {
+ throw new InvalidKeyException("key parameter is null");
+ }
+
+ if (!key.getAlgorithm().equalsIgnoreCase(algName))
+ {
+ throw new InvalidKeyException("Key not of type " + algName + ".");
+ }
+
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ /*
+ * classes that inherit from us
+ */
+
+ static public class PBEKeyFactory
+ extends JCESecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public PBEKeyFactory(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ static public class DESPBEKeyFactory
+ extends JCESecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public DESPBEKeyFactory(
+ String algorithm,
+ ASN1ObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ static public class DES
+ extends JCESecretKeyFactory
+ {
+ public DES()
+ {
+ super("DES", null);
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESKeySpec)
+ {
+ DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DES");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ static public class DESede
+ extends JCESecretKeyFactory
+ {
+ public DESede()
+ {
+ super("DESede", null);
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+ else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
+ {
+ byte[] bytes = key.getEncoded();
+
+ try
+ {
+ if (bytes.length == 16)
+ {
+ byte[] longKey = new byte[24];
+
+ System.arraycopy(bytes, 0, longKey, 0, 16);
+ System.arraycopy(bytes, 0, longKey, 16, 8);
+
+ return new DESedeKeySpec(longKey);
+ }
+ else
+ {
+ return new DESedeKeySpec(bytes);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESedeKeySpec)
+ {
+ DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DESede");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndDES
+ */
+ static public class PBEWithMD5AndDES
+ extends DESPBEKeyFactory
+ {
+ public PBEWithMD5AndDES()
+ {
+ super("PBEwithMD5andDES", null, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndRC2
+ */
+ static public class PBEWithMD5AndRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5AndRC2()
+ {
+ super("PBEwithMD5andRC2", null, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndDES
+ */
+ static public class PBEWithSHA1AndDES
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA1AndDES()
+ {
+ super("PBEwithSHA1andDES", null, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndRC2
+ */
+ static public class PBEWithSHA1AndRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA1AndRC2()
+ {
+ super("PBEwithSHA1andRC2", null, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES3Key
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAndDES3Key()
+ {
+ super("PBEwithSHAandDES3Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, true, PKCS12, SHA1, 192, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd2-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES2Key
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAndDES2Key()
+ {
+ super("PBEwithSHAandDES2Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd128BitRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitRC2()
+ {
+ super("PBEwithSHAand128BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd40BitRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd40BitRC2()
+ {
+ super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbewithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAndTwofish-CBC
+ */
+ static public class PBEWithSHAAndTwofish
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAndTwofish()
+ {
+ super("PBEwithSHAandTwofish-CBC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC4
+ */
+ static public class PBEWithSHAAnd128BitRC4
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitRC4()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 128, 0);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC4
+ */
+ static public class PBEWithSHAAnd40BitRC4
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd40BitRC4()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 40, 0);
+ }
+ }
+
+ /**
+ * PBEWithHmacRIPEMD160
+ */
+ public static class PBEWithRIPEMD160
+ extends PBEKeyFactory
+ {
+ public PBEWithRIPEMD160()
+ {
+ super("PBEwithHmacRIPEMD160", null, false, PKCS12, RIPEMD160, 160, 0);
+ }
+ }
+
+ /**
+ * PBEWithHmacSHA
+ */
+ public static class PBEWithSHA
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA()
+ {
+ super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0);
+ }
+ }
+
+ /**
+ * PBEWithHmacTiger
+ */
+ public static class PBEWithTiger
+ extends PBEKeyFactory
+ {
+ public PBEWithTiger()
+ {
+ super("PBEwithHmacTiger", null, false, PKCS12, TIGER, 192, 0);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And128BitAES-BC
+ */
+ static public class PBEWithSHAAnd128BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitAESBC()
+ {
+ super("PBEWithSHA1And128BitAES-CBC-BC", null, true, PKCS12, SHA1, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And192BitAES-BC
+ */
+ static public class PBEWithSHAAnd192BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd192BitAESBC()
+ {
+ super("PBEWithSHA1And192BitAES-CBC-BC", null, true, PKCS12, SHA1, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And256BitAES-BC
+ */
+ static public class PBEWithSHAAnd256BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd256BitAESBC()
+ {
+ super("PBEWithSHA1And256BitAES-CBC-BC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And128BitAES-BC
+ */
+ static public class PBEWithSHA256And128BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And128BitAESBC()
+ {
+ super("PBEWithSHA256And128BitAES-CBC-BC", null, true, PKCS12, SHA256, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And192BitAES-BC
+ */
+ static public class PBEWithSHA256And192BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And192BitAESBC()
+ {
+ super("PBEWithSHA256And192BitAES-CBC-BC", null, true, PKCS12, SHA256, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And256BitAES-BC
+ */
+ static public class PBEWithSHA256And256BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And256BitAESBC()
+ {
+ super("PBEWithSHA256And256BitAES-CBC-BC", null, true, PKCS12, SHA256, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And128BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And128BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And192BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And192BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And256BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And256BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java
new file mode 100644
index 00000000..9b33841f
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/JDKAlgorithmParameters.java
@@ -0,0 +1,643 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.misc.CAST5CBCParameters;
+import org.spongycastle.asn1.pkcs.PKCS12PBEParams;
+import org.spongycastle.asn1.pkcs.RC2CBCParameter;
+import org.spongycastle.jce.spec.IESParameterSpec;
+
+public abstract class JDKAlgorithmParameters
+ extends AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class IVAlgorithmParameters
+ extends JDKAlgorithmParameters
+ {
+ private byte[] iv;
+
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ return engineGetEncoded("ASN.1");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IvParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+ }
+
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ //
+ // check that we don't have a DER encoded octet string
+ //
+ if ((params.length % 8) != 0
+ && params[0] == 0x04 && params[1] == params.length - 2)
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ ASN1OctetString oct = (ASN1OctetString)aIn.readObject();
+
+ params = oct.getOctets();
+ }
+
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+
+ try
+ {
+ ASN1OctetString oct = (ASN1OctetString)aIn.readObject();
+
+ engineInit(oct.getOctets());
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Exception decoding: " + e);
+ }
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "IV Parameters";
+ }
+ }
+
+ public static class RC2AlgorithmParameters
+ extends JDKAlgorithmParameters
+ {
+ private short[] table = {
+ 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+ 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+ 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+ 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+ 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+ 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+ 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+ 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+ 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+ 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+ 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+ 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+ 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+ 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+ 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
+ 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
+ };
+
+ private short[] ekb = {
+ 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
+ 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
+ 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+ 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+ 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+ 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+ 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+ 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+ 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+ 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+ 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+ 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+ 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+ 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+ 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
+ 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
+ };
+
+ private byte[] iv;
+ private int parameterVersion = 58;
+
+ protected byte[] engineGetEncoded()
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ if (parameterVersion == -1)
+ {
+ return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+ }
+ else
+ {
+ return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+ }
+ }
+
+ if (format.equals("RAW"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == RC2ParameterSpec.class)
+ {
+ if (parameterVersion != -1)
+ {
+ if (parameterVersion < 256)
+ {
+ return new RC2ParameterSpec(ekb[parameterVersion], iv);
+ }
+ else
+ {
+ return new RC2ParameterSpec(parameterVersion, iv);
+ }
+ }
+ }
+
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+ else if (paramSpec instanceof RC2ParameterSpec)
+ {
+ int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+ if (effKeyBits != -1)
+ {
+ if (effKeyBits < 256)
+ {
+ parameterVersion = table[effKeyBits];
+ }
+ else
+ {
+ parameterVersion = effKeyBits;
+ }
+ }
+
+ this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+ }
+ else
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ RC2CBCParameter p = RC2CBCParameter.getInstance(aIn.readObject());
+
+ if (p.getRC2ParameterVersion() != null)
+ {
+ parameterVersion = p.getRC2ParameterVersion().intValue();
+ }
+
+ iv = p.getIV();
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "RC2 Parameters";
+ }
+ }
+
+ public static class CAST5AlgorithmParameters
+ extends JDKAlgorithmParameters
+ {
+ private byte[] iv;
+ private int keyLength = 128;
+
+ protected byte[] engineGetEncoded()
+ {
+ byte[] tmp = new byte[iv.length];
+
+ System.arraycopy(iv, 0, tmp, 0, iv.length);
+ return tmp;
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return new CAST5CBCParameters(engineGetEncoded(), keyLength).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ return engineGetEncoded();
+ }
+
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to CAST5 parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec instanceof IvParameterSpec)
+ {
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+ else
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a CAST5 parameters algorithm parameters object");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.iv = new byte[params.length];
+
+ System.arraycopy(params, 0, iv, 0, iv.length);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+ CAST5CBCParameters p = CAST5CBCParameters.getInstance(aIn.readObject());
+
+ keyLength = p.getKeyLength();
+
+ iv = p.getIV();
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "CAST5 Parameters";
+ }
+ }
+
+ public static class PKCS12PBE
+ extends JDKAlgorithmParameters
+ {
+ PKCS12PBEParams params;
+
+ protected byte[] engineGetEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ try
+ {
+ dOut.writeObject(params);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+
+ return bOut.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getIV(),
+ params.getIterations().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+
+ this.params = PKCS12PBEParams.getInstance(aIn.readObject());
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PKCS12 PBE Parameters";
+ }
+ }
+
+ public static class IES
+ extends JDKAlgorithmParameters
+ {
+ IESParameterSpec currentSpec;
+
+ /**
+ * in the abscence of a standard way of doing it this will do for
+ * now...
+ */
+ protected byte[] engineGetEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ try
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DEROctetString(currentSpec.getDerivationV()));
+ v.add(new DEROctetString(currentSpec.getEncodingV()));
+ v.add(new ASN1Integer(currentSpec.getMacKeySize()));
+
+ dOut.writeObject(new DERSequence(v));
+ dOut.close();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding IESParameters");
+ }
+
+ return bOut.toByteArray();
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IESParameterSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IESParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IESParameterSpec required to initialise a IES algorithm parameters object");
+ }
+
+ this.currentSpec = (IESParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(params);
+
+ try
+ {
+ ASN1Sequence s = (ASN1Sequence)aIn.readObject();
+
+ this.currentSpec = new IESParameterSpec(
+ ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ ((ASN1Integer)s.getObjectAt(0)).getValue().intValue());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid IES Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid IES Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "IES Parameters";
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java
new file mode 100644
index 00000000..e3102c77
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/MultiCertStoreSpi.java
@@ -0,0 +1,85 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.jce.MultiCertStoreParameters;
+
+import java.security.InvalidAlgorithmParameterException;
+import org.spongycastle.jce.cert.CRLSelector;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import org.spongycastle.jce.cert.CertStoreParameters;
+import org.spongycastle.jce.cert.CertStoreSpi;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class MultiCertStoreSpi
+ extends CertStoreSpi
+{
+ private MultiCertStoreParameters params;
+
+ public MultiCertStoreSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof MultiCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.spongycastle.jce.provider.MultiCertStoreSpi: parameter must be a MultiCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (MultiCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(CertSelector certSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCerts = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection certs = store.getCertificates(certSelector);
+
+ if (searchAllStores)
+ {
+ allCerts.addAll(certs);
+ }
+ else if (!certs.isEmpty())
+ {
+ return certs;
+ }
+ }
+
+ return allCerts;
+ }
+
+ public Collection engineGetCRLs(CRLSelector crlSelector)
+ throws CertStoreException
+ {
+ boolean searchAllStores = params.getSearchAllStores();
+ Iterator iter = params.getCertStores().iterator();
+ List allCRLs = searchAllStores ? new ArrayList() : Collections.EMPTY_LIST;
+
+ while (iter.hasNext())
+ {
+ CertStore store = (CertStore)iter.next();
+ Collection crls = store.getCRLs(crlSelector);
+
+ if (searchAllStores)
+ {
+ allCRLs.addAll(crls);
+ }
+ else if (!crls.isEmpty())
+ {
+ return crls;
+ }
+ }
+
+ return allCRLs;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java
new file mode 100644
index 00000000..3e22d9f6
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCRLUtil.java
@@ -0,0 +1,155 @@
+package org.spongycastle.jce.provider;
+
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import org.spongycastle.jce.cert.PKIXParameters;
+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.List;
+import java.util.Set;
+
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509Store;
+
+public class PKIXCRLUtil
+{
+ public Set findCRLs(X509CRLStoreSelector crlselect, ExtendedPKIXParameters paramsPKIX, Date currentDate)
+ throws AnnotatedException
+ {
+ Set initialSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+ }
+
+ Set finalSet = new HashSet();
+ Date validityDate = currentDate;
+
+ if (paramsPKIX.getDate() != null)
+ {
+ validityDate = paramsPKIX.getDate();
+ }
+
+ // based on RFC 5280 6.3.3
+ for (Iterator it = initialSet.iterator(); it.hasNext();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (crl.getNextUpdate().after(validityDate))
+ {
+ X509Certificate cert = crlselect.getCertificateChecking();
+
+ if (cert != null)
+ {
+ if (crl.getThisUpdate().before(cert.getNotAfter()))
+ {
+ finalSet.add(crl);
+ }
+ }
+ else
+ {
+ finalSet.add(crl);
+ }
+ }
+ }
+
+ return finalSet;
+ }
+
+ public Set findCRLs(X509CRLStoreSelector crlselect, PKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ Set completeSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ completeSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+ }
+
+ return completeSet;
+ }
+
+/**
+ * Return a Collection of all CRLs found in the X509Store's that are
+ * matching the crlSelect criteriums.
+ *
+ * @param crlSelect a {@link X509CRLStoreSelector} object that will be used
+ * to select the CRLs
+ * @param crlStores a List containing only
+ * {@link org.spongycastle.x509.X509Store X509Store} objects.
+ * These are used to search for CRLs
+ *
+ * @return a Collection of all found {@link java.security.cert.X509CRL X509CRL} objects. May be
+ * empty but never <code>null</code>.
+ */
+ private final Collection findCRLs(X509CRLStoreSelector crlSelect,
+ List crlStores) throws AnnotatedException
+ {
+ Set crls = new HashSet();
+ Iterator iter = crlStores.iterator();
+
+ AnnotatedException lastException = null;
+ boolean foundValidStore = false;
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store store = (X509Store)obj;
+
+ try
+ {
+ crls.addAll(store.getMatches(crlSelect));
+ foundValidStore = true;
+ }
+ catch (StoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ else
+ {
+ CertStore store = (CertStore)obj;
+
+ try
+ {
+ crls.addAll(store.getCRLs(crlSelect));
+ foundValidStore = true;
+ }
+ catch (CertStoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ }
+ if (!foundValidStore && lastException != null)
+ {
+ throw lastException;
+ }
+ return crls;
+ }
+
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
new file mode 100644
index 00000000..d02dd511
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -0,0 +1,395 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathBuilderException;
+import org.spongycastle.jce.cert.CertPathBuilderResult;
+import org.spongycastle.jce.cert.CertPathBuilderSpi;
+import org.spongycastle.jce.cert.CertPathParameters;
+import org.spongycastle.jce.cert.CertPathValidator;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import org.spongycastle.jce.cert.CertificateFactory;
+import org.spongycastle.jce.cert.PKIXBuilderParameters;
+import org.spongycastle.jce.cert.PKIXBuilderParameters;
+import org.spongycastle.jce.cert.PKIXCertPathBuilderResult;
+import org.spongycastle.jce.cert.PKIXCertPathValidatorResult;
+import org.spongycastle.jce.cert.TrustAnchor;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.jce.PrincipalUtil;
+
+/**
+ * Implements the PKIX CertPathBuilding algorithem for BouncyCastle.
+ * <br />
+ * <b>MAYBE: implement more CertPath validation whil build path to omit invalid pathes</b>
+ *
+ * @see CertPathBuilderSpi
+ **/
+public class PKIXCertPathBuilderSpi
+ extends CertPathBuilderSpi
+{
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all
+ * information to build the CertPath
+ **/
+ public CertPathBuilderResult engineBuild(
+ CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXBuilderParameters)
+ && !(params instanceof ExtendedPKIXBuilderParameters))
+ {
+ throw new InvalidAlgorithmParameterException(
+ "Parameters must be an instance of "
+ + PKIXBuilderParameters.class.getName() + " or "
+ + ExtendedPKIXBuilderParameters.class.getName() + ".");
+ }
+
+ ExtendedPKIXBuilderParameters pkixParams = null;
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) params;
+ }
+ else
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
+ .getInstance((PKIXBuilderParameters) params);
+ }
+
+ Collection targets;
+ Iterator targetIter;
+ List certPathList = new ArrayList();
+ Set certPathSet = new HashSet();
+ X509Certificate cert;
+ Collection certs;
+ CertPath certPath = null;
+ Exception certPathException = null;
+
+ // search target certificates
+ CertSelector certSelect = pkixParams.getTargetCertConstraints();
+ if (certSelect == null)
+ {
+ throw new CertPathBuilderException("targetCertConstraints must be non-null for CertPath building");
+ }
+
+ try
+ {
+ targets = findCertificates(certSelect, pkixParams.getCertStores());
+ }
+ catch (CertStoreException e)
+ {
+ throw new CertPathBuilderException(e);
+ }
+
+ if (targets.isEmpty())
+ {
+ throw new CertPathBuilderException("no certificate found matching targetCertContraints");
+ }
+
+ CertificateFactory cFact;
+ CertPathValidator validator;
+
+ try
+ {
+ cFact = CertificateFactory.getInstance("X.509", "SC");
+ validator = CertPathValidator.getInstance("PKIX", "SC");
+ }
+ catch (Exception e)
+ {
+ throw new CertPathBuilderException("exception creating support classes: " + e);
+ }
+
+ //
+ // check all potential target certificates
+ targetIter = targets.iterator();
+ while (targetIter.hasNext())
+ {
+ cert = (X509Certificate)targetIter.next();
+ certPathList.clear();
+ certPathSet.clear();
+ while (cert != null)
+ {
+ // add cert to the certpath
+ certPathList.add(cert);
+ certPathSet.add(cert);
+
+ // check whether the issuer of <cert> is a TrustAnchor
+ if (findTrustAnchor(cert, pkixParams.getTrustAnchors()) != null)
+ {
+ try
+ {
+ certPath = cFact.generateCertPath(certPathList);
+
+ PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(certPath, pkixParams);
+
+ return new PKIXCertPathBuilderResult(certPath,
+ result.getTrustAnchor(),
+ result.getPolicyTree(),
+ result.getPublicKey());
+ }
+ catch (CertificateException ex)
+ {
+ certPathException = ex;
+ }
+ catch (CertPathValidatorException ex)
+ {
+ certPathException = ex;
+ }
+ // if validation failed go to next certificate
+ cert = null;
+ }
+ else
+ {
+ // try to get the issuer certificate from one
+ // of the CertStores
+ try
+ {
+ X509Certificate issuer = findIssuer(cert, pkixParams.getCertStores());
+ if (issuer.equals(cert))
+ {
+ cert = null;
+ }
+ else
+ {
+ cert = issuer;
+ // validation failed - circular path detected, go to next certificate
+ if (certPathSet.contains(cert))
+ {
+ cert = null;
+ }
+ }
+ }
+ catch (CertPathValidatorException ex)
+ {
+ certPathException = ex;
+ cert = null;
+ }
+ }
+ }
+ }
+
+ if (certPath != null)
+ {
+ throw new CertPathBuilderException("found certificate chain, but could not be validated", certPathException);
+ }
+
+ throw new CertPathBuilderException("unable to find certificate chain");
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the fiven X509 certificate.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ *
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ *
+ * @exception CertPathValidatorException if a TrustAnchor was
+ * found but the signature verificytion on the given certificate
+ * has thrown an exception. This Exception can be obtainted with
+ * <code>getCause()</code> method.
+ **/
+ final TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws CertPathBuilderException
+ {
+ Iterator iter = trustAnchors.iterator();
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+
+ try
+ {
+ certSelectX509.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathBuilderException("can't get trust anchor principal",null);
+ }
+
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X509Principal certIssuer = PrincipalUtil.getIssuerX509Principal(cert);
+ X509Principal caName = new X509Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (Exception ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ cert.verify(trustPublicKey);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new CertPathBuilderException("TrustAnchor found put certificate validation failed",invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ /**
+ * Return a Collection of all certificates found in the
+ * CertStore's that are matching the certSelect criteriums.
+ *
+ * @param certSelect a {@link CertSelector CertSelector}
+ * object that will be used to select the certificates
+ * @param certStores a List containing only {@link CertStore
+ * CertStore} objects. These are used to search for
+ * certificates
+ *
+ * @return a Collection of all found {@link Certificate Certificate}
+ * objects. May be empty but never <code>null</code>.
+ **/
+ private Collection findCertificates(
+ CertSelector certSelect,
+ List certStores)
+ throws CertStoreException
+ {
+ Set certs = new HashSet();
+ Iterator iter = certStores.iterator();
+
+ while (iter.hasNext())
+ {
+ CertStore certStore = (CertStore)iter.next();
+
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+
+ return certs;
+ }
+
+ /**
+ * Find the issuer certificate of the given certificate.
+ *
+ * @param cert the certificate hows issuer certificate should
+ * be found.
+ * @param certStores a list of <code>CertStore</code> object
+ * that will be searched
+ *
+ * @return then <code>X509Certificate</code> object containing
+ * the issuer certificate or <code>null</code> if not found
+ *
+ * @exception CertPathValidatorException if a TrustAnchor was
+ * found but the signature verificytion on the given certificate
+ * has thrown an exception. This Exception can be obtainted with
+ * <code>getCause()</code> method.
+ **/
+ private X509Certificate findIssuer(
+ X509Certificate cert,
+ List certStores)
+ throws CertPathValidatorException
+ {
+ Exception invalidKeyEx = null;
+ X509CertSelector certSelect = new X509CertSelector();
+ try
+ {
+ certSelect.setSubject(PrincipalUtil.getIssuerX509Principal(cert).getEncoded());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathValidatorException("Issuer not found", null, null, -1);
+ }
+
+ Iterator iter;
+ try
+ {
+ iter = findCertificates(certSelect, certStores).iterator();
+ }
+ catch (CertStoreException e)
+ {
+ throw new CertPathValidatorException(e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext() && issuer == null)
+ {
+ issuer = (X509Certificate)iter.next();
+ try
+ {
+ cert.verify(issuer.getPublicKey());
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ issuer = null;
+ }
+ }
+
+ if (issuer == null && invalidKeyEx == null)
+ {
+ throw new CertPathValidatorException("Issuer not found", null, null, -1);
+ }
+
+ if (issuer == null && invalidKeyEx != null)
+ {
+ throw new CertPathValidatorException("issuer found but certificate validation failed",invalidKeyEx,null,-1);
+ }
+
+ return issuer;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
new file mode 100644
index 00000000..989d9c9a
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -0,0 +1,431 @@
+package org.spongycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathParameters;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import org.spongycastle.jce.cert.CertPathValidatorResult;
+import org.spongycastle.jce.cert.CertPathValidatorSpi;
+import org.spongycastle.jce.cert.PKIXCertPathChecker;
+import org.spongycastle.jce.cert.PKIXCertPathValidatorResult;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.jce.X509Principal;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+
+/**
+ * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC
+ * 3280.
+ */
+public class PKIXCertPathValidatorSpi
+ extends CertPathValidatorSpi
+{
+
+ public CertPathValidatorResult engineValidate(
+ CertPath certPath,
+ CertPathParameters params)
+ throws CertPathValidatorException,
+ InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXParameters))
+ {
+ throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName()
+ + " instance.");
+ }
+
+ ExtendedPKIXParameters paramsPKIX;
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ paramsPKIX = (ExtendedPKIXParameters)params;
+ }
+ else
+ {
+ paramsPKIX = ExtendedPKIXParameters.getInstance((PKIXParameters)params);
+ }
+ if (paramsPKIX.getTrustAnchors() == null)
+ {
+ throw new InvalidAlgorithmParameterException(
+ "trustAnchors is null, this is not allowed for certification path validation.");
+ }
+
+ //
+ // 6.1.1 - inputs
+ //
+
+ //
+ // (a)
+ //
+ List certs = certPath.getCertificates();
+ int n = certs.size();
+
+ if (certs.isEmpty())
+ {
+ throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
+ }
+
+ //
+ // (b)
+ //
+ // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
+
+ //
+ // (c)
+ //
+ Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
+
+ //
+ // (d)
+ //
+ TrustAnchor trust;
+ try
+ {
+ trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
+ paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1);
+ }
+
+ if (trust == null)
+ {
+ throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+ }
+
+ //
+ // (e), (f), (g) are part of the paramsPKIX object.
+ //
+ Iterator certIter;
+ int index = 0;
+ int i;
+ // Certificate for each interation of the validation loop
+ // Signature information for each iteration of the validation loop
+ //
+ // 6.1.2 - setup
+ //
+
+ //
+ // (a)
+ //
+ List[] policyNodes = new ArrayList[n + 1];
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ Set policySet = new HashSet();
+
+ policySet.add(RFC3280CertPathUtilities.ANY_POLICY);
+
+ PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(),
+ RFC3280CertPathUtilities.ANY_POLICY, false);
+
+ policyNodes[0].add(validPolicyTree);
+
+ //
+ // (b) and (c)
+ //
+ PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
+
+ // (d)
+ //
+ int explicitPolicy;
+ Set acceptablePolicies = new HashSet();
+
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ //
+ // (e)
+ //
+ int inhibitAnyPolicy;
+
+ if (paramsPKIX.isAnyPolicyInhibited())
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ //
+ // (f)
+ //
+ int policyMapping;
+
+ if (paramsPKIX.isPolicyMappingInhibited())
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ //
+ // (g), (h), (i), (j)
+ //
+ PublicKey workingPublicKey;
+ X509Principal workingIssuerName;
+
+ X509Certificate sign = trust.getTrustedCert();
+ try
+ {
+ if (sign != null)
+ {
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+ workingPublicKey = sign.getPublicKey();
+ }
+ else
+ {
+ workingIssuerName = new X509Principal(trust.getCAName());
+ workingPublicKey = trust.getCAPublicKey();
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+ -1);
+ }
+
+ AlgorithmIdentifier workingAlgId = null;
+ try
+ {
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+ }
+ ASN1ObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
+
+ //
+ // (k)
+ //
+ int maxPathLength = n;
+
+ //
+ // 6.1.3
+ //
+
+ if (paramsPKIX.getTargetConstraints() != null
+ && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0)))
+ {
+ throw new ExtCertPathValidatorException(
+ "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+ }
+
+ //
+ // initialize CertPathChecker's
+ //
+ List pathCheckers = paramsPKIX.getCertPathCheckers();
+ certIter = pathCheckers.iterator();
+ while (certIter.hasNext())
+ {
+ ((PKIXCertPathChecker) certIter.next()).init(false);
+ }
+
+ X509Certificate cert = null;
+
+ for (index = certs.size() - 1; index >= 0; index--)
+ {
+ // try
+ // {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialized the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate) certs.get(index);
+ boolean verificationAlreadyPerformed = (index == certs.size() - 1);
+
+ //
+ // 6.1.3
+ //
+
+ RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
+ verificationAlreadyPerformed, workingIssuerName, sign);
+
+ RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies,
+ validPolicyTree, policyNodes, inhibitAnyPolicy);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree);
+
+ RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy);
+
+ //
+ // 6.1.4
+ //
+
+ if (i != n)
+ {
+ if (cert != null && cert.getVersion() == 1)
+ {
+ throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
+ certPath, index);
+ }
+
+ RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
+
+ validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree,
+ policyMapping);
+
+ RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator);
+
+ // (h)
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping);
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy);
+
+ //
+ // (i)
+ //
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping);
+
+ // (j)
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
+
+ // (k)
+ RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
+
+ // (l)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
+
+ // (m)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength);
+
+ // (n)
+ RFC3280CertPathUtilities.prepareNextCertN(certPath, index);
+
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ // (o)
+ RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers);
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // (c)
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+
+ // (d)
+ try
+ {
+ workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+ }
+
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ // (f)
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ // (e)
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ }
+
+ //
+ // 6.1.5 Wrap-up procedure
+ //
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert);
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy);
+
+ //
+ // (c) (d) and (e) are already done
+ //
+
+ //
+ // (f)
+ //
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
+
+ PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet,
+ index + 1, policyNodes, validPolicyTree, acceptablePolicies);
+
+ if ((explicitPolicy > 0) || (intersection != null))
+ {
+ return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey());
+ }
+
+ throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+ }
+
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java
new file mode 100644
index 00000000..1a0b4e7b
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/PKIXPolicyNode.java
@@ -0,0 +1,169 @@
+package org.spongycastle.jce.provider;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.jce.cert.PolicyNode;
+
+public class PKIXPolicyNode
+ implements PolicyNode
+{
+ protected List children;
+ protected int depth;
+ protected Set expectedPolicies;
+ protected PolicyNode parent;
+ protected Set policyQualifiers;
+ protected String validPolicy;
+ protected boolean critical;
+
+ /*
+ *
+ * CONSTRUCTORS
+ *
+ */
+
+ public PKIXPolicyNode(
+ List _children,
+ int _depth,
+ Set _expectedPolicies,
+ PolicyNode _parent,
+ Set _policyQualifiers,
+ String _validPolicy,
+ boolean _critical)
+ {
+ children = _children;
+ depth = _depth;
+ expectedPolicies = _expectedPolicies;
+ parent = _parent;
+ policyQualifiers = _policyQualifiers;
+ validPolicy = _validPolicy;
+ critical = _critical;
+ }
+
+ public void addChild(
+ PKIXPolicyNode _child)
+ {
+ children.add(_child);
+ _child.setParent(this);
+ }
+
+ public Iterator getChildren()
+ {
+ return children.iterator();
+ }
+
+ public int getDepth()
+ {
+ return depth;
+ }
+
+ public Set getExpectedPolicies()
+ {
+ return expectedPolicies;
+ }
+
+ public PolicyNode getParent()
+ {
+ return parent;
+ }
+
+ public Set getPolicyQualifiers()
+ {
+ return policyQualifiers;
+ }
+
+ public String getValidPolicy()
+ {
+ return validPolicy;
+ }
+
+ public boolean hasChildren()
+ {
+ return !children.isEmpty();
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public void removeChild(PKIXPolicyNode _child)
+ {
+ children.remove(_child);
+ }
+
+ public void setCritical(boolean _critical)
+ {
+ critical = _critical;
+ }
+
+ public void setParent(PKIXPolicyNode _parent)
+ {
+ parent = _parent;
+ }
+
+ public String toString()
+ {
+ return toString("");
+ }
+
+ public String toString(String _indent)
+ {
+ StringBuffer _buf = new StringBuffer();
+ _buf.append(_indent);
+ _buf.append(validPolicy);
+ _buf.append(" {\n");
+
+ for(int i = 0; i < children.size(); i++)
+ {
+ _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + " "));
+ }
+
+ _buf.append(_indent);
+ _buf.append("}\n");
+ return _buf.toString();
+ }
+
+ public Object clone()
+ {
+ return copy();
+ }
+
+ public PKIXPolicyNode copy()
+ {
+ Set _expectedPolicies = new HashSet();
+ Iterator _iter = expectedPolicies.iterator();
+ while (_iter.hasNext())
+ {
+ _expectedPolicies.add(new String((String)_iter.next()));
+ }
+
+ Set _policyQualifiers = new HashSet();
+ _iter = policyQualifiers.iterator();
+ while (_iter.hasNext())
+ {
+ _policyQualifiers.add(new String((String)_iter.next()));
+ }
+
+ PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(),
+ depth,
+ _expectedPolicies,
+ null,
+ _policyQualifiers,
+ new String(validPolicy),
+ critical);
+
+ _iter = children.iterator();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy();
+ _child.setParent(_node);
+ _node.addChild(_child);
+ }
+
+ return _node;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java
new file mode 100644
index 00000000..74efc9a9
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/ProviderUtil.java
@@ -0,0 +1,72 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Permission;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+public class ProviderUtil
+{
+ private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ "SC", ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+ private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+ "SC", ConfigurableProvider.EC_IMPLICITLY_CA);
+
+ private static ThreadLocal threadSpec = new ThreadLocal();
+ private static volatile ECParameterSpec ecImplicitCaParams;
+
+ static void setParameter(String parameterName, Object parameter)
+ {
+ SecurityManager securityManager = System.getSecurityManager();
+
+ if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+ {
+ ECParameterSpec curveSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+ }
+
+ curveSpec = (ECParameterSpec)parameter;
+
+ threadSpec.set(curveSpec);
+ }
+ else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_PERMISSION);
+ }
+
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ }
+
+ public static ECParameterSpec getEcImplicitlyCa()
+ {
+ ECParameterSpec spec = (ECParameterSpec)threadSpec.get();
+
+ if (spec != null)
+ {
+ return spec;
+ }
+
+ return ecImplicitCaParams;
+ }
+
+ static int getReadLimit(InputStream in)
+ throws IOException
+ {
+ if (in instanceof ByteArrayInputStream)
+ {
+ return in.available();
+ }
+
+ return Integer.MAX_VALUE;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
new file mode 100644
index 00000000..3f37d4c9
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -0,0 +1,2582 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.text.SimpleDateFormat;
+import org.spongycastle.jce.cert.CertPath;
+import org.spongycastle.jce.cert.CertPathBuilder;
+import org.spongycastle.jce.cert.CertPathBuilderException;
+import org.spongycastle.jce.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import org.spongycastle.jce.cert.PKIXCertPathChecker;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509Extension;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.GeneralSubtree;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.NameConstraints;
+import org.spongycastle.asn1.x509.PolicyInformation;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+
+public class RFC3280CertPathUtilities
+{
+ private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ /**
+ * If the complete CRL includes an issuing distribution point (IDP) CRL
+ * extension check the following:
+ * <p/>
+ * (i) If the distribution point name is present in the IDP CRL extension
+ * and the distribution field is present in the DP, then verify that one of
+ * the names in the IDP matches one of the names in the DP. If the
+ * distribution point name is present in the IDP CRL extension and the
+ * distribution field is omitted from the DP, then verify that one of the
+ * names in the IDP matches one of the names in the cRLIssuer field of the
+ * DP.
+ * </p>
+ * <p/>
+ * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate does not include the basic
+ * constraints extension with the cA boolean asserted.
+ * </p>
+ * <p/>
+ * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+ * extension, verify that the certificate includes the basic constraints
+ * extension with the cA boolean asserted.
+ * </p>
+ * <p/>
+ * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+ * </p>
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate.
+ * @param crl The CRL.
+ * @throws AnnotatedException if one of the conditions is not met or an error occurs.
+ */
+ protected static void processCRLB2(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (b) (2) (i)
+ // distribution point name is present
+ if (idp != null)
+ {
+ if (idp.getDistributionPoint() != null)
+ {
+ // make list of names
+ DistributionPointName dpName = IssuingDistributionPoint.getInstance(idp).getDistributionPoint();
+ List names = new ArrayList();
+
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ names.add(genNames[j]);
+ }
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ try
+ {
+ Enumeration e = ASN1Sequence.getInstance(
+ ASN1Sequence.fromByteArray(CertPathValidatorUtilities.getIssuerPrincipal(crl)
+ .getEncoded())).getObjects();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read CRL issuer.", e);
+ }
+ vec.add(dpName.getName());
+ names.add(new GeneralName(X509Name.getInstance(new DERSequence(vec))));
+ }
+ boolean matches = false;
+ // verify that one of the names in the IDP matches one
+ // of the names in the DP.
+ if (dp.getDistributionPoint() != null)
+ {
+ dpName = dp.getDistributionPoint();
+ GeneralName[] genNames = null;
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ if (dp.getCRLIssuer() != null)
+ {
+ genNames = dp.getCRLIssuer().getNames();
+ }
+ else
+ {
+ genNames = new GeneralName[1];
+ try
+ {
+ genNames[0] = new GeneralName(new X509Name(
+ (ASN1Sequence)ASN1Sequence.fromByteArray(CertPathValidatorUtilities
+ .getEncodedIssuerPrincipal(cert).getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read certificate issuer.", e);
+ }
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+ Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().toASN1Primitive()).getObjects();
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ vec.add(dpName.getName());
+ genNames[j] = new GeneralName(new X509Name(new DERSequence(vec)));
+ }
+ }
+ if (genNames != null)
+ {
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ // verify that one of the names in
+ // the IDP matches one of the names in the cRLIssuer field of
+ // the DP
+ else
+ {
+ if (dp.getCRLIssuer() == null)
+ {
+ throw new AnnotatedException("Either the cRLIssuer or the distributionPoint field must "
+ + "be contained in DistributionPoint.");
+ }
+ GeneralName[] genNames = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ }
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue((X509Extension)cert,
+ BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Basic constraints extension could not be decoded.", e);
+ }
+
+ if (cert instanceof X509Certificate)
+ {
+ // (b) (2) (ii)
+ if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+ {
+ throw new AnnotatedException("CA Cert CRL only contains user certificates.");
+ }
+
+ // (b) (2) (iii)
+ if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+ {
+ throw new AnnotatedException("End CRL only contains CA certificates.");
+ }
+ }
+
+ // (b) (2) (iv)
+ if (idp.onlyContainsAttributeCerts())
+ {
+ throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted.");
+ }
+ }
+ }
+
+ /**
+ * If the DP includes cRLIssuer, then verify that the issuer field in the
+ * complete CRL matches cRLIssuer in the DP and that the complete CRL
+ * contains an issuing distribution point extension with the indirectCRL
+ * boolean asserted. Otherwise, verify that the CRL issuer matches the
+ * certificate issuer.
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate ot attribute certificate.
+ * @param crl The CRL for <code>cert</code>.
+ * @throws AnnotatedException if one of the above conditions does not apply or an error
+ * occurs.
+ */
+ protected static void processCRLB1(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ ASN1Primitive idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+ boolean isIndirect = false;
+ if (idp != null)
+ {
+ if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL())
+ {
+ isIndirect = true;
+ }
+ }
+ byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+
+ boolean matchIssuer = false;
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (Arrays.areEqual(genNames[j].getName().toASN1Primitive().getEncoded(), issuerBytes))
+ {
+ matchIssuer = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.", e);
+ }
+ }
+ }
+ if (matchIssuer && !isIndirect)
+ {
+ throw new AnnotatedException("Distribution point contains cRLIssuer field but CRL is not indirect.");
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("CRL issuer of CRL does not match CRL issuer of distribution point.");
+ }
+ }
+ else
+ {
+ if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals(
+ CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)))
+ {
+ matchIssuer = true;
+ }
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("Cannot find matching CRL issuer for certificate.");
+ }
+ }
+
+ protected static ReasonsMask processCRLD(
+ X509CRL crl,
+ DistributionPoint dp)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (d) (1)
+ if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null)
+ {
+ return new ReasonsMask(dp.getReasons()).intersect(new ReasonsMask(idp.getOnlySomeReasons()));
+ }
+ // (d) (4)
+ if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null)
+ {
+ return ReasonsMask.allReasons;
+ }
+ // (d) (2) and (d)(3)
+ return (dp.getReasons() == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(dp.getReasons())).intersect(idp == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(idp.getOnlySomeReasons()));
+
+ }
+
+ public static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+
+ public static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+
+ public static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+
+ public static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+
+ public static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+
+ public static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+
+ public static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+
+ public static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+
+ public static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+
+ public static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+
+ public static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+
+ public static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ public static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+
+ public static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ public static final String ANY_POLICY = "2.5.29.32.0";
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+
+ protected static final int CRL_SIGN = 6;
+
+ /**
+ * Obtain and validate the certification path for the complete CRL issuer.
+ * If a key usage extension is present in the CRL issuer's certificate,
+ * verify that the cRLSign bit is set.
+ *
+ * @param crl CRL which contains revocation information for the certificate
+ * <code>cert</code>.
+ * @param cert The attribute certificate or certificate to check if it is
+ * revoked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param paramsPKIX paramsPKIX PKIX parameters.
+ * @param certPathCerts The certificates on the certification path.
+ * @return A <code>Set</code> with all keys of possible CRL issuer
+ * certificates.
+ * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+ * some error occurs.
+ */
+ protected static Set processCRLF(
+ X509CRL crl,
+ Object cert,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ ExtendedPKIXParameters paramsPKIX,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ // (f)
+
+ // get issuer from CRL
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ try
+ {
+ byte[] issuerPrincipal = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+ selector.setSubject(issuerPrincipal);
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+ }
+
+ // get CRL signing certs
+ Collection coll;
+ try
+ {
+ coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getStores());
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getAdditionalStores()));
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate for CRL cannot be searched.", e);
+ }
+
+ coll.add(defaultCRLSignCert);
+
+ Iterator cert_it = coll.iterator();
+
+ List validCerts = new ArrayList();
+ List validKeys = new ArrayList();
+
+ while (cert_it.hasNext())
+ {
+ X509Certificate signingCert = (X509Certificate)cert_it.next();
+
+ /*
+ * CA of the certificate, for which this CRL is checked, has also
+ * signed CRL, so skip the path validation, because is already done
+ */
+ if (signingCert.equals(defaultCRLSignCert))
+ {
+ validCerts.add(signingCert);
+ validKeys.add(defaultCRLSignKey);
+ continue;
+ }
+ try
+ {
+ CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ selector = new X509CertStoreSelector();
+ selector.setCertificate(signingCert);
+ ExtendedPKIXParameters temp = (ExtendedPKIXParameters)paramsPKIX.clone();
+ temp.setTargetCertConstraints(selector);
+ ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters)ExtendedPKIXBuilderParameters
+ .getInstance(temp);
+ /*
+ * if signingCert is placed not higher on the cert path a
+ * dependency loop results. CRL for cert is checked, but
+ * signingCert is needed for checking the CRL which is dependent
+ * on checking cert because it is higher in the cert path and so
+ * signing signingCert transitively. so, revocation is disabled,
+ * forgery attacks of the CRL are detected in this outer loop
+ * for all other it must be enabled to prevent forgery attacks
+ */
+ if (certPathCerts.contains(signingCert))
+ {
+ params.setRevocationEnabled(false);
+ }
+ else
+ {
+ params.setRevocationEnabled(true);
+ }
+ List certs = builder.build(params).getCertPath().getCertificates();
+ validCerts.add(signingCert);
+ validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0));
+ }
+ catch (CertPathBuilderException e)
+ {
+ throw new AnnotatedException("Internal error.", e);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ Set checkKeys = new HashSet();
+
+ AnnotatedException lastException = null;
+ for (int i = 0; i < validCerts.size(); i++)
+ {
+ X509Certificate signCert = (X509Certificate)validCerts.get(i);
+ boolean[] keyusage = signCert.getKeyUsage();
+
+ if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+ {
+ lastException = new AnnotatedException(
+ "Issuer certificate key usage extension does not permit CRL signing.");
+ }
+ else
+ {
+ checkKeys.add(validKeys.get(i));
+ }
+ }
+
+ if (checkKeys.isEmpty() && lastException == null)
+ {
+ throw new AnnotatedException("Cannot find a valid issuer certificate.");
+ }
+ if (checkKeys.isEmpty() && lastException != null)
+ {
+ throw lastException;
+ }
+
+ return checkKeys;
+ }
+
+ protected static PublicKey processCRLG(
+ X509CRL crl,
+ Set keys)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+ for (Iterator it = keys.iterator(); it.hasNext();)
+ {
+ PublicKey key = (PublicKey)it.next();
+ try
+ {
+ crl.verify(key);
+ return key;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ throw new AnnotatedException("Cannot verify CRL.", lastException);
+ }
+
+ protected static X509CRL processCRLH(
+ Set deltacrls,
+ PublicKey key)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+
+ for (Iterator it = deltacrls.iterator(); it.hasNext();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+ try
+ {
+ crl.verify(key);
+ return crl;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (lastException != null)
+ {
+ throw new AnnotatedException("Cannot verify delta CRL.", lastException);
+ }
+ return null;
+ }
+
+ protected static Set processCRLA1i(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set set = new HashSet();
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ CRLDistPoint freshestCRL = null;
+ try
+ {
+ freshestCRL = CRLDistPoint
+ .getInstance(CertPathValidatorUtilities.getExtensionValue(cert, FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e);
+ }
+ if (freshestCRL == null)
+ {
+ try
+ {
+ freshestCRL = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e);
+ }
+ }
+ if (freshestCRL != null)
+ {
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "No new delta CRL locations could be added from Freshest CRL extension.", e);
+ }
+ // get delta CRL(s)
+ try
+ {
+ set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ }
+ return set;
+ }
+
+ protected static Set[] processCRLA1ii(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set deltaSet = new HashSet();
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ crlselect.setCertificateChecking(cert);
+
+ try
+ {
+ crlselect.addIssuerName(PrincipalUtil.getIssuerX509Principal(crl).getEncoded());
+ }
+ catch (CRLException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL." + e, e);
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL." + e, e);
+ }
+
+ crlselect.setCompleteCRLEnabled(true);
+ Set completeSet = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ return new Set[]
+ {
+ completeSet,
+ deltaSet};
+ }
+
+
+
+ /**
+ * If use-deltas is set, verify the issuer and scope of the delta CRL.
+ *
+ * @param deltaCRL The delta CRL.
+ * @param completeCRL The complete CRL.
+ * @param pkixParams The PKIX paramaters.
+ * @throws AnnotatedException if an exception occurs.
+ */
+ protected static void processCRLC(
+ X509CRL deltaCRL,
+ X509CRL completeCRL,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (deltaCRL == null)
+ {
+ return;
+ }
+ IssuingDistributionPoint completeidp = null;
+ try
+ {
+ completeidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+
+ if (pkixParams.isUseDeltasEnabled())
+ {
+ // (c) (1)
+ try
+ {
+ if (!PrincipalUtil.getIssuerX509Principal(deltaCRL).equals(PrincipalUtil.getIssuerX509Principal(completeCRL)))
+ {
+ throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer.");
+ }
+ }
+ catch (CRLException e)
+ {
+ throw new AnnotatedException(
+ "Cannot extract issuer from CRL.", e);
+ }
+
+ // (c) (2)
+ IssuingDistributionPoint deltaidp = null;
+ try
+ {
+ deltaidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL could not be decoded.", e);
+ }
+
+ boolean match = false;
+ if (completeidp == null)
+ {
+ if (deltaidp == null)
+ {
+ match = true;
+ }
+ }
+ else
+ {
+ if (completeidp.equals(deltaidp))
+ {
+ match = true;
+ }
+ }
+ if (!match)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL and complete CRL does not match.");
+ }
+
+ // (c) (3)
+ ASN1Primitive completeKeyIdentifier = null;
+ try
+ {
+ completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from complete CRL.", e);
+ }
+
+ ASN1Primitive deltaKeyIdentifier = null;
+ try
+ {
+ deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from delta CRL.", e);
+ }
+
+ if (completeKeyIdentifier == null)
+ {
+ throw new AnnotatedException("CRL authority key identifier is null.");
+ }
+
+ if (deltaKeyIdentifier == null)
+ {
+ throw new AnnotatedException("Delta CRL authority key identifier is null.");
+ }
+
+ if (!completeKeyIdentifier.equals(deltaKeyIdentifier))
+ {
+ throw new AnnotatedException(
+ "Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+ }
+ }
+ }
+
+ protected static void processCRLI(
+ Date validDate,
+ X509CRL deltacrl,
+ Object cert,
+ CertStatus certStatus,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (pkixParams.isUseDeltasEnabled() && deltacrl != null)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, cert, certStatus);
+ }
+ }
+
+ protected static void processCRLJ(
+ Date validDate,
+ X509CRL completecrl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, completecrl, cert, certStatus);
+ }
+ }
+
+ protected static PKIXPolicyNode prepareCertB(
+ CertPath certPath,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ // (b)
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+ Map m_idp = new HashMap();
+ Set s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+ String id_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(0)).getId();
+ String sd_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(1)).getId();
+ Set tmp;
+
+ if (!m_idp.containsKey(id_p))
+ {
+ tmp = new HashSet();
+ tmp.add(sd_p);
+ m_idp.put(id_p, tmp);
+ s_idp.add(id_p);
+ }
+ else
+ {
+ tmp = (Set)m_idp.get(id_p);
+ tmp.add(sd_p);
+ }
+ }
+
+ Iterator it_idp = s_idp.iterator();
+ while (it_idp.hasNext())
+ {
+ String id_p = (String)it_idp.next();
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Certificate policies extension could not be decoded.", e, certPath, index);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathValidatorException(
+ "Policy information could not be decoded.", ex, certPath, index);
+ }
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = CertPathValidatorUtilities
+ .getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be decoded.", ex, certPath,
+ index);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, (Set)m_idp
+ .get(id_p), p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(
+ _validPolicyTree, policyNodes, node2);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return _validPolicyTree;
+ }
+
+ protected static void prepareNextCertA(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ //
+ // (a) check the policy mappings
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ if (pm != null)
+ {
+ ASN1Sequence mappings = pm;
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1ObjectIdentifier issuerDomainPolicy = null;
+ ASN1ObjectIdentifier subjectDomainPolicy = null;
+ try
+ {
+ ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j));
+
+ issuerDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(0));
+ subjectDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(1));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension contents could not be decoded.",
+ e, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(issuerDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy", null, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+ }
+ }
+ }
+ }
+
+ protected static void processCertF(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ //
+ // (f)
+ //
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ throw new ExtCertPathValidatorException("No valid policy tree found when one expected.", null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode processCertE(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (e)
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+ return validPolicyTree;
+ }
+
+ protected static void processCertBC(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (b), (c) permitted and excluded subtree checking.
+ //
+ if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n)))
+ {
+ X509Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert);
+ ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded());
+ ASN1Sequence dns;
+
+ try
+ {
+ dns = DERSequence.getInstance(aIn.readObject());
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Exception extracting subject name when checking subtrees.", e,
+ certPath, index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkPermittedDN(dns);
+ nameConstraintValidator.checkExcludedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException("Subtree check for certificate subject failed.", e, certPath,
+ index);
+ }
+
+ GeneralNames altName = null;
+ try
+ {
+ altName = GeneralNames.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME));
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Subject alternative name extension could not be decoded.", e,
+ certPath, index);
+ }
+ Vector emails = new X509Name(dns).getValues(X509Name.EmailAddress);
+ for (Enumeration e = emails.elements(); e.hasMoreElements();)
+ {
+ String email = (String)e.nextElement();
+ GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email);
+ try
+ {
+ nameConstraintValidator.checkPermitted(emailAsGeneralName);
+ nameConstraintValidator.checkExcluded(emailAsGeneralName);
+ }
+ catch (PKIXNameConstraintValidatorException ex)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+ }
+ }
+ if (altName != null)
+ {
+ GeneralName[] genNames = null;
+ try
+ {
+ genNames = altName.getNames();
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Subject alternative name contents could not be decoded.", e,
+ certPath, index);
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+
+ try
+ {
+ nameConstraintValidator.checkPermitted(genNames[j]);
+ nameConstraintValidator.checkExcluded(genNames[j]);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative name failed.", e, certPath, index);
+ }
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode processCertD(
+ CertPath certPath,
+ int index,
+ Set acceptablePolicies,
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (d) policy Information checking against initial policy and
+ // policy mapping
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+ //
+ // (d) (1)
+ //
+ Enumeration e = certPolicies.getObjects();
+ Set pols = new HashSet();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+ ASN1ObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+ pols.add(pOid.getId());
+
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(pOid.getId()))
+ {
+ Set pq = null;
+ try
+ {
+ pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info set could not be build.", ex,
+ certPath, index);
+ }
+
+ boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies.isEmpty() || acceptablePolicies.contains(RFC3280CertPathUtilities.ANY_POLICY))
+ {
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(pols);
+ }
+ else
+ {
+ Iterator it = acceptablePolicies.iterator();
+ Set t1 = new HashSet();
+
+ while (it.hasNext())
+ {
+ Object o = it.next();
+
+ if (pols.contains(o))
+ {
+ t1.add(o);
+ }
+ }
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(t1);
+ }
+
+ //
+ // (d) (2)
+ //
+ if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert)))
+ {
+ e = certPolicies.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+ {
+ Set _apq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ List _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
+
+ Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+ while (_policySetIter.hasNext())
+ {
+ Object _tmp = _policySetIter.next();
+
+ String _policy;
+ if (_tmp instanceof String)
+ {
+ _policy = (String)_tmp;
+ }
+ else if (_tmp instanceof ASN1ObjectIdentifier)
+ {
+ _policy = ((ASN1ObjectIdentifier)_tmp).getId();
+ }
+ else
+ {
+ continue;
+ }
+
+ boolean _found = false;
+ Iterator _childrenIter = _node.getChildren();
+
+ while (_childrenIter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
+
+ if (_policy.equals(_child.getValidPolicy()))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ Set _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.add(_policy);
+
+ PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(), i,
+ _newChildExpectedPolicies, _node, _apq, _policy, false);
+ _node.addChild(_newChild);
+ policyNodes[i].add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(_validPolicyTree, policyNodes,
+ node);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensionOids != null)
+ {
+ boolean critical = criticalExtensionOids.contains(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+
+ List nodes = policyNodes[i];
+ for (int j = 0; j < nodes.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
+ node.setCritical(critical);
+ }
+ }
+ return _validPolicyTree;
+ }
+ return null;
+ }
+
+ protected static void processCertA(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ int index,
+ PublicKey workingPublicKey,
+ boolean verificationAlreadyPerformed,
+ X509Principal workingIssuerName,
+ X509Certificate sign)
+ throws ExtCertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (a) verify
+ //
+ if (!verificationAlreadyPerformed)
+ {
+ try
+ {
+ // (a) (1)
+ //
+ CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
+ paramsPKIX.getSigProvider());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+ }
+ }
+
+ try
+ {
+ // (a) (2)
+ //
+ cert.checkValidity(CertPathValidatorUtilities
+ .getValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+ }
+
+ //
+ // (a) (3)
+ //
+ if (paramsPKIX.isRevocationEnabled())
+ {
+ try
+ {
+ checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX,
+ certPath, index), sign, workingPublicKey, certs);
+ }
+ catch (AnnotatedException e)
+ {
+ Throwable cause = e;
+ if (null != e.getCause())
+ {
+ cause = e.getCause();
+ }
+ throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index);
+ }
+ }
+
+ //
+ // (a) (4) name chaining
+ //
+ if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
+ {
+ throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)
+ + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+ certPath, index);
+ }
+ }
+
+ protected static int prepareNextCertI1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 0)
+ {
+ tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < explicitPolicy)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertI2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 1)
+ {
+ tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < policyMapping)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static void prepareNextCertG(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (g) handle the name constraints extension
+ //
+ NameConstraints nc = null;
+ try
+ {
+ ASN1Sequence ncSeq = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.NAME_CONSTRAINTS));
+ if (ncSeq != null)
+ {
+ nc = NameConstraints.getInstance(ncSeq);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Name constraints extension could not be decoded.", e, certPath,
+ index);
+ }
+ if (nc != null)
+ {
+
+ //
+ // (g) (1) permitted subtrees
+ //
+ GeneralSubtree[] permitted = nc.getPermittedSubtrees();
+ if (permitted != null)
+ {
+ try
+ {
+ nameConstraintValidator.intersectPermittedSubtree(permitted);
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ GeneralSubtree[] excluded = nc.getExcludedSubtrees();
+ if (excluded != null)
+ {
+ for (int i = 0; i != excluded.length; i++)
+ try
+ {
+ nameConstraintValidator.addExcludedSubtree(excluded[i]);
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks a distribution point for revocation information for the
+ * certificate <code>cert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param certStatus The current certificate revocation status.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ private static void checkCRL(
+ DistributionPoint dp,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ Date currentDate = new Date(System.currentTimeMillis());
+ if (validDate.getTime() > currentDate.getTime())
+ {
+ throw new AnnotatedException("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX);
+ boolean validCrlFound = false;
+ AnnotatedException lastException = null;
+ Iterator crl_iter = crls.iterator();
+
+ while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons())
+ {
+ try
+ {
+ X509CRL crl = (X509CRL)crl_iter.next();
+
+ // (d)
+ ReasonsMask interimReasonsMask = RFC3280CertPathUtilities.processCRLD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.hasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+ paramsPKIX, certPathCerts);
+ // (g)
+ PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
+
+ X509CRL deltaCRL = null;
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRLs
+ Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL validity time
+ */
+
+ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (cert.getNotAfter().getTime() < crl.getThisUpdate().getTime())
+ {
+ throw new AnnotatedException("No valid CRL for current time found.");
+ }
+ }
+
+ RFC3280CertPathUtilities.processCRLB1(dp, cert, crl);
+
+ // (b) (2)
+ RFC3280CertPathUtilities.processCRLB2(dp, cert, crl);
+
+ // (c)
+ RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+ // (j)
+ RFC3280CertPathUtilities.processCRLJ(validDate, crl, cert, certStatus);
+
+ // (k)
+ if (certStatus.getCertStatus() == CRLReason.removeFromCRL)
+ {
+ certStatus.setCertStatus(CertStatus.UNREVOKED);
+ }
+
+ // update reasons mask
+ reasonMask.addReasons(interimReasonsMask);
+
+ Set criticalExtensions = crl.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("CRL contains unsupported critical extensions.");
+ }
+ }
+
+ if (deltaCRL != null)
+ {
+ criticalExtensions = deltaCRL.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("Delta CRL contains unsupported critical extension.");
+ }
+ }
+ }
+
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+
+ /**
+ * Checks a certificate if it is revoked.
+ *
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param sign The issuer certificate of the certificate <code>cert</code>.
+ * @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ protected static void checkCRLs(
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ AnnotatedException lastException = null;
+ CRLDistPoint crldp = null;
+ try
+ {
+ crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("CRL distribution point extension could not be read.", e);
+ }
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ boolean validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Distribution points could not be read.", e);
+ }
+ if (dps != null)
+ {
+ for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++)
+ {
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone();
+ try
+ {
+ checkCRL(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the process
+ * above with any available CRLs not specified in a distribution point
+ * but issued by the certificate issuer.
+ */
+
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons())
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer fields
+ * omitted and a distribution point name of the certificate
+ * issuer.
+ */
+ ASN1Primitive issuer = null;
+ try
+ {
+ issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded())
+ .readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e);
+ }
+ DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.directoryName, issuer))), null, null);
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone();
+ checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ if (lastException instanceof AnnotatedException)
+ {
+ throw lastException;
+ }
+
+ throw new AnnotatedException("No valid CRL found.", lastException);
+ }
+ if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
+ {
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss +0000");
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String message = "Certificate revocation after " + df.format(certStatus.getRevocationDate());
+ message += ", reason: " + crlReasons[certStatus.getCertStatus()];
+ throw new AnnotatedException(message);
+ }
+ if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ certStatus.setCertStatus(CertStatus.UNDETERMINED);
+ }
+ if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
+ {
+ throw new AnnotatedException("Certificate status could not be determined.");
+ }
+ }
+
+ protected static int prepareNextCertJ(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (j)
+ //
+ ASN1Integer iap = null;
+ try
+ {
+ iap = ASN1Integer.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.INHIBIT_ANY_POLICY));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Inhibit any-policy extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.getValue().intValue();
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ {
+ return _inhibitAnyPolicy;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static void prepareNextCertK(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (k)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ if (!(bc.isCA()))
+ {
+ throw new CertPathValidatorException("Not a CA certificate");
+ }
+ }
+ else
+ {
+ throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+ }
+ }
+
+ protected static int prepareNextCertL(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (l)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ throw new ExtCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+ }
+
+ return maxPathLength - 1;
+ }
+ return maxPathLength;
+ }
+
+ protected static int prepareNextCertM(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (m)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.intValue();
+
+ if (_plc < maxPathLength)
+ {
+ return _plc;
+ }
+ }
+ }
+ return maxPathLength;
+ }
+
+ protected static void prepareNextCertN(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (n)
+ //
+ boolean[] _usage = cert.getKeyUsage();
+
+ if ((_usage != null) && !_usage[RFC3280CertPathUtilities.KEY_CERT_SIGN])
+ {
+ throw new ExtCertPathValidatorException(
+ "Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+ certPath, index);
+ }
+ }
+
+ protected static void prepareNextCertO(
+ CertPath certPath,
+ int index,
+ Set criticalExtensions,
+ List pathCheckers)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (o)
+ //
+
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+ }
+ }
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+ index);
+ }
+ }
+
+ protected static int prepareNextCertH1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (1)
+ //
+ if (explicitPolicy != 0)
+ {
+ return explicitPolicy - 1;
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertH2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (2)
+ //
+ if (policyMapping != 0)
+ {
+ return policyMapping - 1;
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static int prepareNextCertH3(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (3)
+ //
+ if (inhibitAnyPolicy != 0)
+ {
+ return inhibitAnyPolicy - 1;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static final String[] crlReasons = new String[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ protected static int wrapupCertA(
+ int explicitPolicy,
+ X509Certificate cert)
+ {
+ //
+ // (a)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0))
+ {
+ explicitPolicy--;
+ }
+ return explicitPolicy;
+ }
+
+ protected static int wrapupCertB(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (b)
+ //
+ int tmpInt;
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+ }
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ try
+ {
+ tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+ index);
+ }
+ if (tmpInt == 0)
+ {
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static void wrapupCertF(
+ CertPath certPath,
+ int index,
+ List pathCheckers,
+ Set criticalExtensions)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException("Additional certificate path checker failed.", e, certPath,
+ index);
+ }
+ }
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension: " + criticalExtensions, null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode wrapupCertG(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ Set userInitialPolicySet,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ Set acceptablePolicies)
+ throws CertPathValidatorException
+ {
+ int n = certPath.getCertificates().size();
+ //
+ // (g)
+ //
+ PKIXPolicyNode intersection;
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ intersection = null;
+ }
+ else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g)
+ // (ii)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ if (acceptablePolicies.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ else
+ {
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ _validPolicyNodeSet.add(_iter.next());
+ }
+ }
+ }
+ }
+
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!acceptablePolicies.contains(_validPolicy))
+ {
+ // validPolicyTree =
+ // removePolicyNode(validPolicyTree, policyNodes,
+ // _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree,
+ policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in
+ // RFC3280.
+ // However, as far as the validation result is concerned, both
+ // produce
+ // adequate result. The only difference is whether AnyPolicy is
+ // remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(_c_node.getValidPolicy()))
+ {
+ _validPolicyNodeSet.add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!userInitialPolicySet.contains(_validPolicy))
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes,
+ node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ return intersection;
+ }
+
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java
new file mode 100644
index 00000000..dd0a32c9
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLEntryObject.java
@@ -0,0 +1,293 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Enumerated;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.X509Extension;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+import org.spongycastle.jce.X509Principal;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+public class X509CRLEntryObject extends X509CRLEntry
+{
+ private TBSCertList.CRLEntry c;
+
+ private X500Name certificateIssuer;
+ private int hashValue;
+ private boolean isHashValueSet;
+
+ public X509CRLEntryObject(TBSCertList.CRLEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = null;
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+ * is <code>false</code> {@link #getCertificateIssuer()} will always
+ * return <code>null</code>, <code>previousCertificateIssuer</code> is
+ * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+ * has no certificate issuer CRL entry extension
+ * <code>previousCertificateIssuer</code> is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TBSCertList.CRLEntry object.
+ * @param isIndirect
+ * <code>true</code> if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CRLEntry.
+ */
+ public X509CRLEntryObject(
+ TBSCertList.CRLEntry c,
+ boolean isIndirect,
+ X500Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+ }
+
+ /**
+ * Will return true if any extensions are present and marked as critical as
+ * we currently don't handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId());
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.getInstance(
+ X509ExtensionUtil.fromExtensionValue(ext)).getNames();
+ for (int i = 0; i < names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ return X500Name.getInstance(names[i].getName());
+ }
+ }
+ return null;
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ X509Principal getCertificateIssuer()
+ {
+ if (certificateIssuer == null)
+ {
+ return null;
+ }
+ try
+ {
+ return new X509Principal(certificateIssuer.getEncoded());
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e.toString());
+ }
+ }
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Cache the hashCode value - calculating it with the standard method.
+ * @return calculated hashCode.
+ */
+ public int hashCode()
+ {
+ if (!isHashValueSet)
+ {
+ hashValue = super.hashCode();
+ isHashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getUserCertificate().getValue();
+ }
+
+ public Date getRevocationDate()
+ {
+ return c.getRevocationDate().getDate();
+ }
+
+ public boolean hasExtensions()
+ {
+ return c.getExtensions() != null;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl);
+
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+ if (e.hasMoreElements())
+ {
+ buf.append(" crlEntryExtensions:").append(nl);
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.reasonCode))
+ {
+ buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl);
+ }
+ else if (oid.equals(X509Extension.certificateIssuer))
+ {
+ buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java
new file mode 100644
index 00000000..46f9dab5
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CRLObject.java
@@ -0,0 +1,556 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLNumber;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.IssuingDistributionPoint;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.encoders.Hex;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+public class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ public X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = c.getIssuer();
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(ASN1Integer.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs != null)
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ for (int i = 0; i < certs.length; i++)
+ {
+ if (isIndirect && certs[i].hasExtensions())
+ {
+ Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (certs[i].getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ try
+ {
+ issuer = org.spongycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java
new file mode 100644
index 00000000..74b9c611
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/provider/X509CertificateObject.java
@@ -0,0 +1,858 @@
+package org.spongycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OutputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1String;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERIA5String;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.misc.MiscObjectIdentifiers;
+import org.spongycastle.asn1.misc.NetscapeCertType;
+import org.spongycastle.asn1.misc.NetscapeRevocationURL;
+import org.spongycastle.asn1.misc.VerisignCzagExtension;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x500.style.RFC4519Style;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.BasicConstraints;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.provider.RFC3280CertPathUtilities;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Integers;
+import org.spongycastle.util.encoders.Hex;
+
+public class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private org.spongycastle.asn1.x509.Certificate c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ org.spongycastle.asn1.x509.Certificate c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ public String getSigAlgName()
+ {
+ Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
+
+ if (prov != null)
+ {
+ String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ Provider[] provs = Security.getProviders();
+
+ //
+ // search every provider looking for a real algorithm
+ //
+ for (int i = 0; i != provs.length; i++)
+ {
+ String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
+ if (algName != null)
+ {
+ return algName;
+ }
+ }
+
+ return this.getSigAlgOID();
+ }
+
+ /**
+ * return the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Collection getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
+ }
+
+ public Collection getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getExtnValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ String oidId = oid.getId();
+
+ if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
+ || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
+ || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
+ || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
+ || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
+ || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
+ || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
+ || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
+ || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
+ {
+ continue;
+ }
+
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.keyUsage))
+ {
+ buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return null;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ list.add(Integers.valueOf(genName.getTagNo()));
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getEncoded());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
+ list.add(addrBytes);
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(list);
+ }
+ if (temp.size() == 0)
+ {
+ return null;
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java b/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java
new file mode 100644
index 00000000..0711e29c
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/jce/spec/PSSParameterSpec.java
@@ -0,0 +1,44 @@
+package org.spongycastle.jce.spec;
+
+/**
+ * This class specifies a parameter spec for RSA PSS encoding scheme,
+ * as defined in the PKCS#1 v2.1.
+ *
+ * @see java.security.spec.AlgorithmParameterSpec
+ * @see java.security.Signature
+ */
+public class PSSParameterSpec
+ extends Object
+ implements java.security.spec.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/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java b/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java
new file mode 100644
index 00000000..5b161b4d
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateHolder.java
@@ -0,0 +1,406 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.Holder;
+import org.spongycastle.asn1.x509.IssuerSerial;
+import org.spongycastle.asn1.x509.ObjectDigestInfo;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+
+/**
+ * The Holder object.
+ *
+ * <pre>
+ * Holder ::= SEQUENCE {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ * </pre>
+ * @deprecated use org.spongycastle.cert.AttributeCertificateHolder
+ */
+public class AttributeCertificateHolder
+ implements CertSelector, Selector
+{
+ final Holder holder;
+
+ AttributeCertificateHolder(ASN1Sequence seq)
+ {
+ holder = Holder.getInstance(seq);
+ }
+
+ public AttributeCertificateHolder(X509Principal issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new org.spongycastle.asn1.x509.Holder(new IssuerSerial(
+ new GeneralNames(new GeneralName(issuerName)),
+ new ASN1Integer(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ X509Principal name;
+
+ try
+ {
+ name = PrincipalUtil.getIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+
+ holder = new Holder(new IssuerSerial(generateGeneralNames(name),
+ new ASN1Integer(cert.getSerialNumber())));
+ }
+
+ public AttributeCertificateHolder(X509Principal principal)
+ {
+ holder = new Holder(generateGeneralNames(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ * <p>
+ * <code>digestedObjectType</code> can be one of the following:
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ * <p>
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * <code>digestedObjectType</code> is
+ * <code>otherObjectDigest</code>.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(int digestedObjectType,
+ String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
+ {
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType,
+ new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays
+ .clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ * <p>
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int getDigestedObjectType()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestedObjectType()
+ .getValue().intValue();
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getDigestAlgorithm()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
+ .getId();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or <code>null</code> if no object digest info is set.
+ */
+ public byte[] getObjectDigest()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getObjectDigest().getBytes();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getOtherObjectTypeID()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
+ }
+ return null;
+ }
+
+ private GeneralNames generateGeneralNames(X509Principal principal)
+ {
+ return new GeneralNames(new GeneralName(principal));
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
+ .getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Object[] getNames(GeneralName[] names)
+ {
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X509Principal(
+ ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ private Principal[] getPrincipals(GeneralNames names)
+ {
+ Object[] p = this.getNames(names.getNames());
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder
+ * entity names field.
+ *
+ * @return an array of Principal objects (usually X509Principal), null if no
+ * entity names field is set.
+ */
+ public Principal[] getEntityNames()
+ {
+ if (holder.getEntityName() != null)
+ {
+ return getPrincipals(holder.getEntityName());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public Principal[] getIssuer()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return getPrincipals(holder.getBaseCertificateID().getIssuer());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this
+ * holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is
+ * set.
+ */
+ public BigInteger getSerialNumber()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue();
+ }
+
+ return null;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)holder
+ .toASN1Object());
+ }
+
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
+ }
+
+ if (holder.getEntityName() != null)
+ {
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
+ holder.getEntityName()))
+ {
+ return true;
+ }
+ }
+ if (holder.getObjectDigestInfo() != null)
+ {
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance(getDigestAlgorithm(), "SC");
+
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ switch (getDigestedObjectType())
+ {
+ case ObjectDigestInfo.publicKey:
+ // TODO: DSA Dss-parms
+ md.update(cert.getPublicKey().getEncoded());
+ break;
+ case ObjectDigestInfo.publicKeyCert:
+ md.update(cert.getEncoded());
+ break;
+ }
+ if (!Arrays.areEqual(md.digest(), getObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.equals(other.holder);
+ }
+
+ public int hashCode()
+ {
+ return this.holder.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java b/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java
new file mode 100644
index 00000000..44512802
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/AttributeCertificateIssuer.java
@@ -0,0 +1,211 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.x509.AttCertIssuer;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.V2Form;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.util.Selector;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ */
+public class AttributeCertificateIssuer
+ implements CertSelector, Selector
+{
+ final ASN1Encodable form;
+
+ /**
+ * @param issuer
+ */
+ AttributeCertificateIssuer(
+ AttCertIssuer issuer)
+ {
+ form = issuer.getIssuer();
+ }
+
+ public AttributeCertificateIssuer(
+ X509Principal principal)
+ {
+ form = new V2Form(new GeneralNames(new GeneralName(principal)));
+ }
+
+ private Object[] getNames()
+ {
+ GeneralNames name;
+
+ if (form instanceof V2Form)
+ {
+ name = ((V2Form)form).getIssuerName();
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.getNames();
+
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X509Principal(((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate issuer object.
+ *
+ * @return an array of Principal objects (usually X509Principal)
+ */
+ public Principal[] getPrincipals()
+ {
+ Object[] p = this.getNames();
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.cert.CertSelector#clone()
+ */
+ public Object clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.cert.CertSelector#match(java.security.cert.Certificate)
+ */
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (form instanceof V2Form)
+ {
+ V2Form issuer = (V2Form)form;
+ if (issuer.getBaseCertificateID() != null)
+ {
+ return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), issuer.getBaseCertificateID().getIssuer());
+ }
+
+ GeneralNames name = issuer.getIssuerName();
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ GeneralNames name = (GeneralNames)form;
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert), name))
+ {
+ return true;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.equals(other.form);
+ }
+
+ public int hashCode()
+ {
+ return this.form.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java b/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java
new file mode 100644
index 00000000..55d80de9
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXBuilderParameters.java
@@ -0,0 +1,210 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import org.spongycastle.jce.cert.PKIXBuilderParameters;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.TrustAnchor;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class contains extended parameters for PKIX certification path builders.
+ *
+ * @see java.security.cert.PKIXBuilderParameters
+ * @see org.spongycastle.jce.provider.PKIXCertPathBuilderSpi
+ */
+public class ExtendedPKIXBuilderParameters extends ExtendedPKIXParameters
+{
+
+ private int maxPathLength = 5;
+
+ private Set excludedCerts = Collections.EMPTY_SET;
+
+ /**
+ * Excluded certificates are not used for building a certification path.
+ * <p>
+ * The returned set is immutable.
+ *
+ * @return Returns the excluded certificates.
+ */
+ public Set getExcludedCerts()
+ {
+ return Collections.unmodifiableSet(excludedCerts);
+ }
+
+ /**
+ * Sets the excluded certificates which are not used for building a
+ * certification path. If the <code>Set</code> is <code>null</code> an
+ * empty set is assumed.
+ * <p>
+ * The given set is cloned to protect it against subsequent modifications.
+ *
+ * @param excludedCerts The excluded certificates to set.
+ */
+ public void setExcludedCerts(Set excludedCerts)
+ {
+ if (excludedCerts == null)
+ {
+ excludedCerts = Collections.EMPTY_SET;
+ }
+ else
+ {
+ this.excludedCerts = new HashSet(excludedCerts);
+ }
+ }
+
+ /**
+ * 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}.
+ *
+ * <p>
+ * 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>Selector</code> specifying the
+ * constraints on the target certificate or attribute
+ * certificate.
+ * @throws InvalidAlgorithmParameterException if <code>trustAnchors</code>
+ * is empty.
+ * @throws NullPointerException if <code>trustAnchors</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements of
+ * <code>trustAnchors</code> is not of type
+ * <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXBuilderParameters(Set trustAnchors,
+ Selector targetConstraints)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ setTargetConstraints(targetConstraints);
+ }
+
+ /**
+ * Sets the maximum number of intermediate non-self-issued certificates in a
+ * certification path. The PKIX <code>CertPathBuilder</code> must not
+ * build paths longer then this length.
+ * <p>
+ * A value of 0 implies that the path can only contain a single certificate.
+ * A value of -1 does not limit the length. The default length is 5.
+ *
+ * <p>
+ *
+ * The basic constraints extension of a CA certificate overrides this value
+ * if smaller.
+ *
+ * @param maxPathLength the maximum number of non-self-issued intermediate
+ * certificates in the certification path
+ * @throws InvalidParameterException if <code>maxPathLength</code> is set
+ * to a value less than -1
+ *
+ * @see org.spongycastle.jce.provider.PKIXCertPathBuilderSpi
+ * @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 in the certification path.
+ *
+ * @return the maximum number of non-self-issued intermediate certificates
+ * in the certification path, or -1 if no limit exists.
+ *
+ * @see #setMaxPathLength(int)
+ */
+ public int getMaxPathLength()
+ {
+ return maxPathLength;
+ }
+
+ /**
+ * Can alse handle <code>ExtendedPKIXBuilderParameters</code> and
+ * <code>PKIXBuilderParameters</code>.
+ *
+ * @param params Parameters to set.
+ * @see org.spongycastle.x509.ExtendedPKIXParameters#setParams(java.security.cert.PKIXParameters)
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ super.setParams(params);
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ ExtendedPKIXBuilderParameters _params = (ExtendedPKIXBuilderParameters) params;
+ maxPathLength = _params.maxPathLength;
+ excludedCerts = new HashSet(_params.excludedCerts);
+ }
+ if (params instanceof PKIXBuilderParameters)
+ {
+ PKIXBuilderParameters _params = (PKIXBuilderParameters) params;
+ maxPathLength = _params.getMaxPathLength();
+ }
+ }
+
+ /**
+ * Makes a copy of this <code>PKIXParameters</code> 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()
+ {
+ ExtendedPKIXBuilderParameters params = null;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(getTrustAnchors(),
+ getTargetConstraints());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns an instance of <code>ExtendedPKIXParameters</code> which can be
+ * safely casted to <code>ExtendedPKIXBuilderParameters</code>.
+ * <p>
+ * This method can be used to get a copy from other
+ * <code>PKIXBuilderParameters</code>, <code>PKIXParameters</code>,
+ * and <code>ExtendedPKIXParameters</code> instances.
+ *
+ * @param pkixParams The PKIX parameters to create a copy of.
+ * @return An <code>ExtendedPKIXBuilderParameters</code> instance.
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXBuilderParameters params;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(pkixParams
+ .getTrustAnchors(), X509CertStoreSelector
+ .getInstance((X509CertSelector) pkixParams
+ .getTargetCertConstraints()));
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java b/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java
new file mode 100644
index 00000000..c2636c5b
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/ExtendedPKIXParameters.java
@@ -0,0 +1,647 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.Store;
+
+import java.security.InvalidAlgorithmParameterException;
+import org.spongycastle.jce.cert.CertSelector;
+import org.spongycastle.jce.cert.CertStore;
+import org.spongycastle.jce.cert.CollectionCertStoreParameters;
+import org.spongycastle.jce.cert.LDAPCertStoreParameters;
+import org.spongycastle.jce.cert.PKIXParameters;
+import org.spongycastle.jce.cert.TrustAnchor;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class extends the PKIXParameters with a validity model parameter.
+ */
+public class ExtendedPKIXParameters
+ extends PKIXParameters
+{
+
+ private List stores;
+
+ private Selector selector;
+
+ private boolean additionalLocationsEnabled;
+
+ private List additionalStores;
+
+ private Set trustedACIssuers;
+
+ private Set necessaryACAttributes;
+
+ private Set prohibitedACAttributes;
+
+ private Set attrCertCheckers;
+
+ /**
+ * Creates an instance of <code>PKIXParameters</code> with the specified
+ * <code>Set</code> of most-trusted CAs. Each element of the set is a
+ * {@link TrustAnchor TrustAnchor}. <p/> Note that the <code>Set</code>
+ * is copied to protect against subsequent modifications.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @throws InvalidAlgorithmParameterException if the specified
+ * <code>Set</code> is empty.
+ * @throws NullPointerException if the specified <code>Set</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements in the <code>Set</code>
+ * is not of type <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXParameters(Set trustAnchors)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ stores = new ArrayList();
+ additionalStores = new ArrayList();
+ trustedACIssuers = new HashSet();
+ necessaryACAttributes = new HashSet();
+ prohibitedACAttributes = new HashSet();
+ attrCertCheckers = new HashSet();
+ }
+
+ /**
+ * Returns an instance with the parameters of a given
+ * <code>PKIXParameters</code> object.
+ *
+ * @param pkixParams The given <code>PKIXParameters</code>
+ * @return an extended PKIX params object
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(pkixParams.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+
+ /**
+ * Method to support <code>clone()</code> under J2ME.
+ * <code>super.clone()</code> does not exist and fields are not copied.
+ *
+ * @param params Parameters to set. If this are
+ * <code>ExtendedPKIXParameters</code> they are copied to.
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ setDate(params.getDate());
+ setCertPathCheckers(params.getCertPathCheckers());
+ setCertStores(params.getCertStores());
+ setAnyPolicyInhibited(params.isAnyPolicyInhibited());
+ setExplicitPolicyRequired(params.isExplicitPolicyRequired());
+ setPolicyMappingInhibited(params.isPolicyMappingInhibited());
+ setRevocationEnabled(params.isRevocationEnabled());
+ setInitialPolicies(params.getInitialPolicies());
+ setPolicyQualifiersRejected(params.getPolicyQualifiersRejected());
+ setSigProvider(params.getSigProvider());
+ setTargetCertConstraints(params.getTargetCertConstraints());
+ try
+ {
+ setTrustAnchors(params.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ ExtendedPKIXParameters _params = (ExtendedPKIXParameters) params;
+ validityModel = _params.validityModel;
+ useDeltas = _params.useDeltas;
+ additionalLocationsEnabled = _params.additionalLocationsEnabled;
+ selector = _params.selector == null ? null
+ : (Selector) _params.selector.clone();
+ stores = new ArrayList(_params.stores);
+ additionalStores = new ArrayList(_params.additionalStores);
+ trustedACIssuers = new HashSet(_params.trustedACIssuers);
+ prohibitedACAttributes = new HashSet(_params.prohibitedACAttributes);
+ necessaryACAttributes = new HashSet(_params.necessaryACAttributes);
+ attrCertCheckers = new HashSet(_params.attrCertCheckers);
+ }
+ }
+
+ /**
+ * This is the default PKIX validity model. Actually there are two variants
+ * of this: The PKIX model and the modified PKIX model. The PKIX model
+ * verifies that all involved certificates must have been valid at the
+ * current time. The modified PKIX model verifies that all involved
+ * certificates were valid at the signing time. Both are indirectly choosen
+ * with the {@link PKIXParameters#setDate(java.util.Date)} method, so this
+ * methods sets the Date when <em>all</em> certificates must have been
+ * valid.
+ */
+ public static final int PKIX_VALIDITY_MODEL = 0;
+
+ /**
+ * This model uses the following validity model. Each certificate must have
+ * been valid at the moment where is was used. That means the end
+ * certificate must have been valid at the time the signature was done. The
+ * CA certificate which signed the end certificate must have been valid,
+ * when the end certificate was signed. The CA (or Root CA) certificate must
+ * have been valid, when the CA certificate was signed and so on. So the
+ * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when
+ * the <em>end certificate</em> must have been valid. <p/> It is used e.g.
+ * in the German signature law.
+ */
+ public static final int CHAIN_VALIDITY_MODEL = 1;
+
+ private int validityModel = PKIX_VALIDITY_MODEL;
+
+ private boolean useDeltas = false;
+
+ /**
+ * Defaults to <code>false</code>.
+ *
+ * @return Returns if delta CRLs should be used.
+ */
+ public boolean isUseDeltasEnabled()
+ {
+ return useDeltas;
+ }
+
+ /**
+ * Sets if delta CRLs should be used for checking the revocation status.
+ *
+ * @param useDeltas <code>true</code> if delta CRLs should be used.
+ */
+ public void setUseDeltasEnabled(boolean useDeltas)
+ {
+ this.useDeltas = useDeltas;
+ }
+
+ /**
+ * @return Returns the validity model.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public int getValidityModel()
+ {
+ return validityModel;
+ }
+
+ /**
+ * Sets the Java CertStore to this extended PKIX parameters.
+ *
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>CertStore</code>.
+ */
+ public void setCertStores(List stores)
+ {
+ if (stores != null)
+ {
+ Iterator it = stores.iterator();
+ while (it.hasNext())
+ {
+ addCertStore((CertStore)it.next());
+ }
+ }
+ }
+
+ /**
+ * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * The <code>List</code> is cloned.
+ *
+ * @param stores A list of stores to use.
+ * @see #getStores
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a {@link Store}.
+ */
+ public void setStores(List stores)
+ {
+ if (stores == null)
+ {
+ this.stores = new ArrayList();
+ }
+ else
+ {
+ for (Iterator i = stores.iterator(); i.hasNext();)
+ {
+ if (!(i.next() instanceof Store))
+ {
+ throw new ClassCastException(
+ "All elements of list must be "
+ + "of type org.spongycastle.util.Store.");
+ }
+ }
+ this.stores = new ArrayList(stores);
+ }
+ }
+
+ /**
+ * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * This method should be used to add local stores, like collection based
+ * X.509 stores, if available. Local stores should be considered first,
+ * before trying to use additional (remote) locations, because they do not
+ * need possible additional network traffic.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores
+ */
+ public void addStore(Store store)
+ {
+ if (stores != null)
+ {
+ stores.add(store);
+ }
+ }
+
+ /**
+ * Adds a additional Bouncy Castle {@link Store} to find CRLs, certificates,
+ * attribute certificates or cross certificates.
+ * <p>
+ * You should not use this method. This method is used for adding additional
+ * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
+ * during X.509 object processing, e.g. in certificates or CRLs. This method
+ * is used in PKIX certification path processing.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores()
+ */
+ public void addAddionalStore(Store store)
+ {
+ if (store != null)
+ {
+ additionalStores.add(store);
+ }
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #addAddionalStore(Store)
+ */
+ public List getAdditionalStores()
+ {
+ return Collections.unmodifiableList(additionalStores);
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #setStores(List)
+ */
+ public List getStores()
+ {
+ return Collections.unmodifiableList(new ArrayList(stores));
+ }
+
+ /**
+ * @param validityModel The validity model to set.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public void setValidityModel(int validityModel)
+ {
+ this.validityModel = validityModel;
+ }
+
+ public Object clone()
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns if additional {@link X509Store}s for locations like LDAP found
+ * in certificates or CRLs should be used.
+ *
+ * @return Returns <code>true</code> if additional stores are used.
+ */
+ public boolean isAdditionalLocationsEnabled()
+ {
+ return additionalLocationsEnabled;
+ }
+
+ /**
+ * Sets if additional {@link X509Store}s for locations like LDAP found in
+ * certificates or CRLs should be used.
+ *
+ * @param enabled <code>true</code> if additional stores are used.
+ */
+ public void setAdditionalLocationsEnabled(boolean enabled)
+ {
+ additionalLocationsEnabled = enabled;
+ }
+
+ /**
+ * Returns the required constraints on the target certificate or attribute
+ * certificate. The constraints are returned as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ *
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> returned is cloned to protect
+ * against subsequent modifications.
+ *
+ * @return a <code>Selector</code> specifying the constraints on the
+ * target certificate or attribute certificate (or <code>null</code>)
+ * @see #setTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public Selector getTargetConstraints()
+ {
+ if (selector != null)
+ {
+ return (Selector) selector.clone();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate or attribute
+ * certificate. The constraints are specified as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> specified is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param selector a <code>Selector</code> specifying the constraints on
+ * the target certificate or attribute certificate (or
+ * <code>null</code>)
+ * @see #getTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public void setTargetConstraints(Selector selector)
+ {
+ if (selector != null)
+ {
+ this.selector = (Selector) selector.clone();
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate. The constraints
+ * are specified as an instance of <code>X509CertSelector</code>. If
+ * <code>null</code>, no constraints are defined.
+ *
+ * <p>
+ * This method wraps the given <code>X509CertSelector</code> into a
+ * <code>X509CertStoreSelector</code>.
+ * <p>
+ * Note that the <code>X509CertSelector</code> specified is cloned to
+ * protect against subsequent modifications.
+ *
+ * @param selector a <code>X509CertSelector</code> specifying the
+ * constraints on the target certificate (or <code>null</code>)
+ * @see #getTargetCertConstraints
+ * @see X509CertStoreSelector
+ */
+ public void setTargetCertConstraints(CertSelector selector)
+ {
+ super.setTargetCertConstraints(selector);
+ if (selector != null)
+ {
+ this.selector = X509CertStoreSelector
+ .getInstance((X509CertSelector) selector);
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Returns the trusted attribute certificate issuers. If attribute
+ * certificates is verified the trusted AC issuers must be set.
+ * <p>
+ * The returned <code>Set</code> consists of <code>TrustAnchor</code>s.
+ * <p>
+ * The returned <code>Set</code> is immutable. Never <code>null</code>
+ *
+ * @return Returns an immutable set of the trusted AC issuers.
+ */
+ public Set getTrustedACIssuers()
+ {
+ return Collections.unmodifiableSet(trustedACIssuers);
+ }
+
+ /**
+ * Sets the trusted attribute certificate issuers. If attribute certificates
+ * is verified the trusted AC issuers must be set.
+ * <p>
+ * The <code>trustedACIssuers</code> must be a <code>Set</code> of
+ * <code>TrustAnchor</code>
+ * <p>
+ * The given set is cloned.
+ *
+ * @param trustedACIssuers The trusted AC issuers to set. Is never
+ * <code>null</code>.
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>TrustAnchor</code>.
+ */
+ public void setTrustedACIssuers(Set trustedACIssuers)
+ {
+ if (trustedACIssuers == null)
+ {
+ trustedACIssuers.clear();
+ return;
+ }
+ for (Iterator it = trustedACIssuers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof TrustAnchor))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + TrustAnchor.class.getName() + ".");
+ }
+ }
+ this.trustedACIssuers.clear();
+ this.trustedACIssuers.addAll(trustedACIssuers);
+ }
+
+ /**
+ * Returns the neccessary attributes which must be contained in an attribute
+ * certificate.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the necessary AC attributes.
+ */
+ public Set getNecessaryACAttributes()
+ {
+ return Collections.unmodifiableSet(necessaryACAttributes);
+ }
+
+ /**
+ * Sets the neccessary which must be contained in an attribute certificate.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param necessaryACAttributes The necessary AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>necessaryACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setNecessaryACAttributes(Set necessaryACAttributes)
+ {
+ if (necessaryACAttributes == null)
+ {
+ this.necessaryACAttributes.clear();
+ return;
+ }
+ for (Iterator it = necessaryACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.necessaryACAttributes.clear();
+ this.necessaryACAttributes.addAll(necessaryACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificates which are not allowed.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the prohibited AC attributes. Is never <code>null</code>.
+ */
+ public Set getProhibitedACAttributes()
+ {
+ return prohibitedACAttributes;
+ }
+
+ /**
+ * Sets the attribute certificates which are not allowed.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param prohibitedACAttributes The prohibited AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>prohibitedACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setProhibitedACAttributes(Set prohibitedACAttributes)
+ {
+ if (prohibitedACAttributes == null)
+ {
+ this.prohibitedACAttributes.clear();
+ return;
+ }
+ for (Iterator it = prohibitedACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.prohibitedACAttributes.clear();
+ this.prohibitedACAttributes.addAll(prohibitedACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificate checker. The returned set contains
+ * {@link PKIXAttrCertChecker}s and is immutable.
+ *
+ * @return Returns the attribute certificate checker. Is never
+ * <code>null</code>.
+ */
+ public Set getAttrCertCheckers()
+ {
+ return Collections.unmodifiableSet(attrCertCheckers);
+ }
+
+ /**
+ * Sets the attribute certificate checkers.
+ * <p>
+ * All elements in the <code>Set</code> must a {@link PKIXAttrCertChecker}.
+ * <p>
+ * The given set is cloned.
+ *
+ * @param attrCertCheckers The attribute certificate checkers to set. Is
+ * never <code>null</code>.
+ * @throws ClassCastException if an element of <code>attrCertCheckers</code>
+ * is not a <code>PKIXAttrCertChecker</code>.
+ */
+/*
+ public void setAttrCertCheckers(Set attrCertCheckers)
+ {
+ if (attrCertCheckers == null)
+ {
+ this.attrCertCheckers.clear();
+ return;
+ }
+ for (Iterator it = attrCertCheckers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof PKIXAttrCertChecker))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + PKIXAttrCertChecker.class.getName() + ".");
+ }
+ }
+ this.attrCertCheckers.clear();
+ this.attrCertCheckers.addAll(attrCertCheckers);
+ }
+*/
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java b/prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java
new file mode 100644
index 00000000..b47236d1
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/X509AttributeCertStoreSelector.java
@@ -0,0 +1,486 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.Targets;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Selector;
+
+/**
+ * This class is an <code>Selector</code> like implementation to select
+ * attribute certificates from a given set of criteria.
+ *
+ * @see org.spongycastle.x509.X509AttributeCertificate
+ * @see org.spongycastle.x509.X509Store
+ */
+public class X509AttributeCertStoreSelector
+ implements Selector
+{
+
+ // TODO: name constraints???
+
+ private AttributeCertificateHolder holder;
+
+ private AttributeCertificateIssuer issuer;
+
+ private BigInteger serialNumber;
+
+ private Date attributeCertificateValid;
+
+ private X509AttributeCertificate attributeCert;
+
+ private Collection targetNames = new HashSet();
+
+ private Collection targetGroups = new HashSet();
+
+ public X509AttributeCertStoreSelector()
+ {
+ super();
+ }
+
+ /**
+ * Decides if the given attribute certificate should be selected.
+ *
+ * @param obj The attribute certificate which should be checked.
+ * @return <code>true</code> if the attribute certificate can be selected,
+ * <code>false</code> otherwise.
+ */
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509AttributeCertificate))
+ {
+ return false;
+ }
+
+ X509AttributeCertificate attrCert = (X509AttributeCertificate) obj;
+
+ if (this.attributeCert != null)
+ {
+ if (!this.attributeCert.equals(attrCert))
+ {
+ return false;
+ }
+ }
+ if (serialNumber != null)
+ {
+ if (!attrCert.getSerialNumber().equals(serialNumber))
+ {
+ return false;
+ }
+ }
+ if (holder != null)
+ {
+ if (!attrCert.getHolder().equals(holder))
+ {
+ return false;
+ }
+ }
+ if (issuer != null)
+ {
+ if (!attrCert.getIssuer().equals(issuer))
+ {
+ return false;
+ }
+ }
+
+ if (attributeCertificateValid != null)
+ {
+ try
+ {
+ attrCert.checkValidity(attributeCertificateValid);
+ }
+ catch (CertificateExpiredException e)
+ {
+ return false;
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ return false;
+ }
+ }
+ if (!targetNames.isEmpty() || !targetGroups.isEmpty())
+ {
+
+ byte[] targetInfoExt = attrCert
+ .getExtensionValue(X509Extensions.TargetInformation.getId());
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation
+ .getInstance(new ASN1InputStream(
+ ((DEROctetString) DEROctetString
+ .fromByteArray(targetInfoExt)).getOctets())
+ .readObject());
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+ Targets[] targetss = targetinfo.getTargetsObjects();
+ if (!targetNames.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetNames.contains(targets[j]
+ .getTargetName()))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ if (!targetGroups.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetGroups.contains(targets[j]
+ .getTargetGroup()))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return the clone.
+ */
+ public Object clone()
+ {
+ X509AttributeCertStoreSelector sel = new X509AttributeCertStoreSelector();
+ sel.attributeCert = attributeCert;
+ sel.attributeCertificateValid = getAttributeCertificateValid();
+ sel.holder = holder;
+ sel.issuer = issuer;
+ sel.serialNumber = serialNumber;
+ sel.targetGroups = getTargetGroups();
+ sel.targetNames = getTargetNames();
+ return sel;
+ }
+
+ /**
+ * Returns the attribute certificate which must be matched.
+ *
+ * @return Returns the attribute certificate.
+ */
+ public X509AttributeCertificate getAttributeCert()
+ {
+ return attributeCert;
+ }
+
+ /**
+ * Set the attribute certificate to be matched. If <code>null</code> is
+ * given any will do.
+ *
+ * @param attributeCert The attribute certificate to set.
+ */
+ public void setAttributeCert(X509AttributeCertificate attributeCert)
+ {
+ this.attributeCert = attributeCert;
+ }
+
+ /**
+ * Get the criteria for the validity.
+ *
+ * @return Returns the attributeCertificateValid.
+ */
+ public Date getAttributeCertificateValid()
+ {
+ if (attributeCertificateValid != null)
+ {
+ return new Date(attributeCertificateValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Set the time, when the certificate must be valid. If <code>null</code>
+ * is given any will do.
+ *
+ * @param attributeCertificateValid The attribute certificate validation
+ * time to set.
+ */
+ public void setAttributeCertificateValid(Date attributeCertificateValid)
+ {
+ if (attributeCertificateValid != null)
+ {
+ this.attributeCertificateValid = new Date(attributeCertificateValid
+ .getTime());
+ }
+ else
+ {
+ this.attributeCertificateValid = null;
+ }
+ }
+
+ /**
+ * Gets the holder.
+ *
+ * @return Returns the holder.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return holder;
+ }
+
+ /**
+ * Sets the holder. If <code>null</code> is given any will do.
+ *
+ * @param holder The holder to set.
+ */
+ public void setHolder(AttributeCertificateHolder holder)
+ {
+ this.holder = holder;
+ }
+
+ /**
+ * Returns the issuer criterion.
+ *
+ * @return Returns the issuer.
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return issuer;
+ }
+
+ /**
+ * Sets the issuer the attribute certificate must have. If <code>null</code>
+ * is given any will do.
+ *
+ * @param issuer The issuer to set.
+ */
+ public void setIssuer(AttributeCertificateIssuer issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ /**
+ * Gets the serial number the attribute certificate must have.
+ *
+ * @return Returns the serialNumber.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ /**
+ * Sets the serial number the attribute certificate must have. If
+ * <code>null</code> is given any will do.
+ *
+ * @param serialNumber The serialNumber to set.
+ */
+ public void setSerialNumber(BigInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name The name as a GeneralName (not <code>null</code>)
+ */
+ public void addTargetName(GeneralName name)
+ {
+ targetNames.add(name);
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetName(byte[] name) throws IOException
+ {
+ addTargetName(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target names criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ * @param names A collection of target names.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetName(byte[])
+ * @see #addTargetName(GeneralName)
+ */
+ public void setTargetNames(Collection names) throws IOException
+ {
+ targetNames = extractGeneralNames(names);
+ }
+
+ /**
+ * Gets the target names. The collection consists of <code>List</code>s
+ * made up of an <code>Integer</code> in the first entry and a DER encoded
+ * byte array or a <code>String</code> in the second entry.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ * @see #setTargetNames(Collection)
+ */
+ public Collection getTargetNames()
+ {
+ return Collections.unmodifiableCollection(targetNames);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param group The group as GeneralName form (not <code>null</code>)
+ */
+ public void addTargetGroup(GeneralName group)
+ {
+ targetGroups.add(group);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificate</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+ * @throws IOException if a parsing error occurs.
+ */
+ public void addTargetGroup(byte[] name) throws IOException
+ {
+ addTargetGroup(GeneralName.getInstance(ASN1Primitive.fromByteArray(name)));
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER
+ * encoded GeneralNames.
+ *
+ * @param names A collection of target groups.
+ * @throws IOException if a parsing error occurs.
+ * @see #addTargetGroup(byte[])
+ * @see #addTargetGroup(GeneralName)
+ */
+ public void setTargetGroups(Collection names) throws IOException
+ {
+ targetGroups = extractGeneralNames(names);
+ }
+
+
+
+ /**
+ * Gets the target groups. The collection consists of <code>List</code>s
+ * made up of an <code>Integer</code> in the first entry and a DER encoded
+ * byte array or a <code>String</code> in the second entry.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ * @see #setTargetGroups(Collection)
+ */
+ public Collection getTargetGroups()
+ {
+ return Collections.unmodifiableCollection(targetGroups);
+ }
+
+ private Set extractGeneralNames(Collection names)
+ throws IOException
+ {
+ if (names == null || names.isEmpty())
+ {
+ return new HashSet();
+ }
+ Set temp = new HashSet();
+ for (Iterator it = names.iterator(); it.hasNext();)
+ {
+ Object o = it.next();
+ if (o instanceof GeneralName)
+ {
+ temp.add(o);
+ }
+ else
+ {
+ temp.add(GeneralName.getInstance(ASN1Primitive.fromByteArray((byte[])o)));
+ }
+ }
+ return temp;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java b/prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 00000000..554911f0
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/X509CRLStoreSelector.java
@@ -0,0 +1,330 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRL;
+import java.security.cert.X509CRL;
+import org.spongycastle.jce.cert.X509CRLSelector;
+
+/**
+ * This class is a Selector implementation for X.509 certificate revocation
+ * lists.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCRLCollection
+ */
+public class X509CRLStoreSelector
+ extends X509CRLSelector
+ implements Selector
+{
+ private boolean deltaCRLIndicator = false;
+
+ private boolean completeCRLEnabled = false;
+
+ private BigInteger maxBaseCRLNumber = null;
+
+ private byte[] issuingDistributionPoint = null;
+
+ private boolean issuingDistributionPointEnabled = false;
+
+ private X509AttributeCertificate attrCertChecking;
+
+ /**
+ * Returns if the issuing distribution point criteria should be applied.
+ * Defaults to <code>false</code>.
+ * <p>
+ * You may also set the issuing distribution point criteria if not a missing
+ * issuing distribution point should be assumed.
+ *
+ * @return Returns if the issuing distribution point check is enabled.
+ */
+ public boolean isIssuingDistributionPointEnabled()
+ {
+ return issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Enables or disables the issuing distribution point check.
+ *
+ * @param issuingDistributionPointEnabled <code>true</code> to enable the
+ * issuing distribution point check.
+ */
+ public void setIssuingDistributionPointEnabled(
+ boolean issuingDistributionPointEnabled)
+ {
+ this.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Sets the attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If <code>null</code> is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the <code>X509AttributeCertificate</code> being checked (or
+ * <code>null</code>)
+ * @see #getAttrCertificateChecking()
+ */
+ public void setAttrCertificateChecking(X509AttributeCertificate attrCert)
+ {
+ attrCertChecking = attrCert;
+ }
+
+ /**
+ * Returns the attribute certificate being checked.
+ *
+ * @return Returns the attribute certificate being checked.
+ * @see #setAttrCertificateChecking(X509AttributeCertificate)
+ */
+ public X509AttributeCertificate getAttrCertificateChecking()
+ {
+ return attrCertChecking;
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509CRL))
+ {
+ return false;
+ }
+ X509CRL crl = (X509CRL)obj;
+ ASN1Integer dci = null;
+ try
+ {
+ byte[] bytes = crl
+ .getExtensionValue(X509Extensions.DeltaCRLIndicator.getId());
+ if (bytes != null)
+ {
+ dci = ASN1Integer.getInstance(X509ExtensionUtil
+ .fromExtensionValue(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ if (isDeltaCRLIndicatorEnabled())
+ {
+ if (dci == null)
+ {
+ return false;
+ }
+ }
+ if (isCompleteCRLEnabled())
+ {
+ if (dci != null)
+ {
+ return false;
+ }
+ }
+ if (dci != null)
+ {
+
+ if (maxBaseCRLNumber != null)
+ {
+ if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1)
+ {
+ return false;
+ }
+ }
+ }
+ if (issuingDistributionPointEnabled)
+ {
+ byte[] idp = crl
+ .getExtensionValue(X509Extensions.IssuingDistributionPoint
+ .getId());
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.areEqual(idp, issuingDistributionPoint))
+ {
+ return false;
+ }
+ }
+
+ }
+ return super.match((X509CRL)obj);
+ }
+
+ public boolean match(CRL crl)
+ {
+ return match((Object)crl);
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to <code>false</code>.
+ *
+ * @return Returns <code>true</code> if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public boolean isDeltaCRLIndicatorEnabled()
+ {
+ return deltaCRLIndicator;
+ }
+
+ /**
+ * If this is set to <code>true</code> the CRL reported contains the delta
+ * CRL indicator CRL extension.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator
+ * extension must be in the CRL.
+ */
+ public void setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator)
+ {
+ this.deltaCRLIndicator = deltaCRLIndicator;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CRLSelector</code>.
+ *
+ * @param selector A <code>X509CRLSelector</code> instance.
+ * @return An instance of an <code>X509CRLStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation
+ * fails.
+ */
+ public static X509CRLStoreSelector getInstance(X509CRLSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException(
+ "cannot create from null selector");
+ }
+ X509CRLStoreSelector cs = new X509CRLStoreSelector();
+ cs.setCertificateChecking(selector.getCertificateChecking());
+ cs.setDateAndTime(selector.getDateAndTime());
+ try
+ {
+ cs.setIssuerNames(selector.getIssuerNames());
+ }
+ catch (IOException e)
+ {
+ // cannot happen
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ //cs.setIssuers(selector.getIssuers());
+ cs.setMaxCRLNumber(selector.getMaxCRL());
+ cs.setMinCRLNumber(selector.getMinCRL());
+ return cs;
+ }
+
+ public Object clone()
+ {
+ X509CRLStoreSelector sel = X509CRLStoreSelector.getInstance(this);
+ sel.deltaCRLIndicator = deltaCRLIndicator;
+ sel.completeCRLEnabled = completeCRLEnabled;
+ sel.maxBaseCRLNumber = maxBaseCRLNumber;
+ sel.attrCertChecking = attrCertChecking;
+ sel.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ sel.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ return sel;
+ }
+
+ /**
+ * If <code>true</code> only complete CRLs are returned. Defaults to
+ * <code>false</code>.
+ *
+ * @return <code>true</code> if only complete CRLs are returned.
+ */
+ public boolean isCompleteCRLEnabled()
+ {
+ return completeCRLEnabled;
+ }
+
+ /**
+ * If set to <code>true</code> only complete CRLs are returned.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param completeCRLEnabled <code>true</code> if only complete CRLs
+ * should be returned.
+ */
+ public void setCompleteCRLEnabled(boolean completeCRLEnabled)
+ {
+ this.completeCRLEnabled = completeCRLEnabled;
+ }
+
+ /**
+ * Get the maximum base CRL number. Defaults to <code>null</code>.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger getMaxBaseCRLNumber()
+ {
+ return maxBaseCRLNumber;
+ }
+
+ /**
+ * Sets the maximum base CRL number. Setting to <code>null</code> disables
+ * this cheack.
+ * <p>
+ * This is only meaningful for delta CRLs. Complete CRLs must have a CRL
+ * number which is greater or equal than the base number of the
+ * corresponding CRL.
+ *
+ * @param maxBaseCRLNumber The maximum base CRL number to set.
+ */
+ public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber)
+ {
+ this.maxBaseCRLNumber = maxBaseCRLNumber;
+ }
+
+ /**
+ * Returns the issuing distribution point. Defaults to <code>null</code>,
+ * which is a missing issuing distribution point extension.
+ * <p>
+ * The internal byte array is cloned before it is returned.
+ * <p>
+ * The criteria must be enable with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @return Returns the issuing distribution point.
+ * @see #setIssuingDistributionPoint(byte[])
+ */
+ public byte[] getIssuingDistributionPoint()
+ {
+ return Arrays.clone(issuingDistributionPoint);
+ }
+
+ /**
+ * Sets the issuing distribution point.
+ * <p>
+ * The issuing distribution point extension is a CRL extension which
+ * identifies the scope and the distribution point of a CRL. The scope
+ * contains among others information about revocation reasons contained in
+ * the CRL. Delta CRLs and complete CRLs must have matching issuing
+ * distribution points.
+ * <p>
+ * The byte array is cloned to protect against subsequent modifications.
+ * <p>
+ * You must also enable or disable this criteria with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @param issuingDistributionPoint The issuing distribution point to set.
+ * This is the DER encoded OCTET STRING extension value.
+ * @see #getIssuingDistributionPoint()
+ */
+ public void setIssuingDistributionPoint(byte[] issuingDistributionPoint)
+ {
+ this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java b/prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 00000000..f4efcddb
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/X509CertStoreSelector.java
@@ -0,0 +1,86 @@
+package org.spongycastle.x509;
+
+import org.spongycastle.util.Selector;
+
+import java.io.IOException;
+import java.security.cert.Certificate;
+import org.spongycastle.jce.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+
+/**
+ * This class is a Selector implementation for X.509 certificates.
+ *
+ * @see org.spongycastle.util.Selector
+ * @see org.spongycastle.x509.X509Store
+ * @see org.spongycastle.jce.provider.X509StoreCertCollection
+ */
+public class X509CertStoreSelector
+ extends X509CertSelector
+ implements Selector
+{
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate other = (X509Certificate)obj;
+
+ return super.match(other);
+ }
+
+ public boolean match(Certificate cert)
+ {
+ return match((Object)cert);
+ }
+
+ public Object clone()
+ {
+ X509CertStoreSelector selector = (X509CertStoreSelector)super.clone();
+
+ return selector;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CertSelector</code>.
+ *
+ * @param selector A <code>X509CertSelector</code> instance.
+ * @return An instance of an <code>X509CertStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation fails.
+ */
+ public static X509CertStoreSelector getInstance(X509CertSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("cannot create from null selector");
+ }
+ X509CertStoreSelector cs = new X509CertStoreSelector();
+ cs.setAuthorityKeyIdentifier(selector.getAuthorityKeyIdentifier());
+ cs.setBasicConstraints(selector.getBasicConstraints());
+ cs.setCertificate(selector.getCertificate());
+ cs.setCertificateValid(selector.getCertificateValid());
+ cs.setMatchAllSubjectAltNames(selector.getMatchAllSubjectAltNames());
+ try
+ {
+ cs.setPathToNames(selector.getPathToNames());
+ cs.setExtendedKeyUsage(selector.getExtendedKeyUsage());
+ //cs.setNameConstraints(selector.getNameConstraints());
+ cs.setPolicy(selector.getPolicy());
+ cs.setSubjectPublicKeyAlgID(selector.getSubjectPublicKeyAlgID());
+ cs.setSubject(selector.getSubjectAsBytes());
+ cs.setIssuer(selector.getIssuerAsBytes());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error in passed in selector: " + e);
+ }
+ cs.setKeyUsage(selector.getKeyUsage());
+ cs.setPrivateKeyValid(selector.getPrivateKeyValid());
+ cs.setSerialNumber(selector.getSerialNumber());
+ cs.setSubjectKeyIdentifier(selector.getSubjectKeyIdentifier());
+ cs.setSubjectPublicKey(selector.getSubjectPublicKey());
+ return cs;
+ }
+
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java b/prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java
new file mode 100644
index 00000000..93ec8b63
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/X509Util.java
@@ -0,0 +1,397 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+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.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jce.X509Principal;
+import org.spongycastle.util.Strings;
+
+class X509Util
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+ // The parameters field SHALL be NULL for RSA based signature algorithms.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+
+ //
+ // RFC 4491
+ //
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+
+ //
+ // explicit params
+ //
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, new DERNull());
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, new DERNull());
+ params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, new DERNull());
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, new DERNull());
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, new DERNull());
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ static ASN1ObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (ASN1ObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new ASN1ObjectIdentifier(algorithmName);
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ ASN1ObjectIdentifier sigOid,
+ String algorithmName)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (params.containsKey(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ return new AlgorithmIdentifier(sigOid, new DERNull());
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm);
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm,
+ String provider)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ if (provider != null)
+ {
+ return Signature.getInstance(algorithm, provider);
+ }
+ else
+ {
+ return Signature.getInstance(algorithm);
+ }
+ }
+
+ static byte[] calculateSignature(
+ ASN1ObjectIdentifier sigOid,
+ String sigName,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static byte[] calculateSignature(
+ ASN1ObjectIdentifier sigOid,
+ String sigName,
+ String provider,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName, provider);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ 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.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm,
+ Provider prov)
+ throws NoSuchAlgorithmException
+ {
+ algorithm = Strings.toUpperCase(algorithm);
+
+ String alias;
+
+ while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
+ {
+ algorithm = alias;
+ }
+
+ String className = prov.getProperty(baseName + "." + algorithm);
+
+ if (className != null)
+ {
+ try
+ {
+ Class cls;
+ ClassLoader clsLoader = prov.getClass().getClassLoader();
+
+ if (clsLoader != null)
+ {
+ cls = clsLoader.loadClass(className);
+ }
+ else
+ {
+ cls = Class.forName(className);
+ }
+
+ return new Implementation(cls.newInstance(), prov);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!");
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!");
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName());
+ }
+
+ /**
+ * return an implementation for a given algorithm/provider.
+ * If the provider is null, we grab the first avalaible who has the required algorithm.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ Provider[] prov = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != prov.length; i++)
+ {
+ //
+ // try case insensitive
+ //
+ Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]);
+ if (imp != null)
+ {
+ return imp;
+ }
+
+ try
+ {
+ imp = getImplementation(baseName, algorithm, prov[i]);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // continue
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm);
+ }
+
+ static Provider getProvider(String provider)
+ throws NoSuchProviderException
+ {
+ Provider prov = Security.getProvider(provider);
+
+ if (prov == null)
+ {
+ throw new NoSuchProviderException("Provider " + provider + " not found");
+ }
+
+ return prov;
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java b/prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java
new file mode 100644
index 00000000..d038b5cf
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/X509V1CertificateGenerator.java
@@ -0,0 +1,341 @@
+package org.spongycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ * @deprecated use org.spongycastle.cert.X509v1CertificateBuilder.
+ */
+public class X509V1CertificateGenerator
+{
+ private V1TBSCertificateGenerator tbsGen;
+ private ASN1ObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ new ByteArrayInputStream(key.getEncoded())).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC" and the passed in source of randomness
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider and the passed in source of randomness
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateEncodingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ try
+ {
+ return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java b/prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java
new file mode 100644
index 00000000..8da36afb
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/X509V2CRLGenerator.java
@@ -0,0 +1,430 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.CertificateList;
+import org.spongycastle.asn1.x509.Extensions;
+import org.spongycastle.asn1.x509.TBSCertList;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V2TBSCertListGenerator;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CRLObject;
+
+/**
+ * class to produce an X.509 Version 2 CRL.
+ * @deprecated use org.spongycastle.cert.X509v2CRLBuilder.
+ */
+public class X509V2CRLGenerator
+{
+ private V2TBSCertListGenerator tbsGen;
+ private ASN1ObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V2CRLGenerator()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V2TBSCertListGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setThisUpdate(
+ Date date)
+ {
+ tbsGen.setThisUpdate(new Time(date));
+ }
+
+ public void setNextUpdate(
+ Date date)
+ {
+ tbsGen.setNextUpdate(new Time(date));
+ }
+
+ /**
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason);
+ }
+
+ /**
+ * Add a CRL entry with an Invalidity Date extension as well as a CRLReason extension.
+ * Reason being as indicated by CRLReason, i.e. CRLReason.keyCompromise
+ * or 0 if CRLReason is not to be used
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason, Date invalidityDate)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), reason, new ASN1GeneralizedTime(invalidityDate));
+ }
+
+ /**
+ * Add a CRL entry with extensions.
+ **/
+ public void addCRLEntry(BigInteger userCertificate, Date revocationDate, X509Extensions extensions)
+ {
+ tbsGen.addCRLEntry(new ASN1Integer(userCertificate), new Time(revocationDate), Extensions.getInstance(extensions));
+ }
+
+ /**
+ * Add the CRLEntry objects contained in a previous CRL.
+ *
+ * @param other the X509CRL to source the other entries from.
+ */
+ public void addCRL(X509CRL other)
+ throws CRLException
+ {
+ Set revocations = other.getRevokedCertificates();
+
+ if (revocations != null)
+ {
+ Iterator it = revocations.iterator();
+ while (it.hasNext())
+ {
+ X509CRLEntry entry = (X509CRLEntry)it.next();
+
+ ASN1InputStream aIn = new ASN1InputStream(entry.getEncoded());
+
+ try
+ {
+ tbsGen.addCRLEntry(ASN1Sequence.getInstance(aIn.readObject()));
+ }
+ catch (IOException e)
+ {
+ throw new CRLException("exception processing encoding of CRL: " + e.toString());
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 0)
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider "SC" and an user defined SecureRandom object as
+ * source of randomness.
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509CRL(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509CRL(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509CRL generateX509CRL(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject
+ * using the default provider and an user defined SecureRandom object as
+ * source of randomness.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 CRL, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509CRL generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CRLException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertList tbsCrl = generateCertList();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCrl);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCRLException("cannot generate CRL encoding", e);
+ }
+
+ return generateJcaObject(tbsCrl, signature);
+ }
+
+ private TBSCertList generateCertList()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertList();
+ }
+
+ private X509CRL generateJcaObject(TBSCertList tbsCrl, byte[] signature)
+ throws CRLException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCrl);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CRLObject(new CertificateList(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+
+ private static class ExtCRLException
+ extends CRLException
+ {
+ Throwable cause;
+
+ ExtCRLException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java b/prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java
new file mode 100644
index 00000000..e58310e2
--- /dev/null
+++ b/prov/src/main/jdk1.3/org/spongycastle/x509/X509V3CertificateGenerator.java
@@ -0,0 +1,491 @@
+package org.spongycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.TBSCertificate;
+import org.spongycastle.asn1.x509.Time;
+import org.spongycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.X509ExtensionsGenerator;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.provider.X509CertificateObject;
+import org.spongycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ * @deprecated use org.spongycastle.cert.X509v3CertificateBuilder.
+ */
+public class X509V3CertificateGenerator
+{
+ private V3TBSCertificateGenerator tbsGen;
+ private ASN1ObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * Set the subject unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setSubjectUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID));
+ }
+
+ /**
+ * Set the issuer unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setIssuerUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID));
+ }
+
+ private DERBitString booleanToBitString(boolean[] id)
+ {
+ byte[] bytes = new byte[(id.length + 7) / 8];
+
+ for (int i = 0; i != id.length; i++)
+ {
+ bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;
+ }
+
+ int pad = id.length % 8;
+
+ if (pad == 0)
+ {
+ return new DERBitString(bytes);
+ }
+ else
+ {
+ return new DERBitString(bytes, 8 - pad);
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new ASN1ObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ String oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extValue = cert.getExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ this.addExtension(oid, critical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateParsingException(e.toString());
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ this.copyAndAddExtension(oid.getId(), critical, cert);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC".
+ * @deprecated use generate(key, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "SC", and the passed in source of randomness
+ * (if required).
+ * @deprecated use generate(key, random, "SC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "SC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider, and the passed in source of randomness
+ * (if required).
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "SC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private TBSCertificate generateTbsCert()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertificate();
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateParsingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}