Prevent KDC unset status assertion failures

Assign status values if S4U2Self padata fails to decode, if an
S4U2Proxy request uses invalid KDC options, or if an S4U2Proxy request
uses an evidence ticket which does not match the canonicalized request
server principal name.  Reported by Samuel Cabrero.

If a status value is not assigned during KDC processing, default to
"UNKNOWN_REASON" rather than failing an assertion.  This change will
prevent future denial of service bugs due to similar mistakes, and
will allow us to omit assigning status values for unlikely errors such
as small memory allocation failures.

CVE-2017-11368:

In MIT krb5 1.7 and later, an authenticated attacker can cause an
assertion failure in krb5kdc by sending an invalid S4U2Self or
S4U2Proxy request.

  CVSSv3 Vector: AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H/E:H/RL:O/RC:C

ticket: 8599 (new)
target_version: 1.15-next
target_version: 1.14-next
tags: pullup
gen_session_key(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
                krb5_db_entry *server, krb5_keyblock *skey,
                const char **status)
{
    krb5_error_code retval;
    krb5_enctype useenctype = 0;

    /*
     * Some special care needs to be taken in the user-to-user
     * case, since we don't know what keytypes the application server
     * which is doing user-to-user authentication can support.  We
     * know that it at least must be able to support the encryption
     * type of the session key in the TGT, since otherwise it won't be
     * able to decrypt the U2U ticket!  So we use that in preference
     * to anything else.
     */
    if (req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
        retval = get_2ndtkt_enctype(kdc_active_realm, req, &useenctype,
                                    status);
        if (retval != 0)
            goto cleanup;
    }
    if (useenctype == 0) {
        useenctype = select_session_keytype(kdc_active_realm, server,
                                            req->nktypes,
                                            req->ktype);
    }
    if (useenctype == 0) {
        /* unsupported ktype */
        *status = "BAD_ENCRYPTION_TYPE";
        retval = KRB5KDC_ERR_ETYPE_NOSUPP;
        goto cleanup;
    }
    retval = krb5_c_make_random_key(kdc_context, useenctype, skey);
    if (retval != 0) {
        /* random key failed */
        *status = "MAKE_RANDOM_KEY";
        goto cleanup;
    }
cleanup:
    return retval;
}

gen_session_key(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
                krb5_db_entry *server, krb5_keyblock *skey,
                const char **status)
{
    krb5_error_code retval;
    krb5_enctype useenctype = 0;

    /*
     * Some special care needs to be taken in the user-to-user
     * case, since we don't know what keytypes the application server
     * which is doing user-to-user authentication can support.  We
     * know that it at least must be able to support the encryption
     * type of the session key in the TGT, since otherwise it won't be
     * able to decrypt the U2U ticket!  So we use that in preference
     * to anything else.
     */
    if (req->kdc_options & KDC_OPT_ENC_TKT_IN_SKEY) {
        retval = get_2ndtkt_enctype(kdc_active_realm, req, &useenctype,
                                    status);
        if (retval != 0)
            goto cleanup;
    }
    if (useenctype == 0) {
        useenctype = select_session_keytype(kdc_active_realm, server,
                                            req->nktypes,
                                            req->ktype);
    }
    if (useenctype == 0) {
        /* unsupported ktype */
        *status = "BAD_ENCRYPTION_TYPE";
        retval = KRB5KDC_ERR_ETYPE_NOSUPP;
        goto cleanup;
    }
    retval = krb5_c_make_random_key(kdc_context, useenctype, skey);
    if (retval != 0) {
        /* random key failed */
        *status = "MAKE_RANDOM_KEY";
        goto cleanup;
    }
cleanup:
    return retval;
}
