One of the optional portions of the W3C XML digital signature specification allows for a set of SignatureProperties to be assigned to a signature. SignatureProperties allow the signer to place some metadata into the signature itself, such as the time the signature was created and the name of the person creating the signature. Since the XML digital signature specification does not lay out specific properties, you are free to create as many domain specific properties as you'd like. Although the SignedXml class does not support this feature, it's easy enough to add on your own by deriving from the default SignedXml implementation.
Signature properties exist as a SignatureProperties element in the signature itself, embedded as a DataObject. The signature's references contain a pointer to this element with a Type of "http://www.w3.org/2000/02/xmldsig#SignatureProperty", as specified in the W3C spec. The SignatureProperties element will contain as many SignatureProperty elements as needed. Each SignatureProperty will have a Target pointing to the signature that we're creating and will contain arbitrary XML (which should be in a different namespace to be valid).
In order to implement this, we'll first create a SignaturePropertiesSignedXml class which derives from SignedXml and takes the typical XmlDocument constructor parameter, as well as an ID for the signature (which is needed for the SignatureProperty Target attribute), and the ID of the SignatureProperties element itself (which is needed for the reference to work). We then use this information to create the SignatureProperties element, and place it into a DataObject. Finally we create and add the reference to the SignatureProperties element:
Now that the constructor has done the work of setting up the signature properties, we'll need a simple method to add individual properties. This is easily accomplished by taking the XML content of the property, creating a SignatureProperty element with a Target of the containing signature, and adding the input XML to the SignatureProperty:
Finally, we need to override GetIdElement (see my previous post on doing this for more information), since the default GetIdElement implementation does not search DataObjects and we have a reference that points to our SignatureProperties which is contained within a DataObject. In the override, we just check to see if we're searching for the signature properties, and if not fall back to default behavior.
And that's it! We can now pretty easily use this class to add metadata to the signature. For example:
Will produce a signature that contains the time and person who signed the document:
To verify this signature you don't even have to use the custom SignaturePropertiesSignedXml class -- since the SignatureProperties element is now a child of the XML document (since we made this an enveloped signature), the standard SignedXml class will be able to find it to verify the signature.