You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			281 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			281 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | //------------------------------------------------------------ | ||
|  | // Copyright (c) Microsoft Corporation.  All rights reserved. | ||
|  | //------------------------------------------------------------ | ||
|  | namespace System.IdentityModel | ||
|  | { | ||
|  |     using System; | ||
|  |     using System.IdentityModel.Selectors; | ||
|  |     using System.IdentityModel.Tokens; | ||
|  |     using System.Security.Cryptography; | ||
|  |     using System.Xml; | ||
|  | 
 | ||
|  |     /// <summary> | ||
|  |     /// Wraps a reader pointing to a enveloped signed XML and provides | ||
|  |     /// a reader that can be used to read the content without having to | ||
|  |     /// process the signature. The Signature is automatically validated | ||
|  |     /// when the last element of the envelope is read. | ||
|  |     /// </summary> | ||
|  |     public sealed class EnvelopedSignatureReader : DelegatingXmlDictionaryReader | ||
|  |     { | ||
|  |         bool _automaticallyReadSignature; | ||
|  |         DictionaryManager _dictionaryManager; | ||
|  |         int _elementCount; | ||
|  |         bool _resolveIntrinsicSigningKeys; | ||
|  |         bool _requireSignature; | ||
|  |         SigningCredentials _signingCredentials; | ||
|  |         SecurityTokenResolver _signingTokenResolver; | ||
|  |         SignedXml _signedXml; | ||
|  |         SecurityTokenSerializer _tokenSerializer; | ||
|  |         WrappedReader _wrappedReader; | ||
|  |         bool _disposed; | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Initializes an instance of <see cref="EnvelopedSignatureReader"/> | ||
|  |         /// </summary> | ||
|  |         /// <param name="reader">Reader pointing to the enveloped signed XML.</param> | ||
|  |         /// <param name="securityTokenSerializer">Token Serializer to resolve the signing token.</param> | ||
|  |         public EnvelopedSignatureReader(XmlReader reader, SecurityTokenSerializer securityTokenSerializer) | ||
|  |             : this(reader, securityTokenSerializer, null) | ||
|  |         { | ||
|  |         } | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Initializes an instance of <see cref="EnvelopedSignatureReader"/> | ||
|  |         /// </summary> | ||
|  |         /// <param name="reader">Reader pointing to the enveloped signed XML.</param> | ||
|  |         /// <param name="securityTokenSerializer">Token Serializer to deserialize the KeyInfo of the Signature.</param> | ||
|  |         /// <param name="signingTokenResolver">Token Resolver to resolve the signing token.</param> | ||
|  |         /// <exception cref="ArgumentNullException">One of the input parameter is null.</exception> | ||
|  |         public EnvelopedSignatureReader(XmlReader reader, SecurityTokenSerializer securityTokenSerializer, SecurityTokenResolver signingTokenResolver) | ||
|  |             : this(reader, securityTokenSerializer, signingTokenResolver, true, true, true) | ||
|  |         { | ||
|  |         } | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Initializes an instance of <see cref="EnvelopedSignatureReader"/> | ||
|  |         /// </summary> | ||
|  |         /// <param name="reader">Reader pointing to the enveloped signed XML.</param> | ||
|  |         /// <param name="securityTokenSerializer">Token Serializer to deserialize the KeyInfo of the Signature.</param> | ||
|  |         /// <param name="signingTokenResolver">Token Resolver to resolve the signing token.</param> | ||
|  |         /// <param name="requireSignature">The value indicates whether the signature is optional.</param> | ||
|  |         /// <param name="automaticallyReadSignature">This value indicates if the Signature should be read  | ||
|  |         /// when the Signature element is encountered or allow the caller to read the Signature manually.</param> | ||
|  |         /// <param name="resolveIntrinsicSigningKeys">A value indicating if intrinsic signing keys should be resolved.</param> | ||
|  |         public EnvelopedSignatureReader(XmlReader reader, SecurityTokenSerializer securityTokenSerializer, SecurityTokenResolver signingTokenResolver, bool requireSignature, bool automaticallyReadSignature, bool resolveIntrinsicSigningKeys) | ||
|  |         { | ||
|  |             if (reader == null) | ||
|  |             { | ||
|  |                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); | ||
|  |             } | ||
|  |             if (securityTokenSerializer == null) | ||
|  |             { | ||
|  |                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("securityTokenSerializer"); | ||
|  |             } | ||
|  | 
 | ||
|  |             _automaticallyReadSignature = automaticallyReadSignature; | ||
|  |             _dictionaryManager = new DictionaryManager(); | ||
|  |             _tokenSerializer = securityTokenSerializer; | ||
|  |             _requireSignature = requireSignature; | ||
|  |             _signingTokenResolver = signingTokenResolver ?? EmptySecurityTokenResolver.Instance; | ||
|  |             _resolveIntrinsicSigningKeys = resolveIntrinsicSigningKeys; | ||
|  | 
 | ||
|  |             XmlDictionaryReader dictionaryReader = XmlDictionaryReader.CreateDictionaryReader(reader); | ||
|  |             _wrappedReader = new WrappedReader(dictionaryReader); | ||
|  | 
 | ||
|  |             base.InitializeInnerReader(_wrappedReader); | ||
|  |         } | ||
|  | 
 | ||
|  |         void OnEndOfRootElement() | ||
|  |         { | ||
|  |             if (null == _signedXml) | ||
|  |             { | ||
|  |                 if (_requireSignature) | ||
|  |                 { | ||
|  |                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( | ||
|  |                         new CryptographicException(SR.GetString(SR.ID3089))); | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 ResolveSigningCredentials(); | ||
|  |                 _signedXml.StartSignatureVerification(_signingCredentials.SigningKey); | ||
|  |                 _wrappedReader.XmlTokens.SetElementExclusion(XD.XmlSignatureDictionary.Signature.Value, XD.XmlSignatureDictionary.Namespace.Value); | ||
|  |                 WifSignedInfo signedInfo = _signedXml.Signature.SignedInfo as WifSignedInfo; | ||
|  |                 _signedXml.EnsureDigestValidity(signedInfo[0].ExtractReferredId(), _wrappedReader); | ||
|  |                 _signedXml.CompleteSignatureVerification();                 | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Returns the SigningCredentials used in the signature after the  | ||
|  |         /// envelope is consumed and when the signature is validated. | ||
|  |         /// </summary> | ||
|  |         public SigningCredentials SigningCredentials | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  |                 return _signingCredentials; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Gets a XmlBuffer of the envelope that was enveloped signed. | ||
|  |         /// The buffer is available after the XML has been read and | ||
|  |         /// signature validated. | ||
|  |         /// </summary> | ||
|  |         internal XmlTokenStream XmlTokens | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  |                 return _wrappedReader.XmlTokens.Trim(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Overrides the base Read method. Checks if the end of the envelope is reached and  | ||
|  |         /// validates the signature if requireSignature is enabled. If the reader gets | ||
|  |         /// positioned on a Signature element the whole signature is read in if automaticallyReadSignature | ||
|  |         /// is enabled. | ||
|  |         /// </summary> | ||
|  |         /// <returns>true if the next node was read successfully; false if there are no more nodes</returns> | ||
|  |         public override bool Read() | ||
|  |         { | ||
|  |             if ((base.NodeType == XmlNodeType.Element) && (!base.IsEmptyElement)) | ||
|  |             { | ||
|  |                 _elementCount++; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (base.NodeType == XmlNodeType.EndElement) | ||
|  |             { | ||
|  |                 _elementCount--; | ||
|  |                 if (_elementCount == 0) | ||
|  |                 { | ||
|  |                     OnEndOfRootElement(); | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             bool result = base.Read(); | ||
|  |             if (_automaticallyReadSignature | ||
|  |                 && (_signedXml == null) | ||
|  |                 && result | ||
|  |                 && base.InnerReader.IsLocalName(XD.XmlSignatureDictionary.Signature) | ||
|  |                 && base.InnerReader.IsNamespaceUri(XD.XmlSignatureDictionary.Namespace)) | ||
|  |             { | ||
|  |                 ReadSignature(); | ||
|  |             } | ||
|  | 
 | ||
|  |             return result; | ||
|  |         } | ||
|  | 
 | ||
|  |         void ReadSignature() | ||
|  |         { | ||
|  |             _signedXml = new SignedXml(new WifSignedInfo(_dictionaryManager), _dictionaryManager, _tokenSerializer); | ||
|  |             _signedXml.TransformFactory = ExtendedTransformFactory.Instance; | ||
|  | 
 | ||
|  |             _signedXml.ReadFrom(_wrappedReader); | ||
|  | 
 | ||
|  |             if (_signedXml.Signature.SignedInfo.ReferenceCount != 1) | ||
|  |             { | ||
|  |                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.ID3057))); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void ResolveSigningCredentials() | ||
|  |         { | ||
|  |             if (_signedXml.Signature == null || _signedXml.Signature.KeyIdentifier == null || _signedXml.Signature.KeyIdentifier.Count == 0) | ||
|  |             { | ||
|  |                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID3276))); | ||
|  |             } | ||
|  | 
 | ||
|  |             SecurityKey signingKey = null; | ||
|  |             if (!_signingTokenResolver.TryResolveSecurityKey(_signedXml.Signature.KeyIdentifier[0], out signingKey)) | ||
|  |             { | ||
|  |                 if (_resolveIntrinsicSigningKeys && _signedXml.Signature.KeyIdentifier.CanCreateKey) | ||
|  |                 { | ||
|  |                     signingKey = _signedXml.Signature.KeyIdentifier.CreateKey(); | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     // | ||
|  |                     // we cannot find the signing key to verify the signature | ||
|  |                     // | ||
|  |                     EncryptedKeyIdentifierClause encryptedKeyClause; | ||
|  |                     if (_signedXml.Signature.KeyIdentifier.TryFind<EncryptedKeyIdentifierClause>(out encryptedKeyClause)) | ||
|  |                     { | ||
|  |                         // | ||
|  |                         // System.IdentityModel.Tokens.EncryptedKeyIdentifierClause.ToString() does not print out  | ||
|  |                         // very good information except the cipher data in this case. We have worked around that | ||
|  |                         // by using the token serializer to serialize the key identifier clause again. | ||
|  |                         // | ||
|  |                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( | ||
|  |                                 new SignatureVerificationFailedException( | ||
|  |                                 SR.GetString(SR.ID4036, XmlUtil.SerializeSecurityKeyIdentifier(_signedXml.Signature.KeyIdentifier, _tokenSerializer)))); | ||
|  |                     } | ||
|  |                     else | ||
|  |                     { | ||
|  |                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( | ||
|  |                                 new SignatureVerificationFailedException(SR.GetString(SR.ID4037, _signedXml.Signature.KeyIdentifier.ToString()))); | ||
|  |                     } | ||
|  | 
 | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             WifSignedInfo signedInfo = _signedXml.Signature.SignedInfo as WifSignedInfo; | ||
|  |             _signingCredentials = new SigningCredentials(signingKey, _signedXml.Signature.SignedInfo.SignatureMethod, signedInfo[0].DigestMethod, _signedXml.Signature.KeyIdentifier); | ||
|  |         } | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Reads the signature if the reader is currently positioned at a Signature element. | ||
|  |         /// </summary> | ||
|  |         /// <returns>true if the signature was successfully read else false.</returns> | ||
|  |         /// <remarks>Does not move the reader when returning false.</remarks> | ||
|  |         public bool TryReadSignature() | ||
|  |         { | ||
|  |             if (IsStartElement(XD.XmlSignatureDictionary.Signature, XD.XmlSignatureDictionary.Namespace)) | ||
|  |             { | ||
|  |                 ReadSignature(); | ||
|  |                 return true; | ||
|  |             } | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         #region IDisposable Members | ||
|  | 
 | ||
|  |         /// <summary> | ||
|  |         /// Releases the unmanaged resources used by the System.IdentityModel.Protocols.XmlSignature.EnvelopedSignatureReader 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 (_wrappedReader != null) | ||
|  |                 { | ||
|  |                     _wrappedReader.Close(); | ||
|  |                     _wrappedReader = null; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             // Free native resources, if any. | ||
|  | 
 | ||
|  |             _disposed = true; | ||
|  |         } | ||
|  | 
 | ||
|  |         #endregion | ||
|  |     } | ||
|  | } |