Discuss this help topic in SecureBlackbox Forum
XML: Create custom signature
The xml signature could have neither enveloping nor enveloped nor detached signature type.
For example, the signature and data signed can be present in the same XML document as sibling elements (sometimes it is called internally detached signature):
Signed document:
<root>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<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="#data">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>...</ds:SignatureValue/>
<ds:KeyInfo>...</ds:KeyInfo>
</ds:Signature>
<document Id="data">
<title>Title</title>
<content>Text...</content>
</document>
</root>
Code sample:
C#:
void Sign(TElXMLDOMElement SignedElement,
TElXMLDOMElement SignatureParentElement, TElX509Certificate Cert)
{
TElXMLSigner Signer = new TElXMLSigner(null);
TElXMLKeyInfoX509Data X509Data = new TElXMLKeyInfoX509Data(false);
try
{
Signer.SignatureType = SBXMLSec.Unit.xstEnveloped;
Signer.CanonicalizationMethod = SBXMLDefs.Unit.xcmCanon;
Signer.SignatureMethodType = SBXMLSec.Unit.xmtSig;
Signer.SignatureMethod = SBXMLSec.Unit.xsmRSA_SHA1;
TElXMLReference Ref = new TElXMLReference();
Ref.DigestMethod = SBXMLSec.Unit.xdmSHA1;
Ref.URI = "#" + SBXMLUtils.Unit.GetElementId(SignedElement);
Ref.URINode = SignedElement;
Signer.References.Add(Ref);
X509Data.Certificate = Cert;
Signer.KeyData = X509Data;
Signer.UpdateReferencesDigest();
Signer.GenerateSignature();
Signer.SaveEnveloped(SignatureParentElement);
}
finally
{
Signer.Dispose();
X509Data.Dispose();
}
}
Delphi:
procedure Sign(SignedElement : TElXMLDOMElement;
SignatureParentElement : TElXMLDOMElement; Cert : TElX509Certificate);
var
Signer: TElXMLSigner;
X509Data: TElXMLKeyInfoX509Data;
Ref: TElXMLReference;
begin
Signer:= TElXMLSigner.Create(nil);
X509Data := TElXMLKeyInfoX509Data.Create(false);
try
Signer.SignatureType := xstEnveloped;
Signer.CanonicalizationMethod := xcmCanon;
Signer.SignatureMethodType := xmtSig;
Signer.SignatureMethod := xsmRSA_SHA1;
Ref := TElXMLReference.Create;
Ref.DigestMethod := xdmSHA1;
Ref.URI := '#' + GetElementId(SignedElement);
Ref.URINode := SignedElement;
Signer.References.Add(Ref);
X509Data.Certificate := Cert;
Signer.KeyData := X509Data;
Signer.UpdateReferencesDigest;
Signer.GenerateSignature;
Signer.SaveEnveloped(SignatureParentElement);
finally
FreeAndNil(Signer);
FreeAndNil(X509Data);
end;
end;
In this code we save a signature using enveloped signature type as the most similar signature type, but without enveloped signature transform, as we don't need to exclude <ds:Signature> element from reference computation.
The Save*() methods works as follows:
Depending on the situation you can choose any of those methods to save a custom signature type. For example, a signature could have several references: the first is referencing the data in a sibling element, and the second is referencing the data that should be placed in enveloping object. Consider this example:
<root>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<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="#data">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>...</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#objId">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>...</ds:SignatureValue/>
<ds:KeyInfo>...</ds:KeyInfo>
<ds:Object Id="objId"><data>Hello, World!</data></ds:Object>
</ds:Signature>
<document Id="data">
<title>Title</title>
<content>Text...</content>
</document>
</root>
In this case using enveloping signature type would be simpler, but it is possible to achieve similar signature using enveloped signature type by creating a custom object.