XML Signatures


XML signatures define a powerful new technology that is used for digitally signing data that is represented in an XML format. XML has become such an important standard that it is now used in practically every conceivable programming scenario where the exchange of data takes place between applications. In many of these scenarios where data must be exchanged there may also be requirements for ensuring data integrity, authentication, and/or nonrepudiation.

Recall from previous chapters that in public key encryption, the original data is encrypted with the public key and decrypted with the private key. In digital signatures, only a message digest of the original data is encrypted with the private key and decrypted with the public key. Then, the message digest is recalculated and checked to see if the data was tampered with.

To make use of this new technology, you must learn two distinct aspects of XML signatures. The first is the XML signature syntax and processing rules as defined in the specification. The second is how to program with XML signatures on the .NET platform using the classes defined in the System.Security.Cryptography.Xmlnamespace .

The XML signature specification is sometimes referred to as XMLDSIG and is defined by W3C. The specification provides the syntax and semantics of XML signature in the form of an XML schema [11] and Document Type Definition (DTD) as well as the associated processing rules.

[11] XML schema is a standardized language (which is itself represented in XML) that is used to define XML syntax. XML schema improves and extends upon traditional DTD language. For more information on the XML schema definition language, see http://www.w3.org/TR/xmlschema-1/.

The XML Signature Specification

For all of the nitty-gritty details, you may want to read through the official W3C XML Signature Syntax and Processing specification found at www.w3.org/TR/xmldsig- core /. You can also learn about this technology in the request for comment found at www.ietf.org/rfc/rfc3275.txt. The status of the XML signature specification is now at the Recommendation stage, meaning that it is stable and may now be used as an implementation reference for widespread deployment.

What XML Signatures Provide

XML signatures can be applied to arbitrary data that may be located within or external to a given XML document. XML signatures support the following capabilities for data:

  • Integrity assures that the data has not been tampered with or corrupted since it was signed.

  • Authentication assures that the data originates from the signer.

  • Nonrepudiation assures that the signer is committed to the document contents.

XML Signature Syntax

Data objects are hashed and encrypted into a digest, which is then placed into an element, together with related information, which is then cryptographically signed. XML digital signatures are represented with the Signature element, which has the following layout. Again, the character ? denotes zero or one occurrence, + denotes one or more occurrences, and * denotes zero or more occurrences.

 <Signature ID?>    <SignedInfo>       <CanonicalizationMethod/>       <SignatureMethod/>       (<Reference URI? >          (<Transforms>)?          <DigestMethod>          <DigestValue>       </Reference>)+    </SignedInfo>    <SignatureValue> (<KeyInfo>)? (<Object ID?>)* </Signature> 
THE XML SIGNATURE ELEMENTS

The Signature element is the main syntactic component used in XML signatures. All other XML signature elements are children of the Signature element. This section provides a brief overview of the XML signature elements, including the Signature element and each of its children.

  • The Signature element is the outermost element (i.e., root element) of an XML signature that encloses the signed data.

  • The SignedInfo element contains the canonicalization and signature algorithm elements, and one or more reference elements. The SignedInfo element can also specify an optional ID attribute that can be referenced by other signature elements.

  • The CanonicalizationMethod element specifies the algorithm that is applied to the SignedInfo element prior to performing the signature operation. Canonicalization means to make the data conform to an established standard format, which is necessary for consistent digital signature results. This allows for crossplatform differences, such as the code representing a carriage return and so on.

  • The SignatureMethod element specifies the algorithm that is used to convert the canonicalized SignedInfo element into the corresponding SignatureValue element. This element represents a combination of digest algorithm (such as SHA-1), encryption algorithm (such as RSA), and possibly a padding algorithm.

  • The SignatureValue element contains the computed value of the digital signature, which is base64 encoded.

  • The KeyInfo element is optional, and it provides information that can be used to obtain the key for validating the signature. The KeyInfo element may contain public key-exchange information such as key name or certificate information.

  • The Object element is optional and may occur one or more times. It may contain any arbitrary data.

It might be helpful to look again at a before and after picture to help make this syntax more concrete. The following invoice document is the same one that we saw in the XML encryption example earlier in this chapter.

 <invoice>    <items>       <item>          <desc>Deluxe corncob pipe</desc>          <unitprice>14.95</unitprice>          <quantity>1</quantity>       </item>    </items>    <creditinfo>       <cardnumber>0123456789</cardnumber>       <expiration>01/06/2005</expiration>       <lastname>Finn</lastname>       <firstname>Huckleberry</firstname>    </creditinfo> </invoice> 

Now, after the signature is applied to this XML document, we obtain the following. The entire invoice element, along with its purchased items and credit information, is all wrapped up in a rather complex Signature element, which contains all the details needed to verify the RSA signature that is contained.

 <  Signature  xmlns="http://.../xmldsig#">    <SignedInfo>       <CanonicalizationMethod Algorithm="..." />       <SignatureMethod Algorithm="http://...                                   /xmldsig#rsa-sha1" />       <Reference URI="#MyDataObjectID">          <DigestMethod Algorithm="http://...                                   /xmldsig#sha1" />          <DigestValue>fFyEpmWrhIwMjnrBZOOGmATvvG8=          </DigestValue>       </Reference>    </SignedInfo>    <SignatureValue>V2tW6tmZnOnuvKi8cZBXp...    </SignatureValue>       <KeyInfo>          <KeyValue xmlns="http://www.w3.org/2000/09/                           xmldsig#">             <RSAKeyValue>                <Modulus>rJzbWtkPyhq+eBMhRdimd...</Modulus>                <Exponent>AQAB</Exponent>             </RSAKeyValue>          </KeyValue>       </KeyInfo>    <Object Id="MyDataObjectID">       <invoice xmlns="">          <items>             <item>                <desc>Deluxe corncob pipe</desc>                <unitprice>14.95</unitprice>                <quantity>1</quantity>             </item>          </items>          <creditinfo>             <cardnumber>0123456789</cardnumber>             <expiration>01/06/2005</expiration>             <lastname>Finn</lastname>             <firstname>Huckleberry</firstname>          </creditinfo>       </invoice>    </Object> </Signature> 
DETACHED, ENVELOPING, AND ENVELOPED SIGNATURES

There are three ways in which a signature may be defined within an XML document.

  • Detached signature is calculated over a data object that is external to the XML Signature element. In this scenario, the data object is identified via a URI or a transform. The Signature element and data object may reside either in separate XML documents or in separate tags within the same XML document.

  • Enveloping signature is calculated over data content defined within an Object element of the actual signature itself. The Object element, or its content, is identified via a Reference element via a URI fragment identifier or transform.

  • Enveloped signature is calculated over the XML content that contains the Signature element.

Classes Used in XML Signatures

Let's take a brief look at the classes that we will be working with in the upcoming XML signature example program. These classes are defined in the System.Security.Cryptography.Xml namespace. We will not have to do as much work as we did in the previous section on XML encryption, because the .NET library provides more complete support for XML signatures.

THE DATAOBJECT CLASS

The DataObject class encapsulates an XML element that holds the data to be signed. We will use the Data property, which gets or sets the data of the DataObject , and the ID property, which gets or sets the ID of the DataObject .

 public XmlNodeList Data    {get; set;} public string Id    {get; set;} 
THE SIGNEDXML CLASS

The SignedXml class encapsulates the core XML signature object for a signed XML document. This class has several methods and properties that we will use in the upcoming program example. The SigningKey property gets or sets the asymmetric algorithm key used for signing the XML element.

 public AsymmetricAlgorithm SigningKey    {get; set;} 

The AddObject method adds a new DataObject to the list of objects to be signed.

 public void AddObject(    DataObject dataObject ); 

The AddReference method adds a Reference element to the list of references that are to be hashed and signed.

 public void AddReference(    Reference reference ); 

The KeyInfo property gets or sets the KeyInfo element of the SignedXml object.

 public KeyInfo KeyInfo    {get; set;} 

The ComputeSignature method performs the actual signature operation on the XML element. There are two overloaded versions of this method. We will use the one with no parameter.

 public void ComputeSignature(); public void ComputeSignature(    KeyedHashAlgorithm macAlg ); 

The EnvelopingXmlSignature Example

The EnvelopingXmlSignature example program demonstrates how to sign and validate an XML signature. The entire source code for this simple program is shown in the following code listing.

The first thing that the program does in the Main method is call the CreateXMLDocument method, which creates an XML file that contains a simple invoice document named OriginalInvoice.xml . Next, the program calls the PerformXMLSignature method that computes an XML signature for the invoice and then writes the resulting signed invoice to a file named SignedInvoice.xml . Then, the VerifyXMLSignature method is called, which verifies that the signature in SignedInvoice.xml is valid, and it displays the fact that it is indeed valid in the console window. Next, in order to show the effect of tampering with a signed XML document, the TamperSignedXMLDocument method is called, which takes the valid SignedInvoice.xml file and modifies the credit-card number in the invoice, and then writes the modified result to the file named TamperedInvoice.xml . This tampered file contains the original invoice data but with a forged credit-card number and the original signature, which is no longer valid due to the tampered data. Finally, the VerifyXMLSignature method is called once again, but, this time, it attempts to verify the signature in TamperedInvoice.xml , and the negative result is then displayed in the console window. Take a look through the following source code listing to understand how these operations work, and then study the console output and the three resulting XML files that follow. Here is the source code.

 //EnvelopingXMLSignature.cs //NOTE: must add a project reference to System.Security using System; using System.IO; using System.Xml; using System.Security.Cryptography; using System.Security.Cryptography.Xml; class EnvelopingXMLSignature {    static void Main(string[] args)    {       //create participants       Sender sender = new Sender();       Receiver receiver = new Receiver();       Tamperer tamperer = new Tamperer();       //show the effects of signing and tampering       sender.CreateXmlDocument("OriginalInvoice.xml");       sender.PerformXmlSignature(          "OriginalInvoice.xml", "SignedInvoice.xml");       receiver.VerifyXmlSignature("SignedInvoice.xml");       tamperer.TamperSignedXmlDocument(          "SignedInvoice.xml", "TamperedInvoice.xml");       receiver.VerifyXmlSignature("TamperedInvoice.xml");    } } class Sender {    public void CreateXmlDocument(String originalFilename)    {       //establish the original XML document       XmlDocument xmlDoc = new XmlDocument();       xmlDoc.PreserveWhitespace = true;       xmlDoc.LoadXml(          "<invoice>\n" +          "   <items>\n" +          "      <item>\n" +          "         <desc>Deluxe corncob pipe</desc>\n" +          "         <unitprice>14.95</unitprice>\n" +          "         <quantity>1</quantity>\n" +          "      </item>\n" +          "   </items>\n" +          "   <creditinfo>\n" +          "      <cardnumber>0123456789</cardnumber>\n" +          "      <expiration>01/06/2005</expiration>\n" +          "      <lastname>Finn</lastname>\n" +          "      <firstname>Huckleberry</firstname>\n" +          "   </creditinfo>\n" +          "</invoice>\n");       //write original XML document to file       StreamWriter file =          new StreamWriter(originalFilename);       file.Write(xmlDoc.OuterXml);       file.Close();       //let the user know what happened       Console.WriteLine(          "Original XML document written to\n\t:" +          originalFilename);    }    public void PerformXmlSignature(       String originalFilename, String signedFilename)    {       //load the XML document       XmlDocument xmlDoc = new XmlDocument();       xmlDoc.PreserveWhitespace = true;       xmlDoc.Load(originalFilename);       //create signature wrapper with default RSA key       RSA key = RSA.Create();       SignedXml signedXml = new SignedXml();       signedXml.SigningKey = key;       //create data object to hold the data to be signed       DataObject dataObject = new DataObject();       dataObject.Data = xmlDoc.ChildNodes;       //set data object id for URI ref from elsewhere       dataObject.Id = "MyDataObjectID";       //add data object to be signed to signature wrapper       signedXml.AddObject(dataObject);       //create reference object to ref data object       Reference reference = new Reference();       reference.Uri = "#MyDataObjectID";       //add reference object to signature wrapper       signedXml.AddReference(reference);       //add key information to signature wrapper       KeyInfo keyInfo = new KeyInfo();       keyInfo.AddClause(new RSAKeyValue(key));       signedXml.KeyInfo = keyInfo;       //generate the XML signature       signedXml.ComputeSignature();       //apply XML signature to XML document       XmlElement xmlSignature = signedXml.GetXml();       xmlDoc = new XmlDocument();       xmlDoc.PreserveWhitespace = true;       XmlNode xmlNode = xmlDoc.ImportNode(xmlSignature,                         true);       xmlDoc.AppendChild(xmlNode);       xmlDoc.Save(signedFilename);       //let the user know what happened       Console.WriteLine(          "Signed XML document written to\n\t:" +          signedFilename);    } } class Receiver {    public void VerifyXmlSignature(String signedFilename)    {       //load signed XML document       XmlDocument xmlDoc = new XmlDocument();       xmlDoc.PreserveWhitespace = true;       xmlDoc.Load(signedFilename);       //create signature wrapper from signed XML file       SignedXml signedXml = new SignedXml(xmlDoc);       //get <Signature> node (assume only one exists)       XmlNodeList nodeList = xmlDoc.GetElementsByTagName(          "Signature",          "http://www.w3.org/2000/09/xmldsig#");       signedXml.LoadXml((XmlElement)nodeList[0]);       //let the user know what happened       if (signedXml.CheckSignature())          Console.WriteLine(             signedFilename + " signature is VALID");       else          Console.WriteLine(             signedFilename + " signature is NOT VALID");    } } class Tamperer {    public void TamperSignedXmlDocument(       String signedFilename, String tamperedFilename)    {       //load signed XML document       XmlDocument xmlDoc = new XmlDocument();       xmlDoc.PreserveWhitespace = true;       xmlDoc.Load(signedFilename);       //tamper signed XML document and write to file       XmlNodeList nodeList =          xmlDoc.GetElementsByTagName("cardnumber");       XmlNode xmlOldNode = (XmlElement)nodeList[0];       XmlNode xmlNewNode = xmlOldNode.Clone();       xmlNewNode.InnerText = "9876543210";       xmlOldNode.ParentNode.ReplaceChild(          xmlNewNode, xmlOldNode);       xmlDoc.Save(tamperedFilename);       //let the user know what happened       Console.WriteLine(          "Tampered signed XML document written to\n\t" +          tamperedFilename);    } } 

If you run the preceding program, you will see the following console window output. In particular, notice that the file named SignedInvoice.xml contains a valid XML signature, but the file named TamperedInvoice.xml does not contain a valid XML signature. These two files are identical except that the credit-card information was modified after the signature was generated. Since only the rightful owner of the private key used to generate the signature knows the value of that key, it is impossible for nonauthorized individuals to modify the document in an undetectable manner. This is because nonauthorized individuals do not know the correct value of this private key.

Of course, in this simple example the code that does the tampering happens to be the same program that does the signing, which is a bit unrealistic if not downright silly. Nobody would intentionally tamper with data that they themselves have produced. This example is only intended to prove the concept that, by signing a document, you can detect if it has been modified by someone else after signing has taken place.

 Original XML document written to OriginalInvoice.xml Signed XML document written to SignedInvoice.xml  SignedInvoice.xml signature is VALID  Tampered signed XML document written to TamperedInvoice.xml  TamperedInvoice.xml signature is NOT VALID  Press any key to continue 

Now, let's look at the three XML files that this program has generated: OriginalInvoice.xml, SignedInvoice.xml , and TamperedInvoice.xml . First, here is OriginalInvoice.xml . Notice that the credit-card number is set to 0123456789. We will see what happens if we try tampering with this card number shortly.

 <invoice>    <items>       <item>          <desc>Deluxe corncob pipe</desc>          <unitprice>14.95</unitprice>          <quantity>1</quantity>       </item>    </items>    <creditinfo>       <cardnumber>  0123456789  </cardnumber>       <expiration>01/06/2005</expiration>       <lastname>Finn</lastname>       <firstname>Huckleberry</firstname>    </creditinfo> </invoice> 

Now, let's look at the SignedInvoice.xml file. Several parts of the file have been shortened using ellipses, and a few carriage returns have been added to make it more legible and to fit it within the confines of this printed page. As you can see, the signed version of this file contains information on both the signature and the public aspects of the key that corresponds with the private key used to used sign the file.

 <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">    <SignedInfo>       <CanonicalizationMethod Algorithm="..." />       <SignatureMethod Algorithm="..." />       <Reference URI="  #MyDataObjectID  ">          <DigestMethod Algorithm="..." />          <DigestValue>...</DigestValue>       </Reference>    </SignedInfo>    <SignatureValue>...</SignatureValue>    <KeyInfo>       <KeyValue xmlns="...">          <RSAKeyValue>             <Modulus>...</Modulus>             <Exponent>...</Exponent>          </RSAKeyValue>       </KeyValue>    </KeyInfo>    <Object Id="  MyDataObjectID  ">       <invoice xmlns="">          <items>             <item>                <desc>Deluxe corncob pipe</desc>                <unitprice>14.95</unitprice>                <quantity>1</quantity>             </item>          </items>          <creditinfo>             <cardnumber>  0123456789  </cardnumber>             <expiration>01/06/2005</expiration>             <lastname>Finn</lastname>             <firstname>Huckleberry</firstname>          </creditinfo>       </invoice>    </Object> </Signature> 

We will not bother showing the entire contents of the TamperedInvoice.xml , since it is identical to the SignedInvoice.xml file in every way except that the credit-card number is changed from 0123456789 to 9876543210, as shown in the following snippet. You can verify that this is the only difference by comparing these two files using a tool such as Windiff.exe .

 <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">    <SignedInfo>       ...          <creditinfo>             <cardnumber>  9876543210  </cardnumber>             <expiration>01/06/2005</expiration>             <lastname>Finn</lastname>             <firstname>Huckleberry</firstname>          </creditinfo>       </invoice>    </Object> </Signature> 


.NET Security and Cryptography
.NET Security and Cryptography
ISBN: 013100851X
EAN: 2147483647
Year: 2003
Pages: 126

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net