1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.IdentityModel
6 {
7     using System.Collections.Generic;
8     using System.Diagnostics;
9     using System.IO;
10     using System.IdentityModel.Tokens;
11     using System.IdentityModel.Selectors;
12     using System.Security.Cryptography;
13     using System.Text;
14     using System.Xml;
15 
16     sealed class SignedXml : ISignatureValueSecurityElement
17     {
18         internal const string DefaultPrefix = XmlSignatureStrings.Prefix;
19 
20         SecurityTokenSerializer tokenSerializer;
21         readonly Signature signature;
22         TransformFactory transformFactory;
23         DictionaryManager dictionaryManager;
24 
SignedXml(DictionaryManager dictionaryManager, SecurityTokenSerializer tokenSerializer)25         public SignedXml(DictionaryManager dictionaryManager, SecurityTokenSerializer tokenSerializer)
26             : this(new StandardSignedInfo(dictionaryManager), dictionaryManager, tokenSerializer)
27         {
28         }
29 
SignedXml(SignedInfo signedInfo, DictionaryManager dictionaryManager, SecurityTokenSerializer tokenSerializer)30         internal SignedXml(SignedInfo signedInfo, DictionaryManager dictionaryManager, SecurityTokenSerializer tokenSerializer)
31         {
32             if (signedInfo == null)
33             {
34                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("signedInfo"));
35             }
36             if (dictionaryManager == null)
37             {
38                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryManager");
39             }
40             if (tokenSerializer == null)
41             {
42                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("tokenSerializer");
43             }
44             this.transformFactory = StandardTransformFactory.Instance;
45             this.tokenSerializer = tokenSerializer;
46             this.signature = new Signature(this, signedInfo);
47             this.dictionaryManager = dictionaryManager;
48         }
49 
50         public bool HasId
51         {
52             get { return true; }
53         }
54 
55         public string Id
56         {
57             get { return this.signature.Id; }
58             set { this.signature.Id = value; }
59         }
60 
61         public SecurityTokenSerializer SecurityTokenSerializer
62         {
63             get { return this.tokenSerializer; }
64         }
65 
66         public Signature Signature
67         {
68             get { return this.signature; }
69         }
70 
71         public TransformFactory TransformFactory
72         {
73             get { return this.transformFactory; }
74             set { this.transformFactory = value; }
75         }
76 
ComputeSignature(HashAlgorithm hash, AsymmetricSignatureFormatter formatter, string signatureMethod)77         void ComputeSignature(HashAlgorithm hash, AsymmetricSignatureFormatter formatter, string signatureMethod)
78         {
79             this.Signature.SignedInfo.ComputeReferenceDigests();
80             this.Signature.SignedInfo.ComputeHash(hash);
81             byte[] signature;
82             if (SecurityUtils.RequiresFipsCompliance && signatureMethod == SecurityAlgorithms.RsaSha256Signature)
83             {
84                 // This is to avoid the RSAPKCS1SignatureFormatter.CreateSignature from using SHA256Managed (non-FIPS-Compliant).
85                 // Hence we precompute the hash using SHA256CSP (FIPS compliant) and pass it to method.
86                 // NOTE: RSAPKCS1SignatureFormatter does not understand SHA256CSP inherently and hence this workaround.
87                 formatter.SetHashAlgorithm("SHA256");
88                 signature = formatter.CreateSignature(hash.Hash);
89             }
90             else
91             {
92                 signature = formatter.CreateSignature(hash);
93             }
94             this.Signature.SetSignatureValue(signature);
95         }
96 
ComputeSignature(KeyedHashAlgorithm hash)97         void ComputeSignature(KeyedHashAlgorithm hash)
98         {
99             this.Signature.SignedInfo.ComputeReferenceDigests();
100             this.Signature.SignedInfo.ComputeHash(hash);
101             byte[] signature = hash.Hash;
102             this.Signature.SetSignatureValue(signature);
103         }
104 
ComputeSignature(SecurityKey signingKey)105         public void ComputeSignature(SecurityKey signingKey)
106         {
107             string signatureMethod = this.Signature.SignedInfo.SignatureMethod;
108             SymmetricSecurityKey symmetricKey = signingKey as SymmetricSecurityKey;
109             if (symmetricKey != null)
110             {
111                 using (KeyedHashAlgorithm algorithm = symmetricKey.GetKeyedHashAlgorithm(signatureMethod))
112                 {
113                     if (algorithm == null)
114                     {
115                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
116                             SR.GetString(SR.UnableToCreateKeyedHashAlgorithm, symmetricKey, signatureMethod)));
117                     }
118                     ComputeSignature(algorithm);
119                 }
120             }
121             else
122             {
123                 AsymmetricSecurityKey asymmetricKey = signingKey as AsymmetricSecurityKey;
124                 if (asymmetricKey == null)
125                 {
126                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
127                         SR.GetString(SR.UnknownICryptoType, signingKey)));
128                 }
129                 using (HashAlgorithm hash = asymmetricKey.GetHashAlgorithmForSignature(signatureMethod))
130                 {
131                     if (hash == null)
132                     {
133                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
134                             SR.GetString(SR.UnableToCreateHashAlgorithmFromAsymmetricCrypto, signatureMethod, asymmetricKey)));
135                     }
136 
137                     AsymmetricSignatureFormatter formatter = asymmetricKey.GetSignatureFormatter(signatureMethod);
138                     if (formatter == null)
139                     {
140                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
141                             SR.GetString(SR.UnableToCreateSignatureFormatterFromAsymmetricCrypto, signatureMethod, asymmetricKey)));
142                     }
143                     ComputeSignature(hash, formatter, signatureMethod);
144                 }
145             }
146         }
147 
CompleteSignatureVerification()148         public void CompleteSignatureVerification()
149         {
150             this.Signature.SignedInfo.EnsureAllReferencesVerified();
151         }
152 
EnsureDigestValidity(string id, object resolvedXmlSource)153         public void EnsureDigestValidity(string id, object resolvedXmlSource)
154         {
155             this.Signature.SignedInfo.EnsureDigestValidity(id, resolvedXmlSource);
156         }
157 
EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)158         public bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)
159         {
160             return this.Signature.SignedInfo.EnsureDigestValidityIfIdMatches(id, resolvedXmlSource);
161         }
162 
GetSignatureValue()163         public byte[] GetSignatureValue()
164         {
165             return this.Signature.GetSignatureBytes();
166         }
167 
ReadFrom(XmlReader reader)168         public void ReadFrom(XmlReader reader)
169         {
170             ReadFrom(XmlDictionaryReader.CreateDictionaryReader(reader));
171         }
172 
ReadFrom(XmlDictionaryReader reader)173         public void ReadFrom(XmlDictionaryReader reader)
174         {
175             this.signature.ReadFrom(reader, this.dictionaryManager);
176         }
177 
VerifySignature(KeyedHashAlgorithm hash)178         void VerifySignature(KeyedHashAlgorithm hash)
179         {
180             this.Signature.SignedInfo.ComputeHash(hash);
181             if (!CryptoHelper.IsEqual(hash.Hash, GetSignatureValue()))
182             {
183                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.SignatureVerificationFailed)));
184             }
185         }
186 
VerifySignature(HashAlgorithm hash, AsymmetricSignatureDeformatter deformatter, string signatureMethod)187         void VerifySignature(HashAlgorithm hash, AsymmetricSignatureDeformatter deformatter, string signatureMethod)
188         {
189             this.Signature.SignedInfo.ComputeHash(hash);
190             bool result;
191 
192             if (SecurityUtils.RequiresFipsCompliance && signatureMethod == SecurityAlgorithms.RsaSha256Signature)
193             {
194                 // This is to avoid the RSAPKCS1SignatureFormatter.VerifySignature from using SHA256Managed (non-FIPS-Compliant).
195                 // Hence we precompute the hash using SHA256CSP (FIPS compliant) and pass it to method.
196                 // NOTE: RSAPKCS1SignatureFormatter does not understand SHA256CSP inherently and hence this workaround.
197                 deformatter.SetHashAlgorithm("SHA256");
198                 result = deformatter.VerifySignature(hash.Hash, GetSignatureValue());
199             }
200             else
201             {
202                 result = deformatter.VerifySignature(hash, GetSignatureValue());
203             }
204 
205             if (!result)
206             {
207                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.SignatureVerificationFailed)));
208             }
209         }
210 
StartSignatureVerification(SecurityKey verificationKey)211         public void StartSignatureVerification(SecurityKey verificationKey)
212         {
213             string signatureMethod = this.Signature.SignedInfo.SignatureMethod;
214             SymmetricSecurityKey symmetricKey = verificationKey as SymmetricSecurityKey;
215             if (symmetricKey != null)
216             {
217                 using (KeyedHashAlgorithm hash = symmetricKey.GetKeyedHashAlgorithm(signatureMethod))
218                 {
219                     if (hash == null)
220                     {
221                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
222                             SR.GetString(SR.UnableToCreateKeyedHashAlgorithmFromSymmetricCrypto, signatureMethod, symmetricKey)));
223                     }
224                     VerifySignature(hash);
225                 }
226             }
227             else
228             {
229                 AsymmetricSecurityKey asymmetricKey = verificationKey as AsymmetricSecurityKey;
230                 if (asymmetricKey == null)
231                 {
232                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.UnknownICryptoType, verificationKey)));
233                 }
234                 using (HashAlgorithm hash = asymmetricKey.GetHashAlgorithmForSignature(signatureMethod))
235                 {
236                     if (hash == null)
237                     {
238                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
239                             SR.GetString(SR.UnableToCreateHashAlgorithmFromAsymmetricCrypto, signatureMethod, asymmetricKey)));
240                     }
241                     AsymmetricSignatureDeformatter deformatter = asymmetricKey.GetSignatureDeformatter(signatureMethod);
242                     if (deformatter == null)
243                     {
244                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
245                             SR.GetString(SR.UnableToCreateSignatureDeformatterFromAsymmetricCrypto, signatureMethod, asymmetricKey)));
246                     }
247 
248                     VerifySignature(hash, deformatter, signatureMethod);
249                 }
250             }
251         }
252 
WriteTo(XmlDictionaryWriter writer)253         public void WriteTo(XmlDictionaryWriter writer)
254         {
255             this.WriteTo(writer, this.dictionaryManager);
256         }
257 
WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)258         public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
259         {
260             this.signature.WriteTo(writer, dictionaryManager);
261         }
262     }
263 
264     sealed class Signature
265     {
266         SignedXml signedXml;
267         string id;
268         SecurityKeyIdentifier keyIdentifier;
269         string prefix = SignedXml.DefaultPrefix;
270         readonly SignatureValueElement signatureValueElement = new SignatureValueElement();
271         readonly SignedInfo signedInfo;
272 
Signature(SignedXml signedXml, SignedInfo signedInfo)273         public Signature(SignedXml signedXml, SignedInfo signedInfo)
274         {
275             this.signedXml = signedXml;
276             this.signedInfo = signedInfo;
277         }
278 
279         public string Id
280         {
281             get { return this.id; }
282             set { this.id = value; }
283         }
284 
285         public SecurityKeyIdentifier KeyIdentifier
286         {
287             get { return this.keyIdentifier; }
288             set { this.keyIdentifier = value; }
289         }
290 
291         public SignedInfo SignedInfo
292         {
293             get { return this.signedInfo; }
294         }
295 
296         public ISignatureValueSecurityElement SignatureValue
297         {
298             get { return this.signatureValueElement; }
299         }
300 
GetSignatureBytes()301         public byte[] GetSignatureBytes()
302         {
303             return this.signatureValueElement.Value;
304         }
305 
ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)306         public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
307         {
308             reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.Signature, dictionaryManager.XmlSignatureDictionary.Namespace);
309             this.prefix = reader.Prefix;
310             this.Id = reader.GetAttribute(dictionaryManager.UtilityDictionary.IdAttribute, null);
311             reader.Read();
312 
313             this.signedInfo.ReadFrom(reader, signedXml.TransformFactory, dictionaryManager);
314             this.signatureValueElement.ReadFrom(reader, dictionaryManager);
315             if (signedXml.SecurityTokenSerializer.CanReadKeyIdentifier(reader))
316             {
317                 this.keyIdentifier = signedXml.SecurityTokenSerializer.ReadKeyIdentifier(reader);
318             }
319             reader.ReadEndElement(); // Signature
320         }
321 
SetSignatureValue(byte[] signatureValue)322         public void SetSignatureValue(byte[] signatureValue)
323         {
324             this.signatureValueElement.Value = signatureValue;
325         }
326 
WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)327         public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
328         {
329             writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.Signature, dictionaryManager.XmlSignatureDictionary.Namespace);
330             if (this.id != null)
331             {
332                 writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.id);
333             }
334             this.signedInfo.WriteTo(writer, dictionaryManager);
335             this.signatureValueElement.WriteTo(writer, dictionaryManager);
336             if (this.keyIdentifier != null)
337             {
338                 this.signedXml.SecurityTokenSerializer.WriteKeyIdentifier(writer, this.keyIdentifier);
339             }
340 
341             writer.WriteEndElement(); // Signature
342         }
343 
344         sealed class SignatureValueElement : ISignatureValueSecurityElement
345         {
346             string id;
347             string prefix = SignedXml.DefaultPrefix;
348             byte[] signatureValue;
349             string signatureText;
350 
351             public bool HasId
352             {
353                 get { return true; }
354             }
355 
356             public string Id
357             {
358                 get { return this.id; }
359                 set { this.id = value; }
360             }
361 
362             internal byte[] Value
363             {
364                 get { return this.signatureValue; }
365                 set
366                 {
367                     this.signatureValue = value;
368                     this.signatureText = null;
369                 }
370             }
371 
ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)372             public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
373             {
374                 reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.SignatureValue, dictionaryManager.XmlSignatureDictionary.Namespace);
375                 this.prefix = reader.Prefix;
376                 this.Id = reader.GetAttribute(UtilityStrings.IdAttribute, null);
377                 reader.Read();
378 
379                 this.signatureText = reader.ReadString();
380                 this.signatureValue = System.Convert.FromBase64String(signatureText.Trim());
381 
382                 reader.ReadEndElement(); // SignatureValue
383             }
384 
WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)385             public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
386             {
387                 writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.SignatureValue, dictionaryManager.XmlSignatureDictionary.Namespace);
388                 if (this.id != null)
389                 {
390                     writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.id);
391                 }
392                 if (this.signatureText != null)
393                 {
394                     writer.WriteString(this.signatureText);
395                 }
396                 else
397                 {
398                     writer.WriteBase64(this.signatureValue, 0, this.signatureValue.Length);
399                 }
400                 writer.WriteEndElement(); // SignatureValue
401             }
402 
ISignatureValueSecurityElement.GetSignatureValue()403             byte[] ISignatureValueSecurityElement.GetSignatureValue()
404             {
405                 return this.Value;
406             }
407         }
408     }
409 
410     internal interface ISignatureReaderProvider
411     {
GetReader(object callbackContext)412         XmlDictionaryReader GetReader(object callbackContext);
413     }
414 
415     abstract class SignedInfo : ISecurityElement
416     {
417         readonly ExclusiveCanonicalizationTransform canonicalizationMethodElement = new ExclusiveCanonicalizationTransform(true);
418         string id;
419         ElementWithAlgorithmAttribute signatureMethodElement;
420         SignatureResourcePool resourcePool;
421         DictionaryManager dictionaryManager;
422         MemoryStream canonicalStream;
423         ISignatureReaderProvider readerProvider;
424         object signatureReaderProviderCallbackContext;
425         bool sendSide = true;
426 
SignedInfo(DictionaryManager dictionaryManager)427         protected SignedInfo(DictionaryManager dictionaryManager)
428         {
429             if (dictionaryManager == null)
430                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryManager");
431 
432             this.signatureMethodElement = new ElementWithAlgorithmAttribute(dictionaryManager.XmlSignatureDictionary.SignatureMethod);
433             this.dictionaryManager = dictionaryManager;
434         }
435 
436         protected DictionaryManager DictionaryManager
437         {
438             get { return this.dictionaryManager; }
439         }
440 
441         protected MemoryStream CanonicalStream
442         {
443             get { return this.canonicalStream; }
444             set { this.canonicalStream = value; }
445         }
446 
447         protected bool SendSide
448         {
449             get { return this.sendSide; }
450             set { this.sendSide = value; }
451         }
452 
453         public ISignatureReaderProvider ReaderProvider
454         {
455             get { return this.readerProvider; }
456             set { this.readerProvider = value; }
457         }
458 
459         public object SignatureReaderProviderCallbackContext
460         {
461             get { return this.signatureReaderProviderCallbackContext; }
462             set { this.signatureReaderProviderCallbackContext = value; }
463         }
464 
465         public string CanonicalizationMethod
466         {
467             get { return this.canonicalizationMethodElement.Algorithm; }
468             set
469             {
470                 if (value != this.canonicalizationMethodElement.Algorithm)
471                 {
472                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedTransformAlgorithm)));
473                 }
474             }
475         }
476 
477         public XmlDictionaryString CanonicalizationMethodDictionaryString
478         {
479             set
480             {
481                 if (value != null && value.Value != this.canonicalizationMethodElement.Algorithm)
482                 {
483                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedTransformAlgorithm)));
484                 }
485             }
486         }
487 
488         public bool HasId
489         {
490             get { return true; }
491         }
492 
493         public string Id
494         {
495             get { return this.id; }
496             set { this.id = value; }
497         }
498 
499         public abstract int ReferenceCount
500         {
501             get;
502         }
503 
504         public string SignatureMethod
505         {
506             get { return this.signatureMethodElement.Algorithm; }
507             set { this.signatureMethodElement.Algorithm = value; }
508         }
509 
510         public XmlDictionaryString SignatureMethodDictionaryString
511         {
512             get { return this.signatureMethodElement.AlgorithmDictionaryString; }
513             set { this.signatureMethodElement.AlgorithmDictionaryString = value; }
514         }
515 
516         public SignatureResourcePool ResourcePool
517         {
518             get
519             {
520                 if (this.resourcePool == null)
521                 {
522                     this.resourcePool = new SignatureResourcePool();
523                 }
524                 return this.resourcePool;
525             }
526             set
527             {
528                 this.resourcePool = value;
529             }
530         }
531 
ComputeHash(HashAlgorithm algorithm)532         public void ComputeHash(HashAlgorithm algorithm)
533         {
534             if ((this.CanonicalizationMethod != SecurityAlgorithms.ExclusiveC14n) && (this.CanonicalizationMethod != SecurityAlgorithms.ExclusiveC14nWithComments))
535             {
536                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.UnsupportedTransformAlgorithm)));
537             }
538             HashStream hashStream = this.ResourcePool.TakeHashStream(algorithm);
539             ComputeHash(hashStream);
540             hashStream.FlushHash();
541         }
542 
ComputeHash(HashStream hashStream)543         protected virtual void ComputeHash(HashStream hashStream)
544         {
545             if (this.sendSide)
546             {
547                 XmlDictionaryWriter utf8Writer = this.ResourcePool.TakeUtf8Writer();
548                 utf8Writer.StartCanonicalization(hashStream, false, null);
549                 WriteTo(utf8Writer, this.dictionaryManager);
550                 utf8Writer.EndCanonicalization();
551             }
552             else if (this.canonicalStream != null)
553             {
554                 this.canonicalStream.WriteTo(hashStream);
555             }
556             else
557             {
558                 if (this.readerProvider == null)
559                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.InclusiveNamespacePrefixRequiresSignatureReader)));
560 
561                 XmlDictionaryReader signatureReader = this.readerProvider.GetReader(this.signatureReaderProviderCallbackContext);
562 
563                 DiagnosticUtility.DebugAssert(signatureReader != null, "Require a Signature reader to validate signature.");
564 
565                 if (!signatureReader.CanCanonicalize)
566                 {
567                     MemoryStream stream = new MemoryStream();
568                     XmlDictionaryWriter bufferingWriter = XmlDictionaryWriter.CreateBinaryWriter(stream, this.DictionaryManager.ParentDictionary);
569                     string[] inclusivePrefix = GetInclusivePrefixes();
570                     if (inclusivePrefix != null)
571                     {
572                         bufferingWriter.WriteStartElement("a");
573                         for (int i = 0; i < inclusivePrefix.Length; ++i)
574                         {
575                             string ns = GetNamespaceForInclusivePrefix(inclusivePrefix[i]);
576                             if (ns != null)
577                             {
578                                 bufferingWriter.WriteXmlnsAttribute(inclusivePrefix[i], ns);
579                             }
580                         }
581                     }
582                     signatureReader.MoveToContent();
583                     bufferingWriter.WriteNode(signatureReader, false);
584                     if (inclusivePrefix != null)
585                         bufferingWriter.WriteEndElement();
586                     bufferingWriter.Flush();
587                     byte[] buffer = stream.ToArray();
588                     int bufferLength = (int)stream.Length;
589                     bufferingWriter.Close();
590 
591                     signatureReader.Close();
592 
593                     // Create a reader around the buffering Stream.
594                     signatureReader = XmlDictionaryReader.CreateBinaryReader(buffer, 0, bufferLength, this.DictionaryManager.ParentDictionary, XmlDictionaryReaderQuotas.Max);
595                     if (inclusivePrefix != null)
596                         signatureReader.ReadStartElement("a");
597                 }
598                 signatureReader.ReadStartElement(dictionaryManager.XmlSignatureDictionary.Signature, dictionaryManager.XmlSignatureDictionary.Namespace);
599                 signatureReader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.SignedInfo, dictionaryManager.XmlSignatureDictionary.Namespace);
600                 signatureReader.StartCanonicalization(hashStream, false, GetInclusivePrefixes());
601                 signatureReader.Skip();
602                 signatureReader.EndCanonicalization();
603                 signatureReader.Close();
604             }
605         }
606 
ComputeReferenceDigests()607         public abstract void ComputeReferenceDigests();
608 
GetInclusivePrefixes()609         protected string[] GetInclusivePrefixes()
610         {
611             return this.canonicalizationMethodElement.GetInclusivePrefixes();
612         }
613 
GetNamespaceForInclusivePrefix(string prefix)614         protected virtual string GetNamespaceForInclusivePrefix(string prefix)
615         {
616             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
617         }
618 
EnsureAllReferencesVerified()619         public abstract void EnsureAllReferencesVerified();
620 
EnsureDigestValidity(string id, object resolvedXmlSource)621         public void EnsureDigestValidity(string id, object resolvedXmlSource)
622         {
623             if (!EnsureDigestValidityIfIdMatches(id, resolvedXmlSource))
624             {
625                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
626                     SR.GetString(SR.RequiredTargetNotSigned, id)));
627             }
628         }
629 
EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)630         public abstract bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource);
631 
HasUnverifiedReference(string id)632         public virtual bool HasUnverifiedReference(string id)
633         {
634             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
635         }
636 
ReadCanonicalizationMethod(XmlDictionaryReader reader, DictionaryManager dictionaryManager)637         protected void ReadCanonicalizationMethod(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
638         {
639             // we will ignore any comments in the SignedInfo elemnt when verifying signature
640             this.canonicalizationMethodElement.ReadFrom(reader, dictionaryManager, false);
641         }
642 
ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)643         public abstract void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager);
644 
ReadSignatureMethod(XmlDictionaryReader reader, DictionaryManager dictionaryManager)645         protected void ReadSignatureMethod(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
646         {
647             this.signatureMethodElement.ReadFrom(reader, dictionaryManager);
648         }
649 
WriteCanonicalizationMethod(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)650         protected void WriteCanonicalizationMethod(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
651         {
652             this.canonicalizationMethodElement.WriteTo(writer, dictionaryManager);
653         }
654 
WriteSignatureMethod(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)655         protected void WriteSignatureMethod(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
656         {
657             this.signatureMethodElement.WriteTo(writer, dictionaryManager);
658         }
659 
WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)660         public abstract void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager);
661     }
662 
663     // whitespace preservation convention: ws1 immediately inside open tag; ws2 immediately after end tag.
664     class StandardSignedInfo : SignedInfo
665     {
666         string prefix = SignedXml.DefaultPrefix;
667         List<Reference> references;
668         Dictionary<string, string> context;
669 
StandardSignedInfo(DictionaryManager dictionaryManager)670         public StandardSignedInfo(DictionaryManager dictionaryManager)
671             : base(dictionaryManager)
672         {
673             this.references = new List<Reference>();
674         }
675 
676         public override int ReferenceCount
677         {
678             get { return this.references.Count; }
679         }
680 
681         public Reference this[int index]
682         {
683             get { return this.references[index]; }
684         }
685 
AddReference(Reference reference)686         public void AddReference(Reference reference)
687         {
688             reference.ResourcePool = this.ResourcePool;
689             this.references.Add(reference);
690         }
691 
EnsureAllReferencesVerified()692         public override void EnsureAllReferencesVerified()
693         {
694             for (int i = 0; i < this.references.Count; i++)
695             {
696                 if (!this.references[i].Verified)
697                 {
698                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
699                         new CryptographicException(SR.GetString(SR.UnableToResolveReferenceUriForSignature, this.references[i].Uri)));
700                 }
701             }
702         }
703 
EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)704         public override bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)
705         {
706             for (int i = 0; i < this.references.Count; i++)
707             {
708                 if (this.references[i].EnsureDigestValidityIfIdMatches(id, resolvedXmlSource))
709                 {
710                     return true;
711                 }
712             }
713             return false;
714         }
715 
HasUnverifiedReference(string id)716         public override bool HasUnverifiedReference(string id)
717         {
718             for (int i = 0; i < this.references.Count; i++)
719             {
720                 if (!this.references[i].Verified && this.references[i].ExtractReferredId() == id)
721                 {
722                     return true;
723                 }
724             }
725             return false;
726         }
727 
ComputeReferenceDigests()728         public override void ComputeReferenceDigests()
729         {
730             if (this.references.Count == 0)
731             {
732                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.AtLeastOneReferenceRequired)));
733             }
734             for (int i = 0; i < this.references.Count; i++)
735             {
736                 this.references[i].ComputeAndSetDigest();
737             }
738         }
739 
ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)740         public override void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)
741         {
742             this.SendSide = false;
743             if (reader.CanCanonicalize)
744             {
745                 this.CanonicalStream = new MemoryStream();
746                 reader.StartCanonicalization(this.CanonicalStream, false, null);
747             }
748 
749             reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.SignedInfo, dictionaryManager.XmlSignatureDictionary.Namespace);
750             this.prefix = reader.Prefix;
751             this.Id = reader.GetAttribute(dictionaryManager.UtilityDictionary.IdAttribute, null);
752             reader.Read();
753 
754             ReadCanonicalizationMethod(reader, dictionaryManager);
755             ReadSignatureMethod(reader, dictionaryManager);
756             while (reader.IsStartElement(dictionaryManager.XmlSignatureDictionary.Reference, dictionaryManager.XmlSignatureDictionary.Namespace))
757             {
758                 Reference reference = new Reference(dictionaryManager);
759                 reference.ReadFrom(reader, transformFactory, dictionaryManager);
760                 AddReference(reference);
761             }
762             reader.ReadEndElement(); // SignedInfo
763 
764             if (reader.CanCanonicalize)
765                 reader.EndCanonicalization();
766 
767             string[] inclusivePrefixes = GetInclusivePrefixes();
768             if (inclusivePrefixes != null)
769             {
770                 // Clear the canonicalized stream. We cannot use this while inclusive prefixes are
771                 // specified.
772                 this.CanonicalStream = null;
773                 this.context = new Dictionary<string, string>(inclusivePrefixes.Length);
774                 for (int i = 0; i < inclusivePrefixes.Length; i++)
775                 {
776                     this.context.Add(inclusivePrefixes[i], reader.LookupNamespace(inclusivePrefixes[i]));
777                 }
778             }
779         }
780 
WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)781         public override void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
782         {
783             writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.SignedInfo, dictionaryManager.XmlSignatureDictionary.Namespace);
784             if (this.Id != null)
785             {
786                 writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.Id);
787             }
788             WriteCanonicalizationMethod(writer, dictionaryManager);
789             WriteSignatureMethod(writer, dictionaryManager);
790             for (int i = 0; i < this.references.Count; i++)
791             {
792                 this.references[i].WriteTo(writer, dictionaryManager);
793             }
794             writer.WriteEndElement(); // SignedInfo
795         }
796 
GetNamespaceForInclusivePrefix(string prefix)797         protected override string GetNamespaceForInclusivePrefix(string prefix)
798         {
799             if (this.context == null)
800                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
801 
802             if (prefix == null)
803                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("prefix");
804 
805             return context[prefix];
806         }
807 
808         protected string Prefix
809         {
810             get { return prefix; }
811             set { prefix = value; }
812         }
813 
814         protected Dictionary<string, string> Context
815         {
816             get { return context; }
817             set { context = value; }
818         }
819     }
820 
821     sealed class WifSignedInfo : StandardSignedInfo, IDisposable
822     {
823         MemoryStream _bufferedStream;
824         string _defaultNamespace = String.Empty;
825         bool _disposed;
826 
WifSignedInfo(DictionaryManager dictionaryManager)827         public WifSignedInfo(DictionaryManager dictionaryManager)
828             : base(dictionaryManager)
829         {
830         }
831 
~WifSignedInfo()832         ~WifSignedInfo()
833         {
834             Dispose(false);
835         }
836 
Dispose()837         public void Dispose()
838         {
839             Dispose(true);
840             GC.SuppressFinalize(this);
841         }
842 
Dispose(bool disposing)843         void Dispose(bool disposing)
844         {
845             if (_disposed)
846             {
847                 return;
848             }
849 
850             if (disposing)
851             {
852                 //
853                 // Free all of our managed resources
854                 //
855                 if (_bufferedStream != null)
856                 {
857                     _bufferedStream.Close();
858                     _bufferedStream = null;
859                 }
860             }
861 
862             // Free native resources, if any.
863 
864             _disposed = true;
865 
866         }
867 
ComputeHash(HashStream hashStream)868         protected override void ComputeHash(HashStream hashStream)
869         {
870             if (SendSide)
871             {
872                 using (XmlDictionaryWriter utf8Writer = XmlDictionaryWriter.CreateTextWriter(Stream.Null, Encoding.UTF8, false))
873                 {
874                     utf8Writer.StartCanonicalization(hashStream, false, null);
875                     WriteTo(utf8Writer, DictionaryManager);
876                     utf8Writer.EndCanonicalization();
877                 }
878             }
879             else if (CanonicalStream != null)
880             {
881                 CanonicalStream.WriteTo(hashStream);
882             }
883             else
884             {
885                 _bufferedStream.Position = 0;
886                 // We are creating a XmlDictionaryReader with a hard-coded Max XmlDictionaryReaderQuotas. This is a reader that we
887                 // are creating over an already buffered content. The content was initially read off user provided XmlDictionaryReader
888                 // with the correct quotas and hence we know the data is valid.
889                 // Note: signedinfoReader will close _bufferedStream on Dispose.
890                 using (XmlDictionaryReader signedinfoReader = XmlDictionaryReader.CreateTextReader(_bufferedStream, XmlDictionaryReaderQuotas.Max))
891                 {
892                     signedinfoReader.MoveToContent();
893                     using (XmlDictionaryWriter bufferingWriter = XmlDictionaryWriter.CreateTextWriter(Stream.Null, Encoding.UTF8, false))
894                     {
895                         bufferingWriter.WriteStartElement("a", _defaultNamespace);
896                         string[] inclusivePrefix = GetInclusivePrefixes();
897                         for (int i = 0; i < inclusivePrefix.Length; ++i)
898                         {
899                             string ns = GetNamespaceForInclusivePrefix(inclusivePrefix[i]);
900                             if (ns != null)
901                             {
902                                 bufferingWriter.WriteXmlnsAttribute(inclusivePrefix[i], ns);
903                             }
904                         }
905                         bufferingWriter.StartCanonicalization(hashStream, false, inclusivePrefix);
906                         bufferingWriter.WriteNode(signedinfoReader, false);
907                         bufferingWriter.EndCanonicalization();
908                         bufferingWriter.WriteEndElement();
909                     }
910                 }
911             }
912         }
913 
ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)914         public override void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)
915         {
916             reader.MoveToStartElement(XmlSignatureConstants.Elements.SignedInfo, XmlSignatureConstants.Namespace);
917 
918             SendSide = false;
919             _defaultNamespace = reader.LookupNamespace(String.Empty);
920             _bufferedStream = new MemoryStream();
921 
922 
923             XmlWriterSettings settings = new XmlWriterSettings();
924             settings.Encoding = Encoding.UTF8;
925             settings.NewLineHandling = NewLineHandling.None;
926 
927             using (XmlWriter bufferWriter = XmlTextWriter.Create(_bufferedStream, settings))
928             {
929                 bufferWriter.WriteNode(reader, true);
930                 bufferWriter.Flush();
931             }
932 
933             _bufferedStream.Position = 0;
934 
935             //
936             // We are creating a XmlDictionaryReader with a hard-coded Max XmlDictionaryReaderQuotas. This is a reader that we
937             // are creating over an already buffered content. The content was initially read off user provided XmlDictionaryReader
938             // with the correct quotas and hence we know the data is valid.
939             // Note: effectiveReader will close _bufferedStream on Dispose.
940             //
941             using (XmlDictionaryReader effectiveReader = XmlDictionaryReader.CreateTextReader(_bufferedStream, XmlDictionaryReaderQuotas.Max))
942             {
943                 CanonicalStream = new MemoryStream();
944                 effectiveReader.StartCanonicalization(CanonicalStream, false, null);
945 
946                 effectiveReader.MoveToStartElement(XmlSignatureConstants.Elements.SignedInfo, XmlSignatureConstants.Namespace);
947                 Prefix = effectiveReader.Prefix;
948                 Id = effectiveReader.GetAttribute(WSSecurityUtilityConstants.Attributes.Id, null);
949                 effectiveReader.Read();
950 
951                 ReadCanonicalizationMethod(effectiveReader, DictionaryManager);
952                 ReadSignatureMethod(effectiveReader, DictionaryManager);
953                 while (effectiveReader.IsStartElement(XmlSignatureConstants.Elements.Reference, XmlSignatureConstants.Namespace))
954                 {
955                     Reference reference = new Reference(DictionaryManager);
956                     reference.ReadFrom(effectiveReader, transformFactory, DictionaryManager);
957                     AddReference(reference);
958                 }
959                 effectiveReader.ReadEndElement();
960 
961                 effectiveReader.EndCanonicalization();
962             }
963 
964             string[] inclusivePrefixes = GetInclusivePrefixes();
965             if (inclusivePrefixes != null)
966             {
967                 // Clear the canonicalized stream. We cannot use this while inclusive prefixes are
968                 // specified.
969                 CanonicalStream = null;
970                 Context = new Dictionary<string, string>(inclusivePrefixes.Length);
971                 for (int i = 0; i < inclusivePrefixes.Length; i++)
972                 {
973                     Context.Add(inclusivePrefixes[i], reader.LookupNamespace(inclusivePrefixes[i]));
974                 }
975             }
976         }
977     }
978 
979     sealed class Reference
980     {
981         ElementWithAlgorithmAttribute digestMethodElement;
982         DigestValueElement digestValueElement = new DigestValueElement();
983         string id;
984         string prefix = SignedXml.DefaultPrefix;
985         object resolvedXmlSource;
986         readonly TransformChain transformChain = new TransformChain();
987         string type;
988         string uri;
989         SignatureResourcePool resourcePool;
990         bool verified;
991         string referredId;
992         DictionaryManager dictionaryManager;
993 
Reference(DictionaryManager dictionaryManager)994         public Reference(DictionaryManager dictionaryManager)
995             : this(dictionaryManager, null)
996         {
997         }
998 
Reference(DictionaryManager dictionaryManager, string uri)999         public Reference(DictionaryManager dictionaryManager, string uri)
1000             : this(dictionaryManager, uri, null)
1001         {
1002         }
1003 
Reference(DictionaryManager dictionaryManager, string uri, object resolvedXmlSource)1004         public Reference(DictionaryManager dictionaryManager, string uri, object resolvedXmlSource)
1005         {
1006             if (dictionaryManager == null)
1007                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("dictionaryManager");
1008 
1009             this.dictionaryManager = dictionaryManager;
1010             this.digestMethodElement = new ElementWithAlgorithmAttribute(dictionaryManager.XmlSignatureDictionary.DigestMethod);
1011             this.uri = uri;
1012             this.resolvedXmlSource = resolvedXmlSource;
1013         }
1014 
1015         public string DigestMethod
1016         {
1017             get { return this.digestMethodElement.Algorithm; }
1018             set { this.digestMethodElement.Algorithm = value; }
1019         }
1020 
1021         public XmlDictionaryString DigestMethodDictionaryString
1022         {
1023             get { return this.digestMethodElement.AlgorithmDictionaryString; }
1024             set { this.digestMethodElement.AlgorithmDictionaryString = value; }
1025         }
1026 
1027         public string Id
1028         {
1029             get { return this.id; }
1030             set { this.id = value; }
1031         }
1032 
1033         public SignatureResourcePool ResourcePool
1034         {
1035             get { return this.resourcePool; }
1036             set { this.resourcePool = value; }
1037         }
1038 
1039         public TransformChain TransformChain
1040         {
1041             get { return this.transformChain; }
1042         }
1043 
1044         public int TransformCount
1045         {
1046             get { return this.transformChain.TransformCount; }
1047         }
1048 
1049         public string Type
1050         {
1051             get { return this.type; }
1052             set { this.type = value; }
1053         }
1054 
1055         public string Uri
1056         {
1057             get { return this.uri; }
1058             set { this.uri = value; }
1059         }
1060 
1061         public bool Verified
1062         {
1063             get { return this.verified; }
1064         }
1065 
AddTransform(Transform transform)1066         public void AddTransform(Transform transform)
1067         {
1068             this.transformChain.Add(transform);
1069         }
1070 
EnsureDigestValidity(string id, byte[] computedDigest)1071         public void EnsureDigestValidity(string id, byte[] computedDigest)
1072         {
1073             if (!EnsureDigestValidityIfIdMatches(id, computedDigest))
1074             {
1075                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
1076                     SR.GetString(SR.RequiredTargetNotSigned, id)));
1077             }
1078         }
1079 
EnsureDigestValidity(string id, object resolvedXmlSource)1080         public void EnsureDigestValidity(string id, object resolvedXmlSource)
1081         {
1082             if (!EnsureDigestValidityIfIdMatches(id, resolvedXmlSource))
1083             {
1084                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
1085                     SR.GetString(SR.RequiredTargetNotSigned, id)));
1086             }
1087         }
1088 
EnsureDigestValidityIfIdMatches(string id, byte[] computedDigest)1089         public bool EnsureDigestValidityIfIdMatches(string id, byte[] computedDigest)
1090         {
1091             if (this.verified || id != ExtractReferredId())
1092             {
1093                 return false;
1094             }
1095             if (!CryptoHelper.IsEqual(computedDigest, GetDigestValue()))
1096             {
1097                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1098                     new CryptographicException(SR.GetString(SR.DigestVerificationFailedForReference, this.uri)));
1099             }
1100             this.verified = true;
1101             return true;
1102         }
1103 
EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)1104         public bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)
1105         {
1106             if (this.verified)
1107             {
1108                 return false;
1109             }
1110 
1111             // During StrTransform the extractedReferredId on the reference will point to STR and hence will not be
1112             // equal to the referred element ie security token Id.
1113             if (id != ExtractReferredId() && !this.IsStrTranform())
1114             {
1115                 return false;
1116             }
1117 
1118             this.resolvedXmlSource = resolvedXmlSource;
1119             if (!CheckDigest())
1120             {
1121                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1122                     new CryptographicException(SR.GetString(SR.DigestVerificationFailedForReference, this.uri)));
1123             }
1124             this.verified = true;
1125             return true;
1126         }
1127 
IsStrTranform()1128         public bool IsStrTranform()
1129         {
1130             return this.TransformChain.TransformCount == 1 && this.TransformChain[0].Algorithm == SecurityAlgorithms.StrTransform;
1131         }
1132 
1133 
ExtractReferredId()1134         public string ExtractReferredId()
1135         {
1136             if (this.referredId == null)
1137             {
1138                 if (StringComparer.OrdinalIgnoreCase.Equals(uri, String.Empty))
1139                 {
1140                     return String.Empty;
1141                 }
1142 
1143                 if (this.uri == null || this.uri.Length < 2 || this.uri[0] != '#')
1144                 {
1145                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1146                         new CryptographicException(SR.GetString(SR.UnableToResolveReferenceUriForSignature, this.uri)));
1147                 }
1148                 this.referredId = this.uri.Substring(1);
1149             }
1150             return this.referredId;
1151         }
1152 
1153 
1154         /// <summary>
1155         /// We look at the URI reference to decide if we should preserve comments while canonicalization.
1156         /// Only when the reference is xpointer(/) or xpointer(id(SomeId)) do we preserve comments during canonicalization
1157         /// of the reference element for computing the digest.
1158         /// </summary>
1159         /// <param name="uri">The Uri reference </param>
1160         /// <returns>true if comments should be preserved.</returns>
ShouldPreserveComments(string uri)1161         private static bool ShouldPreserveComments(string uri)
1162         {
1163             bool preserveComments = false;
1164 
1165             if (!String.IsNullOrEmpty(uri))
1166             {
1167                 //removes the hash
1168                 string idref = uri.Substring(1);
1169 
1170                 if (idref == "xpointer(/)")
1171                 {
1172                     preserveComments = true;
1173                 }
1174                 else if (idref.StartsWith("xpointer(id(", StringComparison.Ordinal) && (idref.IndexOf(")", StringComparison.Ordinal) > 0))
1175                 {
1176                     // Dealing with XPointer of type #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional
1177                     preserveComments = true;
1178                 }
1179             }
1180 
1181             return preserveComments;
1182         }
1183 
CheckDigest()1184         public bool CheckDigest()
1185         {
1186             byte[] computedDigest = ComputeDigest();
1187             bool result = CryptoHelper.IsEqual(computedDigest, GetDigestValue());
1188 #if LOG_DIGESTS
1189             Console.WriteLine(">>> Checking digest for reference '{0}', result {1}", uri, result);
1190             Console.WriteLine("    Computed digest {0}", Convert.ToBase64String(computedDigest));
1191             Console.WriteLine("    Received digest {0}", Convert.ToBase64String(GetDigestValue()));
1192 #endif
1193             return result;
1194         }
1195 
ComputeAndSetDigest()1196         public void ComputeAndSetDigest()
1197         {
1198             this.digestValueElement.Value = ComputeDigest();
1199         }
1200 
ComputeDigest()1201         public byte[] ComputeDigest()
1202         {
1203             if (this.transformChain.TransformCount == 0)
1204             {
1205                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.EmptyTransformChainNotSupported)));
1206             }
1207 
1208             if (this.resolvedXmlSource == null)
1209             {
1210                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
1211                     SR.GetString(SR.UnableToResolveReferenceUriForSignature, this.uri)));
1212             }
1213             return this.transformChain.TransformToDigest(this.resolvedXmlSource, this.ResourcePool, this.DigestMethod, this.dictionaryManager);
1214         }
1215 
GetDigestValue()1216         public byte[] GetDigestValue()
1217         {
1218             return this.digestValueElement.Value;
1219         }
1220 
ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)1221         public void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)
1222         {
1223             reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.Reference, dictionaryManager.XmlSignatureDictionary.Namespace);
1224             this.prefix = reader.Prefix;
1225             this.Id = reader.GetAttribute(UtilityStrings.IdAttribute, null);
1226             this.Uri = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.URI, null);
1227             this.Type = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.Type, null);
1228             reader.Read();
1229 
1230             if (reader.IsStartElement(dictionaryManager.XmlSignatureDictionary.Transforms, dictionaryManager.XmlSignatureDictionary.Namespace))
1231             {
1232                 this.transformChain.ReadFrom(reader, transformFactory, dictionaryManager, ShouldPreserveComments(this.Uri));
1233             }
1234 
1235             this.digestMethodElement.ReadFrom(reader, dictionaryManager);
1236             this.digestValueElement.ReadFrom(reader, dictionaryManager);
1237 
1238             reader.MoveToContent();
1239             reader.ReadEndElement(); // Reference
1240         }
1241 
SetResolvedXmlSource(object resolvedXmlSource)1242         public void SetResolvedXmlSource(object resolvedXmlSource)
1243         {
1244             this.resolvedXmlSource = resolvedXmlSource;
1245         }
1246 
WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)1247         public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
1248         {
1249             writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.Reference, dictionaryManager.XmlSignatureDictionary.Namespace);
1250             if (this.id != null)
1251             {
1252                 writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.id);
1253             }
1254             if (this.uri != null)
1255             {
1256                 writer.WriteAttributeString(dictionaryManager.XmlSignatureDictionary.URI, null, this.uri);
1257             }
1258             if (this.type != null)
1259             {
1260                 writer.WriteAttributeString(dictionaryManager.XmlSignatureDictionary.Type, null, this.type);
1261             }
1262 
1263             if (this.transformChain.TransformCount > 0)
1264             {
1265                 this.transformChain.WriteTo(writer, dictionaryManager);
1266             }
1267 
1268             this.digestMethodElement.WriteTo(writer, dictionaryManager);
1269             this.digestValueElement.WriteTo(writer, dictionaryManager);
1270 
1271             writer.WriteEndElement(); // Reference
1272         }
1273 
1274         struct DigestValueElement
1275         {
1276             byte[] digestValue;
1277             string digestText;
1278             string prefix;
1279 
1280             internal byte[] Value
1281             {
1282                 get { return this.digestValue; }
1283                 set
1284                 {
1285                     this.digestValue = value;
1286                     this.digestText = null;
1287                 }
1288             }
1289 
ReadFromSystem.IdentityModel.Reference.DigestValueElement1290             public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
1291             {
1292                 reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.DigestValue, dictionaryManager.XmlSignatureDictionary.Namespace);
1293                 this.prefix = reader.Prefix;
1294                 reader.Read();
1295                 reader.MoveToContent();
1296 
1297                 this.digestText = reader.ReadString();
1298                 this.digestValue = System.Convert.FromBase64String(digestText.Trim());
1299 
1300                 reader.MoveToContent();
1301                 reader.ReadEndElement(); // DigestValue
1302             }
1303 
WriteToSystem.IdentityModel.Reference.DigestValueElement1304             public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
1305             {
1306                 writer.WriteStartElement(this.prefix ?? XmlSignatureStrings.Prefix, dictionaryManager.XmlSignatureDictionary.DigestValue, dictionaryManager.XmlSignatureDictionary.Namespace);
1307                 if (this.digestText != null)
1308                 {
1309                     writer.WriteString(this.digestText);
1310                 }
1311                 else
1312                 {
1313                     writer.WriteBase64(this.digestValue, 0, this.digestValue.Length);
1314                 }
1315                 writer.WriteEndElement(); // DigestValue
1316             }
1317         }
1318     }
1319 
1320     sealed class TransformChain
1321     {
1322         string prefix = SignedXml.DefaultPrefix;
1323         MostlySingletonList<Transform> transforms;
1324 
TransformChain()1325         public TransformChain()
1326         {
1327         }
1328 
1329         public int TransformCount
1330         {
1331             get { return this.transforms.Count; }
1332         }
1333 
1334         public Transform this[int index]
1335         {
1336             get
1337             {
1338                 return this.transforms[index];
1339             }
1340         }
1341 
1342         public bool NeedsInclusiveContext
1343         {
1344             get
1345             {
1346                 for (int i = 0; i < this.TransformCount; i++)
1347                 {
1348                     if (this[i].NeedsInclusiveContext)
1349                     {
1350                         return true;
1351                     }
1352                 }
1353                 return false;
1354             }
1355         }
1356 
Add(Transform transform)1357         public void Add(Transform transform)
1358         {
1359             this.transforms.Add(transform);
1360         }
1361 
ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager, bool preserveComments)1362         public void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager, bool preserveComments)
1363         {
1364             reader.MoveToStartElement(dictionaryManager.XmlSignatureDictionary.Transforms, dictionaryManager.XmlSignatureDictionary.Namespace);
1365             this.prefix = reader.Prefix;
1366             reader.Read();
1367 
1368             while (reader.IsStartElement(dictionaryManager.XmlSignatureDictionary.Transform, dictionaryManager.XmlSignatureDictionary.Namespace))
1369             {
1370                 string transformAlgorithmUri = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null);
1371                 Transform transform = transformFactory.CreateTransform(transformAlgorithmUri);
1372                 transform.ReadFrom(reader, dictionaryManager, preserveComments);
1373                 Add(transform);
1374             }
1375             reader.MoveToContent();
1376             reader.ReadEndElement(); // Transforms
1377             if (this.TransformCount == 0)
1378             {
1379                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(SR.GetString(SR.AtLeastOneTransformRequired)));
1380             }
1381         }
1382 
TransformToDigest(object data, SignatureResourcePool resourcePool, string digestMethod, DictionaryManager dictionaryManager)1383         public byte[] TransformToDigest(object data, SignatureResourcePool resourcePool, string digestMethod, DictionaryManager dictionaryManager)
1384         {
1385             DiagnosticUtility.DebugAssert(TransformCount > 0, "");
1386             for (int i = 0; i < this.TransformCount - 1; i++)
1387             {
1388                 data = this[i].Process(data, resourcePool, dictionaryManager);
1389             }
1390             return this[this.TransformCount - 1].ProcessAndDigest(data, resourcePool, digestMethod, dictionaryManager);
1391         }
1392 
WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)1393         public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
1394         {
1395             writer.WriteStartElement(this.prefix, dictionaryManager.XmlSignatureDictionary.Transforms, dictionaryManager.XmlSignatureDictionary.Namespace);
1396             for (int i = 0; i < this.TransformCount; i++)
1397             {
1398                 this[i].WriteTo(writer, dictionaryManager);
1399             }
1400             writer.WriteEndElement(); // Transforms
1401         }
1402     }
1403 
1404     struct ElementWithAlgorithmAttribute
1405     {
1406         readonly XmlDictionaryString elementName;
1407         string algorithm;
1408         XmlDictionaryString algorithmDictionaryString;
1409         string prefix;
1410 
ElementWithAlgorithmAttributeSystem.IdentityModel.ElementWithAlgorithmAttribute1411         public ElementWithAlgorithmAttribute(XmlDictionaryString elementName)
1412         {
1413             if (elementName == null)
1414             {
1415                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("elementName"));
1416             }
1417             this.elementName = elementName;
1418             this.algorithm = null;
1419             this.algorithmDictionaryString = null;
1420             this.prefix = SignedXml.DefaultPrefix;
1421         }
1422 
1423         public string Algorithm
1424         {
1425             get { return this.algorithm; }
1426             set { this.algorithm = value; }
1427         }
1428 
1429         public XmlDictionaryString AlgorithmDictionaryString
1430         {
1431             get { return this.algorithmDictionaryString; }
1432             set { this.algorithmDictionaryString = value; }
1433         }
1434 
ReadFromSystem.IdentityModel.ElementWithAlgorithmAttribute1435         public void ReadFrom(XmlDictionaryReader reader, DictionaryManager dictionaryManager)
1436         {
1437             reader.MoveToStartElement(this.elementName, dictionaryManager.XmlSignatureDictionary.Namespace);
1438             this.prefix = reader.Prefix;
1439             bool isEmptyElement = reader.IsEmptyElement;
1440             this.algorithm = reader.GetAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null);
1441             if (this.algorithm == null)
1442             {
1443                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CryptographicException(
1444                     SR.GetString(SR.RequiredAttributeMissing, dictionaryManager.XmlSignatureDictionary.Algorithm, this.elementName)));
1445             }
1446             reader.Read();
1447             reader.MoveToContent();
1448 
1449             if (!isEmptyElement)
1450             {
1451                 reader.MoveToContent();
1452                 reader.ReadEndElement();
1453             }
1454         }
1455 
WriteToSystem.IdentityModel.ElementWithAlgorithmAttribute1456         public void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)
1457         {
1458             writer.WriteStartElement(this.prefix, this.elementName, dictionaryManager.XmlSignatureDictionary.Namespace);
1459             writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null);
1460             if (this.algorithmDictionaryString != null)
1461             {
1462                 writer.WriteString(this.algorithmDictionaryString);
1463             }
1464             else
1465             {
1466                 writer.WriteString(this.algorithm);
1467             }
1468             writer.WriteEndAttribute();
1469             writer.WriteEndElement();
1470         }
1471     }
1472 }
1473