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