Skip to content

Instantly share code, notes, and snippets.

@bseddon
Last active May 10, 2021 19:30
Show Gist options
  • Save bseddon/833241837ca7877a2e8329abe1138c96 to your computer and use it in GitHub Desktop.
Save bseddon/833241837ca7877a2e8329abe1138c96 to your computer and use it in GitHub Desktop.
Signing an XML document

Protocols such as https://www.w3.org/TR/xmldsig-core/ or https://www.w3.org/TR/xmldsig-core2/ define how to sign an XML document using a PKI certificate (gist XML Digital Signature describes how such a certificate can be generated using OpenSSL).

An XML document cannot be signed by manually adding information even with a certificate. Instead an application is needed to apply the certificate and sign the document using the private key associated with a certificate. However, when a suitable application is used then the XML document:

<?xml version="1.0" encoding="UTF-8"?>
<root>
	<someElement>Ipso facto...</someElement>
</root> 

can be signed by adding a signature like this:

<?xml version="1.0" encoding="UTF-8"?>
<root>
	<someElement>Ipso facto...</someElement>
	<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
		<ds:SignedInfo>
			<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
			<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
			<ds:Reference>
				<ds:Transforms>
					<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
				</ds:Transforms>
				<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
				<ds:DigestValue>whlSvfZOFZGYphP1oxAi1xZ3iF5bjlpLIrw4utZ2NaI=</ds:DigestValue>
			</ds:Reference>
		</ds:SignedInfo>
		<ds:SignatureValue>Wklm/qGt78W+dFikpn52rbsXXjWIhJ0r0nsW6rf6RDV9UHiU93IUDJGuEzqW7YrvC8l9HsxSLqj26qrZuoKlzz4txbTtsQdCbbya/IqeEgC4S3SV1uCt2H+Xl1yDee8UT+us6PaOYXHgvJC4E9SEdFXyRDvwM6Vanwn0RzzVTQQMnIBl2sxjRByfGaGg35Xo2TR8RMd5UCx3PBqqdRCUf8rD2K+dT+f3IL0f1A2aOHELZnZXsz1KZCGlH3csasAI0qi9sckkKGdlHVCRltKmHgAcI0JZiubx8v3CMPmBuAh3fhBChY3gijV7HpOWdkSF60X6BwI393aOrbrGDQ8bbg==
		</ds:SignatureValue>
		<ds:KeyInfo>
			<ds:X509Data>
				<ds:X509Certificate> -- the signer's certificate in base64 will go here -- </ds:X509Certificate>
			</ds:X509Data>
		</ds:KeyInfo>
	</ds:Signature>
</root>

OK, there's a lot going on in the signature but it breaks down in a fairly straight forward way. The value of the node '/root/ds:Signature/ds:SignedInfo/ds:Reference/ds:DigestValue' is the hash of the original XML content hashed using the algorithm '/root/ds:Signature/ds:signedInfo/ds:Reference/ds:DigestMethod'. The original content can be recovered by removing the /root/ds:Signature node. Hashing the recovered contents using the specified algorithm should generate the same value recorded within the signature node. This allows a user to check if the document content has been modified.

But what if a third-party changes the content, computes a new hash and updates the disgest value within the signature? To protect against this attack, the signature is hashed with the private key of the certificate. This signed hash is in the value of node '/root/ds:Signature/ds:SignatureValue'. Unless this value can be updated using the private key it will not be possible to reproduce the hash contained within the signature and the change will be detected. This is why its important that the private key is kept private.

Note that it is not necessary to have the private key to verify the signature only to update it. Because a copy of the certificate associated with the private key is recorded in the signature and the certificate contains the public key, the signature can be verified without the private key. The wonder of RSA cryptography.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment