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 class PreserveAbsentParameters : IDigestAlgorithmFinder
{
private readonly IDigestAlgorithmFinder m_inner;
private readonly Dictionary<DerObjectIdentifier, AlgorithmIdentifier> m_absent;
internal PreserveAbsentParameters(IDigestAlgorithmFinder inner, IEnumerable<AlgorithmIdentifier> algIDs)
{
if (inner == null)
throw new ArgumentNullException("inner");
m_inner = inner;
if (algIDs == null)
throw new ArgumentNullException("algIDs");
m_absent = BuildAbsent(algIDs);
}
public AlgorithmIdentifier Find(AlgorithmIdentifier signatureAlgorithm)
{
return Preserve(m_inner.Find(signatureAlgorithm));
}
public AlgorithmIdentifier Find(DerObjectIdentifier digestOid)
{
if (m_absent.TryGetValue(digestOid, out AlgorithmIdentifier value))
return value;
return m_inner.Find(digestOid);
}
public AlgorithmIdentifier Find(string digestName)
{
return Preserve(m_inner.Find(digestName));
}
private AlgorithmIdentifier Preserve(AlgorithmIdentifier algID)
{
if (X509Utilities.HasAbsentParameters(algID) && m_absent.TryGetValue(algID.Algorithm, out AlgorithmIdentifier value))
return value;
return algID;
}
private static Dictionary<DerObjectIdentifier, AlgorithmIdentifier> BuildAbsent(IEnumerable<AlgorithmIdentifier> algIDs)
{
Dictionary<DerObjectIdentifier, AlgorithmIdentifier> dictionary = new Dictionary<DerObjectIdentifier, AlgorithmIdentifier>();
foreach (AlgorithmIdentifier algID in algIDs) {
if (X509Utilities.HasAbsentParameters(algID))
CollectionUtilities.TryAdd(dictionary, algID.Algorithm, algID);
}
return dictionary;
}
}
private readonly ContentInfo m_contentInfo;
private readonly SignedData m_signedData;
private readonly CmsProcessable m_signedContent;
private readonly IDictionary<string, byte[]> m_hashes;
private SignerInformationStore m_signerInfoStore;
public ContentInfo ContentInfo => m_contentInfo;
public CmsProcessable SignedContent => m_signedContent;
public DerObjectIdentifier SignedContentType => SignedData.EncapContentInfo.ContentType;
public SignedData SignedData => m_signedData;
public int Version => SignedData.Version.IntValueExact;
private CmsSignedData(CmsSignedData c)
{
m_contentInfo = c.m_contentInfo;
m_signedData = c.m_signedData;
m_signedContent = c.m_signedContent;
m_hashes = null;
m_signerInfoStore = c.m_signerInfoStore;
}
private CmsSignedData(DerObjectIdentifier contentType, SignedData signedData, CmsProcessable signedContent, SignerInformationStore signerInfoStore)
{
m_contentInfo = new ContentInfo(contentType, signedData);
m_signedData = signedData;
m_signedContent = signedContent;
m_hashes = null;
m_signerInfoStore = 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)
{
m_contentInfo = sigData;
m_signedData = SignedData.GetInstance(sigData.Content);
m_signedContent = signedContent;
}
public CmsSignedData(IDictionary<string, byte[]> hashes, ContentInfo sigData)
{
m_contentInfo = sigData;
m_signedData = SignedData.GetInstance(sigData.Content);
m_signedContent = null;
m_hashes = hashes;
}
public CmsSignedData(ContentInfo sigData)
{
m_contentInfo = sigData;
m_signedData = SignedData.GetInstance(sigData.Content);
ContentInfo encapContentInfo = m_signedData.EncapContentInfo;
Asn1Encodable content = encapContentInfo.Content;
if (content != null) {
Asn1OctetString asn1OctetString = content as Asn1OctetString;
if (asn1OctetString != null)
m_signedContent = new CmsProcessableByteArray(asn1OctetString.GetOctets());
else
m_signedContent = new Pkcs7ProcessableObject(encapContentInfo.ContentType, content);
}
}
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);
}
[Obsolete("Use 'GetDigestAlgorithms' instead")]
public ISet<AlgorithmIdentifier> GetDigestAlgorithmIDs()
{
HashSet<AlgorithmIdentifier> hashSet = new HashSet<AlgorithmIdentifier>();
foreach (Asn1Encodable digestAlgorithm in SignedData.DigestAlgorithms) {
hashSet.Add(AlgorithmIdentifier.GetInstance(digestAlgorithm));
}
return CollectionUtilities.ReadOnly(hashSet);
}
public IEnumerable<AlgorithmIdentifier> GetDigestAlgorithms()
{
return CollectionUtilities.Select(SignedData.DigestAlgorithms, AlgorithmIdentifier.GetInstance);
}
public byte[] GetEncoded()
{
return m_contentInfo.GetEncoded();
}
public byte[] GetEncoded(string encoding)
{
return m_contentInfo.GetEncoded(encoding);
}
public IStore<Asn1Encodable> GetOtherRevInfos(DerObjectIdentifier otherRevInfoFormat)
{
return CmsSignedHelper.GetOtherRevInfos(m_signedData.CRLs, otherRevInfoFormat);
}
public SignerInformationStore GetSignerInfos()
{
if (m_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.GetID(), out byte[] value))
throw new InvalidOperationException();
list.Add(new SignerInformation(instance, contentType, null, value));
}
}
m_signerInfoStore = new SignerInformationStore(list);
}
return m_signerInfoStore;
}
public static CmsSignedData AddDigestAlgorithm(CmsSignedData signedData, AlgorithmIdentifier digestAlgorithm)
{
return AddDigestAlgorithm(signedData, digestAlgorithm, DefaultDigestAlgorithmFinder.Instance);
}
public static CmsSignedData AddDigestAlgorithm(CmsSignedData signedData, AlgorithmIdentifier digestAlgorithm, IDigestAlgorithmFinder digestAlgorithmFinder)
{
DigestAlgorithmsBuilder digestAlgorithmsBuilder = new DigestAlgorithmsBuilder(digestAlgorithmFinder);
digestAlgorithmsBuilder.AddExisting(signedData.GetDigestAlgorithms());
if (!digestAlgorithmsBuilder.Add(digestAlgorithm))
return signedData;
SignedData signedData2 = signedData.SignedData;
SignedData signedData3 = new SignedData(digestAlgorithmsBuilder.Build(!(signedData2.DigestAlgorithms is BerSet)), signedData2.EncapContentInfo, signedData2.Certificates, signedData2.CRLs, signedData2.SignerInfos);
return new CmsSignedData(signedData.ContentInfo.ContentType, signedData3, signedData.m_signedContent, signedData.m_signerInfoStore);
}
public static CmsSignedData ReplaceSigners(CmsSignedData signedData, SignerInformationStore signerInformationStore)
{
return ReplaceSigners(signedData, signerInformationStore, DefaultDigestAlgorithmFinder.Instance);
}
public static CmsSignedData ReplaceSigners(CmsSignedData signedData, SignerInformationStore signerInformationStore, IDigestAlgorithmFinder digestAlgorithmFinder)
{
digestAlgorithmFinder = new PreserveAbsentParameters(digestAlgorithmFinder, signedData.GetDigestAlgorithms());
DigestAlgorithmsBuilder digestAlgorithmsBuilder = new DigestAlgorithmsBuilder(digestAlgorithmFinder);
List<SignerInformation> signersInternal = signerInformationStore.SignersInternal;
List<SignerInfo> list = new List<SignerInfo>(signersInternal.Count);
foreach (SignerInformation item in signersInternal) {
CmsUtilities.AddDigestAlgorithms(digestAlgorithmsBuilder, item);
list.Add(item.SignerInfo);
}
SignedData signedData2 = signedData.SignedData;
SignedData signedData3 = new SignedData(digestAlgorithmsBuilder.Build(!(signedData2.DigestAlgorithms is BerSet)), signerInfos: list.ToAsn1Set(false, !(signedData2.SignerInfos is BerSet)), contentInfo: signedData2.EncapContentInfo, certificates: signedData2.Certificates, crls: signedData2.CRLs);
return new CmsSignedData(signedData.ContentInfo.ContentType, signedData3, signedData.m_signedContent, signerInformationStore);
}
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)
{
Asn1Set certificates = null;
Asn1Set crls = null;
if (x509Certs != null || x509AttrCerts != null) {
List<Asn1Encodable> list = new List<Asn1Encodable>();
if (x509Certs != null)
CmsUtilities.CollectCertificates(list, x509Certs);
if (x509AttrCerts != null)
CmsUtilities.CollectAttributeCertificates(list, x509AttrCerts);
Asn1Set asn1Set = list.ToBerSet();
if (asn1Set.Count > 0)
certificates = asn1Set;
}
if (x509Crls != null || otherRevocationInfos != null) {
List<Asn1Encodable> list2 = new List<Asn1Encodable>();
if (x509Crls != null)
CmsUtilities.CollectCrls(list2, x509Crls);
if (otherRevocationInfos != null)
CmsUtilities.CollectOtherRevocationInfos(list2, otherRevocationInfos);
Asn1Set asn1Set2 = list2.ToBerSet();
if (asn1Set2.Count > 0)
crls = asn1Set2;
}
SignedData signedData2 = signedData.SignedData;
SignedData signedData3 = new SignedData(signedData2.DigestAlgorithms, signedData2.EncapContentInfo, certificates, crls, signedData2.SignerInfos);
return new CmsSignedData(signedData.ContentInfo.ContentType, signedData3, signedData.m_signedContent, signedData.m_signerInfoStore);
}
}
}