Basics of XML signature validation

Adobe AIR 1.5 and later

For a quick explanation and code examples of validating XML signatures, see the following quick start articles on the Adobe Developer Connection:

Adobe® AIR® provides the XMLSignatureValidator class and IURIDereferencer interface for validating XML signatures. The XML syntax accepted by the XMLSignatureValidator class is a subset of the W3C recommendation for XML Signature Syntax and Processing. (Because only a subset of the recommendation is supported, not all legal signatures can be validated.) AIR does not provide an API for creating XML signatures.

XML signature validation classes

The XML signature validation API includes the following classes:

Package

Classes

flash.security

XMLSignatureValidator string constants are defined in the following classes:

flash.events

Using the XML signature validation classes

To use the XMLSignatureValidator class to validate an XML signature, you must:

  • Create an XMLSignatureValidator object

  • Provide an implementation of the IURIDereferencer interface. The XMLSignatureValidator object calls the IURIDereferencer dereference() method, passing in the URI for each reference in a signature. The dereference() method must resolve the URI and return the referenced data (which could be in the same document as the signature, or could be in an external resource).

  • Set the certificate trust, revocation checking, and reference validation settings of the XMLSignatureValidator object as appropriate for your application.

  • Add event listeners for the complete and error events.

  • Call the verify() method, passing in the signature to validate.

  • Handle the complete and error events and interpret the results.

The following example implements a validate() function that verifies the validity of an XML signature. The XMLSignatureValidator properties are set such that the signing certificate must be in the system trust store, or chain to a certificate in the trust store. The example also assumes that a suitable IURIDereferencer class named XMLDereferencer exists.

private function validate( xmlSignature:XML ):void 
{ 
    var verifier:XMLSignatureValidator = new XMLSignatureValidator(); 
    verifier.addEventListener(Event.COMPLETE, verificationComplete); 
    verifier.addEventListener(ErrorEvent.ERROR, verificationError); 
    try 
    { 
        verifier.uriDereferencer = new XMLDereferencer(); 
 
        verifier.referencesValidationSetting = 
            ReferencesValidationSetting.VALID_IDENTITY; 
        verifier.revocationCheckSetting = RevocationCheckSettings.BEST_EFFORT; 
        verifier.useSystemTrustStore = true; 
         
        //Verify the signature 
        verifier.verify( xmlSignature ); 
    } 
    catch (e:Error) 
        { 
            trace("Verification error.\n" + e); 
        } 
} 
 
//Trace verification results 
private function verificationComplete(event:Event):void 
 
    var signature:XMLSignatureValidator = event.target as XMLSignatureValidator; 
    trace("Signature status: " + signature.validityStatus + "\n"); 
    trace("  Digest status: " + signature.digestStatus + "\n"); 
    trace("  Identity status: " + signature.identityStatus + "\n"); 
    trace("  Reference status: " + signature.referencesStatus + "\n"); 
} 
 
private function verificationError(event:ErrorEvent):void 
{ 
    trace("Verification error.\n" + event.text);                 
}

The XML signature validation process

When you call the XMLSignatureValidator verify() method, AIR performs the following steps:

  • The runtime verifies the cryptographic integrity of the signature using the public key of the signing certificate.

  • The runtime establishes the cryptographic integrity, identity, and trustworthiness of the certificate based on the current settings of the XMLSignatureValidator object.

    The trust placed in the signing certificate is key to the integrity of the validation process. Signature validation is conducted using a well-defined cryptographic process, but the trustworthiness of the signing certificate is a judgment that cannot be made algorithmically.

    In general, you have three ways to decide whether a certificate is trustworthy:

    • By relying on certification authorities and the operating system trust store.

    • By obtaining, directly from the signer, a copy of the certificate, another certificate that serves as a trust anchor for the certificate, or sufficient information to reliably identify the certificate, such as the public key.

    • Asking the end user of your application if they trust the certificate. Such a query is invalid with self-signed certificates since the identifying information in the certificate is inherently unreliable.

  • The runtime verifies the cryptographic integrity of the signed data.

    The signed data is verified with the help of your IURIDereferencer implementation. For each reference in the signature document, the IURIDereferencer implementation dereference() method is called. The data returned by the dereference() method is used to compute the reference digest. This digest value is compared to the digest recorded in the signature document. If the digests match, then the data has not been altered since it was signed.

    One important consideration when relying on the results of validating an XML signature is that only what is signed is secure. For example, consider a signed manifest listing the files in a package. When the XMLSignatureValidator verifies the signature, it only checks whether the manifest itself is unaltered. The data in the files is not signed, so the signature will still validate when files referenced in the manifest are changed or deleted.

    Note: To verify files in such a manifest, you can compute the digest of the file data (using the same hashing algorithm used in the manifest) and compare the result to the digest stored in the signed manifest. In some cases, you should also check for the presence of additional files.

Interpreting validation results

The validation results are reported by the status properties of the XMLSignatureValidator object. These properties can be read after the validator object dispatches the complete event. The four status properties include: validityStatus , digestStatus , identityStatus , and referencesStatus .

The validityStatus property

The validityStatus property reports the overall validity of the signature. The validityStatus depends on the state of the other three status properties and can have one of the following values:

  • valid — If digestStatus , identityStatus , and referencesStatus are all valid .

  • invalid — If one or more of the individual status properties is invalid .

  • unknown — If one or more of the individual status properties is unknown and no individual status is invalid .

The digestStatus property

The digestStatus property reports the results of the cryptographic verification of the message digest. The digestStatus property can have one of the following values:

  • valid — If the signature document itself is unaltered since signing.

  • invalid — If the signature document has been altered or is malformed.

  • unknown — If the verify() method has not completed without error.

The identityStatus property

The identityStatus property reports the status of the signing certificate. The value of this property depends on several factors including:

  • the cryptographic integrity of the certificate

  • whether the certificate is expired or revoked

  • whether the certificate is trusted on the current machine

  • the state of the XMLSignatureValidator object (such as whether additional certificates have been added for building the trust chain, whether those certificates are trusted, and the values of the useSystemTrustStore and revocationCheckSettings properties)

The identityStatus property can have the following values:
  • valid — To be considered valid, the signing certificate must meet the following conditions:

    • The signing certificate must be unaltered.

    • The signing certificate must not be expired or revoked—except when a valid timestamp is present in the signature. If the signature is timestamped, the certificate will be considered valid as long as it was valid at the time the document was signed. (The certificate used by the timestamp service to sign the timestamp must chain to a trusted root certificate on the user’s computer.)

    • The signing certificate is trusted. A certificate is trusted if the certificate is in the system trust store or chains to another certificate in the system trust store and you set the useSystemTrustStore property to true. You can also designate a certificate as trusted using the addCertificate() method of the XMLSignatureValidator object.

    • The certificate is, in fact, the signing certificate.

  • invalid — The certificate is expired or revoked—and no timestamp proving validity at the time of signing is present—or the certificate has been altered.

  • unknown — If the certificate is not invalid, but is not trusted either. Self-signed certificates, for example, will be reported as unknown (unless explicitly trusted). The identityStatus is also reported as unknown if the verify() method has not completed without error or if the identity has not been checked because the signature digest is invalid.

The referencesStatus property

The referencesStatus property reports the cryptographic integrity of the references in the SignedData element of the signature.

  • valid — If the computed digest of every reference in the signature matches the corresponding digest recorded in the XML signature. A valid status indicates that the signed data has not been altered.

  • invalid — If any computed digest does not match the corresponding digest in the signature.

  • unknown — If the reference digests have not been checked. The references are not checked if the overall signature digest is invalid or the signing certificate is invalid. If the identityStatus is unknown , then the references are only checked when the referencesValidationSetting is validOrUnknown .

// Ethnio survey code removed