CmsSignedData
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Operators.Utilities;
using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.X509;
using System;
using System.Collections.Generic;
using System.IO;
namespace Org.BouncyCastle.Cms
{
    public class CmsSignedData
    {
        private readonly CmsProcessable signedContent;
        private SignedData signedData;
        private ContentInfo contentInfo;
        private SignerInformationStore signerInfoStore;
        private IDictionary<string, byte[]> m_hashes;
        public int Version => signedData.Version.IntValueExact;
        public DerObjectIdentifier SignedContentType => signedData.EncapContentInfo.ContentType;
        public CmsProcessable SignedContent => signedContent;
        public ContentInfo ContentInfo => contentInfo;
        private CmsSignedData(CmsSignedData c)
        {
            signedData = c.signedData;
            contentInfo = c.contentInfo;
            signedContent = c.signedContent;
            signerInfoStore = c.signerInfoStore;
        }
        public CmsSignedData(byte[] sigBlock)
            : this(CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false)))
        {
        }
        public CmsSignedData(CmsProcessable signedContent, byte[] sigBlock)
            : this(signedContent, CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false)))
        {
        }
        public CmsSignedData(IDictionary<string, byte[]> hashes, byte[] sigBlock)
            : this(hashes, CmsUtilities.ReadContentInfo(sigBlock))
        {
        }
        public CmsSignedData(CmsProcessable signedContent, Stream sigData)
            : this(signedContent, CmsUtilities.ReadContentInfo(sigData))
        {
        }
        public CmsSignedData(Stream sigData)
            : this(CmsUtilities.ReadContentInfo(sigData))
        {
        }
        public CmsSignedData(CmsProcessable signedContent, ContentInfo sigData)
        {
            this.signedContent = signedContent;
            contentInfo = sigData;
            signedData = SignedData.GetInstance(contentInfo.Content);
        }
        public CmsSignedData(IDictionary<string, byte[]> hashes, ContentInfo sigData)
        {
            m_hashes = hashes;
            contentInfo = sigData;
            signedData = SignedData.GetInstance(contentInfo.Content);
        }
        public CmsSignedData(ContentInfo sigData)
        {
            contentInfo = sigData;
            signedData = SignedData.GetInstance(contentInfo.Content);
            if (signedData.EncapContentInfo.Content != null)
                signedContent = new CmsProcessableByteArray(((Asn1OctetString)signedData.EncapContentInfo.Content).GetOctets());
        }
        public SignerInformationStore GetSignerInfos()
        {
            if (signerInfoStore == null) {
                List<SignerInformation> list = new List<SignerInformation>();
                foreach (Asn1Encodable signerInfo in signedData.SignerInfos) {
                    SignerInfo instance = SignerInfo.GetInstance(signerInfo);
                    DerObjectIdentifier contentType = signedData.EncapContentInfo.ContentType;
                    if (m_hashes == null)
                        list.Add(new SignerInformation(instance, contentType, signedContent, null));
                    else {
                        if (!m_hashes.TryGetValue(instance.DigestAlgorithm.Algorithm.Id, out byte[] value))
                            throw new InvalidOperationException();
                        list.Add(new SignerInformation(instance, contentType, null, value));
                    }
                }
                signerInfoStore = new SignerInformationStore(list);
            }
            return signerInfoStore;
        }
        public IStore<X509V2AttributeCertificate> GetAttributeCertificates()
        {
            return CmsSignedHelper.GetAttributeCertificates(signedData.Certificates);
        }
        public IStore<X509Certificate> GetCertificates()
        {
            return CmsSignedHelper.GetCertificates(signedData.Certificates);
        }
        public IStore<X509Crl> GetCrls()
        {
            return CmsSignedHelper.GetCrls(signedData.CRLs);
        }
        public IStore<Asn1Encodable> GetOtherRevInfos(DerObjectIdentifier otherRevInfoFormat)
        {
            return CmsSignedHelper.GetOtherRevInfos(signedData.CRLs, otherRevInfoFormat);
        }
        public ISet<AlgorithmIdentifier> GetDigestAlgorithmIDs()
        {
            Asn1Set digestAlgorithms = signedData.DigestAlgorithms;
            HashSet<AlgorithmIdentifier> hashSet = new HashSet<AlgorithmIdentifier>();
            foreach (Asn1Encodable item in digestAlgorithms) {
                hashSet.Add(AlgorithmIdentifier.GetInstance(item));
            }
            return CollectionUtilities.ReadOnly(hashSet);
        }
        public byte[] GetEncoded()
        {
            return contentInfo.GetEncoded();
        }
        public byte[] GetEncoded(string encoding)
        {
            return contentInfo.GetEncoded(encoding);
        }
        public static CmsSignedData AddDigestAlgorithm(CmsSignedData signedData, AlgorithmIdentifier digestAlgorithm)
        {
            return AddDigestAlgorithm(signedData, digestAlgorithm, DefaultDigestAlgorithmFinder.Instance);
        }
        public static CmsSignedData AddDigestAlgorithm(CmsSignedData signedData, AlgorithmIdentifier digestAlgorithm, IDigestAlgorithmFinder digestAlgorithmFinder)
        {
            ISet<AlgorithmIdentifier> digestAlgorithmIDs = signedData.GetDigestAlgorithmIDs();
            AlgorithmIdentifier item = CmsSignedHelper.FixDigestAlgID(digestAlgorithm, digestAlgorithmFinder);
            if (digestAlgorithmIDs.Contains(item))
                return signedData;
            CmsSignedData cmsSignedData = new CmsSignedData(signedData);
            HashSet<AlgorithmIdentifier> hashSet = new HashSet<AlgorithmIdentifier>();
            foreach (AlgorithmIdentifier item2 in hashSet) {
                hashSet.Add(CmsSignedHelper.FixDigestAlgID(item2, digestAlgorithmFinder));
            }
            hashSet.Add(item);
            Asn1Set element = CmsUtilities.ConvertToDLSet(hashSet);
            Asn1Sequence asn1Sequence = (Asn1Sequence)signedData.signedData.ToAsn1Object();
            Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(asn1Sequence.Count);
            asn1EncodableVector.Add(asn1Sequence[0]);
            asn1EncodableVector.Add(element);
            for (int i = 2; i != asn1Sequence.Count; i++) {
                asn1EncodableVector.Add(asn1Sequence[i]);
            }
            cmsSignedData.signedData = SignedData.GetInstance(new BerSequence(asn1EncodableVector));
            cmsSignedData.contentInfo = new ContentInfo(cmsSignedData.contentInfo.ContentType, cmsSignedData.signedData);
            return cmsSignedData;
        }
        public static CmsSignedData ReplaceSigners(CmsSignedData signedData, SignerInformationStore signerInformationStore)
        {
            return ReplaceSigners(signedData, signerInformationStore, DefaultDigestAlgorithmFinder.Instance);
        }
        public static CmsSignedData ReplaceSigners(CmsSignedData signedData, SignerInformationStore signerInformationStore, IDigestAlgorithmFinder digestAlgorithmFinder)
        {
            CmsSignedData cmsSignedData = new CmsSignedData(signedData);
            cmsSignedData.signerInfoStore = signerInformationStore;
            HashSet<AlgorithmIdentifier> digestAlgs = new HashSet<AlgorithmIdentifier>();
            IList<SignerInformation> signers = signerInformationStore.GetSigners();
            Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(signers.Count);
            foreach (SignerInformation item in signers) {
                CmsUtilities.AddDigestAlgs(digestAlgs, item, digestAlgorithmFinder);
                asn1EncodableVector.Add(item.ToSignerInfo());
            }
            Asn1Set element = CmsUtilities.ConvertToDLSet(digestAlgs);
            Asn1Set element2 = DLSet.FromVector(asn1EncodableVector);
            Asn1Sequence asn1Sequence = (Asn1Sequence)signedData.signedData.ToAsn1Object();
            asn1EncodableVector = new Asn1EncodableVector(asn1Sequence.Count);
            asn1EncodableVector.Add(asn1Sequence[0]);
            asn1EncodableVector.Add(element);
            for (int i = 2; i != asn1Sequence.Count - 1; i++) {
                asn1EncodableVector.Add(asn1Sequence[i]);
            }
            asn1EncodableVector.Add(element2);
            cmsSignedData.signedData = SignedData.GetInstance(new BerSequence(asn1EncodableVector));
            cmsSignedData.contentInfo = new ContentInfo(cmsSignedData.contentInfo.ContentType, cmsSignedData.signedData);
            return cmsSignedData;
        }
        public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls)
        {
            return ReplaceCertificatesAndRevocations(signedData, x509Certs, x509Crls, null, null);
        }
        public static CmsSignedData ReplaceCertificatesAndCrls(CmsSignedData signedData, IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, IStore<X509V2AttributeCertificate> x509AttrCerts)
        {
            return ReplaceCertificatesAndRevocations(signedData, x509Certs, x509Crls, x509AttrCerts, null);
        }
        public static CmsSignedData ReplaceCertificatesAndRevocations(CmsSignedData signedData, IStore<X509Certificate> x509Certs, IStore<X509Crl> x509Crls, IStore<X509V2AttributeCertificate> x509AttrCerts, IStore<OtherRevocationInfoFormat> otherRevocationInfos)
        {
            CmsSignedData cmsSignedData = new CmsSignedData(signedData);
            Asn1Set certificates = null;
            Asn1Set crls = null;
            if (x509Certs != null || x509AttrCerts != null) {
                List<Asn1Encodable> list = new List<Asn1Encodable>();
                if (x509Certs != null)
                    list.AddRange(CmsUtilities.GetCertificatesFromStore(x509Certs));
                if (x509AttrCerts != null)
                    list.AddRange(CmsUtilities.GetAttributeCertificatesFromStore(x509AttrCerts));
                Asn1Set asn1Set = CmsUtilities.CreateBerSetFromList(list);
                if (asn1Set.Count > 0)
                    certificates = asn1Set;
            }
            if (x509Crls != null || otherRevocationInfos != null) {
                List<Asn1Encodable> list2 = new List<Asn1Encodable>();
                if (x509Crls != null)
                    list2.AddRange(CmsUtilities.GetCrlsFromStore(x509Crls));
                if (otherRevocationInfos != null)
                    list2.AddRange(CmsUtilities.GetOtherRevocationInfosFromStore(otherRevocationInfos));
                Asn1Set asn1Set2 = CmsUtilities.CreateBerSetFromList(list2);
                if (asn1Set2.Count > 0)
                    crls = asn1Set2;
            }
            SignedData signedData2 = signedData.signedData;
            cmsSignedData.signedData = new SignedData(signedData2.DigestAlgorithms, signedData2.EncapContentInfo, certificates, crls, signedData2.SignerInfos);
            cmsSignedData.contentInfo = new ContentInfo(cmsSignedData.contentInfo.ContentType, cmsSignedData.signedData);
            return cmsSignedData;
        }
    }
}