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

package org.bouncycastle.tsp.ers;

import java.util.List;
import java.util.ArrayList;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.tsp.TimeStampResponse;
import java.math.BigInteger;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.cms.SignerInformationVerifier;
import org.bouncycastle.cert.X509CertificateHolder;
import java.util.Date;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.cms.SignedData;
import org.bouncycastle.asn1.tsp.TSTInfo;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import java.io.OutputStream;
import org.bouncycastle.asn1.tsp.ArchiveTimeStampChain;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import java.io.IOException;
import org.bouncycastle.tsp.TSPException;
import org.bouncycastle.util.io.Streams;
import java.io.InputStream;
import org.bouncycastle.asn1.tsp.ArchiveTimeStamp;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.operator.DigestCalculatorProvider;
import org.bouncycastle.asn1.tsp.EvidenceRecord;

public class ERSEvidenceRecord
{
    private final EvidenceRecord evidenceRecord;
    private final DigestCalculatorProvider digestCalculatorProvider;
    private final ERSArchiveTimeStamp firstArchiveTimeStamp;
    private final ERSArchiveTimeStamp lastArchiveTimeStamp;
    private final byte[] previousChainsDigest;
    private final DigestCalculator digCalc;
    private final ArchiveTimeStamp primaryArchiveTimeStamp;
    
    public ERSEvidenceRecord(final InputStream inputStream, final DigestCalculatorProvider digestCalculatorProvider) throws TSPException, ERSException, IOException {
        this(EvidenceRecord.getInstance(Streams.readAll(inputStream)), digestCalculatorProvider);
    }
    
    public ERSEvidenceRecord(final byte[] array, final DigestCalculatorProvider digestCalculatorProvider) throws TSPException, ERSException {
        this(EvidenceRecord.getInstance(array), digestCalculatorProvider);
    }
    
    public ERSEvidenceRecord(final EvidenceRecord evidenceRecord, final DigestCalculatorProvider digestCalculatorProvider) throws TSPException, ERSException {
        this.evidenceRecord = evidenceRecord;
        this.digestCalculatorProvider = digestCalculatorProvider;
        final ArchiveTimeStampChain[] archiveTimeStampChains = evidenceRecord.getArchiveTimeStampSequence().getArchiveTimeStampChains();
        this.primaryArchiveTimeStamp = archiveTimeStampChains[0].getArchiveTimestamps()[0];
        this.validateChains(archiveTimeStampChains);
        final ArchiveTimeStamp[] archiveTimestamps = archiveTimeStampChains[archiveTimeStampChains.length - 1].getArchiveTimestamps();
        this.lastArchiveTimeStamp = new ERSArchiveTimeStamp(archiveTimestamps[archiveTimestamps.length - 1], digestCalculatorProvider);
        Label_0221: {
            if (archiveTimeStampChains.length > 1) {
                try {
                    final ASN1EncodableVector asn1EncodableVector = new ASN1EncodableVector();
                    for (int i = 0; i != archiveTimeStampChains.length - 1; ++i) {
                        asn1EncodableVector.add(archiveTimeStampChains[i]);
                    }
                    this.digCalc = digestCalculatorProvider.get(this.lastArchiveTimeStamp.getDigestAlgorithmIdentifier());
                    final OutputStream outputStream = this.digCalc.getOutputStream();
                    outputStream.write(new DERSequence(asn1EncodableVector).getEncoded("DER"));
                    outputStream.close();
                    this.previousChainsDigest = this.digCalc.getDigest();
                    break Label_0221;
                }
                catch (final Exception ex) {
                    throw new ERSException(ex.getMessage(), ex);
                }
            }
            this.digCalc = null;
            this.previousChainsDigest = null;
        }
        this.firstArchiveTimeStamp = new ERSArchiveTimeStamp(this.previousChainsDigest, archiveTimestamps[0], digestCalculatorProvider);
    }
    
    private void validateChains(final ArchiveTimeStampChain[] array) throws ERSException, TSPException {
        for (int i = 0; i != array.length; ++i) {
            final ArchiveTimeStamp[] archiveTimestamps = array[i].getArchiveTimestamps();
            ArchiveTimeStamp archiveTimeStamp = archiveTimestamps[0];
            final AlgorithmIdentifier digestAlgorithmIdentifier = archiveTimestamps[0].getDigestAlgorithmIdentifier();
            for (int j = 1; j != archiveTimestamps.length; ++j) {
                final ArchiveTimeStamp archiveTimeStamp2 = archiveTimestamps[j];
                if (!digestAlgorithmIdentifier.equals(archiveTimeStamp2.getDigestAlgorithmIdentifier())) {
                    throw new ERSException("invalid digest algorithm in chain");
                }
                final ContentInfo timeStamp = archiveTimeStamp2.getTimeStamp();
                if (!timeStamp.getContentType().equals(CMSObjectIdentifiers.signedData)) {
                    throw new TSPException("cannot identify TSTInfo");
                }
                final TSTInfo timeStamp2 = this.extractTimeStamp(timeStamp);
                try {
                    new ERSArchiveTimeStamp(archiveTimeStamp2, this.digestCalculatorProvider.get(digestAlgorithmIdentifier)).validatePresent(new ERSByteData(archiveTimeStamp.getTimeStamp().getEncoded("DER")), timeStamp2.getGenTime().getDate());
                }
                catch (final Exception ex) {
                    throw new ERSException("invalid timestamp renewal found: " + ex.getMessage(), ex);
                }
                archiveTimeStamp = archiveTimeStamp2;
            }
        }
    }
    
    ArchiveTimeStamp[] getArchiveTimeStamps() {
        final ArchiveTimeStampChain[] archiveTimeStampChains = this.evidenceRecord.getArchiveTimeStampSequence().getArchiveTimeStampChains();
        return archiveTimeStampChains[archiveTimeStampChains.length - 1].getArchiveTimestamps();
    }
    
    public byte[] getPrimaryRootHash() throws TSPException, ERSException {
        final ContentInfo timeStamp = this.primaryArchiveTimeStamp.getTimeStamp();
        if (timeStamp.getContentType().equals(CMSObjectIdentifiers.signedData)) {
            return this.extractTimeStamp(timeStamp).getMessageImprint().getHashedMessage();
        }
        throw new ERSException("cannot identify TSTInfo for digest");
    }
    
    private TSTInfo extractTimeStamp(final ContentInfo contentInfo) throws TSPException {
        final SignedData instance = SignedData.getInstance(contentInfo.getContent());
        if (instance.getEncapContentInfo().getContentType().equals(PKCSObjectIdentifiers.id_ct_TSTInfo)) {
            return TSTInfo.getInstance(ASN1OctetString.getInstance(instance.getEncapContentInfo().getContent()).getOctets());
        }
        throw new TSPException("cannot parse time stamp");
    }
    
    public boolean isRelatedTo(final ERSEvidenceRecord ersEvidenceRecord) {
        return this.primaryArchiveTimeStamp.getTimeStamp().equals(ersEvidenceRecord.primaryArchiveTimeStamp.getTimeStamp());
    }
    
    public boolean isContaining(final ERSData ersData, final Date date) throws ERSException {
        return this.firstArchiveTimeStamp.isContaining(ersData, date);
    }
    
    public void validatePresent(final ERSData ersData, final Date date) throws ERSException {
        this.firstArchiveTimeStamp.validatePresent(ersData, date);
    }
    
    public void validatePresent(final boolean b, final byte[] array, final Date date) throws ERSException {
        this.firstArchiveTimeStamp.validatePresent(b, array, date);
    }
    
    public X509CertificateHolder getSigningCertificate() {
        return this.lastArchiveTimeStamp.getSigningCertificate();
    }
    
    public void validate(final SignerInformationVerifier signerInformationVerifier) throws TSPException {
        if (this.firstArchiveTimeStamp != this.lastArchiveTimeStamp) {
            final ArchiveTimeStamp[] archiveTimeStamps = this.getArchiveTimeStamps();
            for (int i = 0; i != archiveTimeStamps.length - 1; ++i) {
                try {
                    this.lastArchiveTimeStamp.validatePresent(new ERSByteData(archiveTimeStamps[i].getTimeStamp().getEncoded("DER")), this.lastArchiveTimeStamp.getGenTime());
                }
                catch (final Exception ex) {
                    throw new TSPException("unable to process previous ArchiveTimeStamps", ex);
                }
            }
        }
        this.lastArchiveTimeStamp.validate(signerInformationVerifier);
    }
    
    public EvidenceRecord toASN1Structure() {
        return this.evidenceRecord;
    }
    
    public byte[] getEncoded() throws IOException {
        return this.evidenceRecord.getEncoded();
    }
    
    public TimeStampRequest generateTimeStampRenewalRequest(final TimeStampRequestGenerator timeStampRequestGenerator) throws TSPException, ERSException {
        return this.generateTimeStampRenewalRequest(timeStampRequestGenerator, null);
    }
    
    public TimeStampRequest generateTimeStampRenewalRequest(final TimeStampRequestGenerator timeStampRequestGenerator, final BigInteger bigInteger) throws ERSException, TSPException {
        final ERSArchiveTimeStampGenerator buildTspRenewalGenerator = this.buildTspRenewalGenerator();
        try {
            return buildTspRenewalGenerator.generateTimeStampRequest(timeStampRequestGenerator, bigInteger);
        }
        catch (final IOException ex) {
            throw new ERSException(ex.getMessage(), ex);
        }
    }
    
    public ERSEvidenceRecord renewTimeStamp(final TimeStampResponse timeStampResponse) throws ERSException, TSPException {
        final ArchiveTimeStamp asn1Structure = this.buildTspRenewalGenerator().generateArchiveTimeStamp(timeStampResponse).toASN1Structure();
        try {
            return new ERSEvidenceRecord(this.evidenceRecord.addArchiveTimeStamp(asn1Structure, false), this.digestCalculatorProvider);
        }
        catch (final IllegalArgumentException ex) {
            throw new ERSException(ex.getMessage(), ex);
        }
    }
    
    private ERSArchiveTimeStampGenerator buildTspRenewalGenerator() throws ERSException {
        DigestCalculator value;
        try {
            value = this.digestCalculatorProvider.get(this.lastArchiveTimeStamp.getDigestAlgorithmIdentifier());
        }
        catch (final OperatorCreationException ex) {
            throw new ERSException(ex.getMessage(), ex);
        }
        final ArchiveTimeStamp[] archiveTimeStamps = this.getArchiveTimeStamps();
        if (!value.getAlgorithmIdentifier().equals(archiveTimeStamps[0].getDigestAlgorithmIdentifier())) {
            throw new ERSException("digest mismatch for timestamp renewal");
        }
        final ERSArchiveTimeStampGenerator ersArchiveTimeStampGenerator = new ERSArchiveTimeStampGenerator(value);
        final ArrayList list = new ArrayList(archiveTimeStamps.length);
        for (int i = 0; i != archiveTimeStamps.length; ++i) {
            try {
                list.add((Object)new ERSByteData(archiveTimeStamps[i].getTimeStamp().getEncoded("DER")));
            }
            catch (final IOException ex2) {
                throw new ERSException("unable to process previous ArchiveTimeStamps", ex2);
            }
        }
        ersArchiveTimeStampGenerator.addData(new ERSDataGroup((List<ERSData>)list));
        return ersArchiveTimeStampGenerator;
    }
    
    public TimeStampRequest generateHashRenewalRequest(final DigestCalculator digestCalculator, final ERSData ersData, final TimeStampRequestGenerator timeStampRequestGenerator) throws ERSException, TSPException, IOException {
        return this.generateHashRenewalRequest(digestCalculator, ersData, timeStampRequestGenerator, null);
    }
    
    public TimeStampRequest generateHashRenewalRequest(final DigestCalculator digestCalculator, final ERSData ersData, final TimeStampRequestGenerator timeStampRequestGenerator, final BigInteger bigInteger) throws ERSException, TSPException, IOException {
        try {
            this.firstArchiveTimeStamp.validatePresent(ersData, new Date());
        }
        catch (final Exception ex) {
            throw new ERSException("attempt to hash renew on invalid data");
        }
        final ERSArchiveTimeStampGenerator ersArchiveTimeStampGenerator = new ERSArchiveTimeStampGenerator(digestCalculator);
        ersArchiveTimeStampGenerator.addData(ersData);
        ersArchiveTimeStampGenerator.addPreviousChains(this.evidenceRecord.getArchiveTimeStampSequence());
        return ersArchiveTimeStampGenerator.generateTimeStampRequest(timeStampRequestGenerator, bigInteger);
    }
    
    public ERSEvidenceRecord renewHash(final DigestCalculator digestCalculator, final ERSData ersData, final TimeStampResponse timeStampResponse) throws ERSException, TSPException {
        try {
            this.firstArchiveTimeStamp.validatePresent(ersData, new Date());
        }
        catch (final Exception ex) {
            throw new ERSException("attempt to hash renew on invalid data");
        }
        try {
            final ERSArchiveTimeStampGenerator ersArchiveTimeStampGenerator = new ERSArchiveTimeStampGenerator(digestCalculator);
            ersArchiveTimeStampGenerator.addData(ersData);
            ersArchiveTimeStampGenerator.addPreviousChains(this.evidenceRecord.getArchiveTimeStampSequence());
            return new ERSEvidenceRecord(this.evidenceRecord.addArchiveTimeStamp(ersArchiveTimeStampGenerator.generateArchiveTimeStamp(timeStampResponse).toASN1Structure(), true), this.digestCalculatorProvider);
        }
        catch (final IOException ex2) {
            throw new ERSException(ex2.getMessage(), ex2);
        }
        catch (final IllegalArgumentException ex3) {
            throw new ERSException(ex3.getMessage(), ex3);
        }
    }
    
    DigestCalculatorProvider getDigestAlgorithmProvider() {
        return this.digestCalculatorProvider;
    }
}
