Home | History | Annotate | Download | only in x509
      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 
     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