Exemple #1
0
/* Derive encryption and integrity keys for CMAC-using enctypes. */
static krb5_error_code
derive_keys(const struct krb5_enc_provider *enc, krb5_key key,
            krb5_keyusage usage, krb5_key *ke_out, krb5_key *ki_out)
{
    krb5_error_code ret;
    unsigned char buf[K5CLENGTH];
    krb5_data constant = make_data(buf, K5CLENGTH);
    krb5_key ke, ki;

    *ke_out = *ki_out = NULL;

    /* Derive the encryption key. */
    store_32_be(usage, buf);
    buf[4] = 0xAA;
    ret = krb5int_derive_key(enc, key, &ke, &constant, DERIVE_SP800_108_CMAC);
    if (ret != 0)
        return ret;

    /* Derive the integrity key. */
    buf[4] = 0x55;
    ret = krb5int_derive_key(enc, key, &ki, &constant, DERIVE_SP800_108_CMAC);
    if (ret != 0) {
        krb5_k_free_key(NULL, ke);
        return ret;
    }

    *ke_out = ke;
    *ki_out = ki;
    return 0;
}
Exemple #2
0
static krb5_error_code
nonce_generate(krb5_context ctx, unsigned int length, krb5_data *nonce_out)
{
    krb5_data nonce;
    krb5_error_code retval;
    krb5_timestamp now;

    retval = krb5_timeofday(ctx, &now);
    if (retval != 0)
        return retval;

    retval = alloc_data(&nonce, sizeof(now) + length);
    if (retval != 0)
        return retval;

    retval = krb5_c_random_make_octets(ctx, &nonce);
    if (retval != 0) {
        free(nonce.data);
        return retval;
    }

    store_32_be(now, nonce.data);
    *nonce_out = nonce;
    return 0;
}
Exemple #3
0
krb5_error_code KRB5_CALLCONV
krb5_c_random_make_octets(krb5_context context, krb5_data *outdata)
{
#ifdef _WIN32
    DWORD pid = GetCurrentProcessId();
#else
    pid_t pid = getpid();
#endif
    unsigned char pidbuf[4];

    k5_mutex_lock(&fortuna_lock);

    if (!have_entropy) {
        k5_mutex_unlock(&fortuna_lock);
        return KRB5_CRYPTO_INTERNAL;
    }

    if (pid != last_pid) {
        /* We forked; make sure child's PRNG stream differs from parent's. */
        store_32_be(pid, pidbuf);
        generator_reseed(&main_state, pidbuf, 4);
        last_pid = pid;
    }

    accumulator_output(&main_state, (unsigned char *)outdata->data,
                       outdata->length);
    k5_mutex_unlock(&fortuna_lock);
    return 0;
}
Exemple #4
0
/* Set up the actual message we will send across the underlying transport to
 * communicate the payload message, using one or both of state->out.sgbuf. */
static krb5_error_code
set_transport_message(struct conn_state *state, const krb5_data *realm,
                      const krb5_data *message)
{
    struct outgoing_message *out = &state->out;
    char *req = NULL;
    size_t reqlen;
    krb5_error_code ret;

    if (message == NULL || message->length == 0)
        return 0;

    if (state->addr.transport == TCP) {
        store_32_be(message->length, out->msg_len_buf);
        SG_SET(&out->sgbuf[0], out->msg_len_buf, 4);
        SG_SET(&out->sgbuf[1], message->data, message->length);
        out->sg_count = 2;
        return 0;
    } else if (state->addr.transport == HTTPS) {
        ret = make_proxy_request(state, realm, message, &req, &reqlen);
        if (ret != 0)
            return ret;
        SG_SET(&state->out.sgbuf[0], req, reqlen);
        SG_SET(&state->out.sgbuf[1], 0, 0);
        state->out.sg_count = 1;
        free(state->http.https_request);
        state->http.https_request = req;
        return 0;
    } else {
        SG_SET(&out->sgbuf[0], message->data, message->length);
        SG_SET(&out->sgbuf[1], NULL, 0);
        out->sg_count = 1;
        return 0;
    }
}
Exemple #5
0
/*
 * krb5_ser_pack_int32()        - Pack a 4-byte integer if space is available.
 *                                Update buffer pointer and remaining space.
 */
krb5_error_code KRB5_CALLCONV
krb5_ser_pack_int32(krb5_int32 iarg, krb5_octet **bufp, size_t *remainp)
{
    if (*remainp >= sizeof(krb5_int32)) {
        store_32_be(iarg, *bufp);
        *bufp += sizeof(krb5_int32);
        *remainp -= sizeof(krb5_int32);
        return(0);
    }
    else
        return(ENOMEM);
}
Exemple #6
0
static krb5_error_code
make_proxy_request(struct conn_state *state, const krb5_data *realm,
                   const krb5_data *message, char **req_out, size_t *len_out)
{
    krb5_kkdcp_message pm;
    krb5_data *encoded_pm = NULL;
    struct k5buf buf;
    const char *uri_path;
    krb5_error_code ret;

    *req_out = NULL;
    *len_out = 0;

    /*
     * Stuff the message length in at the front of the kerb_message field
     * before encoding.  The proxied messages are actually the payload we'd
     * be sending and receiving if we were using plain TCP.
     */
    memset(&pm, 0, sizeof(pm));
    ret = alloc_data(&pm.kerb_message, message->length + 4);
    if (ret != 0)
        goto cleanup;
    store_32_be(message->length, pm.kerb_message.data);
    memcpy(pm.kerb_message.data + 4, message->data, message->length);
    pm.target_domain = *realm;
    ret = encode_krb5_kkdcp_message(&pm, &encoded_pm);
    if (ret != 0)
        goto cleanup;

    /* Build the request to transmit: the headers + the proxy message. */
    k5_buf_init_dynamic(&buf);
    uri_path = (state->http.uri_path != NULL) ? state->http.uri_path : "";
    k5_buf_add_fmt(&buf, "POST /%s HTTP/1.0\r\n", uri_path);
    k5_buf_add(&buf, "Cache-Control: no-cache\r\n");
    k5_buf_add(&buf, "Pragma: no-cache\r\n");
    k5_buf_add(&buf, "User-Agent: kerberos/1.0\r\n");
    k5_buf_add(&buf, "Content-type: application/kerberos\r\n");
    k5_buf_add_fmt(&buf, "Content-Length: %d\r\n\r\n", encoded_pm->length);
    k5_buf_add_len(&buf, encoded_pm->data, encoded_pm->length);
    if (k5_buf_status(&buf) != 0) {
        ret = ENOMEM;
        goto cleanup;
    }

    *req_out = buf.data;
    *len_out = buf.len;

cleanup:
    krb5_free_data_contents(NULL, &pm.kerb_message);
    krb5_free_data(NULL, encoded_pm);
    return ret;
}
Exemple #7
0
/* Store a 32-bit integer into the cache file according to the file format. */
static krb5_error_code
store32(krb5_context context, krb5_ccache id, uint32_t i)
{
    unsigned char buf[4];

    k5_cc_mutex_assert_locked(context, &((fcc_data *)id->data)->lock);

    if (version(id) < 3)
        store_32_n(i, buf);
    else
        store_32_be(i, buf);
    return write_bytes(context, id, buf, 4);
}
Exemple #8
0
int main ()
{
    /* Test some low-level assumptions the Kerberos code depends
       on.  */

    union {
        uint64_t n64;
        uint32_t n32;
        uint16_t n16;
        unsigned char b[9];
    } u;
    static unsigned char buf[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };

    assert(load_64_be(buf+1) == 0x0102030405060708LL);
    assert(load_64_le(buf+1) == 0x0807060504030201LL);
    assert(load_32_le(buf+2) == 0x05040302);
    assert(load_32_be(buf+2) == 0x02030405);
    assert(load_16_be(buf+3) == 0x0304);
    assert(load_16_le(buf+3) == 0x0403);
    u.b[0] = 0;
    assert((store_64_be(0x0102030405060708LL, u.b+1), !memcmp(buf, u.b, 9)));
    u.b[1] = 9;
    assert((store_64_le(0x0807060504030201LL, u.b+1), !memcmp(buf, u.b, 9)));
    u.b[2] = 10;
    assert((store_32_be(0x02030405, u.b+2), !memcmp(buf, u.b, 9)));
    u.b[3] = 11;
    assert((store_32_le(0x05040302, u.b+2), !memcmp(buf, u.b, 9)));
    u.b[4] = 12;
    assert((store_16_be(0x0304, u.b+3), !memcmp(buf, u.b, 9)));
    u.b[4] = 13;
    assert((store_16_le(0x0403, u.b+3), !memcmp(buf, u.b, 9)));
    /* Verify that load_*_n properly does native format.  Assume
       the unaligned thing is okay.  */
    u.n64 = 0x090a0b0c0d0e0f00LL;
    assert(load_64_n((unsigned char *) &u.n64) == 0x090a0b0c0d0e0f00LL);
    u.n32 = 0x06070809;
    assert(load_32_n((unsigned char *) &u.n32) == 0x06070809);
    u.n16 = 0x0a0b;
    assert(load_16_n((unsigned char *) &u.n16) == 0x0a0b);

    return 0;
}
Exemple #9
0
static krb5_error_code
k5_sha1_hash(unsigned int icount, const krb5_data *input,
	     krb5_data *output)
{
    SHS_INFO ctx;
    unsigned int i;

    if (output->length != SHS_DIGESTSIZE)
	return(KRB5_CRYPTO_INTERNAL);

    shsInit(&ctx);
    for (i=0; i<icount; i++)
	shsUpdate(&ctx, (unsigned char *) input[i].data, input[i].length);
    shsFinal(&ctx);

    for (i=0; i<(sizeof(ctx.digest)/sizeof(ctx.digest[0])); i++) {
	store_32_be(ctx.digest[i], &output->data[i*4]);
    }

    return(0);
}
static void
set_conn_state_msg_length (struct conn_state *state, const krb5_data *message)
{
    if (!message || message->length == 0)
        return;

    if (!state->is_udp) {

        store_32_be(message->length, state->x.out.msg_len_buf);
        SG_SET(&state->x.out.sgbuf[0], state->x.out.msg_len_buf, 4);
        SG_SET(&state->x.out.sgbuf[1], message->data, message->length);
        state->x.out.sg_count = 2;

    } else {

        SG_SET(&state->x.out.sgbuf[0], message->data, message->length);
        SG_SET(&state->x.out.sgbuf[1], 0, 0);
        state->x.out.sg_count = 1;

    }
}
Exemple #11
0
OM_uint32 KRB5_CALLCONV
krb5_gss_pseudo_random(OM_uint32 *minor_status,
                       gss_ctx_id_t context,
                       int prf_key,
                       const gss_buffer_t prf_in,
                       ssize_t desired_output_len,
                       gss_buffer_t prf_out)
{
    krb5_error_code code;
    krb5_key key = NULL;
    krb5_gss_ctx_id_t ctx;
    int i;
    OM_uint32 minor;
    size_t prflen;
    krb5_data t, ns;
    unsigned char *p;

    prf_out->length = 0;
    prf_out->value = NULL;

    t.length = 0;
    t.data = NULL;

    ns.length = 0;
    ns.data = NULL;

    ctx = (krb5_gss_ctx_id_t)context;

    switch (prf_key) {
    case GSS_C_PRF_KEY_FULL:
        if (ctx->have_acceptor_subkey) {
            key = ctx->acceptor_subkey;
            break;
        }
        /* fallthrough */
    case GSS_C_PRF_KEY_PARTIAL:
        key = ctx->subkey;
        break;
    default:
        code = EINVAL;
        goto cleanup;
    }

    if (key == NULL) {
        code = EINVAL;
        goto cleanup;
    }

    prf_out->value = k5alloc(desired_output_len, &code);
    if (prf_out->value == NULL) {
        code = KG_INPUT_TOO_LONG;
        goto cleanup;
    }
    prf_out->length = desired_output_len;

    code = krb5_c_prf_length(ctx->k5_context,
                             krb5_k_key_enctype(ctx->k5_context, key),
                             &prflen);
    if (code != 0)
        goto cleanup;

    ns.length = 4 + prf_in->length;
    ns.data = k5alloc(ns.length, &code);
    if (ns.data == NULL) {
        code = KG_INPUT_TOO_LONG;
        goto cleanup;
    }

    t.length = prflen;
    t.data = k5alloc(t.length, &code);
    if (t.data == NULL)
        goto cleanup;

    memcpy(ns.data + 4, prf_in->value, prf_in->length);
    i = 0;
    p = (unsigned char *)prf_out->value;
    while (desired_output_len > 0) {
        store_32_be(i, ns.data);

        code = krb5_k_prf(ctx->k5_context, key, &ns, &t);
        if (code != 0)
            goto cleanup;

        memcpy(p, t.data, MIN(t.length, desired_output_len));

        p += t.length;
        desired_output_len -= t.length;
        i++;
    }

cleanup:
    if (code != 0)
        gss_release_buffer(&minor, prf_out);
    krb5_free_data_contents(ctx->k5_context, &ns);
    krb5_free_data_contents(ctx->k5_context, &t);

    *minor_status = (OM_uint32)code;
    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
}
Exemple #12
0
static void pack_int32(prof_int32 oval, unsigned char **bufpp, size_t *remainp)
{
    store_32_be(oval, *bufpp);
    *bufpp += sizeof(prof_int32);
    *remainp -= sizeof(prof_int32);
}
Exemple #13
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);
}
Exemple #14
0
/*
 * NIST SP800-108 KDF in feedback mode (section 5.2).
 * Parameters:
 *   - CMAC (with enc as the enc provider) is the PRF.
 *   - A block counter of four bytes is used.
 *   - Label is the key derivation constant.
 *   - Context is empty.
 *   - Four bytes are used to encode the output length in the PRF input.
 */
static krb5_error_code
derive_random_sp800_108_cmac(const struct krb5_enc_provider *enc,
                             krb5_key inkey, krb5_data *outrnd,
                             const krb5_data *in_constant)
{
    size_t blocksize, keybytes, n;
    krb5_crypto_iov iov[6];
    krb5_error_code ret;
    krb5_data prf;
    unsigned int i;
    unsigned char ibuf[4], Lbuf[4];

    blocksize = enc->block_size;
    keybytes = enc->keybytes;

    if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
        return KRB5_CRYPTO_INTERNAL;

    /* Allocate encryption data buffer. */
    ret = alloc_data(&prf, blocksize);
    if (ret)
        return ret;

    /* K(i-1): the previous block of PRF output, initially all-zeros. */
    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[0].data = prf;
    /* [i]2: four-byte big-endian binary string giving the block counter */
    iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[1].data = make_data(ibuf, sizeof(ibuf));
    /* Label: the fixed derived-key input */
    iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[2].data = *in_constant;
    /* 0x00: separator byte */
    iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[3].data = make_data("", 1);
    /* Context: (unused) */
    iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[4].data = empty_data();
    /* [L]2: four-byte big-endian binary string giving the output length */
    iov[5].flags = KRB5_CRYPTO_TYPE_DATA;
    iov[5].data = make_data(Lbuf, sizeof(Lbuf));
    store_32_be(outrnd->length * 8, Lbuf);

    for (i = 1, n = 0; n < keybytes; i++) {
        /* Update the block counter. */
        store_32_be(i, ibuf);

        /* Compute a CMAC checksum, storing the result into K(i-1). */
        ret = krb5int_cmac_checksum(enc, inkey, iov, 6, &prf);
        if (ret)
            goto cleanup;

        /* Copy the result into the appropriate part of the output buffer. */
        if (keybytes - n <= blocksize) {
            memcpy(outrnd->data + n, prf.data, keybytes - n);
            break;
        }
        memcpy(outrnd->data + n, prf.data, blocksize);
        n += blocksize;
    }

cleanup:
    zapfree(prf.data, blocksize);
    return ret;
}
Exemple #15
0
static krb5_error_code
F(char *output, char *u_tmp1, char *u_tmp2,
  const struct krb5_hash_provider *hash, size_t hlen, krb5_keyblock *pass,
  const krb5_data *salt, unsigned long count, int i)
{
    unsigned char ibytes[4];
    unsigned int j, k;
    krb5_data sdata;
    krb5_data out;
    krb5_error_code err;

#if 0
    printf("F(i=%d, count=%lu, pass=%d:%s)\n", i, count,
           pass->length, pass->data);
#endif

    /* Compute U_1.  */
    store_32_be(i, ibytes);

    memcpy(u_tmp2, salt->data, salt->length);
    memcpy(u_tmp2 + salt->length, ibytes, 4);
    sdata = make_data(u_tmp2, salt->length + 4);

#if 0
    printd("initial salt", &sdata);
#endif

    out = make_data(u_tmp1, hlen);

#if 0
    printf("F: computing hmac #1 (U_1) with %s\n", pdata.contents);
#endif
    err = hmac(hash, pass, &sdata, &out);
    if (err)
        return err;
#if 0
    printd("F: prf return value", &out);
#endif
    memcpy(output, u_tmp1, hlen);

    /* Compute U_2, .. U_c.  */
    sdata.length = hlen;
    for (j = 2; j <= count; j++) {
#if 0
        printf("F: computing hmac #%d (U_%d)\n", j, j);
#endif
        memcpy(u_tmp2, u_tmp1, hlen);
        err = hmac(hash, pass, &sdata, &out);
        if (err)
            return err;
#if 0
        printd("F: prf return value", &out);
#endif
        /* And xor them together.  */
        for (k = 0; k < hlen; k++)
            output[k] ^= u_tmp1[k];
#if 0
        printf("F: xor result:\n");
        for (k = 0; k < hlen; k++)
            printf(" %02x", 0xff & output[k]);
        printf("\n");
#endif
    }
    return 0;
}
Exemple #16
0
OM_uint32 krb5_gss_export_name(OM_uint32  *minor_status,
                               const gss_name_t input_name,
                               gss_buffer_t exported_name)
{
    krb5_context context;
    krb5_error_code code;
    size_t length;
    char *str;
    unsigned char *cp;

    if (minor_status)
        *minor_status = 0;

    code = krb5_gss_init_context(&context);
    if (code) {
        if (minor_status)
            *minor_status = code;
        return GSS_S_FAILURE;
    }

    exported_name->length = 0;
    exported_name->value = NULL;

    if (! kg_validate_name(input_name)) {
        if (minor_status)
            *minor_status = (OM_uint32) G_VALIDATE_FAILED;
        krb5_free_context(context);
        return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
    }

    if ((code = krb5_unparse_name(context, (krb5_principal) input_name,
                                  &str))) {
        if (minor_status)
            *minor_status = code;
        save_error_info((OM_uint32)code, context);
        krb5_free_context(context);
        return(GSS_S_FAILURE);
    }

    krb5_free_context(context);
    length = strlen(str);
    exported_name->length = 10 + length + gss_mech_krb5->length;
    exported_name->value = malloc(exported_name->length);
    if (!exported_name->value) {
        free(str);
        if (minor_status)
            *minor_status = ENOMEM;
        return(GSS_S_FAILURE);
    }
    cp = exported_name->value;

    /* Note: we assume the OID will be less than 128 bytes... */
    *cp++ = 0x04; *cp++ = 0x01;
    store_16_be(gss_mech_krb5->length+2, cp);
    cp += 2;
    *cp++ = 0x06;
    *cp++ = (gss_mech_krb5->length) & 0xFF;
    memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
    cp += gss_mech_krb5->length;
    store_32_be(length, cp);
    cp += 4;
    memcpy(cp, str, length);

    free(str);

    return(GSS_S_COMPLETE);
}
Exemple #17
0
OM_uint32 KRB5_CALLCONV
krb5_gss_export_name_composite(OM_uint32 *minor_status,
                               gss_name_t name,
                               gss_buffer_t exp_composite_name)
{
    krb5_context context;
    krb5_error_code code;
    krb5_gss_name_t kname;
    krb5_data *attrs = NULL;
    char *princstr = NULL;
    unsigned char *cp;
    size_t princlen;

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

    code = krb5_gss_init_context(&context);
    if (code != 0) {
        *minor_status = code;
        return GSS_S_FAILURE;
    }

    kname = (krb5_gss_name_t)name;

    code = k5_mutex_lock(&kname->lock);
    if (code != 0) {
        *minor_status = code;
        return GSS_S_FAILURE;
    }

    code = krb5_unparse_name(context, kname->princ, &princstr);
    if (code != 0)
        goto cleanup;

    princlen = strlen(princstr);

    if (kname->ad_context != NULL) {
        code = krb5_authdata_export_attributes(context,
                                               kname->ad_context,
                                               AD_USAGE_MASK,
                                               &attrs);
        if (code != 0)
            goto cleanup;
    }

    /* 04 02 OID Name AuthData */

    exp_composite_name->length = 10 + gss_mech_krb5->length + princlen;
    if (attrs != NULL)
        exp_composite_name->length += 4 + attrs->length;
    exp_composite_name->value = malloc(exp_composite_name->length);
    if (exp_composite_name->value == NULL) {
        code = ENOMEM;
        goto cleanup;
    }

    cp = exp_composite_name->value;

    /* Note: we assume the OID will be less than 128 bytes... */
    *cp++ = 0x04;
    if (attrs != NULL)
        *cp++ = 0x02;
    else
        *cp++ = 0x01;

    store_16_be(gss_mech_krb5->length + 2, cp);
    cp += 2;
    *cp++ = 0x06;
    *cp++ = (gss_mech_krb5->length) & 0xFF;
    memcpy(cp, gss_mech_krb5->elements, gss_mech_krb5->length);
    cp += gss_mech_krb5->length;

    store_32_be(princlen, cp);
    cp += 4;
    memcpy(cp, princstr, princlen);
    cp += princlen;

    if (attrs != NULL) {
        store_32_be(attrs->length, cp);
        cp += 4;
        memcpy(cp, attrs->data, attrs->length);
        cp += attrs->length;
    }

cleanup:
    krb5_free_unparsed_name(context, princstr);
    krb5_free_data(context, attrs);
    k5_mutex_unlock(&kname->lock);
    krb5_free_context(context);

    return kg_map_name_error(minor_status, code);
}
Exemple #18
0
krb5_error_code
krb5_dk_make_checksum(const struct krb5_hash_provider *hash,
		      const krb5_keyblock *key, krb5_keyusage usage,
		      const krb5_data *input, krb5_data *output)
{
    int i;
    const struct krb5_enc_provider *enc;
    size_t blocksize, keybytes, keylength;
    krb5_error_code ret;
    unsigned char constantdata[K5CLENGTH];
    krb5_data datain;
    unsigned char *kcdata;
    krb5_keyblock kc;

    for (i=0; i<krb5_enctypes_length; i++) {
	if (krb5_enctypes_list[i].etype == key->enctype)
	    break;
    }

    if (i == krb5_enctypes_length)
	return(KRB5_BAD_ENCTYPE);

    enc = krb5_enctypes_list[i].enc;

    /* allocate and set to-be-derived keys */

    blocksize = enc->block_size;
    keybytes = enc->keybytes;
    keylength = enc->keylength;

    /* key->length will be tested in enc->encrypt
       output->length will be tested in krb5_hmac */

    if ((kcdata = (unsigned char *) malloc(keylength)) == NULL)
	return(ENOMEM);

    kc.contents = kcdata;
    kc.length = keylength;

    /* derive the key */
 
    datain.data = (char *) constantdata;
    datain.length = K5CLENGTH;

    store_32_be(usage, constantdata);

    datain.data[4] = (char) 0x99;

    if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0)
	goto cleanup;

    /* hash the data */

    datain = *input;

    if ((ret = krb5_hmac(hash, &kc, 1, &datain, output)) != 0)
	memset(output->data, 0, output->length);

    /* ret is set correctly by the prior call */

cleanup:
    memset(kcdata, 0, keylength);

    free(kcdata);

    return(ret);
}
Exemple #19
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;
}
Exemple #20
0
/* Construct a cookie pa-data item using the cookie values from state, or a
 * trivial "MIT" cookie if no values are set. */
krb5_error_code
kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
                     krb5_db_entry *local_tgt,
                     krb5_const_principal client_princ,
                     krb5_pa_data **cookie_out)
{
    krb5_error_code ret;
    krb5_secure_cookie cookie;
    krb5_pa_data **contents = state->out_cookie_padata, *pa;
    krb5_keyblock *key = NULL;
    krb5_timestamp now;
    krb5_enc_data enc;
    krb5_data *der_cookie = NULL;
    krb5_kvno kvno;
    size_t ctlen;

    *cookie_out = NULL;
    memset(&enc, 0, sizeof(enc));

    /* Make a trivial cookie if there are no contents to marshal or we don't
     * have a TGT entry to encrypt them. */
    if (contents == NULL || *contents == NULL || local_tgt == NULL)
        return make_padata(KRB5_PADATA_FX_COOKIE, "MIT", 3, cookie_out);

    ret = get_cookie_key(context, local_tgt, 0, client_princ, &key, &kvno);
    if (ret)
        goto cleanup;

    /* Encode the cookie. */
    ret = krb5_timeofday(context, &now);
    if (ret)
        goto cleanup;
    cookie.time = now;
    cookie.data = contents;
    ret = encode_krb5_secure_cookie(&cookie, &der_cookie);
    if (ret)
        goto cleanup;

    /* Encrypt the cookie in key. */
    ret = krb5_c_encrypt_length(context, key->enctype, der_cookie->length,
                                &ctlen);
    if (ret)
        goto cleanup;
    ret = alloc_data(&enc.ciphertext, ctlen);
    if (ret)
        goto cleanup;
    ret = krb5_c_encrypt(context, key, KRB5_KEYUSAGE_PA_FX_COOKIE, NULL,
                         der_cookie, &enc);
    if (ret)
        goto cleanup;

    /* Construct the cookie pa-data entry. */
    ret = alloc_padata(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa);
    memcpy(pa->contents, "MIT1", 4);
    store_32_be(kvno, pa->contents + 4);
    memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length);
    *cookie_out = pa;

cleanup:
    krb5_free_keyblock(context, key);
    if (der_cookie != NULL) {
        zapfree(der_cookie->data, der_cookie->length);
        free(der_cookie);
    }
    krb5_free_data_contents(context, &enc.ciphertext);
    return ret;
}
Exemple #21
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;
}