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 Write(ReadOnlySpan<byte> buffer)
{
_out.Write(buffer);
}
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);
}
}
}