// 
// Decompiled by Procyon v0.6.0
// 

package org.bouncycastle.jcajce.provider.asymmetric.x509;

import java.net.UnknownHostException;
import java.net.InetAddress;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
import org.bouncycastle.util.Integers;
import org.bouncycastle.asn1.x509.GeneralName;
import java.io.OutputStream;
import java.io.BufferedOutputStream;
import org.bouncycastle.jcajce.io.OutputStreamFactory;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.jcajce.CompositePublicKey;
import java.security.Provider;
import java.security.SignatureException;
import java.security.NoSuchProviderException;
import java.security.InvalidKeyException;
import java.security.cert.CertificateException;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
import org.bouncycastle.asn1.ASN1IA5String;
import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.Exceptions;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.PublicKey;
import org.bouncycastle.asn1.ASN1Primitive;
import java.util.Enumeration;
import org.bouncycastle.asn1.x509.Extensions;
import java.util.HashSet;
import java.util.Set;
import java.util.Collection;
import org.bouncycastle.asn1.ASN1Integer;
import java.security.cert.CertificateParsingException;
import java.util.Collections;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import java.util.ArrayList;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x509.Extension;
import java.util.List;
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.util.Arrays;
import java.security.cert.CertificateEncodingException;
import java.io.IOException;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.jce.X509Principal;
import java.security.Principal;
import java.math.BigInteger;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateExpiredException;
import java.util.Date;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.jcajce.interfaces.BCX509Certificate;
import java.security.cert.X509Certificate;

abstract class X509CertificateImpl extends X509Certificate implements BCX509Certificate
{
    protected JcaJceHelper bcHelper;
    protected org.bouncycastle.asn1.x509.Certificate c;
    protected BasicConstraints basicConstraints;
    protected boolean[] keyUsage;
    protected String sigAlgName;
    protected byte[] sigAlgParams;
    
    X509CertificateImpl(final JcaJceHelper bcHelper, final org.bouncycastle.asn1.x509.Certificate c, final BasicConstraints basicConstraints, final boolean[] keyUsage, final String sigAlgName, final byte[] sigAlgParams) {
        this.bcHelper = bcHelper;
        this.c = c;
        this.basicConstraints = basicConstraints;
        this.keyUsage = keyUsage;
        this.sigAlgName = sigAlgName;
        this.sigAlgParams = sigAlgParams;
    }
    
    @Override
    public X500Name getIssuerX500Name() {
        return this.c.getIssuer();
    }
    
    @Override
    public TBSCertificate getTBSCertificateNative() {
        return this.c.getTBSCertificate();
    }
    
    @Override
    public X500Name getSubjectX500Name() {
        return this.c.getSubject();
    }
    
    @Override
    public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
        this.checkValidity(new Date());
    }
    
    @Override
    public void checkValidity(final Date date) throws CertificateExpiredException, CertificateNotYetValidException {
        if (date.getTime() > this.getNotAfter().getTime()) {
            throw new CertificateExpiredException("certificate expired on " + this.c.getEndDate().getTime());
        }
        if (date.getTime() < this.getNotBefore().getTime()) {
            throw new CertificateNotYetValidException("certificate not valid till " + this.c.getStartDate().getTime());
        }
    }
    
    @Override
    public int getVersion() {
        return this.c.getVersionNumber();
    }
    
    @Override
    public BigInteger getSerialNumber() {
        return this.c.getSerialNumber().getValue();
    }
    
    @Override
    public Principal getIssuerDN() {
        return new X509Principal(this.c.getIssuer());
    }
    
    @Override
    public X500Principal getIssuerX500Principal() {
        try {
            return new X500Principal(this.c.getIssuer().getEncoded("DER"));
        }
        catch (final IOException ex) {
            throw new IllegalStateException("can't encode issuer DN");
        }
    }
    
    @Override
    public Principal getSubjectDN() {
        return new X509Principal(this.c.getSubject());
    }
    
    @Override
    public X500Principal getSubjectX500Principal() {
        try {
            return new X500Principal(this.c.getSubject().getEncoded("DER"));
        }
        catch (final IOException ex) {
            throw new IllegalStateException("can't encode subject DN");
        }
    }
    
    @Override
    public Date getNotBefore() {
        return this.c.getStartDate().getDate();
    }
    
    @Override
    public Date getNotAfter() {
        return this.c.getEndDate().getDate();
    }
    
    @Override
    public byte[] getTBSCertificate() throws CertificateEncodingException {
        try {
            return this.c.getTBSCertificate().getEncoded("DER");
        }
        catch (final IOException ex) {
            throw new CertificateEncodingException(ex.toString());
        }
    }
    
    @Override
    public byte[] getSignature() {
        return this.c.getSignature().getOctets();
    }
    
    @Override
    public String getSigAlgName() {
        return this.sigAlgName;
    }
    
    @Override
    public String getSigAlgOID() {
        return this.c.getSignatureAlgorithm().getAlgorithm().getId();
    }
    
    @Override
    public byte[] getSigAlgParams() {
        return Arrays.clone(this.sigAlgParams);
    }
    
    @Override
    public boolean[] getIssuerUniqueID() {
        final ASN1BitString issuerUniqueId = this.c.getTBSCertificate().getIssuerUniqueId();
        if (issuerUniqueId != null) {
            final byte[] bytes = issuerUniqueId.getBytes();
            final boolean[] array = new boolean[bytes.length * 8 - issuerUniqueId.getPadBits()];
            for (int i = 0; i != array.length; ++i) {
                array[i] = ((bytes[i / 8] & 128 >>> i % 8) != 0x0);
            }
            return array;
        }
        return null;
    }
    
    @Override
    public boolean[] getSubjectUniqueID() {
        final ASN1BitString subjectUniqueId = this.c.getTBSCertificate().getSubjectUniqueId();
        if (subjectUniqueId != null) {
            final byte[] bytes = subjectUniqueId.getBytes();
            final boolean[] array = new boolean[bytes.length * 8 - subjectUniqueId.getPadBits()];
            for (int i = 0; i != array.length; ++i) {
                array[i] = ((bytes[i / 8] & 128 >>> i % 8) != 0x0);
            }
            return array;
        }
        return null;
    }
    
    @Override
    public boolean[] getKeyUsage() {
        return Arrays.clone(this.keyUsage);
    }
    
    @Override
    public List getExtendedKeyUsage() throws CertificateParsingException {
        final byte[] extensionOctets = getExtensionOctets(this.c, Extension.extendedKeyUsage);
        if (null == extensionOctets) {
            return null;
        }
        try {
            final ASN1Sequence instance = ASN1Sequence.getInstance(extensionOctets);
            final ArrayList list = new ArrayList();
            for (int i = 0; i != instance.size(); ++i) {
                list.add(((ASN1ObjectIdentifier)instance.getObjectAt(i)).getId());
            }
            return Collections.unmodifiableList((List<?>)list);
        }
        catch (final Exception ex) {
            throw new CertificateParsingException("error processing extended key usage extension");
        }
    }
    
    @Override
    public int getBasicConstraints() {
        if (this.basicConstraints == null || !this.basicConstraints.isCA()) {
            return -1;
        }
        final ASN1Integer pathLenConstraintInteger = this.basicConstraints.getPathLenConstraintInteger();
        if (pathLenConstraintInteger == null) {
            return Integer.MAX_VALUE;
        }
        return pathLenConstraintInteger.intPositiveValueExact();
    }
    
    @Override
    public Collection getSubjectAlternativeNames() throws CertificateParsingException {
        return getAlternativeNames(this.c, Extension.subjectAlternativeName);
    }
    
    @Override
    public Collection getIssuerAlternativeNames() throws CertificateParsingException {
        return getAlternativeNames(this.c, Extension.issuerAlternativeName);
    }
    
    @Override
    public Set getCriticalExtensionOIDs() {
        if (this.getVersion() == 3) {
            final HashSet set = new HashSet();
            final Extensions extensions = this.c.getExtensions();
            if (extensions != null) {
                final Enumeration oids = extensions.oids();
                while (oids.hasMoreElements()) {
                    final ASN1ObjectIdentifier asn1ObjectIdentifier = oids.nextElement();
                    if (extensions.getExtension(asn1ObjectIdentifier).isCritical()) {
                        set.add(asn1ObjectIdentifier.getId());
                    }
                }
                return set;
            }
        }
        return null;
    }
    
    @Override
    public byte[] getExtensionValue(final String s) {
        return X509SignatureUtil.getExtensionValue(this.c.getExtensions(), s);
    }
    
    @Override
    public Set getNonCriticalExtensionOIDs() {
        if (this.getVersion() == 3) {
            final HashSet set = new HashSet();
            final Extensions extensions = this.c.getExtensions();
            if (extensions != null) {
                final Enumeration oids = extensions.oids();
                while (oids.hasMoreElements()) {
                    final ASN1ObjectIdentifier asn1ObjectIdentifier = oids.nextElement();
                    if (!extensions.getExtension(asn1ObjectIdentifier).isCritical()) {
                        set.add(asn1ObjectIdentifier.getId());
                    }
                }
                return set;
            }
        }
        return null;
    }
    
    @Override
    public boolean hasUnsupportedCriticalExtension() {
        if (this.getVersion() == 3) {
            final Extensions extensions = this.c.getExtensions();
            if (extensions != null) {
                final Enumeration oids = extensions.oids();
                while (oids.hasMoreElements()) {
                    final ASN1ObjectIdentifier asn1ObjectIdentifier = oids.nextElement();
                    if (!Extension.keyUsage.equals(asn1ObjectIdentifier) && !Extension.certificatePolicies.equals(asn1ObjectIdentifier) && !Extension.policyMappings.equals(asn1ObjectIdentifier) && !Extension.inhibitAnyPolicy.equals(asn1ObjectIdentifier) && !Extension.cRLDistributionPoints.equals(asn1ObjectIdentifier) && !Extension.issuingDistributionPoint.equals(asn1ObjectIdentifier) && !Extension.deltaCRLIndicator.equals(asn1ObjectIdentifier) && !Extension.policyConstraints.equals(asn1ObjectIdentifier) && !Extension.basicConstraints.equals(asn1ObjectIdentifier) && !Extension.subjectAlternativeName.equals(asn1ObjectIdentifier)) {
                        if (Extension.nameConstraints.equals(asn1ObjectIdentifier)) {
                            continue;
                        }
                        if (extensions.getExtension(asn1ObjectIdentifier).isCritical()) {
                            return true;
                        }
                        continue;
                    }
                }
            }
        }
        return false;
    }
    
    @Override
    public PublicKey getPublicKey() {
        try {
            return BouncyCastleProvider.getPublicKey(this.c.getSubjectPublicKeyInfo());
        }
        catch (final IOException ex) {
            throw Exceptions.illegalStateException("failed to recover public key: " + ex.getMessage(), ex);
        }
    }
    
    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        final String lineSeparator = Strings.lineSeparator();
        sb.append("  [0]         Version: ").append(this.getVersion()).append(lineSeparator);
        sb.append("         SerialNumber: ").append(this.getSerialNumber()).append(lineSeparator);
        sb.append("             IssuerDN: ").append(this.getIssuerDN()).append(lineSeparator);
        sb.append("           Start Date: ").append(this.getNotBefore()).append(lineSeparator);
        sb.append("           Final Date: ").append(this.getNotAfter()).append(lineSeparator);
        sb.append("            SubjectDN: ").append(this.getSubjectDN()).append(lineSeparator);
        sb.append("           Public Key: ").append(this.getPublicKey()).append(lineSeparator);
        sb.append("  Signature Algorithm: ").append(this.getSigAlgName()).append(lineSeparator);
        X509SignatureUtil.prettyPrintSignature(this.getSignature(), sb, lineSeparator);
        final Extensions extensions = this.c.getExtensions();
        if (extensions != null) {
            final Enumeration oids = extensions.oids();
            if (oids.hasMoreElements()) {
                sb.append("       Extensions: \n");
            }
            while (oids.hasMoreElements()) {
                final ASN1ObjectIdentifier asn1ObjectIdentifier = oids.nextElement();
                final Extension extension = extensions.getExtension(asn1ObjectIdentifier);
                if (extension.getExtnValue() != null) {
                    final ASN1InputStream asn1InputStream = new ASN1InputStream(extension.getExtnValue().getOctets());
                    sb.append("                       critical(").append(extension.isCritical()).append(") ");
                    try {
                        if (asn1ObjectIdentifier.equals(Extension.basicConstraints)) {
                            sb.append(BasicConstraints.getInstance(asn1InputStream.readObject())).append(lineSeparator);
                        }
                        else if (asn1ObjectIdentifier.equals(Extension.keyUsage)) {
                            sb.append(KeyUsage.getInstance(asn1InputStream.readObject())).append(lineSeparator);
                        }
                        else if (asn1ObjectIdentifier.equals(MiscObjectIdentifiers.netscapeCertType)) {
                            sb.append(new NetscapeCertType(ASN1BitString.getInstance(asn1InputStream.readObject()))).append(lineSeparator);
                        }
                        else if (asn1ObjectIdentifier.equals(MiscObjectIdentifiers.netscapeRevocationURL)) {
                            sb.append(new NetscapeRevocationURL(ASN1IA5String.getInstance(asn1InputStream.readObject()))).append(lineSeparator);
                        }
                        else if (asn1ObjectIdentifier.equals(MiscObjectIdentifiers.verisignCzagExtension)) {
                            sb.append(new VerisignCzagExtension(ASN1IA5String.getInstance(asn1InputStream.readObject()))).append(lineSeparator);
                        }
                        else {
                            sb.append(asn1ObjectIdentifier.getId());
                            sb.append(" value = ").append(ASN1Dump.dumpAsString(asn1InputStream.readObject())).append(lineSeparator);
                        }
                    }
                    catch (final Exception ex) {
                        sb.append(asn1ObjectIdentifier.getId());
                        sb.append(" value = ").append("*****").append(lineSeparator);
                    }
                }
                else {
                    sb.append(lineSeparator);
                }
            }
        }
        return sb.toString();
    }
    
    @Override
    public final void verify(final PublicKey publicKey) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
        this.doVerify(publicKey, new SignatureCreator() {
            @Override
            public Signature createSignature(final String algorithm) throws NoSuchAlgorithmException {
                try {
                    return X509CertificateImpl.this.bcHelper.createSignature(algorithm);
                }
                catch (final Exception ex) {
                    return Signature.getInstance(algorithm);
                }
            }
        });
    }
    
    @Override
    public final void verify(final PublicKey publicKey, final String s) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
        this.doVerify(publicKey, new SignatureCreator() {
            @Override
            public Signature createSignature(final String s) throws NoSuchAlgorithmException, NoSuchProviderException {
                if (s != null) {
                    return Signature.getInstance(s, s);
                }
                return Signature.getInstance(s);
            }
        });
    }
    
    @Override
    public final void verify(final PublicKey publicKey, final Provider provider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        try {
            this.doVerify(publicKey, new SignatureCreator() {
                @Override
                public Signature createSignature(final String s) throws NoSuchAlgorithmException {
                    if (provider != null) {
                        return Signature.getInstance(s, provider);
                    }
                    return Signature.getInstance(s);
                }
            });
        }
        catch (final NoSuchProviderException ex) {
            throw new NoSuchAlgorithmException("provider issue: " + ex.getMessage());
        }
    }
    
    private void doVerify(final PublicKey publicKey, final SignatureCreator signatureCreator) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, NoSuchProviderException {
        if (publicKey instanceof CompositePublicKey && X509SignatureUtil.isCompositeAlgorithm(this.c.getSignatureAlgorithm())) {
            final List<PublicKey> publicKeys = ((CompositePublicKey)publicKey).getPublicKeys();
            final ASN1Sequence instance = ASN1Sequence.getInstance(this.c.getSignatureAlgorithm().getParameters());
            final ASN1Sequence instance2 = ASN1Sequence.getInstance(this.c.getSignature().getOctets());
            boolean b = false;
            for (int i = 0; i != publicKeys.size(); ++i) {
                if (publicKeys.get(i) != null) {
                    final AlgorithmIdentifier instance3 = AlgorithmIdentifier.getInstance(instance.getObjectAt(i));
                    final Signature signature = signatureCreator.createSignature(X509SignatureUtil.getSignatureName(instance3));
                    SignatureException ex = null;
                    try {
                        this.checkSignature(publicKeys.get(i), signature, instance3.getParameters(), ASN1BitString.getInstance(instance2.getObjectAt(i)).getOctets());
                        b = true;
                    }
                    catch (final SignatureException ex2) {
                        ex = ex2;
                    }
                    if (ex != null) {
                        throw ex;
                    }
                }
            }
            if (!b) {
                throw new InvalidKeyException("no matching key found");
            }
        }
        else if (X509SignatureUtil.isCompositeAlgorithm(this.c.getSignatureAlgorithm())) {
            final ASN1Sequence instance4 = ASN1Sequence.getInstance(this.c.getSignatureAlgorithm().getParameters());
            final ASN1Sequence instance5 = ASN1Sequence.getInstance(this.c.getSignature().getOctets());
            boolean b2 = false;
            for (int j = 0; j != instance5.size(); ++j) {
                final AlgorithmIdentifier instance6 = AlgorithmIdentifier.getInstance(instance4.getObjectAt(j));
                final String signatureName = X509SignatureUtil.getSignatureName(instance6);
                SignatureException ex3 = null;
                try {
                    this.checkSignature(publicKey, signatureCreator.createSignature(signatureName), instance6.getParameters(), ASN1BitString.getInstance(instance5.getObjectAt(j)).getOctets());
                    b2 = true;
                }
                catch (final InvalidKeyException ex4) {}
                catch (final NoSuchAlgorithmException ex5) {}
                catch (final SignatureException ex6) {
                    ex3 = ex6;
                }
                if (ex3 != null) {
                    throw ex3;
                }
            }
            if (!b2) {
                throw new InvalidKeyException("no matching key found");
            }
        }
        else {
            final Signature signature2 = signatureCreator.createSignature(this.getSigAlgName());
            if (publicKey instanceof CompositePublicKey && MiscObjectIdentifiers.id_composite_key.equals(((CompositePublicKey)publicKey).getAlgorithmIdentifier().getAlgorithm())) {
                final List<PublicKey> publicKeys2 = ((CompositePublicKey)publicKey).getPublicKeys();
                int k = 0;
                while (k != publicKeys2.size()) {
                    try {
                        this.checkSignature((PublicKey)publicKeys2.get(k), signature2, this.c.getSignatureAlgorithm().getParameters(), this.getSignature());
                        return;
                    }
                    catch (final InvalidKeyException ex7) {
                        ++k;
                        continue;
                    }
                    break;
                }
                throw new InvalidKeyException("no matching signature found");
            }
            this.checkSignature(publicKey, signature2, this.c.getSignatureAlgorithm().getParameters(), this.getSignature());
        }
    }
    
    private void checkSignature(final PublicKey publicKey, final Signature signature, final ASN1Encodable asn1Encodable, final byte[] signature2) throws CertificateException, InvalidKeyException, NoSuchAlgorithmException, SignatureException {
        if (!X509SignatureUtil.areEquivalentAlgorithms(this.c.getSignatureAlgorithm(), this.c.getTBSCertificate().getSignature())) {
            throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
        }
        X509SignatureUtil.setSignatureParameters(signature, asn1Encodable);
        signature.initVerify(publicKey);
        try {
            final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(OutputStreamFactory.createStream(signature), 512);
            this.c.getTBSCertificate().encodeTo(bufferedOutputStream, "DER");
            bufferedOutputStream.close();
        }
        catch (final IOException ex) {
            throw new CertificateEncodingException(ex.toString());
        }
        if (!signature.verify(signature2)) {
            throw new SignatureException("certificate does not verify with supplied key");
        }
    }
    
    private static Collection getAlternativeNames(final org.bouncycastle.asn1.x509.Certificate certificate, final ASN1ObjectIdentifier asn1ObjectIdentifier) throws CertificateParsingException {
        final byte[] extensionOctets = getExtensionOctets(certificate, asn1ObjectIdentifier);
        if (extensionOctets == null) {
            return null;
        }
        try {
            final ArrayList c = new ArrayList();
            final Enumeration objects = ASN1Sequence.getInstance(extensionOctets).getObjects();
            while (objects.hasMoreElements()) {
                final GeneralName instance = GeneralName.getInstance(objects.nextElement());
                final ArrayList list = new ArrayList();
                list.add(Integers.valueOf(instance.getTagNo()));
                switch (instance.getTagNo()) {
                    case 0:
                    case 3:
                    case 5: {
                        list.add(instance.getEncoded());
                        break;
                    }
                    case 4: {
                        list.add(X500Name.getInstance(RFC4519Style.INSTANCE, instance.getName()).toString());
                        break;
                    }
                    case 1:
                    case 2:
                    case 6: {
                        list.add(((ASN1String)instance.getName()).getString());
                        break;
                    }
                    case 8: {
                        list.add(ASN1ObjectIdentifier.getInstance(instance.getName()).getId());
                        break;
                    }
                    case 7: {
                        final byte[] octets = ASN1OctetString.getInstance(instance.getName()).getOctets();
                        String hostAddress;
                        try {
                            hostAddress = InetAddress.getByAddress(octets).getHostAddress();
                        }
                        catch (final UnknownHostException ex) {
                            continue;
                        }
                        list.add(hostAddress);
                        break;
                    }
                    default: {
                        throw new IOException("Bad tag number: " + instance.getTagNo());
                    }
                }
                c.add(Collections.unmodifiableList((List<?>)list));
            }
            if (c.size() == 0) {
                return null;
            }
            return Collections.unmodifiableCollection((Collection<?>)c);
        }
        catch (final Exception ex2) {
            throw new CertificateParsingException(ex2.getMessage());
        }
    }
    
    static byte[] getExtensionOctets(final org.bouncycastle.asn1.x509.Certificate certificate, final ASN1ObjectIdentifier asn1ObjectIdentifier) {
        final ASN1OctetString extensionValue = Extensions.getExtensionValue(certificate.getExtensions(), asn1ObjectIdentifier);
        return (byte[])((extensionValue == null) ? null : extensionValue.getOctets());
    }
}
