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 'pkix/src/main/java/org/spongycastle/cert/selector')
-rw-r--r--pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java422
-rw-r--r--pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java268
-rw-r--r--pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java194
-rw-r--r--pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java152
-rw-r--r--pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java35
-rw-r--r--pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java57
-rw-r--r--pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java72
7 files changed, 1200 insertions, 0 deletions
diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java b/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java
new file mode 100644
index 00000000..23748ac3
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/cert/selector/MSOutlookKeyIdCalculator.java
@@ -0,0 +1,422 @@
+package org.spongycastle.cert.selector;
+
+import java.io.IOException;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.util.Pack;
+
+class MSOutlookKeyIdCalculator
+{
+ // This is less than ideal, but it seems to be the best way of supporting this without exposing SHA-1
+ // as the class is only used to workout the MSOutlook Key ID, you can think of the fact it's SHA-1 as
+ // a coincidence...
+ static byte[] calculateKeyId(SubjectPublicKeyInfo info)
+ {
+ SHA1Digest dig = new SHA1Digest();
+ byte[] hash = new byte[dig.getDigestSize()];
+ byte[] spkiEnc = new byte[0];
+ try
+ {
+ spkiEnc = info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return new byte[0];
+ }
+
+ // try the outlook 2010 calculation
+ dig.update(spkiEnc, 0, spkiEnc.length);
+
+ dig.doFinal(hash, 0);
+
+ return hash;
+ }
+
+ private static abstract class GeneralDigest
+ {
+ private static final int BYTE_LENGTH = 64;
+ private byte[] xBuf;
+ private int xBufOff;
+
+ private long byteCount;
+
+ /**
+ * Standard constructor
+ */
+ protected GeneralDigest()
+ {
+ xBuf = new byte[4];
+ xBufOff = 0;
+ }
+
+ /**
+ * Copy constructor. We are using copy constructors in place
+ * of the Object.clone() interface as this interface is not
+ * supported by J2ME.
+ */
+ protected GeneralDigest(GeneralDigest t)
+ {
+ xBuf = new byte[t.xBuf.length];
+
+ copyIn(t);
+ }
+
+ protected void copyIn(GeneralDigest t)
+ {
+ System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
+
+ xBufOff = t.xBufOff;
+ byteCount = t.byteCount;
+ }
+
+ public void update(
+ byte in)
+ {
+ xBuf[xBufOff++] = in;
+
+ if (xBufOff == xBuf.length)
+ {
+ processWord(xBuf, 0);
+ xBufOff = 0;
+ }
+
+ byteCount++;
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ //
+ // fill the current word
+ //
+ while ((xBufOff != 0) && (len > 0))
+ {
+ update(in[inOff]);
+
+ inOff++;
+ len--;
+ }
+
+ //
+ // process whole words.
+ //
+ while (len > xBuf.length)
+ {
+ processWord(in, inOff);
+
+ inOff += xBuf.length;
+ len -= xBuf.length;
+ byteCount += xBuf.length;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (len > 0)
+ {
+ update(in[inOff]);
+
+ inOff++;
+ len--;
+ }
+ }
+
+ public void finish()
+ {
+ long bitLength = (byteCount << 3);
+
+ //
+ // add the pad bytes.
+ //
+ update((byte)128);
+
+ while (xBufOff != 0)
+ {
+ update((byte)0);
+ }
+
+ processLength(bitLength);
+
+ processBlock();
+ }
+
+ public void reset()
+ {
+ byteCount = 0;
+
+ xBufOff = 0;
+ for (int i = 0; i < xBuf.length; i++)
+ {
+ xBuf[i] = 0;
+ }
+ }
+
+ protected abstract void processWord(byte[] in, int inOff);
+
+ protected abstract void processLength(long bitLength);
+
+ protected abstract void processBlock();
+ }
+
+ private static class SHA1Digest
+ extends GeneralDigest
+ {
+ private static final int DIGEST_LENGTH = 20;
+
+ private int H1, H2, H3, H4, H5;
+
+ private int[] X = new int[80];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public SHA1Digest()
+ {
+ reset();
+ }
+
+ public String getAlgorithmName()
+ {
+ return "SHA-1";
+ }
+
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ protected void processWord(
+ byte[] in,
+ int inOff)
+ {
+ // Note: Inlined for performance
+ // X[xOff] = Pack.bigEndianToInt(in, inOff);
+ int n = in[ inOff] << 24;
+ n |= (in[++inOff] & 0xff) << 16;
+ n |= (in[++inOff] & 0xff) << 8;
+ n |= (in[++inOff] & 0xff);
+ X[xOff] = n;
+
+ if (++xOff == 16)
+ {
+ processBlock();
+ }
+ }
+
+ protected void processLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ processBlock();
+ }
+
+ X[14] = (int)(bitLength >>> 32);
+ X[15] = (int)(bitLength & 0xffffffff);
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ finish();
+
+ Pack.intToBigEndian(H1, out, outOff);
+ Pack.intToBigEndian(H2, out, outOff + 4);
+ Pack.intToBigEndian(H3, out, outOff + 8);
+ Pack.intToBigEndian(H4, out, outOff + 12);
+ Pack.intToBigEndian(H5, out, outOff + 16);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public void reset()
+ {
+ super.reset();
+
+ H1 = 0x67452301;
+ H2 = 0xefcdab89;
+ H3 = 0x98badcfe;
+ H4 = 0x10325476;
+ H5 = 0xc3d2e1f0;
+
+ xOff = 0;
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // Additive constants
+ //
+ private static final int Y1 = 0x5a827999;
+ private static final int Y2 = 0x6ed9eba1;
+ private static final int Y3 = 0x8f1bbcdc;
+ private static final int Y4 = 0xca62c1d6;
+
+ private int f(
+ int u,
+ int v,
+ int w)
+ {
+ return ((u & v) | ((~u) & w));
+ }
+
+ private int h(
+ int u,
+ int v,
+ int w)
+ {
+ return (u ^ v ^ w);
+ }
+
+ private int g(
+ int u,
+ int v,
+ int w)
+ {
+ return ((u & v) | (u & w) | (v & w));
+ }
+
+ protected void processBlock()
+ {
+ //
+ // expand 16 word block into 80 word block.
+ //
+ for (int i = 16; i < 80; i++)
+ {
+ int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
+ X[i] = t << 1 | t >>> 31;
+ }
+
+ //
+ // set up working variables.
+ //
+ int A = H1;
+ int B = H2;
+ int C = H3;
+ int D = H4;
+ int E = H5;
+
+ //
+ // round 1
+ //
+ int idx = 0;
+
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;
+ B = B << 30 | B >>> 2;
+
+ D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;
+ A = A << 30 | A >>> 2;
+
+ C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;
+ E = E << 30 | E >>> 2;
+
+ B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;
+ D = D << 30 | D >>> 2;
+
+ A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;
+ C = C << 30 | C >>> 2;
+ }
+
+ //
+ // round 2
+ //
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;
+ B = B << 30 | B >>> 2;
+
+ D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;
+ A = A << 30 | A >>> 2;
+
+ C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;
+ E = E << 30 | E >>> 2;
+
+ B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;
+ D = D << 30 | D >>> 2;
+
+ A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;
+ C = C << 30 | C >>> 2;
+ }
+
+ //
+ // round 3
+ //
+ for (int j = 0; j < 4; j++)
+ {
+ // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;
+ B = B << 30 | B >>> 2;
+
+ D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;
+ A = A << 30 | A >>> 2;
+
+ C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;
+ E = E << 30 | E >>> 2;
+
+ B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;
+ D = D << 30 | D >>> 2;
+
+ A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;
+ C = C << 30 | C >>> 2;
+ }
+
+ //
+ // round 4
+ //
+ for (int j = 0; j <= 3; j++)
+ {
+ // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4
+ // B = rotateLeft(B, 30)
+ E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;
+ B = B << 30 | B >>> 2;
+
+ D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;
+ A = A << 30 | A >>> 2;
+
+ C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;
+ E = E << 30 | E >>> 2;
+
+ B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;
+ D = D << 30 | D >>> 2;
+
+ A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;
+ C = C << 30 | C >>> 2;
+ }
+
+
+ H1 += A;
+ H2 += B;
+ H3 += C;
+ H4 += D;
+ H5 += E;
+
+ //
+ // reset start of the buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ X[i] = 0;
+ }
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java
new file mode 100644
index 00000000..3ae30b33
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelector.java
@@ -0,0 +1,268 @@
+package org.spongycastle.cert.selector;
+
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Date;
+
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.Target;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.Targets;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+import org.spongycastle.util.Selector;
+
+/**
+ * This class is an <code>Selector</code> like implementation to select
+ * attribute certificates from a given set of criteria.
+ */
+public class X509AttributeCertificateHolderSelector
+ implements Selector
+{
+
+ // TODO: name constraints???
+
+ private final AttributeCertificateHolder holder;
+
+ private final AttributeCertificateIssuer issuer;
+
+ private final BigInteger serialNumber;
+
+ private final Date attributeCertificateValid;
+
+ private final X509AttributeCertificateHolder attributeCert;
+
+ private final Collection targetNames;
+
+ private final Collection targetGroups;
+
+ X509AttributeCertificateHolderSelector(
+ AttributeCertificateHolder holder,
+ AttributeCertificateIssuer issuer,
+ BigInteger serialNumber,
+ Date attributeCertificateValid,
+ X509AttributeCertificateHolder attributeCert,
+ Collection targetNames,
+ Collection targetGroups)
+ {
+ this.holder = holder;
+ this.issuer = issuer;
+ this.serialNumber = serialNumber;
+ this.attributeCertificateValid = attributeCertificateValid;
+ this.attributeCert = attributeCert;
+ this.targetNames = targetNames;
+ this.targetGroups = targetGroups;
+ }
+
+ /**
+ * Decides if the given attribute certificate should be selected.
+ *
+ * @param obj The X509AttributeCertificateHolder which should be checked.
+ * @return <code>true</code> if the attribute certificate is a match
+ * <code>false</code> otherwise.
+ */
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)obj;
+
+ if (this.attributeCert != null)
+ {
+ if (!this.attributeCert.equals(attrCert))
+ {
+ return false;
+ }
+ }
+ if (serialNumber != null)
+ {
+ if (!attrCert.getSerialNumber().equals(serialNumber))
+ {
+ return false;
+ }
+ }
+ if (holder != null)
+ {
+ if (!attrCert.getHolder().equals(holder))
+ {
+ return false;
+ }
+ }
+ if (issuer != null)
+ {
+ if (!attrCert.getIssuer().equals(issuer))
+ {
+ return false;
+ }
+ }
+
+ if (attributeCertificateValid != null)
+ {
+ if (!attrCert.isValidOn(attributeCertificateValid))
+ {
+ return false;
+ }
+ }
+ if (!targetNames.isEmpty() || !targetGroups.isEmpty())
+ {
+ Extension targetInfoExt = attrCert.getExtension(Extension.targetInformation);
+ if (targetInfoExt != null)
+ {
+ TargetInformation targetinfo;
+ try
+ {
+ targetinfo = TargetInformation.getInstance(targetInfoExt.getParsedValue());
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+ Targets[] targetss = targetinfo.getTargetsObjects();
+ if (!targetNames.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetNames.contains(GeneralName.getInstance(targets[j]
+ .getTargetName())))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ if (!targetGroups.isEmpty())
+ {
+ boolean found = false;
+
+ for (int i=0; i<targetss.length; i++)
+ {
+ Targets t = targetss[i];
+ Target[] targets = t.getTargets();
+ for (int j=0; j<targets.length; j++)
+ {
+ if (targetGroups.contains(GeneralName.getInstance(targets[j]
+ .getTargetGroup())))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found)
+ {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return the clone.
+ */
+ public Object clone()
+ {
+ X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector(
+ holder, issuer, serialNumber, attributeCertificateValid, attributeCert, targetNames, targetGroups);
+
+ return sel;
+ }
+
+ /**
+ * Returns the attribute certificate holder which must be matched.
+ *
+ * @return Returns an X509AttributeCertificateHolder
+ */
+ public X509AttributeCertificateHolder getAttributeCert()
+ {
+ return attributeCert;
+ }
+
+ /**
+ * Get the criteria for the validity.
+ *
+ * @return Returns the attributeCertificateValid.
+ */
+ public Date getAttributeCertificateValid()
+ {
+ if (attributeCertificateValid != null)
+ {
+ return new Date(attributeCertificateValid.getTime());
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the holder.
+ *
+ * @return Returns the holder.
+ */
+ public AttributeCertificateHolder getHolder()
+ {
+ return holder;
+ }
+
+ /**
+ * Returns the issuer criterion.
+ *
+ * @return Returns the issuer.
+ */
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return issuer;
+ }
+
+ /**
+ * Gets the serial number the attribute certificate must have.
+ *
+ * @return Returns the serialNumber.
+ */
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ /**
+ * Gets the target names. The collection consists of GeneralName objects.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target names
+ */
+ public Collection getTargetNames()
+ {
+ return targetNames;
+ }
+
+ /**
+ * Gets the target groups. The collection consists of GeneralName objects.
+ * <p>
+ * The returned collection is immutable.
+ *
+ * @return The collection of target groups.
+ */
+ public Collection getTargetGroups()
+ {
+ return targetGroups;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java
new file mode 100644
index 00000000..35df571d
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/cert/selector/X509AttributeCertificateHolderSelectorBuilder.java
@@ -0,0 +1,194 @@
+package org.spongycastle.cert.selector;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.AttributeCertificateHolder;
+import org.spongycastle.cert.AttributeCertificateIssuer;
+import org.spongycastle.cert.X509AttributeCertificateHolder;
+
+/**
+ * This class builds selectors according to the set criteria.
+ */
+public class X509AttributeCertificateHolderSelectorBuilder
+{
+
+ // TODO: name constraints???
+
+ private AttributeCertificateHolder holder;
+
+ private AttributeCertificateIssuer issuer;
+
+ private BigInteger serialNumber;
+
+ private Date attributeCertificateValid;
+
+ private X509AttributeCertificateHolder attributeCert;
+
+ private Collection targetNames = new HashSet();
+
+ private Collection targetGroups = new HashSet();
+
+ public X509AttributeCertificateHolderSelectorBuilder()
+ {
+ }
+
+ /**
+ * Set the attribute certificate to be matched. If <code>null</code> is
+ * given any will do.
+ *
+ * @param attributeCert The attribute certificate holder to set.
+ */
+ public void setAttributeCert(X509AttributeCertificateHolder attributeCert)
+ {
+ this.attributeCert = attributeCert;
+ }
+
+ /**
+ * Set the time, when the certificate must be valid. If <code>null</code>
+ * is given any will do.
+ *
+ * @param attributeCertificateValid The attribute certificate validation
+ * time to set.
+ */
+ public void setAttributeCertificateValid(Date attributeCertificateValid)
+ {
+ if (attributeCertificateValid != null)
+ {
+ this.attributeCertificateValid = new Date(attributeCertificateValid
+ .getTime());
+ }
+ else
+ {
+ this.attributeCertificateValid = null;
+ }
+ }
+
+ /**
+ * Sets the holder. If <code>null</code> is given any will do.
+ *
+ * @param holder The holder to set.
+ */
+ public void setHolder(AttributeCertificateHolder holder)
+ {
+ this.holder = holder;
+ }
+
+ /**
+ * Sets the issuer the attribute certificate must have. If <code>null</code>
+ * is given any will do.
+ *
+ * @param issuer The issuer to set.
+ */
+ public void setIssuer(AttributeCertificateIssuer issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ /**
+ * Sets the serial number the attribute certificate must have. If
+ * <code>null</code> is given any will do.
+ *
+ * @param serialNumber The serialNumber to set.
+ */
+ public void setSerialNumber(BigInteger serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ /**
+ * Adds a target name criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificateHolder</code>
+ * must contain at least one of the specified target names.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param name The name as a GeneralName (not <code>null</code>)
+ */
+ public void addTargetName(GeneralName name)
+ {
+ targetNames.add(name);
+ }
+
+ /**
+ * Adds a collection with target names criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of either GeneralName objects or byte[] arrays representing
+ * DER encoded GeneralName structures.
+ *
+ * @param names A collection of target names.
+ * @throws java.io.IOException if a parsing error occurs.
+ * @see #addTargetName(org.spongycastle.asn1.x509.GeneralName)
+ */
+ public void setTargetNames(Collection names) throws IOException
+ {
+ targetNames = extractGeneralNames(names);
+ }
+
+ /**
+ * Adds a target group criterion for the attribute certificate to the target
+ * information extension criteria. The <code>X509AttributeCertificateHolder</code>
+ * must contain at least one of the specified target groups.
+ * <p>
+ * Each attribute certificate may contain a target information extension
+ * limiting the servers where this attribute certificate can be used. If
+ * this extension is not present, the attribute certificate is not targeted
+ * and may be accepted by any server.
+ *
+ * @param group The group as GeneralName form (not <code>null</code>)
+ */
+ public void addTargetGroup(GeneralName group)
+ {
+ targetGroups.add(group);
+ }
+
+ /**
+ * Adds a collection with target groups criteria. If <code>null</code> is
+ * given any will do.
+ * <p>
+ * The collection consists of <code>GeneralName</code> objects or <code>byte[]</code representing DER
+ * encoded GeneralNames.
+ *
+ * @param names A collection of target groups.
+ * @throws java.io.IOException if a parsing error occurs.
+ * @see #addTargetGroup(org.spongycastle.asn1.x509.GeneralName)
+ */
+ public void setTargetGroups(Collection names) throws IOException
+ {
+ targetGroups = extractGeneralNames(names);
+ }
+
+ private Set extractGeneralNames(Collection names)
+ throws IOException
+ {
+ if (names == null || names.isEmpty())
+ {
+ return new HashSet();
+ }
+ Set temp = new HashSet();
+ for (Iterator it = names.iterator(); it.hasNext();)
+ {
+ temp.add(GeneralName.getInstance(it.next()));
+ }
+ return temp;
+ }
+
+ public X509AttributeCertificateHolderSelector build()
+ {
+ X509AttributeCertificateHolderSelector sel = new X509AttributeCertificateHolderSelector(
+ holder, issuer, serialNumber, attributeCertificateValid, attributeCert, Collections.unmodifiableCollection(new HashSet(targetNames)), Collections.unmodifiableCollection(new HashSet(targetGroups)));
+
+ return sel;
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java b/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java
new file mode 100644
index 00000000..8b6b88e3
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/cert/selector/X509CertificateHolderSelector.java
@@ -0,0 +1,152 @@
+package org.spongycastle.cert.selector;
+
+import java.math.BigInteger;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.cms.IssuerAndSerialNumber;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.Selector;
+
+/**
+ * a basic index for a X509CertificateHolder class
+ */
+public class X509CertificateHolderSelector
+ implements Selector
+{
+ private byte[] subjectKeyId;
+
+ private X500Name issuer;
+ private BigInteger serialNumber;
+
+ /**
+ * Construct a selector with the value of a public key's subjectKeyId.
+ *
+ * @param subjectKeyId a subjectKeyId
+ */
+ public X509CertificateHolderSelector(byte[] subjectKeyId)
+ {
+ this(null, null, subjectKeyId);
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ */
+ public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber)
+ {
+ this(issuer, serialNumber, null);
+ }
+
+ /**
+ * Construct a signer ID based on the issuer and serial number of the signer's associated
+ * certificate.
+ *
+ * @param issuer the issuer of the signer's associated certificate.
+ * @param serialNumber the serial number of the signer's associated certificate.
+ * @param subjectKeyId the subject key identifier to use to match the signers associated certificate.
+ */
+ public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ this.issuer = issuer;
+ this.serialNumber = serialNumber;
+ this.subjectKeyId = subjectKeyId;
+ }
+
+ public X500Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public byte[] getSubjectKeyIdentifier()
+ {
+ return Arrays.clone(subjectKeyId);
+ }
+
+ public int hashCode()
+ {
+ int code = Arrays.hashCode(subjectKeyId);
+
+ if (this.serialNumber != null)
+ {
+ code ^= this.serialNumber.hashCode();
+ }
+
+ if (this.issuer != null)
+ {
+ code ^= this.issuer.hashCode();
+ }
+
+ return code;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof X509CertificateHolderSelector))
+ {
+ return false;
+ }
+
+ X509CertificateHolderSelector id = (X509CertificateHolderSelector)o;
+
+ return Arrays.areEqual(subjectKeyId, id.subjectKeyId)
+ && equalsObj(this.serialNumber, id.serialNumber)
+ && equalsObj(this.issuer, id.issuer);
+ }
+
+ private boolean equalsObj(Object a, Object b)
+ {
+ return (a != null) ? a.equals(b) : b == null;
+ }
+
+ public boolean match(Object obj)
+ {
+ if (obj instanceof X509CertificateHolder)
+ {
+ X509CertificateHolder certHldr = (X509CertificateHolder)obj;
+
+ if (this.getSerialNumber() != null)
+ {
+ IssuerAndSerialNumber iAndS = new IssuerAndSerialNumber(certHldr.toASN1Structure());
+
+ return iAndS.getName().equals(this.issuer)
+ && iAndS.getSerialNumber().getValue().equals(this.serialNumber);
+ }
+ else if (subjectKeyId != null)
+ {
+ Extension ext = certHldr.getExtension(Extension.subjectKeyIdentifier);
+
+ if (ext == null)
+ {
+ return Arrays.areEqual(subjectKeyId, MSOutlookKeyIdCalculator.calculateKeyId(certHldr.getSubjectPublicKeyInfo()));
+ }
+
+ byte[] subKeyID = ASN1OctetString.getInstance(ext.getParsedValue()).getOctets();
+
+ return Arrays.areEqual(subjectKeyId, subKeyID);
+ }
+ }
+ else if (obj instanceof byte[])
+ {
+ return Arrays.areEqual(subjectKeyId, (byte[])obj);
+ }
+
+ return false;
+ }
+
+ public Object clone()
+ {
+ return new X509CertificateHolderSelector(this.issuer, this.serialNumber, this.subjectKeyId);
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
new file mode 100644
index 00000000..551000b0
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaSelectorConverter.java
@@ -0,0 +1,35 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.io.IOException;
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaSelectorConverter
+{
+ public JcaSelectorConverter()
+ {
+
+ }
+
+ public X509CertificateHolderSelector getCertificateHolderSelector(X509CertSelector certSelector)
+ {
+ try
+ {
+ if (certSelector.getSubjectKeyIdentifier() != null)
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber(), ASN1OctetString.getInstance(certSelector.getSubjectKeyIdentifier()).getOctets());
+ }
+ else
+ {
+ return new X509CertificateHolderSelector(X500Name.getInstance(certSelector.getIssuerAsBytes()), certSelector.getSerialNumber());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
new file mode 100644
index 00000000..6dbcef43
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertSelectorConverter.java
@@ -0,0 +1,57 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.X509CertSelector;
+
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaX509CertSelectorConverter
+{
+ public JcaX509CertSelectorConverter()
+ {
+ }
+
+ protected X509CertSelector doConversion(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyIdentifier)
+ {
+ X509CertSelector selector = new X509CertSelector();
+
+ if (issuer != null)
+ {
+ try
+ {
+ selector.setIssuer(issuer.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ if (serialNumber != null)
+ {
+ selector.setSerialNumber(serialNumber);
+ }
+
+ if (subjectKeyIdentifier != null)
+ {
+ try
+ {
+ selector.setSubjectKeyIdentifier(new DEROctetString(subjectKeyIdentifier).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to convert issuer: " + e.getMessage());
+ }
+ }
+
+ return selector;
+ }
+
+ public X509CertSelector getCertSelector(X509CertificateHolderSelector holderSelector)
+ {
+ return doConversion(holderSelector.getIssuer(), holderSelector.getSerialNumber(), holderSelector.getSubjectKeyIdentifier());
+ }
+}
diff --git a/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java
new file mode 100644
index 00000000..fd73a9fa
--- /dev/null
+++ b/pkix/src/main/java/org/spongycastle/cert/selector/jcajce/JcaX509CertificateHolderSelector.java
@@ -0,0 +1,72 @@
+package org.spongycastle.cert.selector.jcajce;
+
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.x500.X500Name;
+import org.spongycastle.asn1.x509.Extension;
+import org.spongycastle.cert.selector.X509CertificateHolderSelector;
+
+public class JcaX509CertificateHolderSelector
+ extends X509CertificateHolderSelector
+{
+ /**
+ * Construct a signer identifier based on the issuer, serial number and subject key identifier (if present) of the passed in
+ * certificate.
+ *
+ * @param certificate certificate providing the issue and serial number and subject key identifier.
+ */
+ public JcaX509CertificateHolderSelector(X509Certificate certificate)
+ {
+ super(convertPrincipal(certificate.getIssuerX500Principal()), certificate.getSerialNumber(), getSubjectKeyId(certificate));
+ }
+
+ /**
+ * Construct a signer identifier based on the provided issuer and serial number..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ */
+ public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber)
+ {
+ super(convertPrincipal(issuer), serialNumber);
+ }
+
+ /**
+ * Construct a signer identifier based on the provided issuer, serial number, and subjectKeyId..
+ *
+ * @param issuer the issuer to use.
+ * @param serialNumber the serial number to use.
+ * @param subjectKeyId the subject key ID to use.
+ */
+ public JcaX509CertificateHolderSelector(X500Principal issuer, BigInteger serialNumber, byte[] subjectKeyId)
+ {
+ super(convertPrincipal(issuer), serialNumber, subjectKeyId);
+ }
+
+ private static X500Name convertPrincipal(X500Principal issuer)
+ {
+ if (issuer == null)
+ {
+ return null;
+ }
+ return X500Name.getInstance(issuer.getEncoded());
+ }
+
+ private static byte[] getSubjectKeyId(X509Certificate cert)
+ {
+ byte[] ext = cert.getExtensionValue(Extension.subjectKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ return ASN1OctetString.getInstance(ASN1OctetString.getInstance(ext).getOctets()).getOctets();
+ }
+ else
+ {
+ return null;
+ }
+ }
+}