[Prev]

12.4.2 Signature Validation

For signature validation you need to walk the decoded data structure to locate the signature as well as the references and pass them to zxsig_validate(). The validation involves wire order exclusive canonical encoding of the referenced XML blobs, computation of SHA1 or MD5 checksums over them, and finally computation of SHA1 check sum over the <SignedInfo> element and validation of the actual <SignatureValue> against that. The validation involves public key decryption using the signer's certificate.

A nasty problem in exclusive canonicalization is that the namespaces that are needed in the blob may actually appear in the containing XML structures, thus in order to know the correct meaning of a namespace prefix, we need to perform the seen computation for all elements outside and above the blob of interest. ((This is yet another
 indication of how botched the XML namespace concept is. Or this could
 have been fixed in the exclusive canonicalization spec by not using
 namespace prefixes at all.))

To verify signature, you have to do certain amount of preparatory work to locate the signature and the data that was signed. Generally what should be signed will be evident from protocol specifications or from the security requirements of your application environment. Conversely, if there is a signature, but it does not reference the appropriate elements, its worthless and you might as well reject the document without even verifying the signature.

Example

    struct zxsig_ref refs[1];
    cf = zxid_new_conf("/var/zxid/");
    ent = zxid_get_ent_from_file(cf, "YV7HPtu3bfqW3I4W_DZr-_DKMP4.");
    
    refs[0].ref = r->Envelope->Body->ArtifactResolve
                   ->Signature->SignedInfo->Reference;
    refs[0].blob = (struct zx_elem_s*)r->Envelope->Body->ArtifactResolve;
    res = zxsig_validate(cf->ctx, ent->sign_cert,
                         r->Envelope->Body->ArtifactResolve->Signature,
                         1, refs);
    if (res == ZXSIG_OK) {
      D("sig vfy ok %d", res);
    } else {
      ERR("sig vfy failed due to(%d)", res);
    }

This code illustrates

  1. You have to determine who signed and provide the entity object that corresponds to the signer. Often you would determine the entity from <Issuer> element somewhere inside the message.

    The entity is used for retrieving the signing certificate. Another alternative is that the signature itself contains a <KeyInfo> element and you extract the certificate from there. You would still need to have a way to know if you trust the certificate.

  2. You have to prepare the refs array. It contains pairs of <SignedInfo><Reference> specifications combined with the actual elements that are signed. Generally the URI XML attribute of the <Reference> element points to the data that was signed. However, it is application dependent what type of ID XML attribute the URI actually references or the URI could even reference something outside the document. It would be way too unreliable for the zxsig_validate() to attempt guessing how to locate the signed data: therefore we push the responsibility to you. Your code will have to walk the data to locate all referenced bits and pieces.

    In the above example, locating the one signed bit was very easy: the specification says where it is (and this location is fixed so there really is no need to check the URI either).

    You pass the length of the refs array and the array itself as two last arguments to zxsig_validate().

  3. You need to locate the <Signature> element in the document and pass it as argument to zxsig_validate(). Usually a protocol specification will say where the <Signature> element is to be found, so locating it is not difficult.

  4. The return value will indicate validation status. ZXSIG_OK, which has numerical value of 0, indicates success. Other nonzero values indicate various kinds of failure.


[Prev | Next]