AttributeCertificateHolder.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.x509;
2
3import java.io.IOException;
4import java.math.BigInteger;
5import java.security.MessageDigest;
6import java.security.Principal;
7import java.security.cert.CertSelector;
8import java.security.cert.Certificate;
9import java.security.cert.CertificateEncodingException;
10import java.security.cert.CertificateParsingException;
11import java.security.cert.X509Certificate;
12import java.util.ArrayList;
13import java.util.List;
14
15import javax.security.auth.x500.X500Principal;
16
17import org.bouncycastle.asn1.ASN1Encodable;
18import org.bouncycastle.asn1.ASN1Integer;
19import org.bouncycastle.asn1.ASN1ObjectIdentifier;
20import org.bouncycastle.asn1.ASN1Sequence;
21import org.bouncycastle.asn1.DERSequence;
22import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
23import org.bouncycastle.asn1.x509.GeneralName;
24import org.bouncycastle.asn1.x509.GeneralNames;
25import org.bouncycastle.asn1.x509.Holder;
26import org.bouncycastle.asn1.x509.IssuerSerial;
27import org.bouncycastle.asn1.x509.ObjectDigestInfo;
28import org.bouncycastle.jce.PrincipalUtil;
29import org.bouncycastle.jce.X509Principal;
30import org.bouncycastle.util.Arrays;
31import org.bouncycastle.util.Selector;
32
33/**
34 * The Holder object.
35 *
36 * <pre>
37 *          Holder ::= SEQUENCE {
38 *                baseCertificateID   [0] IssuerSerial OPTIONAL,
39 *                         -- the issuer and serial number of
40 *                         -- the holder's Public Key Certificate
41 *                entityName          [1] GeneralNames OPTIONAL,
42 *                         -- the name of the claimant or role
43 *                objectDigestInfo    [2] ObjectDigestInfo OPTIONAL
44 *                         -- used to directly authenticate the holder,
45 *                         -- for example, an executable
46 *          }
47 * </pre>
48 * @deprecated use org.bouncycastle.cert.AttributeCertificateHolder
49 */
50public class AttributeCertificateHolder
51    implements CertSelector, Selector
52{
53    final Holder holder;
54
55    AttributeCertificateHolder(ASN1Sequence seq)
56    {
57        holder = Holder.getInstance(seq);
58    }
59
60    public AttributeCertificateHolder(X509Principal issuerName,
61        BigInteger serialNumber)
62    {
63        holder = new org.bouncycastle.asn1.x509.Holder(new IssuerSerial(
64            GeneralNames.getInstance(new DERSequence(new GeneralName(issuerName))),
65            new ASN1Integer(serialNumber)));
66    }
67
68    public AttributeCertificateHolder(X500Principal issuerName,
69        BigInteger serialNumber)
70    {
71        this(X509Util.convertPrincipal(issuerName), serialNumber);
72    }
73
74    public AttributeCertificateHolder(X509Certificate cert)
75        throws CertificateParsingException
76    {
77        X509Principal name;
78
79        try
80        {
81            name = PrincipalUtil.getIssuerX509Principal(cert);
82        }
83        catch (Exception e)
84        {
85            throw new CertificateParsingException(e.getMessage());
86        }
87
88        holder = new Holder(new IssuerSerial(generateGeneralNames(name),
89            new ASN1Integer(cert.getSerialNumber())));
90    }
91
92    public AttributeCertificateHolder(X509Principal principal)
93    {
94        holder = new Holder(generateGeneralNames(principal));
95    }
96
97    public AttributeCertificateHolder(X500Principal principal)
98    {
99        this(X509Util.convertPrincipal(principal));
100    }
101
102    /**
103     * Constructs a holder for v2 attribute certificates with a hash value for
104     * some type of object.
105     * <p>
106     * <code>digestedObjectType</code> can be one of the following:
107     * <ul>
108     * <li>0 - publicKey - A hash of the public key of the holder must be
109     * passed.
110     * <li>1 - publicKeyCert - A hash of the public key certificate of the
111     * holder must be passed.
112     * <li>2 - otherObjectDigest - A hash of some other object type must be
113     * passed. <code>otherObjectTypeID</code> must not be empty.
114     * </ul>
115     * <p>
116     * This cannot be used if a v1 attribute certificate is used.
117     *
118     * @param digestedObjectType The digest object type.
119     * @param digestAlgorithm The algorithm identifier for the hash.
120     * @param otherObjectTypeID The object type ID if
121     *            <code>digestedObjectType</code> is
122     *            <code>otherObjectDigest</code>.
123     * @param objectDigest The hash value.
124     */
125    public AttributeCertificateHolder(int digestedObjectType,
126        String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
127    {
128        holder = new Holder(new ObjectDigestInfo(digestedObjectType,
129            new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays
130                .clone(objectDigest)));
131    }
132
133    /**
134     * Returns the digest object type if an object digest info is used.
135     * <p>
136     * <ul>
137     * <li>0 - publicKey - A hash of the public key of the holder must be
138     * passed.
139     * <li>1 - publicKeyCert - A hash of the public key certificate of the
140     * holder must be passed.
141     * <li>2 - otherObjectDigest - A hash of some other object type must be
142     * passed. <code>otherObjectTypeID</code> must not be empty.
143     * </ul>
144     *
145     * @return The digest object type or -1 if no object digest info is set.
146     */
147    public int getDigestedObjectType()
148    {
149        if (holder.getObjectDigestInfo() != null)
150        {
151            return holder.getObjectDigestInfo().getDigestedObjectType()
152                .getValue().intValue();
153        }
154        return -1;
155    }
156
157    /**
158     * Returns the other object type ID if an object digest info is used.
159     *
160     * @return The other object type ID or <code>null</code> if no object
161     *         digest info is set.
162     */
163    public String getDigestAlgorithm()
164    {
165        if (holder.getObjectDigestInfo() != null)
166        {
167            return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
168                .getId();
169        }
170        return null;
171    }
172
173    /**
174     * Returns the hash if an object digest info is used.
175     *
176     * @return The hash or <code>null</code> if no object digest info is set.
177     */
178    public byte[] getObjectDigest()
179    {
180        if (holder.getObjectDigestInfo() != null)
181        {
182            return holder.getObjectDigestInfo().getObjectDigest().getBytes();
183        }
184        return null;
185    }
186
187    /**
188     * Returns the digest algorithm ID if an object digest info is used.
189     *
190     * @return The digest algorithm ID or <code>null</code> if no object
191     *         digest info is set.
192     */
193    public String getOtherObjectTypeID()
194    {
195        if (holder.getObjectDigestInfo() != null)
196        {
197            holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
198        }
199        return null;
200    }
201
202    private GeneralNames generateGeneralNames(X509Principal principal)
203    {
204        return GeneralNames.getInstance(new DERSequence(new GeneralName(principal)));
205    }
206
207    private boolean matchesDN(X509Principal subject, GeneralNames targets)
208    {
209        GeneralName[] names = targets.getNames();
210
211        for (int i = 0; i != names.length; i++)
212        {
213            GeneralName gn = names[i];
214
215            if (gn.getTagNo() == GeneralName.directoryName)
216            {
217                try
218                {
219                    if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
220                        .getEncoded()).equals(subject))
221                    {
222                        return true;
223                    }
224                }
225                catch (IOException e)
226                {
227                }
228            }
229        }
230
231        return false;
232    }
233
234    private Object[] getNames(GeneralName[] names)
235    {
236        List l = new ArrayList(names.length);
237
238        for (int i = 0; i != names.length; i++)
239        {
240            if (names[i].getTagNo() == GeneralName.directoryName)
241            {
242                try
243                {
244                    l.add(new X500Principal(
245                        ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
246                }
247                catch (IOException e)
248                {
249                    throw new RuntimeException("badly formed Name object");
250                }
251            }
252        }
253
254        return l.toArray(new Object[l.size()]);
255    }
256
257    private Principal[] getPrincipals(GeneralNames names)
258    {
259        Object[] p = this.getNames(names.getNames());
260        List l = new ArrayList();
261
262        for (int i = 0; i != p.length; i++)
263        {
264            if (p[i] instanceof Principal)
265            {
266                l.add(p[i]);
267            }
268        }
269
270        return (Principal[])l.toArray(new Principal[l.size()]);
271    }
272
273    /**
274     * Return any principal objects inside the attribute certificate holder
275     * entity names field.
276     *
277     * @return an array of Principal objects (usually X500Principal), null if no
278     *         entity names field is set.
279     */
280    public Principal[] getEntityNames()
281    {
282        if (holder.getEntityName() != null)
283        {
284            return getPrincipals(holder.getEntityName());
285        }
286
287        return null;
288    }
289
290    /**
291     * Return the principals associated with the issuer attached to this holder
292     *
293     * @return an array of principals, null if no BaseCertificateID is set.
294     */
295    public Principal[] getIssuer()
296    {
297        if (holder.getBaseCertificateID() != null)
298        {
299            return getPrincipals(holder.getBaseCertificateID().getIssuer());
300        }
301
302        return null;
303    }
304
305    /**
306     * Return the serial number associated with the issuer attached to this
307     * holder.
308     *
309     * @return the certificate serial number, null if no BaseCertificateID is
310     *         set.
311     */
312    public BigInteger getSerialNumber()
313    {
314        if (holder.getBaseCertificateID() != null)
315        {
316            return holder.getBaseCertificateID().getSerial().getValue();
317        }
318
319        return null;
320    }
321
322    public Object clone()
323    {
324        return new AttributeCertificateHolder((ASN1Sequence)holder
325            .toASN1Object());
326    }
327
328    public boolean match(Certificate cert)
329    {
330        if (!(cert instanceof X509Certificate))
331        {
332            return false;
333        }
334
335        X509Certificate x509Cert = (X509Certificate)cert;
336
337        try
338        {
339            if (holder.getBaseCertificateID() != null)
340            {
341                return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
342                    && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
343            }
344
345            if (holder.getEntityName() != null)
346            {
347                if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
348                    holder.getEntityName()))
349                {
350                    return true;
351                }
352            }
353            if (holder.getObjectDigestInfo() != null)
354            {
355                MessageDigest md = null;
356                try
357                {
358                    md = MessageDigest.getInstance(getDigestAlgorithm(), "BC");
359
360                }
361                catch (Exception e)
362                {
363                    return false;
364                }
365                switch (getDigestedObjectType())
366                {
367                case ObjectDigestInfo.publicKey:
368                    // TODO: DSA Dss-parms
369                    md.update(cert.getPublicKey().getEncoded());
370                    break;
371                case ObjectDigestInfo.publicKeyCert:
372                    md.update(cert.getEncoded());
373                    break;
374                }
375                if (!Arrays.areEqual(md.digest(), getObjectDigest()))
376                {
377                    return false;
378                }
379            }
380        }
381        catch (CertificateEncodingException e)
382        {
383            return false;
384        }
385
386        return false;
387    }
388
389    public boolean equals(Object obj)
390    {
391        if (obj == this)
392        {
393            return true;
394        }
395
396        if (!(obj instanceof AttributeCertificateHolder))
397        {
398            return false;
399        }
400
401        AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
402
403        return this.holder.equals(other.holder);
404    }
405
406    public int hashCode()
407    {
408        return this.holder.hashCode();
409    }
410
411    public boolean match(Object obj)
412    {
413        if (!(obj instanceof X509Certificate))
414        {
415            return false;
416        }
417
418        return match((Certificate)obj);
419    }
420}
421