Files
SuperVPN/output/Libraries/BouncyCastle.Crypto/Org/BouncyCastle/Cms/CmsSignedDataStreamGenerator.cs
2025-10-09 09:57:24 +09:00

523 lines
18 KiB
C#

using System;
using System.Collections;
using System.IO;
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.Crypto.Parameters;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Collections;
using Org.BouncyCastle.Utilities.IO;
using Org.BouncyCastle.X509;
namespace Org.BouncyCastle.Cms;
public class CmsSignedDataStreamGenerator : CmsSignedGenerator
{
private class DigestAndSignerInfoGeneratorHolder
{
internal readonly ISignerInfoGenerator signerInf;
internal readonly string digestOID;
internal AlgorithmIdentifier DigestAlgorithm => new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), DerNull.Instance);
internal DigestAndSignerInfoGeneratorHolder(ISignerInfoGenerator signerInf, string digestOID)
{
this.signerInf = signerInf;
this.digestOID = digestOID;
}
}
private class SignerInfoGeneratorImpl : ISignerInfoGenerator
{
private readonly CmsSignedDataStreamGenerator outer;
private readonly SignerIdentifier _signerIdentifier;
private readonly string _digestOID;
private readonly string _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, string digestOID, string encOID, CmsAttributeTableGenerator sAttr, CmsAttributeTableGenerator unsAttr)
{
this.outer = outer;
_signerIdentifier = signerIdentifier;
_digestOID = digestOID;
_encOID = encOID;
_sAttr = sAttr;
_unsAttr = unsAttr;
_encName = Helper.GetEncryptionAlgName(_encOID);
string digestAlgName = Helper.GetDigestAlgName(_digestOID);
string algorithm = digestAlgName + "with" + _encName;
if (_sAttr != null)
{
_sig = Helper.GetSignatureInstance(algorithm);
}
else if (_encName.Equals("RSA"))
{
_sig = Helper.GetSignatureInstance("RSA");
}
else
{
if (!_encName.Equals("DSA"))
{
throw new SignatureException("algorithm: " + _encName + " not supported in base signatures.");
}
_sig = Helper.GetSignatureInstance("NONEwithDSA");
}
_sig.Init(forSigning: true, new ParametersWithRandom(key, outer.rand));
}
public SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm, byte[] calculatedDigest)
{
try
{
string digestAlgName = Helper.GetDigestAlgName(_digestOID);
string algorithm = digestAlgName + "with" + _encName;
byte[] array = calculatedDigest;
Asn1Set asn1Set = null;
if (_sAttr != null)
{
IDictionary baseParameters = outer.GetBaseParameters(contentType, digestAlgorithm, calculatedDigest);
Org.BouncyCastle.Asn1.Cms.AttributeTable attributeTable = _sAttr.GetAttributes(baseParameters);
if (contentType == null && attributeTable != null && attributeTable[CmsAttributes.ContentType] != null)
{
IDictionary dictionary = attributeTable.ToDictionary();
dictionary.Remove(CmsAttributes.ContentType);
attributeTable = new Org.BouncyCastle.Asn1.Cms.AttributeTable(dictionary);
}
asn1Set = outer.GetAttributeSet(attributeTable);
array = asn1Set.GetEncoded("DER");
}
else if (_encName.Equals("RSA"))
{
DigestInfo digestInfo = new DigestInfo(digestAlgorithm, calculatedDigest);
array = digestInfo.GetEncoded("DER");
}
_sig.BlockUpdate(array, 0, array.Length);
byte[] array2 = _sig.GenerateSignature();
Asn1Set unauthenticatedAttributes = null;
if (_unsAttr != null)
{
IDictionary baseParameters2 = outer.GetBaseParameters(contentType, digestAlgorithm, calculatedDigest);
baseParameters2[CmsAttributeTableParameter.Signature] = array2.Clone();
Org.BouncyCastle.Asn1.Cms.AttributeTable attributes = _unsAttr.GetAttributes(baseParameters2);
unauthenticatedAttributes = outer.GetAttributeSet(attributes);
}
Asn1Encodable defaultX509Parameters = SignerUtilities.GetDefaultX509Parameters(algorithm);
AlgorithmIdentifier encAlgorithmIdentifier = Helper.GetEncAlgorithmIdentifier(new DerObjectIdentifier(_encOID), defaultX509Parameters);
return new SignerInfo(_signerIdentifier, digestAlgorithm, asn1Set, encAlgorithmIdentifier, new DerOctetString(array2), unauthenticatedAttributes);
}
catch (IOException e)
{
throw new CmsStreamException("encoding error.", e);
}
catch (SignatureException e2)
{
throw new CmsStreamException("error creating signature.", e2);
}
}
}
private class CmsSignedDataOutputStream : BaseOutputStream
{
private readonly CmsSignedDataStreamGenerator outer;
private Stream _out;
private DerObjectIdentifier _contentOID;
private BerSequenceGenerator _sGen;
private BerSequenceGenerator _sigGen;
private BerSequenceGenerator _eiGen;
public CmsSignedDataOutputStream(CmsSignedDataStreamGenerator outer, Stream outStream, string contentOID, BerSequenceGenerator sGen, BerSequenceGenerator sigGen, BerSequenceGenerator eiGen)
{
this.outer = outer;
_out = outStream;
_contentOID = new DerObjectIdentifier(contentOID);
_sGen = sGen;
_sigGen = sigGen;
_eiGen = eiGen;
}
public override void WriteByte(byte b)
{
_out.WriteByte(b);
}
public override void Write(byte[] bytes, int off, int len)
{
_out.Write(bytes, off, len);
}
public override void Close()
{
DoClose();
base.Close();
}
private void DoClose()
{
Platform.Dispose(_out);
_eiGen.Close();
outer._digests.Clear();
if (outer._certs.Count > 0)
{
Asn1Set obj = (outer.UseDerForCerts ? CmsUtilities.CreateDerSetFromList(outer._certs) : CmsUtilities.CreateBerSetFromList(outer._certs));
WriteToGenerator(_sigGen, new BerTaggedObject(explicitly: false, 0, obj));
}
if (outer._crls.Count > 0)
{
Asn1Set obj2 = (outer.UseDerForCrls ? CmsUtilities.CreateDerSetFromList(outer._crls) : CmsUtilities.CreateBerSetFromList(outer._crls));
WriteToGenerator(_sigGen, new BerTaggedObject(explicitly: false, 1, obj2));
}
foreach (object messageDigest in outer._messageDigests)
{
DictionaryEntry dictionaryEntry = (DictionaryEntry)messageDigest;
outer._messageHashes.Add(dictionaryEntry.Key, DigestUtilities.DoFinal((IDigest)dictionaryEntry.Value));
}
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector();
foreach (DigestAndSignerInfoGeneratorHolder signerInf in outer._signerInfs)
{
AlgorithmIdentifier digestAlgorithm = signerInf.DigestAlgorithm;
byte[] array = (byte[])outer._messageHashes[Helper.GetDigestAlgName(signerInf.digestOID)];
outer._digests[signerInf.digestOID] = array.Clone();
asn1EncodableVector.Add(signerInf.signerInf.Generate(_contentOID, digestAlgorithm, array));
}
foreach (SignerInformation signer in outer._signers)
{
asn1EncodableVector.Add(signer.ToSignerInfo());
}
WriteToGenerator(_sigGen, new DerSet(asn1EncodableVector));
_sigGen.Close();
_sGen.Close();
}
private static void WriteToGenerator(Asn1Generator ag, Asn1Encodable ae)
{
byte[] encoded = ae.GetEncoded();
ag.GetRawOutputStream().Write(encoded, 0, encoded.Length);
}
}
private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
private readonly IList _signerInfs = Platform.CreateArrayList();
private readonly ISet _messageDigestOids = new HashSet();
private readonly IDictionary _messageDigests = Platform.CreateHashtable();
private readonly IDictionary _messageHashes = Platform.CreateHashtable();
private bool _messageDigestsLocked;
private int _bufferSize;
public CmsSignedDataStreamGenerator()
{
}
public CmsSignedDataStreamGenerator(SecureRandom rand)
: base(rand)
{
}
public void SetBufferSize(int bufferSize)
{
_bufferSize = bufferSize;
}
public void AddDigests(params string[] digestOids)
{
AddDigests((IEnumerable)digestOids);
}
public void AddDigests(IEnumerable digestOids)
{
foreach (string digestOid in digestOids)
{
ConfigureDigest(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, Helper.GetEncOid(privateKey, digestOid), digestOid, signedAttrGenerator, unsignedAttrGenerator);
}
public void AddSigner(AsymmetricKeyParameter privateKey, X509Certificate cert, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
{
DoAddSigner(privateKey, CmsSignedGenerator.GetSignerIdentifier(cert), encryptionOid, 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, Helper.GetEncOid(privateKey, digestOid), digestOid, signedAttrGenerator, unsignedAttrGenerator);
}
public void AddSigner(AsymmetricKeyParameter privateKey, byte[] subjectKeyID, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
{
DoAddSigner(privateKey, CmsSignedGenerator.GetSignerIdentifier(subjectKeyID), encryptionOid, digestOid, signedAttrGenerator, unsignedAttrGenerator);
}
private void DoAddSigner(AsymmetricKeyParameter privateKey, SignerIdentifier signerIdentifier, string encryptionOid, string digestOid, CmsAttributeTableGenerator signedAttrGenerator, CmsAttributeTableGenerator unsignedAttrGenerator)
{
ConfigureDigest(digestOid);
SignerInfoGeneratorImpl signerInf = new SignerInfoGeneratorImpl(this, privateKey, signerIdentifier, digestOid, encryptionOid, signedAttrGenerator, unsignedAttrGenerator);
_signerInfs.Add(new DigestAndSignerInfoGeneratorHolder(signerInf, digestOid));
}
internal override void AddSignerCallback(SignerInformation si)
{
RegisterDigestOid(si.DigestAlgorithmID.Algorithm.Id);
}
public Stream Open(Stream outStream)
{
return Open(outStream, encapsulate: 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, isExplicit: true);
DerObjectIdentifier derObjectIdentifier = ((signedContentType == null) ? null : new DerObjectIdentifier(signedContentType));
berSequenceGenerator2.AddObject(CalculateVersion(derObjectIdentifier));
Asn1EncodableVector asn1EncodableVector = new Asn1EncodableVector();
foreach (string messageDigestOid in _messageDigestOids)
{
asn1EncodableVector.Add(new AlgorithmIdentifier(new DerObjectIdentifier(messageDigestOid), DerNull.Instance));
}
byte[] encoded = new DerSet(asn1EncodableVector).GetEncoded();
berSequenceGenerator2.GetRawOutputStream().Write(encoded, 0, encoded.Length);
BerSequenceGenerator berSequenceGenerator3 = new BerSequenceGenerator(berSequenceGenerator2.GetRawOutputStream());
berSequenceGenerator3.AddObject(derObjectIdentifier);
Stream s = (encapsulate ? CmsUtilities.CreateBerOctetOutputStream(berSequenceGenerator3.GetRawOutputStream(), 0, isExplicit: true, _bufferSize) : null);
Stream safeTeeOutputStream = GetSafeTeeOutputStream(dataOutputStream, s);
Stream outStream2 = AttachDigestsToOutputStream(_messageDigests.Values, safeTeeOutputStream);
return new CmsSignedDataOutputStream(this, outStream2, signedContentType, berSequenceGenerator, berSequenceGenerator2, berSequenceGenerator3);
}
private void RegisterDigestOid(string digestOid)
{
if (_messageDigestsLocked)
{
if (!_messageDigestOids.Contains(digestOid))
{
throw new InvalidOperationException("Cannot register new digest OIDs after the data stream is opened");
}
}
else
{
_messageDigestOids.Add(digestOid);
}
}
private void ConfigureDigest(string digestOid)
{
RegisterDigestOid(digestOid);
string digestAlgName = Helper.GetDigestAlgName(digestOid);
IDigest digest = (IDigest)_messageDigests[digestAlgName];
if (digest == null)
{
if (_messageDigestsLocked)
{
throw new InvalidOperationException("Cannot configure new digests after the data stream is opened");
}
digest = Helper.GetDigestInstance(digestAlgName);
_messageDigests[digestAlgName] = digest;
}
}
internal void Generate(Stream outStream, string eContentType, bool encapsulate, Stream dataOutputStream, CmsProcessable content)
{
Stream stream = Open(outStream, eContentType, encapsulate, dataOutputStream);
content?.Write(stream);
Platform.Dispose(stream);
}
private DerInteger CalculateVersion(DerObjectIdentifier contentOid)
{
bool flag = false;
bool flag2 = false;
bool flag3 = false;
bool flag4 = false;
if (_certs != null)
{
foreach (object cert in _certs)
{
if (cert is Asn1TaggedObject)
{
Asn1TaggedObject asn1TaggedObject = (Asn1TaggedObject)cert;
if (asn1TaggedObject.TagNo == 1)
{
flag3 = true;
}
else if (asn1TaggedObject.TagNo == 2)
{
flag4 = true;
}
else if (asn1TaggedObject.TagNo == 3)
{
flag = true;
break;
}
}
}
}
if (flag)
{
return new DerInteger(5);
}
if (_crls != null)
{
foreach (object crl in _crls)
{
if (crl is Asn1TaggedObject)
{
flag2 = true;
break;
}
}
}
if (flag2)
{
return new DerInteger(5);
}
if (flag4)
{
return new DerInteger(4);
}
if (flag3 || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(_signers))
{
return new DerInteger(3);
}
return new DerInteger(1);
}
private bool CheckForVersion3(IList signerInfos)
{
foreach (SignerInformation signerInfo in signerInfos)
{
SignerInfo instance = SignerInfo.GetInstance(signerInfo.ToSignerInfo());
if (instance.Version.Value.IntValue == 3)
{
return true;
}
}
return false;
}
private static Stream AttachDigestsToOutputStream(ICollection 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)
{
if (s == null)
{
return new NullOutputStream();
}
return s;
}
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);
}
}