Example #1
0
krb5_error_code
kg_make_confounder(krb5_context context, krb5_enctype enctype,
                   unsigned char *buf)
{
    int confsize;
    krb5_data lrandom;

    confsize = kg_confounder_size(context, enctype);
    if (confsize < 0)
        return KRB5_BAD_MSIZE;

    lrandom.length = confsize;
    lrandom.data = (char *)buf;

    return(krb5_c_random_make_octets(context, &lrandom));
}
Example #2
0
static krb5_error_code
make_seal_token_v1_iov(krb5_context context,
                       krb5_gss_ctx_id_rec *ctx,
                       int conf_req_flag,
                       int *conf_state,
                       gss_iov_buffer_desc *iov,
                       int iov_count,
                       int toktype)
{
    krb5_error_code code = 0;
    gss_iov_buffer_t header;
    gss_iov_buffer_t padding;
    gss_iov_buffer_t trailer;
    krb5_checksum md5cksum;
    krb5_checksum cksum;
    size_t k5_headerlen = 0, k5_trailerlen = 0;
    size_t data_length = 0, assoc_data_length = 0;
    size_t tmsglen = 0, tlen;
    unsigned char *ptr;
    krb5_keyusage sign_usage = KG_USAGE_SIGN;

    assert(toktype == KG_TOK_WRAP_MSG);

    md5cksum.length = cksum.length = 0;
    md5cksum.contents = cksum.contents = NULL;

    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
    if (header == NULL)
        return EINVAL;

    padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
    if (padding == NULL && (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
        return EINVAL;

    trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
    if (trailer != NULL)
        trailer->buffer.length = 0;

    /* Determine confounder length */
    if (toktype == KG_TOK_WRAP_MSG || conf_req_flag)
        k5_headerlen = kg_confounder_size(context, ctx->enc);

    /* Check padding length */
    if (toktype == KG_TOK_WRAP_MSG) {
        size_t k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
        size_t gss_padlen;
        size_t conf_data_length;

        kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
        conf_data_length = k5_headerlen + data_length - assoc_data_length;

        if (k5_padlen == 1)
            gss_padlen = 1; /* one byte to indicate one byte of padding */
        else
            gss_padlen = k5_padlen - (conf_data_length % k5_padlen);

        if (ctx->gss_flags & GSS_C_DCE_STYLE) {
            /* DCE will pad the actual data itself; padding buffer optional and will be zeroed */
            gss_padlen = 0;

            if (conf_data_length % k5_padlen)
                code = KRB5_BAD_MSIZE;
        } else if (padding->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
            code = kg_allocate_iov(padding, gss_padlen);
        } else if (padding->buffer.length < gss_padlen) {
            code = KRB5_BAD_MSIZE;
        }
        if (code != 0)
            goto cleanup;

        /* Initialize padding buffer to pad itself */
        if (padding != NULL) {
            padding->buffer.length = gss_padlen;
            memset(padding->buffer.value, (int)gss_padlen, gss_padlen);
        }

        if (ctx->gss_flags & GSS_C_DCE_STYLE)
            tmsglen = k5_headerlen; /* confounder length */
        else
            tmsglen = conf_data_length + padding->buffer.length + assoc_data_length;
    }

    /* Determine token size */
    tlen = g_token_size(ctx->mech_used, 14 + ctx->cksum_size + tmsglen);

    k5_headerlen += tlen - tmsglen;

    if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
        code = kg_allocate_iov(header, k5_headerlen);
    else if (header->buffer.length < k5_headerlen)
        code = KRB5_BAD_MSIZE;
    if (code != 0)
        goto cleanup;

    header->buffer.length = k5_headerlen;

    ptr = (unsigned char *)header->buffer.value;
    g_make_token_header(ctx->mech_used, 14 + ctx->cksum_size + tmsglen, &ptr, toktype);

    /* 0..1 SIGN_ALG */
    store_16_le(ctx->signalg, &ptr[0]);

    /* 2..3 SEAL_ALG or Filler */
    if (toktype == KG_TOK_WRAP_MSG && conf_req_flag) {
        store_16_le(ctx->sealalg, &ptr[2]);
    } else {
        /* No seal */
        ptr[2] = 0xFF;
        ptr[3] = 0xFF;
    }

    /* 4..5 Filler */
    ptr[4] = 0xFF;
    ptr[5] = 0xFF;

    /* pad the plaintext, encrypt if needed, and stick it in the token */

    /* initialize the checksum */
    switch (ctx->signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
        break;
    case SGN_ALG_HMAC_MD5:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
        if (toktype != KG_TOK_WRAP_MSG)
            sign_usage = 15;
        break;
    default:
    case SGN_ALG_DES_MAC:
        abort ();
    }

    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &k5_trailerlen);
    if (code != 0)
        goto cleanup;
    md5cksum.length = k5_trailerlen;

    if (k5_headerlen != 0) {
        code = kg_make_confounder(context, ctx->enc, ptr + 14 + ctx->cksum_size);
        if (code != 0)
            goto cleanup;
    }

    /* compute the checksum */
    code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
                                   ctx->cksum_size, ctx->seq, ctx->enc,
                                   sign_usage, iov, iov_count, toktype,
                                   &md5cksum);
    if (code != 0)
        goto cleanup;

    switch (ctx->signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_3:
        code = kg_encrypt(context, ctx->seq, KG_USAGE_SEAL,
                          (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ?
                           ctx->seq->contents : NULL),
                          md5cksum.contents, md5cksum.contents, 16);
        if (code != 0)
            goto cleanup;

        cksum.length = ctx->cksum_size;
        cksum.contents = md5cksum.contents + 16 - cksum.length;

        memcpy(ptr + 14, cksum.contents, cksum.length);
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        assert(md5cksum.length == ctx->cksum_size);
        memcpy(ptr + 14, md5cksum.contents, md5cksum.length);
        break;
    case SGN_ALG_HMAC_MD5:
        memcpy(ptr + 14, md5cksum.contents, ctx->cksum_size);
        break;
    }

    /* create the seq_num */
    code = kg_make_seq_num(context, ctx->seq, ctx->initiate ? 0 : 0xFF,
                           (OM_uint32)ctx->seq_send, ptr + 14, ptr + 6);
    if (code != 0)
        goto cleanup;

    if (conf_req_flag) {
        if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
            unsigned char bigend_seqnum[4];
            krb5_keyblock *enc_key;
            size_t i;

            store_32_be(ctx->seq_send, bigend_seqnum);

            code = krb5_copy_keyblock(context, ctx->enc, &enc_key);
            if (code != 0)
                goto cleanup;

            assert(enc_key->length == 16);

            for (i = 0; i < enc_key->length; i++)
                ((char *)enc_key->contents)[i] ^= 0xF0;

            code = kg_arcfour_docrypt_iov(context, enc_key, 0,
                                          bigend_seqnum, 4,
                                          iov, iov_count);
            krb5_free_keyblock(context, enc_key);
        } else {
            code = kg_encrypt_iov(context, ctx->proto,
                                  ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
                                  0 /*EC*/, 0 /*RRC*/,
                                  ctx->enc, KG_USAGE_SEAL, NULL,
                                  iov, iov_count);
        }
        if (code != 0)
            goto cleanup;
    }

    ctx->seq_send++;
    ctx->seq_send &= 0xFFFFFFFFL;

    code = 0;

    if (conf_state != NULL)
        *conf_state = conf_req_flag;

cleanup:
    if (code != 0)
        kg_release_iov(iov, iov_count);
    krb5_free_checksum_contents(context, &md5cksum);

    return code;
}
Example #3
0
OM_uint32
kg_seal_iov_length(OM_uint32 *minor_status,
                   gss_ctx_id_t context_handle,
                   int conf_req_flag,
                   gss_qop_t qop_req,
                   int *conf_state,
                   gss_iov_buffer_desc *iov,
                   int iov_count)
{
    krb5_gss_ctx_id_rec *ctx;
    gss_iov_buffer_t header, trailer, padding;
    size_t data_length, assoc_data_length;
    size_t gss_headerlen, gss_padlen, gss_trailerlen;
    unsigned int k5_headerlen = 0, k5_trailerlen = 0, k5_padlen = 0;
    krb5_error_code code;
    krb5_context context;
    int dce_style;

    if (qop_req != GSS_C_QOP_DEFAULT) {
        *minor_status = (OM_uint32)G_UNKNOWN_QOP;
        return GSS_S_FAILURE;
    }

    if (!kg_validate_ctx_id(context_handle)) {
        *minor_status = (OM_uint32)G_VALIDATE_FAILED;
        return GSS_S_NO_CONTEXT;
    }

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

    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
    if (header == NULL) {
        *minor_status = EINVAL;
        return GSS_S_FAILURE;
    }
    INIT_IOV_DATA(header);

    trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
    if (trailer != NULL) {
        INIT_IOV_DATA(trailer);
    }

    dce_style = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0);

    /* For CFX, EC is used instead of padding, and is placed in header or trailer */
    padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
    if (padding == NULL) {
        if (conf_req_flag && ctx->proto == 0 && !dce_style) {
            *minor_status = EINVAL;
            return GSS_S_FAILURE;
        }
    } else {
        INIT_IOV_DATA(padding);
    }

    kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);

    if (conf_req_flag && kg_integ_only_iov(iov, iov_count))
        conf_req_flag = FALSE;

    context = ctx->k5_context;

    gss_headerlen = gss_padlen = gss_trailerlen = 0;

    if (ctx->proto == 1) {
        krb5_enctype enctype;
        size_t ec;

        if (ctx->have_acceptor_subkey)
            enctype = ctx->acceptor_subkey->enctype;
        else
            enctype = ctx->subkey->enctype;

        code = krb5_c_crypto_length(context, enctype,
                                    conf_req_flag ?
                                        KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
                                    &k5_trailerlen);
        if (code != 0) {
            *minor_status = code;
            return GSS_S_FAILURE;
        }

        if (conf_req_flag) {
            code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
            if (code != 0) {
                *minor_status = code;
                return GSS_S_FAILURE;
            }
        }

        gss_headerlen = 16; /* Header */
        if (conf_req_flag) {
            gss_headerlen += k5_headerlen; /* Kerb-Header */
            gss_trailerlen = 16 /* E(Header) */ + k5_trailerlen; /* Kerb-Trailer */

            code = krb5_c_padding_length(context, enctype,
                                         data_length - assoc_data_length + 16 /* E(Header) */, &k5_padlen);
            if (code != 0) {
                *minor_status = code;
                return GSS_S_FAILURE;
            }

            if (k5_padlen == 0 && dce_style) {
                /* Windows rejects AEAD tokens with non-zero EC */
                code = krb5_c_block_size(context, enctype, &ec);
                if (code != 0) {
                    *minor_status = code;
                    return GSS_S_FAILURE;
                }
            } else
                ec = k5_padlen;

            gss_trailerlen += ec;
        } else {
            gss_trailerlen = k5_trailerlen; /* Kerb-Checksum */
        }
    } else if (!dce_style) {
        k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;

        if (k5_padlen == 1)
            gss_padlen = 1;
        else
            gss_padlen = k5_padlen - ((data_length - assoc_data_length) % k5_padlen);
    }

    data_length += gss_padlen;

    if (ctx->proto == 0) {
        /* Header | Checksum | Confounder | Data | Pad */
        size_t data_size;

        k5_headerlen = kg_confounder_size(context, ctx->enc);

        data_size = 14 /* Header */ + ctx->cksum_size + k5_headerlen;

        if (!dce_style)
            data_size += data_length;

        gss_headerlen = g_token_size(ctx->mech_used, data_size);

        /* g_token_size() will include data_size as well as the overhead, so
         * subtract data_length just to get the overhead (ie. token size) */
        if (!dce_style)
            gss_headerlen -= data_length;
    }

    if (minor_status != NULL)
        *minor_status = 0;

    if (trailer == NULL)
        gss_headerlen += gss_trailerlen;
    else
        trailer->buffer.length = gss_trailerlen;

    assert(gss_padlen == 0 || padding != NULL);

    if (padding != NULL)
        padding->buffer.length = gss_padlen;

    header->buffer.length = gss_headerlen;

    if (conf_state != NULL)
        *conf_state = conf_req_flag;

    return GSS_S_COMPLETE;
}
Example #4
0
/*
 * Split a STREAM | SIGN_DATA | DATA into
 *         HEADER | SIGN_DATA | DATA | PADDING | TRAILER
 */
static OM_uint32
kg_unseal_stream_iov(OM_uint32 *minor_status,
                     krb5_gss_ctx_id_rec *ctx,
                     int *conf_state,
                     gss_qop_t *qop_state,
                     gss_iov_buffer_desc *iov,
                     int iov_count,
                     int toktype)
{
    unsigned char *ptr;
    unsigned int bodysize;
    OM_uint32 code = 0, major_status = GSS_S_FAILURE;
    krb5_context context = ctx->k5_context;
    int conf_req_flag, toktype2;
    int i = 0, j;
    gss_iov_buffer_desc *tiov = NULL;
    gss_iov_buffer_t stream, data = NULL;
    gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;

    assert(toktype == KG_TOK_WRAP_MSG);

    if (toktype != KG_TOK_WRAP_MSG || (ctx->gss_flags & GSS_C_DCE_STYLE)) {
        code = EINVAL;
        goto cleanup;
    }

    stream = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM);
    assert(stream != NULL);

    ptr = (unsigned char *)stream->buffer.value;

    code = g_verify_token_header(ctx->mech_used,
                                 &bodysize, &ptr, -1,
                                 stream->buffer.length, 0);
    if (code != 0) {
        major_status = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
    }

    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;

    tiov = (gss_iov_buffer_desc *)calloc((size_t)iov_count + 2, sizeof(gss_iov_buffer_desc));
    if (tiov == NULL) {
        code = ENOMEM;
        goto cleanup;
    }

    /* HEADER */
    theader = &tiov[i++];
    theader->type = GSS_IOV_BUFFER_TYPE_HEADER;
    theader->buffer.value = stream->buffer.value;
    theader->buffer.length = ptr - (unsigned char *)stream->buffer.value;
    if (bodysize < 14 ||
        stream->buffer.length != theader->buffer.length + bodysize) {
        major_status = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
    }
    theader->buffer.length += 14;

    /* n[SIGN_DATA] | DATA | m[SIGN_DATA] */
    for (j = 0; j < iov_count; j++) {
        OM_uint32 type = GSS_IOV_BUFFER_TYPE(iov[j].type);

        if (type == GSS_IOV_BUFFER_TYPE_DATA) {
            if (data != NULL) {
                /* only a single DATA buffer can appear */
                code = EINVAL;
                goto cleanup;
            }

            data = &iov[j];
            tdata = &tiov[i];
        }
        if (type == GSS_IOV_BUFFER_TYPE_DATA ||
            type == GSS_IOV_BUFFER_TYPE_SIGN_ONLY)
            tiov[i++] = iov[j];
    }

    if (data == NULL) {
        /* a single DATA buffer must be present */
        code = EINVAL;
        goto cleanup;
    }

    /* PADDING | TRAILER */
    tpadding = &tiov[i++];
    tpadding->type = GSS_IOV_BUFFER_TYPE_PADDING;
    tpadding->buffer.length = 0;
    tpadding->buffer.value = NULL;

    ttrailer = &tiov[i++];
    ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;

    switch (toktype2) {
    case KG2_TOK_MIC_MSG:
    case KG2_TOK_WRAP_MSG:
    case KG2_TOK_DEL_CTX: {
        size_t ec, rrc;
        krb5_enctype enctype;
        unsigned int k5_headerlen = 0;
        unsigned int k5_trailerlen = 0;

        if (ctx->have_acceptor_subkey)
            enctype = ctx->acceptor_subkey->keyblock.enctype;
        else
            enctype = ctx->subkey->keyblock.enctype;
        conf_req_flag = ((ptr[0] & FLAG_WRAP_CONFIDENTIAL) != 0);
        ec = conf_req_flag ? load_16_be(ptr + 2) : 0;
        rrc = load_16_be(ptr + 4);

        if (rrc != 0) {
            if (!gss_krb5int_rotate_left((unsigned char *)stream->buffer.value + 16,
                                         stream->buffer.length - 16, rrc)) {
                code = ENOMEM;
                goto cleanup;
            }
            store_16_be(0, ptr + 4); /* set RRC to zero */
        }

        if (conf_req_flag) {
            code = krb5_c_crypto_length(context, enctype, KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
            if (code != 0)
                goto cleanup;
            theader->buffer.length += k5_headerlen; /* length validated later */
        }

        /* no PADDING for CFX, EC is used instead */
        code = krb5_c_crypto_length(context, enctype,
                                    conf_req_flag ? KRB5_CRYPTO_TYPE_TRAILER : KRB5_CRYPTO_TYPE_CHECKSUM,
                                    &k5_trailerlen);
        if (code != 0)
            goto cleanup;

        ttrailer->buffer.length = ec + (conf_req_flag ? 16 : 0 /* E(Header) */) + k5_trailerlen;
        ttrailer->buffer.value = (unsigned char *)stream->buffer.value +
            stream->buffer.length - ttrailer->buffer.length;
        break;
    }
    case KG_TOK_MIC_MSG:
    case KG_TOK_WRAP_MSG:
    case KG_TOK_DEL_CTX:
        theader->buffer.length += ctx->cksum_size +
            kg_confounder_size(context, ctx->enc->keyblock.enctype);

        /*
         * we can't set the padding accurately until decryption;
         * kg_fixup_padding_iov() will take care of this
         */
        tpadding->buffer.length = 1;
        tpadding->buffer.value = (unsigned char *)stream->buffer.value + stream->buffer.length - 1;

        /* no TRAILER for pre-CFX */
        ttrailer->buffer.length = 0;
        ttrailer->buffer.value = NULL;

        break;
    default:
        code = (OM_uint32)G_BAD_TOK_HEADER;
        major_status = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
        break;
    }

    /* IOV: -----------0-------------+---1---+--2--+----------------3--------------*/
    /* Old: GSS-Header | Conf        | Data  | Pad |                               */
    /* CFX: GSS-Header | Kerb-Header | Data  |     | EC | E(Header) | Kerb-Trailer */
    /* GSS: -------GSS-HEADER--------+-DATA--+-PAD-+----------GSS-TRAILER----------*/

    /* validate lengths */
    if (stream->buffer.length < theader->buffer.length +
        tpadding->buffer.length +
        ttrailer->buffer.length)
    {
        code = (OM_uint32)KRB5_BAD_MSIZE;
        major_status = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
    }

    /* setup data */
    tdata->buffer.length = stream->buffer.length - ttrailer->buffer.length -
        tpadding->buffer.length - theader->buffer.length;

    assert(data != NULL);

    if (data->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
        code = kg_allocate_iov(tdata, tdata->buffer.length);
        if (code != 0)
            goto cleanup;
        memcpy(tdata->buffer.value,
               (unsigned char *)stream->buffer.value + theader->buffer.length, tdata->buffer.length);
    } else
        tdata->buffer.value = (unsigned char *)stream->buffer.value + theader->buffer.length;

    assert(i <= iov_count + 2);

    major_status = kg_unseal_iov_token(&code, ctx, conf_state, qop_state,
                                       tiov, i, toktype);
    if (major_status == GSS_S_COMPLETE)
        *data = *tdata;
    else
        kg_release_iov(tdata, 1);

cleanup:
    if (tiov != NULL)
        free(tiov);

    *minor_status = code;

    return major_status;
}
Example #5
0
static OM_uint32
kg_unseal_v1_iov(krb5_context context,
                 OM_uint32 *minor_status,
                 krb5_gss_ctx_id_rec *ctx,
                 gss_iov_buffer_desc *iov,
                 int iov_count,
                 size_t token_wrapper_len,
                 int *conf_state,
                 gss_qop_t *qop_state,
                 int toktype)
{
    OM_uint32 code;
    gss_iov_buffer_t header;
    gss_iov_buffer_t trailer;
    unsigned char *ptr;
    int sealalg;
    int signalg;
    krb5_checksum cksum;
    krb5_checksum md5cksum;
    size_t cksum_len = 0;
    size_t conflen = 0;
    int direction;
    krb5_ui_4 seqnum;
    OM_uint32 retval;
    size_t sumlen;
    krb5_keyusage sign_usage = KG_USAGE_SIGN;

    md5cksum.length = cksum.length = 0;
    md5cksum.contents = cksum.contents = NULL;

    header = kg_locate_header_iov(iov, iov_count, toktype);
    assert(header != NULL);

    trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
    if (trailer != NULL && trailer->buffer.length != 0) {
        *minor_status = (OM_uint32)KRB5_BAD_MSIZE;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (header->buffer.length < token_wrapper_len + 14) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    ptr = (unsigned char *)header->buffer.value + token_wrapper_len;

    signalg  = ptr[0];
    signalg |= ptr[1] << 8;

    sealalg  = ptr[2];
    sealalg |= ptr[3] << 8;

    if (ptr[4] != 0xFF || ptr[5] != 0xFF) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (toktype != KG_TOK_WRAP_MSG && sealalg != 0xFFFF) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if (toktype == KG_TOK_WRAP_MSG &&
        !(sealalg == 0xFFFF || sealalg == ctx->sealalg)) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
        (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
        (ctx->sealalg == SEAL_ALG_DES3KD &&
         signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
        (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
         signalg != SGN_ALG_HMAC_MD5)) {
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
    case SGN_ALG_HMAC_MD5:
        cksum_len = 8;
        if (toktype != KG_TOK_WRAP_MSG)
            sign_usage = 15;
        break;
    case SGN_ALG_3:
        cksum_len = 16;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        cksum_len = 20;
        break;
    default:
        *minor_status = 0;
        return GSS_S_DEFECTIVE_TOKEN;
    }

    /* get the token parameters */
    code = kg_get_seq_num(context, ctx->seq, ptr + 14, ptr + 6, &direction,
                          &seqnum);
    if (code != 0) {
        *minor_status = code;
        return GSS_S_BAD_SIG;
    }

    /* decode the message, if SEAL */
    if (toktype == KG_TOK_WRAP_MSG) {
        if (sealalg != 0xFFFF) {
            if (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) {
                unsigned char bigend_seqnum[4];
                krb5_keyblock *enc_key;
                size_t i;

                store_32_be(seqnum, bigend_seqnum);

                code = krb5_k_key_keyblock(context, ctx->enc, &enc_key);
                if (code != 0) {
                    retval = GSS_S_FAILURE;
                    goto cleanup;
                }

                assert(enc_key->length == 16);

                for (i = 0; i < enc_key->length; i++)
                    ((char *)enc_key->contents)[i] ^= 0xF0;

                code = kg_arcfour_docrypt_iov(context, enc_key, 0,
                                              &bigend_seqnum[0], 4,
                                              iov, iov_count);
                krb5_free_keyblock(context, enc_key);
            } else {
                code = kg_decrypt_iov(context, 0,
                                      ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0),
                                      0 /*EC*/, 0 /*RRC*/,
                                      ctx->enc, KG_USAGE_SEAL, NULL,
                                      iov, iov_count);
            }
            if (code != 0) {
                retval = GSS_S_FAILURE;
                goto cleanup;
            }
        }
        conflen = kg_confounder_size(context, ctx->enc->keyblock.enctype);
    }

    if (header->buffer.length != token_wrapper_len + 14 + cksum_len + conflen) {
        retval = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
    }

    /* compute the checksum of the message */

    /* initialize the checksum */

    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
    case SGN_ALG_DES_MAC:
    case SGN_ALG_3:
        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
        break;
    case SGN_ALG_HMAC_MD5:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
        break;
    default:
        abort();
    }

    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
    if (code != 0) {
        retval = GSS_S_FAILURE;
        goto cleanup;
    }
    md5cksum.length = sumlen;

    /* compute the checksum of the message */
    code = kg_make_checksum_iov_v1(context, md5cksum.checksum_type,
                                   cksum_len, ctx->seq, ctx->enc,
                                   sign_usage, iov, iov_count, toktype,
                                   &md5cksum);
    if (code != 0) {
        retval = GSS_S_FAILURE;
        goto cleanup;
    }

    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_3:
        code = kg_encrypt_inplace(context, ctx->seq, KG_USAGE_SEAL,
                                  (g_OID_equal(ctx->mech_used,
                                               gss_mech_krb5_old) ?
                                   ctx->seq->keyblock.contents : NULL),
                                  md5cksum.contents, 16);
        if (code != 0) {
            retval = GSS_S_FAILURE;
            goto cleanup;
        }

        cksum.length = cksum_len;
        cksum.contents = md5cksum.contents + 16 - cksum.length;

        code = k5_bcmp(cksum.contents, ptr + 14, cksum.length);
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
    case SGN_ALG_HMAC_MD5:
        code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
        break;
    default:
        code = 0;
        retval = GSS_S_DEFECTIVE_TOKEN;
        goto cleanup;
        break;
    }

    if (code != 0) {
        code = 0;
        retval = GSS_S_BAD_SIG;
        goto cleanup;
    }

    /*
     * For GSS_C_DCE_STYLE, the caller manages the padding, because the
     * pad length is in the RPC PDU. The value of the padding may be
     * uninitialized. For normal GSS, the last bytes of the decrypted
     * data contain the pad length. kg_fixup_padding_iov() will find
     * this and fixup the last data IOV appropriately.
     */
    if (toktype == KG_TOK_WRAP_MSG &&
        (ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
        retval = kg_fixup_padding_iov(&code, iov, iov_count);
        if (retval != GSS_S_COMPLETE)
            goto cleanup;
    }

    if (conf_state != NULL)
        *conf_state = (sealalg != 0xFFFF);

    if (qop_state != NULL)
        *qop_state = GSS_C_QOP_DEFAULT;

    if ((ctx->initiate && direction != 0xff) ||
        (!ctx->initiate && direction != 0)) {
        *minor_status = (OM_uint32)G_BAD_DIRECTION;
        retval = GSS_S_BAD_SIG;
    }

    code = 0;
    retval = g_order_check(&ctx->seqstate, (gssint_uint64)seqnum);

cleanup:
    krb5_free_checksum_contents(context, &md5cksum);

    *minor_status = code;

    return retval;
}
Example #6
0
/* AEAD */
static krb5_error_code
kg_translate_iov_v1(krb5_context context, krb5_enctype enctype,
                    gss_iov_buffer_desc *iov, int iov_count,
                    krb5_crypto_iov **pkiov, size_t *pkiov_count)
{
    gss_iov_buffer_desc *header;
    gss_iov_buffer_desc *trailer;
    int i = 0, j;
    size_t kiov_count;
    krb5_crypto_iov *kiov;
    size_t conf_len;

    *pkiov = NULL;
    *pkiov_count = 0;

    conf_len = kg_confounder_size(context, enctype);

    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
    assert(header != NULL);

    if (header->buffer.length < conf_len)
        return KRB5_BAD_MSIZE;

    trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
    assert(trailer == NULL || trailer->buffer.length == 0);

    kiov_count = 3 + iov_count;
    kiov = (krb5_crypto_iov *)malloc(kiov_count * sizeof(krb5_crypto_iov));
    if (kiov == NULL)
        return ENOMEM;

    /* For pre-CFX (raw enctypes) there is no krb5 header */
    kiov[i].flags = KRB5_CRYPTO_TYPE_HEADER;
    kiov[i].data.length = 0;
    kiov[i].data.data = NULL;
    i++;

    /* For pre-CFX, the confounder is at the end of the GSS header */
    kiov[i].flags = KRB5_CRYPTO_TYPE_DATA;
    kiov[i].data.length = conf_len;
    kiov[i].data.data = (char *)header->buffer.value + header->buffer.length - conf_len;
    i++;

    for (j = 0; j < iov_count; j++) {
        kiov[i].flags = kg_translate_flag_iov(iov[j].type);
        if (kiov[i].flags == KRB5_CRYPTO_TYPE_EMPTY)
            continue;

        kiov[i].data.length = iov[j].buffer.length;
        kiov[i].data.data = (char *)iov[j].buffer.value;
        i++;
    }

    kiov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
    kiov[i].data.length = 0;
    kiov[i].data.data = NULL;
    i++;

    *pkiov = kiov;
    *pkiov_count = i;

    return 0;
}
Example #7
0
static krb5_error_code
make_seal_token_v1 (krb5_context context,
                    krb5_keyblock *enc,
                    krb5_keyblock *seq,
                    gssint_uint64 *seqnum,
                    int direction,
                    gss_buffer_t text,
                    gss_buffer_t token,
                    int signalg,
                    size_t cksum_size,
                    int sealalg,
                    int do_encrypt,
                    int toktype,
                    int bigend,
                    gss_OID oid)
{
    krb5_error_code code;
    size_t sumlen;
    char *data_ptr;
    krb5_data plaind;
    krb5_checksum md5cksum;
    krb5_checksum cksum;
    /* msglen contains the message length
     * we are signing/encrypting.  tmsglen
     * contains the length of the message
     * we plan to write out to the token.
     * tlen is the length of the token
     * including header. */
    unsigned int conflen=0, tmsglen, tlen, msglen;
    unsigned char *t, *ptr;
    unsigned char *plain;
    unsigned char pad;
    krb5_keyusage sign_usage = KG_USAGE_SIGN;


    assert((!do_encrypt) || (toktype == KG_TOK_SEAL_MSG));
    /* create the token buffer */
    /* Do we need confounder? */
    if (do_encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG)))
        conflen = kg_confounder_size(context, enc);
    else conflen = 0;

    if (toktype == KG_TOK_SEAL_MSG) {
        switch (sealalg) {
        case SEAL_ALG_MICROSOFT_RC4:
            msglen = conflen + text->length+1;
            pad = 1;
            break;
        default:
            /* XXX knows that des block size is 8 */
            msglen = (conflen+text->length+8)&(~7);
            pad = 8-(text->length%8);
        }
        tmsglen = msglen;
    } else {
        tmsglen = 0;
        msglen = text->length;
        pad = 0;
    }
    tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen);

    if ((t = (unsigned char *) xmalloc(tlen)) == NULL)
        return(ENOMEM);

    /*** fill in the token */

    ptr = t;
    g_make_token_header(oid, 14+cksum_size+tmsglen, &ptr, toktype);

    /* 0..1 SIGN_ALG */
    store_16_le(signalg, &ptr[0]);

    /* 2..3 SEAL_ALG or Filler */
    if ((toktype == KG_TOK_SEAL_MSG) && do_encrypt) {
        store_16_le(sealalg, &ptr[2]);
    } else {
        /* No seal */
        ptr[2] = 0xff;
        ptr[3] = 0xff;
    }

    /* 4..5 Filler */
    ptr[4] = 0xff;
    ptr[5] = 0xff;

    /* pad the plaintext, encrypt if needed, and stick it in the token */

    /* initialize the the cksum */
    switch (signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case SGN_ALG_MD2_5:
        md5cksum.checksum_type = CKSUMTYPE_RSA_MD5;
        break;
    case SGN_ALG_HMAC_SHA1_DES3_KD:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
        break;
    case SGN_ALG_HMAC_MD5:
        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
        if (toktype != KG_TOK_SEAL_MSG)
            sign_usage = 15;
        break;
    default:
    case SGN_ALG_DES_MAC:
        abort ();
    }

    code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
    if (code) {
        xfree(t);
        return(code);
    }
    md5cksum.length = sumlen;


    if ((plain = (unsigned char *) xmalloc(msglen ? msglen : 1)) == NULL) {
        xfree(t);
        return(ENOMEM);
    }

    if (conflen) {
        if ((code = kg_make_confounder(context, enc, plain))) {
            xfree(plain);
            xfree(t);
            return(code);
        }
    }

    memcpy(plain+conflen, text->value, text->length);
    if (pad) memset(plain+conflen+text->length, pad, pad);

    /* compute the checksum */

    /* 8 = head of token body as specified by mech spec */
    if (! (data_ptr =
           (char *) xmalloc(8 + (bigend ? text->length : msglen)))) {
        xfree(plain);
        xfree(t);
        return(ENOMEM);
    }
    (void) memcpy(data_ptr, ptr-2, 8);
    if (bigend)
        (void) memcpy(data_ptr+8, text->value, text->length);
    else
        (void) memcpy(data_ptr+8, plain, msglen);
    plaind.length = 8 + (bigend ? text->length : msglen);
    plaind.data = data_ptr;
    code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq,
                                sign_usage, &plaind, &md5cksum);
    xfree(data_ptr);

    if (code) {
        xfree(plain);
        xfree(t);
        return(code);
    }
    switch(signalg) {
    case SGN_ALG_DES_MAC_MD5:
    case 3:

        if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL,
                               (g_OID_equal(oid, gss_mech_krb5_old) ?
                                seq->contents : NULL),
                               md5cksum.contents, md5cksum.contents, 16))) {
            krb5_free_checksum_contents(context, &md5cksum);
            xfree (plain);
            xfree(t);
            return code;
        }

        cksum.length = cksum_size;
        cksum.contents = md5cksum.contents + 16 - cksum.length;

        memcpy(ptr+14, cksum.contents, cksum.length);
        break;

    case SGN_ALG_HMAC_SHA1_DES3_KD:
        /*
         * Using key derivation, the call to krb5_c_make_checksum
         * already dealt with encrypting.
         */
        if (md5cksum.length != cksum_size)
            abort ();
        memcpy (ptr+14, md5cksum.contents, md5cksum.length);
        break;
    case SGN_ALG_HMAC_MD5:
        memcpy (ptr+14, md5cksum.contents, cksum_size);
        break;
    }

    krb5_free_checksum_contents(context, &md5cksum);

    /* create the seq_num */

    if ((code = kg_make_seq_num(context, seq, direction?0:0xff,
                                (krb5_ui_4)*seqnum, ptr+14, ptr+6))) {
        xfree (plain);
        xfree(t);
        return(code);
    }

    if (do_encrypt) {
        switch(sealalg) {
        case SEAL_ALG_MICROSOFT_RC4:
        {
            unsigned char bigend_seqnum[4];
            krb5_keyblock *enc_key;
            int i;
            store_32_be(*seqnum, bigend_seqnum);
            code = krb5_copy_keyblock (context, enc, &enc_key);
            if (code)
            {
                xfree(plain);
                xfree(t);
                return(code);
            }
            assert (enc_key->length == 16);
            for (i = 0; i <= 15; i++)
                ((char *) enc_key->contents)[i] ^=0xf0;
            code = kg_arcfour_docrypt (enc_key, 0,
                                       bigend_seqnum, 4,
                                       plain, tmsglen,
                                       ptr+14+cksum_size);
            krb5_free_keyblock (context, enc_key);
            if (code)
            {
                xfree(plain);
                xfree(t);
                return(code);
            }
        }
        break;
        default:
            if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL,
                                   (krb5_pointer) plain,
                                   (krb5_pointer) (ptr+cksum_size+14),
                                   tmsglen))) {
                xfree(plain);
                xfree(t);
                return(code);
            }
        }
    }else {
        if (tmsglen)
            memcpy(ptr+14+cksum_size, plain, tmsglen);
    }
    xfree(plain);


    /* that's it.  return the token */

    (*seqnum)++;
    *seqnum &= 0xffffffffL;

    token->length = tlen;
    token->value = (void *) t;

    return(0);
}