You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,320 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
namespace System.IdentityModel
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IdentityModel.Selectors;
|
||||
using System.IdentityModel.Tokens;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Runtime;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps a writer and generates a signature automatically when the envelope
|
||||
/// is written completely. By default the generated signature is inserted as
|
||||
/// the last element in the envelope. This can be modified by explicitily
|
||||
/// calling WriteSignature to indicate the location inside the envelope where
|
||||
/// the signature should be inserted.
|
||||
/// </summary>
|
||||
public sealed class EnvelopedSignatureWriter : DelegatingXmlDictionaryWriter
|
||||
{
|
||||
DictionaryManager _dictionaryManager;
|
||||
XmlWriter _innerWriter;
|
||||
SigningCredentials _signingCreds;
|
||||
string _referenceId;
|
||||
SecurityTokenSerializer _tokenSerializer;
|
||||
HashStream _hashStream;
|
||||
HashAlgorithm _hashAlgorithm;
|
||||
int _elementCount;
|
||||
MemoryStream _signatureFragment;
|
||||
MemoryStream _endFragment;
|
||||
bool _hasSignatureBeenMarkedForInsert;
|
||||
MemoryStream _writerStream;
|
||||
MemoryStream _preCanonicalTracingStream;
|
||||
bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="EnvelopedSignatureWriter"/>. The returned writer can be directly used
|
||||
/// to write the envelope. The signature will be automatically generated when
|
||||
/// the envelope is completed.
|
||||
/// </summary>
|
||||
/// <param name="innerWriter">Writer to wrap/</param>
|
||||
/// <param name="signingCredentials">SigningCredentials to be used to generate the signature.</param>
|
||||
/// <param name="referenceId">The reference Id of the envelope.</param>
|
||||
/// <param name="securityTokenSerializer">SecurityTokenSerializer to serialize the signature KeyInfo.</param>
|
||||
/// <exception cref="ArgumentNullException">One of he input parameter is null.</exception>
|
||||
/// <exception cref="ArgumentException">The string 'referenceId' is either null or empty.</exception>
|
||||
public EnvelopedSignatureWriter(XmlWriter innerWriter, SigningCredentials signingCredentials, string referenceId, SecurityTokenSerializer securityTokenSerializer)
|
||||
{
|
||||
if (innerWriter == null)
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("innerWriter");
|
||||
}
|
||||
|
||||
if (signingCredentials == null)
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("signingCredentials");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(referenceId))
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.ID0006), "referenceId"));
|
||||
}
|
||||
|
||||
if (securityTokenSerializer == null)
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenSerializer");
|
||||
}
|
||||
|
||||
// Remember the user's writer here. We need to finally write out the signed XML
|
||||
// into this writer.
|
||||
_dictionaryManager = new DictionaryManager();
|
||||
_innerWriter = innerWriter;
|
||||
_signingCreds = signingCredentials;
|
||||
_referenceId = referenceId;
|
||||
_tokenSerializer = securityTokenSerializer;
|
||||
|
||||
_signatureFragment = new MemoryStream();
|
||||
_endFragment = new MemoryStream();
|
||||
_writerStream = new MemoryStream();
|
||||
|
||||
XmlDictionaryWriter effectiveWriter = XmlDictionaryWriter.CreateTextWriter(_writerStream, Encoding.UTF8, false);
|
||||
|
||||
// Initialize the base writer to the newly created writer. The user should write the XML
|
||||
// to this.
|
||||
base.InitializeInnerWriter(effectiveWriter);
|
||||
_hashAlgorithm = CryptoHelper.CreateHashAlgorithm(_signingCreds.DigestAlgorithm);
|
||||
_hashStream = new HashStream(_hashAlgorithm);
|
||||
base.InnerWriter.StartCanonicalization(_hashStream, false, null);
|
||||
|
||||
//
|
||||
// Add tracing for the un-canonicalized bytes
|
||||
//
|
||||
if (DiagnosticUtility.ShouldTraceVerbose)
|
||||
{
|
||||
_preCanonicalTracingStream = new MemoryStream();
|
||||
base.InitializeTracingWriter(new XmlTextWriter(_preCanonicalTracingStream, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
|
||||
private void ComputeSignature()
|
||||
{
|
||||
PreDigestedSignedInfo signedInfo = new PreDigestedSignedInfo(_dictionaryManager);
|
||||
signedInfo.AddEnvelopedSignatureTransform = true;
|
||||
signedInfo.CanonicalizationMethod = XD.ExclusiveC14NDictionary.Namespace.Value;
|
||||
signedInfo.SignatureMethod = _signingCreds.SignatureAlgorithm;
|
||||
signedInfo.DigestMethod = _signingCreds.DigestAlgorithm;
|
||||
signedInfo.AddReference(_referenceId, _hashStream.FlushHashAndGetValue(_preCanonicalTracingStream));
|
||||
|
||||
SignedXml signedXml = new SignedXml(signedInfo, _dictionaryManager, _tokenSerializer);
|
||||
signedXml.ComputeSignature(_signingCreds.SigningKey);
|
||||
signedXml.Signature.KeyIdentifier = _signingCreds.SigningKeyIdentifier;
|
||||
signedXml.WriteTo(base.InnerWriter);
|
||||
((IDisposable)_hashStream).Dispose();
|
||||
_hashStream = null;
|
||||
}
|
||||
|
||||
private void OnEndRootElement()
|
||||
{
|
||||
if (!_hasSignatureBeenMarkedForInsert)
|
||||
{
|
||||
// Default case. Signature is added as the last child element.
|
||||
// We still have to compute the signature. Write end element as a different fragment.
|
||||
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).StartFragment(_endFragment, false);
|
||||
base.WriteEndElement();
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).EndFragment();
|
||||
}
|
||||
else if (_hasSignatureBeenMarkedForInsert)
|
||||
{
|
||||
// Signature should be added to the middle between the start and element
|
||||
// elements. Finish the end fragment and compute the signature and
|
||||
// write the signature as a seperate fragment.
|
||||
base.WriteEndElement();
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).EndFragment();
|
||||
}
|
||||
|
||||
// Stop Canonicalization.
|
||||
base.EndCanonicalization();
|
||||
|
||||
// Compute signature and write it into a seperate fragment.
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).StartFragment(_signatureFragment, false);
|
||||
ComputeSignature();
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).EndFragment();
|
||||
|
||||
// Put all fragments together. The fragment before the signature is already written into the writer.
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).WriteFragment(_signatureFragment.GetBuffer(), 0, (int)_signatureFragment.Length);
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).WriteFragment(_endFragment.GetBuffer(), 0, (int)_endFragment.Length);
|
||||
|
||||
// _startFragment.Close();
|
||||
_signatureFragment.Close();
|
||||
_endFragment.Close();
|
||||
|
||||
_writerStream.Position = 0;
|
||||
_hasSignatureBeenMarkedForInsert = false;
|
||||
|
||||
// Write the signed stream to the writer provided by the user.
|
||||
// We are creating a Text Reader over a stream that we just wrote out. Hence, it is safe to
|
||||
// create a XmlTextReader and not a XmlDictionaryReader.
|
||||
// Note: reader will close _writerStream on Dispose.
|
||||
XmlReader reader = XmlDictionaryReader.CreateTextReader(_writerStream, XmlDictionaryReaderQuotas.Max);
|
||||
reader.MoveToContent();
|
||||
_innerWriter.WriteNode(reader, false);
|
||||
_innerWriter.Flush();
|
||||
reader.Close();
|
||||
base.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the position of the signature within the envelope. Call this
|
||||
/// method while writing the envelope to indicate at which point the
|
||||
/// signature should be inserted.
|
||||
/// </summary>
|
||||
public void WriteSignature()
|
||||
{
|
||||
base.Flush();
|
||||
if (_writerStream == null || _writerStream.Length == 0)
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID6029)));
|
||||
}
|
||||
|
||||
if (_signatureFragment.Length != 0)
|
||||
{
|
||||
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID6030)));
|
||||
}
|
||||
|
||||
Fx.Assert(_endFragment != null && _endFragment.Length == 0, SR.GetString(SR.ID8026));
|
||||
|
||||
// Capture the remaing as a seperate fragment.
|
||||
((IFragmentCapableXmlDictionaryWriter)base.InnerWriter).StartFragment(_endFragment, false);
|
||||
|
||||
_hasSignatureBeenMarkedForInsert = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the base class implementation. When the last element of the envelope is written
|
||||
/// the signature is automatically computed over the envelope and the signature is inserted at
|
||||
/// the appropriate position, if WriteSignature was explicitly called or is inserted at the
|
||||
/// end of the envelope.
|
||||
/// </summary>
|
||||
public override void WriteEndElement()
|
||||
{
|
||||
_elementCount--;
|
||||
if (_elementCount == 0)
|
||||
{
|
||||
base.Flush();
|
||||
OnEndRootElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the base class implementation. When the last element of the envelope is written
|
||||
/// the signature is automatically computed over the envelope and the signature is inserted at
|
||||
/// the appropriate position, if WriteSignature was explicitly called or is inserted at the
|
||||
/// end of the envelope.
|
||||
/// </summary>
|
||||
public override void WriteFullEndElement()
|
||||
{
|
||||
_elementCount--;
|
||||
if (_elementCount == 0)
|
||||
{
|
||||
base.Flush();
|
||||
OnEndRootElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteFullEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the base class. Writes the specified start tag and associates
|
||||
/// it with the given namespace.
|
||||
/// </summary>
|
||||
/// <param name="prefix">The namespace prefix of the element.</param>
|
||||
/// <param name="localName">The local name of the element.</param>
|
||||
/// <param name="ns">The namespace URI to associate with the element.</param>
|
||||
public override void WriteStartElement(string prefix, string localName, string ns)
|
||||
{
|
||||
_elementCount++;
|
||||
base.WriteStartElement(prefix, localName, ns);
|
||||
}
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
/// <summary>
|
||||
/// Releases the unmanaged resources used by the System.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureWriter and optionally
|
||||
/// releases the managed resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">
|
||||
/// True to release both managed and unmanaged resources; false to release only unmanaged resources.
|
||||
/// </param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
//
|
||||
// Free all of our managed resources
|
||||
//
|
||||
if (_hashStream != null)
|
||||
{
|
||||
_hashStream.Dispose();
|
||||
_hashStream = null;
|
||||
}
|
||||
|
||||
if (_hashAlgorithm != null)
|
||||
{
|
||||
((IDisposable)_hashAlgorithm).Dispose();
|
||||
_hashAlgorithm = null;
|
||||
}
|
||||
|
||||
if (_signatureFragment != null)
|
||||
{
|
||||
_signatureFragment.Dispose();
|
||||
_signatureFragment = null;
|
||||
}
|
||||
|
||||
if (_endFragment != null)
|
||||
{
|
||||
_endFragment.Dispose();
|
||||
_endFragment = null;
|
||||
}
|
||||
|
||||
if (_writerStream != null)
|
||||
{
|
||||
_writerStream.Dispose();
|
||||
_writerStream = null;
|
||||
}
|
||||
|
||||
if (_preCanonicalTracingStream != null)
|
||||
{
|
||||
_preCanonicalTracingStream.Dispose();
|
||||
_preCanonicalTracingStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Free native resources, if any.
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user