diff options
Diffstat (limited to 'pkix/src/main/java/org/spongycastle/cert/selector')
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; + } + } +} |