int X509v3_addr_is_canonical(IPAddrBlocks *addr)
{
    unsigned char a_min[ADDR_RAW_BUF_LEN], a_max[ADDR_RAW_BUF_LEN];
    unsigned char b_min[ADDR_RAW_BUF_LEN], b_max[ADDR_RAW_BUF_LEN];
    IPAddressOrRanges *aors;
    int i, j, k;

    /*
     * Empty extension is canonical.
     */
    if (addr == NULL)
        return 1;

    /*
     * Check whether the top-level list is in order.
     */
    for (i = 0; i < sk_IPAddressFamily_num(addr) - 1; i++) {
        const IPAddressFamily *a = sk_IPAddressFamily_value(addr, i);
        const IPAddressFamily *b = sk_IPAddressFamily_value(addr, i + 1);
        if (IPAddressFamily_cmp(&a, &b) >= 0)
            return 0;
    }

    /*
     * Top level's ok, now check each address family.
     */
    for (i = 0; i < sk_IPAddressFamily_num(addr); i++) {
        IPAddressFamily *f = sk_IPAddressFamily_value(addr, i);
        int length = length_from_afi(X509v3_addr_get_afi(f));

        /*
         * Inheritance is canonical.  Anything other than inheritance or
         * a SEQUENCE OF IPAddressOrRange is an ASN.1 error or something.
         */
        if (f == NULL || f->ipAddressChoice == NULL)
            return 0;
        switch (f->ipAddressChoice->type) {
        case IPAddressChoice_inherit:
            continue;
        case IPAddressChoice_addressesOrRanges:
            break;
        default:
            return 0;
        }

        /*
         * It's an IPAddressOrRanges sequence, check it.
         */
        aors = f->ipAddressChoice->u.addressesOrRanges;
        if (sk_IPAddressOrRange_num(aors) == 0)
            return 0;
        for (j = 0; j < sk_IPAddressOrRange_num(aors) - 1; j++) {
            IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
            IPAddressOrRange *b = sk_IPAddressOrRange_value(aors, j + 1);

            if (!extract_min_max(a, a_min, a_max, length) ||
                !extract_min_max(b, b_min, b_max, length))
                return 0;

            /*
             * Punt misordered list, overlapping start, or inverted range.
             */
            if (memcmp(a_min, b_min, length) >= 0 ||
                memcmp(a_min, a_max, length) > 0 ||
                memcmp(b_min, b_max, length) > 0)
                return 0;

            /*
             * Punt if adjacent or overlapping.  Check for adjacency by
             * subtracting one from b_min first.
             */
            for (k = length - 1; k >= 0 && b_min[k]-- == 0x00; k--) ;
            if (memcmp(a_max, b_min, length) >= 0)
                return 0;

            /*
             * Check for range that should be expressed as a prefix.
             */
            if (a->type == IPAddressOrRange_addressRange &&
                range_should_be_prefix(a_min, a_max, length) >= 0)
                return 0;
        }

        /*
         * Check range to see if it's inverted or should be a
         * prefix.
         */
        j = sk_IPAddressOrRange_num(aors) - 1;
        {
            IPAddressOrRange *a = sk_IPAddressOrRange_value(aors, j);
            if (a != NULL && a->type == IPAddressOrRange_addressRange) {
                if (!extract_min_max(a, a_min, a_max, length))
                    return 0;
                if (memcmp(a_min, a_max, length) > 0 ||
                    range_should_be_prefix(a_min, a_max, length) >= 0)
                    return 0;
            }
        }
    }

    /*
     * If we made it through all that, we're happy.
     */
    return 1;
}