1package org.bouncycastle.cert.selector;
2
3import java.math.BigInteger;
4
5import org.bouncycastle.asn1.ASN1OctetString;
6import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
7import org.bouncycastle.asn1.x500.X500Name;
8import org.bouncycastle.asn1.x509.Extension;
9import org.bouncycastle.cert.X509CertificateHolder;
10import org.bouncycastle.util.Arrays;
11import org.bouncycastle.util.Selector;
12
13/**
14 * a basic index for a X509CertificateHolder class
15 */
16public class X509CertificateHolderSelector
17    implements Selector
18{
19    private byte[] subjectKeyId;
20
21    private X500Name issuer;
22    private BigInteger serialNumber;
23
24    /**
25     * Construct a selector with the value of a public key's subjectKeyId.
26     *
27     * @param subjectKeyId a subjectKeyId
28     */
29    public X509CertificateHolderSelector(byte[] subjectKeyId)
30    {
31        this(null, null, subjectKeyId);
32    }
33
34    /**
35     * Construct a signer ID based on the issuer and serial number of the signer's associated
36     * certificate.
37     *
38     * @param issuer the issuer of the signer's associated certificate.
39     * @param serialNumber the serial number of the signer's associated certificate.
40     */
41    public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber)
42    {
43        this(issuer, serialNumber, null);
44    }
45
46    /**
47     * Construct a signer ID based on the issuer and serial number of the signer's associated
48     * certificate.
49     *
50     * @param issuer the issuer of the signer's associated certificate.
51     * @param serialNumber the serial number of the signer's associated certificate.
52     * @param subjectKeyId the subject key identifier to use to match the signers associated certificate.
53     */
54    public X509CertificateHolderSelector(X500Name issuer, BigInteger serialNumber, byte[] subjectKeyId)
55    {
56        this.issuer = issuer;
57        this.serialNumber = serialNumber;
58        this.subjectKeyId = subjectKeyId;
59    }
60
61    public X500Name getIssuer()
62    {
63        return issuer;
64    }
65
66    public BigInteger getSerialNumber()
67    {
68        return serialNumber;
69    }
70
71    public byte[] getSubjectKeyIdentifier()
72    {
73        return Arrays.clone(subjectKeyId);
74    }
75
76    public int hashCode()
77    {
78        int code = Arrays.hashCode(subjectKeyId);
79
80        if (this.serialNumber != null)
81        {
82            code ^= this.serialNumber.hashCode();
83        }
84
85        if (this.issuer != null)
86        {
87            code ^= this.issuer.hashCode();
88        }
89
90        return code;
91    }
92
93    public boolean equals(
94        Object  o)
95    {
96        if (!(o instanceof X509CertificateHolderSelector))
97        {
98            return false;
99        }
100
101        X509CertificateHolderSelector id = (X509CertificateHolderSelector)o;
102
103        return Arrays.areEqual(subjectKeyId, id.subjectKeyId)
104            && equalsObj(this.serialNumber, id.serialNumber)
105            && equalsObj(this.issuer, id.issuer);
106    }
107
108    private boolean equalsObj(Object a, Object b)
109    {
110        return (a != null) ? a.equals(b) : b == null;
111    }
112
113    public boolean match(Object obj)
114    {
115        if (obj instanceof X509CertificateHolder)
116        {
117            X509CertificateHolder certHldr = (X509CertificateHolder)obj;
118
119            if (this.getSerialNumber() != null)
120            {
121                IssuerAndSerialNumber iAndS = new IssuerAndSerialNumber(certHldr.toASN1Structure());
122
123                return iAndS.getName().equals(this.issuer)
124                    && iAndS.getSerialNumber().getValue().equals(this.serialNumber);
125            }
126            else if (subjectKeyId != null)
127            {
128                Extension ext = certHldr.getExtension(Extension.subjectKeyIdentifier);
129
130                if (ext == null)
131                {
132                    return Arrays.areEqual(subjectKeyId, MSOutlookKeyIdCalculator.calculateKeyId(certHldr.getSubjectPublicKeyInfo()));
133                }
134
135                byte[] subKeyID = ASN1OctetString.getInstance(ext.getParsedValue()).getOctets();
136
137                return Arrays.areEqual(subjectKeyId, subKeyID);
138            }
139        }
140        else if (obj instanceof byte[])
141        {
142            return Arrays.areEqual(subjectKeyId, (byte[])obj);
143        }
144
145        return false;
146    }
147
148    public Object clone()
149    {
150        return new X509CertificateHolderSelector(this.issuer, this.serialNumber, this.subjectKeyId);
151    }
152}
153