Handle invalid RFC 1964 tokens [CVE-2014-4341...]

Detect the following cases which would otherwise cause invalid memory
accesses and/or integer underflow:

* An RFC 1964 token being processed by an RFC 4121-only context
  [CVE-2014-4342]

* A header with fewer than 22 bytes after the token ID or an
  incomplete checksum [CVE-2014-4341 CVE-2014-4342]

* A ciphertext shorter than the confounder [CVE-2014-4341]

* A declared padding length longer than the plaintext [CVE-2014-4341]

If we detect a bad pad byte, continue on to compute the checksum to
avoid creating a padding oracle, but treat the checksum as invalid
even if it compares equal.

CVE-2014-4341:

In MIT krb5, an unauthenticated remote attacker with the ability to
inject packets into a legitimately established GSSAPI application
session can cause a program crash due to invalid memory references
when attempting to read beyond the end of a buffer.

    CVSSv2 Vector: AV:N/AC:M/Au:N/C:N/I:N/A:P/E:POC/RL:OF/RC:C

CVE-2014-4342:

In MIT krb5 releases krb5-1.7 and later, an unauthenticated remote
attacker with the ability to inject packets into a legitimately
established GSSAPI application session can cause a program crash due
to invalid memory references when reading beyond the end of a buffer
or by causing a null pointer dereference.

    CVSSv2 Vector: AV:N/AC:M/Au:N/C:N/I:N/A:P/E:POC/RL:OF/RC:C

[tlyu@mit.edu: CVE summaries, CVSS]

(cherry picked from commit fb99962cbd063ac04c9a9d2cc7c75eab73f3533d)

ticket: 7949
version_fixed: 1.12.2
status: resolved
kg_unseal(minor_status, context_handle, input_token_buffer,
          message_buffer, conf_state, qop_state, toktype)
    OM_uint32 *minor_status;
    gss_ctx_id_t context_handle;
    gss_buffer_t input_token_buffer;
    gss_buffer_t message_buffer;
    int *conf_state;
    gss_qop_t *qop_state;
    int toktype;
{
    krb5_gss_ctx_id_rec *ctx;
    unsigned char *ptr;
    unsigned int bodysize;
    int err;
    int toktype2;
    int vfyflags = 0;
    OM_uint32 ret;

    ctx = (krb5_gss_ctx_id_rec *) context_handle;

    if (! ctx->established) {
        *minor_status = KG_CTX_INCOMPLETE;
        return(GSS_S_NO_CONTEXT);
    }

    /* parse the token, leave the data in message_buffer, setting conf_state */

    /* verify the header */

    ptr = (unsigned char *) input_token_buffer->value;


    err = g_verify_token_header(ctx->mech_used,
                                &bodysize, &ptr, -1,
                                input_token_buffer->length,
                                vfyflags);
    if (err) {
        *minor_status = err;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (bodysize < 2) {
        *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    toktype2 = load_16_be(ptr);

    ptr += 2;
    bodysize -= 2;

    switch (toktype2) {
    case KG2_TOK_MIC_MSG:
    case KG2_TOK_WRAP_MSG:
    case KG2_TOK_DEL_CTX:
        ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
                                          ptr, bodysize, message_buffer,
                                          conf_state, qop_state, toktype);
        break;
    case KG_TOK_MIC_MSG:
    case KG_TOK_WRAP_MSG:
    case KG_TOK_DEL_CTX:
        ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
                           message_buffer, conf_state, qop_state,
                           toktype);
        break;
    default:
        *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
        ret = GSS_S_DEFECTIVE_TOKEN;
        break;
    }

    if (ret != 0)
        save_error_info (*minor_status, ctx->k5_context);

    return ret;
}

kg_unseal(minor_status, context_handle, input_token_buffer,
          message_buffer, conf_state, qop_state, toktype)
    OM_uint32 *minor_status;
    gss_ctx_id_t context_handle;
    gss_buffer_t input_token_buffer;
    gss_buffer_t message_buffer;
    int *conf_state;
    gss_qop_t *qop_state;
    int toktype;
{
    krb5_gss_ctx_id_rec *ctx;
    unsigned char *ptr;
    unsigned int bodysize;
    int err;
    int toktype2;
    int vfyflags = 0;
    OM_uint32 ret;

    ctx = (krb5_gss_ctx_id_rec *) context_handle;

    if (! ctx->established) {
        *minor_status = KG_CTX_INCOMPLETE;
        return(GSS_S_NO_CONTEXT);
    }

    /* parse the token, leave the data in message_buffer, setting conf_state */

    /* verify the header */

    ptr = (unsigned char *) input_token_buffer->value;


    err = g_verify_token_header(ctx->mech_used,
                                &bodysize, &ptr, -1,
                                input_token_buffer->length,
                                vfyflags);
    if (err) {
        *minor_status = err;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (bodysize < 2) {
        *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    toktype2 = load_16_be(ptr);

    ptr += 2;
    bodysize -= 2;

    switch (toktype2) {
    case KG2_TOK_MIC_MSG:
    case KG2_TOK_WRAP_MSG:
    case KG2_TOK_DEL_CTX:
        ret = gss_krb5int_unseal_token_v3(&ctx->k5_context, minor_status, ctx,
                                          ptr, bodysize, message_buffer,
                                          conf_state, qop_state, toktype);
        break;
    case KG_TOK_MIC_MSG:
    case KG_TOK_WRAP_MSG:
    case KG_TOK_DEL_CTX:
        ret = kg_unseal_v1(ctx->k5_context, minor_status, ctx, ptr, bodysize,
                           message_buffer, conf_state, qop_state,
                           toktype);
        break;
    default:
        *minor_status = (OM_uint32)G_BAD_TOK_HEADER;
        ret = GSS_S_DEFECTIVE_TOKEN;
        break;
    }

    if (ret != 0)
        save_error_info (*minor_status, ctx->k5_context);

    return ret;
}
