See also: The Genero Web Services XML Library
The Signature class provides methods to create detached, enveloped or enveloping XML signatures of one or more references of XML documents or document fragments, and to determine whether a signed referenced document has been modified afterwards. It follows the XML-Signature specifications.
The status is set to zero after a successful method call.
Syntax
xml.Signature
Class Methods | |
Name | Description |
xml.Signature.Create() |
Constructor of a
blank Signature object. Returns a Signature object or NULL. Throws an exception in case of errors, and updates status with an error code. |
xml.Signature.CreateFromNode( |
Constructor of a
new Signature object from a XML Signature node, according to the XML-Signature specification. Returns a Signature object or NULL. The node must be an ELEMENT node with Signature as the local name, and belonging to the XML-Signature namespace http://www.w3.org/2000/09/xmldsig#, as defined here. Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
setKey( |
Defines the key used for signing or
validation. Only RSA, DSA of HMAC keys intended for SIGNATURE are allowed. During the computation of the signature, some key information can be added according to the feature set on that CryptoKey object. If no features are set, nothing is added. See XML Signature concepts for more details. Throws an exception in case of errors, and updates status with an error code. |
setCertificate( |
Defines the X509 certificate to be
added to the Signature object when signing a document. If NULL, no
certificate is added. During the computation of the signature, some certificate information can be added according to the feature set on that CryptoX509 object. If no features are set, the complete X509 certificate is automatically added. During the verification of a signature the certificate set with the setCertificate method isn't used. See XML Signature concepts for more details. Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
setCanonicalization( |
Sets the canonicalization method to use for the
signature, where url
is one of the four canonicalization identifier. The default value is the c14n method. Note: Windows .NET default c14n canonicalization method is not compatible with the w3c standard, therefore it is recommended to use the exc-c14n method when interoperating with a Windows system. Throws an exception in case of errors, and updates status with an error code. |
setID( |
Sets an ID value for the
signature. Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
getType() |
Returns a string with the type of
the Signature object.
The string can be Detached, Enveloped, Enveloping or Invalid according to the XML-Signature specification. Throws an exception in case of errors, and updates status with an error code. |
getDocument() |
Returns a new DomDocument object
representing the signature in XML.
If the type of the signature is enveloped, it's up to the user to add it at the right place in the XML document it is intended to sign. Throws an exception in case of errors, and updates status with an error code. |
getCanonicalization() |
Returns one of the four canonicalization identifier of the
signature. Throws an exception in case of errors, and updates status with an error code. |
getID() |
Returns the ID value of the signature. Throws an exception in case of errors, and updates status with an error code. |
getSignatureMethod() |
Returns the algorithm method of the signature. Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
createReference( |
Creates a new reference that will be
signed with the compute() method, where uri
represents the data to be signed, and digest a URL
as identifier for the hash algorithm.
The returned value represents the index for any further manipulation of this reference. The uri can be:
Throws an exception in case of errors, and updates status with an error code. |
setReferenceID( |
Sets an ID value
for the signature reference of index ind.
Throws an exception in case of errors, and updates status with an error code. |
appendReferenceTransformation( |
Appends a transformation related to
the reference of index ind, and is executed before
any computation; where trans represents an URL as identifier of the
transformation algorithm.
A transformation modifies the reference URI before signing or validating it. Several transformations are executed one after another, and only once the last transformation was applied, is the reference really signed or verified. Depending on the transformation identifier, additional parameters are necessary. Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
getReferenceCount() |
Returns the number of references in
this Signature object.
Throws an exception in case of errors, and updates status with an error code. |
getReferenceURI( |
Returns the URI of the reference of
index ind in this Signature object.
Throws an exception in case of errors, and updates status with an error code. |
getReferenceDigest( |
Returns the digest algorithm identifier of the reference of
index ind in this Signature object.
Throws an exception in case of errors, and updates status with an error code. |
getReferenceID( |
Returns the ID value of the
reference of index ind in this Signature object, or
NULL if there is none. Throws an exception in case of errors, and updates status with an error code. |
getReferenceTransformationCount( |
Returns the number of transformation
related to the reference of index ind.
Throws an exception in case of errors, and updates status with an error code. |
getReferenceTransformation( |
Returns the transformation identifier related to the
reference of index ind, and at position pos
in the list of transformation.
Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
createObject() |
Creates a new object that will embed
additional XML nodes. The returned value represents the index for any further manipulation of this signature object. Note: An object is enveloping additional XML nodes, but is not necessarily signed unless there is a reference on it. Throws an exception in case of errors, and updates status with an error code. |
setObjectID( |
Sets an ID value
for the signature object of index ind.
Throws an exception in case of errors, and updates status with an error code. |
appendObjectData( |
Appends a copy of a XML node node
to the signature object of index ind.
Throws an exception in case of errors, and updates status with an error code. |
Class Methods | |
Name | Description |
xml.Signature.RetrieveObjectDataListFromSignatureNode( |
Returns a DomNodeList containing all
embedded XML nodes related to the signature object of index ind
in the XML Signature node node.
Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
getObjectCount() |
Returns the number of objects in
this Signature object.
Throws an exception in case of errors, and updates status with an error code. |
getObjectId( |
Returns the ID value of the
signature object of index ind in this Signature
object.
Throws an exception in case of errors, and updates status with an error code. |
Object Methods | |
Name | Description |
compute( |
Computes the signature of all
references set in this Signature object. If the signature type is:
Also, see Windows .NET special recommendation Throws an exception in case of errors, and updates status with an error code. |
verify( |
Verifies whether all references in
this Signature object haven't changed, and returns TRUE if valid, FALSE
otherwise. If the signature type is:
By default, the validation process uses the CryptoKey set with setKey() to verify the signature. However, if the signature contains a X509 certificate or a X509 retrieval method, it uses the list of trusted certificate, or if the signature contains a RSA or DSA retrieval method, it uses the RSA or DSA public key automatically loaded. Note: See Windows .NET special recommendation Throws an exception in case of errors, and updates status with an error code. |
The purpose of a signature is to verify the integrity of a XML document, that it was not altered, and that it still contains the same data as when it was created. The following points describe the different ways to achieve that.
Identifier | Description |
http://www.w3.org/2000/09/xmldsig#sha1 (See specification for details) |
Computes the digest of the reference set with
createReference(), by applying a hash operation using a SHA algorithm
of 160 bits. Note: It is the only digest algorithm recommended by the W3C. |
http://www.w3.org/2001/04/xmlenc#sha512 (See specification for details) |
Computes the digest of the reference set with
createReference(), by applying a hash operation using a SHA algorithm
of 512 bits. |
http://www.w3.org/2001/04/xmldsig-more#sha384 (See specification for details) |
Computes the digest of the reference set with
createReference(), by applying a hash operation using a SHA algorithm
of 384 bits. |
http://www.w3.org/2001/04/xmlenc#sha256 (See specification for details) |
Computes the digest of the reference set with
createReference(), by applying a hash operation using a SHA algorithm
of 256 bits. |
http://www.w3.org/2001/04/xmldsig-more#sha224 (See specification for details) |
Computes the digest of the reference set with
createReference(), by applying a hash operation using a SHA algorithm
of 224 bits. |
http://www.w3.org/2001/04/xmldsig-more#md5 (See specification for details) |
Computes the digest of the reference set with
createReference(), by applying a hash operation using a MD5 algorithm. |
http://www.w3.org/2001/04/xmlenc#ripemd160 (See specification for details) |
Computes the digest of the reference set with
createReference(), by applying a hash operation using a RIPEMD
algorithm. |
Identifier | Description | Additional parameters |
http://www.w3.org/2000/09/xmldsig#base64
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into
the raw data associated to a BASE64 encoded form.
This is intended to sign the raw data associated with the BASE64 encoded content of an element. See specification for details. |
No |
http://www.w3.org/TR/2001/REC-xml-c14n-20010315
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into a canonicalized XML document without any XML comments.
This is intended to transform two equivalent XML documents into a standardized XML representation in order to obtain the same hash value. For instance, the following two XML nodes are equivalent but would produce different hash values if not canonicalized:
|
No |
http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into a canonicalized XML document keeping all XML comments.
This is intended to transform two equivalent XML documents into a standardized XML representation in order to obtain the same hash value. For instance, the following two XML nodes are equivalent but would produce different hash values if not canonicalized.
|
No |
http://www.w3.org/2001/10/xml-exc-c14n#
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into a canonicalized XML document without any XML comments,
and removing all unused namespaces declaration. This is intended to transform two equivalent XML documents into a standardized XML representation in order to obtain the same hash value. For instance, the following two XML nodes are equivalent but would produce different hash values if not canonicalized.
|
No |
http://www.w3.org/2001/10/xml-exc-c14n#WithComments
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into a canonicalized XML document keeping all XML comments,
and removing all unused namespaces declaration. This is intended to transform two equivalent XML documents into a standardized XML representation in order to obtain the same hash value. For instance, the following two XML nodes are equivalent but would produce different hash values if not canonicalized.
|
No |
http://www.w3.org/2000/09/xmldsig#enveloped-signature
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into the same XML document or fragment, but without the
Signature node. This is intended to create enveloped signatures where the <dsig:Signature> node is inside the document, but without taking it into account during signature computation or verification. See specification for details. |
No |
http://www.w3.org/TR/1999/REC-xpath-19991116
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into a XML document according to a XPath filtering expression
applied to each node of the input document,
where the expression represents a predicate to the XPath expression
(//. | //@* | //namespace::*). In other words: (//. | //@* | //namespace::*)[expr] This is intended to identify the nodes to be signed using a XPath expression instead of an attribute of type ID. For instance, the following samples output only the MyCode node of the input document: CALL s.appendReferenceTransformation( i, "http://www.w3.org/TR/1999/REC-xpath-19991116", "ancestor-or-self::MyCode", NULL) CALL s.appendReferenceTransformation( i, "http://www.w3.org/TR/1999/REC-xpath-19991116", "ancestor-or-self::p:MyCode", "p","http://www.tempuri.org") See specification for details. |
XPath
expression, followed by NULL or a list of prefix,namespace matching the XPath expression. |
http://www.w3.org/2002/06/xmldsig-filter2
(See specification for details) |
Transforms the output from the previous transformation
(or the reference if there is no previous transformation), into a XML document according to a XPath filtering 2.0
expression applied to the entire document at once. This is intended to identify the nodes to be signed using a XPath expression instead of an attribute of type ID, and to perform fast and more complex operations such as intersect, subtract or union. For instance, the following samples output the entire document without the MyCode node child of the MyElement root node: CALL s.appendReferenceTransformation( i, "http://www.w3.org/2002/06/xmldsig-filter2", "subtract", "/MyElement/MyCode") CALL s.appendReferenceTransformation( i, "http://www.w3.org/2002/06/xmldsig-filter2", "subtract", "/p1:MyElement/p2:MyCode", "p2","http://www.tempuri.org/ns2", "p1","http://www.tempuri.org/ns1")See specification for details. |
XPathFilter2.0
type (intersect,subtract or union),
followed by the XPath expression, followed by NULL or a list of prefix,namespace matching the XPath expression. |
01
IMPORT xml02
03
MAIN04
DEFINE doc xml.DomDocument05
DEFINE root xml.DomNode06
DEFINE sig xml.Signature07
DEFINE key xml.CryptoKey08
DEFINE index INTEGER09
# Create DomDocument object10
LET doc = xml.DomDocument.Create()11
# Notice that whitespaces are significant in crytography,12
# therefore it is recommended that you remove unnecessary ones13
CALL doc.setFeature("whitespace-in-element-content",FALSE)14
TRY15
# Load document to be signed16
CALL doc.load("MyDocument.xml")17
# Create HMAC key18
LET key = xml.CryptoKey.Create("http://www.w3.org/2000/09/xmldsig#hmac-sha1")19
CALL key.setKey("secretpassword")20
# Create signature object with the key to use21
LET sig = xml.Signature.Create()22
CALL sig.setKey(key)23
# Set XML node to be signed. In our case, the node with attribute 'xml:id="code"'24
LET index = sig.createReference("#code","http://www.w3.org/2000/09/xmldsig#sha1")25
# Set canonicalization method on the XML fragment to be signed.26
CALL sig.appendReferenceTransformation(index,"http://www.w3.org/2001/10/xml-exc-c14n#")27
# Compute detached signature28
CALL sig.compute(doc)29
# Retrieve signature document30
LET doc=sig.getDocument()31
# Save signature on disk32
CALL doc.setFeature("format-pretty-print",TRUE)33
CALL doc.save("MyDocumentDetachedSignature.xml")34
CATCH35
DISPLAY "Unable to create a detached signature :",STATUS36
END TRY37
END MAIN
Note: All keys or certificates in PEM or DER format were created with the OpenSSL tool.
01
IMPORT xml02
03
MAIN04
DEFINE doc xml.DomDocument05
DEFINE node xml.DomNode06
DEFINE sig xml.Signature07
DEFINE key xml.CryptoKey08
# Create DomDocument object09
LET doc = xml.DomDocument.Create()10
# Notice that whitespaces are significants in crytography,11
# therefore it is recommended to remove unnecessary ones12
CALL doc.setFeature("whitespace-in-element-content",FALSE)13
TRY14
# Load Signature into a DomDocument object15
CALL doc.load("MyDocumentDetachedSignature.xml")16
# Create signature object from DomDocument root node17
LET sig = xml.Signature.CreateFromNode(doc.getDocumentElement())18
# Create HMAC key and assign it to the signature object19
LET key = xml.CryptoKey.Create("http://www.w3.org/2000/09/xmldsig#hmac-sha1")20
CALL key.setKey("secretpassword")21
CALL sig.setKey(key)22
# Load original XML document into a DomDocument object23
CALL doc.load("MyDocument.xml")24
# Verify detached signature validity of original document25
LET isVerified = sig.verify(doc)26
# Notice that if something has been modified in the node with attribute 'xml:id="code"' of the original XML document,27
# the program will display "FAILED".28
IF isVerified THEN29
DISPLAY "Signature OK"30
ELSE31
DISPLAY "Signature FAILED"32
END IF33
CATCH34
DISPLAY "Unable to verify the detached signature :",STATUS35
END TRY36
END MAIN
Note: All keys or certificates in PEM or DER format were created with the OpenSSL tool.
01
IMPORT xml02
03
MAIN04
DEFINE doc xml.DomDocument05
DEFINE root xml.DomNode06
DEFINE sig xml.Signature07
DEFINE key xml.CryptoKey08
DEFINE index INTEGER09
DEFINE objInd INTEGER10
# Create DomDocument object11
LET doc = xml.DomDocument.Create()12
# Notice that whitespaces are significants in crytography,13
# therefore it is recommended to remove unnecessary ones14
CALL doc.setFeature("whitespace-in-element-content",FALSE)15
TRY16
# Load document to be signed17
CALL doc.load("MyDocument.xml")18
# Create DSA key and load it from file19
LET key = xml.CryptoKey.Create("http://www.w3.org/2000/09/xmldsig#dsa-sha1")20
CALL key.loadPEM("DSAKey.pem")21
# Create signature object with the key to use22
LET sig = xml.Signature.Create()23
CALL sig.setKey(key)24
# Create an object inside the signature to envelop the root node25
LET objInd = sig.createObject()26
# Set the object id to get a reference27
CALL sig.setObjectId(objInd,"data")28
# Copy the enveloping node from the document29
CALL sig.appendObjectData(objInd,doc.getDocumentElement())30
# Set the reference to be signed on the object node. In our case, the object node with attribute 'data'31
LET index = sig.createReference("#data","http://www.w3.org/2000/09/xmldsig#sha1")32
# Set canonicalization method on the enveloping object to be signed.33
CALL sig.appendReferenceTransformation(index,"http://www.w3.org/2001/10/xml-exc-c14n#")34
# Compute enveloping signature35
CALL sig.compute(NULL)36
# Retrieve signature document37
LET doc=sig.getDocument()38
# Save signature on disk39
CALL doc.setFeature("format-pretty-print",TRUE)40
CALL doc.save("MyDocumentEnvelopingSignature.xml")41
CATCH42
DISPLAY "Unable to create an enveloping signature :",STATUS43
END TRY44
END MAIN
Note: All keys or certificates in PEM or DER format were created with the OpenSSL tool.
01
IMPORT xml02
03
MAIN04
DEFINE doc xml.DomDocument05
DEFINE node xml.DomNode06
DEFINE sig xml.Signature07
DEFINE cert xml.CryptoX50908
DEFINE pub xml.CryptoKey09
# Create DomDocument object10
LET doc = xml.DomDocument.Create()11
# Notice that whitespaces are significants in crytography,12
# therefore it is recommended to remove unnecessary ones13
CALL doc.setFeature("whitespace-in-element-content",FALSE)14
TRY15
# Load Signature into a DomDocument object16
CALL doc.load("MyDocumentEnvelopingSignature.xml")17
# Create signature object from DomDocument root node18
LET sig = xml.Signature.CreateFromNode(doc.getDocumentElement())19
# Create X509 certificate20
LET cert = xml.CryptoX509.Create()21
CALL cert.loadPEM("DSACertificate.crt")22
# Create public key from that X509 certificate23
LET pub = cert.createPublicKey("http://www.w3.org/2000/09/xmldsig#dsa-sha1")24
# Assign it to the signature25
CALL sig.setKey(pub)26
# Verify enveloping signature validity27
LET isVerified = sig.verify(NULL)28
# Notice that if something has been modified in the signature29
# or if the certificate isn't associated to the private DSA key of exemple 3,30
# the program will display "FAILED".31
IF isVerified THEN32
DISPLAY "Signature OK"33
ELSE34
DISPLAY "Signature FAILED"35
END IF36
CATCH37
DISPLAY "Unable to verify the enveloping signature :",STATUS38
END TRY39
END MAIN
Note: All keys or certificates in PEM or DER format were created with the OpenSSL tool.
01
IMPORT xml02
03
MAIN04
DEFINE doc xml.DomDocument05
DEFINE doc2 xml.DomDocument06
DEFINE root xml.DomNode07
DEFINE node xml.DomNode08
DEFINE signNode xml.DomNode09
DEFINE sig xml.Signature10
DEFINE key xml.CryptoKey11
DEFINE index INTEGER12
# Create DomDocument object13
LET doc = xml.DomDocument.Create()14
# Notice that whitespaces are significants in crytography,15
# therefore it is recommended to remove unnecessary ones16
CALL doc.setFeature("whitespace-in-element-content",FALSE)17
TRY18
# Load document to be signed19
CALL doc.load("MyDocument.xml")20
# Create rsa key21
LET key = xml.CryptoKey.Create("http://www.w3.org/2000/09/xmldsig#rsa-sha1")22
CALL key.loadPEM("RSAKey.pem")23
# Create signature object with the key to use24
LET sig = xml.Signature.Create()25
CALL sig.setKey(key)26
# Set XML node to be signed. In our case, the node with attribute 'xml:id="code"'27
LET index = sig.createReference("#code","http://www.w3.org/2000/09/xmldsig#sha1")28
# Add enveloped method to not take the XML signature node into account when computing the entire document.29
CALL sig.appendReferenceTransformation(index,"http://www.w3.org/2000/09/xmldsig#enveloped-signature")30
# Set canonicalization method on the XML fragment to be signed.31
CALL sig.appendReferenceTransformation(index,"http://www.w3.org/2001/10/xml-exc-c14n#")32
# Compute enveloped signature33
CALL sig.compute(doc)34
# Retrieve signature document35
LET doc2=sig.getDocument()36
# Append the signature node to the original document to get a valid enveloped signature37
# Notice that the enveloped signature can be added anywhere in the original document38
LET signNode = doc2.getDocumentElement() # Get Signature node39
LET node = doc.importNode(signNode,true) # Import it into the original document40
LET root = doc.getDocumentElement() # Retrieve the original document root node41
CALL root.appendChild(node) # Append the signature node as last child of the original document42
# Save document with enveloped signature back to disk43
CALL doc.setFeature("format-pretty-print",TRUE)44
CALL doc.save("MyDocumentEnvelopedSignature.xml")45
CATCH46
DISPLAY "Unable to create an enveloped signature :",STATUS47
END TRY48
END MAIN
Note: All keys or certificates in PEM or DER format were created with the OpenSSL tool.
01
IMPORT xml02
03
MAIN04
DEFINE doc xml.DomDocument05
DEFINE node xml.DomNode06
DEFINE sig xml.Signature07
DEFINE key xml.CryptoKey08
DEFINE list xml.DomNodeList09
# Create DomDocument object10
LET doc = xml.DomDocument.Create()11
# Notice that whitespaces are significants in crytography,12
# therefore it is recommended to remove unnecessary ones13
CALL doc.setFeature("whitespace-in-element-content",FALSE)14
TRY15
# Load original document with enveloped signature into a DomDocument object16
CALL doc.load("MyDocumentEnvelopedSignature.xml")17
# Because the signature can be anywhere in the original document, we must first retrieve it18
LET list = signature.getElementsByTagNameNS("Signature","http://www.w3.org/2000/09/xmldsig#")19
IF list.getCount() != 1 THEN20
DISPLAY "Unable to find one Signature node"21
EXIT PROGRAM (-1)22
ELSE23
LET node = list.getItem(1)24
END IF25
# Create RSA key26
LET key = xml.CryptoKey.Create("http://www.w3.org/2000/09/xmldsig#rsa-sha1")27
CALL key.loadPEM("RSAKey.pem")28
# Create signature object from DomNode object and set RSA key to use29
LET sig = xml.Signature.CreateFromNode(node)30
CALL sig.setKey(key)31
# Verify enveloped signature validity of original document32
LET isVerified = sig.verify(doc)33
# Notice that if something has been modified in the node with attribute 'xml:id="code"' of the original XML document with the enveloped signature,34
# the program will display "FAILED".35
IF isVerified THEN36
DISPLAY "Signature OK"37
ELSE38
DISPLAY "Signature FAILED"39
END IF40
CATCH41
DISPLAY "Unable to verify the enveloped signature :",STATUS42
END TRY43
END MAIN
Note: All keys or certificates in PEM or DER format were created with the OpenSSL tool.