Home | History | Annotate | Download | only in provider
      1 package org.bouncycastle.jce.provider;
      2 
      3 import java.io.ByteArrayOutputStream;
      4 import java.io.IOException;
      5 import java.math.BigInteger;
      6 import java.net.InetAddress;
      7 import java.net.UnknownHostException;
      8 import java.security.InvalidKeyException;
      9 import java.security.NoSuchAlgorithmException;
     10 import java.security.NoSuchProviderException;
     11 import java.security.Principal;
     12 import java.security.Provider;
     13 import java.security.PublicKey;
     14 import java.security.Security;
     15 import java.security.Signature;
     16 import java.security.SignatureException;
     17 import java.security.cert.Certificate;
     18 import java.security.cert.CertificateEncodingException;
     19 import java.security.cert.CertificateException;
     20 import java.security.cert.CertificateExpiredException;
     21 import java.security.cert.CertificateNotYetValidException;
     22 import java.security.cert.CertificateParsingException;
     23 import java.security.cert.X509Certificate;
     24 import java.util.ArrayList;
     25 import java.util.Collection;
     26 import java.util.Collections;
     27 import java.util.Date;
     28 import java.util.Enumeration;
     29 import java.util.HashSet;
     30 import java.util.List;
     31 import java.util.Set;
     32 
     33 import javax.security.auth.x500.X500Principal;
     34 
     35 import org.bouncycastle.asn1.ASN1Encodable;
     36 import org.bouncycastle.asn1.ASN1Encoding;
     37 import org.bouncycastle.asn1.ASN1InputStream;
     38 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     39 import org.bouncycastle.asn1.ASN1OutputStream;
     40 import org.bouncycastle.asn1.ASN1Primitive;
     41 import org.bouncycastle.asn1.ASN1Sequence;
     42 import org.bouncycastle.asn1.ASN1String;
     43 import org.bouncycastle.asn1.DERBitString;
     44 import org.bouncycastle.asn1.DERIA5String;
     45 import org.bouncycastle.asn1.DERNull;
     46 import org.bouncycastle.asn1.DEROctetString;
     47 import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
     48 import org.bouncycastle.asn1.misc.NetscapeCertType;
     49 import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
     50 import org.bouncycastle.asn1.misc.VerisignCzagExtension;
     51 import org.bouncycastle.asn1.util.ASN1Dump;
     52 import org.bouncycastle.asn1.x500.X500Name;
     53 import org.bouncycastle.asn1.x500.style.RFC4519Style;
     54 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     55 import org.bouncycastle.asn1.x509.BasicConstraints;
     56 import org.bouncycastle.asn1.x509.Extension;
     57 import org.bouncycastle.asn1.x509.Extensions;
     58 import org.bouncycastle.asn1.x509.GeneralName;
     59 import org.bouncycastle.asn1.x509.KeyUsage;
     60 // BEGIN android-added
     61 import org.bouncycastle.asn1.x509.X509Name;
     62 // END android-added
     63 import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
     64 import org.bouncycastle.jce.X509Principal;
     65 import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
     66 import org.bouncycastle.util.Arrays;
     67 import org.bouncycastle.util.Integers;
     68 import org.bouncycastle.util.encoders.Hex;
     69 
     70 public class X509CertificateObject
     71     extends X509Certificate
     72     implements PKCS12BagAttributeCarrier
     73 {
     74     private org.bouncycastle.asn1.x509.Certificate    c;
     75     private BasicConstraints            basicConstraints;
     76     private boolean[]                   keyUsage;
     77     private boolean                     hashValueSet;
     78     private int                         hashValue;
     79 
     80     private PKCS12BagAttributeCarrier   attrCarrier = new PKCS12BagAttributeCarrierImpl();
     81 
     82     public X509CertificateObject(
     83         org.bouncycastle.asn1.x509.Certificate    c)
     84         throws CertificateParsingException
     85     {
     86         this.c = c;
     87 
     88         try
     89         {
     90             byte[]  bytes = this.getExtensionBytes("2.5.29.19");
     91 
     92             if (bytes != null)
     93             {
     94                 basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
     95             }
     96         }
     97         catch (Exception e)
     98         {
     99             throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
    100         }
    101 
    102         try
    103         {
    104             byte[] bytes = this.getExtensionBytes("2.5.29.15");
    105             if (bytes != null)
    106             {
    107                 DERBitString    bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
    108 
    109                 bytes = bits.getBytes();
    110                 int length = (bytes.length * 8) - bits.getPadBits();
    111 
    112                 keyUsage = new boolean[(length < 9) ? 9 : length];
    113 
    114                 for (int i = 0; i != length; i++)
    115                 {
    116                     keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
    117                 }
    118             }
    119             else
    120             {
    121                 keyUsage = null;
    122             }
    123         }
    124         catch (Exception e)
    125         {
    126             throw new CertificateParsingException("cannot construct KeyUsage: " + e);
    127         }
    128     }
    129 
    130     public void checkValidity()
    131         throws CertificateExpiredException, CertificateNotYetValidException
    132     {
    133         this.checkValidity(new Date());
    134     }
    135 
    136     public void checkValidity(
    137         Date    date)
    138         throws CertificateExpiredException, CertificateNotYetValidException
    139     {
    140         if (date.getTime() > this.getNotAfter().getTime())  // for other VM compatibility
    141         {
    142             throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
    143         }
    144 
    145         if (date.getTime() < this.getNotBefore().getTime())
    146         {
    147             throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
    148         }
    149     }
    150 
    151     public int getVersion()
    152     {
    153         return c.getVersionNumber();
    154     }
    155 
    156     public BigInteger getSerialNumber()
    157     {
    158         return c.getSerialNumber().getValue();
    159     }
    160 
    161     public Principal getIssuerDN()
    162     {
    163         try
    164         {
    165             return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
    166         }
    167         catch (IOException e)
    168         {
    169             return null;
    170         }
    171     }
    172 
    173     public X500Principal getIssuerX500Principal()
    174     {
    175         try
    176         {
    177             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
    178             ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
    179 
    180             aOut.writeObject(c.getIssuer());
    181 
    182             return new X500Principal(bOut.toByteArray());
    183         }
    184         catch (IOException e)
    185         {
    186             throw new IllegalStateException("can't encode issuer DN");
    187         }
    188     }
    189 
    190     public Principal getSubjectDN()
    191     {
    192         return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
    193     }
    194 
    195     public X500Principal getSubjectX500Principal()
    196     {
    197         try
    198         {
    199             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
    200             ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
    201 
    202             aOut.writeObject(c.getSubject());
    203 
    204             return new X500Principal(bOut.toByteArray());
    205         }
    206         catch (IOException e)
    207         {
    208             throw new IllegalStateException("can't encode issuer DN");
    209         }
    210     }
    211 
    212     public Date getNotBefore()
    213     {
    214         return c.getStartDate().getDate();
    215     }
    216 
    217     public Date getNotAfter()
    218     {
    219         return c.getEndDate().getDate();
    220     }
    221 
    222     public byte[] getTBSCertificate()
    223         throws CertificateEncodingException
    224     {
    225         try
    226         {
    227             return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
    228         }
    229         catch (IOException e)
    230         {
    231             throw new CertificateEncodingException(e.toString());
    232         }
    233     }
    234 
    235     public byte[] getSignature()
    236     {
    237         return c.getSignature().getBytes();
    238     }
    239 
    240     /**
    241      * return a more "meaningful" representation for the signature algorithm used in
    242      * the certficate.
    243      */
    244     public String getSigAlgName()
    245     {
    246         Provider    prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
    247 
    248         if (prov != null)
    249         {
    250             String      algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
    251 
    252             if (algName != null)
    253             {
    254                 return algName;
    255             }
    256         }
    257 
    258         Provider[] provs = Security.getProviders();
    259 
    260         //
    261         // search every provider looking for a real algorithm
    262         //
    263         for (int i = 0; i != provs.length; i++)
    264         {
    265             String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
    266             if (algName != null)
    267             {
    268                 return algName;
    269             }
    270         }
    271 
    272         return this.getSigAlgOID();
    273     }
    274 
    275     /**
    276      * return the object identifier for the signature.
    277      */
    278     public String getSigAlgOID()
    279     {
    280         return c.getSignatureAlgorithm().getAlgorithm().getId();
    281     }
    282 
    283     /**
    284      * return the signature parameters, or null if there aren't any.
    285      */
    286     public byte[] getSigAlgParams()
    287     {
    288         if (c.getSignatureAlgorithm().getParameters() != null)
    289         {
    290             try
    291             {
    292                 return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
    293             }
    294             catch (IOException e)
    295             {
    296                 return null;
    297             }
    298         }
    299         else
    300         {
    301             return null;
    302         }
    303     }
    304 
    305     public boolean[] getIssuerUniqueID()
    306     {
    307         DERBitString    id = c.getTBSCertificate().getIssuerUniqueId();
    308 
    309         if (id != null)
    310         {
    311             byte[]          bytes = id.getBytes();
    312             boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
    313 
    314             for (int i = 0; i != boolId.length; i++)
    315             {
    316                 boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
    317             }
    318 
    319             return boolId;
    320         }
    321 
    322         return null;
    323     }
    324 
    325     public boolean[] getSubjectUniqueID()
    326     {
    327         DERBitString    id = c.getTBSCertificate().getSubjectUniqueId();
    328 
    329         if (id != null)
    330         {
    331             byte[]          bytes = id.getBytes();
    332             boolean[]       boolId = new boolean[bytes.length * 8 - id.getPadBits()];
    333 
    334             for (int i = 0; i != boolId.length; i++)
    335             {
    336                 boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
    337             }
    338 
    339             return boolId;
    340         }
    341 
    342         return null;
    343     }
    344 
    345     public boolean[] getKeyUsage()
    346     {
    347         return keyUsage;
    348     }
    349 
    350     public List getExtendedKeyUsage()
    351         throws CertificateParsingException
    352     {
    353         byte[]  bytes = this.getExtensionBytes("2.5.29.37");
    354 
    355         if (bytes != null)
    356         {
    357             try
    358             {
    359                 ASN1InputStream dIn = new ASN1InputStream(bytes);
    360                 ASN1Sequence    seq = (ASN1Sequence)dIn.readObject();
    361                 List            list = new ArrayList();
    362 
    363                 for (int i = 0; i != seq.size(); i++)
    364                 {
    365                     list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId());
    366                 }
    367 
    368                 return Collections.unmodifiableList(list);
    369             }
    370             catch (Exception e)
    371             {
    372                 throw new CertificateParsingException("error processing extended key usage extension");
    373             }
    374         }
    375 
    376         return null;
    377     }
    378 
    379     public int getBasicConstraints()
    380     {
    381         if (basicConstraints != null)
    382         {
    383             if (basicConstraints.isCA())
    384             {
    385                 if (basicConstraints.getPathLenConstraint() == null)
    386                 {
    387                     return Integer.MAX_VALUE;
    388                 }
    389                 else
    390                 {
    391                     return basicConstraints.getPathLenConstraint().intValue();
    392                 }
    393             }
    394             else
    395             {
    396                 return -1;
    397             }
    398         }
    399 
    400         return -1;
    401     }
    402 
    403     public Collection getSubjectAlternativeNames()
    404         throws CertificateParsingException
    405     {
    406         return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId()));
    407     }
    408 
    409     public Collection getIssuerAlternativeNames()
    410         throws CertificateParsingException
    411     {
    412         return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId()));
    413     }
    414 
    415     public Set getCriticalExtensionOIDs()
    416     {
    417         if (this.getVersion() == 3)
    418         {
    419             Set             set = new HashSet();
    420             Extensions  extensions = c.getTBSCertificate().getExtensions();
    421 
    422             if (extensions != null)
    423             {
    424                 Enumeration     e = extensions.oids();
    425 
    426                 while (e.hasMoreElements())
    427                 {
    428                     ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
    429                     Extension       ext = extensions.getExtension(oid);
    430 
    431                     if (ext.isCritical())
    432                     {
    433                         set.add(oid.getId());
    434                     }
    435                 }
    436 
    437                 return set;
    438             }
    439         }
    440 
    441         return null;
    442     }
    443 
    444     private byte[] getExtensionBytes(String oid)
    445     {
    446         Extensions exts = c.getTBSCertificate().getExtensions();
    447 
    448         if (exts != null)
    449         {
    450             Extension   ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
    451             if (ext != null)
    452             {
    453                 return ext.getExtnValue().getOctets();
    454             }
    455         }
    456 
    457         return null;
    458     }
    459 
    460     public byte[] getExtensionValue(String oid)
    461     {
    462         Extensions exts = c.getTBSCertificate().getExtensions();
    463 
    464         if (exts != null)
    465         {
    466             Extension   ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
    467 
    468             if (ext != null)
    469             {
    470                 try
    471                 {
    472                     return ext.getExtnValue().getEncoded();
    473                 }
    474                 catch (Exception e)
    475                 {
    476                     throw new IllegalStateException("error parsing " + e.toString());
    477                 }
    478             }
    479         }
    480 
    481         return null;
    482     }
    483 
    484     public Set getNonCriticalExtensionOIDs()
    485     {
    486         if (this.getVersion() == 3)
    487         {
    488             Set             set = new HashSet();
    489             Extensions  extensions = c.getTBSCertificate().getExtensions();
    490 
    491             if (extensions != null)
    492             {
    493                 Enumeration     e = extensions.oids();
    494 
    495                 while (e.hasMoreElements())
    496                 {
    497                     ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
    498                     Extension       ext = extensions.getExtension(oid);
    499 
    500                     if (!ext.isCritical())
    501                     {
    502                         set.add(oid.getId());
    503                     }
    504                 }
    505 
    506                 return set;
    507             }
    508         }
    509 
    510         return null;
    511     }
    512 
    513     public boolean hasUnsupportedCriticalExtension()
    514     {
    515         if (this.getVersion() == 3)
    516         {
    517             Extensions  extensions = c.getTBSCertificate().getExtensions();
    518 
    519             if (extensions != null)
    520             {
    521                 Enumeration     e = extensions.oids();
    522 
    523                 while (e.hasMoreElements())
    524                 {
    525                     ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
    526                     String              oidId = oid.getId();
    527 
    528                     if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
    529                      || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
    530                      || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
    531                      || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
    532                      || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
    533                      || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
    534                      || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
    535                      || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
    536                      || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
    537                      || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
    538                      || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
    539                     {
    540                         continue;
    541                     }
    542 
    543                     Extension       ext = extensions.getExtension(oid);
    544 
    545                     if (ext.isCritical())
    546                     {
    547                         return true;
    548                     }
    549                 }
    550             }
    551         }
    552 
    553         return false;
    554     }
    555 
    556     public PublicKey getPublicKey()
    557     {
    558         try
    559         {
    560             return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
    561         }
    562         catch (IOException e)
    563         {
    564             return null;   // should never happen...
    565         }
    566     }
    567 
    568     // BEGIN android-changed
    569     private byte[] encoded;
    570     // END android-changed
    571     public byte[] getEncoded()
    572         throws CertificateEncodingException
    573     {
    574         try
    575         {
    576             // BEGIN android-changed
    577             if (encoded == null) {
    578                 encoded = c.getEncoded(ASN1Encoding.DER);
    579             }
    580             return encoded;
    581             // END android-changed
    582         }
    583         catch (IOException e)
    584         {
    585             throw new CertificateEncodingException(e.toString());
    586         }
    587     }
    588 
    589     public boolean equals(
    590         Object o)
    591     {
    592         if (o == this)
    593         {
    594             return true;
    595         }
    596 
    597         if (!(o instanceof Certificate))
    598         {
    599             return false;
    600         }
    601 
    602         Certificate other = (Certificate)o;
    603 
    604         try
    605         {
    606             byte[] b1 = this.getEncoded();
    607             byte[] b2 = other.getEncoded();
    608 
    609             return Arrays.areEqual(b1, b2);
    610         }
    611         catch (CertificateEncodingException e)
    612         {
    613             return false;
    614         }
    615     }
    616 
    617     public synchronized int hashCode()
    618     {
    619         if (!hashValueSet)
    620         {
    621             hashValue = calculateHashCode();
    622             hashValueSet = true;
    623         }
    624 
    625         return hashValue;
    626     }
    627 
    628     private int calculateHashCode()
    629     {
    630         try
    631         {
    632             int hashCode = 0;
    633             byte[] certData = this.getEncoded();
    634             for (int i = 1; i < certData.length; i++)
    635             {
    636                  hashCode += certData[i] * i;
    637             }
    638             return hashCode;
    639         }
    640         catch (CertificateEncodingException e)
    641         {
    642             return 0;
    643         }
    644     }
    645 
    646     public void setBagAttribute(
    647         ASN1ObjectIdentifier oid,
    648         ASN1Encodable        attribute)
    649     {
    650         attrCarrier.setBagAttribute(oid, attribute);
    651     }
    652 
    653     public ASN1Encodable getBagAttribute(
    654         ASN1ObjectIdentifier oid)
    655     {
    656         return attrCarrier.getBagAttribute(oid);
    657     }
    658 
    659     public Enumeration getBagAttributeKeys()
    660     {
    661         return attrCarrier.getBagAttributeKeys();
    662     }
    663 
    664     public String toString()
    665     {
    666         StringBuffer    buf = new StringBuffer();
    667         String          nl = System.getProperty("line.separator");
    668 
    669         buf.append("  [0]         Version: ").append(this.getVersion()).append(nl);
    670         buf.append("         SerialNumber: ").append(this.getSerialNumber()).append(nl);
    671         buf.append("             IssuerDN: ").append(this.getIssuerDN()).append(nl);
    672         buf.append("           Start Date: ").append(this.getNotBefore()).append(nl);
    673         buf.append("           Final Date: ").append(this.getNotAfter()).append(nl);
    674         buf.append("            SubjectDN: ").append(this.getSubjectDN()).append(nl);
    675         buf.append("           Public Key: ").append(this.getPublicKey()).append(nl);
    676         buf.append("  Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
    677 
    678         byte[]  sig = this.getSignature();
    679 
    680         buf.append("            Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
    681         for (int i = 20; i < sig.length; i += 20)
    682         {
    683             if (i < sig.length - 20)
    684             {
    685                 buf.append("                       ").append(new String(Hex.encode(sig, i, 20))).append(nl);
    686             }
    687             else
    688             {
    689                 buf.append("                       ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
    690             }
    691         }
    692 
    693         Extensions extensions = c.getTBSCertificate().getExtensions();
    694 
    695         if (extensions != null)
    696         {
    697             Enumeration     e = extensions.oids();
    698 
    699             if (e.hasMoreElements())
    700             {
    701                 buf.append("       Extensions: \n");
    702             }
    703 
    704             while (e.hasMoreElements())
    705             {
    706                 ASN1ObjectIdentifier     oid = (ASN1ObjectIdentifier)e.nextElement();
    707                 Extension ext = extensions.getExtension(oid);
    708 
    709                 if (ext.getExtnValue() != null)
    710                 {
    711                     byte[]                  octs = ext.getExtnValue().getOctets();
    712                     ASN1InputStream         dIn = new ASN1InputStream(octs);
    713                     buf.append("                       critical(").append(ext.isCritical()).append(") ");
    714                     try
    715                     {
    716                         if (oid.equals(Extension.basicConstraints))
    717                         {
    718                             buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
    719                         }
    720                         else if (oid.equals(Extension.keyUsage))
    721                         {
    722                             buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl);
    723                         }
    724                         else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
    725                         {
    726                             buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
    727                         }
    728                         else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
    729                         {
    730                             buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
    731                         }
    732                         else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
    733                         {
    734                             buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
    735                         }
    736                         else
    737                         {
    738                             buf.append(oid.getId());
    739                             buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
    740                             //buf.append(" value = ").append("*****").append(nl);
    741                         }
    742                     }
    743                     catch (Exception ex)
    744                     {
    745                         buf.append(oid.getId());
    746                    //     buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl);
    747                         buf.append(" value = ").append("*****").append(nl);
    748                     }
    749                 }
    750                 else
    751                 {
    752                     buf.append(nl);
    753                 }
    754             }
    755         }
    756 
    757         return buf.toString();
    758     }
    759 
    760     public final void verify(
    761         PublicKey   key)
    762         throws CertificateException, NoSuchAlgorithmException,
    763         InvalidKeyException, NoSuchProviderException, SignatureException
    764     {
    765         Signature   signature;
    766         String      sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
    767 
    768         try
    769         {
    770             signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
    771         }
    772         catch (Exception e)
    773         {
    774             signature = Signature.getInstance(sigName);
    775         }
    776 
    777         checkSignature(key, signature);
    778     }
    779 
    780     public final void verify(
    781         PublicKey   key,
    782         String      sigProvider)
    783         throws CertificateException, NoSuchAlgorithmException,
    784         InvalidKeyException, NoSuchProviderException, SignatureException
    785     {
    786         String    sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
    787         Signature signature = Signature.getInstance(sigName, sigProvider);
    788 
    789         checkSignature(key, signature);
    790     }
    791 
    792     private void checkSignature(
    793         PublicKey key,
    794         Signature signature)
    795         throws CertificateException, NoSuchAlgorithmException,
    796             SignatureException, InvalidKeyException
    797     {
    798         if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
    799         {
    800             throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
    801         }
    802 
    803         ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
    804 
    805         // TODO This should go after the initVerify?
    806         X509SignatureUtil.setSignatureParameters(signature, params);
    807 
    808         signature.initVerify(key);
    809 
    810         signature.update(this.getTBSCertificate());
    811 
    812         if (!signature.verify(this.getSignature()))
    813         {
    814             throw new SignatureException("certificate does not verify with supplied key");
    815         }
    816     }
    817 
    818     private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
    819     {
    820         if (!id1.getAlgorithm().equals(id2.getAlgorithm()))
    821         {
    822             return false;
    823         }
    824 
    825         if (id1.getParameters() == null)
    826         {
    827             if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
    828             {
    829                 return false;
    830             }
    831 
    832             return true;
    833         }
    834 
    835         if (id2.getParameters() == null)
    836         {
    837             if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
    838             {
    839                 return false;
    840             }
    841 
    842             return true;
    843         }
    844 
    845         return id1.getParameters().equals(id2.getParameters());
    846     }
    847 
    848     private static Collection getAlternativeNames(byte[] extVal)
    849         throws CertificateParsingException
    850     {
    851         if (extVal == null)
    852         {
    853             return null;
    854         }
    855         try
    856         {
    857             Collection temp = new ArrayList();
    858             Enumeration it = ASN1Sequence.getInstance(extVal).getObjects();
    859             while (it.hasMoreElements())
    860             {
    861                 GeneralName genName = GeneralName.getInstance(it.nextElement());
    862                 List list = new ArrayList();
    863                 list.add(Integers.valueOf(genName.getTagNo()));
    864                 switch (genName.getTagNo())
    865                 {
    866                 case GeneralName.ediPartyName:
    867                 case GeneralName.x400Address:
    868                 case GeneralName.otherName:
    869                     list.add(genName.getEncoded());
    870                     break;
    871                 case GeneralName.directoryName:
    872                     // BEGIN android-changed
    873                     list.add(X509Name.getInstance(genName.getName()).toString(true, X509Name.DefaultSymbols));
    874                     // END android-changed
    875                     break;
    876                 case GeneralName.dNSName:
    877                 case GeneralName.rfc822Name:
    878                 case GeneralName.uniformResourceIdentifier:
    879                     list.add(((ASN1String)genName.getName()).getString());
    880                     break;
    881                 case GeneralName.registeredID:
    882                     list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
    883                     break;
    884                 case GeneralName.iPAddress:
    885                     byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets();
    886                     final String addr;
    887                     try
    888                     {
    889                         addr = InetAddress.getByAddress(addrBytes).getHostAddress();
    890                     }
    891                     catch (UnknownHostException e)
    892                     {
    893                         continue;
    894                     }
    895                     list.add(addr);
    896                     break;
    897                 default:
    898                     throw new IOException("Bad tag number: " + genName.getTagNo());
    899                 }
    900 
    901                 temp.add(Collections.unmodifiableList(list));
    902             }
    903             if (temp.size() == 0)
    904             {
    905                 return null;
    906             }
    907             return Collections.unmodifiableCollection(temp);
    908         }
    909         catch (Exception e)
    910         {
    911             throw new CertificateParsingException(e.getMessage());
    912         }
    913     }
    914 }
    915