Web Services Security, Part 2
by Bilal Siddiqui
|
Pages: 1, 2, 3
Four Steps to XML Digital Signature Authoring
The first step is to create a Signature element. The
Signature element will eventually wrap all the other XMLDS
elements. Have a look at Listing 2,
which has exactly the same body as that of Listing 1. The only difference between
Listings 1 and 2 is that Listing 2 contains the XMLDS
namespace declaration (http://www.w3.org/2000/09/xmldsig#)
and a SOAP header. The SOAP header wraps a Signature
element.
The Signature element in Listing 2 contains three child elements:
SignedInfo, SignatureValue, and
KeyInfo.
Listing 2 shows that the
Signature element is only a wrapper for other XMLDS tags. In
steps 2, 3, and 4, we'll create the child nodes of the three
Signature children (SignedInfo,
SignatureValue, and KeyInfo).
The second step is to create the child nodes of the
SignedInfo element. Listing
3 is the result of inserting the SignedInfo child nodes
into Listing 2. The complete
SignedInfo structure tells the details of the process that
leads to an XML signature. You can notice from Listing 3 that there are several
children of the SignedInfo element and each of its children
contains some bit of information as explained below.
The CanonicalizationMethod is a required element that
identifies the canonicalization algorithm applied to the
SignedInfo element before producing the signature.
Canonicalization algorithms are important in XML signature applications because message digest algorithms treat XML data as octet streams. Two different octet streams can represent the same XML resource. For example, if you change the sequence of attributes occurring in an XML element, the resulting XML file will be a logically equivalent version of the original XML file. However the two logically equivalent XML files will contain two different octet streams and will produce different digest values.
Canonicalization algorithms are meant to produce identical octet streams for logically equivalent XML data. In order to make sure that logically equivalent XML documents produce the same digest value (and the same signature), we need to canonicalize our XML resources before digesting their octet streams.
The CanonicalizationMethod element in Listing 3 has an attribute named
Algorithm, which has a URI string as value
(http://www.w3.org/2001/10/xml-exc-c14n#). This URI string
identifies Exclusive XML Canonicalization, an algorithm by the W3C. The
details of XML canonicalization are beyond the scope of this
article. Please refer to the resources section for a series of articles
that discusses XML canonicalization in detail.
At this stage, we have just created the
CanonicalizationMethod element. We have not yet applied the
canonicalization algorithm to anything. We will apply the canonicalization
algorithm to the SignedInfo element after authoring all its
children.
The next child of the SignedInfo element in Listing 3 is a SignatureMethod
element, whose Algorithm attribute identifies the algorithm
that will be used to produce the cryptographic signature.
The third child of the SignedInfo element is a
Reference element. There should be at least one
Reference element inside a SignedInfo
element. The Reference element is used to hold various bits
of information as explained below.
-
A reference to the data that is being signed. This is the job of the
URIattribute of theReferenceelement. You may include the data to be signed within the XML document or you may keep it external. If your data and the signature reside within the same XML document, you will refer to it using a fragment identifier as a value of theURIattribute of theReferenceelement. This is what we have done in Listing 3. The value of the URI attribute points to theGetSpecialDiscountedBookingForPartnerselement. If, on the other hand, your data is external to the XMLDS file, you will refer to it using a URI as theURLattribute value of theReferenceelement.XMLDS allows you to perform some operations on your data before digesting and signing it. For example, you can canonicalize your data before signing it Or you may want to apply some XSL transformations on your data before digesting it. For instance, you may have some pricing data in a simple tabular form of model numbers and prices and you may want to transform the tabular form into a formal invoice before signing it. In this case, you may use an XSL transform as a template representing your invoice. This would mean that you intend to sign the complete formal invoice and not just the raw data included in XMLDS file.
The
Transformselement holds the information regarding what operations you performed on your data before signing it. Look at theTransformselement in Listing 3, which contains oneTransformchild element. There can be any number ofTransformelements.Each
Transformelement identifies a transformation algorithm. When you apply a transformation to your data before signing it, you will include a reference to what you did by adding aTransformelement. This will tell the recipient application of your signed file to do the same transformation before attempting to verify the signature. In our case, we have applied just one operation, which is the canonicalization algorithm specified by theAlgorithmattribute of theTransformelement in Listing 3.If there is more than one
Transformelement, their order is important. Transformations are applied in the same order that they appear in aTransformselement. All the transformations are performed before digesting the data. Hence, the output of the lastTransformelement is the input to the message digest algorithm. -
What algorithm did you use to produce the digest value? The XMLDS specification suggests the use of SHA-1 digest algorithm. The
DigestMethodchild of theReferenceelement holds this information in itsAlgorithmattribute value (http://www.w3.org/2000/09/xmldsig#sha1). -
The digest value itself. The
DigestValueelement in Listing 3 contains the actual digest value produced by digesting the canonicalized form of theGetSpecialDiscountedBookingForPartnerselement. Note that binary data in raw form (such as the sequence of octets produced by message digest, signature, and encryption algorithms) cannot be wrapped inside XML markup as such; it may produce problems while XML parsing. Such data is base-64 encoded before wrapping inside XML markup. The result of base-64 encoding is that the encrypted data does not contain any byte that conflicts with XML processing rules.
Once the SignedInfo and its child elements have been
authored, you will canonicalize the complete SignedInfo
element with the algorithm identified by the
CanonicalizationMethod element. You will then produce the
signature value and wrap the signature value inside a
SignatureValue element as shown in Listing 4. While signing, you will use
the canonical form of the complete SignedInfo element as data
to be signed. This includes all the child elements of the
SignedInfo element.
Notice that the SignedInfo structure contains a reference
to the data being signed (the URI attribute of the
Reference element), the digest value, and the name of the
signature method as well as other bits of information. Therefore, signing
the SignedInfo structure effectively means that you are
signing the digest value of your data along with a reference to the data
itself.
The Signature element in Listing 2 contains another child named
KeyInfo. The fourth step is to create its child elements. In
Listing 5, the KeyInfo
element contains a KeyName child element. The
KeyName element is an identifier for the key that will be
used for signature verification. KeyName is just a
placeholder for key identifiers. XMLDS does not specify the mechanism
which will relate the identifier with the actual key pair used for
signing. It is up to XMLDS applications to design their own mechanism for
key identification. For example, the key identifier in Listing 5
(MyKeyIdentifier) may identify a shared secret (a symmetric key)
previously exchanged between the tour operator and the hotel.
Moreover, the KeyInfo element is optional: you may or may
not include a KeyInfo element in a signature. The
KeyInfo element is optional because a signature application
may not want to include key information inside the XMLDS file. The
KeyInfo element may also be used in XML Encryption
applications that we will demonstrate in the next section.
These four steps are a very simple demonstration of XMLDS. Listing 5 is a complete SOAP message that carries message integrity and user authentication data in its header.
Now it's time to demonstrate the processing of the XMLDS-based header of Listing 5 at the hotel's web service end.
XML Digital Signature Validation
The validation procedure is simple and can be logically deduced from XMLDS authoring steps discussed earlier. It involves three main tasks.
First, canonicalize the SignedInfo element. Recall that
the CanonicalizationMethod element specifies the
canonicalization algorithm. Use this canonical form of the
SignedInfo element for the rest of the validation
process.
Second, check the integrity of the message by verifying the digest
value contained in the Reference element that we authored in
step 2 above. For digest verification, you need to know three things:
-
The data that needs to be digested. You dereference the
URIattribute of theReferenceelement in order to get the data that needs to be digested. -
Any transformations that may have been applied to the data before applying the digest algorithm. The
Transformselement contains this information. You will apply the same transformations to the data before digesting it. -
The digest algorithm. This information is contained in the
Algorithmattribute value of theDigestMethodelement. You will apply the message digest and verify that the digest value is the same as that contained in theDigestValueelement.
If the digest verification fails, the validation process fails and we're done.
If the digest value is found to be in order, the third task is to
verify the signature. For the signature verification, you need the
signer's key (the public key or the shared secret). You obtain the key
information from the KeyInfo element if it is present (or
your application may already know the keying information from some other
means). Once you know the key to be used in signature validation, read the
signature method used to produce the signature. The Algorithm
attribute of the SignatureMethod element contains this
information. Then use the canonical form of the SignedInfo
element and the key to confirm the signature value.
An XMLDS implementation can create SOAP headers to produce signed SOAP messages. The XML firewall sitting at the recipient's end will process the SOAP header to verify the signatures before forwarding the request to the SOAP server. This process is graphically illustrated in Figure 1. We can achieve the following two security objectives through this procedure:
- We can verify that the SOAP message that we received was really sent by the sender we think it came from.
- We can verify that the data we received has not been changed while on its way and is the same that the sender intended to send.
So now we are sure that the request for special discounted booking is really coming from a trusted partner hotel and that no one has altered the data on its way. But hackers can still see the data while traveling across the Internet. So let's see how the XML encryption specification solves this problem.