Subject: bug#31946: 27.0.50; The NSM should warn about more TLS problems

From: Noam Postavsky <[email-masked]>
Date: Sun, 29 Jul 2018 10:45:38 -0400

Lars Ingebrigtsen <[email-masked]> writes:

> Noam Postavsky <[email-masked]> writes:
>
>> Going by the certificate serial number, Firefox doesn't show this
>> certificate at all in the chain.

> Yeah, I didn't get any further here, and I don't know what more to
> check...

gnutls rejects SHA1 certificates by default as of 3.6.0, so I tried with
the latest stable gnutls version (3.6.3), and it does reject
sha1-intermediate.badssl.com while accepting www.usps.com.  Stepping
through with gdb I see the problematic certificate is dropped in
_gnutls_verify_crt_status, the *second* time it's called from
gnutls_x509_trust_list_verify_crt2.  I'm not sure yet how we can use
this from Emacs, but at least it's a direction to look in.

    int
    gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
    [...]
    {
        [...]
            hash_pjw_bare(cert_list[cert_list_size - 1]->raw_issuer_dn.
            [...]
            _gnutls_verify_crt_status(cert_list, cert_list_size,
                                            list->node[hash].trusted_cas,
                                            list->
                                            node[hash].trusted_ca_size,
                                            flags, purpose, func);
            if (SIGNER_OLD_OR_UNKNOWN(*voutput)
               [...]) {
                    /* if we couldn't find the issuer, try to see if the last
                     * certificate is in the trusted list and try to verify against
                     * (if it is not self signed) */
                        hash_pjw_bare(cert_list[cert_list_size - 1]->raw_dn.
                        [...]
                     _gnutls_debug_log("issuer in verification was not found or insecure; trying against trust list\n");

                    *voutput =
                        _gnutls_verify_crt_status(cert_list, cert_list_size,
                                                list->node[hash].trusted_cas,
                                                list->
                                                node[hash].trusted_ca_size,
                                                flags, purpose, func);

    unsigned int
    _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
    [...]
    {
       [...]
        /* We want to shorten the chain by removing the cert that matches
         * one of the certs we trust and all the certs after that i.e. if
         * cert chain is A signed-by B signed-by C signed-by D (signed-by
         * self-signed E but already removed above), and we trust B, remove
         * B, C and D. */
         [...]

        for (; i < clist_size; i++) { [...]
            for (j = 0; j < tcas_size; j++) { [...]
                /* we check for a certificate that may not be identical with the one
                 * sent by the client, but will have the same name and key. That is
                 * because it can happen that a CA certificate is upgraded from intermediate
                 * CA to self-signed CA at some point. */
                if (_gnutls_check_if_same_key
                    (certificate_list[i], trusted_cas[j], i) != 0) {
                    /* explicit time check for trusted CA that we remove from
                     * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
                     */
                    [...]
                    clist_size = i;