Beispiel #1
0
/*
 * Normally defined in lib/gssapi/krb5/delete_sec_context.c; this version
 * is tailored for imported lucid contexts and has fewer dependencies.
 * Does not handle output tokens.
 */
OM_uint32
krb5_gss_delete_sec_context(OM_uint32 *minor_status,
                            gss_ctx_id_t *context_handle,
                            gss_buffer_t output_token)
{
    krb5_gss_ctx_id_t ctx;

    if (output_token) {
        *minor_status = EINVAL;
        return GSS_S_FAILURE;
    }

    *minor_status = 0;
    if (*context_handle == GSS_C_NO_CONTEXT)
        return GSS_S_COMPLETE;

    ctx = (krb5_gss_ctx_id_t)*context_handle;
    g_seqstate_free(ctx->seqstate);
    krb5_k_free_key(NULL, ctx->enc);
    krb5_k_free_key(NULL, ctx->seq);
    krb5_k_free_key(NULL, ctx->subkey);
    krb5_k_free_key(NULL, ctx->acceptor_subkey);
    memset(ctx, 0, sizeof(*ctx));
    free(ctx);
    *context_handle = GSS_C_NO_CONTEXT;
    return GSS_S_COMPLETE;
}
Beispiel #2
0
krb5_error_code KRB5_CALLCONV
krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
{
    if (auth_context == NULL)
        return 0;
    if (auth_context->local_addr)
        krb5_free_address(context, auth_context->local_addr);
    if (auth_context->remote_addr)
        krb5_free_address(context, auth_context->remote_addr);
    if (auth_context->local_port)
        krb5_free_address(context, auth_context->local_port);
    if (auth_context->remote_port)
        krb5_free_address(context, auth_context->remote_port);
    if (auth_context->authentp)
        krb5_free_authenticator(context, auth_context->authentp);
    if (auth_context->key)
        krb5_k_free_key(context, auth_context->key);
    if (auth_context->send_subkey)
        krb5_k_free_key(context, auth_context->send_subkey);
    if (auth_context->recv_subkey)
        krb5_k_free_key(context, auth_context->recv_subkey);
    if (auth_context->rcache)
        krb5_rc_close(context, auth_context->rcache);
    if (auth_context->permitted_etypes)
        free(auth_context->permitted_etypes);
    if (auth_context->ad_context)
        krb5_authdata_context_free(context, auth_context->ad_context);
    free(auth_context);
    return 0;
}
Beispiel #3
0
krb5_error_code
krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp, krb5_key key,
			krb5_keyusage usage, const krb5_data *ivec,
			krb5_crypto_iov *data, size_t num_data)
{
    const struct krb5_enc_provider *enc = ktp->enc;
    krb5_error_code ret;
    krb5_crypto_iov *header, *trailer, *padding;
    krb5_data cksum = empty_data();
    krb5_key ke = NULL, ki = NULL;

    /* E(Confounder | Plaintext | Pad) | Checksum */

    /* Validate header and trailer lengths, and zero out padding length. */
    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
    if (header == NULL || header->data.length < enc->block_size)
        return KRB5_BAD_MSIZE;
    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
    if (trailer == NULL || trailer->data.length < enc->block_size)
        return KRB5_BAD_MSIZE;
    padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
    if (padding != NULL)
	padding->data.length = 0;

    /* Derive the encryption and integrity keys. */
    ret = derive_keys(enc, key, usage, &ke, &ki);
    if (ret != 0)
        goto cleanup;

    /* Generate confounder. */
    header->data.length = enc->block_size;
    ret = krb5_c_random_make_octets(NULL, &header->data);
    if (ret != 0)
        goto cleanup;

    /* Checksum the plaintext. */
    ret = krb5int_cmac_checksum(enc, ki, data, num_data, &trailer->data);
    if (ret != 0)
        goto cleanup;

    /* Encrypt the plaintext (header | data | padding) */
    ret = enc->encrypt(ke, ivec, data, num_data);
    if (ret != 0)
        goto cleanup;

cleanup:
    krb5_k_free_key(NULL, ke);
    krb5_k_free_key(NULL, ki);
    zapfree(cksum.data, cksum.length);
    return ret;
}
Beispiel #4
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)));
}
Beispiel #5
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;
}
Beispiel #6
0
krb5_error_code
krb5int_dk_cmac_prf(const struct krb5_keytypes *ktp, krb5_key key,
                    const krb5_data *in, krb5_data *out)
{
    krb5_crypto_iov iov;
    krb5_data prfconst = make_data("prf", 3);
    krb5_key kp = NULL;
    krb5_error_code ret;

    if (ktp->prf_length != ktp->enc->block_size)
        return KRB5_BAD_MSIZE;

    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = *in;

    /* Derive a key using the PRF constant. */
    ret = krb5int_derive_key(ktp->enc, key, &kp, &prfconst,
                             DERIVE_SP800_108_CMAC);
    if (ret != 0)
        goto cleanup;

    /* PRF is CMAC of input */
    ret = krb5int_cmac_checksum(ktp->enc, kp, &iov, 1, out);
    if (ret != 0)
        goto cleanup;

cleanup:
    krb5_k_free_key(NULL, kp);
    return ret;
}
Beispiel #7
0
krb5_error_code
krb5int_dk_cmac_decrypt(const struct krb5_keytypes *ktp, krb5_key key,
                        krb5_keyusage usage, const krb5_data *ivec,
                        krb5_crypto_iov *data, size_t num_data)
{
    const struct krb5_enc_provider *enc = ktp->enc;
    krb5_error_code ret;
    krb5_crypto_iov *header, *trailer;
    krb5_data cksum = empty_data();
    krb5_key ke = NULL, ki = NULL;

    /* E(Confounder | Plaintext | Pad) | Checksum */

    /* Validate header and trailer lengths. */
    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
    if (header == NULL || header->data.length != enc->block_size)
        return KRB5_BAD_MSIZE;
    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
    if (trailer == NULL || trailer->data.length != enc->block_size)
        return KRB5_BAD_MSIZE;

    /* Derive the encryption and integrity keys. */
    ret = derive_keys(enc, key, usage, &ke, &ki);
    if (ret != 0)
        goto cleanup;

    /* Decrypt the plaintext (header | data | padding). */
    ret = enc->decrypt(ke, ivec, data, num_data);
    if (ret != 0)
        goto cleanup;

    /* Verify the hash. */
    ret = alloc_data(&cksum, enc->block_size);
    if (ret != 0)
        goto cleanup;
    ret = krb5int_cmac_checksum(enc, ki, data, num_data, &cksum);
    if (ret != 0)
        goto cleanup;
    if (k5_bcmp(cksum.data, trailer->data.data, enc->block_size) != 0)
        ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;

cleanup:
    krb5_k_free_key(NULL, ke);
    krb5_k_free_key(NULL, ki);
    zapfree(cksum.data, cksum.length);
    return ret;
}
Beispiel #8
0
krb5_error_code KRB5_CALLCONV
krb5_auth_con_setrecvsubkey_k(krb5_context ctx, krb5_auth_context ac,
                              krb5_key key)
{
    krb5_k_free_key(ctx, ac->recv_subkey);
    ac->recv_subkey = key;
    krb5_k_reference_key(ctx, key);
    return 0;
}
Beispiel #9
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;
}
Beispiel #10
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;
}
Beispiel #11
0
krb5_error_code krb5int_confounder_verify(const struct krb5_cksumtypes *ctp,
                                          krb5_key key, krb5_keyusage usage,
                                          const krb5_crypto_iov *data,
                                          size_t num_data,
                                          const krb5_data *input,
                                          krb5_boolean *valid)
{
    krb5_error_code ret;
    unsigned char *plaintext = NULL;
    krb5_key xorkey = NULL;
    krb5_data computed = empty_data();
    krb5_crypto_iov *hash_iov = NULL, iov;
    size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize;

    plaintext = k5memdup(input->data, input->length, &ret);
    if (plaintext == NULL)
        return ret;

    ret = mk_xorkey(key, &xorkey);
    if (ret != 0)
        goto cleanup;

    /* Decrypt the input checksum. */
    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = make_data(plaintext, input->length);
    ret = ctp->enc->decrypt(xorkey, NULL, &iov, 1);
    if (ret != 0)
        goto cleanup;

    /* Hash the confounder, then the input data. */
    hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret);
    if (hash_iov == NULL)
        goto cleanup;
    hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
    hash_iov[0].data = make_data(plaintext, blocksize);
    memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov));
    ret = alloc_data(&computed, hashsize);
    if (ret != 0)
        goto cleanup;
    ret = ctp->hash->hash(hash_iov, num_data + 1, &computed);
    if (ret != 0)
        goto cleanup;

    /* Compare the decrypted hash to the computed one. */
    *valid = (memcmp(plaintext + blocksize, computed.data, hashsize) == 0);

cleanup:
    zapfree(plaintext, input->length);
    zapfree(computed.data, hashsize);
    free(hash_iov);
    krb5_k_free_key(NULL, xorkey);
    return ret;
}
Beispiel #12
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);
}
Beispiel #13
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;
}
Beispiel #14
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;
}
Beispiel #15
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;
}
Beispiel #16
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;
}
Beispiel #17
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;
}
Beispiel #18
0
krb5_error_code
krb5int_confounder_checksum(const struct krb5_cksumtypes *ctp,
                            krb5_key key, krb5_keyusage usage,
                            const krb5_crypto_iov *data, size_t num_data,
                            krb5_data *output)
{
    krb5_error_code ret;
    krb5_data conf, hashval;
    krb5_key xorkey = NULL;
    krb5_crypto_iov *hash_iov, iov;
    size_t blocksize = ctp->enc->block_size, hashsize = ctp->hash->hashsize;

    /* Partition the output buffer into confounder and hash. */
    conf = make_data(output->data, blocksize);
    hashval = make_data(output->data + blocksize, hashsize);

    /* Create the confounder. */
    ret = krb5_c_random_make_octets(NULL, &conf);
    if (ret != 0)
        return ret;

    ret = mk_xorkey(key, &xorkey);
    if (ret)
        return ret;

    /* Hash the confounder, then the input data. */
    hash_iov = k5alloc((num_data + 1) * sizeof(krb5_crypto_iov), &ret);
    if (hash_iov == NULL)
        goto cleanup;
    hash_iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
    hash_iov[0].data = conf;
    memcpy(hash_iov + 1, data, num_data * sizeof(krb5_crypto_iov));
    ret = ctp->hash->hash(hash_iov, num_data + 1, &hashval);
    if (ret != 0)
        goto cleanup;

    /* Confounder and hash are in output buffer; encrypt them in place. */
    iov.flags = KRB5_CRYPTO_TYPE_DATA;
    iov.data = *output;
    ret = ctp->enc->encrypt(xorkey, NULL, &iov, 1);

cleanup:
    free(hash_iov);
    krb5_k_free_key(NULL, xorkey);
    return ret;
}
Beispiel #19
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;
}
Beispiel #20
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;
}
Beispiel #21
0
/* Decode a reply to produce the clear-text output. */
static krb5_error_code
get_clear_result(krb5_context context, krb5_auth_context auth_context,
                 const krb5_data *packet, krb5_data **clear_out,
                 krb5_boolean *is_error_out)
{
    krb5_error_code ret;
    char *ptr, *end = packet->data + packet->length;
    unsigned int plen, vno, aplen;
    krb5_data ap_rep, cipher, error;
    krb5_ap_rep_enc_part *ap_rep_enc;
    krb5_replay_data replay;
    krb5_key send_subkey = NULL;
    krb5_data clear = empty_data();

    *clear_out = NULL;
    *is_error_out = FALSE;

    /* Check for an unframed KRB-ERROR (expected for RFC 3244 requests; also
     * received from MS AD for version 1 requests). */
    if (krb5_is_krb_error(packet)) {
        *is_error_out = TRUE;
        return get_error_edata(context, packet, clear_out);
    }

    if (packet->length < 6)
        return KRB5KRB_AP_ERR_MODIFIED;

    /* Decode and verify the length. */
    ptr = packet->data;
    plen = (*ptr++ & 0xff);
    plen = (plen << 8) | (*ptr++ & 0xff);
    if (plen != packet->length)
        return KRB5KRB_AP_ERR_MODIFIED;

    /* Decode and verify the version number. */
    vno = (*ptr++ & 0xff);
    vno = (vno << 8) | (*ptr++ & 0xff);
    if (vno != 1 && vno != 0xff80)
        return KRB5KDC_ERR_BAD_PVNO;

    /* Decode and check the AP-REP length. */
    aplen = (*ptr++ & 0xff);
    aplen = (aplen << 8) | (*ptr++ & 0xff);
    if (aplen > end - ptr)
        return KRB5KRB_AP_ERR_MODIFIED;

    /* A zero-length AP-REQ indicates a framed KRB-ERROR response.  (Expected
     * for protocol version 1; specified but unusual for RFC 3244 requests.) */
    if (aplen == 0) {
        *is_error_out = TRUE;
        error = make_data(ptr, end - ptr);
        return get_error_edata(context, &error, clear_out);
    }

    /* We have an AP-REP.  Save send_subkey to later smash recv_subkey. */
    ret = krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
    if (ret)
        return ret;

    /* Verify the AP-REP. */
    ap_rep = make_data(ptr, aplen);
    ptr += ap_rep.length;
    ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
    if (ret)
        goto cleanup;
    krb5_free_ap_rep_enc_part(context, ap_rep_enc);

    /* Smash recv_subkey to be send_subkey, per spec. */
    ret = krb5_auth_con_setrecvsubkey_k(context, auth_context, send_subkey);
    if (ret)
        goto cleanup;

    /* Extract and decrypt the result. */
    cipher = make_data(ptr, end - ptr);
    ret = krb5_rd_priv(context, auth_context, &cipher, &clear, &replay);
    if (ret)
        goto cleanup;

    ret = krb5_copy_data(context, &clear, clear_out);
    if (ret)
        goto cleanup;
    *is_error_out = FALSE;

cleanup:
    krb5_k_free_key(context, send_subkey);
    krb5_free_data_contents(context, &clear);
    return ret;
}
Beispiel #22
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;
}
Beispiel #23
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;
}
Beispiel #24
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;
}
Beispiel #25
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;
}
Beispiel #26
0
Datei: t_cts.c Projekt: 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);
}
Beispiel #27
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;
}
Beispiel #28
0
/* Import a lucid context structure, creating a krb5 GSS context structure
 * sufficient for use by by wrap/unwrap/get_mic/verify_mic operations. */
static krb5_error_code
import_lucid_sec_context_v1(const gss_krb5_lucid_context_v1_t *lctx,
                            gss_ctx_id_t *context_handle_out)
{
    krb5_error_code ret;
    krb5_gss_ctx_id_t gctx;
    OM_uint32 tmpmin;
    krb5_key key = NULL;

    gctx = k5alloc(sizeof(*gctx), &ret);
    if (gctx == NULL)
        return ret;

    gctx->initiate = lctx->initiate;
    gctx->krb_times.endtime = lctx->endtime;
    gctx->seq_send = lctx->send_seq;
    gctx->seq_recv = lctx->recv_seq;
    gctx->proto = lctx->protocol;
    if (lctx->protocol == 0) {
        /* Ignore sign_alg and seal_alg since they follow from the enctype. */
        ret = lkey_to_key(&lctx->rfc1964_kd.ctx_key, &key);
        if (ret)
            goto cleanup;
        /* For raw enctypes, choose an enctype expected by kg_setup_keys. */
        if (key->keyblock.enctype == ENCTYPE_DES_CBC_RAW)
            key->keyblock.enctype = ENCTYPE_DES_CBC_CRC;
        else if (key->keyblock.enctype == ENCTYPE_DES3_CBC_RAW)
            key->keyblock.enctype = ENCTYPE_DES3_CBC_SHA1;
        ret = kg_setup_keys(NULL, gctx, key, &gctx->cksumtype);
        if (ret)
            goto cleanup;
        if (gctx->proto != 0) { /* ctx_key did not have a pre-CFX enctype. */
            ret = EINVAL;
            goto cleanup;
        }
    } else if (lctx->protocol == 1) {
        ret = lkey_to_key(&lctx->cfx_kd.ctx_key, &gctx->subkey);
        if (ret)
            goto cleanup;
        ret = get_cksumtype(gctx->subkey, &gctx->cksumtype);
        if (ret)
            goto cleanup;
        if (lctx->cfx_kd.have_acceptor_subkey) {
            gctx->have_acceptor_subkey = 1;
            ret = lkey_to_key(&lctx->cfx_kd.acceptor_subkey,
                              &gctx->acceptor_subkey);
            if (ret)
                goto cleanup;
            ret = get_cksumtype(gctx->acceptor_subkey,
                                &gctx->acceptor_subkey_cksumtype);
            if (ret)
                goto cleanup;
        }
    }

    gctx->seed_init = 0;
    gctx->established = 1;
    gctx->mech_used = (gss_OID_desc *)gss_mech_krb5;

    /*
     * The lucid context doesn't convey the gss_flags which indicate whether
     * the protocol needs replay or sequence protection.  Assume we don't
     * (because RPCSEC_GSS doesn't).
     */
    g_seqstate_init(&gctx->seqstate, gctx->seq_recv, 0, 0, gctx->proto);

    *context_handle_out = (gss_ctx_id_t)gctx;
    gctx = NULL;

cleanup:
    krb5_k_free_key(NULL, key);
    krb5_gss_delete_sec_context(&tmpmin, (gss_ctx_id_t *)&gctx, NULL);
    return ret;
}
Beispiel #29
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;
}
Beispiel #30
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;
}