diff options
Diffstat (limited to 'mcs/class/System.Security/System.Security.Cryptography.Xml')
23 files changed, 2463 insertions, 0 deletions
diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/ChangeLog b/mcs/class/System.Security/System.Security.Cryptography.Xml/ChangeLog new file mode 100644 index 00000000000..8b7882eea4d --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/ChangeLog @@ -0,0 +1,48 @@ +2003-01-17 Sebastien Pouliot <spouliot@videotron.ca> + + * KeyInfo.cs: Changed some protected declaration to private. + * KeyInfoName.cs: Changed some protected declaration to private. + * KeyInfoNode.cs: Changed some protected declaration to private. + * KeyInfoRetrievalMethod.cs: Changed some protected declaration to private. + * KeyInfoX509Data.cs: Changed some protected declaration to private. + * Transform.cs: Changed some protected declaration to private. + * XmlDsigBase64Transform.cs: Changed some protected declaration to private. + * XmlDsigC14NTransform.cs: Changed some protected declaration to private. + * XmlDsigC14NWithCommentsTransform.cs: Changed some protected declaration to private. + * XmlDsigEnvelopedSignatureTransform.cs: Changed some protected declaration to private. + * XmlDsigXPathTransform.cs: Changed some protected declaration to private. + * XmlDsigXsltTransform.cs: Changed some protected declaration to private. + +2002-11-28 Sebastien Pouliot <spouliot@videotron.ca> + + * TODOAttribute.cs: New. Still much to do ;-) + * XmlDsigXPathTransform.cs: Corrected to compile. Transform is non- + functionnal. + * XmlDsigXsltTransform.cs: Corrected to compile. Transform is non- + functionnal. + +2002-11-20 Sebastien Pouliot <spouliot@videotron.ca> + + * DataObject.cs: New. Complete implementation. + * DSAKeyValue.cs: New. Complete implementation. + * KeyInfo.cs: New. Complete implementation. + * KeyInfoClause.cs: New. Abstract class (complete). + * KeyInfoName.cs: New. Complete implementation. + * KeyInfoNode.cs: New. Complete implementation. + * KeyInfoRetrievalMethod.cs: New. Complete implementation. + * KeyInfoX509Data.cs: New. Complete implementation. + * Reference.cs: New. Incomplete implementation. + * RSAKeyValue.cs: New. Complete implementation. + * Signature.cs: New. Almost complete implementation - returned + XML isn't exactly like the MS implementation. + * SignedInfo.cs: New. Complete except SignatureLength. + * SignedXml.cs: New. Minimal implementation (only enveloped signatures). + Still many TODO! + * Transform.cs: New. Abstract class (complete). + * TransformChain.cs: New. Complete implementation. + * XmlDsigBase64Transform.cs: New. Stub + basic logic. + * XmlDsigC14NTransform.cs: New. Stub + basic logic. + * XmlDsigC14NWithCommentsTransform.cs: New. Stub + basic logic. + * XmlDsigEnvelopedSignatureTransform.cs: New. Stub + basic logic. + * XmlDsigXPathTransform.cs: New. Stub + basic logic. + * XmlDsigXsltTransform.cs: New. Stub + basic logic. diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/DSAKeyValue.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/DSAKeyValue.cs new file mode 100644 index 00000000000..e451cd16596 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/DSAKeyValue.cs @@ -0,0 +1,60 @@ +// +// DSAKeyValue.cs - DSAKeyInfo implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Security.Cryptography; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class DSAKeyValue : KeyInfoClause { + + private DSA dsa; + + public DSAKeyValue () + { + dsa = DSA.Create (); + } + + public DSAKeyValue (DSA key) + { + dsa = key; + } + + public DSA Key + { + get { return dsa; } + set { dsa = value; } + } + + public override XmlElement GetXml () + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<KeyValue xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"); + sb.Append (dsa.ToXmlString (false)); + sb.Append ("</KeyValue>"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml(sb.ToString ()); + return doc.DocumentElement; + } + + public override void LoadXml (XmlElement value) + { + if (value == null) + throw new ArgumentNullException (); + + if ((value.LocalName == "KeyValue") && (value.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#")) + dsa.FromXmlString (value.InnerXml); + else + throw new CryptographicException ("value"); + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/DataObject.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/DataObject.cs new file mode 100644 index 00000000000..609bd452a23 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/DataObject.cs @@ -0,0 +1,162 @@ +// +// DataObject.cs - DataObject implementation for XML Signature +// http://www.w3.org/2000/09/xmldsig#Object +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Security.Cryptography; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +// XmlElement part of the signature +// Note: Looks like KeyInfoNode (but the later is XmlElement inside KeyInfo) +// required for "enveloping signatures" +public class DataObject { + + private string id; + private string mimeType; + private string encoding; + private string data; + private XmlDocument doc; + + static private string xmldsig = "http://www.w3.org/2000/09/xmldsig#"; + + public DataObject () + { + Build (null, null, null, null); + } + + public DataObject (string id, string mimeType, string encoding, XmlElement data) + { + if (data == null) + throw new ArgumentNullException ("data"); + + Build (id, mimeType, encoding, data); + } + + private void Build (string id, string mimeType, string encoding, XmlElement data) + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<Object "); + if (id != null) { + this.id = id; + sb.Append ("Id=\""); + sb.Append (id); + sb.Append ("\" "); + } + if (mimeType != null) { + this.mimeType = mimeType; + sb.Append ("MimeType=\""); + sb.Append (mimeType); + sb.Append ("\" "); + } + if (encoding != null) { + this.encoding = encoding; + sb.Append ("Encoding=\""); + sb.Append (encoding); + sb.Append ("\" "); + } + sb.Append ("xmlns=\"http://www.w3.org/2000/09/xmldsig#\" />"); + + doc = new XmlDocument (); + doc.LoadXml (sb.ToString ()); + if (data != null) { + XmlNodeList xnl = doc.GetElementsByTagName ("Object"); + XmlNode newNode = doc.ImportNode (data, true); + xnl[0].AppendChild (newNode); + } + } + + // why is data a XmlNodeList instead of a XmlElement ? + public XmlNodeList Data { + get { + XmlNodeList xnl = doc.GetElementsByTagName ("Object"); + return xnl[0].ChildNodes; + } + set { + if (value == null) + throw new ArgumentNullException ("value"); + + Build (id, mimeType, encoding, null); + XmlNodeList xnl = doc.GetElementsByTagName ("Object"); + if ((xnl != null) && (xnl.Count > 0)) { + foreach (XmlNode xn in value) { + XmlNode newNode = doc.ImportNode (xn, true); + xnl[0].AppendChild (newNode); + } + } + } + } + + // default to null - no encoding + public string Encoding { + get { return encoding; } + set { encoding = value; } + } + + // default to null + public string Id { + get { return id; } + set { id = value; } + } + + // default to null + public string MimeType { + get { return mimeType; } + set { mimeType = value; } + } + + public XmlElement GetXml () + { + if ((doc.DocumentElement.LocalName == "Object") && (doc.DocumentElement.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#")) { + // recreate all attributes in order + XmlAttribute xa = null; + doc.DocumentElement.Attributes.RemoveAll (); + if (id != null) { + xa = doc.CreateAttribute ("Id"); + xa.Value = id; + doc.DocumentElement.Attributes.Append (xa); + } + if (mimeType != null) { + xa = doc.CreateAttribute ("MimeType"); + xa.Value = mimeType; + doc.DocumentElement.Attributes.Append (xa); + } + if (encoding != null) { + xa = doc.CreateAttribute ("Encoding"); + xa.Value = encoding; + doc.DocumentElement.Attributes.Append (xa); + } + xa = doc.CreateAttribute ("xmlns"); + xa.Value = xmldsig; + doc.DocumentElement.Attributes.Append (xa); + } + return doc.DocumentElement; + } + + public void LoadXml (XmlElement value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + if ((value.LocalName == "Object") && (value.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#")) { + doc.LoadXml (value.OuterXml); + XmlAttribute xa = value.Attributes ["Id"]; + id = ((xa != null) ? xa.InnerText : null); + xa = value.Attributes ["MimeType"]; + mimeType = ((xa != null) ? xa.InnerText : null); + xa = value.Attributes ["Encoding"]; + encoding = ((xa != null) ? xa.InnerText : null); + } + else + doc.LoadXml (value.OuterXml); + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfo.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfo.cs new file mode 100644 index 00000000000..9ce4bc4162f --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfo.cs @@ -0,0 +1,136 @@ +// +// KeyInfo.cs - Xml Signature KeyInfo implementation +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Collections; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class KeyInfo : IEnumerable { + + static private string xmldsig = "http://www.w3.org/2000/09/xmldsig#"; + + private ArrayList Info; + private string id; + + public KeyInfo() + { + Info = new ArrayList (); + } + + public int Count { + get { return Info.Count; } + } + + public string Id { + get { return id; } + set { id = value; } + } + + public void AddClause (KeyInfoClause clause) + { + Info.Add (clause); + } + + public IEnumerator GetEnumerator () + { + return Info.GetEnumerator (); + } + + public IEnumerator GetEnumerator (Type requestedObjectType) + { + // Build a new ArrayList... + ArrayList TypeList = new ArrayList (); + IEnumerator e = Info.GetEnumerator (); + while (true) { + // ...with all object of specified type... + if ((e.Current).GetType().Equals (requestedObjectType)) + TypeList.Add (e.Current); + if (!e.MoveNext ()) + break; + } + // ...and return its enumerator + return TypeList.GetEnumerator (); + } + + public XmlElement GetXml () + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<KeyInfo xmlns=\""); + sb.Append (xmldsig); + sb.Append ("\" />"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml (sb.ToString ()); + // we add References afterward so we don't end up with extraneous + // xmlns="..." in each reference elements. + foreach (KeyInfoClause kic in Info) { + XmlNode xn = kic.GetXml (); + XmlNode newNode = doc.ImportNode (xn, true); + doc.DocumentElement.AppendChild (newNode); + } + return doc.DocumentElement; + } + + public void LoadXml (XmlElement value) + { + if (value == null) + throw new ArgumentNullException ("value"); + + if ((value.LocalName == "KeyInfo") && (value.NamespaceURI == xmldsig)) { + foreach (XmlNode n in value.ChildNodes) { + KeyInfoClause kic = null; + if (n is XmlWhitespace) + continue; + + switch (n.LocalName) { + case "KeyValue": + XmlNodeList xnl = n.ChildNodes; + if (xnl.Count > 0) { + // we must now treat the whitespace ! + foreach (XmlNode m in xnl) { + switch (m.LocalName) { + case "DSAKeyValue": + kic = (KeyInfoClause) new DSAKeyValue (); + break; + case "RSAKeyValue": + kic = (KeyInfoClause) new RSAKeyValue (); + break; + } + } + } + break; + case "KeyName": + kic = (KeyInfoClause) new KeyInfoName (); + break; + case "RetrievalMethod": + kic = (KeyInfoClause) new KeyInfoRetrievalMethod (); + break; + case "X509Data": + kic = (KeyInfoClause) new KeyInfoX509Data (); + break; + case "RSAKeyValue": + kic = (KeyInfoClause) new RSAKeyValue (); + break; + default: + kic = (KeyInfoClause) new KeyInfoNode (); + break; + } + + if (kic != null) { + kic.LoadXml ((XmlElement) n); + AddClause (kic); + } + } + } + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoClause.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoClause.cs new file mode 100644 index 00000000000..a4851412e5f --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoClause.cs @@ -0,0 +1,23 @@ +// +// KeyInfoClause.cs - Abstract KeyInfoClause implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public abstract class KeyInfoClause { + + public KeyInfoClause () {} + + public abstract XmlElement GetXml (); + + public abstract void LoadXml (XmlElement element); +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoName.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoName.cs new file mode 100644 index 00000000000..4537e3dc631 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoName.cs @@ -0,0 +1,50 @@ +// +// KeyInfoName.cs - KeyInfoName implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class KeyInfoName : KeyInfoClause { + + private string Name; + + public KeyInfoName() {} + + public string Value { + get { return Name; } + set { Name = value; } + } + + public override XmlElement GetXml () + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<KeyName xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"); + sb.Append (Name); + sb.Append ("</KeyName>"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml(sb.ToString ()); + return doc.DocumentElement; + } + + public override void LoadXml (XmlElement value) + { + if (value == null) + throw new ArgumentNullException (); + + if ((value.LocalName == "KeyName") && (value.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#")) + Name = value.InnerXml; + else + Name = null; + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoNode.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoNode.cs new file mode 100644 index 00000000000..4e0eef0199f --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoNode.cs @@ -0,0 +1,43 @@ +// +// KeyInfoNode.cs - KeyInfoNode implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class KeyInfoNode : KeyInfoClause { + + private XmlElement Node; + + public KeyInfoNode () {} + + public KeyInfoNode (XmlElement node) + { + LoadXml (node); + } + + public XmlElement Value { + get { return Node; } + set { Node = value; } + } + + public override XmlElement GetXml () + { + return Node; + } + + // LAMESPEC: No ArgumentNullException is thrown if value == null + public override void LoadXml (XmlElement value) + { + Node = value; + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoRetrievalMethod.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoRetrievalMethod.cs new file mode 100644 index 00000000000..ae7c2aa268c --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoRetrievalMethod.cs @@ -0,0 +1,60 @@ +// +// KeyInfoRetrievalMethod.cs - KeyInfoRetrievalMethod implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class KeyInfoRetrievalMethod : KeyInfoClause { + + private string URI; + + public KeyInfoRetrievalMethod () {} + + public KeyInfoRetrievalMethod (string strUri) + { + URI = strUri; + } + + public string Uri { + get { return URI; } + set { URI = value; } + } + + public override XmlElement GetXml () + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<RetrievalElement "); + if (URI != null) { + sb.Append ("URI=\""); + sb.Append (URI); + sb.Append ("\" "); + } + sb.Append ("xmlns=\"http://www.w3.org/2000/09/xmldsig#\" />"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml(sb.ToString ()); + return doc.DocumentElement; + } + + public override void LoadXml (XmlElement value) + { + if (value == null) + throw new ArgumentNullException (); + + if ((value.LocalName == "RetrievalElement") && (value.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#")) { + URI = value.Attributes["URI"].Value; + } + else + URI = ""; // not null - so we return URI="" as attribute !!! + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoX509Data.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoX509Data.cs new file mode 100644 index 00000000000..09a742fe739 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/KeyInfoX509Data.cs @@ -0,0 +1,214 @@ +// +// KeyInfoX509Data.cs - KeyInfoX509Data implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Collections; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +// FIXME: framework class isn't documented so compatibility isn't assured! +internal class IssuerSerial { + public string Issuer; + public string Serial; + + public IssuerSerial (string issuer, string serial) + { + Issuer = issuer; + Serial = serial; + } +} + +public class KeyInfoX509Data : KeyInfoClause { + + private byte[] x509crl; + private ArrayList IssuerSerialList; + private ArrayList SubjectKeyIdList; + private ArrayList SubjectNameList; + private ArrayList X509CertificateList; + + public KeyInfoX509Data () + { + IssuerSerialList = new ArrayList (); + SubjectKeyIdList = new ArrayList (); + SubjectNameList = new ArrayList (); + X509CertificateList = new ArrayList (); + } + + public KeyInfoX509Data (byte[] rgbCert) : this () + { + AddCertificate (new X509Certificate (rgbCert)); + } + + public KeyInfoX509Data (X509Certificate cert) : this () + { + AddCertificate (cert); + } + + 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) + { + X509CertificateList.Add (certificate); + } + + public void AddIssuerSerial (string issuerName, string serialNumber) + { + IssuerSerial isser = new IssuerSerial (issuerName, serialNumber); + IssuerSerialList.Add (isser); + } + + public void AddSubjectKeyId (byte[] subjectKeyId) + { + SubjectKeyIdList.Add (subjectKeyId); + } + + public void AddSubjectName (string subjectName) + { + SubjectNameList.Add (subjectName); + } + + public override XmlElement GetXml () + { + // sanity check + int count = IssuerSerialList.Count + SubjectKeyIdList.Count + SubjectNameList.Count + X509CertificateList.Count; + if ((x509crl == null) && (count == 0)) + throw new CryptographicException ("value"); + + StringBuilder sb = new StringBuilder (); + sb.Append ("<X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"); + // <X509IssuerSerial> + if (IssuerSerialList.Count > 0) { + sb.Append ("<X509IssuerSerial>"); + foreach (IssuerSerial iser in IssuerSerialList) { + sb.Append ("<X509IssuerName>"); + sb.Append (iser.Issuer); + sb.Append ("</X509IssuerName>"); + sb.Append ("<X509SerialNumber>"); + sb.Append (iser.Serial); + sb.Append ("</X509SerialNumber>"); + } + sb.Append ("</X509IssuerSerial>"); + } + // <X509SKI> + if (SubjectKeyIdList.Count > 0) { + foreach (byte[] skid in SubjectKeyIdList) { + sb.Append ("<X509SKI>"); + sb.Append (Convert.ToBase64String (skid)); + sb.Append ("</X509SKI>"); + } + } + // <X509SubjectName> + if (SubjectNameList.Count > 0) { + foreach (string subject in SubjectNameList) { + sb.Append ("<X509SubjectName>"); + sb.Append (subject); + sb.Append ("</X509SubjectName>"); + } + } + // <X509Certificate> + if (X509CertificateList.Count > 0) { + foreach (X509Certificate x509 in X509CertificateList) { + sb.Append ("<X509Certificate>"); + sb.Append (Convert.ToBase64String (x509.GetRawCertData ())); + sb.Append ("</X509Certificate>"); + } + } + // only one <X509CRL> + if (x509crl != null) { + sb.Append ("<X509CRL>"); + sb.Append (Convert.ToBase64String (x509crl)); + sb.Append ("</X509CRL>"); + } + sb.Append ("</X509Data>"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml(sb.ToString ()); + return doc.DocumentElement; + } + + public override void LoadXml (XmlElement element) + { + if (element == null) + throw new ArgumentNullException ("element"); + + IssuerSerialList.Clear (); + SubjectKeyIdList.Clear (); + SubjectNameList.Clear (); + X509CertificateList.Clear (); + x509crl = null; + + string ns = "http://www.w3.org/2000/09/xmldsig#"; + if ((element.LocalName == "X509Data") && (element.NamespaceURI == ns)) { + XmlNodeList xnl = null; + // <X509IssuerSerial> + xnl = element.GetElementsByTagName ("X509IssuerSerial", ns); + if (xnl != null) { + for (int i=0; i < xnl.Count; i++) { + XmlElement xel = (XmlElement) xnl[i]; + XmlNodeList issuer = xel.GetElementsByTagName ("X509IssuerName", ns); + XmlNodeList serial = xel.GetElementsByTagName ("X509SerialNumber", ns); + AddIssuerSerial (issuer[0].InnerText, serial[0].InnerText); + } + } + // <X509SKI> + xnl = element.GetElementsByTagName ("X509SKI", ns); + if (xnl != null) { + for (int i=0; i < xnl.Count; i++) { + byte[] skid = Convert.FromBase64String (xnl[i].InnerXml); + AddSubjectKeyId (skid); + } + } + // <X509SubjectName> + xnl = element.GetElementsByTagName ("X509SubjectName", ns); + if (xnl != null) { + for (int i=0; i < xnl.Count; i++) { + AddSubjectName (xnl[i].InnerXml); + } + } + // <X509Certificate> + xnl = element.GetElementsByTagName ("X509Certificate", ns); + if (xnl != null) { + for (int i=0; i < xnl.Count; i++) { + byte[] cert = Convert.FromBase64String (xnl[i].InnerXml); + AddCertificate (new X509Certificate (cert)); + } + } + // only one <X509CRL> + xnl = element.GetElementsByTagName ("X509CRL", ns); + if ((xnl != null) && (xnl.Count > 0)) { + x509crl = Convert.FromBase64String (xnl[0].InnerXml); + } + } + else + throw new CryptographicException ("element"); + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/RSAKeyValue.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/RSAKeyValue.cs new file mode 100644 index 00000000000..20c40c8506a --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/RSAKeyValue.cs @@ -0,0 +1,58 @@ +// +// RSAKeyValue.cs - RSAKeyValue implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class RSAKeyValue : KeyInfoClause { + + private RSA rsa; + + public RSAKeyValue () + { + rsa = RSA.Create (); + } + + public RSAKeyValue (RSA key) + { + rsa = key; + } + + public RSA Key { + get { return rsa; } + set { rsa = value; } + } + + public override XmlElement GetXml () + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<KeyValue xmlns=\"http://www.w3.org/2000/09/xmldsig#\">"); + sb.Append (rsa.ToXmlString (false)); + sb.Append ("</KeyValue>"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml(sb.ToString ()); + return doc.DocumentElement; + } + + public override void LoadXml (XmlElement value) + { + if (value == null) + throw new ArgumentNullException (); + + if ((value.LocalName == "KeyValue") && (value.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#")) + rsa.FromXmlString (value.InnerXml); + else + throw new CryptographicException ("value"); + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/Reference.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/Reference.cs new file mode 100644 index 00000000000..4dde3c48a0f --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/Reference.cs @@ -0,0 +1,209 @@ +// +// Reference.cs - Reference implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Collections; +using System.IO; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +// http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/Overview.html#sec-Reference +public class Reference { + + private TransformChain chain; + private string digestMethod; + private byte[] digestValue; + private string id; + private string uri; + private string type; + private HashAlgorithm hash; + + static private string xmldsig = "http://www.w3.org/2000/09/xmldsig#"; + static private string sha1 = xmldsig + "sha1"; + + public Reference () + { + chain = new TransformChain (); + digestMethod = sha1; + } + + public Reference (Stream stream) : this () + { + } + + public Reference (string uri) : this () + { + this.uri = uri; + } + + // default to SHA1 + public string DigestMethod { + get { return digestMethod; } + set { digestMethod = value; } + } + + public byte[] DigestValue { + get { return digestValue; } + set { digestValue = value; } + } + + public string Id { + get { return id; } + set { id = value; } + } + + public TransformChain TransformChain { + get { return chain; } + } + + public string Type { + get { return type; } + set { type = value; } + } + + public string Uri { + get { return uri; } + set { uri = value; } + } + + public void AddTransform (Transform transform) + { + chain.Add (transform); + } + + public XmlElement GetXml () + { + if (digestMethod == null) + throw new CryptographicException ("DigestMethod"); + if (digestValue == null) + throw new NullReferenceException ("DigestValue"); + + StringBuilder sb = new StringBuilder (); + sb.Append ("<Reference"); + if (id != null) { + sb.Append (" Id=\""); + sb.Append (id); + sb.Append ("\""); + } + if (uri != null) { + sb.Append (" URI=\""); + sb.Append (uri); + sb.Append ("\""); + } + if (type != null) { + sb.Append (" Type=\""); + sb.Append (type); + sb.Append ("\""); + } + sb.Append (" xmlns=\""); + sb.Append (xmldsig); + sb.Append ("\" >"); + + if (chain.Count > 0) { + sb.Append ("<Transforms>"); + sb.Append ("</Transforms>"); + } + + sb.Append ("<DigestMethod Algorithm=\""); + sb.Append (digestMethod); + sb.Append ("\" />"); + sb.Append ("<DigestValue>"); + sb.Append (Convert.ToBase64String (digestValue)); + sb.Append ("</DigestValue>"); + sb.Append ("</Reference>"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml (sb.ToString ()); + + if (chain.Count > 0) { + XmlNodeList xnl = doc.GetElementsByTagName ("Transforms"); + foreach (Transform t in chain) { + XmlNode xn = t.GetXml (); + XmlNode newNode = doc.ImportNode (xn, true); + xnl[0].AppendChild (newNode); + } + } + + return doc.DocumentElement; + } + + private string GetAttributeFromElement (XmlElement xel, string attribute, string element) + { + string result = null; + XmlNodeList xnl = xel.GetElementsByTagName (element); + if ((xnl != null) && (xnl.Count > 0)) { + XmlAttribute xa = xnl[0].Attributes [attribute]; + if (xa != null) + result = xa.InnerText; + } + return result; + } + + // note: we do NOT return null -on purpose- if attribute isn't found + 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 == "Reference") && (value.NamespaceURI == xmldsig)) { + id = GetAttribute (value, "Id"); + uri = GetAttribute (value, "URI"); + type = GetAttribute (value, "Type"); + // Note: order is important for validations + XmlNodeList xnl = value.GetElementsByTagName ("Transform"); + if ((xnl != null) && (xnl.Count > 0)) { + Transform t = null; + foreach (XmlNode xn in xnl) { + string a = GetAttribute ((XmlElement)xn, "Algorithm"); + switch (a) { + case "http://www.w3.org/2000/09/xmldsig#base64": + t = new XmlDsigBase64Transform (); + break; + case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315": + t = new XmlDsigC14NTransform (); + break; + case "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments": + t = new XmlDsigC14NWithCommentsTransform (); + break; + case "http://www.w3.org/2000/09/xmldsig#enveloped-signature": + t = new XmlDsigEnvelopedSignatureTransform (); + break; + case "http://www.w3.org/TR/1999/REC-xpath-19991116": + t = new XmlDsigXPathTransform (); + break; + case "http://www.w3.org/TR/1999/REC-xslt-19991116": + t = new XmlDsigXsltTransform (); + break; + default: + throw new NotSupportedException (); + } + AddTransform (t); + } + } + // get DigestMethod + DigestMethod = GetAttributeFromElement (value, "Algorithm", "DigestMethod"); + // get DigestValue + xnl = value.GetElementsByTagName ("DigestValue"); + if ((xnl != null) && (xnl.Count > 0)) { + DigestValue = Convert.FromBase64String (xnl[0].InnerText); + } + } + else + throw new CryptographicException (); + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/Signature.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/Signature.cs new file mode 100644 index 00000000000..1712a31f5b1 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/Signature.cs @@ -0,0 +1,171 @@ +// +// Signature.cs - Signature implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Collections; +using System.Security.Cryptography; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class Signature { + + private ArrayList list; + private SignedInfo info; + private KeyInfo key; + private string id; + private byte[] signature; + + static private string xmldsig = "http://www.w3.org/2000/09/xmldsig#"; + + public Signature() + { + list = new ArrayList (); + } + + public string Id { + get { return id; } + set { id = value; } + } + + public KeyInfo KeyInfo { + get { return key; } + set { key = value; } + } + + public IList ObjectList { + get { return list; } + set { list = ArrayList.Adapter (value); } + } + + public byte[] SignatureValue { + get { return signature; } + set { signature = value; } + } + + public SignedInfo SignedInfo { + get { return info; } + set { info = value; } + } + + public void AddObject (DataObject dataObject) + { + list.Add (dataObject); + } + + public XmlElement GetXml () + { + if (info == null) + throw new CryptographicException ("SignedInfo"); + if (signature == null) + throw new CryptographicException ("SignatureValue"); + + StringBuilder sb = new StringBuilder (); + sb.Append ("<Signature"); + if (id != null) { + sb.Append (" Id = \""); + sb.Append (id); + sb.Append ("\""); + } + sb.Append (" xmlns=\""); + sb.Append (xmldsig); +/* if (info != null) { + sb.Append ("\">"); + sb.Append (info.GetXml ().OuterXml); + sb.Append ("</Signature>"); + } + else*/ + sb.Append ("\" />"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml (sb.ToString ()); + + XmlNode xn = null; + XmlNode newNode = null; + + if (info != null) { + // this adds the xmlns=xmldsig + xn = info.GetXml (); + newNode = doc.ImportNode (xn, true); + doc.DocumentElement.AppendChild (newNode); + } + + if (signature != null) { + XmlElement sv = doc.CreateElement ("SignatureValue", xmldsig); + sv.InnerText = Convert.ToBase64String (signature); + doc.DocumentElement.AppendChild (sv); + } + + if (key != null) { + xn = key.GetXml (); + newNode = doc.ImportNode (xn, true); + doc.DocumentElement.AppendChild (newNode); + } + + if (list.Count > 0) { + foreach (DataObject obj in list) { + xn = obj.GetXml (); + newNode = doc.ImportNode (xn, true); + doc.DocumentElement.AppendChild (newNode); + } + } + + return doc.DocumentElement; + } + + 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 == "Signature") && (value.NamespaceURI == xmldsig)) { + id = GetAttribute (value, "Id"); + + XmlNodeList xnl = value.GetElementsByTagName ("SignedInfo"); + if ((xnl != null) && (xnl.Count == 1)) { + info = new SignedInfo (); + info.LoadXml ((XmlElement) xnl[0]); + } + + xnl = value.GetElementsByTagName ("SignatureValue"); + if ((xnl != null) && (xnl.Count == 1)) { + signature = Convert.FromBase64String (xnl[0].InnerText); + } + + xnl = value.GetElementsByTagName ("KeyInfo"); + if ((xnl != null) && (xnl.Count == 1)) { + key = new KeyInfo (); + key.LoadXml ((XmlElement) xnl[0]); + } + + xnl = value.GetElementsByTagName ("Object"); + if ((xnl != null) && (xnl.Count > 0)) { + foreach (XmlNode xn in xnl) { + DataObject obj = new DataObject (); + obj.LoadXml ((XmlElement) xn); + AddObject (obj); + } + } + } + + // if invalid + if (info == null) + throw new CryptographicException ("SignedInfo"); + if (signature == null) + throw new CryptographicException ("SignatureValue"); + } +} + +}
\ No newline at end of file diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedInfo.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedInfo.cs new file mode 100644 index 00000000000..a5d4b2b4e91 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedInfo.cs @@ -0,0 +1,182 @@ +// +// SignedInfo.cs - SignedInfo implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Collections; +using System.Text; +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; + + static private string xmldsig = "http://www.w3.org/2000/09/xmldsig#"; + + 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; } + } + + // documented as not supported (and throwing exception) + public int Count { + get { throw new NotSupportedException (); } + } + + public string Id { + get { return id; } + set { 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 (); } + } + + public ArrayList References { + get { return references; } + } + + public string SignatureLength { + get { return signatureLength; } + set { signatureLength = value; } + } + + public string SignatureMethod { + get { return signatureMethod; } + set { 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 (signatureMethod == null) + throw new CryptographicException ("SignatureMethod"); + if (references.Count == 0) + throw new CryptographicException ("References empty"); + + StringBuilder sb = new StringBuilder (); + sb.Append ("<SignedInfo"); + if (id != null) { + sb.Append (" Id=\""); + sb.Append (id); + sb.Append ("\""); + } + sb.Append (" xmlns=\""); + sb.Append (xmldsig); + sb.Append ("\">"); + if (c14nMethod != null) { + sb.Append ("<CanonicalizationMethod Algorithm=\""); + sb.Append (c14nMethod); + sb.Append ("\" />"); + } + if (signatureMethod != null) { + sb.Append ("<SignatureMethod Algorithm=\""); + sb.Append (signatureMethod); + if (signatureLength != null) { + sb.Append ("\">"); + sb.Append ("<HMACOutputLength>"); + sb.Append (signatureLength); + sb.Append ("</HMACOutputLength>"); + sb.Append ("</SignatureMethod>"); + } + else + sb.Append ("\" />"); + } + sb.Append ("</SignedInfo>"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml (sb.ToString ()); + // 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 = doc.ImportNode (xn, true); + doc.DocumentElement.AppendChild (newNode); + } + + return doc.DocumentElement; + } + + private string GetAttributeFromElement (XmlElement xel, string attribute, string element) + { + string result = null; + XmlNodeList xnl = xel.GetElementsByTagName (element); + if ((xnl != null) && (xnl.Count > 0)) { + XmlAttribute xa = xnl[0].Attributes [attribute]; + if (xa != null) + result = xa.InnerText; + } + return result; + } + + 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 == "SignedInfo") && (value.NamespaceURI == xmldsig)) { + id = GetAttribute (value, "Id"); + c14nMethod = GetAttributeFromElement (value, "Algorithm", "CanonicalizationMethod"); + signatureMethod = GetAttributeFromElement (value, "Algorithm", "SignatureMethod"); + // signatureLength for HMAC + XmlNodeList xnl = value.GetElementsByTagName ("Reference"); + foreach (XmlNode xn in xnl) { + Reference r = new Reference (); + r.LoadXml ((XmlElement) xn); + AddReference (r); + } + } + else + throw new CryptographicException (); + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedXml.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedXml.cs new file mode 100644 index 00000000000..fa054bc0b56 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/SignedXml.cs @@ -0,0 +1,354 @@ +// +// SignedXml.cs - SignedXml implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Collections; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class SignedXml { + + private Signature signature; + private AsymmetricAlgorithm key; + private string keyName; + private XmlDocument envdoc; + + public SignedXml () + { + signature = new Signature (); + signature.SignedInfo = new SignedInfo (); + } + + public SignedXml (XmlDocument document) + { + signature = new Signature (); + signature.SignedInfo = new SignedInfo (); + envdoc = document; + } + + public SignedXml (XmlElement elem) : this () + { + if (elem == null) + throw new ArgumentNullException ("elem"); + signature = new Signature (); + signature.SignedInfo = new SignedInfo (); + } + + public const string XmlDsigCanonicalizationUrl = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; + public const string XmlDsigCanonicalizationWithCommentsUrl = XmlDsigCanonicalizationUrl + "#WithComments"; + public const string XmlDsigNamespaceUrl = "http://www.w3.org/2000/09/xmldsig#"; + public const string XmlDsigDSAUrl = XmlDsigNamespaceUrl + "dsa-sha1"; + public const string XmlDsigHMACSHA1Url = XmlDsigNamespaceUrl + "hmac-sha1"; + public const string XmlDsigMinimalCanonicalizationUrl = XmlDsigNamespaceUrl + "minimal"; + public const string XmlDsigRSASHA1Url = XmlDsigNamespaceUrl + "rsa-sha1"; + public const string XmlDsigSHA1Url = XmlDsigNamespaceUrl + "sha1"; + + public KeyInfo KeyInfo { + get { return signature.KeyInfo; } + set { signature.KeyInfo = value; } + } + + public Signature Signature { + get { return signature; } + } + + public string SignatureLength { + get { return signature.SignedInfo.SignatureLength; } + } + + public string SignatureMethod { + get { return signature.SignedInfo.SignatureMethod; } + } + + public byte[] SignatureValue { + get { return signature.SignatureValue; } + } + + public SignedInfo SignedInfo { + get { return signature.SignedInfo; } + } + + public AsymmetricAlgorithm SigningKey { + get { return key; } + set { key = value; } + } + + public string SigningKeyName { + get { return keyName; } + set { keyName = value; } + } + + public void AddObject (DataObject dataObject) + { + signature.AddObject (dataObject); + } + + public void AddReference (Reference reference) + { + signature.SignedInfo.AddReference (reference); + } + + private Stream ApplyTransform (Transform t, XmlDocument doc) + { + t.LoadInput (doc); + if (t is XmlDsigEnvelopedSignatureTransform) { + XmlDocument d = (XmlDocument) t.GetOutput (); + MemoryStream ms = new MemoryStream (); + d.Save (ms); + return ms; + } + else + return (Stream) t.GetOutput (); + } + + private Stream ApplyTransform (Transform t, Stream s) + { + try { + t.LoadInput (s); + s = (Stream) t.GetOutput (); + } + catch (Exception e) { + string temp = e.ToString (); // stop debugger + } + return s; + } + + [MonoTODO("incomplete")] + private byte[] GetReferenceHash (Reference r) + { + XmlDocument doc = new XmlDocument (); + doc.PreserveWhitespace = true; + if (r.Uri == "") + doc = envdoc; + else { + foreach (DataObject obj in signature.ObjectList) { + if ("#" + obj.Id == r.Uri) { + doc.LoadXml (obj.GetXml ().OuterXml); + break; + } + } + } + + Stream s = null; + if (r.TransformChain.Count > 0) { + foreach (Transform t in r.TransformChain) { + if (s == null) + s = ApplyTransform (t, doc); + else + s = ApplyTransform (t, s); + } + } + else + s = ApplyTransform (new XmlDsigC14NTransform (), doc); + + // TODO: We should reuse the same hash object (when possible) + HashAlgorithm hash = (HashAlgorithm) CryptoConfig.CreateFromName (r.DigestMethod); + return hash.ComputeHash (s); + } + + private void DigestReferences () + { + // we must tell each reference which hash algorithm to use + // before asking for the SignedInfo XML ! + foreach (Reference r in signature.SignedInfo.References) { + // assume SHA-1 if nothing is specified + if (r.DigestMethod == null) + r.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1"; + r.DigestValue = GetReferenceHash (r); + } + } + + private Stream SignedInfoTransformed () + { + Transform t = (Transform) CryptoConfig.CreateFromName (signature.SignedInfo.CanonicalizationMethod); + if (t == null) + return null; + + XmlDocument doc = new XmlDocument (); + doc.LoadXml (signature.SignedInfo.GetXml ().OuterXml); + return ApplyTransform (t, doc); + } + + [MonoTODO("Become hash algorithm independant")] + private byte[] Hash () + { + // we must select the hash using ??? SignatureMethod (yuck) + // FIXME: Hardcoded to SHA1 - which is, right now, the only digest defined in XMLDSIG + SHA1 sha = SHA1.Create (); + // get the hash of the C14N SignedInfo element + return sha.ComputeHash (SignedInfoTransformed ()); + } + + public bool CheckSignature () + { + // CryptographicException + if (key == null) + key = GetPublicKey (); + return CheckSignature (key); + } + + private bool CheckReferenceIntegrity () + { + // check digest (hash) for every reference + foreach (Reference r in signature.SignedInfo.References) { + // stop at first broken reference + if (! Compare (r.DigestValue, GetReferenceHash (r))) + return false; + } + return true; + } + + public bool CheckSignature (AsymmetricAlgorithm key) + { + if (key == null) + throw new ArgumentNullException ("key"); + + // Part 1: Are all references digest valid ? + bool result = CheckReferenceIntegrity (); + if (result) { + // Part 2: Is the signature (over SignedInfo) valid ? + byte[] hash = Hash (); + AsymmetricSignatureDeformatter verifier = null; + + if (key is DSA) + verifier = new DSASignatureDeformatter (key); + else if (key is RSA) + verifier = new RSAPKCS1SignatureDeformatter (key); + else + result = false; + + if (verifier != null) { + verifier.SetHashAlgorithm ("SHA1"); + result = verifier.VerifySignature (hash, signature.SignatureValue); + } + } + + return result; + } + + private bool Compare (byte[] expected, byte[] actual) + { + 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]) + return false; + } + } + } + return result; + } + + public bool CheckSignature (KeyedHashAlgorithm macAlg) + { + if (macAlg == null) + throw new ArgumentNullException ("macAlg"); + + // Part 1: Are all references digest valid ? + bool result = CheckReferenceIntegrity (); + if (result) { + // Part 2: Is the signature (over SignedInfo) valid ? + byte[] actual = macAlg.ComputeHash (SignedInfoTransformed ()); + result = Compare (signature.SignatureValue, actual); + } + return result; + } + + public bool CheckSignatureReturningKey (out AsymmetricAlgorithm signingKey) + { + // here's the key used for verifying the signature + if (key == null) + key = GetPublicKey (); + signingKey = key; + // we'll find the key if we haven't already + return CheckSignature (key); + } + + public void ComputeSignature () + { + if (key != null) { + // required before hashing + signature.SignedInfo.SignatureMethod = key.SignatureAlgorithm; + DigestReferences (); + + // the hard part - C14Ning the KeyInfo + byte[] hash = Hash (); + AsymmetricSignatureFormatter signer = null; + + // in need for a CryptoConfig factory + if (key is DSA) + signer = new DSASignatureFormatter (key); + else if (key is RSA) + signer = new RSAPKCS1SignatureFormatter (key); + + if (signer != null) { + signer.SetHashAlgorithm ("SHA1"); + signature.SignatureValue = signer.CreateSignature (hash); + } + } + } + + public void ComputeSignature (KeyedHashAlgorithm macAlg) + { + if (macAlg == null) + throw new ArgumentNullException ("macAlg"); + + if (macAlg is HMACSHA1) { + DigestReferences (); + + signature.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#hmac-sha1"; + signature.SignatureValue = macAlg.ComputeHash (SignedInfoTransformed ()); + } + else + throw new CryptographicException ("unsupported algorithm"); + } + + // is that all ? + public virtual XmlElement GetIdElement (XmlDocument document, string idValue) + { + return document.GetElementById (idValue); + } + + protected virtual AsymmetricAlgorithm GetPublicKey () + { + AsymmetricAlgorithm key = null; + if (signature.KeyInfo != null) { + foreach (KeyInfoClause kic in signature.KeyInfo) { + if (kic is DSAKeyValue) + key = DSA.Create (); + else if (kic is RSAKeyValue) + key = RSA.Create (); + + if (key != null) { + key.FromXmlString (kic.GetXml ().InnerXml); + break; + } + } + } + return key; + } + + public XmlElement GetXml () + { + return signature.GetXml (); + } + + public void LoadXml (XmlElement value) + { + signature.LoadXml (value); + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/TODOAttribute.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/TODOAttribute.cs new file mode 100644 index 00000000000..0920ce8f92d --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/TODOAttribute.cs @@ -0,0 +1,37 @@ +// +// TODOAttribute.cs +// +// Author: +// Ravi Pratap (ravi@ximian.com) +// +// (C) Ximian, Inc. http://www.ximian.com +// + +namespace System { + + /// <summary> + /// The TODO attribute is used to flag all incomplete bits in our class libraries + /// </summary> + /// + /// <remarks> + /// Use this to decorate any element which you think is not complete + /// </remarks> + [AttributeUsage (AttributeTargets.All, AllowMultiple=true)] + public class MonoTODOAttribute : Attribute { + + private string comment; + + public MonoTODOAttribute () + {} + + public MonoTODOAttribute (string comment) + { + this.comment = comment; + } + + public string Comment + { + get { return comment; } + } + } +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/Transform.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/Transform.cs new file mode 100644 index 00000000000..32375dd6716 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/Transform.cs @@ -0,0 +1,57 @@ +// +// Transform.cs - Transform implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public abstract class Transform { + + private string algo; + + public Transform () {} + + public string Algorithm { + get { return algo; } + set { algo = value; } + } + + public abstract Type[] InputTypes { + get; + } + + public abstract Type[] OutputTypes { + get; + } + + protected abstract XmlNodeList GetInnerXml (); + + public abstract object GetOutput (); + + public abstract object GetOutput (Type type); + + public XmlElement GetXml () + { + StringBuilder sb = new StringBuilder (); + sb.Append ("<Transform Algorithm=\""); + sb.Append (algo); + sb.Append ("\"/>"); + + XmlDocument doc = new XmlDocument (); + doc.LoadXml (sb.ToString ()); + return doc.DocumentElement; + } + + public abstract void LoadInnerXml (XmlNodeList nodeList); + + public abstract void LoadInput (object obj); +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/TransformChain.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/TransformChain.cs new file mode 100644 index 00000000000..04e8696ecdb --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/TransformChain.cs @@ -0,0 +1,42 @@ +// +// TransformChain.cs - TransformChain implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.Collections; + +namespace System.Security.Cryptography.Xml { + +public class TransformChain { + + private ArrayList chain; + + public TransformChain() + { + chain = new ArrayList (); + } + + public int Count { + get { return chain.Count; } + } + + public Transform this [int index] { + get { return (Transform) chain [index]; } + } + + public void Add (Transform transform) + { + chain.Add (transform); + } + + public IEnumerator GetEnumerator () + { + return chain.GetEnumerator (); + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigBase64Transform.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigBase64Transform.cs new file mode 100644 index 00000000000..22fde9fd873 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigBase64Transform.cs @@ -0,0 +1,107 @@ +// +// XmlDsigBase64Transform.cs - Base64 Transform implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +// http://www.w3.org/2000/09/xmldsig#base64 +public class XmlDsigBase64Transform : Transform { + + private Type[] input; + private Type[] output; + private CryptoStream cs; + + public XmlDsigBase64Transform () + { + Algorithm = "http://www.w3.org/2000/09/xmldsig#base64"; + } + + public override Type[] InputTypes { + get { + if (input == null) { + lock (this) { + // this way the result is cached if called multiple time + input = new Type [3]; + input[0] = typeof (System.IO.Stream); + input[1] = typeof (System.Xml.XmlDocument); + input[2] = typeof (System.Xml.XmlNodeList); + } + } + return input; + } + } + + public override Type[] OutputTypes { + get { + if (output == null) { + lock (this) { + // this way the result is cached if called multiple time + output = new Type [1]; + output[0] = typeof (System.IO.Stream); + } + } + return output; + } + } + + protected override XmlNodeList GetInnerXml () + { + return null; // THIS IS DOCUMENTED AS SUCH + } + + public override object GetOutput () + { + return (object) cs; + } + + public override object GetOutput (Type type) + { + if (type != Type.GetType ("System.IO.Stream")) + throw new ArgumentException ("type"); + return GetOutput (); + } + + public override void LoadInnerXml (XmlNodeList nodeList) + { + // documented as not changing the state of the transform + } + + public override void LoadInput (object obj) + { + XmlNodeList xnl = null; + Stream stream = null; + + if (obj is Stream) + stream = (obj as Stream); + else if (obj is XmlDocument) + xnl = (obj as XmlDocument).ChildNodes; + else if (obj is XmlNodeList) + xnl = (XmlNodeList) obj; + + if (xnl != null) { + StringBuilder sb = new StringBuilder (); + foreach (XmlNode xn in xnl) + sb.Append (xn.InnerText); + + UTF8Encoding utf8 = new UTF8Encoding (); + byte[] data = utf8.GetBytes (sb.ToString ()); + stream = new MemoryStream (data); + } + + if (stream != null) + cs = new CryptoStream (stream, new FromBase64Transform (), CryptoStreamMode.Read); + // note: there is no default are other types won't throw an exception + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigC14NTransform.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigC14NTransform.cs new file mode 100644 index 00000000000..a689f0f118b --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigC14NTransform.cs @@ -0,0 +1,110 @@ +// +// XmlDsigC14NTransform.cs - C14N Transform implementation for XML Signature +// http://www.w3.org/TR/xml-c14n +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.IO; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class XmlDsigC14NTransform : Transform { + + private Type[] input; + private Type[] output; + private bool comments; + private Stream s; + + public XmlDsigC14NTransform () + { + Algorithm = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; + comments = false; + } + + public XmlDsigC14NTransform (bool includeComments) + { + comments = includeComments; + } + + public override Type[] InputTypes { + get { + if (input == null) { + lock (this) { + // this way the result is cached if called multiple time + input = new Type [3]; + input[0] = typeof (System.IO.Stream); + input[1] = typeof (System.Xml.XmlDocument); + input[2] = typeof (System.Xml.XmlNodeList); + } + } + return input; + } + } + + public override Type[] OutputTypes { + get { + if (output == null) { + lock (this) { + // this way the result is cached if called multiple time + output = new Type [1]; + output[0] = typeof (System.IO.Stream); + } + } + return output; + } + } + + protected override XmlNodeList GetInnerXml () + { + return null; // THIS IS DOCUMENTED AS SUCH + } + + public override object GetOutput () + { + return (object) s; + } + + public override object GetOutput (Type type) + { + if (type == Type.GetType ("Stream")) + return GetOutput (); + throw new ArgumentException ("type"); + } + + public override void LoadInnerXml (XmlNodeList nodeList) + { + // documented as not changing the state of the transform + } + + public override void LoadInput (object obj) + { + XmlNodeList xnl = null; + + if (obj is Stream) + s = (obj as Stream); + else if (obj is XmlDocument) + xnl = (obj as XmlDocument).ChildNodes; + else if (obj is XmlNodeList) + xnl = (XmlNodeList) obj; + + if (xnl != null) { + StringBuilder sb = new StringBuilder (); + foreach (XmlNode xn in xnl) + sb.Append (xn.InnerText); + + UTF8Encoding utf8 = new UTF8Encoding (); + byte[] data = utf8.GetBytes (sb.ToString ()); + s = new MemoryStream (data); + } + + // note: there is no default are other types won't throw an exception + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigC14NWithCommentsTransform.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigC14NWithCommentsTransform.cs new file mode 100644 index 00000000000..cc32ecf6152 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigC14NWithCommentsTransform.cs @@ -0,0 +1,21 @@ +// +// XmlDsigC14NWithCommentsTransform.cs - +// C14N with comments Transform implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.IO; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class XmlDsigC14NWithCommentsTransform : XmlDsigC14NTransform { + + public XmlDsigC14NWithCommentsTransform() : base (true) {} +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigEnvelopedSignatureTransform.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigEnvelopedSignatureTransform.cs new file mode 100644 index 00000000000..f67a8579d79 --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigEnvelopedSignatureTransform.cs @@ -0,0 +1,90 @@ +// +// XmlDsigEnvelopedSignatureTransform.cs - +// Enveloped Signature Transform implementation for XML Signature +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.IO; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +public class XmlDsigEnvelopedSignatureTransform : Transform { + + private Type[] input; + private Type[] output; + private bool comments; + + public XmlDsigEnvelopedSignatureTransform () + { + comments = false; + } + + public XmlDsigEnvelopedSignatureTransform (bool includeComments) + { + comments = includeComments; + } + + public override Type[] InputTypes { + get { + if (input == null) { + lock (this) { + // this way the result is cached if called multiple time + input = new Type [3]; + input[0] = typeof (System.IO.Stream); + input[1] = typeof (System.Xml.XmlDocument); + input[2] = typeof (System.Xml.XmlNodeList); + } + } + return input; + } + } + + public override Type[] OutputTypes { + get { + if (output == null) { + lock (this) { + // this way the result is cached if called multiple time + output = new Type [2]; + input[0] = typeof (System.Xml.XmlDocument); + input[1] = typeof (System.Xml.XmlNodeList); + } + } + return output; + } + } + + protected override XmlNodeList GetInnerXml () + { + return null; // THIS IS DOCUMENTED AS SUCH + } + + public override object GetOutput() + { +// return (object) new XmlNodeList (); + return null; + } + + public override object GetOutput (Type type) + { + if (type == Type.GetType ("Stream")) + return GetOutput (); + throw new ArgumentException ("type"); + } + + public override void LoadInnerXml (XmlNodeList nodeList) + { + // NO CHANGE + } + + public override void LoadInput (object obj) + { + // if (type.Equals (Stream.GetType ()) + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigXPathTransform.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigXPathTransform.cs new file mode 100644 index 00000000000..5c5fd963b8b --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigXPathTransform.cs @@ -0,0 +1,108 @@ +// +// XmlDsigXPathTransform.cs - +// XmlDsigXPathTransform implementation for XML Signature +// http://www.w3.org/TR/1999/REC-xpath-19991116 +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Xml; + +namespace System.Security.Cryptography.Xml { + +// www.w3.org/TR/xmldsig-core/ +// see Section 6.6.3 of the XMLDSIG specification +public class XmlDsigXPathTransform : Transform { + + private Type[] input; + private Type[] output; + private XmlNodeList xnl; + private XmlNodeList xpathNodes; + + public XmlDsigXPathTransform () + { + } + + public override Type[] InputTypes { + get { + if (input == null) { + lock (this) { + // this way the result is cached if called multiple time + input = new Type [3]; + input[0] = typeof (System.IO.Stream); + input[1] = typeof (System.Xml.XmlDocument); + input[2] = typeof (System.Xml.XmlNodeList); + } + } + return input; + } + } + + public override Type[] OutputTypes { + get { + if (output == null) { + lock (this) { + // this way the result is cached if called multiple time + output = new Type [1]; + output[0] = typeof (System.IO.Stream); + } + } + return output; + } + } + + protected override XmlNodeList GetInnerXml () + { + return xnl; + } + + public override object GetOutput () + { + return xpathNodes; + } + + public override object GetOutput (Type type) + { + if (type != typeof (XmlNodeList)) + throw new ArgumentException ("type"); + return GetOutput (); + } + + public override void LoadInnerXml (XmlNodeList nodeList) + { + if (nodeList == null) + throw new CryptographicException ("nodeList"); + xnl = nodeList; + } + + public override void LoadInput (object obj) + { + XmlNode xn = null; + // possible input: Stream, XmlDocument, and XmlNodeList + if (obj is Stream) { + XmlDocument doc = new XmlDocument (); + doc.Load (obj as Stream); + } + else if (obj is XmlDocument) { + } + else if (obj is XmlNodeList) { + xnl = (XmlNodeList) obj; + } + + if (xn != null) { + string xpath = xn.InnerXml; + // only possible output: XmlNodeList + xpathNodes = xnl[0].SelectNodes (xpath); + } + else + xpathNodes = null; + } +} + +} diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigXsltTransform.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigXsltTransform.cs new file mode 100644 index 00000000000..524541ea67c --- /dev/null +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/XmlDsigXsltTransform.cs @@ -0,0 +1,121 @@ +// +// XmlDsigEnvelopedSignatureTransform.cs - +// Enveloped Signature Transform implementation for XML Signature +// http://www.w3.org/TR/1999/REC-xslt-19991116 +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System.IO; +using System.Security.Cryptography; +using System.Xml; +using System.Xml.Xsl; + +namespace System.Security.Cryptography.Xml { + +public class XmlDsigXsltTransform : Transform { + + private Type[] input; + private Type[] output; + private bool comments; + private XmlNodeList xnl; + private CryptoStream cs; + + public XmlDsigXsltTransform () : this (false) {} + + public XmlDsigXsltTransform (bool includeComments) + { + comments = includeComments; + Algorithm = "http://www.w3.org/TR/1999/REC-xslt-19991116"; + } + + public override Type[] InputTypes { + get { + if (input == null) { + lock (this) { + // this way the result is cached if called multiple time + input = new Type [3]; + input[0] = typeof (System.IO.Stream); + input[1] = typeof (System.Xml.XmlDocument); + input[2] = typeof (System.Xml.XmlNodeList); + } + } + return input; + } + } + + public override Type[] OutputTypes { + get { + if (output == null) { + lock (this) { + // this way the result is cached if called multiple time + output = new Type [1]; + output[0] = typeof (System.IO.Stream); + } + } + return output; + } + } + + protected override XmlNodeList GetInnerXml () + { + return xnl; + } + + public override object GetOutput () + { + return (object) cs; + } + + public override object GetOutput (Type type) + { + if (type != Type.GetType ("System.IO.Stream")) + throw new ArgumentException ("type"); + return GetOutput (); + } + + public override void LoadInnerXml (XmlNodeList nodeList) + { + if (nodeList == null) + throw new CryptographicException ("nodeList"); + xnl = nodeList; + } + + [MonoTODO()] + public override void LoadInput (object obj) + { + XslTransform xsl = new XslTransform (); + XmlDocument doc = new XmlDocument (); + Stream stream = null; + + // possible input: Stream, XmlDocument, and XmlNodeList + if (obj is Stream) { + doc.Load (obj as Stream); + xsl.Load (doc); + } + else if (obj is XmlDocument) { + xsl.Load (obj as XmlDocument); + } + else if (obj is XmlNodeList) { +// xnl = (XmlNodeList) obj; +// xsl.Load (obj a); + } + + if (xnl != null) { + stream = new MemoryStream (); + // only possible output: Stream + xsl.Transform (doc, null, stream); + } + + if (stream != null) + cs = new CryptoStream (stream, new FromBase64Transform (), CryptoStreamMode.Read); + else + cs = null; + // note: there is no default are other types won't throw an exception + } +} + +} |