diff options
author | Vladimir Kazakov <vladimir.kazakov@live.com> | 2018-01-05 01:20:13 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2018-01-05 01:20:13 +0300 |
commit | d0369589868f971fd13668906b178b158541344e (patch) | |
tree | e54e28eac29de0bcf23552bf9857f553287f3cf4 /mcs/class/System.Security | |
parent | 87315d19c6bdbb76f916b0f5c0df5043e717f579 (diff) |
XMLDSIG from .NET Core. (#6154)
Diffstat (limited to 'mcs/class/System.Security')
12 files changed, 877 insertions, 1796 deletions
diff --git a/mcs/class/System.Security/Makefile b/mcs/class/System.Security/Makefile index ae2de1a6370..04a3bea4d1e 100644 --- a/mcs/class/System.Security/Makefile +++ b/mcs/class/System.Security/Makefile @@ -8,6 +8,7 @@ MONO_SECURITY=Mono.Security endif LIBRARY = System.Security.dll +API_BIN_REFS := System.Numerics LIB_REFS = secxml/System bare/System.Xml $(MONO_SECURITY) KEYFILE = ../msfinal.pub LIB_MCS_FLAGS = \ diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoX509Data.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoX509Data.cs deleted file mode 100644 index 74280cb9151..00000000000 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoX509Data.cs +++ /dev/null @@ -1,285 +0,0 @@ -// -// KeyInfoX509Data.cs - KeyInfoX509Data implementation for XML Signature -// -// Authors: -// Sebastien Pouliot <sebastien@ximian.com> -// Atsushi Enomoto (atsushi@ximian.com) -// Tim Coleman (tim@timcoleman.com) -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) Tim Coleman, 2004 -// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.Collections; -using System.Runtime.InteropServices; -using System.Security.Cryptography.X509Certificates; -using System.Xml; - -namespace System.Security.Cryptography.Xml { - - public class KeyInfoX509Data : KeyInfoClause { - - private byte[] x509crl; - private ArrayList IssuerSerialList; - private ArrayList SubjectKeyIdList; - private ArrayList SubjectNameList; - private ArrayList X509CertificateList; - - public KeyInfoX509Data () - { - } - - public KeyInfoX509Data (byte[] rgbCert) - { - AddCertificate (new X509Certificate (rgbCert)); - } - - public KeyInfoX509Data (X509Certificate cert) - { - AddCertificate (cert); - } - -#if SECURITY_DEP - public KeyInfoX509Data (X509Certificate cert, X509IncludeOption includeOption) - { - if (cert == null) - throw new ArgumentNullException ("cert"); - - switch (includeOption) { - case X509IncludeOption.None: - case X509IncludeOption.EndCertOnly: - AddCertificate (cert); - break; - case X509IncludeOption.ExcludeRoot: - AddCertificatesChainFrom (cert, false); - break; - case X509IncludeOption.WholeChain: - AddCertificatesChainFrom (cert, true); - break; - } - } - - // this gets complicated because we must: - // 1. build the chain using a X509Certificate2 class; - // 2. test for root using the Mono.Security.X509.X509Certificate class; - // 3. add the certificates as X509Certificate instances; - private void AddCertificatesChainFrom (X509Certificate cert, bool root) - { - X509Chain chain = new X509Chain (); - chain.Build (new X509Certificate2 (cert)); - foreach (X509ChainElement ce in chain.ChainElements) { - byte[] rawdata = ce.Certificate.RawData; - if (!root) { - // exclude root - Mono.Security.X509.X509Certificate mx = new Mono.Security.X509.X509Certificate (rawdata); - if (mx.IsSelfSigned) - rawdata = null; - } - - if (rawdata != null) - AddCertificate (new X509Certificate (rawdata)); - } - } -#endif - - public ArrayList Certificates { - get { return X509CertificateList; } - } - - public byte[] CRL { - get { return x509crl; } - set { x509crl = value; } - } - - public ArrayList IssuerSerials { - get { return IssuerSerialList; } - } - - public ArrayList SubjectKeyIds { - get { return SubjectKeyIdList; } - } - - public ArrayList SubjectNames { - get { return SubjectNameList; } - } - - public void AddCertificate (X509Certificate certificate) - { - if (certificate == null) - throw new ArgumentNullException ("certificate"); - if (X509CertificateList == null) - X509CertificateList = new ArrayList (); - X509CertificateList.Add (certificate); - } - - public void AddIssuerSerial (string issuerName, string serialNumber) - { - if (issuerName == null) - throw new ArgumentException ("issuerName"); - if (IssuerSerialList == null) - IssuerSerialList = new ArrayList (); - - X509IssuerSerial xis = new X509IssuerSerial (issuerName, serialNumber); - IssuerSerialList.Add (xis); - } - - public void AddSubjectKeyId (byte[] subjectKeyId) - { - if (SubjectKeyIdList == null) - SubjectKeyIdList = new ArrayList (); - - SubjectKeyIdList.Add (subjectKeyId); - } - - [ComVisible (false)] - public void AddSubjectKeyId (string subjectKeyId) - { - if (SubjectKeyIdList == null) - SubjectKeyIdList = new ArrayList (); - - byte[] id = null; - if (subjectKeyId != null) - id = Convert.FromBase64String (subjectKeyId); - SubjectKeyIdList.Add (id); - } - - public void AddSubjectName (string subjectName) - { - if (SubjectNameList == null) - SubjectNameList = new ArrayList (); - - SubjectNameList.Add (subjectName); - } - - public override XmlElement GetXml () - { - XmlDocument document = new XmlDocument (); - XmlElement xel = document.CreateElement (XmlSignature.ElementNames.X509Data, XmlSignature.NamespaceURI); - // FIXME: hack to match MS implementation - xel.SetAttribute ("xmlns", XmlSignature.NamespaceURI); - // <X509IssuerSerial> - if ((IssuerSerialList != null) && (IssuerSerialList.Count > 0)) { - foreach (X509IssuerSerial iser in IssuerSerialList) { - XmlElement isl = document.CreateElement (XmlSignature.ElementNames.X509IssuerSerial, XmlSignature.NamespaceURI); - XmlElement xin = document.CreateElement (XmlSignature.ElementNames.X509IssuerName, XmlSignature.NamespaceURI); - xin.InnerText = iser.IssuerName; - isl.AppendChild (xin); - XmlElement xsn = document.CreateElement (XmlSignature.ElementNames.X509SerialNumber, XmlSignature.NamespaceURI); - xsn.InnerText = iser.SerialNumber; - isl.AppendChild (xsn); - xel.AppendChild (isl); - } - } - // <X509SKI> - if ((SubjectKeyIdList != null) && (SubjectKeyIdList.Count > 0)) { - foreach (byte[] skid in SubjectKeyIdList) { - XmlElement ski = document.CreateElement (XmlSignature.ElementNames.X509SKI, XmlSignature.NamespaceURI); - ski.InnerText = Convert.ToBase64String (skid); - xel.AppendChild (ski); - } - } - // <X509SubjectName> - if ((SubjectNameList != null) && (SubjectNameList.Count > 0)) { - foreach (string subject in SubjectNameList) { - XmlElement sn = document.CreateElement (XmlSignature.ElementNames.X509SubjectName, XmlSignature.NamespaceURI); - sn.InnerText = subject; - xel.AppendChild (sn); - } - } - // <X509Certificate> - if ((X509CertificateList != null) && (X509CertificateList.Count > 0)) { - foreach (X509Certificate x509 in X509CertificateList) { - XmlElement cert = document.CreateElement (XmlSignature.ElementNames.X509Certificate, XmlSignature.NamespaceURI); - cert.InnerText = Convert.ToBase64String (x509.GetRawCertData ()); - xel.AppendChild (cert); - } - } - // only one <X509CRL> - if (x509crl != null) { - XmlElement crl = document.CreateElement (XmlSignature.ElementNames.X509CRL, XmlSignature.NamespaceURI); - crl.InnerText = Convert.ToBase64String (x509crl); - xel.AppendChild (crl); - } - return xel; - } - - public override void LoadXml (XmlElement element) - { - if (element == null) - throw new ArgumentNullException ("element"); - - if (IssuerSerialList != null) - IssuerSerialList.Clear (); - if (SubjectKeyIdList != null) - SubjectKeyIdList.Clear (); - if (SubjectNameList != null) - SubjectNameList.Clear (); - if (X509CertificateList != null) - X509CertificateList.Clear (); - x509crl = null; - - if ((element.LocalName != XmlSignature.ElementNames.X509Data) || (element.NamespaceURI != XmlSignature.NamespaceURI)) - throw new CryptographicException ("element"); - - XmlElement [] xnl = null; - // <X509IssuerSerial> - xnl = XmlSignature.GetChildElements (element, XmlSignature.ElementNames.X509IssuerSerial); - if (xnl != null) { - for (int i=0; i < xnl.Length; i++) { - XmlElement xel = (XmlElement) xnl[i]; - XmlElement issuer = XmlSignature.GetChildElement (xel, XmlSignature.ElementNames.X509IssuerName, XmlSignature.NamespaceURI); - XmlElement serial = XmlSignature.GetChildElement (xel, XmlSignature.ElementNames.X509SerialNumber, XmlSignature.NamespaceURI); - AddIssuerSerial (issuer.InnerText, serial.InnerText); - } - } - // <X509SKI> - xnl = XmlSignature.GetChildElements (element, XmlSignature.ElementNames.X509SKI); - if (xnl != null) { - for (int i=0; i < xnl.Length; i++) { - byte[] skid = Convert.FromBase64String (xnl[i].InnerXml); - AddSubjectKeyId (skid); - } - } - // <X509SubjectName> - xnl = XmlSignature.GetChildElements (element, XmlSignature.ElementNames.X509SubjectName); - if (xnl != null) { - for (int i=0; i < xnl.Length; i++) { - AddSubjectName (xnl[i].InnerXml); - } - } - // <X509Certificate> - xnl = XmlSignature.GetChildElements (element, XmlSignature.ElementNames.X509Certificate); - if (xnl != null) { - for (int i=0; i < xnl.Length; i++) { - byte[] cert = Convert.FromBase64String (xnl[i].InnerXml); - AddCertificate (new X509Certificate (cert)); - } - } - // only one <X509CRL> - XmlElement x509el = XmlSignature.GetChildElement (element, XmlSignature.ElementNames.X509CRL, XmlSignature.NamespaceURI); - if (x509el != null) { - x509crl = Convert.FromBase64String (x509el.InnerXml); - } - } - } -} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/Manifest.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/Manifest.cs deleted file mode 100644 index d52ea001d43..00000000000 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/Manifest.cs +++ /dev/null @@ -1,119 +0,0 @@ -// -// Manifest.cs - Manifest implementation for XML Signature -// -// Author: -// Sebastien Pouliot <sebastien@ximian.com> -// -// (C) 2004 Novell (http://www.novell.com) -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.Collections; -using System.Xml; - -namespace System.Security.Cryptography.Xml { - - internal class Manifest { - - private ArrayList references; - private string id; - private XmlElement element; - - public Manifest () - { - references = new ArrayList (); - } - - public Manifest (XmlElement xel) : this () - { - LoadXml (xel); - } - - public string Id { - get { return id; } - set { - element = null; - id = value; - } - } - - public ArrayList References { - get { return references; } - } - - public void AddReference (Reference reference) - { - references.Add (reference); - } - - public XmlElement GetXml () - { - if (element != null) - return element; - - XmlDocument document = new XmlDocument (); - XmlElement xel = document.CreateElement (XmlSignature.ElementNames.SignedInfo, XmlSignature.NamespaceURI); - if (id != null) - xel.SetAttribute (XmlSignature.AttributeNames.Id, id); - - // we add References afterward so we don't end up with extraneous - // xmlns="..." in each reference elements. - foreach (Reference r in references) { - XmlNode xn = r.GetXml (); - XmlNode newNode = document.ImportNode (xn, true); - xel.AppendChild (newNode); - } - - return xel; - } - - private string GetAttribute (XmlElement xel, string attribute) - { - XmlAttribute xa = xel.Attributes [attribute]; - return ((xa != null) ? xa.InnerText : null); - } - - public void LoadXml (XmlElement value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - if ((value.LocalName != XmlSignature.ElementNames.Manifest) || (value.NamespaceURI != XmlSignature.NamespaceURI)) - throw new CryptographicException (); - - id = GetAttribute (value, XmlSignature.AttributeNames.Id); - - for (int i = 0; i < value.ChildNodes.Count; i++) { - XmlNode n = value.ChildNodes [i]; - if (n.NodeType == XmlNodeType.Element && - n.LocalName == XmlSignature.ElementNames.Reference && - n.NamespaceURI == XmlSignature.NamespaceURI) { - Reference r = new Reference (); - r.LoadXml ((XmlElement) n); - AddReference (r); - } - } - element = value; - } - } -} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/Signature.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/Signature.cs deleted file mode 100644 index 49e9d3ad991..00000000000 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/Signature.cs +++ /dev/null @@ -1,221 +0,0 @@ -// -// Signature.cs - Signature implementation for XML Signature -// -// Author: -// Sebastien Pouliot (spouliot@motus.com) -// Tim Coleman (tim@timcoleman.com) -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) Tim Coleman, 2004 -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.Collections; -using System.Security.Cryptography; -using System.Xml; - -namespace System.Security.Cryptography.Xml { - - public class Signature { - static XmlNamespaceManager dsigNsmgr; - - static Signature () - { - dsigNsmgr = new XmlNamespaceManager (new NameTable ()); - dsigNsmgr.AddNamespace ("xd", XmlSignature.NamespaceURI); - } - - private ArrayList list; - private SignedInfo info; - private KeyInfo key; - private string id; - private byte[] signature; - private XmlElement element; - - public Signature () - { - list = new ArrayList (); - } - - public string Id { - get { return id; } - set { - element = null; - id = value; - } - } - - public KeyInfo KeyInfo { - get { return key; } - set { - element = null; - key = value; - } - } - - public IList ObjectList { - get { return list; } - set { list = ArrayList.Adapter (value); } - } - - public byte[] SignatureValue { - get { return signature; } - set { - element = null; - signature = value; - } - } - - public SignedInfo SignedInfo { - get { return info; } - set { - element = null; - info = value; - } - } - - public void AddObject (DataObject dataObject) - { - list.Add (dataObject); - } - - public XmlElement GetXml () - { - return GetXml (null); - } - - internal XmlElement GetXml (XmlDocument document) - { - if (element != null) - return element; - - if (info == null) - throw new CryptographicException ("SignedInfo"); - if (signature == null) - throw new CryptographicException ("SignatureValue"); - - if (document == null) - document = new XmlDocument (); - - XmlElement xel = document.CreateElement (XmlSignature.ElementNames.Signature, XmlSignature.NamespaceURI); - if (id != null) - xel.SetAttribute (XmlSignature.AttributeNames.Id, id); - - XmlNode xn = info.GetXml (); - XmlNode newNode = document.ImportNode (xn, true); - xel.AppendChild (newNode); - - if (signature != null) { - XmlElement sv = document.CreateElement (XmlSignature.ElementNames.SignatureValue, XmlSignature.NamespaceURI); - sv.InnerText = Convert.ToBase64String (signature); - xel.AppendChild (sv); - } - - if (key != null) { - xn = key.GetXml (); - newNode = document.ImportNode (xn, true); - xel.AppendChild (newNode); - } - - if (list.Count > 0) { - foreach (DataObject obj in list) { - xn = obj.GetXml (); - newNode = document.ImportNode (xn, true); - xel.AppendChild (newNode); - } - } - - return xel; - } - - private string GetAttribute (XmlElement xel, string attribute) - { - XmlAttribute xa = xel.Attributes [attribute]; - return ((xa != null) ? xa.InnerText : null); - } - - public void LoadXml (XmlElement value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - if ((value.LocalName == XmlSignature.ElementNames.Signature) && (value.NamespaceURI == XmlSignature.NamespaceURI)) { - id = GetAttribute (value, XmlSignature.AttributeNames.Id); - - // LAMESPEC: This library is totally useless against eXtensibly Marked-up document. - int i = NextElementPos (value.ChildNodes, 0, XmlSignature.ElementNames.SignedInfo, XmlSignature.NamespaceURI, true); - XmlElement sinfo = (XmlElement) value.ChildNodes [i]; - info = new SignedInfo (); - info.LoadXml (sinfo); - - i = NextElementPos (value.ChildNodes, ++i, XmlSignature.ElementNames.SignatureValue, XmlSignature.NamespaceURI, true); - XmlElement sigValue = (XmlElement) value.ChildNodes [i]; - signature = Convert.FromBase64String (sigValue.InnerText); - - // signature isn't required: <element ref="ds:KeyInfo" minOccurs="0"/> - i = NextElementPos (value.ChildNodes, ++i, XmlSignature.ElementNames.KeyInfo, XmlSignature.NamespaceURI, false); - if (i > 0) { - XmlElement kinfo = (XmlElement) value.ChildNodes [i]; - key = new KeyInfo (); - key.LoadXml (kinfo); - } - - XmlNodeList xnl = value.SelectNodes ("xd:Object", dsigNsmgr); - foreach (XmlElement xn in xnl) { - DataObject obj = new DataObject (); - obj.LoadXml (xn); - AddObject (obj); - } - } - else - throw new CryptographicException ("Malformed element: Signature."); - - // if invalid - if (info == null) - throw new CryptographicException ("SignedInfo"); - if (signature == null) - throw new CryptographicException ("SignatureValue"); - } - - private int NextElementPos (XmlNodeList nl, int pos, string name, string ns, bool required) - { - while (pos < nl.Count) { - if (nl [pos].NodeType == XmlNodeType.Element) { - if (nl [pos].LocalName != name || nl [pos].NamespaceURI != ns) { - if (required) - throw new CryptographicException ("Malformed element " + name); - else - return -2; - } - else - return pos; - } - else - pos++; - } - if (required) - throw new CryptographicException ("Malformed element " + name); - return -1; - } - } -} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedInfo.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedInfo.cs deleted file mode 100644 index f9d6d9f0048..00000000000 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedInfo.cs +++ /dev/null @@ -1,219 +0,0 @@ -// -// SignedInfo.cs - SignedInfo implementation for XML Signature -// -// Author: -// Sebastien Pouliot <sebastien@ximian.com> -// Tim Coleman (tim@timcoleman.com) -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) Tim Coleman, 2004 -// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System.Collections; -using System.Runtime.InteropServices; -using System.Xml; - -namespace System.Security.Cryptography.Xml { - - public class SignedInfo : ICollection, IEnumerable { - - private ArrayList references; - private string c14nMethod; - private string id; - private string signatureMethod; - private string signatureLength; - private XmlElement element; - - public SignedInfo() - { - references = new ArrayList (); - c14nMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; - } - - public string CanonicalizationMethod { - get { return c14nMethod; } - set { - c14nMethod = value; - element = null; - } - } - - [ComVisible (false)] - [MonoTODO] - public Transform CanonicalizationMethodObject { - get { throw new NotImplementedException (); } - } - - // documented as not supported (and throwing exception) - public int Count { - get { throw new NotSupportedException (); } - } - - public string Id { - get { return id; } - set { - element = null; - id = value; - } - } - - // documented as not supported (and throwing exception) - public bool IsReadOnly { - get { throw new NotSupportedException (); } - } - - // documented as not supported (and throwing exception) - public bool IsSynchronized { - get { throw new NotSupportedException (); } - } - - // Manipulating this array never affects GetXml() when - // LoadXml() was used. - // (Actually, there is no way to detect modification.) - public ArrayList References { - get { return references; } - } - - public string SignatureLength { - get { return signatureLength; } - set { - element = null; - signatureLength = value; - } - } - - public string SignatureMethod { - get { return signatureMethod; } - set { - element = null; - signatureMethod = value; - } - } - - // documented as not supported (and throwing exception) - public object SyncRoot { - get { throw new NotSupportedException (); } - } - - public void AddReference (Reference reference) - { - references.Add (reference); - } - - // documented as not supported (and throwing exception) - public void CopyTo (Array array, int index) - { - throw new NotSupportedException (); - } - - public IEnumerator GetEnumerator () - { - return references.GetEnumerator (); - } - - public XmlElement GetXml () - { - if (element != null) - return element; - - if (signatureMethod == null) - throw new CryptographicException ("SignatureMethod"); - if (references.Count == 0) - throw new CryptographicException ("References empty"); - - XmlDocument document = new XmlDocument (); - XmlElement xel = document.CreateElement (XmlSignature.ElementNames.SignedInfo, XmlSignature.NamespaceURI); - if (id != null) - xel.SetAttribute (XmlSignature.AttributeNames.Id, id); - - if (c14nMethod != null) { - XmlElement c14n = document.CreateElement (XmlSignature.ElementNames.CanonicalizationMethod, XmlSignature.NamespaceURI); - c14n.SetAttribute (XmlSignature.AttributeNames.Algorithm, c14nMethod); - xel.AppendChild (c14n); - } - if (signatureMethod != null) { - XmlElement sm = document.CreateElement (XmlSignature.ElementNames.SignatureMethod, XmlSignature.NamespaceURI); - sm.SetAttribute (XmlSignature.AttributeNames.Algorithm, signatureMethod); - if (signatureLength != null) { - XmlElement hmac = document.CreateElement (XmlSignature.ElementNames.HMACOutputLength, XmlSignature.NamespaceURI); - hmac.InnerText = signatureLength; - sm.AppendChild (hmac); - } - xel.AppendChild (sm); - } - - // This check is only done when element is created here. - if (references.Count == 0) - throw new CryptographicException ("At least one Reference element is required in SignedInfo."); - - // we add References afterward so we don't end up with extraneous - // xmlns="..." in each reference elements. - foreach (Reference r in references) { - XmlNode xn = r.GetXml (); - XmlNode newNode = document.ImportNode (xn, true); - xel.AppendChild (newNode); - } - - return xel; - } - - private string GetAttribute (XmlElement xel, string attribute) - { - XmlAttribute xa = xel.Attributes [attribute]; - return ((xa != null) ? xa.InnerText : null); - } - - public void LoadXml (XmlElement value) - { - if (value == null) - throw new ArgumentNullException ("value"); - - if ((value.LocalName != XmlSignature.ElementNames.SignedInfo) || (value.NamespaceURI != XmlSignature.NamespaceURI)) - throw new CryptographicException (); - - id = GetAttribute (value, XmlSignature.AttributeNames.Id); - c14nMethod = XmlSignature.GetAttributeFromElement (value, XmlSignature.AttributeNames.Algorithm, XmlSignature.ElementNames.CanonicalizationMethod); - - XmlElement sm = XmlSignature.GetChildElement (value, XmlSignature.ElementNames.SignatureMethod, XmlSignature.NamespaceURI); - if (sm != null) { - signatureMethod = sm.GetAttribute (XmlSignature.AttributeNames.Algorithm); - XmlElement length = XmlSignature.GetChildElement (sm, XmlSignature.ElementNames.HMACOutputLength, XmlSignature.NamespaceURI); - if (length != null) { - signatureLength = length.InnerText; - } - } - - for (int i = 0; i < value.ChildNodes.Count; i++) { - XmlNode n = value.ChildNodes [i]; - if (n.NodeType == XmlNodeType.Element && - n.LocalName == XmlSignature.ElementNames.Reference && - n.NamespaceURI == XmlSignature.NamespaceURI) { - Reference r = new Reference (); - r.LoadXml ((XmlElement) n); - AddReference (r); - } - } - element = value; - } - } -} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedXml.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedXml.cs index 958f9138365..15e50ca5fcf 100644 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedXml.cs +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedXml.cs @@ -1,48 +1,57 @@ -// -// SignedXml.cs - SignedXml implementation for XML Signature -// -// Author: -// Sebastien Pouliot <sebastien@ximian.com> -// Atsushi Enomoto <atsushi@ximian.com> -// Tim Coleman <tim@timcoleman.com> -// -// (C) 2002, 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) Tim Coleman, 2004 -// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. using System.Collections; -using System.IO; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Security.Policy; -using System.Net; -using System.Text; -using System.Xml; using System.Security.Cryptography.X509Certificates; +using System.Xml; namespace System.Security.Cryptography.Xml { - public class SignedXml { + /// <internalonly /> + protected Signature m_signature; + /// <internalonly /> + protected string m_strSigningKeyName; + + private AsymmetricAlgorithm _signingKey; + private XmlDocument _containingDocument; + private IEnumerator _keyInfoEnum; + private X509Certificate2Collection _x509Collection; + private IEnumerator _x509Enum; + + private bool[] _refProcessed; + private int[] _refLevelCache; + + internal XmlResolver _xmlResolver; + internal XmlElement _context; + private bool _bResolverSet; + + private Func<SignedXml, bool> _signatureFormatValidator = DefaultSignatureFormatValidator; + private Collection<string> _safeCanonicalizationMethods; + + // Built in canonicalization algorithm URIs + private static IList<string> s_knownCanonicalizationMethods; + // Built in transform algorithm URIs (excluding canonicalization URIs) + private static IList<string> s_defaultSafeTransformMethods; + + // additional HMAC Url identifiers + private const string XmlDsigMoreHMACMD5Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-md5"; + private const string XmlDsigMoreHMACSHA256Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; + private const string XmlDsigMoreHMACSHA384Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384"; + private const string XmlDsigMoreHMACSHA512Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"; + private const string XmlDsigMoreHMACRIPEMD160Url = "http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160"; + + // defines the XML encryption processing rules + private EncryptedXml _exml; + + // + // public constant Url identifiers most frequently used within the XML Signature classes + // + public const string XmlDsigNamespaceUrl = "http://www.w3.org/2000/09/xmldsig#"; public const string XmlDsigMinimalCanonicalizationUrl = "http://www.w3.org/2000/09/xmldsig#minimal"; public const string XmlDsigCanonicalizationUrl = XmlDsigC14NTransformUrl; @@ -63,6 +72,9 @@ namespace System.Security.Cryptography.Xml { public const string XmlDsigSHA512Url = "http://www.w3.org/2001/04/xmlenc#sha512"; public const string XmlDsigRSASHA512Url = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"; + internal static readonly string XmlDsigDigestDefault = XmlDsigSHA256Url; + internal static readonly string XmlDsigRSADefault = XmlDsigRSASHA256Url; + public const string XmlDsigC14NTransformUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; public const string XmlDsigC14NWithCommentsTransformUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"; public const string XmlDsigExcC14NTransformUrl = "http://www.w3.org/2001/10/xml-exc-c14n#"; @@ -74,91 +86,50 @@ namespace System.Security.Cryptography.Xml { public const string XmlDecryptionTransformUrl = "http://www.w3.org/2002/07/decrypt#XML"; public const string XmlLicenseTransformUrl = "urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform"; - private EncryptedXml encryptedXml; - - protected Signature m_signature; - private AsymmetricAlgorithm key; - protected string m_strSigningKeyName; - private XmlDocument envdoc; - private IEnumerator pkEnumerator; - private XmlElement signatureElement; - private Hashtable hashes; - // FIXME: enable it after CAS implementation - internal XmlResolver _xmlResolver = new XmlUrlResolver (); - private bool _bResolverSet = true; - internal XmlElement _context; - private ArrayList manifests; - private IEnumerator _x509Enumerator; - - private static readonly char [] whitespaceChars = new char [] {' ', '\r', '\n', '\t'}; + // + // public constructors + // public SignedXml () { - m_signature = new Signature (); - m_signature.SignedInfo = new SignedInfo (); - hashes = new Hashtable (2); // 98% SHA1 for now - _context = null; + Initialize (null); } - public SignedXml (XmlDocument document) : this () + public SignedXml (XmlDocument document) { if (document == null) - throw new ArgumentNullException ("document"); - envdoc = document; - _context = document.DocumentElement; + throw new ArgumentNullException (nameof (document)); + + Initialize (document.DocumentElement); } - public SignedXml (XmlElement elem) : this () + public SignedXml (XmlElement elem) { if (elem == null) - throw new ArgumentNullException ("elem"); - envdoc = new XmlDocument (); - _context = elem; - envdoc.LoadXml (elem.OuterXml); - } - - [ComVisible (false)] - public EncryptedXml EncryptedXml { - get { return encryptedXml; } - set { encryptedXml = value; } - } - - public KeyInfo KeyInfo { - get { - if (m_signature.KeyInfo == null) - m_signature.KeyInfo = new KeyInfo (); - return m_signature.KeyInfo; - } - set { m_signature.KeyInfo = value; } - } - - public Signature Signature { - get { return m_signature; } - } - - public string SignatureLength { - get { return m_signature.SignedInfo.SignatureLength; } + throw new ArgumentNullException (nameof (elem)); + + Initialize (elem); } - public string SignatureMethod { - get { return m_signature.SignedInfo.SignatureMethod; } - } + private void Initialize (XmlElement element) + { + _containingDocument = (element == null ? null : element.OwnerDocument); + _context = element; + m_signature = new Signature (); + m_signature.SignedXml = this; + m_signature.SignedInfo = new SignedInfo (); + _signingKey = null; - public byte[] SignatureValue { - get { return m_signature.SignatureValue; } + _safeCanonicalizationMethods = new Collection<string> (KnownCanonicalizationMethods); } - public SignedInfo SignedInfo { - get { return m_signature.SignedInfo; } - } + // + // public properties + // - public AsymmetricAlgorithm SigningKey { - get { return key; } - set { key = value; } - } - - // NOTE: CryptoAPI related ? documented as fx internal - public string SigningKeyName { + /// <internalonly /> + public string SigningKeyName + { get { return m_strSigningKeyName; } set { m_strSigningKeyName = value; } } @@ -179,483 +150,221 @@ namespace System.Security.Cryptography.Xml { get { return _bResolverSet; } } - public void AddObject (DataObject dataObject) + public Func<SignedXml, bool> SignatureFormatValidator { - m_signature.AddObject (dataObject); + get { return _signatureFormatValidator; } + set { _signatureFormatValidator = value; } } - public void AddReference (Reference reference) + public Collection<string> SafeCanonicalizationMethods { - if (reference == null) - throw new ArgumentNullException ("reference"); - m_signature.SignedInfo.AddReference (reference); + get { return _safeCanonicalizationMethods; } } - private Stream ApplyTransform (Transform t, XmlDocument input) + public AsymmetricAlgorithm SigningKey { - // These transformer modify input document, which should - // not affect to the input itself. - if (t is XmlDsigXPathTransform - || t is XmlDsigEnvelopedSignatureTransform - || t is XmlDecryptionTransform - ) - input = (XmlDocument) input.Clone (); - - t.LoadInput (input); - - if (t is XmlDsigEnvelopedSignatureTransform) - // It returns XmlDocument for XmlDocument input. - return CanonicalizeOutput (t.GetOutput ()); - - object obj = t.GetOutput (); - if (obj is Stream) - return (Stream) obj; - else if (obj is XmlDocument) { - MemoryStream ms = new MemoryStream (); - XmlTextWriter xtw = new XmlTextWriter (ms, Encoding.UTF8); - ((XmlDocument) obj).WriteTo (xtw); - - xtw.Flush (); + get { return _signingKey; } + set { _signingKey = value; } + } - // Rewind to the start of the stream - ms.Position = 0; - return ms; - } - else if (obj == null) { - throw new NotImplementedException ("This should not occur. Transform is " + t + "."); - } - else { - // e.g. XmlDsigXPathTransform returns XmlNodeList - return CanonicalizeOutput (obj); + public EncryptedXml EncryptedXml + { + get + { + if (_exml == null) + _exml = new EncryptedXml (_containingDocument); // default processing rules + + return _exml; } + + set { _exml = value; } } - private Stream CanonicalizeOutput (object obj) + public Signature Signature { - Transform c14n = GetC14NMethod (); - c14n.LoadInput (obj); - return (Stream) c14n.GetOutput (); + get { return m_signature; } } - private XmlDocument GetManifest (Reference r) + public SignedInfo SignedInfo { - XmlDocument doc = new XmlDocument (); - doc.PreserveWhitespace = true; - - if (r.Uri [0] == '#') { - // local manifest - if (signatureElement != null) { - XmlElement xel = GetIdElement (signatureElement.OwnerDocument, r.Uri.Substring (1)); - if (xel == null) - throw new CryptographicException ("Manifest targeted by Reference was not found: " + r.Uri.Substring (1)); - doc.AppendChild (doc.ImportNode (xel, true)); - FixupNamespaceNodes (xel, doc.DocumentElement, false); - } - } - else if (_xmlResolver != null) { - // TODO: need testing - Stream s = (Stream) _xmlResolver.GetEntity (new Uri (r.Uri), null, typeof (Stream)); - doc.Load (s); - } - - if (doc.FirstChild != null) { - // keep a copy of the manifests to check their references later - if (manifests == null) - manifests = new ArrayList (); - manifests.Add (doc); - - return doc; - } - return null; + get { return m_signature.SignedInfo; } } - private void FixupNamespaceNodes (XmlElement src, XmlElement dst, bool ignoreDefault) + public string SignatureMethod { - // add namespace nodes - foreach (XmlAttribute attr in src.SelectNodes ("namespace::*")) { - if (attr.LocalName == "xml") - continue; - if (ignoreDefault && attr.LocalName == "xmlns") - continue; - dst.SetAttributeNode (dst.OwnerDocument.ImportNode (attr, true) as XmlAttribute); - } + get { return m_signature.SignedInfo.SignatureMethod; } } - private byte[] GetReferenceHash (Reference r, bool check_hmac) + public string SignatureLength { - Stream s = null; - XmlDocument doc = null; - if (r.Uri == String.Empty) { - doc = envdoc; - } - else if (r.Type == XmlSignature.Uri.Manifest) { - doc = GetManifest (r); - } - else { - doc = new XmlDocument (); - doc.PreserveWhitespace = true; - string objectName = null; - - if (r.Uri.StartsWith ("#xpointer")) { - string uri = string.Join ("", r.Uri.Substring (9).Split (whitespaceChars)); - if (uri.Length < 2 || uri [0] != '(' || uri [uri.Length - 1] != ')') - // FIXME: how to handle invalid xpointer? - uri = String.Empty; - else - uri = uri.Substring (1, uri.Length - 2); - if (uri == "/") - doc = envdoc; - else if (uri.Length > 6 && uri.StartsWith ("id(") && uri [uri.Length - 1] == ')') - // id('foo'), id("foo") - objectName = uri.Substring (4, uri.Length - 6); - } - else if (r.Uri [0] == '#') { - objectName = r.Uri.Substring (1); - } - else if (_xmlResolver != null) { - // TODO: test but doc says that Resolver = null -> no access - try { - // no way to know if valid without throwing an exception - Uri uri = new Uri (r.Uri); - s = (Stream) _xmlResolver.GetEntity (uri, null, typeof (Stream)); - } - catch { - // may still be a local file (and maybe not xml) - s = File.OpenRead (r.Uri); - } - } - if (objectName != null) { - XmlElement found = null; - foreach (DataObject obj in m_signature.ObjectList) { - if (obj.Id == objectName) { - found = obj.GetXml (); - found.SetAttribute ("xmlns", SignedXml.XmlDsigNamespaceUrl); - doc.AppendChild (doc.ImportNode (found, true)); - // FIXME: there should be theoretical justification of copying namespace declaration nodes this way. - foreach (XmlNode n in found.ChildNodes) - // Do not copy default namespace as it must be xmldsig namespace for "Object" element. - if (n.NodeType == XmlNodeType.Element) - FixupNamespaceNodes (n as XmlElement, doc.DocumentElement, true); - break; - } - } - if (found == null && envdoc != null) { - found = GetIdElement (envdoc, objectName); - if (found != null) { - doc.AppendChild (doc.ImportNode (found, true)); - FixupNamespaceNodes (found, doc.DocumentElement, false); - } - } - if (found == null) - throw new CryptographicException (String.Format ("Malformed reference object: {0}", objectName)); - } - } - - if (r.TransformChain.Count > 0) { - foreach (Transform t in r.TransformChain) { - if (s == null) { - s = ApplyTransform (t, doc); - } - else { - t.LoadInput (s); - object o = t.GetOutput (); - if (o is Stream) - s = (Stream) o; - else - s = CanonicalizeOutput (o); - } - } - } - else if (s == null) { - // we must not C14N references from outside the document - // e.g. non-xml documents - if (r.Uri [0] != '#') { - s = new MemoryStream (); - doc.Save (s); - } - else { - // apply default C14N transformation - s = ApplyTransform (new XmlDsigC14NTransform (), doc); - } - } - HashAlgorithm digest = GetHash (r.DigestMethod, check_hmac); - return (digest == null) ? null : digest.ComputeHash (s); + get { return m_signature.SignedInfo.SignatureLength; } } - private void DigestReferences () + public byte[] SignatureValue { - // we must tell each reference which hash algorithm to use - // before asking for the SignedInfo XML ! - foreach (Reference r in m_signature.SignedInfo.References) { - // assume SHA-1 if nothing is specified - if (r.DigestMethod == null) - r.DigestMethod = XmlDsigSHA1Url; - r.DigestValue = GetReferenceHash (r, false); - } + get { return m_signature.SignatureValue; } } - private Transform GetC14NMethod () + public KeyInfo KeyInfo { - Transform t = (Transform) CryptoConfig.CreateFromName (m_signature.SignedInfo.CanonicalizationMethod); - if (t == null) - throw new CryptographicException ("Unknown Canonicalization Method {0}", m_signature.SignedInfo.CanonicalizationMethod); - return t; + get { return m_signature.KeyInfo; } + set { m_signature.KeyInfo = value; } } - private Stream SignedInfoTransformed () + public XmlElement GetXml () { - Transform t = GetC14NMethod (); + // If we have a document context, then return a signature element in this context + if (_containingDocument != null) + return m_signature.GetXml (_containingDocument); + else + return m_signature.GetXml (); + } - if (signatureElement == null) { - // when creating signatures - XmlDocument doc = new XmlDocument (); - doc.PreserveWhitespace = true; - doc.LoadXml (m_signature.SignedInfo.GetXml ().OuterXml); - if (envdoc != null) - foreach (XmlAttribute attr in envdoc.DocumentElement.SelectNodes ("namespace::*")) { - if (attr.LocalName == "xml") - continue; - if (attr.Prefix == doc.DocumentElement.Prefix) - continue; - doc.DocumentElement.SetAttributeNode (doc.ImportNode (attr, true) as XmlAttribute); - } - t.LoadInput (doc); - } - else { - // when verifying signatures - // TODO - check m_signature.SignedInfo.Id - XmlElement el = signatureElement.GetElementsByTagName (XmlSignature.ElementNames.SignedInfo, XmlSignature.NamespaceURI) [0] as XmlElement; - StringWriter sw = new StringWriter (); - XmlTextWriter xtw = new XmlTextWriter (sw); - xtw.WriteStartElement (el.Prefix, el.LocalName, el.NamespaceURI); - - // context namespace nodes (except for "xmlns:xml") - XmlNodeList nl = el.SelectNodes ("namespace::*"); - foreach (XmlAttribute attr in nl) { - if (attr.ParentNode == el) - continue; - if (attr.LocalName == "xml") - continue; - if (attr.Prefix == el.Prefix) - continue; - attr.WriteTo (xtw); - } - foreach (XmlNode attr in el.Attributes) - attr.WriteTo (xtw); - foreach (XmlNode n in el.ChildNodes) - n.WriteTo (xtw); + public void LoadXml (XmlElement value) + { + if (value == null) + throw new ArgumentNullException (nameof (value)); - xtw.WriteEndElement (); - byte [] si = Encoding.UTF8.GetBytes (sw.ToString ()); + m_signature.LoadXml (value); - MemoryStream ms = new MemoryStream (); - ms.Write (si, 0, si.Length); - ms.Position = 0; + if (_context == null) + _context = value; - t.LoadInput (ms); - } - // C14N and C14NWithComments always return a Stream in GetOutput - return (Stream) t.GetOutput (); + _bCacheValid = false; } - // reuse hash - most document will always use the same hash - private HashAlgorithm GetHash (string algorithm, bool check_hmac) - { - HashAlgorithm hash = (HashAlgorithm) hashes [algorithm]; - if (hash == null) { - hash = HashAlgorithm.Create (algorithm); - if (hash == null) - throw new CryptographicException ("Unknown hash algorithm: {0}", algorithm); - hashes.Add (algorithm, hash); - // now ready to be used - } - else { - // important before reusing an hash object - hash.Initialize (); - } - // we can sign using any hash algorith, including HMAC, but we can only verify hash (MS compatibility) - if (check_hmac && (hash is KeyedHashAlgorithm)) - return null; - return hash; - } + // + // public methods + // - public bool CheckSignature () + public void AddReference (Reference reference) { - return (CheckSignatureInternal (null) != null); + m_signature.SignedInfo.AddReference (reference); } - private bool CheckReferenceIntegrity (ArrayList referenceList) + public void AddObject (DataObject dataObject) { - if (referenceList == null) - return false; - - // check digest (hash) for every reference - foreach (Reference r in referenceList) { - // stop at first broken reference - byte[] hash = GetReferenceHash (r, true); - if (! Compare (r.DigestValue, hash)) - return false; - } - return true; + m_signature.AddObject (dataObject); } - public bool CheckSignature (AsymmetricAlgorithm key) + public bool CheckSignature () { - if (key == null) - throw new ArgumentNullException ("key"); - return (CheckSignatureInternal (key) != null); + AsymmetricAlgorithm signingKey; + return CheckSignatureReturningKey (out signingKey); } - private AsymmetricAlgorithm CheckSignatureInternal (AsymmetricAlgorithm key) + public bool CheckSignatureReturningKey (out AsymmetricAlgorithm signingKey) { - pkEnumerator = null; + SignedXmlDebugLog.LogBeginSignatureVerification (this, _context); - if (key != null) { - // check with supplied key - if (!CheckSignatureWithKey (key)) - return null; - } else { - if (Signature.KeyInfo == null) - return null; - // no supplied key, iterates all KeyInfo - while ((key = GetPublicKey ()) != null) { - if (CheckSignatureWithKey (key)) { - break; - } - } - pkEnumerator = null; - if (key == null) - return null; - } + signingKey = null; + bool bRet = false; + AsymmetricAlgorithm key = null; - // some parts may need to be downloaded - // so where doing it last - if (!CheckReferenceIntegrity (m_signature.SignedInfo.References)) - return null; + if (!CheckSignatureFormat ()) + return false; - if (manifests != null) { - // do not use foreach as a manifest could contain manifests... - for (int i=0; i < manifests.Count; i++) { - Manifest manifest = new Manifest ((manifests [i] as XmlDocument).DocumentElement); - if (! CheckReferenceIntegrity (manifest.References)) - return null; + do { + key = GetPublicKey (); + if (key != null) { + bRet = CheckSignature (key); + SignedXmlDebugLog.LogVerificationResult (this, key, bRet); } - } - return key; + } while (key != null && bRet == false); + + signingKey = key; + return bRet; } - // Is the signature (over SignedInfo) valid ? - private bool CheckSignatureWithKey (AsymmetricAlgorithm key) + public bool CheckSignature (AsymmetricAlgorithm key) { - if (key == null) + if (!CheckSignatureFormat ()) return false; - SignatureDescription sd = (SignatureDescription) CryptoConfig.CreateFromName (m_signature.SignedInfo.SignatureMethod); - if (sd == null) + if (!CheckSignedInfo (key)) { + SignedXmlDebugLog.LogVerificationFailure (this, SR.Log_VerificationFailed_SignedInfo); return false; + } - AsymmetricSignatureDeformatter verifier = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName (sd.DeformatterAlgorithm); - if (verifier == null) + // Now is the time to go through all the references and see if their DigestValues are good + if (!CheckDigestedReferences ()) { + SignedXmlDebugLog.LogVerificationFailure (this, SR.Log_VerificationFailed_References); return false; + } - try { - verifier.SetKey (key); - verifier.SetHashAlgorithm (sd.DigestAlgorithm); + SignedXmlDebugLog.LogVerificationResult (this, key, true); + return true; + } - HashAlgorithm hash = GetHash (sd.DigestAlgorithm, true); - // get the hash of the C14N SignedInfo element - MemoryStream ms = (MemoryStream) SignedInfoTransformed (); + public bool CheckSignature (KeyedHashAlgorithm macAlg) + { + if (!CheckSignatureFormat ()) + return false; - byte[] digest = hash.ComputeHash (ms); - return verifier.VerifySignature (digest, m_signature.SignatureValue); + if (!CheckSignedInfo (macAlg)) { + SignedXmlDebugLog.LogVerificationFailure (this, SR.Log_VerificationFailed_SignedInfo); + return false; } - catch { - // e.g. SignatureMethod != AsymmetricAlgorithm type + + if (!CheckDigestedReferences ()) { + SignedXmlDebugLog.LogVerificationFailure (this, SR.Log_VerificationFailed_References); return false; - } + } + + SignedXmlDebugLog.LogVerificationResult (this, macAlg, true); + return true; } - private bool Compare (byte[] expected, byte[] actual) + public bool CheckSignature (X509Certificate2 certificate, bool verifySignatureOnly) { - bool result = ((expected != null) && (actual != null)); - if (result) { - int l = expected.Length; - result = (l == actual.Length); - if (result) { - for (int i=0; i < l; i++) { - if (expected[i] != actual[i]) + if (!verifySignatureOnly) { + // Check key usages to make sure it is good for signing. + foreach (X509Extension extension in certificate.Extensions) { + if (string.Compare (extension.Oid.Value, "2.5.29.15" /* szOID_KEY_USAGE */, StringComparison.OrdinalIgnoreCase) == 0) { + X509KeyUsageExtension keyUsage = new X509KeyUsageExtension (); + keyUsage.CopyFrom (extension); + SignedXmlDebugLog.LogVerifyKeyUsage (this, certificate, keyUsage); + + bool validKeyUsage = (keyUsage.KeyUsages & X509KeyUsageFlags.DigitalSignature) != 0 || + (keyUsage.KeyUsages & X509KeyUsageFlags.NonRepudiation) != 0; + + if (!validKeyUsage) { + SignedXmlDebugLog.LogVerificationFailure (this, SR.Log_VerificationFailed_X509KeyUsage); return false; + } + break; } } - } - return result; - } - public bool CheckSignature (KeyedHashAlgorithm macAlg) - { - if (macAlg == null) - throw new ArgumentNullException ("macAlg"); + // Do the chain verification to make sure the certificate is valid. + X509Chain chain = new X509Chain (); + chain.ChainPolicy.ExtraStore.AddRange (BuildBagOfCerts()); + bool chainVerified = chain.Build (certificate); + SignedXmlDebugLog.LogVerifyX509Chain (this, chain, certificate); - pkEnumerator = null; - - // Is the signature (over SignedInfo) valid ? - Stream s = SignedInfoTransformed (); - if (s == null) - return false; - - byte[] actual = macAlg.ComputeHash (s); - // HMAC signature may be partial and specified by <HMACOutputLength> - if (m_signature.SignedInfo.SignatureLength != null) { - int length = Int32.Parse (m_signature.SignedInfo.SignatureLength); - // we only support signatures with a multiple of 8 bits - // and the value must match the signature length - if ((length & 7) != 0) - throw new CryptographicException ("Signature length must be a multiple of 8 bits."); - - // SignatureLength is in bits (and we works on bytes, only in multiple of 8 bits) - // and both values must match for a signature to be valid - length >>= 3; - if (length != m_signature.SignatureValue.Length) - throw new CryptographicException ("Invalid signature length."); - - // is the length "big" enough to make the signature meaningful ? - // we use a minimum of 80 bits (10 bytes) or half the HMAC normal output length - // e.g. HMACMD5 output 128 bits but our minimum is 80 bits (not 64 bits) - int minimum = Math.Max (10, actual.Length / 2); - if (length < minimum) - throw new CryptographicException ("HMAC signature is too small"); - - if (length < actual.Length) { - byte[] trunked = new byte [length]; - Buffer.BlockCopy (actual, 0, trunked, 0, length); - actual = trunked; + if (!chainVerified) { + SignedXmlDebugLog.LogVerificationFailure (this, SR.Log_VerificationFailed_X509Chain); + return false; } } - if (Compare (m_signature.SignatureValue, actual)) { - // some parts may need to be downloaded - // so where doing it last - return CheckReferenceIntegrity (m_signature.SignedInfo.References); + using (AsymmetricAlgorithm publicKey = Utils.GetAnyPublicKey (certificate)) { + if (!CheckSignature (publicKey)) + return false; } - return false; - } - [MonoTODO] - [ComVisible (false)] - public bool CheckSignature (X509Certificate2 certificate, bool verifySignatureOnly) - { - throw new NotImplementedException (); + SignedXmlDebugLog.LogVerificationResult (this, certificate, true); + return true; } - public bool CheckSignatureReturningKey (out AsymmetricAlgorithm signingKey) + public void ComputeSignature () { - signingKey = CheckSignatureInternal (null); - return (signingKey != null); - } + SignedXmlDebugLog.LogBeginSignatureComputation (this, _context); - public void ComputeSignature () - { - DigestReferences (); + BuildDigestedReferences (); + + // Load the key + AsymmetricAlgorithm key = SigningKey; if (key == null) throw new CryptographicException (SR.Cryptography_Xml_LoadKeyFailed); @@ -665,86 +374,159 @@ namespace System.Security.Cryptography.Xml { if (key is DSA) { SignedInfo.SignatureMethod = XmlDsigDSAUrl; } else if (key is RSA) { - // Default to RSA-SHA1 - SignedInfo.SignatureMethod = XmlDsigRSASHA1Url; + if (SignedInfo.SignatureMethod == null) + SignedInfo.SignatureMethod = XmlDsigRSADefault; } else { throw new CryptographicException (SR.Cryptography_Xml_CreatedKeyFailed); } } // See if there is a signature description class defined in the Config file - SignatureDescription signatureDescription = CryptoConfig.CreateFromName (SignedInfo.SignatureMethod) as SignatureDescription; + SignatureDescription signatureDescription = CryptoHelpers.CreateFromName (SignedInfo.SignatureMethod) as SignatureDescription; if (signatureDescription == null) throw new CryptographicException (SR.Cryptography_Xml_SignatureDescriptionNotCreated); - HashAlgorithm hashAlg = signatureDescription.CreateDigest (); if (hashAlg == null) throw new CryptographicException (SR.Cryptography_Xml_CreateHashAlgorithmFailed); - - byte[] hashvalue = hashAlg.ComputeHash (SignedInfoTransformed ()); + byte[] hashvalue = GetC14NDigest (hashAlg); AsymmetricSignatureFormatter asymmetricSignatureFormatter = signatureDescription.CreateFormatter (key); + SignedXmlDebugLog.LogSigning (this, key, signatureDescription, hashAlg, asymmetricSignatureFormatter); m_signature.SignatureValue = asymmetricSignatureFormatter.CreateSignature (hashAlg); } - public void ComputeSignature (KeyedHashAlgorithm macAlg) + public void ComputeSignature (KeyedHashAlgorithm macAlg) { if (macAlg == null) - throw new ArgumentNullException ("macAlg"); - - string method = null; - - if (macAlg is HMACSHA1) { - method = XmlDsigHMACSHA1Url; - } else if (macAlg is HMACSHA256) { - method = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; - } else if (macAlg is HMACSHA384) { - method = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384"; - } else if (macAlg is HMACSHA512) { - method = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"; - } else if (macAlg is HMACRIPEMD160) { - method = "http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160"; + throw new ArgumentNullException (nameof (macAlg)); + + HMAC hash = macAlg as HMAC; + if (hash == null) + throw new CryptographicException (SR.Cryptography_Xml_SignatureMethodKeyMismatch); + + int signatureLength; + if (m_signature.SignedInfo.SignatureLength == null) + signatureLength = hash.HashSize; + else + signatureLength = Convert.ToInt32 (m_signature.SignedInfo.SignatureLength, null); + // signatureLength should be less than hash size + if (signatureLength < 0 || signatureLength > hash.HashSize) + throw new CryptographicException (SR.Cryptography_Xml_InvalidSignatureLength); + if (signatureLength % 8 != 0) + throw new CryptographicException (SR.Cryptography_Xml_InvalidSignatureLength2); + + BuildDigestedReferences (); + switch (hash.HashName) { + case "SHA1": + SignedInfo.SignatureMethod = SignedXml.XmlDsigHMACSHA1Url; + break; + case "SHA256": + SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA256Url; + break; + case "SHA384": + SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA384Url; + break; + case "SHA512": + SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACSHA512Url; + break; + case "MD5": + SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACMD5Url; + break; + case "RIPEMD160": + SignedInfo.SignatureMethod = SignedXml.XmlDsigMoreHMACRIPEMD160Url; + break; + default: + throw new CryptographicException (SR.Cryptography_Xml_SignatureMethodKeyMismatch); } - if (method == null) - throw new CryptographicException ("unsupported algorithm"); + byte[] hashValue = GetC14NDigest (hash); - DigestReferences (); - m_signature.SignedInfo.SignatureMethod = method; - m_signature.SignatureValue = macAlg.ComputeHash (SignedInfoTransformed ()); + SignedXmlDebugLog.LogSigning (this, hash); + m_signature.SignatureValue = new byte [signatureLength / 8]; + Buffer.BlockCopy (hashValue, 0, m_signature.SignatureValue, 0, signatureLength / 8); } - public virtual XmlElement GetIdElement (XmlDocument document, string idValue) + // + // virtual methods + // + + protected virtual AsymmetricAlgorithm GetPublicKey () { - if ((document == null) || (idValue == null)) - return null; + if (KeyInfo == null) + throw new CryptographicException (SR.Cryptography_Xml_KeyInfoRequired); + + if (_x509Enum != null) { + AsymmetricAlgorithm key = GetNextCertificatePublicKey (); + if (key != null) + return key; + } - // this works only if there's a DTD or XSD available to define the ID - XmlElement xel = document.GetElementById (idValue); - if (xel == null) { - // search an "undefined" ID - xel = (XmlElement) document.SelectSingleNode ("//*[@Id='" + idValue + "']"); - if (xel == null) { - xel = (XmlElement) document.SelectSingleNode ("//*[@ID='" + idValue + "']"); - if (xel == null) { - xel = (XmlElement) document.SelectSingleNode ("//*[@id='" + idValue + "']"); + if (_keyInfoEnum == null) + _keyInfoEnum = KeyInfo.GetEnumerator (); + + // In our implementation, we move to the next KeyInfo clause which is an RSAKeyValue, DSAKeyValue or KeyInfoX509Data + while (_keyInfoEnum.MoveNext()) { + RSAKeyValue rsaKeyValue = _keyInfoEnum.Current as RSAKeyValue; + if (rsaKeyValue != null) + return rsaKeyValue.Key; + + DSAKeyValue dsaKeyValue = _keyInfoEnum.Current as DSAKeyValue; + if (dsaKeyValue != null) + return dsaKeyValue.Key; + + KeyInfoX509Data x509Data = _keyInfoEnum.Current as KeyInfoX509Data; + if (x509Data != null) { + _x509Collection = Utils.BuildBagOfCerts (x509Data, CertUsageType.Verification); + if (_x509Collection.Count > 0) { + _x509Enum = _x509Collection.GetEnumerator (); + AsymmetricAlgorithm key = GetNextCertificatePublicKey (); + if (key != null) + return key; } } } - return xel; + + return null; + } + + private X509Certificate2Collection BuildBagOfCerts () + { + X509Certificate2Collection collection = new X509Certificate2Collection (); + if (KeyInfo != null) { + foreach (KeyInfoClause clause in KeyInfo) { + KeyInfoX509Data x509Data = clause as KeyInfoX509Data; + if (x509Data != null) + collection.AddRange (Utils.BuildBagOfCerts (x509Data, CertUsageType.Verification)); + } + } + + return collection; + } + + private AsymmetricAlgorithm GetNextCertificatePublicKey () + { + while (_x509Enum.MoveNext ()) { + X509Certificate2 certificate = (X509Certificate2)_x509Enum.Current; + if (certificate != null) + return Utils.GetAnyPublicKey (certificate); + } + + return null; + } + + public virtual XmlElement GetIdElement (XmlDocument document, string idValue) + { + return DefaultGetIdElement (document, idValue); } - internal static XmlElement DefaultGetIdElement(XmlDocument document, string idValue) + internal static XmlElement DefaultGetIdElement (XmlDocument document, string idValue) { if (document == null) return null; - try - { - XmlConvert.VerifyNCName(idValue); - } - catch - { + try { + XmlConvert.VerifyNCName (idValue); + } catch (XmlException) { // Identifiers are required to be an NCName // (xml:id version 1.0, part 4, paragraph 2, bullet 1) // @@ -753,152 +535,515 @@ namespace System.Security.Cryptography.Xml { } // Get the element with idValue - XmlElement elem = document.GetElementById(idValue); + XmlElement elem = document.GetElementById (idValue); - if (elem != null) - { + if (elem != null) { // Have to check for duplicate ID values from the DTD. - XmlDocument docClone = (XmlDocument)document.CloneNode(true); - XmlElement cloneElem = docClone.GetElementById(idValue); + XmlDocument docClone = (XmlDocument)document.CloneNode (true); + XmlElement cloneElem = docClone.GetElementById (idValue); // If it's null here we want to know about it, because it means that // GetElementById failed to work across the cloning, and our uniqueness // test is invalid. - System.Diagnostics.Debug.Assert(cloneElem != null); + System.Diagnostics.Debug.Assert (cloneElem != null); // Guard against null anyways - if (cloneElem != null) - { - cloneElem.Attributes.RemoveAll(); + if (cloneElem != null) { + cloneElem.Attributes.RemoveAll (); - XmlElement cloneElem2 = docClone.GetElementById(idValue); + XmlElement cloneElem2 = docClone.GetElementById (idValue); if (cloneElem2 != null) - { - throw new CryptographicException( - SR.Cryptography_Xml_InvalidReference); - } + throw new CryptographicException (SR.Cryptography_Xml_InvalidReference); } return elem; } - elem = GetSingleReferenceTarget(document, "Id", idValue); + elem = GetSingleReferenceTarget (document, "Id", idValue); if (elem != null) return elem; - elem = GetSingleReferenceTarget(document, "id", idValue); + elem = GetSingleReferenceTarget (document, "id", idValue); if (elem != null) return elem; - elem = GetSingleReferenceTarget(document, "ID", idValue); + elem = GetSingleReferenceTarget (document, "ID", idValue); return elem; } - private static XmlElement GetSingleReferenceTarget(XmlDocument document, string idAttributeName, string idValue) + // + // private methods + // + + private bool _bCacheValid; + private byte[] _digestedSignedInfo; + + private static bool DefaultSignatureFormatValidator (SignedXml signedXml) { - // idValue has already been tested as an NCName (unless overridden for compatibility), so there's no - // escaping that needs to be done here. - string xPath = "//*[@" + idAttributeName + "=\"" + idValue + "\"]"; + // Reject the signature if it uses a truncated HMAC + if (signedXml.DoesSignatureUseTruncatedHmac ()) + return false; - // http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel says that for the form URI="#chapter1": - // - // Identifies a node-set containing the element with ID attribute value 'chapter1' ... - // - // Note that it uses the singular. Therefore, if the match is ambiguous, we should consider the document invalid. - // - // In this case, we'll treat it the same as having found nothing across all fallbacks (but shortcut so that we don't - // fall into a trap of finding a secondary element which wasn't the originally signed one). + // Reject the signature if it uses a canonicalization algorithm other than + // one of the ones explicitly allowed + if (!signedXml.DoesSignatureUseSafeCanonicalizationMethod ()) + return false; - XmlNodeList nodeList = document.SelectNodes(xPath); + // Otherwise accept it + return true; + } - if (nodeList == null || nodeList.Count == 0) - { - return null; + // Validation function to see if the current signature is signed with a truncated HMAC - one which + // has a signature length of fewer bits than the whole HMAC output. + private bool DoesSignatureUseTruncatedHmac () + { + // If we're not using the SignatureLength property, then we're not truncating the signature length + if (SignedInfo.SignatureLength == null) + return false; + + // See if we're signed witn an HMAC algorithm + HMAC hmac = CryptoHelpers.CreateFromName (SignatureMethod) as HMAC; + if (hmac == null) + return false; // We aren't signed with an HMAC algorithm, so we cannot have a truncated HMAC + + // Figure out how many bits the signature is using + int actualSignatureSize = 0; + if (!int.TryParse (SignedInfo.SignatureLength, out actualSignatureSize)) + return true; // If the value wasn't a valid integer, then we'll conservatively reject it all together + + // Make sure the full HMAC signature size is the same size that was specified in the XML + // signature. If the actual signature size is not exactly the same as the full HMAC size, then + // reject the signature. + return actualSignatureSize != hmac.HashSize; + } + + // Validation function to see if the signature uses a canonicalization algorithm from our list + // of approved algorithm URIs. + private bool DoesSignatureUseSafeCanonicalizationMethod () + { + foreach (string safeAlgorithm in SafeCanonicalizationMethods) { + if (string.Equals (safeAlgorithm, SignedInfo.CanonicalizationMethod, StringComparison.OrdinalIgnoreCase)) + return true; } - if (nodeList.Count == 1) - { - return nodeList[0] as XmlElement; + SignedXmlDebugLog.LogUnsafeCanonicalizationMethod (this, SignedInfo.CanonicalizationMethod, SafeCanonicalizationMethods); + return false; + } + + private bool ReferenceUsesSafeTransformMethods (Reference reference) + { + TransformChain transformChain = reference.TransformChain; + int transformCount = transformChain.Count; + + for (int i = 0; i < transformCount; i++) { + Transform transform = transformChain [i]; + + if (!IsSafeTransform (transform.Algorithm)) + return false; } - throw new CryptographicException(SR.Cryptography_Xml_InvalidReference); + return true; } - // According to book ".NET Framework Security" this method - // iterates all possible keys then return null - protected virtual AsymmetricAlgorithm GetPublicKey () + private bool IsSafeTransform (string transformAlgorithm) { - if (m_signature.KeyInfo == null) - return null; + // All canonicalization algorithms are valid transform algorithms. + foreach (string safeAlgorithm in SafeCanonicalizationMethods) { + if (string.Equals (safeAlgorithm, transformAlgorithm, StringComparison.OrdinalIgnoreCase)) + return true; + } - if (pkEnumerator == null) { - pkEnumerator = m_signature.KeyInfo.GetEnumerator (); + foreach (string safeAlgorithm in DefaultSafeTransformMethods) { + if (string.Equals (safeAlgorithm, transformAlgorithm, StringComparison.OrdinalIgnoreCase)) + return true; } - -#if SECURITY_DEP - if (_x509Enumerator != null) { - if (_x509Enumerator.MoveNext ()) { - X509Certificate cert = (X509Certificate) _x509Enumerator.Current; - return new X509Certificate2 (cert.GetRawCertData ()).PublicKey.Key; - } else { - _x509Enumerator = null; + + SignedXmlDebugLog.LogUnsafeTransformMethod ( + this, + transformAlgorithm, + SafeCanonicalizationMethods, + DefaultSafeTransformMethods); + + return false; + } + + // Get a list of the built in canonicalization algorithms, as well as any that the machine admin has + // added to the valid set. + private static IList<string> KnownCanonicalizationMethods { + get { + if (s_knownCanonicalizationMethods == null) { + // Start with the list that the machine admin added, if any + List<string> safeAlgorithms = new List<string> (); + + // Built in algorithms + safeAlgorithms.Add (XmlDsigC14NTransformUrl); + safeAlgorithms.Add (XmlDsigC14NWithCommentsTransformUrl); + safeAlgorithms.Add (XmlDsigExcC14NTransformUrl); + safeAlgorithms.Add (XmlDsigExcC14NWithCommentsTransformUrl); + + s_knownCanonicalizationMethods = safeAlgorithms; } - } -#endif - while (pkEnumerator.MoveNext ()) { - AsymmetricAlgorithm key = null; - KeyInfoClause kic = (KeyInfoClause) pkEnumerator.Current; - if (kic is DSAKeyValue) - key = DSA.Create (); - else if (kic is RSAKeyValue) - key = RSA.Create (); + return s_knownCanonicalizationMethods; + } + } - if (key != null) { - key.FromXmlString (kic.GetXml ().InnerXml); - return key; + private static IList<string> DefaultSafeTransformMethods { + get { + if (s_defaultSafeTransformMethods == null) { + List<string> safeAlgorithms = new List<string> (); + + // Built in algorithms + + // KnownCanonicalizationMethods don't need to be added here, because + // the validator will automatically accept those. + // + // xmldsig 6.6.1: + // Any canonicalization algorithm that can be used for + // CanonicalizationMethod can be used as a Transform. + safeAlgorithms.Add (XmlDsigEnvelopedSignatureTransformUrl); + safeAlgorithms.Add (XmlDsigBase64TransformUrl); + safeAlgorithms.Add (XmlLicenseTransformUrl); + safeAlgorithms.Add (XmlDecryptionTransformUrl); + + s_defaultSafeTransformMethods = safeAlgorithms; } -#if SECURITY_DEP - if (kic is KeyInfoX509Data) { - _x509Enumerator = ((KeyInfoX509Data) kic).Certificates.GetEnumerator (); - if (_x509Enumerator.MoveNext ()) { - X509Certificate cert = (X509Certificate) _x509Enumerator.Current; - return new X509Certificate2 (cert.GetRawCertData ()).PublicKey.Key; + return s_defaultSafeTransformMethods; + } + } + + private byte[] GetC14NDigest (HashAlgorithm hash) + { + bool isKeyedHashAlgorithm = hash is KeyedHashAlgorithm; + if (isKeyedHashAlgorithm || !_bCacheValid || !SignedInfo.CacheValid) { + string baseUri = (_containingDocument == null ? null : _containingDocument.BaseURI); + XmlResolver resolver = (_bResolverSet ? _xmlResolver : new XmlSecureResolver (new XmlUrlResolver (), baseUri)); + XmlDocument doc = Utils.PreProcessElementInput (SignedInfo.GetXml (), resolver, baseUri); + + // Add non default namespaces in scope + CanonicalXmlNodeList namespaces = (_context == null ? null : Utils.GetPropagatedAttributes (_context)); + SignedXmlDebugLog.LogNamespacePropagation (this, namespaces); + Utils.AddNamespaces (doc.DocumentElement, namespaces); + + Transform c14nMethodTransform = SignedInfo.CanonicalizationMethodObject; + c14nMethodTransform.Resolver = resolver; + c14nMethodTransform.BaseURI = baseUri; + + SignedXmlDebugLog.LogBeginCanonicalization (this, c14nMethodTransform); + c14nMethodTransform.LoadInput (doc); + SignedXmlDebugLog.LogCanonicalizedOutput (this, c14nMethodTransform); + _digestedSignedInfo = c14nMethodTransform.GetDigestedOutput (hash); + + _bCacheValid = !isKeyedHashAlgorithm; + } + return _digestedSignedInfo; + } + + private int GetReferenceLevel (int index, ArrayList references) + { + if (_refProcessed [index]) return _refLevelCache [index]; + _refProcessed [index] = true; + Reference reference = (Reference)references [index]; + if (reference.Uri == null || reference.Uri.Length == 0 || (reference.Uri.Length > 0 && reference.Uri [0] != '#')) { + _refLevelCache [index] = 0; + return 0; + } + if (reference.Uri.Length > 0 && reference.Uri [0] == '#') + { + string idref = Utils.ExtractIdFromLocalUri (reference.Uri); + if (idref == "xpointer(/)") { + _refLevelCache [index] = 0; + return 0; + } + // If this is pointing to another reference + for (int j = 0; j < references.Count; ++j) { + if (((Reference)references [j]).Id == idref) { + _refLevelCache [index] = GetReferenceLevel (j, references) + 1; + return (_refLevelCache [index]); } } -#endif + // Then the reference points to an object tag + _refLevelCache [index] = 0; + return 0; } - return null; + // Malformed reference + throw new CryptographicException (SR.Cryptography_Xml_InvalidReference); } - public XmlElement GetXml () + private class ReferenceLevelSortOrder : IComparer { - return m_signature.GetXml (envdoc); + private ArrayList _references; + + public ReferenceLevelSortOrder () + { + } + + public ArrayList References + { + get { return _references; } + set { _references = value; } + } + + public int Compare (object a, object b) + { + Reference referenceA = a as Reference; + Reference referenceB = b as Reference; + + // Get the indexes + int iIndexA = 0; + int iIndexB = 0; + int i = 0; + foreach (Reference reference in References) { + if (reference == referenceA) iIndexA = i; + if (reference == referenceB) iIndexB = i; + i++; + } + + int iLevelA = referenceA.SignedXml.GetReferenceLevel (iIndexA, References); + int iLevelB = referenceB.SignedXml.GetReferenceLevel (iIndexB, References); + return iLevelA.CompareTo (iLevelB); + } } - public void LoadXml (XmlElement value) + private void BuildDigestedReferences () { - if (value == null) - throw new ArgumentNullException ("value"); + // Default the DigestMethod and Canonicalization + ArrayList references = SignedInfo.References; + // Reset the cache + _refProcessed = new bool [references.Count]; + _refLevelCache = new int [references.Count]; - signatureElement = value; - m_signature.LoadXml (value); + ReferenceLevelSortOrder sortOrder = new ReferenceLevelSortOrder (); + sortOrder.References = references; + // Don't alter the order of the references array list + ArrayList sortedReferences = new ArrayList (); - if (_context == null) { - _context = value; + foreach (Reference reference in references) + sortedReferences.Add (reference); + + sortedReferences.Sort (sortOrder); + + CanonicalXmlNodeList nodeList = new CanonicalXmlNodeList (); + + foreach (DataObject obj in m_signature.ObjectList) + nodeList.Add (obj.GetXml ()); + + foreach (Reference reference in sortedReferences) { + if (reference.DigestMethod == null) + reference.DigestMethod = XmlDsigDigestDefault; + + SignedXmlDebugLog.LogSigningReference (this, reference); + + reference.UpdateHashValue (_containingDocument, nodeList); + // If this reference has an Id attribute, add it + if (reference.Id != null) + nodeList.Add (reference.GetXml ()); } + } + + private bool CheckDigestedReferences () + { + ArrayList references = m_signature.SignedInfo.References; + for (int i = 0; i < references.Count; ++i) { + Reference digestedReference = (Reference)references [i]; + + if (!ReferenceUsesSafeTransformMethods (digestedReference)) + return false; + + SignedXmlDebugLog.LogVerifyReference (this, digestedReference); + byte[] calculatedHash = null; + try { + calculatedHash = digestedReference.CalculateHashValue (_containingDocument, m_signature.ReferencedItems); + } catch (CryptoSignedXmlRecursionException) { + SignedXmlDebugLog.LogSignedXmlRecursionLimit (this, digestedReference); + return false; + } + // Compare both hashes + SignedXmlDebugLog.LogVerifyReferenceHash (this, digestedReference, calculatedHash, digestedReference.DigestValue); + + if (!CryptographicEquals (calculatedHash, digestedReference.DigestValue)) + return false; + } + + return true; + } + + // Methods _must_ be marked both No Inlining and No Optimization to be fully opted out of optimization. + // This is because if a candidate method is inlined, its method level attributes, including the NoOptimization + // attribute, are lost. + // This method makes no attempt to disguise the length of either of its inputs. It is assumed the attacker has + // knowledge of the algorithms used, and thus the output length. Length is difficult to properly blind in modern CPUs. + [MethodImpl (MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] + private static bool CryptographicEquals (byte[] a, byte[] b) + { + System.Diagnostics.Debug.Assert (a != null); + System.Diagnostics.Debug.Assert (b != null); - // Need to give the EncryptedXml object to the - // XmlDecryptionTransform to give it a fighting - // chance at decrypting the document. - foreach (Reference r in m_signature.SignedInfo.References) { - foreach (Transform t in r.TransformChain) { - if (t is XmlDecryptionTransform) - ((XmlDecryptionTransform) t).EncryptedXml = EncryptedXml; + int result = 0; + + // Short cut if the lengths are not identical + if (a.Length != b.Length) + return false; + + unchecked + { + // Normally this caching doesn't matter, but with the optimizer off, this nets a non-trivial speedup. + int aLength = a.Length; + + for (int i = 0; i < aLength; i++) { + // We use subtraction here instead of XOR because the XOR algorithm gets ever so + // slightly faster as more and more differences pile up. + // This cannot overflow more than once (and back to 0) because bytes are 1 byte + // in length, and result is 4 bytes. The OR propagates all set bytes, so the differences + // can't add up and overflow a second time. + result = result | (a [i] - b [i]); } } + + return (0 == result); + } + + // If we have a signature format validation callback, check to see if this signature's format (not + // the signature itself) is valid according to the validator. A return value of true indicates that + // the signature format is acceptable, false means that the format is not valid. + private bool CheckSignatureFormat () + { + if (_signatureFormatValidator == null) { + // No format validator means that we default to accepting the signature. (This is + // effectively compatibility mode with v3.5). + return true; + } + + SignedXmlDebugLog.LogBeginCheckSignatureFormat (this, _signatureFormatValidator); + + bool formatValid = _signatureFormatValidator (this); + SignedXmlDebugLog.LogFormatValidationResult (this, formatValid); + return formatValid; + } + + private bool CheckSignedInfo (AsymmetricAlgorithm key) + { + if (key == null) + throw new ArgumentNullException (nameof (key)); + + SignedXmlDebugLog.LogBeginCheckSignedInfo (this, m_signature.SignedInfo); + + SignatureDescription signatureDescription = CryptoHelpers.CreateFromName (SignatureMethod) as SignatureDescription; + if (signatureDescription == null) + throw new CryptographicException (SR.Cryptography_Xml_SignatureDescriptionNotCreated); + + // Let's see if the key corresponds with the SignatureMethod + Type ta = Type.GetType (signatureDescription.KeyAlgorithm); + if (!IsKeyTheCorrectAlgorithm (key, ta)) + return false; + + HashAlgorithm hashAlgorithm = signatureDescription.CreateDigest (); + if (hashAlgorithm == null) + throw new CryptographicException (SR.Cryptography_Xml_CreateHashAlgorithmFailed); + byte[] hashval = GetC14NDigest (hashAlgorithm); + + AsymmetricSignatureDeformatter asymmetricSignatureDeformatter = signatureDescription.CreateDeformatter (key); + SignedXmlDebugLog.LogVerifySignedInfo (this, + key, + signatureDescription, + hashAlgorithm, + asymmetricSignatureDeformatter, + hashval, + m_signature.SignatureValue); + return asymmetricSignatureDeformatter.VerifySignature (hashval, m_signature.SignatureValue); + } + + private bool CheckSignedInfo (KeyedHashAlgorithm macAlg) + { + if (macAlg == null) + throw new ArgumentNullException (nameof (macAlg)); + + SignedXmlDebugLog.LogBeginCheckSignedInfo (this, m_signature.SignedInfo); + + int signatureLength; + if (m_signature.SignedInfo.SignatureLength == null) + signatureLength = macAlg.HashSize; + else + signatureLength = Convert.ToInt32 (m_signature.SignedInfo.SignatureLength, null); + + // signatureLength should be less than hash size + if (signatureLength < 0 || signatureLength > macAlg.HashSize) + throw new CryptographicException (SR.Cryptography_Xml_InvalidSignatureLength); + if (signatureLength % 8 != 0) + throw new CryptographicException (SR.Cryptography_Xml_InvalidSignatureLength2); + if (m_signature.SignatureValue == null) + throw new CryptographicException (SR.Cryptography_Xml_SignatureValueRequired); + if (m_signature.SignatureValue.Length != signatureLength / 8) + throw new CryptographicException (SR.Cryptography_Xml_InvalidSignatureLength); + + // Calculate the hash + byte[] hashValue = GetC14NDigest (macAlg); + SignedXmlDebugLog.LogVerifySignedInfo (this, macAlg, hashValue, m_signature.SignatureValue); + + for (int i = 0; i < m_signature.SignatureValue.Length; i++) + if (m_signature.SignatureValue [i] != hashValue [i]) return false; + + return true; + } + + private static XmlElement GetSingleReferenceTarget (XmlDocument document, string idAttributeName, string idValue) + { + // idValue has already been tested as an NCName (unless overridden for compatibility), so there's no + // escaping that needs to be done here. + string xPath = "//*[@" + idAttributeName + "=\"" + idValue + "\"]"; + + // http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel says that for the form URI="#chapter1": + // + // Identifies a node-set containing the element with ID attribute value 'chapter1' ... + // + // Note that it uses the singular. Therefore, if the match is ambiguous, we should consider the document invalid. + // + // In this case, we'll treat it the same as having found nothing across all fallbacks (but shortcut so that we don't + // fall into a trap of finding a secondary element which wasn't the originally signed one). + + XmlNodeList nodeList = document.SelectNodes (xPath); + + if (nodeList == null || nodeList.Count == 0) + return null; + + if (nodeList.Count == 1) + return nodeList [0] as XmlElement; + + throw new CryptographicException (SR.Cryptography_Xml_InvalidReference); + } + + private static bool IsKeyTheCorrectAlgorithm (AsymmetricAlgorithm key, Type expectedType) + { + Type actualType = key.GetType (); + + if (actualType == expectedType) + return true; + + // This check exists solely for compatibility with 4.6. Normally, we would expect "expectedType" to be the superclass type and + // the actualType to be the subclass. + if (expectedType.IsSubclassOf (actualType)) + return true; + + // + // "expectedType" comes from the KeyAlgorithm property of a SignatureDescription. The BCL SignatureDescription classes have historically + // denoted provider-specific implementations ("RSACryptoServiceProvider") rather than the base class for the algorithm ("RSA"). We could + // change those (at the risk of creating other compat problems) but we have no control over third party SignatureDescriptions. + // + // So, in the absence of a better approach, walk up the parent hierarchy until we find the ancestor that's a direct subclass of + // AsymmetricAlgorithm and treat that as the algorithm identifier. + // + while (expectedType != null && expectedType.BaseType != typeof (AsymmetricAlgorithm)) + expectedType = expectedType.BaseType; + + if (expectedType == null) + return false; // SignatureDescription specified something that isn't even a subclass of AsymmetricAlgorithm. For compatibility with 4.6, return false rather throw. + + if (actualType.IsSubclassOf (expectedType)) + return true; + + return false; } } -} +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/X509IssuerSerial.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/X509IssuerSerial.cs deleted file mode 100644 index 505752920a1..00000000000 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/X509IssuerSerial.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// X509IssuerSerial.cs - X509IssuerSerial implementation for XML Encryption -// -// Author: -// Tim Coleman (tim@timcoleman.com) -// Sebastien Pouliot <sebastien@ximian.com> -// -// Copyright (C) Tim Coleman, 2004 -// Copyright (C) 2004-2005 Novell Inc. (http://www.novell.com) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -namespace System.Security.Cryptography.Xml { - - public - struct X509IssuerSerial { - - private string _issuerName; - private string _serialNumber; - - internal X509IssuerSerial (string issuer, string serial) - { - _issuerName = issuer; - _serialNumber = serial; - } - - public string IssuerName { - get { return _issuerName; } - set { _issuerName = value; } - } - - public string SerialNumber { - get { return _serialNumber; } - set { _serialNumber = value; } - } - } -} - diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlSignature.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlSignature.cs deleted file mode 100644 index 1dc64eac1dc..00000000000 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlSignature.cs +++ /dev/null @@ -1,128 +0,0 @@ -// -// XmlSignature.cs: Handles Xml Signature -// -// Author: -// Sebastien Pouliot (spouliot@motus.com) -// Atsushi Enomoto (atsushi@ximian.com) -// Tim Coleman (tim@timcoleman.com) -// -// (C) 2003 Motus Technologies Inc. (http://www.motus.com) -// Copyright (C) Tim Coleman, 2004 -// (C) 2004 Novell Inc. -// - -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using System.Collections; -using System.Xml; - -namespace System.Security.Cryptography.Xml { - - // following the design of WSE - internal class XmlSignature { - - public class ElementNames { - - public const string CanonicalizationMethod = "CanonicalizationMethod"; - public const string DigestMethod = "DigestMethod"; - public const string DigestValue = "DigestValue"; - public const string DSAKeyValue = "DSAKeyValue"; - public const string EncryptedKey = "EncryptedKey"; - public const string HMACOutputLength = "HMACOutputLength"; - public const string KeyInfo = "KeyInfo"; - public const string KeyName = "KeyName"; - public const string KeyValue = "KeyValue"; - public const string Manifest = "Manifest"; - public const string Object = "Object"; - public const string Reference = "Reference"; - public const string RetrievalMethod = "RetrievalMethod"; - public const string RSAKeyValue = "RSAKeyValue"; - public const string Signature = "Signature"; - public const string SignatureMethod = "SignatureMethod"; - public const string SignatureValue = "SignatureValue"; - public const string SignedInfo = "SignedInfo"; - public const string Transform = "Transform"; - public const string Transforms = "Transforms"; - public const string X509Data = "X509Data"; - public const string X509IssuerSerial = "X509IssuerSerial"; - public const string X509IssuerName = "X509IssuerName"; - public const string X509SerialNumber = "X509SerialNumber"; - public const string X509SKI = "X509SKI"; - public const string X509SubjectName = "X509SubjectName"; - public const string X509Certificate = "X509Certificate"; - public const string X509CRL = "X509CRL"; - - public ElementNames () {} - } - - public class AttributeNames { - - public const string Algorithm = "Algorithm"; - public const string Encoding = "Encoding"; - public const string Id = "Id"; - public const string MimeType = "MimeType"; - public const string Type = "Type"; - public const string URI = "URI"; - - public AttributeNames () {} - } - - public class Uri { - public const string Manifest = "http://www.w3.org/2000/09/xmldsig#Manifest"; - } - - public const string NamespaceURI = "http://www.w3.org/2000/09/xmldsig#"; - public const string Prefix = "ds"; - - public XmlSignature () - { - } - - public static XmlElement GetChildElement (XmlElement xel, string element, string ns) - { - for (int i = 0; i < xel.ChildNodes.Count; i++) { - XmlNode n = xel.ChildNodes [i]; - if (n.NodeType == XmlNodeType.Element && n.LocalName == element && n.NamespaceURI == ns) - return n as XmlElement; - } - return null; - } - - public static string GetAttributeFromElement (XmlElement xel, string attribute, string element) - { - XmlElement el = GetChildElement (xel, element, XmlSignature.NamespaceURI); - return el != null ? el.GetAttribute (attribute) : null; - } - - public static XmlElement [] GetChildElements (XmlElement xel, string element) - { - ArrayList al = new ArrayList (); - for (int i = 0; i < xel.ChildNodes.Count; i++) { - XmlNode n = xel.ChildNodes [i]; - if (n.NodeType == XmlNodeType.Element && n.LocalName == element && n.NamespaceURI == XmlSignature.NamespaceURI) - al.Add (n); - } - return al.ToArray (typeof (XmlElement)) as XmlElement []; - } - } -} diff --git a/mcs/class/System.Security/System.Security.dll.sources b/mcs/class/System.Security/System.Security.dll.sources index 75c0a6f9b0a..e77373a0ebe 100644 --- a/mcs/class/System.Security/System.Security.dll.sources +++ b/mcs/class/System.Security/System.Security.dll.sources @@ -1,5 +1,5 @@ #include common_System.Security.dll.sources -corefx/SR.cs + Mono.Security.Cryptography/ManagedProtection.cs Mono.Security.Cryptography/NativeDapiProtection.cs System.Security.Cryptography/MemoryProtectionScope.cs @@ -13,6 +13,8 @@ System.Security.Cryptography.Pkcs/SignerInfoEnumerator.cs ../System.Core/System.Security.Cryptography.X509Certificates/RSACertificateExtensions.cs System.Security.Cryptography.X509Certificates/X509Certificate2UI.cs System.Security.Cryptography.X509Certificates/X509SelectionFlag.cs + +# System.Security.Cryptography.Xml ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/AncestralNamespaceContextManager.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/AttributeSortOrder.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/C14NAncestralNamespaceContextManager.cs @@ -57,9 +59,8 @@ System.Security.Cryptography.X509Certificates/X509SelectionFlag.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoName.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoNode.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoRetrievalMethod.cs -System.Security.Cryptography.Xml/KeyInfoX509Data.cs +../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoX509Data.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyReference.cs -System.Security.Cryptography.Xml/Manifest.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/MyXmlDocument.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/NamespaceFrame.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/NamespaceSortOrder.cs @@ -72,8 +73,8 @@ System.Security.Cryptography.Xml/Manifest.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA384SignatureDescription.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA512SignatureDescription.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SignatureDescription.cs -System.Security.Cryptography.Xml/Signature.cs -System.Security.Cryptography.Xml/SignedInfo.cs +../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Signature.cs +../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedInfo.cs System.Security.Cryptography.Xml/SignedXml.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SymmetricKeyWrap.cs @@ -90,8 +91,8 @@ System.Security.Cryptography.Xml/SignedXml.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDsigXPathTransform.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDsigXsltTransform.cs ../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlLicenseTransform.cs -System.Security.Cryptography.Xml/XmlSignature.cs -../../build/common/MonoTODOAttribute.cs + +# System.Security.Permissions System.Security.Permissions/DataProtectionPermission.cs System.Security.Permissions/DataProtectionPermissionAttribute.cs System.Security.Permissions/DataProtectionPermissionFlags.cs diff --git a/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/EncryptedXmlTest.cs b/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/EncryptedXmlTest.cs index 7ff9beef391..82fc0fb433a 100644 --- a/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/EncryptedXmlTest.cs +++ b/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/EncryptedXmlTest.cs @@ -180,11 +180,22 @@ namespace MonoTests.System.Security.Cryptography.Xml Assert.IsNull (ex.GetIdElement (null, "value")); } + [TestCase (null, TestName = "null")] + [TestCase ("", TestName = "empty")] + public void GetIdElement_WhenElementNameMustBeNonColonizedAndItIsNotProvided_ThrowsArgumentNullException (string elementName) + { + var sut = new EncryptedXml (); + + var ex = Assert.Throws<ArgumentNullException> (() => sut.GetIdElement (new XmlDocument (), elementName), "Exception"); + Assert.That (ex.ParamName, Is.EqualTo ("name"), "ParamName"); + } + [Test] - public void GetIdElement_StringNull () + public void GetIdElement_WhenElementNameMustBeNonColonizedAndItContainsColon_ReturnsNull () { - EncryptedXml ex = new EncryptedXml (); - Assert.IsNull (ex.GetIdElement (new XmlDocument (), null)); + var sut = new EncryptedXml (); + + Assert.That (sut.GetIdElement (new XmlDocument (), "t:test"), Is.Null); } [Test] diff --git a/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/SignedXmlTest.cs b/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/SignedXmlTest.cs index b5baf86ebdb..2a6aae4f774 100644 --- a/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/SignedXmlTest.cs +++ b/mcs/class/System.Security/Test/System.Security.Cryptography.Xml/SignedXmlTest.cs @@ -253,7 +253,7 @@ namespace MonoTests.System.Security.Cryptography.Xml { signedXml.ComputeSignature (); Assert.IsNull (signedXml.SigningKeyName, "SigningKeyName"); - Assert.AreEqual (SignedXml.XmlDsigRSASHA1Url, signedXml.SignatureMethod, "SignatureMethod"); + Assert.AreEqual (SignedXml.XmlDsigRSASHA256Url, signedXml.SignatureMethod, "SignatureMethod"); Assert.AreEqual (128, signedXml.SignatureValue.Length, "SignatureValue"); Assert.IsNull (signedXml.SigningKeyName, "SigningKeyName"); @@ -638,13 +638,13 @@ namespace MonoTests.System.Security.Cryptography.Xml { public void DataReferenceToNonDataObject () { XmlDocument doc = new XmlDocument (); - doc.LoadXml ("<foo Id='id:1'/>"); + doc.LoadXml ("<foo Id='test'/>"); SignedXml signedXml = new SignedXml (doc); DSA key = DSA.Create (); signedXml.SigningKey = key; Reference reference = new Reference (); - reference.Uri = "#id:1"; + reference.Uri = "#test"; XmlDsigC14NTransform t = new XmlDsigC14NTransform (); reference.AddTransform (t); @@ -707,12 +707,30 @@ namespace MonoTests.System.Security.Cryptography.Xml { return sw.ToString (); } + [TestCase (null, TestName = "null")] + [TestCase ("", TestName = "empty")] + public void GetIdElement_WhenElementNameMustBeNonColonizedAndItIsNotProvided_ThrowsArgumentNullException (string elementName) + { + var sut = new SignedXml (); + + var ex = Assert.Throws<ArgumentNullException> (() => sut.GetIdElement (new XmlDocument (), elementName), "Exception"); + Assert.That (ex.ParamName, Is.EqualTo ("name"), "ParamName"); + } + [Test] - public void GetIdElement_Null () + public void GetIdElement_WhenElementNameMustBeNonColonizedAndItContainsColon_ReturnsNull () { - SignedXml sign = new SignedXml (); - Assert.IsNull (sign.GetIdElement (null, "value")); - Assert.IsNull (sign.GetIdElement (new XmlDocument (), null)); + var sut = new SignedXml (); + + Assert.That (sut.GetIdElement (new XmlDocument (), "t:test"), Is.Null); + } + + [Test] + public void GetIdElement_WhenXmlDocumentIsNotProvided_ReturnsNull () + { + var sut = new SignedXml (); + + Assert.That (sut.GetIdElement (null, "value"), Is.Null); } [Test] @@ -789,6 +807,7 @@ namespace MonoTests.System.Security.Cryptography.Xml { SignedXml signedXml = new SignedXml (doc); signedXml.SigningKey = cert.PrivateKey; signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl; + signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url; Reference reference = new Reference (); reference.DigestMethod = SignedXml.XmlDsigSHA1Url; @@ -1408,13 +1427,6 @@ namespace MonoTests.System.Security.Cryptography.Xml { // verify MS-generated signature Assert.IsTrue (sign.CheckSignature (new HMACRIPEMD160 (hmackey))); } - // CVE-2009-0217 - // * a 0-length signature is the worse case - it accepts anything - // * between 1-7 bits length are considered invalid (not a multiple of 8) - // * a 8 bits signature would have one chance, out of 256, to be valid - // * and so on... until we hit (output-length / 2) or 80 bits (see ERRATUM) - - static bool erratum = true; // xmldsig erratum for CVE-2009-0217 static SignedXml GetSignedXml (string xml) { @@ -1426,31 +1438,15 @@ namespace MonoTests.System.Security.Cryptography.Xml { return sign; } - static void CheckErratum (SignedXml signed, KeyedHashAlgorithm hmac, string message) - { - if (erratum) { - try { - signed.CheckSignature (hmac); - Assert.Fail (message + ": unexcepted success"); - } - catch (CryptographicException) { - } - catch (Exception e) { - Assert.Fail (message + ": unexcepted " + e.ToString ()); - } - } else { - Assert.IsTrue (signed.CheckSignature (hmac), message); - } - } - - private void HmacMustBeMultipleOfEightBits (int bits) + [Test] + public void CheckSignature_WhenHmacOutputLengthIsNotMultipleOf8_ThrowsCryptographicException () { string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?> <Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""> <SignedInfo> <CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /> <SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#hmac-sha1"" > - <HMACOutputLength>{0}</HMACOutputLength> + <HMACOutputLength>81</HMACOutputLength> </SignatureMethod> <Reference URI=""#object""> <DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /> @@ -1463,96 +1459,41 @@ namespace MonoTests.System.Security.Cryptography.Xml { <Object Id=""object"">some other text</Object> </Signature> "; - SignedXml sign = GetSignedXml (String.Format (xml, bits)); - // only multiple of 8 bits are supported - sign.CheckSignature (new HMACSHA1 (Encoding.ASCII.GetBytes ("secret"))); - } - [Test] - public void HmacMustBeMultipleOfEightBits () - { - for (int i = 1; i < 160; i++) { - // The .NET framework only supports multiple of 8 bits - if (i % 8 == 0) - continue; - - try { - HmacMustBeMultipleOfEightBits (i); - Assert.Fail ("Unexpected Success " + i.ToString ()); - } - catch (CryptographicException) { - } - catch (Exception e) { - Assert.Fail ("Unexpected Exception " + i.ToString () + " : " + e.ToString ()); - } - } - } + var sut = GetSignedXml (xml); + sut.SignatureFormatValidator = null; - [Test] - [Category ("NotDotNet")] // will fail until a fix is available - public void VerifyHMAC_ZeroLength () - { - string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?> -<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""> - <SignedInfo> - <CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /> - <SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#hmac-sha1"" > - <HMACOutputLength>0</HMACOutputLength> - </SignatureMethod> - <Reference URI=""#object""> - <DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /> - <DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue> - </Reference> - </SignedInfo> - <SignatureValue> - </SignatureValue> - <Object Id=""object"">some other text</Object> -</Signature> -"; - SignedXml sign = GetSignedXml (xml); - - CheckErratum (sign, new HMACSHA1 (Encoding.ASCII.GetBytes ("no clue")), "1"); - CheckErratum (sign, new HMACSHA1 (Encoding.ASCII.GetBytes ("")), "2"); - CheckErratum (sign, new HMACSHA1 (Encoding.ASCII.GetBytes ("oops")), "3"); - CheckErratum (sign, new HMACSHA1 (Encoding.ASCII.GetBytes ("secret")), "4"); + var ex = Assert.Throws<CryptographicException> (() => sut.CheckSignature (new HMACSHA1 (Encoding.ASCII.GetBytes ("secret"))), "Exception"); + Assert.That (ex.Message, Is.StringContaining ("multiple of 8").IgnoreCase, "Message"); } [Test] - [Category ("NotDotNet")] // will fail until a fix is available - public void VerifyHMAC_SmallerThanMinimumLength () + public void CheckSignature_WhenDefaultSignatureFormatValidatorIsUsedAndSignatureUsesTruncatedHmac_ReturnsFalse () { - // 72 is a multiple of 8 but smaller than the minimum of 80 bits - string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#hmac-sha1""><HMACOutputLength>72</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>2dimB+P5Aw5K</SignatureValue><Object Id=""object"">some other text</Object></Signature>"; - SignedXml sign = GetSignedXml (xml); - CheckErratum (sign, new HMACSHA1 (Encoding.ASCII.GetBytes ("secret")), "72"); - } + // The HMAC output length is 128, which is a half of HMACSHA256 that we're going to use. + string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#hmac-sha256""><HMACOutputLength>128</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>aegpvkAwOL8gN/CjSnW6qw==</SignatureValue><Object Id=""object"">some other text</Object></Signature>"; + var sut = GetSignedXml (xml); - [Test] - public void VerifyHMAC_MinimumLength () - { - // 80 bits is the minimum (and the half-size of HMACSHA1) - string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#hmac-sha1""><HMACOutputLength>80</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>jVQPtLj61zNYjw==</SignatureValue><Object Id=""object"">some other text</Object></Signature>"; - SignedXml sign = GetSignedXml (xml); - Assert.IsTrue (sign.CheckSignature (new HMACSHA1 (Encoding.ASCII.GetBytes ("secret")))); - } - [Test] - [Category ("NotDotNet")] // will fail until a fix is available - public void VerifyHMAC_SmallerHalfLength () - { - // 80bits is smaller than the half-size of HMACSHA256 - string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#hmac-sha256""><HMACOutputLength>80</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>vPtw7zKVV/JwQg==</SignatureValue><Object Id=""object"">some other text</Object></Signature>"; - SignedXml sign = GetSignedXml (xml); - CheckErratum (sign, new HMACSHA256 (Encoding.ASCII.GetBytes ("secret")), "80"); + // Although the XML Signature standard allows using truncated HMACs (with some limitations), + // .NET Framework, by default, doesn't allow using them, since it may result in security issues. + Assert.That (sut.CheckSignature (new HMACSHA256 (Encoding.ASCII.GetBytes ("secret"))), Is.False); } [Test] - public void VerifyHMAC_HalfLength () + public void CheckSignature_WhenDefaultSignatureFormatValidatorIsNotUsedAndSignatureUsesTruncatedHmac_ReturnsTrue () { - // 128 is the half-size of HMACSHA256 + // The HMAC output length is 128, which is a half of HMACSHA256 that we're going to use. string xml = @"<Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""><SignedInfo><CanonicalizationMethod Algorithm=""http://www.w3.org/TR/2001/REC-xml-c14n-20010315"" /><SignatureMethod Algorithm=""http://www.w3.org/2001/04/xmldsig-more#hmac-sha256""><HMACOutputLength>128</HMACOutputLength></SignatureMethod><Reference URI=""#object""><DigestMethod Algorithm=""http://www.w3.org/2000/09/xmldsig#sha1"" /><DigestValue>nz4GS0NbH2SrWlD/4fX313CoTzc=</DigestValue></Reference></SignedInfo><SignatureValue>aegpvkAwOL8gN/CjSnW6qw==</SignatureValue><Object Id=""object"">some other text</Object></Signature>"; - SignedXml sign = GetSignedXml (xml); - Assert.IsTrue (sign.CheckSignature (new HMACSHA256 (Encoding.ASCII.GetBytes ("secret")))); + var sut = GetSignedXml (xml); + + // By default, .NET Framework doesn't allow using truncated HMACs, since it may lead to security issues. + // That being said, the XML Signature standard allows using truncated HMACs, but with some limitations. + // It's possible to use truncated HMACs by using a custom signature format validator, or not using it at all. + sut.SignatureFormatValidator = null; + + Assert.That (sut.CheckSignature (new HMACSHA256 (Encoding.ASCII.GetBytes ("secret"))), Is.True); } + [Test] public void VerifyHMAC_FullLength () { @@ -1562,8 +1503,7 @@ namespace MonoTests.System.Security.Cryptography.Xml { } [Test] - [ExpectedException (typeof (CryptographicException))] - public void VerifyHMAC_HMACOutputLength_Signature_Mismatch () + public void CheckSignature_WhenSignatureLengthIsGreaterThanHmacOutputLength_ThrowsCryptographicException () { string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?> <Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""> @@ -1582,13 +1522,15 @@ namespace MonoTests.System.Security.Cryptography.Xml { <Object Id=""object"">some other text</Object> </Signature> "; - SignedXml sign = GetSignedXml (xml); - sign.CheckSignature (new HMACSHA1 (Encoding.ASCII.GetBytes ("no clue"))); + var sut = GetSignedXml (xml); + sut.SignatureFormatValidator = null; + + var ex = Assert.Throws<CryptographicException> (() => sut.CheckSignature (new HMACSHA1 (Encoding.ASCII.GetBytes ("no clue"))), "Exception"); + Assert.That (ex.Message, Is.StringContaining ("length of the signature").IgnoreCase, "Message"); } [Test] - [ExpectedException (typeof (FormatException))] - public void VerifyHMAC_HMACOutputLength_Invalid () + public void CheckSignature_WhenHmacOutputLengthIsInvalid_ThrowsFormatException () { string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?> <Signature xmlns=""http://www.w3.org/2000/09/xmldsig#""> @@ -1607,8 +1549,10 @@ namespace MonoTests.System.Security.Cryptography.Xml { <Object Id=""object"">some other text</Object> </Signature> "; - SignedXml sign = GetSignedXml (xml); - sign.CheckSignature (new HMACSHA1 (Encoding.ASCII.GetBytes ("no clue"))); + var sut = GetSignedXml (xml); + sut.SignatureFormatValidator = null; + + Assert.Throws<FormatException> (() => sut.CheckSignature (new HMACSHA1 (Encoding.ASCII.GetBytes ("no clue")))); } [Test] @@ -1628,7 +1572,7 @@ namespace MonoTests.System.Security.Cryptography.Xml { } [Test] - public void ComputeSignature_WhenSignatureMethodIsNotSpecifiedAndRsaSigningKeyIsUsed_UsesRsaSha1Algorithm () + public void ComputeSignature_WhenSignatureMethodIsNotSpecifiedAndRsaSigningKeyIsUsed_UsesRsaSha256Algorithm () { var unsignedXml = new XmlDocument (); unsignedXml.LoadXml ("<test />"); @@ -1651,7 +1595,7 @@ namespace MonoTests.System.Security.Cryptography.Xml { string.Format ("/{0}:SignedInfo/{0}:SignatureMethod", XmlDsigNamespacePrefix), namespaceManager); - Assert.That (signatureMethodElement.Attributes["Algorithm"].Value, Is.EqualTo (SignedXml.XmlDsigRSASHA1Url)); + Assert.That (signatureMethodElement.Attributes["Algorithm"].Value, Is.EqualTo (SignedXml.XmlDsigRSASHA256Url)); } [Test] diff --git a/mcs/class/System.Security/common_System.Security.dll.sources b/mcs/class/System.Security/common_System.Security.dll.sources index 5a34119a3ad..321dc74da7c 100644 --- a/mcs/class/System.Security/common_System.Security.dll.sources +++ b/mcs/class/System.Security/common_System.Security.dll.sources @@ -1,12 +1,18 @@ Assembly/AssemblyInfo.cs +corefx/SR.cs + ../../build/common/Consts.cs ../../build/common/Locale.cs ../../build/common/MonoTODOAttribute.cs + +# System.Security.Cryptography System.Security.Cryptography/CryptographicAttribute.cs System.Security.Cryptography/CryptographicAttributeCollection.cs System.Security.Cryptography/CryptographicAttributeEnumerator.cs System.Security.Cryptography/DataProtectionScope.cs System.Security.Cryptography/ProtectedData.cs + +# System.Security.Cryptography.Pkcs System.Security.Cryptography.Pkcs/AlgorithmIdentifier.cs System.Security.Cryptography.Pkcs/CmsRecipient.cs System.Security.Cryptography.Pkcs/CmsRecipientCollection.cs @@ -30,5 +36,6 @@ System.Security.Cryptography.Pkcs/SubjectIdentifier.cs System.Security.Cryptography.Pkcs/SubjectIdentifierOrKey.cs System.Security.Cryptography.Pkcs/SubjectIdentifierOrKeyType.cs System.Security.Cryptography.Pkcs/SubjectIdentifierType.cs -System.Security.Cryptography.Xml/X509IssuerSerial.cs +# System.Security.Cryptography.Xml +../../../external/corefx/src/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/X509IssuerSerial.cs |