Esempio n. 1
0
/*
 * This function overloads the keyblock field. It is only useful prior to
 * a krb5_rd_req_decode() call for user to user authentication where the
 * server has the key and needs to use it to decrypt the incoming request.
 * Once decrypted this key is no longer necessary and is then overwritten
 * with the session key sent by the client.
 */
krb5_error_code KRB5_CALLCONV
krb5_auth_con_setuseruserkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock *keyblock)
{
    if (auth_context->key)
        krb5_k_free_key(context, auth_context->key);
    return(krb5_k_create_key(context, keyblock, &(auth_context->key)));
}
Esempio n. 2
0
/* Create a key from key data in a lucid context. */
static krb5_error_code
lkey_to_key(const gss_krb5_lucid_key_t *lkey, krb5_key *key_out)
{
    krb5_keyblock kb;

    kb.enctype = lkey->type;
    kb.length = lkey->length;
    kb.contents = lkey->data;
    return krb5_k_create_key(NULL, &kb, key_out);
}
Esempio n. 3
0
static krb5_error_code
kg_copy_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey)
{
    krb5_error_code code;

    krb5_k_free_key(context, ctx->enc);
    ctx->enc = NULL;
    code = krb5_k_create_key(context, &subkey->keyblock, &ctx->enc);
    if (code != 0)
        return code;

    krb5_k_free_key(context, ctx->seq);
    ctx->seq = NULL;
    code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
    if (code != 0)
        return code;

    return 0;
}
Esempio n. 4
0
krb5_error_code KRB5_CALLCONV
krb5_auth_con_setrecvsubkey(krb5_context ctx, krb5_auth_context ac, krb5_keyblock *keyblock)
{
    if (ac->recv_subkey != NULL)
        krb5_k_free_key(ctx, ac->recv_subkey);
    ac->recv_subkey = NULL;
    if (keyblock != NULL)
        return krb5_k_create_key(ctx, keyblock, &ac->recv_subkey);
    else
        return 0;
}
Esempio n. 5
0
static void enc()
{
    krb5_key k;
    krb5_crypto_iov iov;
    krb5_data cdata = make_data(cipher, 16);

    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = make_data(plain, 16);
    krb5_k_create_key(NULL, &enc_key, &k);
    /* cbc-mac is the same as block encryption for a single block. */
    krb5int_camellia_cbc_mac(k, &iov, 1, &ivec, &cdata);
    krb5_k_free_key(NULL, k);
}
Esempio n. 6
0
/* Internalize a keyblock and convert it to a key. */
static krb5_error_code
intern_key(krb5_context ctx, krb5_key *key, krb5_octet **bp, size_t *sp)
{
    krb5_keyblock *keyblock;
    krb5_error_code ret;

    ret = krb5_internalize_opaque(ctx, KV5M_KEYBLOCK,
                                  (krb5_pointer *) &keyblock, bp, sp);
    if (ret != 0)
        return ret;
    ret = krb5_k_create_key(ctx, keyblock, key);
    krb5_free_keyblock(ctx, keyblock);
    return ret;
}
Esempio n. 7
0
/* Encrypt or decrypt using a keyblock. */
static krb5_error_code
keyblock_crypt(const struct krb5_enc_provider *enc, krb5_keyblock *keyblock,
               const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data)
{
    krb5_error_code ret;
    krb5_key key;

    ret = krb5_k_create_key(NULL, keyblock, &key);
    if (ret != 0)
        return ret;
    /* Works for encryption or decryption since arcfour is a stream cipher. */
    ret = enc->encrypt(key, ivec, data, num_data);
    krb5_k_free_key(NULL, key);
    return ret;
}
Esempio n. 8
0
krb5_error_code KRB5_CALLCONV
krb5_c_encrypt(krb5_context context, const krb5_keyblock *keyblock,
               krb5_keyusage usage, const krb5_data *cipher_state,
               const krb5_data *input, krb5_enc_data *output)
{
    krb5_key key;
    krb5_error_code ret;

    ret = krb5_k_create_key(context, keyblock, &key);
    if (ret != 0)
        return ret;
    ret = krb5_k_encrypt(context, key, usage, cipher_state, input, output);
    krb5_k_free_key(context, key);
    return ret;
}
Esempio n. 9
0
/* Our DR function, a simple wrapper around krb5int_derive_random(). */
static krb5_error_code
dr(const struct krb5_enc_provider *enc, const krb5_keyblock *inkey,
   unsigned char *out, const krb5_data *in_constant)
{
    krb5_data outdata = make_data(out, enc->keybytes);
    krb5_key key = NULL;
    krb5_error_code ret;

    ret = krb5_k_create_key(NULL, inkey, &key);
    if (ret != 0)
        return ret;
    ret = krb5int_derive_random(enc, key, &outdata, in_constant,
                                DERIVE_RFC3961);
    krb5_k_free_key(NULL, key);
    return ret;
}
Esempio n. 10
0
krb5_error_code KRB5_CALLCONV
krb5_c_decrypt_iov(krb5_context context, const krb5_keyblock *keyblock,
                   krb5_keyusage usage, const krb5_data *cipher_state,
                   krb5_crypto_iov *data, size_t num_data)
{
    krb5_key key;
    krb5_error_code ret;

    ret = krb5_k_create_key(context, keyblock, &key);
    if (ret != 0)
        return ret;
    ret = krb5_k_decrypt_iov(context, key, usage, cipher_state, data,
                             num_data);
    krb5_k_free_key(context, key);
    return ret;
}
Esempio n. 11
0
krb5_error_code KRB5_CALLCONV
krb5_c_make_checksum(krb5_context context, krb5_cksumtype cksumtype,
                     const krb5_keyblock *keyblock, krb5_keyusage usage,
                     const krb5_data *input, krb5_checksum *cksum)
{
    krb5_key key = NULL;
    krb5_error_code ret;

    if (keyblock != NULL) {
        ret = krb5_k_create_key(context, keyblock, &key);
        if (ret != 0)
            return ret;
    }
    ret = krb5_k_make_checksum(context, cksumtype, key, usage, input, cksum);
    krb5_k_free_key(context, key);
    return ret;
}
Esempio n. 12
0
int
main(int argc, char **argv)
{
#ifdef CAMELLIA
    krb5_context context = NULL;
    krb5_keyblock keyblock;
    krb5_key key;
    const struct krb5_enc_provider *enc = &krb5int_enc_camellia128;
    krb5_crypto_iov iov;
    unsigned char resultbuf[16];
    krb5_data result = make_data(resultbuf, 16);

    /* Create the example key. */
    keyblock.magic = KV5M_KEYBLOCK;
    keyblock.enctype = ENCTYPE_CAMELLIA128_CTS_CMAC;
    keyblock.length = 16;
    keyblock.contents = keybytes;
    assert(krb5_k_create_key(context, &keyblock, &key) == 0);

    /* Example 1. */
    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = make_data(input, 0);
    assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
    check_result("example 1", resultbuf, cmac1);

    /* Example 2. */
    iov.data.length = 16;
    assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
    check_result("example 2", resultbuf, cmac2);

    /* Example 3. */
    iov.data.length = 40;
    assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
    check_result("example 3", resultbuf, cmac3);

    /* Example 4. */
    iov.data.length = 64;
    assert(krb5int_cmac_checksum(enc, key, &iov, 1, &result) == 0);
    check_result("example 4", resultbuf, cmac4);

    printf("All CMAC tests passed.\n");
    krb5_k_free_key(context, key);
#endif /* CAMELLIA */
    return 0;
}
Esempio n. 13
0
static krb5_error_code
kg_derive_des_enc_key(krb5_context context, krb5_key subkey, krb5_key *out)
{
    krb5_error_code code;
    krb5_keyblock *keyblock;
    unsigned int i;

    *out = NULL;

    code = krb5_k_key_keyblock(context, subkey, &keyblock);
    if (code != 0)
        return code;

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

    code = krb5_k_create_key(context, keyblock, out);
    krb5_free_keyblock(context, keyblock);
    return code;
}
Esempio n. 14
0
static krb5_error_code hmac1(const struct krb5_hash_provider *h,
                             krb5_keyblock *key,
                             krb5_data *in, krb5_data *out)
{
    char tmp[40];
    size_t blocksize, hashsize;
    krb5_error_code err;
    krb5_key k;
    krb5_crypto_iov iov;
    krb5_data d;

    printk(" test key", key);
    blocksize = h->blocksize;
    hashsize = h->hashsize;
    if (hashsize > sizeof(tmp))
        abort();
    if (key->length > blocksize) {
        iov.flags = KRB5_CRYPTO_TYPE_DATA;
        iov.data = make_data(key->contents, key->length);
        d = make_data(tmp, hashsize);
        err = h->hash(&iov, 1, &d);
        if (err) {
            com_err(whoami, err, "hashing key before calling hmac");
            exit(1);
        }
        key->length = d.length;
        key->contents = (krb5_octet *) d.data;
        printk(" pre-hashed key", key);
    }
    printd(" hmac input", in);
    krb5_k_create_key(NULL, key, &k);
    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = *in;
    err = krb5int_hmac(h, k, &iov, 1, out);
    krb5_k_free_key(NULL, k);
    if (err == 0)
        printd(" hmac output", out);
    return err;
}
Esempio n. 15
0
static krb5_error_code
add_cached_dkey(krb5_key key, const krb5_data *constant,
                const krb5_keyblock *dkeyblock, krb5_key *cached_dkey)
{
    krb5_key dkey;
    krb5_error_code ret;
    struct derived_key *dkent = NULL;
    char *data = NULL;

    /* Allocate fields for the new entry. */
    dkent = malloc(sizeof(*dkent));
    if (dkent == NULL)
        goto cleanup;
    data = malloc(constant->length);
    if (data == NULL)
        goto cleanup;
    ret = krb5_k_create_key(NULL, dkeyblock, &dkey);
    if (ret != 0)
        goto cleanup;

    /* Add the new entry to the list. */
    memcpy(data, constant->data, constant->length);
    dkent->dkey = dkey;
    dkent->constant.data = data;
    dkent->constant.length = constant->length;
    dkent->next = key->derived;
    key->derived = dkent;

    /* Return a "copy" of the cached key. */
    krb5_k_reference_key(NULL, dkey);
    *cached_dkey = dkey;
    return 0;

cleanup:
    free(dkent);
    free(data);
    return ENOMEM;
}
Esempio n. 16
0
/* Derive a key by XOR with 0xF0 bytes. */
static krb5_error_code
mk_xorkey(krb5_key origkey, krb5_key *xorkey)
{
    krb5_error_code retval = 0;
    unsigned char *xorbytes;
    krb5_keyblock xorkeyblock;
    size_t i = 0;

    xorbytes = k5memdup(origkey->keyblock.contents, origkey->keyblock.length,
                        &retval);
    if (xorbytes == NULL)
        return retval;
    for (i = 0; i < origkey->keyblock.length; i++)
        xorbytes[i] ^= 0xf0;

    /* Do a shallow copy here. */
    xorkeyblock = origkey->keyblock;
    xorkeyblock.contents = xorbytes;

    retval = krb5_k_create_key(0, &xorkeyblock, xorkey);
    zapfree(xorbytes, sizeof(xorbytes));
    return retval;
}
Esempio n. 17
0
krb5_error_code KRB5_CALLCONV
krb5_mk_req_extended(krb5_context context, krb5_auth_context *auth_context,
                     krb5_flags ap_req_options, krb5_data *in_data,
                     krb5_creds *in_creds, krb5_data *outbuf)
{
    krb5_error_code       retval;
    krb5_checksum         checksum;
    krb5_checksum         *checksump = 0;
    krb5_auth_context     new_auth_context;
    krb5_enctype          *desired_etypes = NULL;

    krb5_ap_req request;
    krb5_data *scratch = 0;
    krb5_data *toutbuf;

    request.ap_options = ap_req_options & AP_OPTS_WIRE_MASK;
    request.authenticator.ciphertext.data = NULL;
    request.ticket = 0;

    if (!in_creds->ticket.length)
        return(KRB5_NO_TKT_SUPPLIED);

    if ((ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) &&
        !(ap_req_options & AP_OPTS_MUTUAL_REQUIRED))
        return(EINVAL);

    /* we need a native ticket */
    if ((retval = decode_krb5_ticket(&(in_creds)->ticket, &request.ticket)))
        return(retval);

    /* verify that the ticket is not expired */
    if ((retval = krb5int_validate_times(context, &in_creds->times)) != 0)
        goto cleanup;

    /* generate auth_context if needed */
    if (*auth_context == NULL) {
        if ((retval = krb5_auth_con_init(context, &new_auth_context)))
            goto cleanup;
        *auth_context = new_auth_context;
    }

    if ((*auth_context)->key != NULL) {
        krb5_k_free_key(context, (*auth_context)->key);
        (*auth_context)->key = NULL;
    }

    /* set auth context keyblock */
    if ((retval = krb5_k_create_key(context, &in_creds->keyblock,
                                    &((*auth_context)->key))))
        goto cleanup;

    /* generate seq number if needed */
    if ((((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE)
         || ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE))
        && ((*auth_context)->local_seq_number == 0)) {
        if ((retval = krb5_generate_seq_number(context, &in_creds->keyblock,
                                               &(*auth_context)->local_seq_number)))
            goto cleanup;
    }

    /* generate subkey if needed */
    if ((ap_req_options & AP_OPTS_USE_SUBKEY)&&(!(*auth_context)->send_subkey)) {
        retval = k5_generate_and_save_subkey(context, *auth_context,
                                             &in_creds->keyblock,
                                             in_creds->keyblock.enctype);
        if (retval)
            goto cleanup;
    }


    if (!in_data && (*auth_context)->checksum_func) {
        retval = (*auth_context)->checksum_func( context,
                                                 *auth_context,
                                                 (*auth_context)->checksum_func_data,
                                                 &in_data);
        if (retval)
            goto cleanup;
    }

    if (in_data) {
        if ((*auth_context)->req_cksumtype == 0x8003) {
            /* XXX Special hack for GSSAPI */
            checksum.checksum_type = 0x8003;
            checksum.length = in_data->length;
            checksum.contents = (krb5_octet *) in_data->data;
        } else {
            krb5_enctype enctype = krb5_k_key_enctype(context,
                                                      (*auth_context)->key);
            krb5_cksumtype cksumtype = ap_req_cksum(context, *auth_context,
                                                    enctype);
            if ((retval = krb5_k_make_checksum(context,
                                               cksumtype,
                                               (*auth_context)->key,
                                               KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
                                               in_data, &checksum)))
                goto cleanup_cksum;
        }
        checksump = &checksum;
    }

    /* Generate authenticator */
    if (((*auth_context)->authentp = (krb5_authenticator *)malloc(sizeof(
                                                                      krb5_authenticator))) == NULL) {
        retval = ENOMEM;
        goto cleanup_cksum;
    }

    if (ap_req_options & AP_OPTS_ETYPE_NEGOTIATION) {
        if ((*auth_context)->permitted_etypes == NULL) {
            retval = krb5_get_tgs_ktypes(context, in_creds->server, &desired_etypes);
            if (retval)
                goto cleanup_cksum;
        } else
            desired_etypes = (*auth_context)->permitted_etypes;
    }

    TRACE_MK_REQ(context, in_creds, (*auth_context)->local_seq_number,
                 (*auth_context)->send_subkey, &in_creds->keyblock);
    if ((retval = generate_authenticator(context,
                                         (*auth_context)->authentp,
                                         in_creds->client, checksump,
                                         (*auth_context)->send_subkey,
                                         (*auth_context)->local_seq_number,
                                         in_creds->authdata,
                                         (*auth_context)->ad_context,
                                         desired_etypes,
                                         in_creds->keyblock.enctype)))
        goto cleanup_cksum;

    /* encode the authenticator */
    if ((retval = encode_krb5_authenticator((*auth_context)->authentp,
                                            &scratch)))
        goto cleanup_cksum;

    /* call the encryption routine */
    if ((retval = krb5_encrypt_helper(context, &in_creds->keyblock,
                                      KRB5_KEYUSAGE_AP_REQ_AUTH,
                                      scratch, &request.authenticator)))
        goto cleanup_cksum;

    if ((retval = encode_krb5_ap_req(&request, &toutbuf)))
        goto cleanup_cksum;
    *outbuf = *toutbuf;

    free(toutbuf);

cleanup_cksum:
    /* Null out these fields, to prevent pointer sharing problems;
     * they were supplied by the caller
     */
    if ((*auth_context)->authentp != NULL) {
        (*auth_context)->authentp->client = NULL;
        (*auth_context)->authentp->checksum = NULL;
    }
    if (checksump && checksump->checksum_type != 0x8003)
        free(checksump->contents);

cleanup:
    if (desired_etypes &&
        desired_etypes != (*auth_context)->permitted_etypes)
        free(desired_etypes);
    if (request.ticket)
        krb5_free_ticket(context, request.ticket);
    if (request.authenticator.ciphertext.data) {
        (void) memset(request.authenticator.ciphertext.data, 0,
                      request.authenticator.ciphertext.length);
        free(request.authenticator.ciphertext.data);
    }
    if (scratch) {
        memset(scratch->data, 0, scratch->length);
        free(scratch->data);
        free(scratch);
    }
    return retval;
}
Esempio n. 18
0
static krb5_error_code
rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context,
                   const krb5_ap_req *req, krb5_const_principal server,
                   krb5_keytab keytab, krb5_flags *ap_req_options,
                   krb5_ticket **ticket, int check_valid_flag)
{
    krb5_error_code       retval = 0;
    krb5_enctype         *desired_etypes = NULL;
    int                   desired_etypes_len = 0;
    int                   rfc4537_etypes_len = 0;
    krb5_enctype         *permitted_etypes = NULL;
    int                   permitted_etypes_len = 0;
    krb5_keyblock         decrypt_key;

    decrypt_key.enctype = ENCTYPE_NULL;
    decrypt_key.contents = NULL;
    req->ticket->enc_part2 = NULL;

    /* if (req->ap_options & AP_OPTS_USE_SESSION_KEY)
       do we need special processing here ?     */

    /* decrypt the ticket */
    if ((*auth_context)->key) { /* User to User authentication */
        if ((retval = krb5_decrypt_tkt_part(context,
                                            &(*auth_context)->key->keyblock,
                                            req->ticket)))
            goto cleanup;
        if (check_valid_flag) {
            decrypt_key = (*auth_context)->key->keyblock;
            (*auth_context)->key->keyblock.contents = NULL;
        }
        krb5_k_free_key(context, (*auth_context)->key);
        (*auth_context)->key = NULL;
    } else {
        retval = decrypt_ticket(context, req, server, keytab,
                                check_valid_flag ? &decrypt_key : NULL);
        if (retval)
            goto cleanup;
    }
    TRACE_RD_REQ_TICKET(context, req->ticket->enc_part2->client,
                        req->ticket->server, req->ticket->enc_part2->session);

    /* XXX this is an evil hack.  check_valid_flag is set iff the call
       is not from inside the kdc.  we can use this to determine which
       key usage to use */
#ifndef LEAN_CLIENT
    if ((retval = decrypt_authenticator(context, req,
                                        &((*auth_context)->authentp),
                                        check_valid_flag)))
        goto cleanup;
#endif
    if (!krb5_principal_compare(context, (*auth_context)->authentp->client,
                                req->ticket->enc_part2->client)) {
        retval = KRB5KRB_AP_ERR_BADMATCH;
        goto cleanup;
    }

    if ((*auth_context)->remote_addr &&
        !krb5_address_search(context, (*auth_context)->remote_addr,
                             req->ticket->enc_part2->caddrs)) {
        retval = KRB5KRB_AP_ERR_BADADDR;
        goto cleanup;
    }

    if (!server) {
        server = req->ticket->server;
    }
    /* Get an rcache if necessary. */
    if (((*auth_context)->rcache == NULL)
        && ((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME)
        && server) {
        if ((retval = krb5_get_server_rcache(context,
                                             krb5_princ_component(context,server,0),
                                             &(*auth_context)->rcache)))
            goto cleanup;
    }
    /* okay, now check cross-realm policy */

#if defined(_SINGLE_HOP_ONLY)

    /* Single hop cross-realm tickets only */

    {
        krb5_transited *trans = &(req->ticket->enc_part2->transited);

        /* If the transited list is empty, then we have at most one hop */
        if (trans->tr_contents.length > 0 && trans->tr_contents.data[0])
            retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
    }

#elif defined(_NO_CROSS_REALM)

    /* No cross-realm tickets */

    {
        char            * lrealm;
        krb5_data       * realm;
        krb5_transited  * trans;

        realm = krb5_princ_realm(context, req->ticket->enc_part2->client);
        trans = &(req->ticket->enc_part2->transited);

        /*
         * If the transited list is empty, then we have at most one hop
         * So we also have to check that the client's realm is the local one
         */
        krb5_get_default_realm(context, &lrealm);
        if ((trans->tr_contents.length > 0 && trans->tr_contents.data[0]) ||
            !data_eq_string(*realm, lrealm)) {
            retval = KRB5KRB_AP_ERR_ILL_CR_TKT;
        }
        free(lrealm);
    }

#else

    /* Hierarchical Cross-Realm */

    {
        krb5_data      * realm;
        krb5_transited * trans;

        realm = krb5_princ_realm(context, req->ticket->enc_part2->client);
        trans = &(req->ticket->enc_part2->transited);

        /*
         * If the transited list is not empty, then check that all realms
         * transited are within the hierarchy between the client's realm
         * and the local realm.
         */
        if (trans->tr_contents.length > 0 && trans->tr_contents.data[0]) {
            retval = krb5_check_transited_list(context, &(trans->tr_contents),
                                               realm,
                                               krb5_princ_realm (context,server));
        }
    }

#endif

    if (retval)  goto cleanup;

    /* only check rcache if sender has provided one---some services
       may not be able to use replay caches (such as datagram servers) */

    if ((*auth_context)->rcache) {
        krb5_donot_replay  rep;
        krb5_tkt_authent   tktauthent;

        tktauthent.ticket = req->ticket;
        tktauthent.authenticator = (*auth_context)->authentp;
        if (!(retval = krb5_auth_to_rep(context, &tktauthent, &rep))) {
            retval = krb5_rc_hash_message(context,
                                          &req->authenticator.ciphertext,
                                          &rep.msghash);
            if (!retval) {
                retval = krb5_rc_store(context, (*auth_context)->rcache, &rep);
                free(rep.msghash);
            }
            free(rep.server);
            free(rep.client);
        }

        if (retval)
            goto cleanup;
    }

    retval = krb5int_validate_times(context, &req->ticket->enc_part2->times);
    if (retval != 0)
        goto cleanup;

    if ((retval = krb5_check_clockskew(context, (*auth_context)->authentp->ctime)))
        goto cleanup;

    if (check_valid_flag) {
        if (req->ticket->enc_part2->flags & TKT_FLG_INVALID) {
            retval = KRB5KRB_AP_ERR_TKT_INVALID;
            goto cleanup;
        }

        if ((retval = krb5_authdata_context_init(context,
                                                 &(*auth_context)->ad_context)))
            goto cleanup;
        if ((retval = krb5int_authdata_verify(context,
                                              (*auth_context)->ad_context,
                                              AD_USAGE_MASK,
                                              auth_context,
                                              &decrypt_key,
                                              req)))
            goto cleanup;
    }

    /* read RFC 4537 etype list from sender */
    retval = decode_etype_list(context,
                               (*auth_context)->authentp,
                               &desired_etypes,
                               &rfc4537_etypes_len);
    if (retval != 0)
        goto cleanup;

    if (desired_etypes == NULL)
        desired_etypes = (krb5_enctype *)calloc(4, sizeof(krb5_enctype));
    else
        desired_etypes = (krb5_enctype *)realloc(desired_etypes,
                                                 (rfc4537_etypes_len + 4) *
                                                 sizeof(krb5_enctype));
    if (desired_etypes == NULL) {
        retval = ENOMEM;
        goto cleanup;
    }

    desired_etypes_len = rfc4537_etypes_len;

    /*
     * RFC 4537:
     *
     *   If the EtypeList is present and the server prefers an enctype from
     *   the client's enctype list over that of the AP-REQ authenticator
     *   subkey (if that is present) or the service ticket session key, the
     *   server MUST create a subkey using that enctype.  This negotiated
     *   subkey is sent in the subkey field of AP-REP message, and it is then
     *   used as the protocol key or base key [RFC3961] for subsequent
     *   communication.
     *
     *   If the enctype of the ticket session key is included in the enctype
     *   list sent by the client, it SHOULD be the last on the list;
     *   otherwise, this enctype MUST NOT be negotiated if it was not included
     *   in the list.
     *
     * The second paragraph does appear to contradict the first with respect
     * to whether it is legal to negotiate the ticket session key type if it
     * is absent in the EtypeList. A literal reading suggests that we can use
     * the AP-REQ subkey enctype. Also a client has no way of distinguishing
     * a server that does not RFC 4537 from one that has chosen the same
     * enctype as the ticket session key for the acceptor subkey, surely.
     */

    if ((*auth_context)->authentp->subkey != NULL) {
        desired_etypes[desired_etypes_len++] = (*auth_context)->authentp->subkey->enctype;
    }
    desired_etypes[desired_etypes_len++] = req->ticket->enc_part2->session->enctype;
    desired_etypes[desired_etypes_len] = ENCTYPE_NULL;

    if (((*auth_context)->auth_context_flags & KRB5_AUTH_CONTEXT_PERMIT_ALL) == 0) {
        if ((*auth_context)->permitted_etypes != NULL) {
            permitted_etypes = (*auth_context)->permitted_etypes;
        } else {
            retval = krb5_get_permitted_enctypes(context, &permitted_etypes);
            if (retval != 0)
                goto cleanup;
        }
        permitted_etypes_len = krb5int_count_etypes(permitted_etypes);
    } else {
        permitted_etypes = NULL;
        permitted_etypes_len = 0;
    }

    /* check if the various etypes are permitted */
    retval = negotiate_etype(context,
                             desired_etypes, desired_etypes_len,
                             rfc4537_etypes_len,
                             permitted_etypes, permitted_etypes_len,
                             &(*auth_context)->negotiated_etype);
    if (retval != 0)
        goto cleanup;
    TRACE_RD_REQ_NEGOTIATED_ETYPE(context, (*auth_context)->negotiated_etype);

    assert((*auth_context)->negotiated_etype != ENCTYPE_NULL);

    (*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number;
    if ((*auth_context)->authentp->subkey) {
        TRACE_RD_REQ_SUBKEY(context, (*auth_context)->authentp->subkey);
        if ((retval = krb5_k_create_key(context,
                                        (*auth_context)->authentp->subkey,
                                        &((*auth_context)->recv_subkey))))
            goto cleanup;
        retval = krb5_k_create_key(context, (*auth_context)->authentp->subkey,
                                   &((*auth_context)->send_subkey));
        if (retval) {
            krb5_k_free_key(context, (*auth_context)->recv_subkey);
            (*auth_context)->recv_subkey = NULL;
            goto cleanup;
        }
    } else {
        (*auth_context)->recv_subkey = 0;
        (*auth_context)->send_subkey = 0;
    }

    if ((retval = krb5_k_create_key(context, req->ticket->enc_part2->session,
                                    &((*auth_context)->key))))
        goto cleanup;

    debug_log_authz_data("ticket", req->ticket->enc_part2->authorization_data);

    /*
     * If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used
     * then the default sequence number is the one's complement of the
     * sequence number sent ot us.
     */
    if ((!(req->ap_options & AP_OPTS_MUTUAL_REQUIRED)) &&
        (*auth_context)->remote_seq_number) {
        (*auth_context)->local_seq_number ^=
            (*auth_context)->remote_seq_number;
    }

    if (ticket)
        if ((retval = krb5_copy_ticket(context, req->ticket, ticket)))
            goto cleanup;
    if (ap_req_options) {
        *ap_req_options = req->ap_options & AP_OPTS_WIRE_MASK;
        if (rfc4537_etypes_len != 0)
            *ap_req_options |= AP_OPTS_ETYPE_NEGOTIATION;
        if ((*auth_context)->negotiated_etype !=
            krb5_k_key_enctype(context, (*auth_context)->key))
            *ap_req_options |= AP_OPTS_USE_SUBKEY;
    }

    retval = 0;

cleanup:
    if (desired_etypes != NULL)
        free(desired_etypes);
    if (permitted_etypes != NULL &&
        permitted_etypes != (*auth_context)->permitted_etypes)
        free(permitted_etypes);
    if (retval) {
        /* only free if we're erroring out...otherwise some
           applications will need the output. */
        if (req->ticket->enc_part2)
            krb5_free_enc_tkt_part(context, req->ticket->enc_part2);
        req->ticket->enc_part2 = NULL;
    }
    if (check_valid_flag)
        krb5_free_keyblock_contents(context, &decrypt_key);

    return retval;
}
Esempio n. 19
0
krb5_error_code
krb5int_dk_string_to_key(const struct krb5_keytypes *ktp,
                         const krb5_data *string, const krb5_data *salt,
                         const krb5_data *parms, krb5_keyblock *keyblock)
{
    krb5_error_code ret;
    size_t keybytes, keylength, concatlen;
    unsigned char *concat = NULL, *foldstring = NULL, *foldkeydata = NULL;
    krb5_data indata;
    krb5_keyblock foldkeyblock;
    krb5_key foldkey = NULL;

    /* keyblock->length is checked by krb5int_derive_key. */

    keybytes = ktp->enc->keybytes;
    keylength = ktp->enc->keylength;

    concatlen = string->length + salt->length;

    concat = k5alloc(concatlen, &ret);
    if (ret != 0)
        goto cleanup;
    foldstring = k5alloc(keybytes, &ret);
    if (ret != 0)
        goto cleanup;
    foldkeydata = k5alloc(keylength, &ret);
    if (ret != 0)
        goto cleanup;

    /* construct input string ( = string + salt), fold it, make_key it */

    if (string->length > 0)
        memcpy(concat, string->data, string->length);
    if (salt->length > 0)
        memcpy(concat + string->length, salt->data, salt->length);

    krb5int_nfold(concatlen*8, concat, keybytes*8, foldstring);

    indata.length = keybytes;
    indata.data = (char *) foldstring;
    foldkeyblock.length = keylength;
    foldkeyblock.contents = foldkeydata;
    foldkeyblock.enctype = ktp->etype;

    ret = ktp->rand2key(&indata, &foldkeyblock);
    if (ret != 0)
        goto cleanup;

    ret = krb5_k_create_key(NULL, &foldkeyblock, &foldkey);
    if (ret != 0)
        goto cleanup;

    /* now derive the key from this one */

    indata.length = kerberos_len;
    indata.data = (char *) kerberos;

    ret = krb5int_derive_keyblock(ktp->enc, NULL, foldkey, keyblock, &indata,
                                  DERIVE_RFC3961);
    if (ret != 0)
        memset(keyblock->contents, 0, keyblock->length);

cleanup:
    zapfree(concat, concatlen);
    zapfree(foldstring, keybytes);
    zapfree(foldkeydata, keylength);
    krb5_k_free_key(NULL, foldkey);
    return ret;
}
Esempio n. 20
0
int
main ()
{
    krb5_context context = 0;
    krb5_data  in, in2, out, out2, check, check2, state, signdata;
    krb5_crypto_iov iov[5];
    int i, j, pos;
    unsigned int dummy;
    size_t len;
    krb5_enc_data enc_out, enc_out2;
    krb5_keyblock *keyblock;
    krb5_key key;

    memset(iov, 0, sizeof(iov));

    in.data = "This is a test.\n";
    in.length = strlen (in.data);
    in2.data = "This is another test.\n";
    in2.length = strlen (in2.data);

    test ("Seeding random number generator",
          krb5_c_random_seed (context, &in));

    /* Set up output buffers. */
    out.data = malloc(2048);
    out2.data = malloc(2048);
    check.data = malloc(2048);
    check2.data = malloc(2048);
    if (out.data == NULL || out2.data == NULL
        || check.data == NULL || check2.data == NULL)
        abort();
    out.magic = KV5M_DATA;
    out.length = 2048;
    out2.magic = KV5M_DATA;
    out2.length = 2048;
    check.length = 2048;
    check2.length = 2048;

    for (i = 0; interesting_enctypes[i]; i++) {
        krb5_enctype enctype = interesting_enctypes [i];

        printf ("Testing enctype %d\n", enctype);
        test ("Initializing a keyblock",
              krb5_init_keyblock (context, enctype, 0, &keyblock));
        test ("Generating random keyblock",
              krb5_c_make_random_key (context, enctype, keyblock));
        test ("Creating opaque key from keyblock",
              krb5_k_create_key (context, keyblock, &key));

        enc_out.ciphertext = out;
        enc_out2.ciphertext = out2;
        /* We use an intermediate `len' because size_t may be different size
           than `int' */
        krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
        enc_out.ciphertext.length = len;

        /* Encrypt, decrypt, and see if we got the plaintext back again. */
        test ("Encrypting (c)",
              krb5_c_encrypt (context, keyblock, 7, 0, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Decrypting",
              krb5_c_decrypt (context, keyblock, 7, 0, &enc_out, &check));
        test ("Comparing", compare_results (&in, &check));

        /* Try again with the opaque-key-using variants. */
        memset(out.data, 0, out.length);
        test ("Encrypting (k)",
              krb5_k_encrypt (context, key, 7, 0, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Decrypting",
              krb5_k_decrypt (context, key, 7, 0, &enc_out, &check));
        test ("Comparing", compare_results (&in, &check));

        /* Check if this enctype supports IOV encryption. */
        if ( krb5_c_crypto_length(context, keyblock->enctype,
                                  KRB5_CRYPTO_TYPE_HEADER, &dummy) == 0 ){
            /* Set up iovecs for stream decryption. */
            memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
            iov[0].flags= KRB5_CRYPTO_TYPE_STREAM;
            iov[0].data.data = out2.data;
            iov[0].data.length = enc_out.ciphertext.length;
            iov[1].flags = KRB5_CRYPTO_TYPE_DATA;

            /* Decrypt the encrypted data from above and check it. */
            test("IOV stream decrypting (c)",
                 krb5_c_decrypt_iov( context, keyblock, 7, 0, iov, 2));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Try again with the opaque-key-using variant. */
            memcpy(out2.data, enc_out.ciphertext.data, enc_out.ciphertext.length);
            test("IOV stream decrypting (k)",
                 krb5_k_decrypt_iov( context, key, 7, 0, iov, 2));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Set up iovecs for AEAD encryption. */
            signdata.magic = KV5M_DATA;
            signdata.data = (char *) "This should be signed";
            signdata.length = strlen(signdata.data);
            iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
            iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
            iov[1].data = in; /*We'll need to copy memory before encrypt*/
            iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
            iov[2].data = signdata;
            iov[3].flags = KRB5_CRYPTO_TYPE_PADDING;
            iov[4].flags = KRB5_CRYPTO_TYPE_TRAILER;

            /* "Allocate" data for the iovec buffers from the "out" buffer. */
            test("Setting up iov lengths",
                 krb5_c_crypto_length_iov(context, keyblock->enctype, iov, 5));
            for (j=0,pos=0; j <= 4; j++ ){
                if (iov[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
                    continue;
                iov[j].data.data = &out.data[pos];
                pos += iov[j].data.length;
            }
            assert (iov[1].data.length == in.length);
            memcpy(iov[1].data.data, in.data, in.length);

            /* Encrypt and decrypt in place, and check the result. */
            test("iov encrypting (c)",
                 krb5_c_encrypt_iov(context, keyblock, 7, 0, iov, 5));
            assert(iov[1].data.length == in.length);
            display("Header", &iov[0].data);
            display("Data", &iov[1].data);
            display("Padding", &iov[3].data);
            display("Trailer", &iov[4].data);
            test("iov decrypting",
                 krb5_c_decrypt_iov(context, keyblock, 7, 0, iov, 5));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));

            /* Try again with opaque-key-using variants. */
            test("iov encrypting (k)",
                 krb5_k_encrypt_iov(context, key, 7, 0, iov, 5));
            assert(iov[1].data.length == in.length);
            display("Header", &iov[0].data);
            display("Data", &iov[1].data);
            display("Padding", &iov[3].data);
            display("Trailer", &iov[4].data);
            test("iov decrypting",
                 krb5_k_decrypt_iov(context, key, 7, 0, iov, 5));
            test("Comparing results",
                 compare_results(&in, &iov[1].data));
        }

        enc_out.ciphertext.length = out.length;
        check.length = 2048;

        test ("init_state",
              krb5_c_init_state (context, keyblock, 7, &state));
        test ("Encrypting with state",
              krb5_c_encrypt (context, keyblock, 7, &state, &in, &enc_out));
        display ("Enc output", &enc_out.ciphertext);
        test ("Encrypting again with state",
              krb5_c_encrypt (context, keyblock, 7, &state, &in2, &enc_out2));
        display ("Enc output", &enc_out2.ciphertext);
        test ("free_state",
              krb5_c_free_state (context, keyblock, &state));
        test ("init_state",
              krb5_c_init_state (context, keyblock, 7, &state));
        test ("Decrypting with state",
              krb5_c_decrypt (context, keyblock, 7, &state, &enc_out, &check));
        test ("Decrypting again with state",
              krb5_c_decrypt (context, keyblock, 7, &state, &enc_out2, &check2));
        test ("free_state",
              krb5_c_free_state (context, keyblock, &state));
        test ("Comparing",
              compare_results (&in, &check));
        test ("Comparing",
              compare_results (&in2, &check2));

        krb5_free_keyblock (context, keyblock);
        krb5_k_free_key (context, key);
    }

    /* Test the RC4 decrypt fallback from key usage 9 to 8. */
    test ("Initializing an RC4 keyblock",
          krb5_init_keyblock (context, ENCTYPE_ARCFOUR_HMAC, 0, &keyblock));
    test ("Generating random RC4 key",
          krb5_c_make_random_key (context, ENCTYPE_ARCFOUR_HMAC, keyblock));
    enc_out.ciphertext = out;
    krb5_c_encrypt_length (context, keyblock->enctype, in.length, &len);
    enc_out.ciphertext.length = len;
    check.length = 2048;
    test ("Encrypting with RC4 key usage 8",
          krb5_c_encrypt (context, keyblock, 8, 0, &in, &enc_out));
    display ("Enc output", &enc_out.ciphertext);
    test ("Decrypting with RC4 key usage 9",
          krb5_c_decrypt (context, keyblock, 9, 0, &enc_out, &check));
    test ("Comparing", compare_results (&in, &check));

    krb5_free_keyblock (context, keyblock);
    free(out.data);
    free(out2.data);
    free(check.data);
    free(check2.data);
    return 0;
}
Esempio n. 21
0
krb5_error_code
kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey,
              krb5_cksumtype *cksumtype)
{
    krb5_error_code code;
    krb5int_access kaccess;

    assert(ctx != NULL);
    assert(subkey != NULL);

    *cksumtype = 0;
    ctx->proto = 0;

    if (ctx->enc == NULL) {
        ctx->signalg = -1;
        ctx->sealalg = -1;
    }

    code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION);
    if (code != 0)
        return code;

    code = (*kaccess.mandatory_cksumtype)(context, subkey->keyblock.enctype,
                                          cksumtype);
    if (code != 0)
        return code;

    switch (subkey->keyblock.enctype) {
    case ENCTYPE_DES_CBC_MD5:
    case ENCTYPE_DES_CBC_MD4:
    case ENCTYPE_DES_CBC_CRC:
        krb5_k_free_key(context, ctx->seq);
        code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq);
        if (code != 0)
            return code;

        krb5_k_free_key(context, ctx->enc);
        code = kg_derive_des_enc_key(context, subkey, &ctx->enc);
        if (code != 0)
            return code;

        ctx->enc->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
        ctx->seq->keyblock.enctype = ENCTYPE_DES_CBC_RAW;
        ctx->signalg = SGN_ALG_DES_MAC_MD5;
        ctx->cksum_size = 8;
        ctx->sealalg = SEAL_ALG_DES;

        break;
    case ENCTYPE_DES3_CBC_SHA1:
        code = kg_copy_keys(context, ctx, subkey);
        if (code != 0)
            return code;

        ctx->enc->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
        ctx->seq->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
        ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
        ctx->cksum_size = 20;
        ctx->sealalg = SEAL_ALG_DES3KD;
        break;
    case ENCTYPE_ARCFOUR_HMAC:
    case ENCTYPE_ARCFOUR_HMAC_EXP:
        code = kg_copy_keys(context, ctx, subkey);
        if (code != 0)
            return code;

        ctx->signalg = SGN_ALG_HMAC_MD5;
        ctx->cksum_size = 8;
        ctx->sealalg = SEAL_ALG_MICROSOFT_RC4;
        break;
    default:
        ctx->proto = 1;
        break;
    }

    return 0;
}
Esempio n. 22
0
static krb5_error_code
pbkdf2_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string,
                     const krb5_data *salt, const krb5_data *pepper,
                     const krb5_data *params, krb5_keyblock *key,
                     enum deriv_alg deriv_alg, unsigned long def_iter_count)
{
    const struct krb5_hash_provider *hash;
    unsigned long iter_count;
    krb5_data out;
    static const krb5_data usage = { KV5M_DATA, 8, "kerberos" };
    krb5_key tempkey = NULL;
    krb5_error_code err;
    krb5_data sandp = empty_data();

    if (params) {
        unsigned char *p = (unsigned char *) params->data;
        if (params->length != 4)
            return KRB5_ERR_BAD_S2K_PARAMS;
        iter_count = load_32_be(p);
        /* Zero means 2^32, which is way above what we will accept.  Also don't
         * accept values less than the default, unless we're running tests. */
        if (iter_count == 0 ||
            (!k5_allow_weak_pbkdf2iter && iter_count < def_iter_count))
            return KRB5_ERR_BAD_S2K_PARAMS;

    } else
        iter_count = def_iter_count;

    /* This is not a protocol specification constraint; this is an
       implementation limit, which should eventually be controlled by
       a config file.  */
    if (iter_count >= MAX_ITERATION_COUNT)
        return KRB5_ERR_BAD_S2K_PARAMS;

    /* Use the output keyblock contents for temporary space. */
    out.data = (char *) key->contents;
    out.length = key->length;
    if (out.length != 16 && out.length != 32)
        return KRB5_CRYPTO_INTERNAL;

    if (pepper != NULL) {
        err = alloc_data(&sandp, pepper->length + 1 + salt->length);
        if (err)
            return err;

        if (pepper->length > 0)
            memcpy(sandp.data, pepper->data, pepper->length);
        sandp.data[pepper->length] = '\0';
        if (salt->length > 0)
            memcpy(&sandp.data[pepper->length + 1], salt->data, salt->length);

        salt = &sandp;
    }

    hash = (ktp->hash != NULL) ? ktp->hash : &krb5int_hash_sha1;
    err = krb5int_pbkdf2_hmac(hash, &out, iter_count, string, salt);
    if (err)
        goto cleanup;

    err = krb5_k_create_key (NULL, key, &tempkey);
    if (err)
        goto cleanup;

    err = krb5int_derive_keyblock(ktp->enc, ktp->hash, tempkey, key, &usage,
                                  deriv_alg);

cleanup:
    if (sandp.data)
        free(sandp.data);
    if (err)
        memset (out.data, 0, out.length);
    krb5_k_free_key (NULL, tempkey);
    return err;
}
Esempio n. 23
0
File: t_cts.c Progetto: PADL/krb5
static void test_cts()
{
    static const char input[4*16] =
        "I would like the General Gau's Chicken, please, and wonton soup.";
    static const unsigned char aeskey[16] = "chicken teriyaki";
    static const int lengths[] = { 17, 31, 32, 47, 48, 64 };

    unsigned int i;
    char outbuf[64], encivbuf[16], decivbuf[16];
    krb5_crypto_iov iov;
    krb5_data in, enciv, deciv;
    krb5_keyblock keyblock;
    krb5_key key;
    krb5_error_code err;

    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data.data = outbuf;
    in.data = (char *)input;
    enciv.length = deciv.length = 16;
    enciv.data = encivbuf;
    deciv.data = decivbuf;
    keyblock.contents = (krb5_octet *)aeskey;
    keyblock.length = 16;
    keyblock.enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;

    err = krb5_k_create_key(NULL, &keyblock, &key);
    if (err) {
        printf("error %ld from krb5_k_create_key\n", (long)err);
        exit(1);
    }

    memset(enciv.data, 0, 16);
    printk("AES 128-bit key", &keyblock);
    for (i = 0; i < sizeof(lengths)/sizeof(lengths[0]); i++) {
        memset(enciv.data, 0, 16);
        memset(deciv.data, 0, 16);

        printf("\n");
        iov.data.length = in.length = lengths[i];
        memcpy(outbuf, input, lengths[i]);
        printd("IV", &enciv);
        err = krb5int_aes_encrypt(key, &enciv, &iov, 1);
        if (err) {
            printf("error %ld from krb5int_aes_encrypt\n", (long)err);
            exit(1);
        }
        printd("Input", &in);
        printd("Output", &iov.data);
        printd("Next IV", &enciv);
        err = krb5int_aes_decrypt(key, &deciv, &iov, 1);
        if (err) {
            printf("error %ld from krb5int_aes_decrypt\n", (long)err);
            exit(1);
        }
        if (memcmp(outbuf, input, lengths[i]) != 0) {
            printd("Decryption result DOESN'T MATCH", &iov.data);
            exit(1);
        }
        if (memcmp(enciv.data, deciv.data, 16)) {
            printd("Decryption IV result DOESN'T MATCH", &deciv);
            exit(1);
        }
    }
    krb5_k_free_key(NULL, key);
}
Esempio n. 24
0
krb5_error_code
krb5int_c_combine_keys(krb5_context context, krb5_keyblock *key1,
                       krb5_keyblock *key2, krb5_keyblock *outkey)
{
    unsigned char *r1 = NULL, *r2 = NULL, *combined = NULL, *rnd = NULL;
    unsigned char *output = NULL;
    size_t keybytes, keylength;
    const struct krb5_enc_provider *enc;
    krb5_data input, randbits;
    krb5_keyblock tkeyblock;
    krb5_key tkey = NULL;
    krb5_error_code ret;
    const struct krb5_keytypes *ktp;
    krb5_boolean myalloc = FALSE;

    if (!enctype_ok(key1->enctype) || !enctype_ok(key2->enctype))
        return KRB5_CRYPTO_INTERNAL;

    if (key1->length != key2->length || key1->enctype != key2->enctype)
        return KRB5_CRYPTO_INTERNAL;

    /* Find our encryption algorithm. */
    ktp = find_enctype(key1->enctype);
    if (ktp == NULL)
        return KRB5_BAD_ENCTYPE;
    enc = ktp->enc;

    keybytes = enc->keybytes;
    keylength = enc->keylength;

    /* Allocate and set up buffers. */
    r1 = k5alloc(keybytes, &ret);
    if (ret)
        goto cleanup;
    r2 = k5alloc(keybytes, &ret);
    if (ret)
        goto cleanup;
    rnd = k5alloc(keybytes, &ret);
    if (ret)
        goto cleanup;
    combined = k5alloc(keybytes * 2, &ret);
    if (ret)
        goto cleanup;
    output = k5alloc(keylength, &ret);
    if (ret)
        goto cleanup;

    /*
     * Get R1 and R2 (by running the input keys through the DR algorithm.
     * Note this is most of derive-key, but not all.
     */

    input.length = key2->length;
    input.data = (char *) key2->contents;
    ret = dr(enc, key1, r1, &input);
    if (ret)
        goto cleanup;

    input.length = key1->length;
    input.data = (char *) key1->contents;
    ret = dr(enc, key2, r2, &input);
    if (ret)
        goto cleanup;

    /*
     * Concatenate the two keys together, and then run them through
     * n-fold to reduce them to a length appropriate for the random-to-key
     * operation.  Note here that krb5int_nfold() takes sizes in bits, hence
     * the multiply by 8.
     */

    memcpy(combined, r1, keybytes);
    memcpy(combined + keybytes, r2, keybytes);

    krb5int_nfold((keybytes * 2) * 8, combined, keybytes * 8, rnd);

    /*
     * Run the "random" bits through random-to-key to produce a encryption
     * key.
     */

    randbits.length = keybytes;
    randbits.data = (char *) rnd;
    tkeyblock.length = keylength;
    tkeyblock.contents = output;

    ret = (*ktp->rand2key)(&randbits, &tkeyblock);
    if (ret)
        goto cleanup;

    ret = krb5_k_create_key(NULL, &tkeyblock, &tkey);
    if (ret)
        goto cleanup;

    /*
     * Run through derive-key one more time to produce the final key.
     * Note that the input to derive-key is the ASCII string "combine".
     */

    input.length = 7;
    input.data = "combine";

    /*
     * Just FYI: _if_ we have space here in the key, then simply use it
     * without modification.  But if the key is blank (no allocated storage)
     * then allocate some memory for it.  This allows programs to use one of
     * the existing keys as the output key, _or_ pass in a blank keyblock
     * for us to allocate.  It's easier for us to allocate it since we already
     * know the crypto library internals
     */

    if (outkey->length == 0 || outkey->contents == NULL) {
        outkey->contents = k5alloc(keylength, &ret);
        if (ret)
            goto cleanup;
        outkey->length = keylength;
        outkey->enctype = key1->enctype;
        myalloc = TRUE;
    }

    ret = krb5int_derive_keyblock(enc, tkey, outkey, &input, DERIVE_RFC3961);
    if (ret) {
        if (myalloc) {
            free(outkey->contents);
            outkey->contents = NULL;
        }
        goto cleanup;
    }

cleanup:
    zapfree(r1, keybytes);
    zapfree(r2, keybytes);
    zapfree(rnd, keybytes);
    zapfree(combined, keybytes * 2);
    zapfree(output, keylength);
    krb5_k_free_key(NULL, tkey);
    return ret;
}
Esempio n. 25
0
/*
 * Function to derive a new key from a given key and given constant data.
 */
static krb5_error_code
derive_key_lucid(const gss_krb5_lucid_key_t *in, gss_krb5_lucid_key_t *out,
		 int usage, char extra)
{
	krb5_error_code code;
	unsigned char constant_data[K5CLENGTH];
	krb5_data datain;
	int keylength __attribute__ ((unused));
#ifdef HAVE_KRB5
	void *enc;
#endif
	krb5_keyblock kin;  /* must send krb5_keyblock, not lucid! */
#if defined(HAVE_HEIMDAL) || HAVE_KRB5INT_DERIVE_KEY
	krb5_context kcontext;
	krb5_keyblock *outkey;
#else
	krb5_keyblock kout;
#endif
#if HAVE_KRB5INT_DERIVE_KEY
	krb5_key key_in, key_out;
#endif

	/*
	 * XXX Hack alert.  We don't have "legal" access to these
	 * values and structures located in libk5crypto
	 */
	switch (in->type) {
	case ENCTYPE_DES3_CBC_SHA1:
#ifdef HAVE_KRB5
	case ENCTYPE_DES3_CBC_RAW:
#endif
		keylength = 24;
#ifdef HAVE_KRB5
		enc = &krb5int_enc_des3;
#endif
		break;
	case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
		keylength = 16;
#ifdef HAVE_KRB5
		enc = &krb5int_enc_aes128;
#endif
		break;
	case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
		keylength = 32;
#ifdef HAVE_KRB5
		enc = &krb5int_enc_aes256;
#endif
		break;
	default:
		code = KRB5_BAD_ENCTYPE;
		goto out;
	}

	/* Convert to correct format for call to krb5_derive_key */
	key_lucid_to_krb5(in, &kin);

	datain.data = (char *) constant_data;
	datain.length = K5CLENGTH;

	((char *)(datain.data))[0] = (usage>>24)&0xff;
	((char *)(datain.data))[1] = (usage>>16)&0xff;
	((char *)(datain.data))[2] = (usage>>8)&0xff;
	((char *)(datain.data))[3] = usage&0xff;

	((char *)(datain.data))[4] = (char) extra;

	/* Step 1: Init context */
	/* Heimdal and newer MIT Kerberos require kcontext */
#if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
	code = krb5_init_context(&kcontext);
	if (code)
		goto out;
#endif

	/* Step 2: Get the derived key */
#ifdef HAVE_KRB5
#if HAVE_KRB5INT_DERIVE_KEY
	code = krb5_k_create_key(kcontext, &kin, &key_in);
	if (code)
		goto out;

	code = ll_krb5int_derive_key(enc, key_in, &key_out, &datain,
				     DERIVE_RFC3961);

	krb5_k_free_key(kcontext, key_in);
	if (code == 0) {
		krb5_k_key_keyblock(kcontext, key_out, &outkey);
		krb5_k_free_key(kcontext, key_out);
	}
#else  /* !HAVE_KRB5INT_DERIVE_KEY */
	out->length = keylength;
	out->type = in->type;

	key_lucid_to_krb5(out, &kout);

	code = krb5_derive_key(enc, &kin, &kout, &datain);
#endif	/* HAVE_KRB5INT_DERIVE_KEY */
#else	/* !defined(HAVE_KRB5) */
	code = krb5_derive_key(kcontext, &kin, in->type, constant_data, K5CLENGTH, &outkey);
#endif	/* defined(HAVE_KRB5) */

	if (code)
		goto out;

	/* Step 3: Copy the key to out */
#if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
	code = key_krb5_to_lucid(outkey, out);
	krb5_free_keyblock(kcontext, outkey);
#else	/* !defined(HAVE_KRB5) */
	code = key_krb5_to_lucid(&kout, out);
#endif	/* defined(HAVE_KRB5) */

	/* Step 4: Free the context */
#if defined(HAVE_KRB5INT_DERIVE_KEY) || defined(HAVE_HEIMDAL)
	krb5_free_context(kcontext);
#endif

  out:
	if (code)
		printerr(0, "ERROR: %s: returning error %d (%s)\n",
			 __FUNCTION__, code, error_message(code));
	return (code);
}