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.4/org/spongycastle')
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java385
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java376
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java317
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java200
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java259
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java355
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java359
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java454
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java128
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java144
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java219
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java299
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java217
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java509
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java405
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java128
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java220
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java1637
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jce/interfaces/ECKey.java22
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java166
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java1439
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/jce/provider/X509SignatureUtil.java125
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/x509/X509CRLStoreSelector.java330
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/x509/X509CertStoreSelector.java86
-rw-r--r--prov/src/main/jdk1.4/org/spongycastle/x509/util/LDAPStoreHelper.java1118
25 files changed, 9897 insertions, 0 deletions
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
new file mode 100644
index 00000000..5c91202b
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -0,0 +1,385 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.sec.ECPrivateKeyStructure;
+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.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECPrivateKey
+ implements ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+ private transient DERBitString publicKey;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCECPrivateKey()
+ {
+ }
+
+ BCECPrivateKey(
+ ECPrivateKey key,
+ ProviderConfiguration configuration)
+ {
+ this.d = key.getD();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getD();
+ this.ecSpec = spec.getParams();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECPublicKey pubKey,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ BCECPrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.publicKey = key.publicKey;
+ this.attrCarrier = key.attrCarrier;
+ this.configuration = key.configuration;
+ }
+
+ BCECPrivateKey(
+ PrivateKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+
+ populateFromPrivKeyInfo(info);
+ }
+
+ BCECPrivateKey(
+ String algorithm,
+ PrivateKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+ populateFromPrivKeyInfo(info);
+ this.algorithm = algorithm;
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+
+ if (info.getPrivateKey() instanceof ASN1Integer)
+ {
+ ASN1Integer derD = ASN1Integer.getInstance(info.getPrivateKey());
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)info.getPrivateKey());
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ X962Parameters params = null;
+
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECPoint pG = p.getG().normalize();
+ ECPoint g = pG.getCurve().createPoint(pG.getAffineXCoord().toBigInteger(), pG.getAffineYCoord().toBigInteger());
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(),
+ g,
+ p.getN(),
+ p.getH(),
+ p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ ECPrivateKeyStructure keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), params);
+ }
+
+ try
+ {
+ if (algorithm.equals("ECGOST3410"))
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), keyStructure);
+ }
+ else
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
+ }
+
+ return KeyUtil.getEncodedPrivateKeyInfo(info);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ 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 void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPrivateKey))
+ {
+ return false;
+ }
+
+ BCECPrivateKey other = (BCECPrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private DERBitString getPublicKeyDetails(BCECPublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
new file mode 100644
index 00000000..8f704ddc
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -0,0 +1,376 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+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.X9ECPoint;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECPublicKey
+ implements ECPublicKey, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient org.spongycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+
+ public BCECPublicKey(
+ String algorithm,
+ BCECPublicKey key
+ )
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.configuration = key.configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = spec.getQ();
+ this.configuration = configuration;
+
+ if (spec.getParams() != null)
+ {
+ this.ecSpec = spec.getParams();
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ BCECPublicKey(
+ ECPublicKey key,
+ ProviderConfiguration configuration)
+ {
+ this.q = key.getQ();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ this.configuration = configuration;
+ }
+
+ BCECPublicKey(
+ String algorithm,
+ ECPoint q,
+ ECParameterSpec ecSpec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = q;
+ this.ecSpec = ecSpec;
+ this.configuration = configuration;
+ }
+
+ BCECPublicKey(
+ SubjectPublicKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+
+ populateFromPubKeyInfo(info);
+ }
+
+ BCECPublicKey(
+ String algorithm,
+ SubjectPublicKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.configuration = configuration;
+ populateFromPubKeyInfo(info);
+ this.algorithm = algorithm;
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ ECCurve curve;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve();
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ SubjectPublicKeyInfo info;
+
+ X962Parameters params = null;
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ if (curveOid == null)
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveParameterSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression);
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(), generator, p.getN(), p.getH(), p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ECPoint point = curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression);
+ ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point));
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.getQ().getX().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.getQ().getY().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPublicKey))
+ {
+ return false;
+ }
+
+ BCECPublicKey other = (BCECPublicKey)o;
+
+ return getQ().equals(other.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
new file mode 100644
index 00000000..27c2eed1
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -0,0 +1,317 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.crypto.BasicAgreement;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DerivationFunction;
+import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
+import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
+import org.spongycastle.crypto.agreement.ECMQVBasicAgreement;
+import org.spongycastle.crypto.agreement.kdf.DHKDFParameters;
+import org.spongycastle.crypto.agreement.kdf.ECDHKEKGenerator;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.crypto.params.MQVPrivateParameters;
+import org.spongycastle.crypto.params.MQVPublicParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.MQVPrivateKey;
+import org.spongycastle.jce.interfaces.MQVPublicKey;
+import org.spongycastle.util.Integers;
+
+/**
+ * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+ * both the simple one, and the simple one with cofactors are supported.
+ *
+ * Also, MQV key agreement per SEC-1
+ */
+public class KeyAgreementSpi
+ extends javax.crypto.KeyAgreementSpi
+{
+ private static final X9IntegerConverter converter = new X9IntegerConverter();
+ private static final Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ Integer i128 = Integers.valueOf(128);
+ Integer i192 = Integers.valueOf(192);
+ Integer i256 = Integers.valueOf(256);
+
+ algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
+ algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
+ algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
+ algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
+ algorithms.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
+ }
+
+ private String kaAlgorithm;
+ private BigInteger result;
+ private ECDomainParameters parameters;
+ private BasicAgreement agreement;
+ private DerivationFunction kdf;
+
+ private byte[] bigIntToBytes(
+ BigInteger r)
+ {
+ return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
+ }
+
+ protected KeyAgreementSpi(
+ String kaAlgorithm,
+ BasicAgreement agreement,
+ DerivationFunction kdf)
+ {
+ this.kaAlgorithm = kaAlgorithm;
+ this.agreement = agreement;
+ this.kdf = kdf;
+ }
+
+ protected Key engineDoPhase(
+ Key key,
+ boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (parameters == null)
+ {
+ throw new IllegalStateException(kaAlgorithm + " not initialised.");
+ }
+
+ if (!lastPhase)
+ {
+ throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
+ }
+
+ CipherParameters pubKey;
+ if (agreement instanceof ECMQVBasicAgreement)
+ {
+ if (!(key instanceof MQVPublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(MQVPublicKey.class) + " for doPhase");
+ }
+
+ MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+ ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+ ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+
+ pubKey = new MQVPublicParameters(staticKey, ephemKey);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+ else
+ {
+ if (!(key instanceof ECPublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPublicKey.class) + " for doPhase");
+ }
+
+ pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+
+ result = agreement.calculateAgreement(pubKey);
+
+ return null;
+ }
+
+ protected byte[] engineGenerateSecret()
+ throws IllegalStateException
+ {
+ if (kdf != null)
+ {
+ throw new UnsupportedOperationException(
+ "KDF can only be used when algorithm is known");
+ }
+
+ return bigIntToBytes(result);
+ }
+
+ protected int engineGenerateSecret(
+ byte[] sharedSecret,
+ int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ byte[] secret = engineGenerateSecret();
+
+ if (sharedSecret.length - offset < secret.length)
+ {
+ throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
+ }
+
+ System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
+
+ return secret.length;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ byte[] secret = bigIntToBytes(result);
+
+ if (kdf != null)
+ {
+ if (!algorithms.containsKey(algorithm))
+ {
+ throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
+ }
+
+ int keySize = ((Integer)algorithms.get(algorithm)).intValue();
+
+ DHKDFParameters params = new DHKDFParameters(new ASN1ObjectIdentifier(algorithm), keySize, secret);
+
+ byte[] keyBytes = new byte[keySize / 8];
+ kdf.init(params);
+ kdf.generateBytes(keyBytes, 0, keyBytes.length);
+ secret = keyBytes;
+ }
+ else
+ {
+ // TODO Should we be ensuring the key is the right length?
+ }
+
+ return new SecretKeySpec(secret, algorithm);
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initFromKey(key);
+ }
+
+ protected void engineInit(
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ initFromKey(key);
+ }
+
+ private void initFromKey(Key key)
+ throws InvalidKeyException
+ {
+ if (agreement instanceof ECMQVBasicAgreement)
+ {
+ if (!(key instanceof MQVPrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+ }
+
+ MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+ ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+ ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+ ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+ ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+
+ ECPublicKeyParameters ephemPubKey = null;
+ if (mqvPrivKey.getEphemeralPublicKey() != null)
+ {
+ ephemPubKey = (ECPublicKeyParameters)
+ ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+ }
+
+ MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+ this.parameters = staticPrivKey.getParameters();
+
+ // TODO Validate that all the keys are using the same parameters?
+
+ agreement.init(localParams);
+ }
+ else
+ {
+ if (!(key instanceof ECPrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPrivateKey.class) + " for initialisation");
+ }
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+ this.parameters = privKey.getParameters();
+
+ agreement.init(privKey);
+ }
+ }
+
+ private static String getSimpleName(Class clazz)
+ {
+ String fullName = clazz.getName();
+
+ return fullName.substring(fullName.lastIndexOf('.') + 1);
+ }
+
+ public static class DH
+ extends KeyAgreementSpi
+ {
+ public DH()
+ {
+ super("ECDH", new ECDHBasicAgreement(), null);
+ }
+ }
+
+ public static class DHC
+ extends KeyAgreementSpi
+ {
+ public DHC()
+ {
+ super("ECDHC", new ECDHCBasicAgreement(), null);
+ }
+ }
+
+ public static class MQV
+ extends KeyAgreementSpi
+ {
+ public MQV()
+ {
+ super("ECMQV", new ECMQVBasicAgreement(), null);
+ }
+ }
+
+ public static class DHwithSHA1KDF
+ extends KeyAgreementSpi
+ {
+ public DHwithSHA1KDF()
+ {
+ super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ }
+ }
+
+ public static class MQVwithSHA1KDF
+ extends KeyAgreementSpi
+ {
+ public MQVwithSHA1KDF()
+ {
+ super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
new file mode 100644
index 00000000..76c11e0b
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
@@ -0,0 +1,200 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ KeyFactorySpi(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ return new BCECPublicKey((ECPublicKey)key, configuration);
+ }
+ else if (key instanceof ECPrivateKey)
+ {
+ return new BCECPrivateKey((ECPrivateKey)key, configuration);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = configuration.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), implicitSpec);
+ }
+ }
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPrivateKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPublicKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public static class EC
+ extends KeyFactorySpi
+ {
+ public EC()
+ {
+ super("EC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDSA
+ extends KeyFactorySpi
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECGOST3410
+ extends KeyFactorySpi
+ {
+ public ECGOST3410()
+ {
+ super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDH
+ extends KeyFactorySpi
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends KeyFactorySpi
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends KeyFactorySpi
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
new file mode 100644
index 00000000..8d74dd59
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -0,0 +1,259 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.sec.SECNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.asn1.x9.X962NamedCurves;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jce.ECNamedCurveTable;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.util.Integers;
+
+public abstract class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ public KeyPairGeneratorSpi(String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ public static class EC
+ extends KeyPairGeneratorSpi
+ {
+ ECKeyGenerationParameters param;
+ ECKeyPairGenerator engine = new ECKeyPairGenerator();
+ ECParameterSpec ecParams = null;
+ int strength = 239;
+ int certainty = 50;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ static private Hashtable ecParameters;
+
+ static {
+ ecParameters = new Hashtable();
+
+ ecParameters.put(Integers.valueOf(192),
+ ECNamedCurveTable.getParameterSpec("prime192v1"));
+ ecParameters.put(Integers.valueOf(239),
+ ECNamedCurveTable.getParameterSpec("prime239v1"));
+ ecParameters.put(Integers.valueOf(256),
+ ECNamedCurveTable.getParameterSpec("prime256v1"));
+ }
+
+ public EC()
+ {
+ super("EC");
+ this.algorithm = "EC";
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ public EC(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ super(algorithm);
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ this.ecParams = (ECParameterSpec)ecParameters.get(Integers.valueOf(strength));
+
+ if (ecParams != null)
+ {
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = (ECParameterSpec)params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+
+ X9ECParameters ecP = X962NamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ ecP = SECNamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ ecP = NISTNamedCurves.getByName(curveName);
+ }
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.getByName(curveName);
+ }
+ if (ecP == null)
+ {
+ // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+ try
+ {
+ ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
+ ecP = X962NamedCurves.getByOID(oid);
+ if (ecP == null)
+ {
+ ecP = SECNamedCurves.getByOID(oid);
+ }
+ if (ecP == null)
+ {
+ ecP = NISTNamedCurves.getByOID(oid);
+ }
+ if (ecP == null)
+ {
+ ecP = TeleTrusTNamedCurves.getByOID(oid);
+ }
+ if (ecP == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+ }
+ }
+
+ this.ecParams = new ECNamedCurveParameterSpec(
+ curveName,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ null); // ecP.getSeed()); Work-around JDK bug -- it won't look up named curves properly if seed is present
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = configuration.getEcImplicitlyCa();
+ this.ecParams = (ECParameterSpec)params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("EC Key Pair Generator not initialised");
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams == null)
+ {
+ return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
+ new BCECPrivateKey(algorithm, priv, configuration));
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+ BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+
+ return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+ }
+ }
+ }
+
+ public static class ECDSA
+ extends EC
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDH
+ extends EC
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends EC
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends EC
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
new file mode 100644
index 00000000..9d61a76b
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -0,0 +1,355 @@
+package org.spongycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+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.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.ECDSASigner;
+import org.spongycastle.crypto.signers.ECNRSigner;
+import org.spongycastle.jcajce.provider.asymmetric.util.DSABase;
+import org.spongycastle.jcajce.provider.asymmetric.util.DSAEncoder;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class SignatureSpi
+ extends DSABase
+{
+ SignatureSpi(Digest digest, DSA signer, DSAEncoder encoder)
+ {
+ super("ECDSA", digest, signer, encoder);
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+ }
+
+ digest.reset();
+
+ signer.init(false, param);
+ }
+
+ protected void doEngineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+
+ digest.reset();
+
+ if (random != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, random));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ static public class ecDSA
+ extends SignatureSpi
+ {
+ public ecDSA()
+ {
+ super(new SHA1Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSAnone
+ extends SignatureSpi
+ {
+ public ecDSAnone()
+ {
+ super(new NullDigest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA224
+ extends SignatureSpi
+ {
+ public ecDSA224()
+ {
+ super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA256
+ extends SignatureSpi
+ {
+ public ecDSA256()
+ {
+ super(new SHA256Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA384
+ extends SignatureSpi
+ {
+ public ecDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSA512
+ extends SignatureSpi
+ {
+ public ecDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecDSARipeMD160
+ extends SignatureSpi
+ {
+ public ecDSARipeMD160()
+ {
+ super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR
+ extends SignatureSpi
+ {
+ public ecNR()
+ {
+ super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR224
+ extends SignatureSpi
+ {
+ public ecNR224()
+ {
+ super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR256
+ extends SignatureSpi
+ {
+ public ecNR256()
+ {
+ super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR384
+ extends SignatureSpi
+ {
+ public ecNR384()
+ {
+ super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecNR512
+ extends SignatureSpi
+ {
+ public ecNR512()
+ {
+ super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA
+ extends SignatureSpi
+ {
+ public ecCVCDSA()
+ {
+ super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA224
+ extends SignatureSpi
+ {
+ public ecCVCDSA224()
+ {
+ super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA256
+ extends SignatureSpi
+ {
+ public ecCVCDSA256()
+ {
+ super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA384
+ extends SignatureSpi
+ {
+ public ecCVCDSA384()
+ {
+ super(new SHA384Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ static public class ecCVCDSA512
+ extends SignatureSpi
+ {
+ public ecCVCDSA512()
+ {
+ super(new SHA512Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ }
+ }
+
+ private static class StdDSAEncoder
+ implements DSAEncoder
+ {
+ public byte[] encode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(r));
+ v.add(new ASN1Integer(s));
+
+ return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ }
+
+ public BigInteger[] decode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ BigInteger[] sig = new BigInteger[2];
+
+ sig[0] = ((ASN1Integer)s.getObjectAt(0)).getValue();
+ sig[1] = ((ASN1Integer)s.getObjectAt(1)).getValue();
+
+ return sig;
+ }
+ }
+
+ private static class CVCDSAEncoder
+ implements DSAEncoder
+ {
+ public byte[] encode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ byte[] first = makeUnsigned(r);
+ byte[] second = makeUnsigned(s);
+ byte[] res;
+
+ if (first.length > second.length)
+ {
+ res = new byte[first.length * 2];
+ }
+ else
+ {
+ res = new byte[second.length * 2];
+ }
+
+ System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length);
+ System.arraycopy(second, 0, res, res.length - second.length, second.length);
+
+ return res;
+ }
+
+
+ private byte[] makeUnsigned(BigInteger val)
+ {
+ byte[] res = val.toByteArray();
+
+ if (res[0] == 0)
+ {
+ byte[] tmp = new byte[res.length - 1];
+
+ System.arraycopy(res, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return res;
+ }
+
+ public BigInteger[] decode(
+ byte[] encoding)
+ throws IOException
+ {
+ BigInteger[] sig = new BigInteger[2];
+
+ byte[] first = new byte[encoding.length / 2];
+ byte[] second = new byte[encoding.length / 2];
+
+ System.arraycopy(encoding, 0, first, 0, first.length);
+ System.arraycopy(encoding, first.length, second, 0, second.length);
+
+ sig[0] = new BigInteger(1, first);
+ sig[1] = new BigInteger(1, second);
+
+ return sig;
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
new file mode 100644
index 00000000..d322a172
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java
@@ -0,0 +1,359 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.sec.ECPrivateKeyStructure;
+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.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECGOST3410PrivateKey
+ implements ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ private String algorithm = "ECGOST3410";
+ private boolean withCompression;
+
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient DERBitString publicKey;
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCECGOST3410PrivateKey()
+ {
+ }
+
+ BCECGOST3410PrivateKey(
+ ECPrivateKey key)
+ {
+ this.d = key.getD();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ }
+
+ public BCECGOST3410PrivateKey(
+ ECPrivateKeySpec spec)
+ {
+ this.d = spec.getD();
+ this.ecSpec = spec.getParams();
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECGOST3410PublicKey pubKey,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ }
+
+ public BCECGOST3410PrivateKey(
+ String algorithm,
+ BCECGOST3410PrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.publicKey = key.publicKey;
+ this.attrCarrier = key.attrCarrier;
+ }
+
+ BCECGOST3410PrivateKey(
+ PrivateKeyInfo info)
+ {
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ ECDomainParameters ecP = ECGOST3410NamedCurves.getByOID(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+
+ if (info.getPrivateKey() instanceof ASN1Integer)
+ {
+ ASN1Integer derD = ASN1Integer.getInstance(info.getPrivateKey());
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)info.getPrivateKey());
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ X962Parameters params = null;
+
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECPoint pG = p.getG().normalize();
+ ECPoint g = pG.getCurve().createPoint(pG.getAffineXCoord().toBigInteger(), pG.getAffineYCoord().toBigInteger());
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(),
+ g,
+ p.getN(),
+ p.getH(),
+ p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ ECPrivateKeyStructure keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getD(), params);
+ }
+
+ try
+ {
+ if (algorithm.equals("ECGOST3410"))
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), keyStructure);
+ }
+ else
+ {
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), keyStructure);
+ }
+
+ return KeyUtil.getEncodedPrivateKeyInfo(info);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ 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 void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECGOST3410PrivateKey))
+ {
+ return false;
+ }
+
+ BCECGOST3410PrivateKey other = (BCECGOST3410PrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private DERBitString getPublicKeyDetails(BCECGOST3410PublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
new file mode 100644
index 00000000..75e6e115
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java
@@ -0,0 +1,454 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+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.X9ECPoint;
+import org.spongycastle.asn1.x9.X9IntegerConverter;
+import org.spongycastle.asn1.x9.X9ObjectIdentifiers;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jce.ECGOST3410NamedCurveTable;
+import org.spongycastle.jce.interfaces.ECPointEncoder;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+import org.spongycastle.math.ec.ECCurve;
+import org.spongycastle.math.ec.ECPoint;
+
+public class BCECGOST3410PublicKey
+ implements ECPublicKey, ECPointEncoder
+{
+ private String algorithm = "ECGOST3410";
+ private boolean withCompression;
+
+ private transient org.spongycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient GOST3410PublicKeyAlgParameters gostParams;
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ BCECGOST3410PublicKey key)
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.gostParams = key.gostParams;
+ }
+
+ public BCECGOST3410PublicKey(
+ ECPublicKeySpec spec)
+ {
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null)
+ {
+ this.ecSpec = spec.getParams();
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.spongycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ this.ecSpec = new ECParameterSpec(
+ dp.getCurve(),
+ dp.getG(),
+ dp.getN(),
+ dp.getH(),
+ dp.getSeed());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public BCECGOST3410PublicKey(
+ String algorithm,
+ ECPublicKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ }
+
+ BCECGOST3410PublicKey(
+ ECPublicKey key)
+ {
+ this.q = key.getQ();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParameters();
+ }
+
+ BCECGOST3410PublicKey(
+ String algorithm,
+ ECPoint q,
+ ECParameterSpec ecSpec)
+ {
+ this.algorithm = algorithm;
+ this.q = q;
+ this.ecSpec = ecSpec;
+ }
+
+ BCECGOST3410PublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPubKeyInfo(info);
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ DERBitString bits = info.getPublicKeyData();
+ ASN1OctetString key;
+ this.algorithm = "ECGOST3410";
+
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+
+ byte[] keyEnc = key.getOctets();
+ byte[] x = new byte[32];
+ byte[] y = new byte[32];
+
+ for (int i = 0; i != x.length; i++)
+ {
+ x[i] = keyEnc[32 - 1 - i];
+ }
+
+ for (int i = 0; i != y.length; i++)
+ {
+ y[i] = keyEnc[64 - 1 - i];
+ }
+
+ gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+
+ ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+
+ ecSpec = spec;
+
+ this.q = spec.getCurve().createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+ }
+ else
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters());
+ ECCurve curve;
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ ecSpec = new ECNamedCurveParameterSpec(
+ ECUtil.getCurveName(oid),
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ curve = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve();
+ }
+ else
+ {
+ X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
+ ecSpec = new ECParameterSpec(
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ curve = ((ECParameterSpec)ecSpec).getCurve();
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString)ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ SubjectPublicKeyInfo info;
+
+ if (algorithm.equals("ECGOST3410"))
+ {
+ ASN1Encodable params = null;
+ if (gostParams != null)
+ {
+ params = gostParams;
+ }
+ else if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ params = new GOST3410PublicKeyAlgParameters(
+ ECGOST3410NamedCurves.getOID(((ECNamedCurveParameterSpec)ecSpec).getName()),
+ CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression);
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(), generator, p.getN(), p.getH(), p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECPoint qq = this.getQ();
+ ECPoint point = qq.getCurve().createPoint(qq.getX().toBigInteger(), qq.getY().toBigInteger(), false);
+ ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point));
+
+ BigInteger bX = this.q.getX().toBigInteger();
+ BigInteger bY = this.q.getY().toBigInteger();
+ byte[] encKey = new byte[64];
+
+ byte[] val = bX.toByteArray();
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[i] = val[val.length - 1 - i];
+ }
+
+ val = bY.toByteArray();
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[32 + i] = val[val.length - 1 - i];
+ }
+
+ try
+ {
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ X962Parameters params = null;
+ if (ecSpec instanceof ECNamedCurveParameterSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveParameterSpec)ecSpec).getName());
+
+ if (curveOid == null)
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveParameterSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecSpec;
+
+ ECCurve curve = p.getG().getCurve();
+ ECPoint generator = curve.createPoint(p.getG().getX().toBigInteger(), p.getG().getY().toBigInteger(), withCompression);
+
+ X9ECParameters ecP = new X9ECParameters(
+ p.getCurve(), generator, p.getN(), p.getH(), p.getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ECPoint point = curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression);
+ ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(point));
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public ECParameterSpec getParameters()
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ public org.spongycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.spongycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.spongycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+ }
+ else
+ {
+ return new org.spongycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+ }
+ }
+
+ return q;
+ }
+
+ public org.spongycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.getQ().getX().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.getQ().getY().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return (ECParameterSpec)ecSpec;
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECGOST3410PublicKey))
+ {
+ return false;
+ }
+
+ BCECGOST3410PublicKey other = (BCECGOST3410PublicKey)o;
+
+ return getQ().equals(other.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
new file mode 100644
index 00000000..36847af2
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java
@@ -0,0 +1,128 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECParameterSpec;
+import org.spongycastle.jce.spec.ECPrivateKeySpec;
+import org.spongycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPublicKeySpec(k.getQ(), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.spongycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), k.getParameters());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.spongycastle.jce.spec.ECPrivateKeySpec(k.getD(), implicitSpec);
+ }
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCECGOST3410PrivateKey((ECPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECGOST3410PublicKey((ECPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ return new BCECGOST3410PrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ {
+ return new BCECGOST3410PublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
new file mode 100644
index 00000000..f950260e
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java
@@ -0,0 +1,144 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.ECKeyPairGenerator;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECKeyGenerationParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ ECParameterSpec ecParams = null;
+ ECKeyPairGenerator engine = new ECKeyPairGenerator();
+
+ String algorithm = "ECGOST3410";
+ ECKeyGenerationParameters param;
+ int strength = 239;
+ SecureRandom random = null;
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("ECGOST3410");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+
+ if (ecParams != null)
+ {
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = p;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+
+ ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
+ }
+
+ this.ecParams = new ECNamedCurveParameterSpec(
+ curveName,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(ecParams.getCurve(), ecParams.getG(), ecParams.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ this.ecParams = null;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec: " + params.getClass().getName());
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ throw new IllegalStateException("EC Key Pair Generator not initialised");
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams == null)
+ {
+ return new KeyPair(new BCECGOST3410PublicKey(algorithm, pub),
+ new BCECGOST3410PrivateKey(algorithm, priv));
+ }
+ else
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+
+ BCECGOST3410PublicKey pubKey = new BCECGOST3410PublicKey(algorithm, pub, p);
+ return new KeyPair(pubKey,
+ new BCECGOST3410PrivateKey(algorithm, priv, pubKey, p));
+ }
+ }
+}
+
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
new file mode 100644
index 00000000..c3660fb1
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java
@@ -0,0 +1,219 @@
+package org.spongycastle.jcajce.provider.asymmetric.ecgost;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.GOST3411Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.crypto.signers.ECGOST3410Signer;
+import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
+import org.spongycastle.jce.interfaces.ECKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.interfaces.GOST3410Key;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.util.GOST3410Util;
+
+public class SignatureSpi
+ extends java.security.Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+
+ public SignatureSpi()
+ {
+ super("ECGOST3410");
+ this.digest = new GOST3411Digest();
+ this.signer = new ECGOST3410Signer();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else if (publicKey instanceof GOST3410Key)
+ {
+ param = GOST3410Util.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+ }
+
+ digest.reset();
+
+ if (appRandom != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, appRandom));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] sigBytes = new byte[64];
+ BigInteger[] sig = signer.generateSignature(hash);
+ byte[] r = sig[0].toByteArray();
+ byte[] s = sig[1].toByteArray();
+
+ if (s[0] != 0)
+ {
+ System.arraycopy(s, 0, sigBytes, 32 - s.length, s.length);
+ }
+ else
+ {
+ System.arraycopy(s, 1, sigBytes, 32 - (s.length - 1), s.length - 1);
+ }
+
+ if (r[0] != 0)
+ {
+ System.arraycopy(r, 0, sigBytes, 64 - r.length, r.length);
+ }
+ else
+ {
+ System.arraycopy(r, 1, sigBytes, 64 - (r.length - 1), r.length - 1);
+ }
+
+ return sigBytes;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ byte[] r = new byte[32];
+ byte[] s = new byte[32];
+
+ System.arraycopy(sigBytes, 0, s, 0, 32);
+
+ System.arraycopy(sigBytes, 32, r, 0, 32);
+
+ sig = new BigInteger[2];
+ sig[0] = new BigInteger(1, r);
+ sig[1] = new BigInteger(1, s);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
new file mode 100644
index 00000000..7a6e69d3
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/elgamal/CipherSpi.java
@@ -0,0 +1,299 @@
+package org.spongycastle.jcajce.provider.asymmetric.elgamal;
+
+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.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.interfaces.DHKey;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.BufferedAsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.encodings.ISO9796d1Encoding;
+import org.spongycastle.crypto.encodings.OAEPEncoding;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.ElGamalEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.spongycastle.jce.interfaces.ElGamalKey;
+import org.spongycastle.jce.interfaces.ElGamalPrivateKey;
+import org.spongycastle.jce.interfaces.ElGamalPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private BufferedAsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = new BufferedAsymmetricBlockCipher(engine);
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return cipher.getInputBlockSize();
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof ElGamalKey)
+ {
+ ElGamalKey k = (ElGamalKey)key;
+
+ return k.getParameters().getP().bitLength();
+ }
+ else if (key instanceof DHKey)
+ {
+ DHKey k = (DHKey)key;
+
+ return k.getParams().getP().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an ElGamal key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return cipher.getOutputBlockSize();
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new ElGamalEngine());
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new PKCS1Encoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("ISO9796-1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new ISO9796d1Encoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new OAEPEncoding(new ElGamalEngine()));
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING"))
+ {
+ cipher = new BufferedAsymmetricBlockCipher(new OAEPEncoding(new ElGamalEngine()));
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with ElGamal.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (params == null)
+ {
+ if (key instanceof ElGamalPublicKey)
+ {
+ param = ElGamalUtil.generatePublicKeyParameter((PublicKey)key);
+ }
+ else if (key instanceof ElGamalPrivateKey)
+ {
+ param = ElGamalUtil.generatePrivateKeyParameter((PrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to ElGamal");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ switch (opmode)
+ {
+ case javax.crypto.Cipher.ENCRYPT_MODE:
+ case javax.crypto.Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case javax.crypto.Cipher.DECRYPT_MODE:
+ case javax.crypto.Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to ElGamal");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameters in ElGamal");
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ cipher.processBytes(input, inputOffset, inputLen);
+ try
+ {
+ return cipher.doFinal();
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ byte[] out;
+
+ cipher.processBytes(input, inputOffset, inputLen);
+
+ try
+ {
+ out = cipher.doFinal();
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new ElGamalEngine());
+ }
+ }
+
+ static public class PKCS1v1_5Padding
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding()
+ {
+ super(new PKCS1Encoding(new ElGamalEngine()));
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 00000000..eb66bcf3
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,217 @@
+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 java.security.spec.PSSParameterSpec;
+
+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 (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
+ {
+ PSSParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+ */
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ PSSParameterSpec pssSpec = (PSSParameterSpec)currentSpec;
+ RSASSAPSSparams pssP = new RSASSAPSSparams(RSASSAPSSparams.DEFAULT_HASH_ALGORITHM, RSASSAPSSparams.DEFAULT_MASK_GEN_FUNCTION, new ASN1Integer(pssSpec.getSaltLength()), 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
+ {
+ if (paramSpec == PSSParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PSSParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+ }
+
+ this.currentSpec = (PSSParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+ currentSpec = new PSSParameterSpec(
+ pssP.getSaltLength().intValue());
+ }
+ 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 (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.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
new file mode 100644
index 00000000..7609b4a7
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -0,0 +1,509 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+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.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.digests.MD5Digest;
+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.encodings.ISO9796d1Encoding;
+import org.spongycastle.crypto.encodings.OAEPEncoding;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+ private boolean publicKeyOnly = false;
+ private boolean privateKeyOnly = false;
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = engine;
+ }
+
+ public CipherSpi(
+ boolean publicKeyOnly,
+ boolean privateKeyOnly,
+ AsymmetricBlockCipher engine)
+ {
+ this.publicKeyOnly = publicKeyOnly;
+ this.privateKeyOnly = privateKeyOnly;
+ cipher = engine;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ try
+ {
+ return cipher.getInputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof RSAPrivateKey)
+ {
+ RSAPrivateKey k = (RSAPrivateKey)key;
+
+ return k.getModulus().bitLength();
+ }
+ else if (key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return k.getModulus().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an RSA key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ try
+ {
+ return cipher.getOutputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ if (md.equals("1"))
+ {
+ privateKeyOnly = true;
+ publicKeyOnly = false;
+ return;
+ }
+ else if (md.equals("2"))
+ {
+ privateKeyOnly = false;
+ publicKeyOnly = true;
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new RSABlindedEngine();
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new PKCS1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("ISO9796-1PADDING"))
+ {
+ cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA224Digest());
+ }
+ else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA256Digest());
+ }
+ else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA384Digest());
+ }
+ else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new SHA512Digest());
+ }
+ else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+ {
+ cipher = new OAEPEncoding(new RSABlindedEngine(), new MD5Digest());
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (params == null)
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ if (privateKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 1 requires RSAPrivateKey");
+ }
+
+ param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateKey)
+ {
+ if (publicKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 2 requires RSAPublicKey");
+ }
+
+ param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to RSA");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if (!(cipher instanceof RSABlindedEngine))
+ {
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+ else
+ {
+ param = new ParametersWithRandom(param, new SecureRandom());
+ }
+ }
+
+ switch (opmode)
+ {
+ case javax.crypto.Cipher.ENCRYPT_MODE:
+ case javax.crypto.Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case javax.crypto.Cipher.DECRYPT_MODE:
+ case javax.crypto.Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to RSA");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ throw new InvalidAlgorithmParameterException("cannot recognise parameters.");
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // this shouldn't happen
+ throw new InvalidKeyException("Eeeek! " + e.toString());
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ byte[] out;
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+ bOut.reset();
+
+ out = cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new RSABlindedEngine());
+ }
+ }
+
+ static public class PKCS1v1_5Padding
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding()
+ {
+ super(new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PrivateOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PrivateOnly()
+ {
+ super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PublicOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PublicOnly()
+ {
+ super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class OAEPPadding
+ extends CipherSpi
+ {
+ public OAEPPadding()
+ {
+ super(new OAEPEncoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class ISO9796d1Padding
+ extends CipherSpi
+ {
+ public ISO9796d1Padding()
+ {
+ super(new ISO9796d1Encoding(new RSABlindedEngine()));
+ }
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
new file mode 100644
index 00000000..23dd0100
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
@@ -0,0 +1,405 @@
+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 java.security.spec.PSSParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+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;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class PSSSignatureSpi
+ extends Signature
+{
+ private AlgorithmParameters engineParams;
+ private PSSParameterSpec paramSpec;
+ private AsymmetricBlockCipher signer;
+ private Digest contentDigest;
+ private Digest mgfDigest;
+ private int saltLength;
+ private byte trailer;
+ private boolean isRaw;
+
+ private org.spongycastle.crypto.signers.PSSSigner pss;
+
+ 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;
+ }
+
+ if (paramSpec != null)
+ {
+ this.saltLength = paramSpec.getSaltLength();
+ }
+ 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;
+ }
+
+ if (paramSpec != null)
+ {
+ this.saltLength = paramSpec.getSaltLength();
+ }
+
+ 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");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(false,
+ RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength);
+ pss.init(true, RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey));
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ pss.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ pss.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ return pss.generateSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new SignatureException(e.getMessage());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ return pss.verifySignature(sigBytes);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ throws InvalidParameterException
+ {
+ if (params instanceof PSSParameterSpec)
+ {
+ PSSParameterSpec newParamSpec = (PSSParameterSpec)params;
+
+ this.engineParams = null;
+ this.paramSpec = newParamSpec;
+ this.saltLength = paramSpec.getSaltLength();
+
+ if (mgfDigest == null)
+ {
+ switch (saltLength)
+ {
+ case 20:
+ this.mgfDigest = new SHA1Digest();
+ break;
+ case 28:
+ this.mgfDigest = new SHA224Digest();
+ break;
+ case 32:
+ this.mgfDigest = new SHA256Digest();
+ break;
+ case 48:
+ this.mgfDigest = new SHA384Digest();
+ break;
+ case 64:
+ this.mgfDigest = new SHA512Digest();
+ break;
+ }
+ setupContentDigest();
+ }
+ }
+ else
+ {
+ throw new InvalidParameterException("Only PSSParameterSpec supported");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("PSS", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(new PSSParameterSpec(saltLength));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ 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");
+ }
+
+ 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.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
new file mode 100644
index 00000000..bdc65b04
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/DSABase.java
@@ -0,0 +1,128 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.DSA;
+import org.spongycastle.crypto.Digest;
+
+public abstract class DSABase
+ extends Signature
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ protected Digest digest;
+ protected DSA signer;
+ protected DSAEncoder encoder;
+
+ protected DSABase(
+ String name,
+ Digest digest,
+ DSA signer,
+ DSAEncoder encoder)
+ {
+ super(name);
+
+ this.digest = digest;
+ this.signer = signer;
+ this.encoder = encoder;
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ doEngineInitSign(privateKey, appRandom);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return encoder.encode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = encoder.decode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected abstract void doEngineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException;
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java
new file mode 100644
index 00000000..8cfba71f
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/asymmetric/util/ECUtil.java
@@ -0,0 +1,220 @@
+package org.spongycastle.jcajce.provider.asymmetric.util;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+import org.spongycastle.asn1.nist.NISTNamedCurves;
+import org.spongycastle.asn1.sec.SECNamedCurves;
+import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.spongycastle.asn1.x9.X962NamedCurves;
+import org.spongycastle.asn1.x9.X9ECParameters;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.jce.interfaces.ECPrivateKey;
+import org.spongycastle.jce.interfaces.ECPublicKey;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+/**
+ * utility class for converting jce/jca ECDSA, ECDH, and ECDHC
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class ECUtil
+{
+ /**
+ * Returns a sorted array of middle terms of the reduction polynomial.
+ * @param k The unsorted array of middle terms of the reduction polynomial
+ * of length 1 or 3.
+ * @return the sorted array of middle terms of the reduction polynomial.
+ * This array always has length 3.
+ */
+ static int[] convertMidTerms(
+ int[] k)
+ {
+ int[] res = new int[3];
+
+ if (k.length == 1)
+ {
+ res[0] = k[0];
+ }
+ else
+ {
+ if (k.length != 3)
+ {
+ throw new IllegalArgumentException("Only Trinomials and pentanomials supported");
+ }
+
+ if (k[0] < k[1] && k[0] < k[2])
+ {
+ res[0] = k[0];
+ if (k[1] < k[2])
+ {
+ res[1] = k[1];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[1];
+ }
+ }
+ else if (k[1] < k[2])
+ {
+ res[0] = k[1];
+ if (k[0] < k[2])
+ {
+ res[1] = k[0];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[0];
+ }
+ }
+ else
+ {
+ res[0] = k[2];
+ if (k[0] < k[1])
+ {
+ res[1] = k[0];
+ res[2] = k[1];
+ }
+ else
+ {
+ res[1] = k[1];
+ res[2] = k[0];
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public static AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new ECPublicKeyParameters(
+ ((BCECPublicKey)k).engineGetQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ else
+ {
+ return new ECPublicKeyParameters(
+ k.getQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ }
+
+ throw new InvalidKeyException("cannot identify EC public key.");
+ }
+
+ public static AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ return new ECPrivateKeyParameters(
+ k.getD(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+
+ throw new InvalidKeyException("can't identify EC private key.");
+ }
+
+ public static ASN1ObjectIdentifier getNamedCurveOid(
+ String name)
+ {
+ ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name);
+
+ if (oid == null)
+ {
+ oid = SECNamedCurves.getOID(name);
+ if (oid == null)
+ {
+ oid = NISTNamedCurves.getOID(name);
+ }
+ if (oid == null)
+ {
+ oid = TeleTrusTNamedCurves.getOID(name);
+ }
+ if (oid == null)
+ {
+ oid = ECGOST3410NamedCurves.getOID(name);
+ }
+ }
+
+ return oid;
+ }
+
+ public static X9ECParameters getNamedCurveByOid(
+ ASN1ObjectIdentifier oid)
+ {
+ X9ECParameters params = X962NamedCurves.getByOID(oid);
+
+ if (params == null)
+ {
+ params = SECNamedCurves.getByOID(oid);
+ if (params == null)
+ {
+ params = NISTNamedCurves.getByOID(oid);
+ }
+ if (params == null)
+ {
+ params = TeleTrusTNamedCurves.getByOID(oid);
+ }
+ }
+
+ return params;
+ }
+
+ public static String getCurveName(
+ ASN1ObjectIdentifier oid)
+ {
+ String name = X962NamedCurves.getName(oid);
+
+ if (name == null)
+ {
+ name = SECNamedCurves.getName(oid);
+ if (name == null)
+ {
+ name = NISTNamedCurves.getName(oid);
+ }
+ if (name == null)
+ {
+ name = TeleTrusTNamedCurves.getName(oid);
+ }
+ if (name == null)
+ {
+ name = ECGOST3410NamedCurves.getName(oid);
+ }
+ }
+
+ return name;
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
new file mode 100644
index 00000000..dbad7772
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -0,0 +1,1637 @@
+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);
+ }
+ 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 = new SubjectPublicKeyInfo(
+ (ASN1Sequence)ASN1Primitive.fromByteArray(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.4/org/spongycastle/jce/interfaces/ECKey.java b/prov/src/main/jdk1.4/org/spongycastle/jce/interfaces/ECKey.java
new file mode 100644
index 00000000..1cee721d
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jce/interfaces/ECKey.java
@@ -0,0 +1,22 @@
+package org.spongycastle.jce.interfaces;
+
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+/**
+ * generic interface for an Elliptic Curve Key.
+ */
+public interface ECKey
+{
+ /**
+ * return a parameter specification representing the EC domain parameters
+ * for the key.
+ * @deprecated this method vanises in JDK 1.5. Use getParameters().
+ */
+ public ECParameterSpec getParams();
+
+ /**
+ * return a parameter specification representing the EC domain parameters
+ * for the key.
+ */
+ public ECParameterSpec getParameters();
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java b/prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
new file mode 100644
index 00000000..17adb311
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -0,0 +1,166 @@
+package org.spongycastle.jce.provider;
+
+import java.security.Permission;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import org.spongycastle.jce.spec.ECParameterSpec;
+
+class BouncyCastleProviderConfiguration
+ implements ProviderConfiguration
+{
+ private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+ private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
+ private static Permission BC_DH_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS);
+ private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS);
+
+ private ThreadLocal ecThreadSpec = new ThreadLocal();
+ private ThreadLocal dhThreadSpec = new ThreadLocal();
+
+ private volatile ECParameterSpec ecImplicitCaParams;
+ private volatile Object dhDefaultParams;
+
+ 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);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ curveSpec = (ECParameterSpec)parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid ECParameterSpec");
+ }
+
+ if (curveSpec == null)
+ {
+ ecThreadSpec.set(null);
+ }
+ else
+ {
+ ecThreadSpec.set(curveSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_PERMISSION);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ else // assume java.security.spec
+ {
+ throw new IllegalArgumentException("not a valid ECParameterSpec");
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS))
+ {
+ Object dhSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_LOCAL_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhSpec = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec");
+ }
+
+ if (dhSpec == null)
+ {
+ dhThreadSpec.set(null);
+ }
+ else
+ {
+ dhThreadSpec.set(dhSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter instanceof DHParameterSpec[] || parameter == null)
+ {
+ dhDefaultParams = parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec or DHParameterSpec[]");
+ }
+ }
+ }
+
+ public ECParameterSpec getEcImplicitlyCa()
+ {
+ ECParameterSpec spec = (ECParameterSpec)ecThreadSpec.get();
+
+ if (spec != null)
+ {
+ return spec;
+ }
+
+ return ecImplicitCaParams;
+ }
+
+ public DHParameterSpec getDHDefaultParameters(int keySize)
+ {
+ Object params = dhThreadSpec.get();
+ if (params == null)
+ {
+ params = dhDefaultParams;
+ }
+
+ if (params instanceof DHParameterSpec)
+ {
+ DHParameterSpec spec = (DHParameterSpec)params;
+
+ if (spec.getP().bitLength() == keySize)
+ {
+ return spec;
+ }
+ }
+ else if (params instanceof DHParameterSpec[])
+ {
+ DHParameterSpec[] specs = (DHParameterSpec[])params;
+
+ for (int i = 0; i != specs.length; i++)
+ {
+ if (specs[i].getP().bitLength() == keySize)
+ {
+ return specs[i];
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java b/prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 00000000..e90b3895
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,1439 @@
+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 java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PolicyQualifierInfo;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.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 javax.security.auth.x500.X500Principal;
+
+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.X509LDAPCertStoreParameters;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.util.Selector;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.util.Integers;
+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();
+ X500Principal 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
+ {
+ X500Principal caName = new X500Principal(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(Integers.valueOf(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>X500Principal</code>.
+ */
+ protected static X500Principal getEncodedIssuerPrincipal(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getIssuerX500Principal();
+ }
+ else
+ {
+ return (X500Principal)((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 X500Principal getSubjectPrincipal(X509Certificate cert)
+ {
+ return cert.getSubjectX500Principal();
+ }
+
+ 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 X500Principal getIssuerPrincipal(X509CRL crl)
+ {
+ return crl.getIssuerX500Principal();
+ }
+
+ 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)
+ {
+ if (pkixParams.isAdditionalLocationsEnabled())
+ {
+ try
+ {
+ if (location.startsWith("ldap://"))
+ {
+ // ldap://directory.d-trust.net/CN=D-TRUST
+ // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
+ // skip "ldap://"
+ location = location.substring(7);
+ // after first / baseDN starts
+ String base = null;
+ String url = null;
+ if (location.indexOf("/") != -1)
+ {
+ base = location.substring(location.indexOf("/"));
+ // URL
+ url = "ldap://"
+ + location.substring(0, location.indexOf("/"));
+ }
+ else
+ {
+ url = "ldap://" + location;
+ }
+ // use all purpose parameters
+ X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder(
+ url, base).build();
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ pkixParams.addAdditionalStore(X509Store.getInstance(
+ "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME));
+ }
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException("Exception adding X.509 stores.");
+ }
+ }
+ }
+
+ /**
+ * 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>X500Principal</code> for <code>X509Certificate</code>s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * <code>X500Principal</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>X500Principal</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 X500Principal(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((X500Principal)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(((X500Principal)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;
+ }
+
+ X500Principal 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.getIssuerX500Principal() + "\"");
+ }
+ }
+ 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(cert.getIssuerX500Principal().getEncoded());
+ }
+ catch (IOException 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.4/org/spongycastle/jce/provider/X509SignatureUtil.java b/prov/src/main/jdk1.4/org/spongycastle/jce/provider/X509SignatureUtil.java
new file mode 100644
index 00000000..93cce7a4
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/jce/provider/X509SignatureUtil.java
@@ -0,0 +1,125 @@
+package org.spongycastle.jce.provider;
+
+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.4/org/spongycastle/x509/X509CRLStoreSelector.java b/prov/src/main/jdk1.4/org/spongycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 00000000..4748bfc5
--- /dev/null
+++ b/prov/src/main/jdk1.4/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 java.security.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.4/org/spongycastle/x509/X509CertStoreSelector.java b/prov/src/main/jdk1.4/org/spongycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 00000000..61664c44
--- /dev/null
+++ b/prov/src/main/jdk1.4/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 java.security.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.setIssuer(selector.getIssuerAsBytes());
+ cs.setSubject(selector.getSubjectAsBytes());
+ }
+ 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.4/org/spongycastle/x509/util/LDAPStoreHelper.java b/prov/src/main/jdk1.4/org/spongycastle/x509/util/LDAPStoreHelper.java
new file mode 100644
index 00000000..b78c4a76
--- /dev/null
+++ b/prov/src/main/jdk1.4/org/spongycastle/x509/util/LDAPStoreHelper.java
@@ -0,0 +1,1118 @@
+package org.spongycastle.x509.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.sql.Date;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.x509.Certificate;
+import org.spongycastle.asn1.x509.CertificatePair;
+import org.spongycastle.jce.X509LDAPCertStoreParameters;
+import org.spongycastle.jce.provider.X509AttrCertParser;
+import org.spongycastle.jce.provider.X509CRLParser;
+import org.spongycastle.jce.provider.X509CertPairParser;
+import org.spongycastle.jce.provider.X509CertParser;
+import org.spongycastle.util.StoreException;
+import org.spongycastle.x509.X509AttributeCertStoreSelector;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CRLStoreSelector;
+import org.spongycastle.x509.X509CertPairStoreSelector;
+import org.spongycastle.x509.X509CertStoreSelector;
+import org.spongycastle.x509.X509CertificatePair;
+
+/**
+ * This is a general purpose implementation to get X.509 certificates, CRLs,
+ * attribute certificates and cross certificates from a LDAP location.
+ * <p/>
+ * At first a search is performed in the ldap*AttributeNames of the
+ * {@link org.spongycastle.jce.X509LDAPCertStoreParameters} with the given
+ * information of the subject (for all kind of certificates) or issuer (for
+ * CRLs), respectively, if a {@link org.spongycastle.x509.X509CertStoreSelector} or
+ * {@link org.spongycastle.x509.X509AttributeCertificate} is given with that
+ * details.
+ * <p/>
+ * For the used schemes see:
+ * <ul>
+ * <li><a href="http://www.ietf.org/rfc/rfc2587.txt">RFC 2587</a>
+ * <li><a
+ * href="http://www3.ietf.org/proceedings/01mar/I-D/pkix-ldap-schema-01.txt">Internet
+ * X.509 Public Key Infrastructure Additional LDAP Schema for PKIs and PMIs</a>
+ * </ul>
+ */
+public class LDAPStoreHelper
+{
+
+ // TODO: cache results
+
+ private X509LDAPCertStoreParameters params;
+
+ public LDAPStoreHelper(X509LDAPCertStoreParameters params)
+ {
+ this.params = params;
+ }
+
+ /**
+ * Initial Context Factory.
+ */
+ private static String LDAP_PROVIDER = "com.sun.jndi.ldap.LdapCtxFactory";
+
+ /**
+ * Processing referrals..
+ */
+ private static String REFERRALS_IGNORE = "ignore";
+
+ /**
+ * Security level to be used for LDAP connections.
+ */
+ private static final String SEARCH_SECURITY_LEVEL = "none";
+
+ /**
+ * Package Prefix for loading URL context factories.
+ */
+ private static final String URL_CONTEXT_PREFIX = "com.sun.jndi.url";
+
+ private DirContext connectLDAP() throws NamingException
+ {
+ Properties props = new Properties();
+ props.setProperty(Context.INITIAL_CONTEXT_FACTORY, LDAP_PROVIDER);
+ props.setProperty(Context.BATCHSIZE, "0");
+
+ props.setProperty(Context.PROVIDER_URL, params.getLdapURL());
+ props.setProperty(Context.URL_PKG_PREFIXES, URL_CONTEXT_PREFIX);
+ props.setProperty(Context.REFERRAL, REFERRALS_IGNORE);
+ props.setProperty(Context.SECURITY_AUTHENTICATION,
+ SEARCH_SECURITY_LEVEL);
+
+ DirContext ctx = new InitialDirContext(props);
+ return ctx;
+ }
+
+ private String parseDN(String subject, String dNAttributeName)
+ {
+ String temp = subject;
+ int begin = temp.toLowerCase().indexOf(
+ dNAttributeName.toLowerCase() + "=");
+ if (begin == -1)
+ {
+ return "";
+ }
+ temp = temp.substring(begin + dNAttributeName.length());
+ int end = temp.indexOf(',');
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ while (temp.charAt(end - 1) == '\\')
+ {
+ end = temp.indexOf(',', end + 1);
+ if (end == -1)
+ {
+ end = temp.length();
+ }
+ }
+ temp = temp.substring(0, end);
+ begin = temp.indexOf('=');
+ temp = temp.substring(begin + 1);
+ if (temp.charAt(0) == ' ')
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.startsWith("\""))
+ {
+ temp = temp.substring(1);
+ }
+ if (temp.endsWith("\""))
+ {
+ temp = temp.substring(0, temp.length() - 1);
+ }
+ return temp;
+ }
+
+ private Set createCerts(List list, X509CertStoreSelector xselector)
+ throws StoreException
+ {
+ Set certSet = new HashSet();
+
+ Iterator it = list.iterator();
+ X509CertParser parser = new X509CertParser();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509Certificate cert = (X509Certificate)parser
+ .engineRead();
+ if (xselector.match((Object)cert))
+ {
+ certSet.add(cert);
+ }
+
+ }
+ catch (Exception e)
+ {
+
+ }
+ }
+
+ return certSet;
+ }
+
+ /**
+ * Can use the subject and serial and the subject and serialNumber of the
+ * certificate of the given of the X509CertStoreSelector. If a certificate
+ * for checking is given this has higher precedence.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the certificates in the LDAP
+ * directory.
+ * @param attrNames Attribute names in teh LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded certificates.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List certSubjectSerialSearch(X509CertStoreSelector xselector,
+ String[] attrs, String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ // TODO: support also subjectAltNames?
+ List list = new ArrayList();
+
+ String subject = null;
+ String serial = null;
+
+ subject = getSubjectAsString(xselector);
+
+ if (xselector.getSerialNumber() != null)
+ {
+ serial = xselector.getSerialNumber().toString();
+ }
+ if (xselector.getCertificate() != null)
+ {
+ subject = xselector.getCertificate().getSubjectX500Principal().getName("RFC1779");
+ serial = xselector.getCertificate().getSerialNumber().toString();
+ }
+
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (serial != null && params.getSearchForSerialNumberIn() != null)
+ {
+ attrValue = serial;
+ list.addAll(search(
+ splitString(params.getSearchForSerialNumberIn()),
+ attrValue, attrs));
+ }
+ if (serial == null && subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+
+
+ /**
+ * Can use the subject of the forward certificate of the set certificate
+ * pair or the subject of the forward
+ * {@link org.spongycastle.x509.X509CertStoreSelector} of the given
+ * selector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded certificate pairs.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List crossCertificatePairSubjectSearch(
+ X509CertPairStoreSelector xselector, String[] attrs,
+ String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ // search for subject
+ String subject = null;
+
+ if (xselector.getForwardSelector() != null)
+ {
+ subject = getSubjectAsString(xselector.getForwardSelector());
+ }
+ if (xselector.getCertPair() != null)
+ {
+ if (xselector.getCertPair().getForward() != null)
+ {
+ subject = xselector.getCertPair().getForward()
+ .getSubjectX500Principal().getName("RFC1779");
+ }
+ }
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Can use the entityName of the holder of the attribute certificate, the
+ * serialNumber of attribute certificate and the serialNumber of the
+ * associated certificate of the given of the X509AttributeCertSelector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param subjectAttributeNames Subject attribute names (like "CN", "O", "OU") to use to
+ * search in the LDAP directory
+ * @return A list of found DER encoded attribute certificates.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List attrCertSubjectSerialSearch(
+ X509AttributeCertStoreSelector xselector, String[] attrs,
+ String attrNames[], String subjectAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ // search for serialNumber of associated cert,
+ // serialNumber of the attribute certificate or DN in the entityName
+ // of the holder
+
+ String subject = null;
+ String serial = null;
+
+ Collection serials = new HashSet();
+ Principal principals[] = null;
+ if (xselector.getHolder() != null)
+ {
+ // serialNumber of associated cert
+ if (xselector.getHolder().getSerialNumber() != null)
+ {
+ serials.add(xselector.getHolder().getSerialNumber()
+ .toString());
+ }
+ // DN in the entityName of the holder
+ if (xselector.getHolder().getEntityNames() != null)
+ {
+ principals = xselector.getHolder().getEntityNames();
+ }
+ }
+
+ if (xselector.getAttributeCert() != null)
+ {
+ if (xselector.getAttributeCert().getHolder().getEntityNames() != null)
+ {
+ principals = xselector.getAttributeCert().getHolder()
+ .getEntityNames();
+ }
+ // serialNumber of the attribute certificate
+ serials.add(xselector.getAttributeCert().getSerialNumber()
+ .toString());
+ }
+ if (principals != null)
+ {
+ // only first should be relevant
+ if (principals[0] instanceof X500Principal)
+ {
+ subject = ((X500Principal)principals[0])
+ .getName("RFC1779");
+ }
+ else
+ {
+ // strange ...
+ subject = principals[0].getName();
+ }
+ }
+ if (xselector.getSerialNumber() != null)
+ {
+ serials.add(xselector.getSerialNumber().toString());
+ }
+
+ String attrValue = null;
+ if (subject != null)
+ {
+ for (int i = 0; i < subjectAttributeNames.length; i++)
+ {
+ attrValue = parseDN(subject, subjectAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (serials.size() > 0
+ && params.getSearchForSerialNumberIn() != null)
+ {
+ Iterator it = serials.iterator();
+ while (it.hasNext())
+ {
+ serial = (String)it.next();
+ list.addAll(search(splitString(params.getSearchForSerialNumberIn()), serial, attrs));
+ }
+ }
+ if (serials.size() == 0 && subject == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Can use the issuer of the given of the X509CRLStoreSelector.
+ *
+ * @param xselector The selector with the search criteria.
+ * @param attrs Attributes which contain the attribute certificates in the
+ * LDAP directory.
+ * @param attrNames Attribute names in the LDAP directory which correspond to the
+ * subjectAttributeNames.
+ * @param issuerAttributeNames Issuer attribute names (like "CN", "O", "OU") to use to search
+ * in the LDAP directory
+ * @return A list of found DER encoded CRLs.
+ * @throws StoreException if an error occurs while searching.
+ */
+ private List cRLIssuerSearch(X509CRLStoreSelector xselector,
+ String[] attrs, String attrNames[], String issuerAttributeNames[])
+ throws StoreException
+ {
+ List list = new ArrayList();
+
+ String issuer = null;
+ Collection issuers = new HashSet();
+/*
+ if (xselector.getIssuers() != null)
+ {
+ issuers.addAll(xselector.getIssuers());
+ }
+*/
+ if (xselector.getCertificateChecking() != null)
+ {
+ issuers.add(getCertificateIssuer(xselector.getCertificateChecking()));
+ }
+ if (xselector.getAttrCertificateChecking() != null)
+ {
+ Principal principals[] = xselector.getAttrCertificateChecking().getIssuer().getPrincipals();
+ for (int i=0; i<principals.length; i++)
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ issuers.add(principals[i]);
+ }
+ }
+ }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ issuer = ((X500Principal)it.next()).getName("RFC1779");
+ String attrValue = null;
+
+ for (int i = 0; i < issuerAttributeNames.length; i++)
+ {
+ attrValue = parseDN(issuer, issuerAttributeNames[i]);
+ list
+ .addAll(search(attrNames, "*" + attrValue + "*",
+ attrs));
+ }
+ }
+ if (issuer == null)
+ {
+ list.addAll(search(attrNames, "*", attrs));
+ }
+
+ return list;
+ }
+
+ /**
+ * Returns a <code>List</code> of encodings of the certificates, attribute
+ * certificates, CRL or certificate pairs.
+ *
+ * @param attributeNames The attribute names to look for in the LDAP.
+ * @param attributeValue The value the attribute name must have.
+ * @param attrs The attributes in the LDAP which hold the certificate,
+ * attribute certificate, certificate pair or CRL in a found
+ * entry.
+ * @return A <code>List</code> of byte arrays with the encodings.
+ * @throws StoreException if an error occurs getting the results from the LDAP
+ * directory.
+ */
+ private List search(String attributeNames[], String attributeValue,
+ String[] attrs) throws StoreException
+ {
+ String filter = null;
+ if (attributeNames == null)
+ {
+ filter = null;
+ }
+ else
+ {
+ filter = "";
+ if (attributeValue.equals("**"))
+ {
+ attributeValue = "*";
+ }
+ for (int i = 0; i < attributeNames.length; i++)
+ {
+ filter += "(" + attributeNames[i] + "=" + attributeValue + ")";
+ }
+ filter = "(|" + filter + ")";
+ }
+ String filter2 = "";
+ for (int i = 0; i < attrs.length; i++)
+ {
+ filter2 += "(" + attrs[i] + "=*)";
+ }
+ filter2 = "(|" + filter2 + ")";
+
+ String filter3 = "(&" + filter + "" + filter2 + ")";
+ if (filter == null)
+ {
+ filter3 = filter2;
+ }
+ List list;
+ list = getFromCache(filter3);
+ if (list != null)
+ {
+ return list;
+ }
+ DirContext ctx = null;
+ list = new ArrayList();
+ try
+ {
+
+ ctx = connectLDAP();
+
+ SearchControls constraints = new SearchControls();
+ constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ constraints.setCountLimit(0);
+ constraints.setReturningAttributes(attrs);
+ NamingEnumeration results = ctx.search(params.getBaseDN(), filter3,
+ constraints);
+ while (results.hasMoreElements())
+ {
+ SearchResult sr = (SearchResult)results.next();
+ NamingEnumeration enumeration = ((Attribute)(sr
+ .getAttributes().getAll().next())).getAll();
+ while (enumeration.hasMore())
+ {
+ list.add(enumeration.next());
+ }
+ }
+ addToCache(filter3, list);
+ }
+ catch (NamingException e)
+ {
+ // skip exception, unfortunately if an attribute type is not
+ // supported an exception is thrown
+
+ }
+ finally
+ {
+ try
+ {
+ if (null != ctx)
+ {
+ ctx.close();
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ return list;
+ }
+
+ private Set createCRLs(List list, X509CRLStoreSelector xselector)
+ throws StoreException
+ {
+ Set crlSet = new HashSet();
+
+ X509CRLParser parser = new X509CRLParser();
+ Iterator it = list.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509CRL crl = (X509CRL)parser.engineRead();
+ if (xselector.match((Object)crl))
+ {
+ crlSet.add(crl);
+ }
+ }
+ catch (StreamParsingException e)
+ {
+
+ }
+ }
+
+ return crlSet;
+ }
+
+ private Set createCrossCertificatePairs(List list,
+ X509CertPairStoreSelector xselector) throws StoreException
+ {
+ Set certPairSet = new HashSet();
+
+ int i = 0;
+ while (i < list.size())
+ {
+ X509CertificatePair pair;
+ try
+ {
+ // first try to decode it as certificate pair
+ try
+ {
+ X509CertPairParser parser = new X509CertPairParser();
+ parser.engineInit(new ByteArrayInputStream(
+ (byte[])list.get(i)));
+ pair = (X509CertificatePair)parser.engineRead();
+ }
+ catch (StreamParsingException e)
+ {
+ // now try it to construct it the forward and reverse
+ // certificate
+ byte[] forward = (byte[])list.get(i);
+ byte[] reverse = (byte[])list.get(i + 1);
+ pair = new X509CertificatePair(new CertificatePair(
+ Certificate
+ .getInstance(new ASN1InputStream(
+ forward).readObject()),
+ Certificate
+ .getInstance(new ASN1InputStream(
+ reverse).readObject())));
+ i++;
+ }
+ if (xselector.match((Object)pair))
+ {
+ certPairSet.add(pair);
+ }
+ }
+ catch (CertificateParsingException e)
+ {
+ // try next
+ }
+ catch (IOException e)
+ {
+ // try next
+ }
+ i++;
+ }
+
+ return certPairSet;
+ }
+
+ private Set createAttributeCertificates(List list,
+ X509AttributeCertStoreSelector xselector) throws StoreException
+ {
+ Set certSet = new HashSet();
+
+ Iterator it = list.iterator();
+ X509AttrCertParser parser = new X509AttrCertParser();
+ while (it.hasNext())
+ {
+ try
+ {
+ parser.engineInit(new ByteArrayInputStream((byte[])it
+ .next()));
+ X509AttributeCertificate cert = (X509AttributeCertificate)parser
+ .engineRead();
+ if (xselector.match((Object)cert))
+ {
+ certSet.add(cert);
+ }
+ }
+ catch (StreamParsingException e)
+ {
+
+ }
+ }
+
+ return certSet;
+ }
+
+ /**
+ * Returns the CRLs for issued certificates for other CAs matching the given
+ * selector. <br>
+ * The authorityRevocationList attribute includes revocation information
+ * regarding certificates issued to other CAs.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs
+ * @throws StoreException
+ */
+ public Collection getAuthorityRevocationLists(X509CRLStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getAuthorityRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAuthorityRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAuthorityRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the revocation list for revoked attribute certificates.
+ * <p/>
+ * The attributeCertificateRevocationList holds a list of attribute
+ * certificates that have been revoked.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getAttributeCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params
+ .getAttributeCertificateRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeCertificateRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAttributeCertificateRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the revocation list for revoked attribute certificates for an
+ * attribute authority
+ * <p/>
+ * The attributeAuthorityList holds a list of AA certificates that have been
+ * revoked.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs
+ * @throws StoreException
+ */
+ public Collection getAttributeAuthorityRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeAuthorityRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeAuthorityRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getAttributeAuthorityRevocationListIssuerAttributeName());
+
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns cross certificate pairs.
+ *
+ * @param selector The selector to use to find the cross certificates.
+ * @return A possible empty collection with {@link X509CertificatePair}s
+ * @throws StoreException
+ */
+ public Collection getCrossCertificatePairs(
+ X509CertPairStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getCrossCertificateAttribute());
+ String attrNames[] = splitString(params.getLdapCrossCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getCrossCertificateSubjectAttributeName());
+ List list = crossCertificatePairSubjectSearch(selector, attrs,
+ attrNames, subjectAttributeNames);
+ Set resultSet = createCrossCertificatePairs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptyCertselector = new X509CertStoreSelector();
+ X509CertPairStoreSelector emptySelector = new X509CertPairStoreSelector();
+
+ emptySelector.setForwardSelector(emptyCertselector);
+ emptySelector.setReverseSelector(emptyCertselector);
+ list = crossCertificatePairSubjectSearch(emptySelector, attrs,
+ attrNames, subjectAttributeNames);
+ resultSet.addAll(createCrossCertificatePairs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns end certificates.
+ * <p/>
+ * The attributeDescriptorCertificate is self signed by a source of
+ * authority and holds a description of the privilege and its delegation
+ * rules.
+ *
+ * @param selector The selector to find the certificates.
+ * @return A possible empty collection with certificates.
+ * @throws StoreException
+ */
+ public Collection getUserCertificates(X509CertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getUserCertificateAttribute());
+ String attrNames[] = splitString(params.getLdapUserCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getUserCertificateSubjectAttributeName());
+
+ List list = certSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createCerts(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptySelector = new X509CertStoreSelector();
+ list = certSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createCerts(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns attribute certificates for an attribute authority
+ * <p/>
+ * The aAcertificate holds the privileges of an attribute authority.
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAACertificates(X509AttributeCertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getAACertificateAttribute());
+ String attrNames[] = splitString(params.getLdapAACertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params.getAACertificateSubjectAttributeName());
+
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns an attribute certificate for an authority
+ * <p/>
+ * The attributeDescriptorCertificate is self signed by a source of
+ * authority and holds a description of the privilege and its delegation
+ * rules.
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAttributeDescriptorCertificates(
+ X509AttributeCertStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeDescriptorCertificateAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeDescriptorCertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getAttributeDescriptorCertificateSubjectAttributeName());
+
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns CA certificates.
+ * <p/>
+ * The cACertificate attribute of a CA's directory entry shall be used to
+ * store self-issued certificates (if any) and certificates issued to this
+ * CA by CAs in the same realm as this CA.
+ *
+ * @param selector The selector to find the certificates.
+ * @return A possible empty collection with certificates.
+ * @throws StoreException
+ */
+ public Collection getCACertificates(X509CertStoreSelector selector)
+ throws StoreException
+ {
+ String[] attrs = splitString(params.getCACertificateAttribute());
+ String attrNames[] = splitString(params.getLdapCACertificateAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getCACertificateSubjectAttributeName());
+ List list = certSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createCerts(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CertStoreSelector emptySelector = new X509CertStoreSelector();
+ list = certSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createCerts(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns the delta revocation list for revoked certificates.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getDeltaCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getDeltaRevocationListAttribute());
+ String attrNames[] = splitString(params.getLdapDeltaRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getDeltaRevocationListIssuerAttributeName());
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ /**
+ * Returns an attribute certificate for an user.
+ * <p/>
+ * The attributeCertificateAttribute holds the privileges of a user
+ *
+ * @param selector The selector to find the attribute certificates.
+ * @return A possible empty collection with attribute certificates.
+ * @throws StoreException
+ */
+ public Collection getAttributeCertificateAttributes(
+ X509AttributeCertStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getAttributeCertificateAttributeAttribute());
+ String attrNames[] = splitString(params
+ .getLdapAttributeCertificateAttributeAttributeName());
+ String subjectAttributeNames[] = splitString(params
+ .getAttributeCertificateAttributeSubjectAttributeName());
+ List list = attrCertSubjectSerialSearch(selector, attrs, attrNames,
+ subjectAttributeNames);
+ Set resultSet = createAttributeCertificates(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509AttributeCertStoreSelector emptySelector = new X509AttributeCertStoreSelector();
+ list = attrCertSubjectSerialSearch(emptySelector, attrs, attrNames,
+ subjectAttributeNames);
+ resultSet.addAll(createAttributeCertificates(list, selector));
+ }
+
+ return resultSet;
+ }
+
+ /**
+ * Returns the certificate revocation lists for revoked certificates.
+ *
+ * @param selector The CRL selector to use to find the CRLs.
+ * @return A possible empty collection with CRLs.
+ * @throws StoreException
+ */
+ public Collection getCertificateRevocationLists(
+ X509CRLStoreSelector selector) throws StoreException
+ {
+ String[] attrs = splitString(params.getCertificateRevocationListAttribute());
+ String attrNames[] = splitString(params
+ .getLdapCertificateRevocationListAttributeName());
+ String issuerAttributeNames[] = splitString(params
+ .getCertificateRevocationListIssuerAttributeName());
+ List list = cRLIssuerSearch(selector, attrs, attrNames,
+ issuerAttributeNames);
+ Set resultSet = createCRLs(list, selector);
+ if (resultSet.size() == 0)
+ {
+ X509CRLStoreSelector emptySelector = new X509CRLStoreSelector();
+ list = cRLIssuerSearch(emptySelector, attrs, attrNames,
+ issuerAttributeNames);
+
+ resultSet.addAll(createCRLs(list, selector));
+ }
+ return resultSet;
+ }
+
+ private Map cacheMap = new HashMap(cacheSize);
+
+ private static int cacheSize = 32;
+
+ private static long lifeTime = 60 * 1000;
+
+ private synchronized void addToCache(String searchCriteria, List list)
+ {
+ Date now = new Date(System.currentTimeMillis());
+ List cacheEntry = new ArrayList();
+ cacheEntry.add(now);
+ cacheEntry.add(list);
+ if (cacheMap.containsKey(searchCriteria))
+ {
+ cacheMap.put(searchCriteria, cacheEntry);
+ }
+ else
+ {
+ if (cacheMap.size() >= cacheSize)
+ {
+ // replace oldest
+ Iterator it = cacheMap.entrySet().iterator();
+ long oldest = now.getTime();
+ Object replace = null;
+ while (it.hasNext())
+ {
+ Map.Entry entry = (Map.Entry)it.next();
+ long current = ((Date)((List)entry.getValue()).get(0))
+ .getTime();
+ if (current < oldest)
+ {
+ oldest = current;
+ replace = entry.getKey();
+ }
+ }
+ cacheMap.remove(replace);
+ }
+ cacheMap.put(searchCriteria, cacheEntry);
+ }
+ }
+
+ private List getFromCache(String searchCriteria)
+ {
+ List entry = (List)cacheMap.get(searchCriteria);
+ long now = System.currentTimeMillis();
+ if (entry != null)
+ {
+ // too old
+ if (((Date)entry.get(0)).getTime() < (now - lifeTime))
+ {
+ return null;
+ }
+ return (List)entry.get(1);
+ }
+ return null;
+ }
+
+ /*
+ * spilt string based on spaces
+ */
+ private String[] splitString(String str)
+ {
+ return str.split("\\s+");
+ }
+
+ private String getSubjectAsString(X509CertStoreSelector xselector)
+ {
+ try
+ {
+ byte[] encSubject = xselector.getSubjectAsBytes();
+ if (encSubject != null)
+ {
+ return new X500Principal(encSubject).getName("RFC1779");
+ }
+ }
+ catch (IOException e)
+ {
+ throw new StoreException("exception processing name: " + e.getMessage(), e);
+ }
+ return null;
+ }
+
+ private X500Principal getCertificateIssuer(X509Certificate cert)
+ {
+ return cert.getIssuerX500Principal();
+ }
+}