1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using Microsoft.Win32; 6 using System; 7 using System.Collections; 8 using System.Diagnostics; 9 using System.Globalization; 10 using System.IO; 11 using System.Security; 12 using System.Security.Cryptography; 13 using System.Security.Cryptography.X509Certificates; 14 using System.Security.Permissions; 15 using System.Text; 16 using System.Threading; 17 using System.Xml; 18 19 namespace System.Security.Cryptography.Xml 20 { 21 internal class Utils 22 { 23 // The maximum number of characters in an XML document (0 means no limit). 24 internal const int MaxCharactersInDocument = 0; 25 26 // The entity expansion limit. This is used to prevent entity expansion denial of service attacks. 27 internal const long MaxCharactersFromEntities = (long)1e7; 28 29 // The default XML Dsig recursion limit. 30 // This should be within limits of real world scenarios. 31 // Keeping this number low will preserve some stack space 32 internal const int XmlDsigSearchDepth = 20; 33 Utils()34 private Utils() { } 35 HasNamespace(XmlElement element, string prefix, string value)36 private static bool HasNamespace(XmlElement element, string prefix, string value) 37 { 38 if (IsCommittedNamespace(element, prefix, value)) return true; 39 if (element.Prefix == prefix && element.NamespaceURI == value) return true; 40 return false; 41 } 42 43 // A helper function that determines if a namespace node is a committed attribute IsCommittedNamespace(XmlElement element, string prefix, string value)44 internal static bool IsCommittedNamespace(XmlElement element, string prefix, string value) 45 { 46 if (element == null) 47 throw new ArgumentNullException(nameof(element)); 48 49 string name = ((prefix.Length > 0) ? "xmlns:" + prefix : "xmlns"); 50 if (element.HasAttribute(name) && element.GetAttribute(name) == value) return true; 51 return false; 52 } 53 IsRedundantNamespace(XmlElement element, string prefix, string value)54 internal static bool IsRedundantNamespace(XmlElement element, string prefix, string value) 55 { 56 if (element == null) 57 throw new ArgumentNullException(nameof(element)); 58 59 XmlNode ancestorNode = ((XmlNode)element).ParentNode; 60 while (ancestorNode != null) 61 { 62 XmlElement ancestorElement = ancestorNode as XmlElement; 63 if (ancestorElement != null) 64 if (HasNamespace(ancestorElement, prefix, value)) return true; 65 ancestorNode = ancestorNode.ParentNode; 66 } 67 68 return false; 69 } 70 GetAttribute(XmlElement element, string localName, string namespaceURI)71 internal static string GetAttribute(XmlElement element, string localName, string namespaceURI) 72 { 73 string s = (element.HasAttribute(localName) ? element.GetAttribute(localName) : null); 74 if (s == null && element.HasAttribute(localName, namespaceURI)) 75 s = element.GetAttribute(localName, namespaceURI); 76 return s; 77 } 78 HasAttribute(XmlElement element, string localName, string namespaceURI)79 internal static bool HasAttribute(XmlElement element, string localName, string namespaceURI) 80 { 81 return element.HasAttribute(localName) || element.HasAttribute(localName, namespaceURI); 82 } 83 IsNamespaceNode(XmlNode n)84 internal static bool IsNamespaceNode(XmlNode n) 85 { 86 return n.NodeType == XmlNodeType.Attribute && (n.Prefix.Equals("xmlns") || (n.Prefix.Length == 0 && n.LocalName.Equals("xmlns"))); 87 } 88 IsXmlNamespaceNode(XmlNode n)89 internal static bool IsXmlNamespaceNode(XmlNode n) 90 { 91 return n.NodeType == XmlNodeType.Attribute && n.Prefix.Equals("xml"); 92 } 93 94 // We consider xml:space style attributes as default namespace nodes since they obey the same propagation rules IsDefaultNamespaceNode(XmlNode n)95 internal static bool IsDefaultNamespaceNode(XmlNode n) 96 { 97 bool b1 = n.NodeType == XmlNodeType.Attribute && n.Prefix.Length == 0 && n.LocalName.Equals("xmlns"); 98 bool b2 = IsXmlNamespaceNode(n); 99 return b1 || b2; 100 } 101 IsEmptyDefaultNamespaceNode(XmlNode n)102 internal static bool IsEmptyDefaultNamespaceNode(XmlNode n) 103 { 104 return IsDefaultNamespaceNode(n) && n.Value.Length == 0; 105 } 106 GetNamespacePrefix(XmlAttribute a)107 internal static string GetNamespacePrefix(XmlAttribute a) 108 { 109 Debug.Assert(IsNamespaceNode(a) || IsXmlNamespaceNode(a)); 110 return a.Prefix.Length == 0 ? string.Empty : a.LocalName; 111 } 112 HasNamespacePrefix(XmlAttribute a, string nsPrefix)113 internal static bool HasNamespacePrefix(XmlAttribute a, string nsPrefix) 114 { 115 return GetNamespacePrefix(a).Equals(nsPrefix); 116 } 117 IsNonRedundantNamespaceDecl(XmlAttribute a, XmlAttribute nearestAncestorWithSamePrefix)118 internal static bool IsNonRedundantNamespaceDecl(XmlAttribute a, XmlAttribute nearestAncestorWithSamePrefix) 119 { 120 if (nearestAncestorWithSamePrefix == null) 121 return !IsEmptyDefaultNamespaceNode(a); 122 else 123 return !nearestAncestorWithSamePrefix.Value.Equals(a.Value); 124 } 125 IsXmlPrefixDefinitionNode(XmlAttribute a)126 internal static bool IsXmlPrefixDefinitionNode(XmlAttribute a) 127 { 128 return false; 129 // return a.Prefix.Equals("xmlns") && a.LocalName.Equals("xml") && a.Value.Equals(NamespaceUrlForXmlPrefix); 130 } 131 DiscardWhiteSpaces(string inputBuffer)132 internal static string DiscardWhiteSpaces(string inputBuffer) 133 { 134 return DiscardWhiteSpaces(inputBuffer, 0, inputBuffer.Length); 135 } 136 137 DiscardWhiteSpaces(string inputBuffer, int inputOffset, int inputCount)138 internal static string DiscardWhiteSpaces(string inputBuffer, int inputOffset, int inputCount) 139 { 140 int i, iCount = 0; 141 for (i = 0; i < inputCount; i++) 142 if (Char.IsWhiteSpace(inputBuffer[inputOffset + i])) iCount++; 143 char[] rgbOut = new char[inputCount - iCount]; 144 iCount = 0; 145 for (i = 0; i < inputCount; i++) 146 if (!Char.IsWhiteSpace(inputBuffer[inputOffset + i])) 147 { 148 rgbOut[iCount++] = inputBuffer[inputOffset + i]; 149 } 150 return new string(rgbOut); 151 } 152 SBReplaceCharWithString(StringBuilder sb, char oldChar, string newString)153 internal static void SBReplaceCharWithString(StringBuilder sb, char oldChar, string newString) 154 { 155 int i = 0; 156 int newStringLength = newString.Length; 157 while (i < sb.Length) 158 { 159 if (sb[i] == oldChar) 160 { 161 sb.Remove(i, 1); 162 sb.Insert(i, newString); 163 i += newStringLength; 164 } 165 else i++; 166 } 167 } 168 PreProcessStreamInput(Stream inputStream, XmlResolver xmlResolver, string baseUri)169 internal static XmlReader PreProcessStreamInput(Stream inputStream, XmlResolver xmlResolver, string baseUri) 170 { 171 XmlReaderSettings settings = GetSecureXmlReaderSettings(xmlResolver); 172 XmlReader reader = XmlReader.Create(inputStream, settings, baseUri); 173 return reader; 174 } 175 GetSecureXmlReaderSettings(XmlResolver xmlResolver)176 internal static XmlReaderSettings GetSecureXmlReaderSettings(XmlResolver xmlResolver) 177 { 178 XmlReaderSettings settings = new XmlReaderSettings(); 179 settings.XmlResolver = xmlResolver; 180 settings.DtdProcessing = DtdProcessing.Parse; 181 settings.MaxCharactersFromEntities = MaxCharactersFromEntities; 182 settings.MaxCharactersInDocument = MaxCharactersInDocument; 183 return settings; 184 } 185 PreProcessDocumentInput(XmlDocument document, XmlResolver xmlResolver, string baseUri)186 internal static XmlDocument PreProcessDocumentInput(XmlDocument document, XmlResolver xmlResolver, string baseUri) 187 { 188 if (document == null) 189 throw new ArgumentNullException(nameof(document)); 190 191 MyXmlDocument doc = new MyXmlDocument(); 192 doc.PreserveWhitespace = document.PreserveWhitespace; 193 194 // Normalize the document 195 using (TextReader stringReader = new StringReader(document.OuterXml)) 196 { 197 XmlReaderSettings settings = new XmlReaderSettings(); 198 settings.XmlResolver = xmlResolver; 199 settings.DtdProcessing = DtdProcessing.Parse; 200 settings.MaxCharactersFromEntities = MaxCharactersFromEntities; 201 settings.MaxCharactersInDocument = MaxCharactersInDocument; 202 XmlReader reader = XmlReader.Create(stringReader, settings, baseUri); 203 doc.Load(reader); 204 } 205 return doc; 206 } 207 PreProcessElementInput(XmlElement elem, XmlResolver xmlResolver, string baseUri)208 internal static XmlDocument PreProcessElementInput(XmlElement elem, XmlResolver xmlResolver, string baseUri) 209 { 210 if (elem == null) 211 throw new ArgumentNullException(nameof(elem)); 212 213 MyXmlDocument doc = new MyXmlDocument(); 214 doc.PreserveWhitespace = true; 215 // Normalize the document 216 using (TextReader stringReader = new StringReader(elem.OuterXml)) 217 { 218 XmlReaderSettings settings = new XmlReaderSettings(); 219 settings.XmlResolver = xmlResolver; 220 settings.DtdProcessing = DtdProcessing.Parse; 221 settings.MaxCharactersFromEntities = MaxCharactersFromEntities; 222 settings.MaxCharactersInDocument = MaxCharactersInDocument; 223 XmlReader reader = XmlReader.Create(stringReader, settings, baseUri); 224 doc.Load(reader); 225 } 226 return doc; 227 } 228 DiscardComments(XmlDocument document)229 internal static XmlDocument DiscardComments(XmlDocument document) 230 { 231 XmlNodeList nodeList = document.SelectNodes("//comment()"); 232 if (nodeList != null) 233 { 234 foreach (XmlNode node1 in nodeList) 235 { 236 node1.ParentNode.RemoveChild(node1); 237 } 238 } 239 return document; 240 } 241 AllDescendantNodes(XmlNode node, bool includeComments)242 internal static XmlNodeList AllDescendantNodes(XmlNode node, bool includeComments) 243 { 244 CanonicalXmlNodeList nodeList = new CanonicalXmlNodeList(); 245 CanonicalXmlNodeList elementList = new CanonicalXmlNodeList(); 246 CanonicalXmlNodeList attribList = new CanonicalXmlNodeList(); 247 CanonicalXmlNodeList namespaceList = new CanonicalXmlNodeList(); 248 249 int index = 0; 250 elementList.Add(node); 251 252 do 253 { 254 XmlNode rootNode = (XmlNode)elementList[index]; 255 // Add the children nodes 256 XmlNodeList childNodes = rootNode.ChildNodes; 257 if (childNodes != null) 258 { 259 foreach (XmlNode node1 in childNodes) 260 { 261 if (includeComments || (!(node1 is XmlComment))) 262 { 263 elementList.Add(node1); 264 } 265 } 266 } 267 // Add the attribute nodes 268 XmlAttributeCollection attribNodes = rootNode.Attributes; 269 if (attribNodes != null) 270 { 271 foreach (XmlNode attribNode in rootNode.Attributes) 272 { 273 if (attribNode.LocalName == "xmlns" || attribNode.Prefix == "xmlns") 274 namespaceList.Add(attribNode); 275 else 276 attribList.Add(attribNode); 277 } 278 } 279 index++; 280 } while (index < elementList.Count); 281 foreach (XmlNode elementNode in elementList) 282 { 283 nodeList.Add(elementNode); 284 } 285 foreach (XmlNode attribNode in attribList) 286 { 287 nodeList.Add(attribNode); 288 } 289 foreach (XmlNode namespaceNode in namespaceList) 290 { 291 nodeList.Add(namespaceNode); 292 } 293 294 return nodeList; 295 } 296 NodeInList(XmlNode node, XmlNodeList nodeList)297 internal static bool NodeInList(XmlNode node, XmlNodeList nodeList) 298 { 299 foreach (XmlNode nodeElem in nodeList) 300 { 301 if (nodeElem == node) return true; 302 } 303 return false; 304 } 305 GetIdFromLocalUri(string uri, out bool discardComments)306 internal static string GetIdFromLocalUri(string uri, out bool discardComments) 307 { 308 string idref = uri.Substring(1); 309 // initialize the return value 310 discardComments = true; 311 312 // Deal with XPointer of type #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional 313 if (idref.StartsWith("xpointer(id(", StringComparison.Ordinal)) 314 { 315 int startId = idref.IndexOf("id(", StringComparison.Ordinal); 316 int endId = idref.IndexOf(")", StringComparison.Ordinal); 317 if (endId < 0 || endId < startId + 3) 318 throw new CryptographicException(SR.Cryptography_Xml_InvalidReference); 319 idref = idref.Substring(startId + 3, endId - startId - 3); 320 idref = idref.Replace("\'", ""); 321 idref = idref.Replace("\"", ""); 322 discardComments = false; 323 } 324 return idref; 325 } 326 ExtractIdFromLocalUri(string uri)327 internal static string ExtractIdFromLocalUri(string uri) 328 { 329 string idref = uri.Substring(1); 330 331 // Deal with XPointer of type #xpointer(id("ID")). Other XPointer support isn't handled here and is anyway optional 332 if (idref.StartsWith("xpointer(id(", StringComparison.Ordinal)) 333 { 334 int startId = idref.IndexOf("id(", StringComparison.Ordinal); 335 int endId = idref.IndexOf(")", StringComparison.Ordinal); 336 if (endId < 0 || endId < startId + 3) 337 throw new CryptographicException(SR.Cryptography_Xml_InvalidReference); 338 idref = idref.Substring(startId + 3, endId - startId - 3); 339 idref = idref.Replace("\'", ""); 340 idref = idref.Replace("\"", ""); 341 } 342 return idref; 343 } 344 345 // This removes all children of an element. RemoveAllChildren(XmlElement inputElement)346 internal static void RemoveAllChildren(XmlElement inputElement) 347 { 348 XmlNode child = inputElement.FirstChild; 349 XmlNode sibling = null; 350 351 while (child != null) 352 { 353 sibling = child.NextSibling; 354 inputElement.RemoveChild(child); 355 child = sibling; 356 } 357 } 358 359 // Writes one stream (starting from the current position) into 360 // an output stream, connecting them up and reading until 361 // hitting the end of the input stream. 362 // returns the number of bytes copied Pump(Stream input, Stream output)363 internal static long Pump(Stream input, Stream output) 364 { 365 // Use MemoryStream's WriteTo(Stream) method if possible 366 MemoryStream inputMS = input as MemoryStream; 367 if (inputMS != null && inputMS.Position == 0) 368 { 369 inputMS.WriteTo(output); 370 return inputMS.Length; 371 } 372 373 const int count = 4096; 374 byte[] bytes = new byte[count]; 375 int numBytes; 376 long totalBytes = 0; 377 378 while ((numBytes = input.Read(bytes, 0, count)) > 0) 379 { 380 output.Write(bytes, 0, numBytes); 381 totalBytes += numBytes; 382 } 383 384 return totalBytes; 385 } 386 TokenizePrefixListString(string s)387 internal static Hashtable TokenizePrefixListString(string s) 388 { 389 Hashtable set = new Hashtable(); 390 if (s != null) 391 { 392 string[] prefixes = s.Split(null); 393 foreach (string prefix in prefixes) 394 { 395 if (prefix.Equals("#default")) 396 { 397 set.Add(string.Empty, true); 398 } 399 else if (prefix.Length > 0) 400 { 401 set.Add(prefix, true); 402 } 403 } 404 } 405 return set; 406 } 407 EscapeWhitespaceData(string data)408 internal static string EscapeWhitespaceData(string data) 409 { 410 StringBuilder sb = new StringBuilder(); 411 sb.Append(data); 412 Utils.SBReplaceCharWithString(sb, (char)13, "
"); 413 return sb.ToString(); ; 414 } 415 EscapeTextData(string data)416 internal static string EscapeTextData(string data) 417 { 418 StringBuilder sb = new StringBuilder(); 419 sb.Append(data); 420 sb.Replace("&", "&"); 421 sb.Replace("<", "<"); 422 sb.Replace(">", ">"); 423 SBReplaceCharWithString(sb, (char)13, "
"); 424 return sb.ToString(); ; 425 } 426 EscapeCData(string data)427 internal static string EscapeCData(string data) 428 { 429 return EscapeTextData(data); 430 } 431 EscapeAttributeValue(string value)432 internal static string EscapeAttributeValue(string value) 433 { 434 StringBuilder sb = new StringBuilder(); 435 sb.Append(value); 436 sb.Replace("&", "&"); 437 sb.Replace("<", "<"); 438 sb.Replace("\"", """); 439 SBReplaceCharWithString(sb, (char)9, "	"); 440 SBReplaceCharWithString(sb, (char)10, "
"); 441 SBReplaceCharWithString(sb, (char)13, "
"); 442 return sb.ToString(); 443 } 444 GetOwnerDocument(XmlNodeList nodeList)445 internal static XmlDocument GetOwnerDocument(XmlNodeList nodeList) 446 { 447 foreach (XmlNode node in nodeList) 448 { 449 if (node.OwnerDocument != null) 450 return node.OwnerDocument; 451 } 452 return null; 453 } 454 AddNamespaces(XmlElement elem, CanonicalXmlNodeList namespaces)455 internal static void AddNamespaces(XmlElement elem, CanonicalXmlNodeList namespaces) 456 { 457 if (namespaces != null) 458 { 459 foreach (XmlNode attrib in namespaces) 460 { 461 string name = ((attrib.Prefix.Length > 0) ? attrib.Prefix + ":" + attrib.LocalName : attrib.LocalName); 462 // Skip the attribute if one with the same qualified name already exists 463 if (elem.HasAttribute(name) || (name.Equals("xmlns") && elem.Prefix.Length == 0)) continue; 464 XmlAttribute nsattrib = (XmlAttribute)elem.OwnerDocument.CreateAttribute(name); 465 nsattrib.Value = attrib.Value; 466 elem.SetAttributeNode(nsattrib); 467 } 468 } 469 } 470 AddNamespaces(XmlElement elem, Hashtable namespaces)471 internal static void AddNamespaces(XmlElement elem, Hashtable namespaces) 472 { 473 if (namespaces != null) 474 { 475 foreach (string key in namespaces.Keys) 476 { 477 if (elem.HasAttribute(key)) continue; 478 XmlAttribute nsattrib = (XmlAttribute)elem.OwnerDocument.CreateAttribute(key); 479 nsattrib.Value = namespaces[key] as string; 480 elem.SetAttributeNode(nsattrib); 481 } 482 } 483 } 484 485 // This method gets the attributes that should be propagated GetPropagatedAttributes(XmlElement elem)486 internal static CanonicalXmlNodeList GetPropagatedAttributes(XmlElement elem) 487 { 488 if (elem == null) 489 return null; 490 491 CanonicalXmlNodeList namespaces = new CanonicalXmlNodeList(); 492 XmlNode ancestorNode = elem; 493 494 if (ancestorNode == null) return null; 495 496 bool bDefNamespaceToAdd = true; 497 498 while (ancestorNode != null) 499 { 500 XmlElement ancestorElement = ancestorNode as XmlElement; 501 if (ancestorElement == null) 502 { 503 ancestorNode = ancestorNode.ParentNode; 504 continue; 505 } 506 if (!Utils.IsCommittedNamespace(ancestorElement, ancestorElement.Prefix, ancestorElement.NamespaceURI)) 507 { 508 // Add the namespace attribute to the collection if needed 509 if (!Utils.IsRedundantNamespace(ancestorElement, ancestorElement.Prefix, ancestorElement.NamespaceURI)) 510 { 511 string name = ((ancestorElement.Prefix.Length > 0) ? "xmlns:" + ancestorElement.Prefix : "xmlns"); 512 XmlAttribute nsattrib = elem.OwnerDocument.CreateAttribute(name); 513 nsattrib.Value = ancestorElement.NamespaceURI; 514 namespaces.Add(nsattrib); 515 } 516 } 517 if (ancestorElement.HasAttributes) 518 { 519 XmlAttributeCollection attribs = ancestorElement.Attributes; 520 foreach (XmlAttribute attrib in attribs) 521 { 522 // Add a default namespace if necessary 523 if (bDefNamespaceToAdd && attrib.LocalName == "xmlns") 524 { 525 XmlAttribute nsattrib = elem.OwnerDocument.CreateAttribute("xmlns"); 526 nsattrib.Value = attrib.Value; 527 namespaces.Add(nsattrib); 528 bDefNamespaceToAdd = false; 529 continue; 530 } 531 // retain the declarations of type 'xml:*' as well 532 if (attrib.Prefix == "xmlns" || attrib.Prefix == "xml") 533 { 534 namespaces.Add(attrib); 535 continue; 536 } 537 if (attrib.NamespaceURI.Length > 0) 538 { 539 if (!Utils.IsCommittedNamespace(ancestorElement, attrib.Prefix, attrib.NamespaceURI)) 540 { 541 // Add the namespace attribute to the collection if needed 542 if (!Utils.IsRedundantNamespace(ancestorElement, attrib.Prefix, attrib.NamespaceURI)) 543 { 544 string name = ((attrib.Prefix.Length > 0) ? "xmlns:" + attrib.Prefix : "xmlns"); 545 XmlAttribute nsattrib = elem.OwnerDocument.CreateAttribute(name); 546 nsattrib.Value = attrib.NamespaceURI; 547 namespaces.Add(nsattrib); 548 } 549 } 550 } 551 } 552 } 553 ancestorNode = ancestorNode.ParentNode; 554 } 555 556 return namespaces; 557 } 558 559 // output of this routine is always big endian ConvertIntToByteArray(int dwInput)560 internal static byte[] ConvertIntToByteArray(int dwInput) 561 { 562 byte[] rgbTemp = new byte[8]; // int can never be greater than Int64 563 int t1; // t1 is remaining value to account for 564 int t2; // t2 is t1 % 256 565 int i = 0; 566 567 if (dwInput == 0) return new byte[1]; 568 t1 = dwInput; 569 while (t1 > 0) 570 { 571 t2 = t1 % 256; 572 rgbTemp[i] = (byte)t2; 573 t1 = (t1 - t2) / 256; 574 i++; 575 } 576 // Now, copy only the non-zero part of rgbTemp and reverse 577 byte[] rgbOutput = new byte[i]; 578 // copy and reverse in one pass 579 for (int j = 0; j < i; j++) 580 { 581 rgbOutput[j] = rgbTemp[i - j - 1]; 582 } 583 return rgbOutput; 584 } 585 ConvertByteArrayToInt(byte[] input)586 internal static int ConvertByteArrayToInt(byte[] input) 587 { 588 // Input to this routine is always big endian 589 int dwOutput = 0; 590 for (int i = 0; i < input.Length; i++) 591 { 592 dwOutput *= 256; 593 dwOutput += input[i]; 594 } 595 return (dwOutput); 596 } 597 GetHexArraySize(byte[] hex)598 internal static int GetHexArraySize(byte[] hex) 599 { 600 int index = hex.Length; 601 while (index-- > 0) 602 { 603 if (hex[index] != 0) 604 break; 605 } 606 return index + 1; 607 } 608 BuildBagOfCerts(KeyInfoX509Data keyInfoX509Data, CertUsageType certUsageType)609 internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyInfoX509Data, CertUsageType certUsageType) 610 { 611 X509Certificate2Collection collection = new X509Certificate2Collection(); 612 ArrayList decryptionIssuerSerials = (certUsageType == CertUsageType.Decryption ? new ArrayList() : null); 613 if (keyInfoX509Data.Certificates != null) 614 { 615 foreach (X509Certificate2 certificate in keyInfoX509Data.Certificates) 616 { 617 switch (certUsageType) 618 { 619 case CertUsageType.Verification: 620 collection.Add(certificate); 621 break; 622 case CertUsageType.Decryption: 623 decryptionIssuerSerials.Add(new X509IssuerSerial(certificate.IssuerName.Name, certificate.SerialNumber)); 624 break; 625 } 626 } 627 } 628 629 if (keyInfoX509Data.SubjectNames == null && keyInfoX509Data.IssuerSerials == null && 630 keyInfoX509Data.SubjectKeyIds == null && decryptionIssuerSerials == null) 631 return collection; 632 633 // Open LocalMachine and CurrentUser "Other People"/"My" stores. 634 635 X509Store[] stores = new X509Store[2]; 636 string storeName = (certUsageType == CertUsageType.Verification ? "AddressBook" : "My"); 637 stores[0] = new X509Store(storeName, StoreLocation.CurrentUser); 638 stores[1] = new X509Store(storeName, StoreLocation.LocalMachine); 639 640 for (int index = 0; index < stores.Length; index++) 641 { 642 if (stores[index] != null) 643 { 644 X509Certificate2Collection filters = null; 645 // We don't care if we can't open the store. 646 try 647 { 648 stores[index].Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); 649 filters = stores[index].Certificates; 650 stores[index].Close(); 651 if (keyInfoX509Data.SubjectNames != null) 652 { 653 foreach (string subjectName in keyInfoX509Data.SubjectNames) 654 { 655 filters = filters.Find(X509FindType.FindBySubjectDistinguishedName, subjectName, false); 656 } 657 } 658 if (keyInfoX509Data.IssuerSerials != null) 659 { 660 foreach (X509IssuerSerial issuerSerial in keyInfoX509Data.IssuerSerials) 661 { 662 filters = filters.Find(X509FindType.FindByIssuerDistinguishedName, issuerSerial.IssuerName, false); 663 filters = filters.Find(X509FindType.FindBySerialNumber, issuerSerial.SerialNumber, false); 664 } 665 } 666 if (keyInfoX509Data.SubjectKeyIds != null) 667 { 668 foreach (byte[] ski in keyInfoX509Data.SubjectKeyIds) 669 { 670 string hex = EncodeHexString(ski); 671 filters = filters.Find(X509FindType.FindBySubjectKeyIdentifier, hex, false); 672 } 673 } 674 if (decryptionIssuerSerials != null) 675 { 676 foreach (X509IssuerSerial issuerSerial in decryptionIssuerSerials) 677 { 678 filters = filters.Find(X509FindType.FindByIssuerDistinguishedName, issuerSerial.IssuerName, false); 679 filters = filters.Find(X509FindType.FindBySerialNumber, issuerSerial.SerialNumber, false); 680 } 681 } 682 } 683 // Store doesn't exist, no read permissions, other system error 684 catch (CryptographicException) { } 685 // Opening LocalMachine stores (other than Root or CertificateAuthority) on Linux 686 catch (PlatformNotSupportedException) { } 687 688 if (filters != null) 689 collection.AddRange(filters); 690 } 691 } 692 693 return collection; 694 } 695 696 private static readonly char[] s_hexValues = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; EncodeHexString(byte[] sArray)697 internal static string EncodeHexString(byte[] sArray) 698 { 699 return EncodeHexString(sArray, 0, (uint)sArray.Length); 700 } 701 EncodeHexString(byte[] sArray, uint start, uint end)702 internal static string EncodeHexString(byte[] sArray, uint start, uint end) 703 { 704 string result = null; 705 if (sArray != null) 706 { 707 char[] hexOrder = new char[(end - start) * 2]; 708 uint digit; 709 for (uint i = start, j = 0; i < end; i++) 710 { 711 digit = (uint)((sArray[i] & 0xf0) >> 4); 712 hexOrder[j++] = s_hexValues[digit]; 713 digit = (uint)(sArray[i] & 0x0f); 714 hexOrder[j++] = s_hexValues[digit]; 715 } 716 result = new String(hexOrder); 717 } 718 return result; 719 } 720 DecodeHexString(string s)721 internal static byte[] DecodeHexString(string s) 722 { 723 string hexString = Utils.DiscardWhiteSpaces(s); 724 uint cbHex = (uint)hexString.Length / 2; 725 byte[] hex = new byte[cbHex]; 726 int i = 0; 727 for (int index = 0; index < cbHex; index++) 728 { 729 hex[index] = (byte)((HexToByte(hexString[i]) << 4) | HexToByte(hexString[i + 1])); 730 i += 2; 731 } 732 return hex; 733 } 734 HexToByte(char val)735 internal static byte HexToByte(char val) 736 { 737 if (val <= '9' && val >= '0') 738 return (byte)(val - '0'); 739 else if (val >= 'a' && val <= 'f') 740 return (byte)((val - 'a') + 10); 741 else if (val >= 'A' && val <= 'F') 742 return (byte)((val - 'A') + 10); 743 else 744 return 0xFF; 745 } 746 IsSelfSigned(X509Chain chain)747 internal static bool IsSelfSigned(X509Chain chain) 748 { 749 X509ChainElementCollection elements = chain.ChainElements; 750 if (elements.Count != 1) 751 return false; 752 X509Certificate2 certificate = elements[0].Certificate; 753 if (String.Compare(certificate.SubjectName.Name, certificate.IssuerName.Name, StringComparison.OrdinalIgnoreCase) == 0) 754 return true; 755 return false; 756 } 757 GetAnyPublicKey(X509Certificate2 certificate)758 internal static AsymmetricAlgorithm GetAnyPublicKey(X509Certificate2 certificate) 759 { 760 return (AsymmetricAlgorithm)certificate.GetRSAPublicKey(); 761 } 762 } 763 } 764