CmsSignedDataStreamGenerator
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cms;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.IO;
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 outer;
private readonly SignerIdentifier _signerIdentifier;
internal readonly DerObjectIdentifier m_digestOid;
private readonly DerObjectIdentifier m_encOid;
private readonly CmsAttributeTableGenerator _sAttr;
private readonly CmsAttributeTableGenerator _unsAttr;
private readonly string _encName;
private readonly ISigner _sig;
internal SignerInfoGeneratorImpl(CmsSignedDataStreamGenerator outer, AsymmetricKeyParameter key, SignerIdentifier signerIdentifier, DerObjectIdentifier digestOid, DerObjectIdentifier encOid, CmsAttributeTableGenerator sAttr, CmsAttributeTableGenerator unsAttr)
{
this.outer = outer;
_signerIdentifier = signerIdentifier;
m_digestOid = digestOid;
m_encOid = encOid;
_sAttr = sAttr;
_unsAttr = unsAttr;
_encName = CmsSignedHelper.GetEncryptionAlgName(m_encOid);
string algorithm = CmsSignedHelper.GetDigestAlgName(digestOid) + "with" + _encName;
if (_sAttr != null)
_sig = SignerUtilities.InitSigner(algorithm, true, key, outer.m_random);
else if (_encName.Equals("RSA")) {
_sig = SignerUtilities.InitSigner("RSA", true, key, outer.m_random);
} else {
if (!_encName.Equals("DSA"))
throw new SignatureException("algorithm: " + _encName + " not supported in base signatures.");
_sig = SignerUtilities.InitSigner("NONEwithDSA", true, key, outer.m_random);
}
}
internal SignerInfo Generate(DerObjectIdentifier contentType, byte[] calculatedDigest)
{
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(m_digestOid, DerNull.Instance);
try {
string algorithm = CmsSignedHelper.GetDigestAlgName(m_digestOid) + "with" + _encName;
byte[] array = calculatedDigest;
Asn1Set asn1Set = null;
if (_sAttr != null) {
IDictionary<CmsAttributeTableParameter, object> baseParameters = outer.GetBaseParameters(contentType, algorithmIdentifier, calculatedDigest);
Org.BouncyCastle.Asn1.Cms.AttributeTable attributeTable = _sAttr.GetAttributes(CollectionUtilities.ReadOnly(baseParameters));
if (contentType == null && attributeTable != null && attributeTable[CmsAttributes.ContentType] != null)
attributeTable = attributeTable.Remove(CmsAttributes.ContentType);
asn1Set = outer.GetAttributeSet(attributeTable);
array = asn1Set.GetEncoded("DER");
} else if (_encName.Equals("RSA")) {
array = new DigestInfo(algorithmIdentifier, calculatedDigest).GetEncoded("DER");
}
_sig.BlockUpdate(array, 0, array.Length);
byte[] array2 = _sig.GenerateSignature();
Asn1Set unauthenticatedAttributes = null;
if (_unsAttr != null) {
IDictionary<CmsAttributeTableParameter, object> baseParameters2 = outer.GetBaseParameters(contentType, algorithmIdentifier, calculatedDigest);
baseParameters2[CmsAttributeTableParameter.Signature] = array2.Clone();
Org.BouncyCastle.Asn1.Cms.AttributeTable attributes = _unsAttr.GetAttributes(CollectionUtilities.ReadOnly(baseParameters2));
unauthenticatedAttributes = outer.GetAttributeSet(attributes);
}
Asn1Encodable defaultX509Parameters = SignerUtilities.GetDefaultX509Parameters(algorithm);
AlgorithmIdentifier encAlgorithmIdentifier = CmsSignedHelper.GetEncAlgorithmIdentifier(m_encOid, defaultX509Parameters);
return new SignerInfo(_signerIdentifier, algorithmIdentifier, asn1Set, encAlgorithmIdentifier, new DerOctetString(array2), 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;
public CmsSignedDataOutputStream(CmsSignedDataStreamGenerator outer, Stream outStream, string contentOID, BerSequenceGenerator sGen, BerSequenceGenerator sigGen, BerSequenceGenerator eiGen, BerOctetStringGenerator octGen)
{
this.outer = outer;
_out = outStream;
_contentOID = new DerObjectIdentifier(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 ? CmsUtilities.CreateDerSetFromList(outer._certs) : CmsUtilities.CreateBerSetFromList(outer._certs);
WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, obj));
}
if (outer._crls.Count > 0) {
Asn1Set obj2 = outer.UseDerForCrls ? CmsUtilities.CreateDerSetFromList(outer._crls) : CmsUtilities.CreateBerSetFromList(outer._crls);
WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, obj2));
}
foreach (KeyValuePair<string, IDigest> messageDigest in outer.m_messageDigests) {
outer.m_messageHashes.Add(messageDigest.Key, DigestUtilities.DoFinal(messageDigest.Value));
}
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector();
foreach (SignerInfoGeneratorImpl signerInfoGen in outer.m_signerInfoGens) {
DerObjectIdentifier digestOid = signerInfoGen.m_digestOid;
string digestAlgName = CmsSignedHelper.GetDigestAlgName(digestOid);
byte[] array = outer.m_messageHashes[digestAlgName];
outer.m_digests[digestOid] = (byte[])array.Clone();
asn1EncodableVector.Add(signerInfoGen.Generate(_contentOID, array));
}
foreach (SignerInformation signer in outer._signers) {
asn1EncodableVector.Add(signer.ToSignerInfo());
}
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 IDictionary<string, IDigest> m_messageDigests = new Dictionary<string, IDigest>(StringComparer.OrdinalIgnoreCase);
private readonly IDictionary<string, byte[]> m_messageHashes = new Dictionary<string, byte[]>(StringComparer.OrdinalIgnoreCase);
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)?.Id, 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)?.Id, 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 si)
{
RegisterDigestOid(si.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 = (signedContentType == null) ? null : new DerObjectIdentifier(signedContentType);
berSequenceGenerator2.AddObject(CalculateVersion(derObjectIdentifier));
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector(m_messageDigestOids.Count);
foreach (DerObjectIdentifier messageDigestOid in m_messageDigestOids) {
asn1EncodableVector.Add(new AlgorithmIdentifier(messageDigestOid, DerNull.Instance));
}
DerSet.FromVector(asn1EncodableVector).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, signedContentType, 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);
string digestAlgName = CmsSignedHelper.GetDigestAlgName(digestOid);
if (!m_messageDigests.ContainsKey(digestAlgName)) {
if (_messageDigestsLocked)
throw new InvalidOperationException("Cannot configure new digests after the data stream is opened");
m_messageDigests[digestAlgName] = CmsSignedHelper.GetDigestInstance(digestAlgName);
}
}
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))
return DerInteger.Three;
return DerInteger.One;
}
private bool CheckForVersion3(IList<SignerInformation> signerInfos)
{
foreach (SignerInformation signerInfo in signerInfos) {
if (SignerInfo.GetInstance(signerInfo.ToSignerInfo()).Version.IntValueExact == 3)
return true;
}
return false;
}
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 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);
}
}
}