Suppose we have a document like this:
<?xml version="1.0"?>
<root xmlns="urn-foo-bar">
<subroot>
<value1>value1</value1>
<value2>value2</value2>
</subroot>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform
Algorithm="http://www.w3.org/2000/09/
xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>1Xp...EOko=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>nls...cH0k=</SignatureValue>
<KeyInfo>
<KeyValue>
<RSAKeyValue>
<Modulus>9f3W...fxG0E=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
<X509Data>
<X509Certificate>MIIEi...ktYgN</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
</root>
This document represents data and an enveloped digital signature over the complete XML document. The digital signature completeness is defined in the Reference element, which has URI attribute set to empty string (Reference Uri="").
Checking the Signature
The following should always be applied during signature validation:
- Validating the digital signature
- Validating the certificate(s) used to create the signature
- Validating the certificate(s) chain(s)
Note: In most situations this is the optimal validation sequence. Why? Signatures are broken far more frequently then certificates are revoked/expired. And certificates are revoked/expired far more frequently then their chains.
1. Validating the digital signature
First, get it out of there:
XmlNamespaceManager xmlns = new XmlNamespaceManager(xdkDocument.NameTable); [1]
xmlns.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");
XmlNodeList nodeList = xdkDocument.SelectNodes("//ds:Signature", xmlns);
[1] xdkDocument should be an XmlDocument instance representing your document.
Second, construct a SignedXml instance:
foreach (XmlNode xmlNode in nodeList)
{
// create signed xml object
SignedXml signedXml = new SignedXml(xdkDocument); [2]
// verify signature
signedXml.LoadXml((XmlElement)xmlNode);
}
[2] Note that we are constructing the SignedXml instance from a complete document, not only the signature. Read this.
Third, validate:
bool booSigValid = signedXml.CheckSignature();
If booSigValid is true, proceed.
2. Validating the certificate(s) used to create the signature
First, get it out of there:
XmlNode xndCert = xmlNode.SelectSingleNode(".//ds:X509Certificate", xmlns); [3]
[3] There can be multiple X509Certificate elements qualified with http://www.w3.org/2000/09/xmldsig# namespace in there. Xml Digital Signature specification is allowing the serialization of a complete certificate chain of the certificate used to sign the document. Normally, the signing certificate should be the first to be serialized.
Second, get the X509Certificate2 instance:
byte[] bytCert = Convert.FromBase64String(xndCert.InnerText);
X509Certificate2 x509cert = new X509Certificate2(bytCert);
Third, validate:
bool booCertValid = x509cert.Verify();
If booCertValid is true, proceed.
3. Validating the certificate(s) chain(s)
Building and validating the chain:
X509Chain certChain = new X509Chain();
bool booChainValid = certChain.Build(x509cert);
int intChainLength = certChain.ChainElements.Count; [4]
If booChainValid is true, your signature is valid.
Some Rules and Some Laws
We have three booleans:
- booSigValid - signature validity
- booCertValid - certificate validity
- booChainValid - certificate's chain validity
If booSigValid evaluates to false, there is no discussion. Someone changed the document.
What happens if one of the following two expressions evaluates to true:
1. ((booSigValid) && (!booCertValid) && (!booChainValid))
2. ((booSigValid) && (booCertValid) && (!booChainValid))
This normally means that either the certificate is not valid (CRLed or expired) [4], or one of the chain's certificate is not valid/expired.
[4] The premise is that one checked the signature according to 1, 2, 3 schema described above.
The Question
Is digital signature valid even if CA revoked the certificate after the signature has already been done? Is it valid even after the certificate expires? If signature is valid and certificate has been revoked, what is the legal validity of the signature?
In legal terms, the signature would be invalid on both upper assertions, 1 and 2.
This means, that once the generator of the signature is dead, or one of his predecessors is dead, all his children die too.
Timestamps to the Rescue
According to most country's digital signature laws the signature is valid only during the validity of the signing certificate and validity of the signing certificate's chain, both being checked for revocation and expiry date ... if you don't timestamp it.
If the source document has another signature from a trusted authority, and that authority is a timestamp authority, it would look like this:
<?xml version="1.0"?>
<root xmlns="urn-foo-bar">
<subroot>
<value1>value1</value1>
<value2>value2</value2>
</subroot>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
...
</Signature>
<dsig:Signature Id="TimeStampToken"
xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<dsig:SignedInfo>
<dsig:CanonicalizationMethod
Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<dsig:SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<dsig:Reference
URI="#TimeStampInfo-113D2EEB158BBB2D7CC000000000004DF65">
<dsig:DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>y+xw...scKg=</dsig:DigestValue>
</dsig:Reference>
<dsig:Reference URI="#TimeStampAuthority">
<dsig:DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<dsig:DigestValue>KhFIr...Sv4=</dsig:DigestValue>
<dsig:/Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>R4m...k3aQ==</dsig:SignatureValue>
<dsig:KeyInfo Id="TimeStampAuthority">
<dsig:X509Data>
<dsig:X509Certificate>MII...Osmg==</dsig:X509Certificate>
</dsig:X509Data>
</dsig:KeyInfo>
<dsig:Object
Id="TimeStampInfo-113D2EEB158BBB2D7CC000000000004DF65">
<ts:TimeStampInfo
xmlns:ts="http://www.provider.com/schemas
/timestamp-protocol-20020207"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ts:Policy id="http://provider.tsa.com/documents" />
<ts:Digest>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/
09/xmldsig#sha1" />
<ds:DigestValue>V7+bH...Kmsec=</ds:DigestValue>
</ts:Digest>
<ts:SerialNumber>938...045</ts:SerialNumber>
<ts:CreationTime>2008-04-13T11:31:42.004Z</ts:CreationTime>
<ts:Nonce>121...780</ts:Nonce>
</ts:TimeStampInfo>
</dsig:Object>
</dsig:Signature>
</root>
The second signature would be performed by an out-of-band authority, normally a TSA authority. It would only sign a hash value (in this case SHA1 hash) which was constructed by hashing the original document and the included digital signature.
This (second) signature should be checked using the same 1, 2, 3 steps. For the purpose of this mind experiment, let's say it would generate a booTimestampValid boolean.
Now, let's reexamine the booleans:
- ((booSigValid) && (!booCertValid) && (!booChainValid) && (booTimestampValid))
- ((booSigValid) && (booCertValid) && (!booChainValid) && (booTimestampValid))
In this case, even though the signature's certificate (or its chain) is invalid, the signature would pass legal validity if the timesamp's signature is valid, together with its certificate and certificate chain. Note that the TSA signature is generated with a different set of keys than the original digital signature.
Actually booTimestampValid is defined as ((booSigValid) && (booCertValid) && (booChainValid)) for the timestamp signature/certificate/certificate chain [5].
[5] Legal validity is guaranteed only in cases where 1 or 2 are true.