1 package org.bouncycastle.x509;
2 
3 import java.io.IOException;
4 import java.math.BigInteger;
5 import java.security.MessageDigest;
6 import java.security.Principal;
7 import java.security.cert.CertSelector;
8 import java.security.cert.Certificate;
9 import java.security.cert.CertificateEncodingException;
10 import java.security.cert.CertificateParsingException;
11 import java.security.cert.X509Certificate;
12 import java.util.ArrayList;
13 import java.util.List;
14 
15 import javax.security.auth.x500.X500Principal;
16 
17 import org.bouncycastle.asn1.ASN1Encodable;
18 import org.bouncycastle.asn1.ASN1Integer;
19 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
20 import org.bouncycastle.asn1.ASN1Sequence;
21 import org.bouncycastle.asn1.DERSequence;
22 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
23 import org.bouncycastle.asn1.x509.GeneralName;
24 import org.bouncycastle.asn1.x509.GeneralNames;
25 import org.bouncycastle.asn1.x509.Holder;
26 import org.bouncycastle.asn1.x509.IssuerSerial;
27 import org.bouncycastle.asn1.x509.ObjectDigestInfo;
28 import org.bouncycastle.jce.PrincipalUtil;
29 import org.bouncycastle.jce.X509Principal;
30 import org.bouncycastle.util.Arrays;
31 import 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  */
50 public class AttributeCertificateHolder
51     implements CertSelector, Selector
52 {
53     final Holder holder;
54 
AttributeCertificateHolder(ASN1Sequence seq)55     AttributeCertificateHolder(ASN1Sequence seq)
56     {
57         holder = Holder.getInstance(seq);
58     }
59 
AttributeCertificateHolder(X509Principal issuerName, BigInteger serialNumber)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 
AttributeCertificateHolder(X500Principal issuerName, BigInteger serialNumber)68     public AttributeCertificateHolder(X500Principal issuerName,
69         BigInteger serialNumber)
70     {
71         this(X509Util.convertPrincipal(issuerName), serialNumber);
72     }
73 
AttributeCertificateHolder(X509Certificate cert)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 
AttributeCertificateHolder(X509Principal principal)92     public AttributeCertificateHolder(X509Principal principal)
93     {
94         holder = new Holder(generateGeneralNames(principal));
95     }
96 
AttributeCertificateHolder(X500Principal principal)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      */
AttributeCertificateHolder(int digestedObjectType, String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)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(new ASN1ObjectIdentifier(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      */
getDigestedObjectType()147     public int getDigestedObjectType()
148     {
149         if (holder.getObjectDigestInfo() != null)
150         {
151             return holder.getObjectDigestInfo().getDigestedObjectType().intValueExact();
152         }
153         return -1;
154     }
155 
156     /**
157      * Returns the other object type ID if an object digest info is used.
158      *
159      * @return The other object type ID or <code>null</code> if no object
160      *         digest info is set.
161      */
getDigestAlgorithm()162     public String getDigestAlgorithm()
163     {
164         if (holder.getObjectDigestInfo() != null)
165         {
166             return holder.getObjectDigestInfo().getDigestAlgorithm().getAlgorithm()
167                 .getId();
168         }
169         return null;
170     }
171 
172     /**
173      * Returns the hash if an object digest info is used.
174      *
175      * @return The hash or <code>null</code> if no object digest info is set.
176      */
getObjectDigest()177     public byte[] getObjectDigest()
178     {
179         if (holder.getObjectDigestInfo() != null)
180         {
181             return holder.getObjectDigestInfo().getObjectDigest().getBytes();
182         }
183         return null;
184     }
185 
186     /**
187      * Returns the digest algorithm ID if an object digest info is used.
188      *
189      * @return The digest algorithm ID or <code>null</code> if no object
190      *         digest info is set.
191      */
getOtherObjectTypeID()192     public String getOtherObjectTypeID()
193     {
194         if (holder.getObjectDigestInfo() != null)
195         {
196             holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
197         }
198         return null;
199     }
200 
generateGeneralNames(X509Principal principal)201     private GeneralNames generateGeneralNames(X509Principal principal)
202     {
203         return GeneralNames.getInstance(new DERSequence(new GeneralName(principal)));
204     }
205 
matchesDN(X509Principal subject, GeneralNames targets)206     private boolean matchesDN(X509Principal subject, GeneralNames targets)
207     {
208         GeneralName[] names = targets.getNames();
209 
210         for (int i = 0; i != names.length; i++)
211         {
212             GeneralName gn = names[i];
213 
214             if (gn.getTagNo() == GeneralName.directoryName)
215             {
216                 try
217                 {
218                     if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
219                         .getEncoded()).equals(subject))
220                     {
221                         return true;
222                     }
223                 }
224                 catch (IOException e)
225                 {
226                 }
227             }
228         }
229 
230         return false;
231     }
232 
getNames(GeneralName[] names)233     private Object[] getNames(GeneralName[] names)
234     {
235         List l = new ArrayList(names.length);
236 
237         for (int i = 0; i != names.length; i++)
238         {
239             if (names[i].getTagNo() == GeneralName.directoryName)
240             {
241                 try
242                 {
243                     l.add(new X500Principal(
244                         ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
245                 }
246                 catch (IOException e)
247                 {
248                     throw new RuntimeException("badly formed Name object");
249                 }
250             }
251         }
252 
253         return l.toArray(new Object[l.size()]);
254     }
255 
getPrincipals(GeneralNames names)256     private Principal[] getPrincipals(GeneralNames names)
257     {
258         Object[] p = this.getNames(names.getNames());
259         List l = new ArrayList();
260 
261         for (int i = 0; i != p.length; i++)
262         {
263             if (p[i] instanceof Principal)
264             {
265                 l.add(p[i]);
266             }
267         }
268 
269         return (Principal[])l.toArray(new Principal[l.size()]);
270     }
271 
272     /**
273      * Return any principal objects inside the attribute certificate holder
274      * entity names field.
275      *
276      * @return an array of Principal objects (usually X500Principal), null if no
277      *         entity names field is set.
278      */
getEntityNames()279     public Principal[] getEntityNames()
280     {
281         if (holder.getEntityName() != null)
282         {
283             return getPrincipals(holder.getEntityName());
284         }
285 
286         return null;
287     }
288 
289     /**
290      * Return the principals associated with the issuer attached to this holder
291      *
292      * @return an array of principals, null if no BaseCertificateID is set.
293      */
getIssuer()294     public Principal[] getIssuer()
295     {
296         if (holder.getBaseCertificateID() != null)
297         {
298             return getPrincipals(holder.getBaseCertificateID().getIssuer());
299         }
300 
301         return null;
302     }
303 
304     /**
305      * Return the serial number associated with the issuer attached to this
306      * holder.
307      *
308      * @return the certificate serial number, null if no BaseCertificateID is
309      *         set.
310      */
getSerialNumber()311     public BigInteger getSerialNumber()
312     {
313         if (holder.getBaseCertificateID() != null)
314         {
315             return holder.getBaseCertificateID().getSerial().getValue();
316         }
317 
318         return null;
319     }
320 
clone()321     public Object clone()
322     {
323         return new AttributeCertificateHolder((ASN1Sequence)holder
324             .toASN1Primitive());
325     }
326 
match(Certificate cert)327     public boolean match(Certificate cert)
328     {
329         if (!(cert instanceof X509Certificate))
330         {
331             return false;
332         }
333 
334         X509Certificate x509Cert = (X509Certificate)cert;
335 
336         try
337         {
338             if (holder.getBaseCertificateID() != null)
339             {
340                 return holder.getBaseCertificateID().getSerial().hasValue(x509Cert.getSerialNumber())
341                     && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
342             }
343 
344             if (holder.getEntityName() != null)
345             {
346                 if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
347                     holder.getEntityName()))
348                 {
349                     return true;
350                 }
351             }
352             if (holder.getObjectDigestInfo() != null)
353             {
354                 MessageDigest md = null;
355                 try
356                 {
357                     md = MessageDigest.getInstance(getDigestAlgorithm(), "BC");
358 
359                 }
360                 catch (Exception e)
361                 {
362                     return false;
363                 }
364                 switch (getDigestedObjectType())
365                 {
366                 case ObjectDigestInfo.publicKey:
367                     // TODO: DSA Dss-parms
368                     md.update(cert.getPublicKey().getEncoded());
369                     break;
370                 case ObjectDigestInfo.publicKeyCert:
371                     md.update(cert.getEncoded());
372                     break;
373                 }
374                 if (!Arrays.areEqual(md.digest(), getObjectDigest()))
375                 {
376                     return false;
377                 }
378             }
379         }
380         catch (CertificateEncodingException e)
381         {
382             return false;
383         }
384 
385         return false;
386     }
387 
equals(Object obj)388     public boolean equals(Object obj)
389     {
390         if (obj == this)
391         {
392             return true;
393         }
394 
395         if (!(obj instanceof AttributeCertificateHolder))
396         {
397             return false;
398         }
399 
400         AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
401 
402         return this.holder.equals(other.holder);
403     }
404 
hashCode()405     public int hashCode()
406     {
407         return this.holder.hashCode();
408     }
409 
match(Object obj)410     public boolean match(Object obj)
411     {
412         if (!(obj instanceof X509Certificate))
413         {
414             return false;
415         }
416 
417         return match((Certificate)obj);
418     }
419 }
420