Agile Zone is brought to you in partnership with:

Yaron is a Microsoft MVP in the Connected System Developer realm. Yaron authors the successful Web Services 2.0 blog, in which he helps the community with some of his favorite topics: Web services, security and interoperability. Yaron is also an architect in HP. Yaron is a DZone MVB and is not an employee of DZone and has posted 27 posts at DZone. You can read more from them at their website. View Full User Profile

Xml Digital Signature: Signing the KeyInfo

01.31.2011
| 5930 views |
  • submit to reddit

Frederic Vidal had shown me recently a nice trick with Xml digital signatures. Suppose you want to add a signature which looks like this:

<ds:Signature xmlns:ds='http://www.w3.org/2000/09/xmldsig#' Id='Signature001'>
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315' />
<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1' />
<ds:Reference URI=''>
<ds:Transforms>
<ds:Transform Algorithm='http://www.w3.org/2000/09/xmldsig#enveloped-signature' />
</ds:Transforms>
<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1' />
<ds:DigestValue>sXe2PnaG...</ds:DigestValue>
</ds:Reference>
<ds:Reference URI='#KeyInfo001'>
<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1' />
<ds:DigestValue>ZOS23PQ9TcDu+G...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>jTLX0/8XkY2aCte7...</ds:SignatureValue>
<ds:KeyInfo Id='KeyInfo001'>
<ds:X509Data>
<ds:X509Certificate>E3wdSY4n7MgUmJzMIGfMA0...</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>

The interesting part is the second reference (in bold) – the signature signs the KeyInfo (#KeyInfo001), which is part of the signature element itself. The regular api to add reference to a signature is this:

var reference = new Reference();
reference.Uri = "#KeyInfo001";
However it will not work here since it will look for an element with this ID in the signed document (e.g. soap envelope). However the ID is inside the signature element itself, which is still not a part of the document because it was not create yet.
Frederic had found a nice trick: Inherit from SignedXml and override the default logic to find the references such that it will search in the signature itself (which is the base class).
public class CustomIdSignedXml : SignedXml
{
public CustomIdSignedXml(XmlDocument doc) : base(doc)
{
return;
}

public override XmlElement GetIdElement(XmlDocument doc, string id)
{
if (String.Compare(id, this.KeyInfo.Id, StringComparison.OrdinalIgnoreCase) == 0)
return this.KeyInfo.GetXml();
else
return base.GetIdElement(doc, id);
}
}
This is applicable to web services, since many soap stacks will not allow to customize them to sign the KeyInfo, and if this is required you would need to sign the message like this yourself.
References
Published at DZone with permission of Yaron Naveh, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Mark Anthony replied on Fri, 2012/04/13 - 11:14am

I tried your solution and the soap message looks very similar, but the main difference is that the new message includes a second Reference element inside SignedInfo (with all element within it) and that it doesn't include any of the wsa elements (Action, MessageID, To) but I'm not sure if these are really needed.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.