<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />

CmsSignedDataStreamGenerator

using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Cms; using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Operators.Utilities; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities.Collections; using Org.BouncyCastle.Utilities.IO; using Org.BouncyCastle.X509; using System; using System.Collections.Generic; using System.IO; namespace Org.BouncyCastle.Cms { public class CmsSignedDataStreamGenerator : CmsSignedGenerator { private class SignerInfoGeneratorImpl { private readonly CmsSignedDataStreamGenerator m_outer; private readonly SignerIdentifier m_signerID; private readonly AlgorithmIdentifier m_digAlgID; private readonly DerObjectIdentifier m_sigAlgOid; private readonly CmsAttributeTableGenerator m_sAttrGen; private readonly CmsAttributeTableGenerator m_unsAttrGen; private readonly string m_encName; private readonly ISigner m_signer; internal AlgorithmIdentifier DigestAlgorithm => m_digAlgID; internal int GeneratedVersion { get { if (!m_signerID.IsTagged) return 1; return 3; } } internal SignerInfoGeneratorImpl(CmsSignedDataStreamGenerator outer, AsymmetricKeyParameter key, SignerIdentifier signerID, DerObjectIdentifier digAlgOid, DerObjectIdentifier sigAlgOid, CmsAttributeTableGenerator sAttrGen, CmsAttributeTableGenerator unsAttrGen) { string encryptionAlgName = CmsSignedHelper.GetEncryptionAlgName(sigAlgOid); string algorithm = CmsSignedHelper.GetDigestAlgName(digAlgOid) + "with" + encryptionAlgName; ISigner signer; if (sAttrGen != null) signer = SignerUtilities.InitSigner(algorithm, true, key, outer.m_random); else if ("RSA" == encryptionAlgName) { signer = SignerUtilities.InitSigner("RSA", true, key, outer.m_random); } else { if (!("DSA" == encryptionAlgName)) throw new SignatureException("algorithm: " + m_encName + " not supported in base signatures."); signer = SignerUtilities.InitSigner("NONEwithDSA", true, key, outer.m_random); } m_outer = outer; m_signerID = signerID; m_digAlgID = outer.DigestAlgorithmFinder.Find(digAlgOid); m_sigAlgOid = sigAlgOid; m_sAttrGen = sAttrGen; m_unsAttrGen = unsAttrGen; m_encName = encryptionAlgName; m_signer = signer; } internal SignerInfo Generate(DerObjectIdentifier contentType, byte[] calculatedDigest) { AlgorithmIdentifier algorithmIdentifier = m_digAlgID; DerObjectIdentifier algorithm = algorithmIdentifier.Algorithm; try { string algorithm2 = CmsSignedHelper.GetDigestAlgName(algorithm) + "with" + m_encName; byte[] array = calculatedDigest; Asn1Set asn1Set = null; if (m_sAttrGen != null) { IDictionary<CmsAttributeTableParameter, object> baseParameters = m_outer.GetBaseParameters(contentType, algorithmIdentifier, calculatedDigest); Org.BouncyCastle.Asn1.Cms.AttributeTable attributeTable = m_sAttrGen.GetAttributes(CollectionUtilities.ReadOnly(baseParameters)); if (contentType == null) attributeTable = attributeTable?.Remove(CmsAttributes.ContentType); asn1Set = m_outer.GetAttributeSet(attributeTable); array = asn1Set.GetEncoded("DER"); } else if (m_encName.Equals("RSA")) { array = new DigestInfo(algorithmIdentifier, calculatedDigest).GetEncoded("DER"); } m_signer.BlockUpdate(array, 0, array.Length); byte[] array2 = m_signer.GenerateSignature(); Asn1Set unauthenticatedAttributes = null; if (m_unsAttrGen != null) { IDictionary<CmsAttributeTableParameter, object> baseParameters2 = m_outer.GetBaseParameters(contentType, algorithmIdentifier, calculatedDigest); baseParameters2[CmsAttributeTableParameter.Signature] = array2.Clone(); Org.BouncyCastle.Asn1.Cms.AttributeTable attributes = m_unsAttrGen.GetAttributes(CollectionUtilities.ReadOnly(baseParameters2)); unauthenticatedAttributes = m_outer.GetAttributeSet(attributes); } Asn1Encodable defaultX509Parameters = SignerUtilities.GetDefaultX509Parameters(algorithm2); AlgorithmIdentifier sigAlgID = CmsSignedHelper.GetSigAlgID(m_sigAlgOid, defaultX509Parameters); if (m_sAttrGen == null && EdECObjectIdentifiers.id_Ed448.Equals(sigAlgID.Algorithm)) algorithmIdentifier = new AlgorithmIdentifier(NistObjectIdentifiers.IdShake256); DerOctetString encryptedDigest = new DerOctetString(array2); return new SignerInfo(m_signerID, algorithmIdentifier, asn1Set, sigAlgID, encryptedDigest, unauthenticatedAttributes); } catch (IOException innerException) { throw new CmsStreamException("encoding error.", innerException); } catch (SignatureException innerException2) { throw new CmsStreamException("error creating signature.", innerException2); } } } private class CmsSignedDataOutputStream : BaseOutputStream { private readonly CmsSignedDataStreamGenerator outer; private Stream _out; private DerObjectIdentifier _contentOid; private BerSequenceGenerator _sGen; private BerSequenceGenerator _sigGen; private BerSequenceGenerator _eiGen; private BerOctetStringGenerator _octGen; internal CmsSignedDataOutputStream(CmsSignedDataStreamGenerator outer, Stream outStream, DerObjectIdentifier contentOid, BerSequenceGenerator sGen, BerSequenceGenerator sigGen, BerSequenceGenerator eiGen, BerOctetStringGenerator octGen) { this.outer = outer; _out = outStream; _contentOid = contentOid; _sGen = sGen; _sigGen = sigGen; _eiGen = eiGen; _octGen = octGen; } public override void Write(byte[] buffer, int offset, int count) { _out.Write(buffer, offset, count); } public override void WriteByte(byte value) { _out.WriteByte(value); } protected override void Dispose(bool disposing) { if (disposing) DoClose(); base.Dispose(disposing); } private void DoClose() { _out.Dispose(); _octGen?.Dispose(); _eiGen.Dispose(); outer.m_digests.Clear(); if (outer._certs.Count > 0) { Asn1Set obj = outer._useDerForCerts ? outer._certs.ToDerSet() : outer._certs.ToBerSet(); WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, obj)); } if (outer._crls.Count > 0) { Asn1Set obj2 = outer._useDerForCrls ? outer._crls.ToDerSet() : outer._crls.ToBerSet(); WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, obj2)); } foreach (KeyValuePair<DerObjectIdentifier, IDigest> messageDigest in outer.m_messageDigests) { outer.m_digests.Add(messageDigest.Key, DigestUtilities.DoFinal(messageDigest.Value)); } Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(); foreach (SignerInfoGeneratorImpl signerInfoGen in outer.m_signerInfoGens) { DerObjectIdentifier algorithm = signerInfoGen.DigestAlgorithm.Algorithm; byte[] calculatedDigest = outer.m_digests[algorithm]; asn1EncodableVector.Add(signerInfoGen.Generate(_contentOid, calculatedDigest)); } foreach (SignerInformation signer in outer._signers) { asn1EncodableVector.Add(signer.SignerInfo); } WriteToGenerator(_sigGen, DerSet.FromVector(asn1EncodableVector)); _sigGen.Dispose(); _sGen.Dispose(); } private static void WriteToGenerator(Asn1Generator ag, Asn1Encodable ae) { ae.EncodeTo(ag.GetRawOutputStream()); } } private readonly List<SignerInfoGeneratorImpl> m_signerInfoGens = new List<SignerInfoGeneratorImpl>(); private readonly HashSet<DerObjectIdentifier> m_messageDigestOids = new HashSet<DerObjectIdentifier>(); private readonly Dictionary<DerObjectIdentifier, IDigest> m_messageDigests = new Dictionary<DerObjectIdentifier, IDigest>(); private bool _messageDigestsLocked; private int _bufferSize; public CmsSignedDataStreamGenerator() { } public CmsSignedDataStreamGenerator(SecureRandom random) : base(random) { } public void SetBufferSize(int bufferSize) { _bufferSize = bufferSize; } public void AddDigests(params string[] digestOids) { foreach (string identifier in digestOids) { ConfigureDigest(new DerObjectIdentifier(identifier)); } } public void AddDigests(IEnumerable<string> digestOids) { foreach (string digestOid in digestOids) { ConfigureDigest(new DerObjectIdentifier(digestOid)); } } public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string digestOid) { AddSigner(privateKey, cert, digestOid, new DefaultSignedAttributeTableGenerator(), null); } public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string encryptionOid, string digestOid) { AddSigner(privateKey, cert, encryptionOid, digestOid, new DefaultSignedAttributeTableGenerator(), null); } public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string digestOid, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr) { AddSigner(privateKey, cert, digestOid, new DefaultSignedAttributeTableGenerator(signedAttr), new SimpleAttributeTableGenerator(unsignedAttr)); } public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string encryptionOid, string digestOid, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr) { AddSigner(privateKey, cert, encryptionOid, digestOid, new DefaultSignedAttributeTableGenerator(signedAttr), new SimpleAttributeTableGenerator(unsignedAttr)); } public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator) { AddSigner(privateKey, cert, CmsSignedHelper.GetEncOid(privateKey, digestOid)?.GetID(), digestOid, signedAttrGenerator, unsignedAttrGenerator); } public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator) { DoAddSigner(privateKey, CmsSignedGenerator.GetSignerIdentifier(cert), new DerObjectIdentifier(encryptionOid), new DerObjectIdentifier(digestOid), signedAttrGenerator, unsignedAttrGenerator); } public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string digestOid) { AddSigner(privateKey, subjectKeyID, digestOid, new DefaultSignedAttributeTableGenerator(), null); } public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string encryptionOid, string digestOid) { AddSigner(privateKey, subjectKeyID, encryptionOid, digestOid, new DefaultSignedAttributeTableGenerator(), null); } public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string digestOid, Org.BouncyCastle.Asn1.Cms.AttributeTable signedAttr, Org.BouncyCastle.Asn1.Cms.AttributeTable unsignedAttr) { AddSigner(privateKey, subjectKeyID, digestOid, new DefaultSignedAttributeTableGenerator(signedAttr), new SimpleAttributeTableGenerator(unsignedAttr)); } public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator) { AddSigner(privateKey, subjectKeyID, CmsSignedHelper.GetEncOid(privateKey, digestOid)?.GetID(), digestOid, signedAttrGenerator, unsignedAttrGenerator); } public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator) { DoAddSigner(privateKey, CmsSignedGenerator.GetSignerIdentifier(subjectKeyID), new DerObjectIdentifier(encryptionOid), new DerObjectIdentifier(digestOid), signedAttrGenerator, unsignedAttrGenerator); } private void DoAddSigner(AsymmetricKeyParameter privateKey, SignerIdentifier signerIdentifier, DerObjectIdentifier encryptionOid, DerObjectIdentifier digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator) { ConfigureDigest(digestOid); SignerInfoGeneratorImpl item = new SignerInfoGeneratorImpl(this, privateKey, signerIdentifier, digestOid, encryptionOid, signedAttrGenerator, unsignedAttrGenerator); m_signerInfoGens.Add(item); } internal override void AddSignerCallback(SignerInformation signerInformation) { RegisterDigestOid(signerInformation.DigestAlgorithmID.Algorithm); } public Stream Open(Stream outStream) { return Open(outStream, false); } public Stream Open(Stream outStream, bool encapsulate) { return Open(outStream, CmsSignedGenerator.Data, encapsulate); } public Stream Open(Stream outStream, bool encapsulate, Stream dataOutputStream) { return Open(outStream, CmsSignedGenerator.Data, encapsulate, dataOutputStream); } public Stream Open(Stream outStream, string signedContentType, bool encapsulate) { return Open(outStream, signedContentType, encapsulate, null); } public Stream Open(Stream outStream, string signedContentType, bool encapsulate, Stream dataOutputStream) { if (outStream == null) throw new ArgumentNullException("outStream"); if (!outStream.CanWrite) throw new ArgumentException("Expected writeable stream", "outStream"); if (dataOutputStream != null && !dataOutputStream.CanWrite) throw new ArgumentException("Expected writeable stream", "dataOutputStream"); _messageDigestsLocked = true; BerSequenceGenerator berSequenceGenerator = new BerSequenceGenerator(outStream); berSequenceGenerator.AddObject(CmsObjectIdentifiers.SignedData); BerSequenceGenerator berSequenceGenerator2 = new BerSequenceGenerator(berSequenceGenerator.GetRawOutputStream(), 0, true); DerObjectIdentifier derObjectIdentifier = new DerObjectIdentifier(signedContentType); berSequenceGenerator2.AddObject(CalculateVersion(derObjectIdentifier)); HashSet<DerObjectIdentifier> messageDigestOids = m_messageDigestOids; IDigestAlgorithmFinder digestAlgorithmFinder = base.DigestAlgorithmFinder; DerSet.Map(messageDigestOids, digestAlgorithmFinder.Find).EncodeTo(berSequenceGenerator2.GetRawOutputStream()); BerSequenceGenerator berSequenceGenerator3 = new BerSequenceGenerator(berSequenceGenerator2.GetRawOutputStream()); berSequenceGenerator3.AddObject(derObjectIdentifier); BerOctetStringGenerator berOctetStringGenerator = null; Stream s = null; if (encapsulate) { berOctetStringGenerator = new BerOctetStringGenerator(berSequenceGenerator3.GetRawOutputStream(), 0, true); s = berOctetStringGenerator.GetOctetOutputStream(_bufferSize); } Stream safeTeeOutputStream = GetSafeTeeOutputStream(dataOutputStream, s); Stream outStream2 = AttachDigestsToOutputStream(m_messageDigests.Values, safeTeeOutputStream); return new CmsSignedDataOutputStream(this, outStream2, derObjectIdentifier, berSequenceGenerator, berSequenceGenerator2, berSequenceGenerator3, berOctetStringGenerator); } private void RegisterDigestOid(DerObjectIdentifier digestOid) { if (!_messageDigestsLocked) m_messageDigestOids.Add(digestOid); else if (!m_messageDigestOids.Contains(digestOid)) { throw new InvalidOperationException("Cannot register new digest OIDs after the data stream is opened"); } } private void ConfigureDigest(DerObjectIdentifier digestOid) { RegisterDigestOid(digestOid); if (!m_messageDigests.ContainsKey(digestOid)) { if (_messageDigestsLocked) throw new InvalidOperationException("Cannot configure new digests after the data stream is opened"); m_messageDigests[digestOid] = DigestUtilities.GetDigest(digestOid); } } internal void Generate(Stream outStream, string eContentType, bool encapsulate, Stream dataOutputStream, CmsProcessable content) { using (Stream outStream2 = Open(outStream, eContentType, encapsulate, dataOutputStream)) content?.Write(outStream2); } private DerInteger CalculateVersion(DerObjectIdentifier contentOid) { bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; List<Asn1Encodable>.Enumerator enumerator; if (_certs != null) { enumerator = _certs.GetEnumerator(); try { while (enumerator.MoveNext()) { Asn1TaggedObject asn1TaggedObject = enumerator.Current as Asn1TaggedObject; if (asn1TaggedObject != null) { if (asn1TaggedObject.TagNo == 1) flag3 = true; else if (asn1TaggedObject.TagNo == 2) { flag4 = true; } else if (asn1TaggedObject.TagNo == 3) { flag = true; break; } } } } finally { ((IDisposable)enumerator).Dispose(); } } if (flag) return DerInteger.Five; if (_crls != null) { enumerator = _crls.GetEnumerator(); try { while (enumerator.MoveNext()) { if (enumerator.Current is Asn1TaggedObject) { flag2 = true; break; } } } finally { ((IDisposable)enumerator).Dispose(); } } if (flag2) return DerInteger.Five; if (flag4) return DerInteger.Four; if (flag3 || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(_signers, m_signerInfoGens)) return DerInteger.Three; return DerInteger.One; } private static Stream AttachDigestsToOutputStream(IEnumerable<IDigest> digests, Stream s) { Stream stream = s; foreach (IDigest digest in digests) { stream = GetSafeTeeOutputStream(stream, new DigestSink(digest)); } return stream; } private static bool CheckForVersion3(IList<SignerInformation> signerInfos, IList<SignerInfoGeneratorImpl> signerInfoGens) { foreach (SignerInformation signerInfo in signerInfos) { if (signerInfo.SignerInfo.Version.HasValue(3)) return true; } foreach (SignerInfoGeneratorImpl signerInfoGen in signerInfoGens) { if (signerInfoGen.GeneratedVersion == 3) return true; } return false; } private static Stream GetSafeOutputStream(Stream s) { return s ?? Stream.Null; } private static Stream GetSafeTeeOutputStream(Stream s1, Stream s2) { if (s1 == null) return GetSafeOutputStream(s2); if (s2 == null) return GetSafeOutputStream(s1); return new TeeOutputStream(s1, s2); } } }