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

package org.bouncycastle.cert;

import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.x509.Certificate;
import java.io.OutputStream;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.util.Exceptions;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.x509.DeltaCertificateDescriptor;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DEROctetString;
import java.io.IOException;
import org.bouncycastle.asn1.ASN1Encodable;
import java.util.Enumeration;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Integer;
import java.util.Locale;
import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import java.util.Date;
import java.math.BigInteger;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;

public class X509v3CertificateBuilder
{
    private V3TBSCertificateGenerator tbsGen;
    private ExtensionsGenerator extGenerator;
    
    public X509v3CertificateBuilder(final X500Name x500Name, final BigInteger bigInteger, final Date date, final Date date2, final X500Name x500Name2, final SubjectPublicKeyInfo subjectPublicKeyInfo) {
        this(x500Name, bigInteger, new Time(date), new Time(date2), x500Name2, subjectPublicKeyInfo);
    }
    
    public X509v3CertificateBuilder(final X500Name x500Name, final BigInteger bigInteger, final Date date, final Date date2, final Locale locale, final X500Name x500Name2, final SubjectPublicKeyInfo subjectPublicKeyInfo) {
        this(x500Name, bigInteger, new Time(date, locale), new Time(date2, locale), x500Name2, subjectPublicKeyInfo);
    }
    
    public X509v3CertificateBuilder(final X500Name issuer, final BigInteger bigInteger, final Time startDate, final Time endDate, final X500Name subject, final SubjectPublicKeyInfo subjectPublicKeyInfo) {
        (this.tbsGen = new V3TBSCertificateGenerator()).setSerialNumber(new ASN1Integer(bigInteger));
        this.tbsGen.setIssuer(issuer);
        this.tbsGen.setStartDate(startDate);
        this.tbsGen.setEndDate(endDate);
        this.tbsGen.setSubject(subject);
        this.tbsGen.setSubjectPublicKeyInfo(subjectPublicKeyInfo);
        this.extGenerator = new ExtensionsGenerator();
    }
    
    public X509v3CertificateBuilder(final X509CertificateHolder x509CertificateHolder) {
        (this.tbsGen = new V3TBSCertificateGenerator()).setSerialNumber(new ASN1Integer(x509CertificateHolder.getSerialNumber()));
        this.tbsGen.setIssuer(x509CertificateHolder.getIssuer());
        this.tbsGen.setStartDate(new Time(x509CertificateHolder.getNotBefore()));
        this.tbsGen.setEndDate(new Time(x509CertificateHolder.getNotAfter()));
        this.tbsGen.setSubject(x509CertificateHolder.getSubject());
        this.tbsGen.setSubjectPublicKeyInfo(x509CertificateHolder.getSubjectPublicKeyInfo());
        this.extGenerator = new ExtensionsGenerator();
        final Extensions extensions = x509CertificateHolder.getExtensions();
        final Enumeration oids = extensions.oids();
        while (oids.hasMoreElements()) {
            final ASN1ObjectIdentifier asn1ObjectIdentifier = oids.nextElement();
            if (!Extension.subjectAltPublicKeyInfo.equals(asn1ObjectIdentifier) && !Extension.altSignatureAlgorithm.equals(asn1ObjectIdentifier)) {
                if (Extension.altSignatureValue.equals(asn1ObjectIdentifier)) {
                    continue;
                }
                this.extGenerator.addExtension(extensions.getExtension(asn1ObjectIdentifier));
            }
        }
    }
    
    public boolean hasExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier) {
        return this.doGetExtension(asn1ObjectIdentifier) != null;
    }
    
    public Extension getExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier) {
        return this.doGetExtension(asn1ObjectIdentifier);
    }
    
    private Extension doGetExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier) {
        if (this.extGenerator.isEmpty()) {
            return null;
        }
        return this.extGenerator.generate().getExtension(asn1ObjectIdentifier);
    }
    
    public X509v3CertificateBuilder setSubjectUniqueID(final boolean[] array) {
        this.tbsGen.setSubjectUniqueID(booleanToBitString(array));
        return this;
    }
    
    public X509v3CertificateBuilder setIssuerUniqueID(final boolean[] array) {
        this.tbsGen.setIssuerUniqueID(booleanToBitString(array));
        return this;
    }
    
    public X509v3CertificateBuilder addExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier, final boolean b, final ASN1Encodable asn1Encodable) throws CertIOException {
        try {
            this.extGenerator.addExtension(asn1ObjectIdentifier, b, asn1Encodable);
        }
        catch (final IOException ex) {
            throw new CertIOException("cannot encode extension: " + ex.getMessage(), ex);
        }
        return this;
    }
    
    public X509v3CertificateBuilder addExtension(final Extension extension) throws CertIOException {
        this.extGenerator.addExtension(extension);
        return this;
    }
    
    public X509v3CertificateBuilder addExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier, final boolean b, final byte[] array) throws CertIOException {
        this.extGenerator.addExtension(asn1ObjectIdentifier, b, array);
        return this;
    }
    
    public X509v3CertificateBuilder replaceExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier, final boolean b, final ASN1Encodable asn1Encodable) throws CertIOException {
        try {
            this.extGenerator = CertUtils.doReplaceExtension(this.extGenerator, new Extension(asn1ObjectIdentifier, b, new DEROctetString(asn1Encodable)));
        }
        catch (final IOException ex) {
            throw new CertIOException("cannot encode extension: " + ex.getMessage(), ex);
        }
        return this;
    }
    
    public X509v3CertificateBuilder replaceExtension(final Extension extension) throws CertIOException {
        this.extGenerator = CertUtils.doReplaceExtension(this.extGenerator, extension);
        return this;
    }
    
    public X509v3CertificateBuilder replaceExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier, final boolean b, final byte[] array) throws CertIOException {
        this.extGenerator = CertUtils.doReplaceExtension(this.extGenerator, new Extension(asn1ObjectIdentifier, b, array));
        return this;
    }
    
    public X509v3CertificateBuilder removeExtension(final ASN1ObjectIdentifier asn1ObjectIdentifier) {
        this.extGenerator = CertUtils.doRemoveExtension(this.extGenerator, asn1ObjectIdentifier);
        return this;
    }
    
    public X509v3CertificateBuilder copyAndAddExtension(final ASN1ObjectIdentifier obj, final boolean b, final X509CertificateHolder x509CertificateHolder) {
        final Extension extension = x509CertificateHolder.toASN1Structure().getTBSCertificate().getExtensions().getExtension(obj);
        if (extension == null) {
            throw new NullPointerException("extension " + obj + " not present");
        }
        this.extGenerator.addExtension(obj, b, extension.getExtnValue().getOctets());
        return this;
    }
    
    public X509CertificateHolder build(final ContentSigner contentSigner) {
        final AlgorithmIdentifier algorithmIdentifier = contentSigner.getAlgorithmIdentifier();
        this.tbsGen.setSignature(algorithmIdentifier);
        if (!this.extGenerator.isEmpty()) {
            final Extension extension = this.extGenerator.getExtension(Extension.deltaCertificateDescriptor);
            if (extension != null) {
                final DeltaCertificateDescriptor trimDeltaCertificateDescriptor = DeltaCertificateTool.trimDeltaCertificateDescriptor(DeltaCertificateDescriptor.getInstance(extension.getParsedValue()), this.tbsGen.generateTBSCertificate(), this.extGenerator.generate());
                try {
                    this.extGenerator.replaceExtension(Extension.deltaCertificateDescriptor, extension.isCritical(), trimDeltaCertificateDescriptor);
                }
                catch (final IOException ex) {
                    throw new IllegalStateException("unable to replace deltaCertificateDescriptor: " + ex.getMessage());
                }
            }
            this.tbsGen.setExtensions(this.extGenerator.generate());
        }
        try {
            final TBSCertificate generateTBSCertificate = this.tbsGen.generateTBSCertificate();
            return new X509CertificateHolder(generateStructure(generateTBSCertificate, algorithmIdentifier, generateSig(contentSigner, generateTBSCertificate)));
        }
        catch (final IOException ex2) {
            throw Exceptions.illegalArgumentException("cannot produce certificate signature", ex2);
        }
    }
    
    public X509CertificateHolder build(final ContentSigner contentSigner, final boolean b, final ContentSigner contentSigner2) {
        final AlgorithmIdentifier algorithmIdentifier = contentSigner.getAlgorithmIdentifier();
        final AlgorithmIdentifier algorithmIdentifier2 = contentSigner2.getAlgorithmIdentifier();
        try {
            this.extGenerator.addExtension(Extension.altSignatureAlgorithm, b, algorithmIdentifier2);
        }
        catch (final IOException ex) {
            throw Exceptions.illegalStateException("cannot add altSignatureAlgorithm extension", ex);
        }
        final Extension extension = this.extGenerator.getExtension(Extension.deltaCertificateDescriptor);
        if (extension != null) {
            this.tbsGen.setSignature(algorithmIdentifier);
            try {
                final ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
                extensionsGenerator.addExtensions(this.extGenerator.generate());
                extensionsGenerator.addExtension(Extension.altSignatureValue, false, DERNull.INSTANCE);
                this.extGenerator.replaceExtension(Extension.deltaCertificateDescriptor, extension.isCritical(), DeltaCertificateTool.trimDeltaCertificateDescriptor(DeltaCertificateDescriptor.getInstance(extension.getParsedValue()), this.tbsGen.generateTBSCertificate(), extensionsGenerator.generate()));
            }
            catch (final IOException ex2) {
                throw new IllegalStateException("unable to replace deltaCertificateDescriptor: " + ex2.getMessage());
            }
        }
        this.tbsGen.setSignature(null);
        this.tbsGen.setExtensions(this.extGenerator.generate());
        try {
            this.extGenerator.addExtension(Extension.altSignatureValue, b, new DERBitString(generateSig(contentSigner2, this.tbsGen.generatePreTBSCertificate())));
            this.tbsGen.setSignature(algorithmIdentifier);
            this.tbsGen.setExtensions(this.extGenerator.generate());
            final TBSCertificate generateTBSCertificate = this.tbsGen.generateTBSCertificate();
            return new X509CertificateHolder(generateStructure(generateTBSCertificate, algorithmIdentifier, generateSig(contentSigner, generateTBSCertificate)));
        }
        catch (final IOException ex3) {
            throw Exceptions.illegalArgumentException("cannot produce certificate signature", ex3);
        }
    }
    
    private static byte[] generateSig(final ContentSigner contentSigner, final ASN1Object asn1Object) throws IOException {
        final OutputStream outputStream = contentSigner.getOutputStream();
        asn1Object.encodeTo(outputStream, "DER");
        outputStream.close();
        return contentSigner.getSignature();
    }
    
    private static Certificate generateStructure(final TBSCertificate tbsCertificate, final AlgorithmIdentifier algorithmIdentifier, final byte[] array) {
        final ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector(3);
        asn1EncodableVector.add(tbsCertificate);
        asn1EncodableVector.add(algorithmIdentifier);
        asn1EncodableVector.add(new DERBitString(array));
        return Certificate.getInstance(new DERSequence(asn1EncodableVector));
    }
    
    static DERBitString booleanToBitString(final boolean[] array) {
        final byte[] array2 = new byte[(array.length + 7) / 8];
        for (int i = 0; i != array.length; ++i) {
            final byte[] array3 = array2;
            final int n = i >>> 3;
            array3[n] |= (byte)(array[i] ? ((byte)(128 >> (i & 0x7))) : 0);
        }
        return new DERBitString(array2, 8 - array.length & 0x7);
    }
}
