/* Compare two certificates: they must be identical for this to work. NB: Although "cmp" operations are generally prototyped to take "const" arguments (eg. for use in STACKs), the way X509 handling is - these operations may involve ensuring the hashes are up-to-date and ensuring certain cert information is cached. So this is the point where the "depth-first" constification tree has to halt with an evil cast.  */
int X509_cmp(const X509 *a, const X509 *b)
/* Compare two certificates: they must be identical for this to work. NB: Although "cmp" operations are generally prototyped to take "const" arguments (eg. for use in STACKs), the way X509 handling is - these operations may involve ensuring the hashes are up-to-date and ensuring certain cert information is cached. So this is the point where the "depth-first" constification tree has to halt with an evil cast.  */
int X509_cmp(const X509 *a, const X509 *b)
{
    int rv;
    X509_check_purpose((X509 *)a, -1, 0);
    X509_check_purpose((X509 *)b, -1, 0);
    rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH);
    if (rv)
        return rv;
    if (!a->cert_info->enc.modified && !b->cert_info->enc.modified) {
        rv = (int)(a->cert_info->enc.len - b->cert_info->enc.len);
        if (rv)
            return rv;
        return memcmp(a->cert_info->enc.enc, b->cert_info->enc.enc,
                      a->cert_info->enc.len);
    }
    return rv;
}