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