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

package org.bouncycastle.cms;

import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import java.util.Iterator;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.Time;
import org.bouncycastle.asn1.cms.CMSAlgorithmProtection;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.operator.ContentVerifier;
import org.bouncycastle.asn1.x509.DigestInfo;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.DERNull;
import java.io.OutputStream;
import org.bouncycastle.util.io.TeeOutputStream;
import org.bouncycastle.operator.RawContentVerifier;
import org.bouncycastle.operator.OperatorCreationException;
import java.io.IOException;
import java.util.Enumeration;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.CMSAttributes;
import java.util.Collection;
import java.util.ArrayList;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.asn1.cms.SignerIdentifier;
import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.cms.SignerInfo;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;

public class SignerInformation
{
    private final SignerId sid;
    private final CMSProcessable content;
    private final byte[] signature;
    private final ASN1ObjectIdentifier contentType;
    private final boolean isCounterSignature;
    private AttributeTable signedAttributeValues;
    private AttributeTable unsignedAttributeValues;
    private byte[] resultDigest;
    protected final SignerInfo info;
    protected final AlgorithmIdentifier digestAlgorithm;
    protected final AlgorithmIdentifier encryptionAlgorithm;
    protected final ASN1Set signedAttributeSet;
    protected final ASN1Set unsignedAttributeSet;
    
    SignerInformation(final SignerInfo info, final ASN1ObjectIdentifier contentType, final CMSProcessable content, final byte[] resultDigest) {
        this.info = info;
        this.contentType = contentType;
        this.isCounterSignature = (contentType == null);
        final SignerIdentifier sid = info.getSID();
        if (sid.isTagged()) {
            this.sid = new SignerId(ASN1OctetString.getInstance(sid.getId()).getOctets());
        }
        else {
            final IssuerAndSerialNumber instance = IssuerAndSerialNumber.getInstance(sid.getId());
            this.sid = new SignerId(instance.getName(), instance.getSerialNumber().getValue());
        }
        this.digestAlgorithm = info.getDigestAlgorithm();
        this.signedAttributeSet = info.getAuthenticatedAttributes();
        this.unsignedAttributeSet = info.getUnauthenticatedAttributes();
        this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm();
        this.signature = info.getEncryptedDigest().getOctets();
        this.content = content;
        this.resultDigest = resultDigest;
    }
    
    protected SignerInformation(final SignerInformation signerInformation) {
        this(signerInformation, signerInformation.info);
    }
    
    protected SignerInformation(final SignerInformation signerInformation, final SignerInfo info) {
        this.info = info;
        this.contentType = signerInformation.contentType;
        this.isCounterSignature = signerInformation.isCounterSignature();
        this.sid = signerInformation.getSID();
        this.digestAlgorithm = info.getDigestAlgorithm();
        this.signedAttributeSet = info.getAuthenticatedAttributes();
        this.unsignedAttributeSet = info.getUnauthenticatedAttributes();
        this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm();
        this.signature = info.getEncryptedDigest().getOctets();
        this.content = signerInformation.content;
        this.resultDigest = signerInformation.resultDigest;
        this.signedAttributeValues = this.getSignedAttributes();
        this.unsignedAttributeValues = this.getUnsignedAttributes();
    }
    
    public boolean isCounterSignature() {
        return this.isCounterSignature;
    }
    
    public ASN1ObjectIdentifier getContentType() {
        return this.contentType;
    }
    
    public SignerId getSID() {
        return this.sid;
    }
    
    public int getVersion() {
        return this.info.getVersion().intValueExact();
    }
    
    public AlgorithmIdentifier getDigestAlgorithmID() {
        return this.digestAlgorithm;
    }
    
    public String getDigestAlgOID() {
        return this.digestAlgorithm.getAlgorithm().getId();
    }
    
    public byte[] getDigestAlgParams() {
        try {
            return CMSUtils.encodeObj(this.digestAlgorithm.getParameters());
        }
        catch (final Exception obj) {
            throw new RuntimeException("exception getting digest parameters " + obj);
        }
    }
    
    public byte[] getContentDigest() {
        if (this.resultDigest == null) {
            throw new IllegalStateException("method can only be called after verify.");
        }
        return Arrays.clone(this.resultDigest);
    }
    
    public String getEncryptionAlgOID() {
        return this.encryptionAlgorithm.getAlgorithm().getId();
    }
    
    public byte[] getEncryptionAlgParams() {
        try {
            return CMSUtils.encodeObj(this.encryptionAlgorithm.getParameters());
        }
        catch (final Exception obj) {
            throw new RuntimeException("exception getting encryption parameters " + obj);
        }
    }
    
    public AttributeTable getSignedAttributes() {
        if (this.signedAttributeSet != null && this.signedAttributeValues == null) {
            this.signedAttributeValues = new AttributeTable(this.signedAttributeSet);
        }
        return this.signedAttributeValues;
    }
    
    public AttributeTable getUnsignedAttributes() {
        if (this.unsignedAttributeSet != null && this.unsignedAttributeValues == null) {
            this.unsignedAttributeValues = new AttributeTable(this.unsignedAttributeSet);
        }
        return this.unsignedAttributeValues;
    }
    
    public byte[] getSignature() {
        return Arrays.clone(this.signature);
    }
    
    public SignerInformationStore getCounterSignatures() {
        final AttributeTable unsignedAttributes = this.getUnsignedAttributes();
        if (unsignedAttributes == null) {
            return new SignerInformationStore(new ArrayList<SignerInformation>(0));
        }
        final ArrayList list = new ArrayList();
        final ASN1EncodableVector all = unsignedAttributes.getAll(CMSAttributes.counterSignature);
        for (int i = 0; i < all.size(); ++i) {
            final ASN1Set attrValues = ((Attribute)all.get(i)).getAttrValues();
            if (attrValues.size() < 1) {}
            final Enumeration objects = attrValues.getObjects();
            while (objects.hasMoreElements()) {
                list.add(new SignerInformation(SignerInfo.getInstance(objects.nextElement()), null, new CMSProcessableByteArray(this.getSignature()), null));
            }
        }
        return new SignerInformationStore(list);
    }
    
    public byte[] getEncodedSignedAttributes() throws IOException {
        if (this.signedAttributeSet != null) {
            return this.signedAttributeSet.getEncoded("DER");
        }
        return null;
    }
    
    private boolean doVerify(final SignerInformationVerifier signerInformationVerifier) throws CMSException {
        final String encryptionAlgName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID());
        final AlgorithmIdentifier algorithmIdentifier = (this.signedAttributeSet != null) ? this.info.getDigestAlgorithm() : translateBrokenRSAPkcs7(this.encryptionAlgorithm, this.info.getDigestAlgorithm());
        ContentVerifier contentVerifier;
        try {
            contentVerifier = signerInformationVerifier.getContentVerifier(this.encryptionAlgorithm, algorithmIdentifier);
        }
        catch (final OperatorCreationException ex) {
            throw new CMSException("can't create content verifier: " + ex.getMessage(), ex);
        }
        try {
            final OutputStream outputStream = contentVerifier.getOutputStream();
            if (this.resultDigest == null) {
                final DigestCalculator digestCalculator = signerInformationVerifier.getDigestCalculator(algorithmIdentifier);
                if (this.content != null) {
                    final OutputStream outputStream2 = digestCalculator.getOutputStream();
                    if (this.signedAttributeSet == null) {
                        if (contentVerifier instanceof RawContentVerifier) {
                            this.content.write(outputStream2);
                        }
                        else {
                            final TeeOutputStream teeOutputStream = new TeeOutputStream(outputStream2, outputStream);
                            this.content.write(teeOutputStream);
                            teeOutputStream.close();
                        }
                    }
                    else {
                        this.content.write(outputStream2);
                        outputStream.write(this.getEncodedSignedAttributes());
                    }
                    outputStream2.close();
                }
                else {
                    if (this.signedAttributeSet == null) {
                        throw new CMSException("data not encapsulated in signature - use detached constructor.");
                    }
                    outputStream.write(this.getEncodedSignedAttributes());
                }
                this.resultDigest = digestCalculator.getDigest();
            }
            else if (this.signedAttributeSet == null) {
                if (this.content != null) {
                    this.content.write(outputStream);
                }
            }
            else {
                outputStream.write(this.getEncodedSignedAttributes());
            }
            outputStream.close();
        }
        catch (final IOException ex2) {
            throw new CMSException("can't process mime object to create signature.", ex2);
        }
        catch (final OperatorCreationException ex3) {
            throw new CMSException("can't create digest calculator: " + ex3.getMessage(), ex3);
        }
        this.verifyContentTypeAttributeValue();
        final AttributeTable signedAttributes = this.getSignedAttributes();
        this.verifyAlgorithmIdentifierProtectionAttribute(signedAttributes);
        this.verifyMessageDigestAttribute();
        this.verifyCounterSignatureAttribute(signedAttributes);
        try {
            if (this.signedAttributeSet != null || this.resultDigest == null || !(contentVerifier instanceof RawContentVerifier)) {
                return contentVerifier.verify(this.getSignature());
            }
            final RawContentVerifier rawContentVerifier = (RawContentVerifier)contentVerifier;
            if (encryptionAlgName.equals("RSA")) {
                return rawContentVerifier.verify(new DigestInfo(new AlgorithmIdentifier(algorithmIdentifier.getAlgorithm(), DERNull.INSTANCE), this.resultDigest).getEncoded("DER"), this.getSignature());
            }
            return rawContentVerifier.verify(this.resultDigest, this.getSignature());
        }
        catch (final IOException ex4) {
            throw new CMSException("can't process mime object to create signature.", ex4);
        }
    }
    
    private void verifyContentTypeAttributeValue() throws CMSException {
        final ASN1Primitive singleValuedSignedAttribute = this.getSingleValuedSignedAttribute(CMSAttributes.contentType, "content-type");
        if (singleValuedSignedAttribute == null) {
            if (!this.isCounterSignature && this.signedAttributeSet != null) {
                throw new CMSException("The content-type attribute type MUST be present whenever signed attributes are present in signed-data");
            }
        }
        else {
            if (this.isCounterSignature) {
                throw new CMSException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
            }
            if (!(singleValuedSignedAttribute instanceof ASN1ObjectIdentifier)) {
                throw new CMSException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
            }
            if (!((ASN1ObjectIdentifier)singleValuedSignedAttribute).equals(this.contentType)) {
                throw new CMSException("content-type attribute value does not match eContentType");
            }
        }
    }
    
    private void verifyMessageDigestAttribute() throws CMSException {
        final ASN1Primitive singleValuedSignedAttribute = this.getSingleValuedSignedAttribute(CMSAttributes.messageDigest, "message-digest");
        if (singleValuedSignedAttribute == null) {
            if (this.signedAttributeSet != null) {
                throw new CMSException("the message-digest signed attribute type MUST be present when there are any signed attributes present");
            }
        }
        else {
            if (!(singleValuedSignedAttribute instanceof ASN1OctetString)) {
                throw new CMSException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
            }
            if (!Arrays.constantTimeAreEqual(this.resultDigest, ((ASN1OctetString)singleValuedSignedAttribute).getOctets())) {
                throw new CMSSignerDigestMismatchException("message-digest attribute value does not match calculated value");
            }
        }
    }
    
    private void verifyAlgorithmIdentifierProtectionAttribute(final AttributeTable attributeTable) throws CMSException {
        final AttributeTable unsignedAttributes = this.getUnsignedAttributes();
        if (unsignedAttributes != null && unsignedAttributes.getAll(CMSAttributes.cmsAlgorithmProtect).size() > 0) {
            throw new CMSException("A cmsAlgorithmProtect attribute MUST be a signed attribute");
        }
        if (attributeTable != null) {
            final ASN1EncodableVector all = attributeTable.getAll(CMSAttributes.cmsAlgorithmProtect);
            if (all.size() > 1) {
                throw new CMSException("Only one instance of a cmsAlgorithmProtect attribute can be present");
            }
            if (all.size() > 0) {
                final Attribute instance = Attribute.getInstance(all.get(0));
                if (instance.getAttrValues().size() != 1) {
                    throw new CMSException("A cmsAlgorithmProtect attribute MUST contain exactly one value");
                }
                final CMSAlgorithmProtection instance2 = CMSAlgorithmProtection.getInstance(instance.getAttributeValues()[0]);
                if (!CMSUtils.isEquivalent(instance2.getDigestAlgorithm(), this.info.getDigestAlgorithm())) {
                    throw new CMSException("CMS Algorithm Identifier Protection check failed for digestAlgorithm");
                }
                if (!CMSUtils.isEquivalent(instance2.getSignatureAlgorithm(), this.info.getDigestEncryptionAlgorithm())) {
                    throw new CMSException("CMS Algorithm Identifier Protection check failed for signatureAlgorithm");
                }
            }
        }
    }
    
    private void verifyCounterSignatureAttribute(final AttributeTable attributeTable) throws CMSException {
        if (attributeTable != null && attributeTable.getAll(CMSAttributes.counterSignature).size() > 0) {
            throw new CMSException("A countersignature attribute MUST NOT be a signed attribute");
        }
        final AttributeTable unsignedAttributes = this.getUnsignedAttributes();
        if (unsignedAttributes != null) {
            final ASN1EncodableVector all = unsignedAttributes.getAll(CMSAttributes.counterSignature);
            for (int i = 0; i < all.size(); ++i) {
                if (Attribute.getInstance(all.get(i)).getAttrValues().size() < 1) {
                    throw new CMSException("A countersignature attribute MUST contain at least one AttributeValue");
                }
            }
        }
    }
    
    public boolean verify(final SignerInformationVerifier signerInformationVerifier) throws CMSException {
        final Time signingTime = this.getSigningTime();
        if (signerInformationVerifier.hasAssociatedCertificate() && signingTime != null && !signerInformationVerifier.getAssociatedCertificate().isValidOn(signingTime.getDate())) {
            throw new CMSVerifierCertificateNotValidException("verifier not valid at signingTime");
        }
        return this.doVerify(signerInformationVerifier);
    }
    
    public SignerInfo toASN1Structure() {
        return this.info;
    }
    
    private ASN1Primitive getSingleValuedSignedAttribute(final ASN1ObjectIdentifier asn1ObjectIdentifier, final String str) throws CMSException {
        final AttributeTable unsignedAttributes = this.getUnsignedAttributes();
        if (unsignedAttributes != null && unsignedAttributes.getAll(asn1ObjectIdentifier).size() > 0) {
            throw new CMSException("The " + str + " attribute MUST NOT be an unsigned attribute");
        }
        final AttributeTable signedAttributes = this.getSignedAttributes();
        if (signedAttributes == null) {
            return null;
        }
        final ASN1EncodableVector all = signedAttributes.getAll(asn1ObjectIdentifier);
        switch (all.size()) {
            case 0: {
                return null;
            }
            case 1: {
                final ASN1Set attrValues = ((Attribute)all.get(0)).getAttrValues();
                if (attrValues.size() != 1) {
                    throw new CMSException("A " + str + " attribute MUST have a single attribute value");
                }
                return attrValues.getObjectAt(0).toASN1Primitive();
            }
            default: {
                throw new CMSException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the " + str + " attribute");
            }
        }
    }
    
    private Time getSigningTime() throws CMSException {
        final ASN1Primitive singleValuedSignedAttribute = this.getSingleValuedSignedAttribute(CMSAttributes.signingTime, "signing-time");
        if (singleValuedSignedAttribute == null) {
            return null;
        }
        try {
            return Time.getInstance(singleValuedSignedAttribute);
        }
        catch (final IllegalArgumentException ex) {
            throw new CMSException("signing-time attribute value not a valid 'Time' structure");
        }
    }
    
    public static SignerInformation replaceUnsignedAttributes(final SignerInformation signerInformation, final AttributeTable attributeTable) {
        final SignerInfo info = signerInformation.info;
        ASN1Set set = null;
        if (attributeTable != null) {
            set = new DERSet(attributeTable.toASN1EncodableVector());
        }
        return new SignerInformation(new SignerInfo(info.getSID(), info.getDigestAlgorithm(), info.getAuthenticatedAttributes(), info.getDigestEncryptionAlgorithm(), info.getEncryptedDigest(), set), signerInformation.contentType, signerInformation.content, null);
    }
    
    public static SignerInformation addCounterSigners(final SignerInformation signerInformation, final SignerInformationStore signerInformationStore) {
        final SignerInfo info = signerInformation.info;
        final AttributeTable unsignedAttributes = signerInformation.getUnsignedAttributes();
        ASN1EncodableVector asn1EncodableVector;
        if (unsignedAttributes != null) {
            asn1EncodableVector = unsignedAttributes.toASN1EncodableVector();
        }
        else {
            asn1EncodableVector = new ASN1EncodableVector();
        }
        final ASN1EncodableVector asn1EncodableVector2 = new ASN1EncodableVector();
        final Iterator<SignerInformation> iterator = signerInformationStore.getSigners().iterator();
        while (iterator.hasNext()) {
            asn1EncodableVector2.add(iterator.next().toASN1Structure());
        }
        asn1EncodableVector.add(new Attribute(CMSAttributes.counterSignature, new DERSet(asn1EncodableVector2)));
        return new SignerInformation(new SignerInfo(info.getSID(), info.getDigestAlgorithm(), info.getAuthenticatedAttributes(), info.getDigestEncryptionAlgorithm(), info.getEncryptedDigest(), new DERSet(asn1EncodableVector)), signerInformation.contentType, signerInformation.content, null);
    }
    
    private static AlgorithmIdentifier translateBrokenRSAPkcs7(final AlgorithmIdentifier algorithmIdentifier, final AlgorithmIdentifier algorithmIdentifier2) {
        if (PKCSObjectIdentifiers.rsaEncryption.equals(algorithmIdentifier.getAlgorithm()) && (OIWObjectIdentifiers.sha1WithRSA.equals(algorithmIdentifier2.getAlgorithm()) || PKCSObjectIdentifiers.sha1WithRSAEncryption.equals(algorithmIdentifier2.getAlgorithm()))) {
            return new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
        }
        return algorithmIdentifier2;
    }
}
