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