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