1 //------------------------------------------------------------ 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //------------------------------------------------------------ 4 5 namespace System.IdentityModel 6 { 7 using System.Diagnostics; 8 using System.IO; 9 using System.Security.Cryptography; 10 using System.IdentityModel.Tokens; 11 using System.Text; 12 using System.Xml; 13 14 sealed class PreDigestedSignedInfo : SignedInfo 15 { 16 const int InitialReferenceArraySize = 8; 17 bool addEnvelopedSignatureTransform; 18 int count; 19 string digestMethod; 20 XmlDictionaryString digestMethodDictionaryString; 21 ReferenceEntry[] references; 22 PreDigestedSignedInfo(DictionaryManager dictionaryManager)23 public PreDigestedSignedInfo(DictionaryManager dictionaryManager) 24 : base(dictionaryManager) 25 { 26 this.references = new ReferenceEntry[InitialReferenceArraySize]; 27 } 28 PreDigestedSignedInfo(DictionaryManager dictionaryManager, string canonicalizationMethod, XmlDictionaryString canonicalizationMethodDictionaryString, string digestMethod, XmlDictionaryString digestMethodDictionaryString, string signatureMethod, XmlDictionaryString signatureMethodDictionaryString)29 public PreDigestedSignedInfo(DictionaryManager dictionaryManager, string canonicalizationMethod, XmlDictionaryString canonicalizationMethodDictionaryString, string digestMethod, XmlDictionaryString digestMethodDictionaryString, string signatureMethod, XmlDictionaryString signatureMethodDictionaryString) 30 : base(dictionaryManager) 31 { 32 this.references = new ReferenceEntry[InitialReferenceArraySize]; 33 this.CanonicalizationMethod = canonicalizationMethod; 34 this.CanonicalizationMethodDictionaryString = canonicalizationMethodDictionaryString; 35 this.DigestMethod = digestMethod; 36 this.digestMethodDictionaryString = digestMethodDictionaryString; 37 this.SignatureMethod = signatureMethod; 38 this.SignatureMethodDictionaryString = signatureMethodDictionaryString; 39 } 40 41 public bool AddEnvelopedSignatureTransform 42 { 43 get { return this.addEnvelopedSignatureTransform; } 44 set { this.addEnvelopedSignatureTransform = value; } 45 } 46 47 public string DigestMethod 48 { 49 get { return this.digestMethod; } 50 set { this.digestMethod = value; } 51 } 52 53 public override int ReferenceCount 54 { 55 get { return this.count; } 56 } 57 AddReference(string id, byte[] digest)58 public void AddReference(string id, byte[] digest) 59 { 60 AddReference(id, digest, false); 61 } 62 AddReference(string id, byte[] digest, bool useStrTransform)63 public void AddReference(string id, byte[] digest, bool useStrTransform) 64 { 65 if (this.count == this.references.Length) 66 { 67 ReferenceEntry[] newReferences = new ReferenceEntry[this.references.Length * 2]; 68 Array.Copy(this.references, 0, newReferences, 0, this.count); 69 this.references = newReferences; 70 } 71 this.references[this.count++].Set(id, digest, useStrTransform); 72 } 73 ComputeHash(HashStream hashStream)74 protected override void ComputeHash(HashStream hashStream) 75 { 76 if (this.AddEnvelopedSignatureTransform) 77 { 78 base.ComputeHash(hashStream); 79 } 80 else 81 { 82 SignedInfoCanonicalFormWriter.Instance.WriteSignedInfoCanonicalForm( 83 hashStream, this.SignatureMethod, this.DigestMethod, 84 this.references, this.count, 85 this.ResourcePool.TakeEncodingBuffer(), this.ResourcePool.TakeBase64Buffer()); 86 } 87 } 88 ComputeReferenceDigests()89 public override void ComputeReferenceDigests() 90 { 91 // all digests pre-computed 92 } 93 ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager)94 public override void ReadFrom(XmlDictionaryReader reader, TransformFactory transformFactory, DictionaryManager dictionaryManager) 95 { 96 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); // sender side use only 97 } 98 EnsureAllReferencesVerified()99 public override void EnsureAllReferencesVerified() 100 { 101 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); // sender side use only 102 } 103 EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource)104 public override bool EnsureDigestValidityIfIdMatches(string id, object resolvedXmlSource) 105 { 106 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); // sender side use only 107 } 108 WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager)109 public override void WriteTo(XmlDictionaryWriter writer, DictionaryManager dictionaryManager) 110 { 111 string prefix = XmlSignatureStrings.Prefix; 112 XmlDictionaryString ns = dictionaryManager.XmlSignatureDictionary.Namespace; 113 114 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.SignedInfo, ns); 115 if (this.Id != null) 116 { 117 writer.WriteAttributeString(dictionaryManager.UtilityDictionary.IdAttribute, null, this.Id); 118 } 119 WriteCanonicalizationMethod(writer, dictionaryManager); 120 WriteSignatureMethod(writer, dictionaryManager); 121 for (int i = 0; i < this.count; i++) 122 { 123 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.Reference, ns); 124 writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.URI, null); 125 writer.WriteString("#"); 126 writer.WriteString(this.references[i].id); 127 writer.WriteEndAttribute(); 128 129 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.Transforms, ns); 130 if (this.addEnvelopedSignatureTransform) 131 { 132 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.Transform, ns); 133 writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null); 134 writer.WriteString(dictionaryManager.XmlSignatureDictionary.EnvelopedSignature); 135 writer.WriteEndAttribute(); 136 writer.WriteEndElement(); // Transform 137 } 138 139 if (this.references[i].useStrTransform) 140 { 141 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.Transform, ns); 142 writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null); 143 writer.WriteString(SecurityAlgorithms.StrTransform); 144 writer.WriteEndAttribute(); 145 writer.WriteStartElement(XmlSignatureStrings.SecurityJan2004Prefix, XmlSignatureStrings.TransformationParameters, XmlSignatureStrings.SecurityJan2004Namespace); //<wsse:TransformationParameters> 146 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.CanonicalizationMethod, ns); 147 writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null); 148 writer.WriteString(dictionaryManager.SecurityAlgorithmDictionary.ExclusiveC14n); 149 writer.WriteEndAttribute(); 150 writer.WriteEndElement(); //CanonicalizationMethod 151 writer.WriteEndElement(); // TransformationParameters 152 writer.WriteEndElement(); // Transform 153 } 154 else 155 { 156 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.Transform, ns); 157 writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null); 158 writer.WriteString(dictionaryManager.SecurityAlgorithmDictionary.ExclusiveC14n); 159 writer.WriteEndAttribute(); 160 writer.WriteEndElement(); // Transform 161 } 162 163 writer.WriteEndElement(); // Transforms 164 165 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.DigestMethod, ns); 166 writer.WriteStartAttribute(dictionaryManager.XmlSignatureDictionary.Algorithm, null); 167 if (this.digestMethodDictionaryString != null) 168 { 169 writer.WriteString(this.digestMethodDictionaryString); 170 } 171 else 172 { 173 writer.WriteString(this.digestMethod); 174 } 175 writer.WriteEndAttribute(); 176 writer.WriteEndElement(); // DigestMethod 177 178 byte[] digest = this.references[i].digest; 179 writer.WriteStartElement(prefix, dictionaryManager.XmlSignatureDictionary.DigestValue, ns); 180 writer.WriteBase64(digest, 0, digest.Length); 181 writer.WriteEndElement(); // DigestValue 182 183 writer.WriteEndElement(); // Reference 184 } 185 writer.WriteEndElement(); // SignedInfo 186 } 187 188 189 struct ReferenceEntry 190 { 191 internal string id; 192 internal byte[] digest; 193 internal bool useStrTransform; 194 SetSystem.IdentityModel.PreDigestedSignedInfo.ReferenceEntry195 public void Set(string id, byte[] digest, bool useStrTransform) 196 { 197 if (useStrTransform && string.IsNullOrEmpty(id)) 198 { 199 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(id)); 200 } 201 202 this.id = id; 203 this.digest = digest; 204 this.useStrTransform = useStrTransform; 205 } 206 } 207 208 sealed class SignedInfoCanonicalFormWriter : CanonicalFormWriter 209 { 210 const string xml1 = "<SignedInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\"><CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod><SignatureMethod Algorithm=\""; 211 const string xml2 = "\"></SignatureMethod>"; 212 const string xml3 = "<Reference URI=\"#"; 213 const string xml4 = "\"><Transforms><Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></Transform></Transforms><DigestMethod Algorithm=\""; 214 const string xml4WithStrTransform = "\"><Transforms><Transform Algorithm=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform\"><o:TransformationParameters xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"><CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"></CanonicalizationMethod></o:TransformationParameters></Transform></Transforms><DigestMethod Algorithm=\""; 215 const string xml5 = "\"></DigestMethod><DigestValue>"; 216 const string xml6 = "</DigestValue></Reference>"; 217 const string xml7 = "</SignedInfo>"; 218 219 readonly byte[] fragment1; 220 readonly byte[] fragment2; 221 readonly byte[] fragment3; 222 readonly byte[] fragment4; 223 readonly byte[] fragment4StrTransform; 224 readonly byte[] fragment5; 225 readonly byte[] fragment6; 226 readonly byte[] fragment7; 227 228 readonly byte[] sha1Digest; 229 readonly byte[] sha256Digest; 230 readonly byte[] hmacSha1Signature; 231 readonly byte[] rsaSha1Signature; 232 233 static readonly SignedInfoCanonicalFormWriter instance = new SignedInfoCanonicalFormWriter(); 234 SignedInfoCanonicalFormWriter()235 SignedInfoCanonicalFormWriter() 236 { 237 UTF8Encoding encoding = CanonicalFormWriter.Utf8WithoutPreamble; 238 this.fragment1 = encoding.GetBytes(xml1); 239 this.fragment2 = encoding.GetBytes(xml2); 240 this.fragment3 = encoding.GetBytes(xml3); 241 this.fragment4 = encoding.GetBytes(xml4); 242 this.fragment4StrTransform = encoding.GetBytes(xml4WithStrTransform); 243 this.fragment5 = encoding.GetBytes(xml5); 244 this.fragment6 = encoding.GetBytes(xml6); 245 this.fragment7 = encoding.GetBytes(xml7); 246 this.sha1Digest = encoding.GetBytes(SecurityAlgorithms.Sha1Digest); 247 this.sha256Digest = encoding.GetBytes(SecurityAlgorithms.Sha256Digest); 248 this.hmacSha1Signature = encoding.GetBytes(SecurityAlgorithms.HmacSha1Signature); 249 this.rsaSha1Signature = encoding.GetBytes(SecurityAlgorithms.RsaSha1Signature); 250 } 251 252 public static SignedInfoCanonicalFormWriter Instance 253 { 254 get { return instance; } 255 } 256 EncodeDigestAlgorithm(string algorithm)257 byte[] EncodeDigestAlgorithm(string algorithm) 258 { 259 if (algorithm == SecurityAlgorithms.Sha1Digest) 260 { 261 return this.sha1Digest; 262 } 263 else if (algorithm == SecurityAlgorithms.Sha256Digest) 264 { 265 return this.sha256Digest; 266 } 267 else 268 { 269 return CanonicalFormWriter.Utf8WithoutPreamble.GetBytes(algorithm); 270 } 271 } 272 EncodeSignatureAlgorithm(string algorithm)273 byte[] EncodeSignatureAlgorithm(string algorithm) 274 { 275 if (algorithm == SecurityAlgorithms.HmacSha1Signature) 276 { 277 return this.hmacSha1Signature; 278 } 279 else if (algorithm == SecurityAlgorithms.RsaSha1Signature) 280 { 281 return this.rsaSha1Signature; 282 } 283 else 284 { 285 return CanonicalFormWriter.Utf8WithoutPreamble.GetBytes(algorithm); 286 } 287 } 288 WriteSignedInfoCanonicalForm( Stream stream, string signatureMethod, string digestMethod, ReferenceEntry[] references, int referenceCount, byte[] workBuffer, char[] base64WorkBuffer)289 public void WriteSignedInfoCanonicalForm( 290 Stream stream, string signatureMethod, string digestMethod, 291 ReferenceEntry[] references, int referenceCount, 292 byte[] workBuffer, char[] base64WorkBuffer) 293 { 294 DiagnosticUtility.DebugAssert(XmlSignatureStrings.Prefix.Length == 0, "Update SignedInfoCanonicalFormWriter to match new XmlDSig prefix"); 295 296 stream.Write(this.fragment1, 0, this.fragment1.Length); 297 byte[] signatureMethodBytes = EncodeSignatureAlgorithm(signatureMethod); 298 stream.Write(signatureMethodBytes, 0, signatureMethodBytes.Length); 299 stream.Write(this.fragment2, 0, this.fragment2.Length); 300 301 byte[] digestMethodBytes = EncodeDigestAlgorithm(digestMethod); 302 for (int i = 0; i < referenceCount; i++) 303 { 304 stream.Write(this.fragment3, 0, this.fragment3.Length); 305 EncodeAndWrite(stream, workBuffer, references[i].id); 306 if (references[i].useStrTransform) 307 { 308 stream.Write(this.fragment4StrTransform, 0, this.fragment4StrTransform.Length); 309 } 310 else 311 { 312 stream.Write(this.fragment4, 0, this.fragment4.Length); 313 } 314 315 stream.Write(digestMethodBytes, 0, digestMethodBytes.Length); 316 stream.Write(this.fragment5, 0, this.fragment5.Length); 317 Base64EncodeAndWrite(stream, workBuffer, base64WorkBuffer, references[i].digest); 318 stream.Write(this.fragment6, 0, this.fragment6.Length); 319 } 320 321 stream.Write(this.fragment7, 0, this.fragment7.Length); 322 } 323 324 } 325 } 326 } 327