make fast work with mit kerberos

This commit is contained in:
Love Hornquist Astrand
2013-07-16 15:31:30 +02:00
parent ad74581850
commit f49339f31b

View File

@@ -34,6 +34,7 @@
*/
#include "krb5_locl.h"
#include <heim-ipc.h>
typedef struct krb5_get_init_creds_ctx {
KDCOptions flags;
@@ -87,10 +88,13 @@ typedef struct krb5_get_init_creds_ctx {
#define KRB5_FAST_EXPECTED 32 /* in exchange with KDC, fast was discovered */
#define KRB5_FAST_REQUIRED 64 /* fast required by action of caller */
#define KRB5_FAST_DISABLED 128
#define KRB5_FAST_AP_ARMOR_SERVICE 256
krb5_keyblock *reply_key;
krb5_ccache armor_ccache;
krb5_principal armor_service;
krb5_crypto armor_crypto;
krb5_keyblock armor_key;
krb5_keyblock *strengthen_key;
} fast_state;
} krb5_get_init_creds_ctx;
@@ -160,8 +164,14 @@ free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
* to destroy it, and how would we know? also, the caller should
* take care of cleaning up the armor_ccache).
*/
if (ctx->fast_state.armor_ccache)
krb5_cc_close(context, ctx->fast_state.armor_ccache);
if (ctx->fast_state.armor_service)
krb5_free_principal(context, ctx->fast_state.armor_service);
if (ctx->fast_state.armor_crypto)
krb5_crypto_destroy(context, ctx->fast_state.armor_crypto);
if (ctx->fast_state.strengthen_key)
krb5_free_keyblock(context, ctx->fast_state.strengthen_key);
krb5_free_keyblock_contents(context, &ctx->fast_state.armor_key);
krb5_data_free(&ctx->req_buffer);
@@ -1651,6 +1661,26 @@ krb5_init_creds_set_fast_ccache(krb5_context context,
return 0;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_set_fast_ap_armor_service(krb5_context context,
krb5_init_creds_context ctx,
krb5_const_principal armor_service)
{
krb5_error_code ret;
if (ctx->fast_state.armor_service)
krb5_free_principal(context, ctx->fast_state.armor_service);
if (armor_service) {
ret = krb5_copy_principal(context, armor_service, &ctx->fast_state.armor_service);
if (ret)
return ret;
} else {
ctx->fast_state.armor_service = NULL;
}
ctx->fast_state.flags |= KRB5_FAST_REQUIRED | KRB5_FAST_AP_ARMOR_SERVICE;
return 0;
}
/*
* FAST
*/
@@ -1722,20 +1752,12 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce,
goto out;
if (fastrep.strengthen_key) {
krb5_keyblock result;
if (state->strengthen_key)
krb5_free_keyblock(context, state->strengthen_key);
ret = _krb5_fast_cf2(context,
fastrep.strengthen_key,
"strengthenkey",
state->reply_key,
"replykey",
&result,
NULL);
ret = krb5_copy_keyblock(context, fastrep.strengthen_key, &state->strengthen_key);
if (ret)
goto out;
krb5_free_keyblock_contents(context, state->reply_key);
*state->reply_key = result;
}
if (nonce != fastrep.nonce) {
@@ -1796,12 +1818,13 @@ fast_unwrap_error(krb5_context context, struct fast_state *state, KRB_ERROR *err
return 0;
}
static krb5_error_code
make_fast_ap_fxarmor(krb5_context context,
struct fast_state *state,
KrbFastArmor **armor)
krb5_error_code
_krb5_make_fast_ap_fxarmor(krb5_context context,
krb5_ccache armor_ccache,
krb5_data *armor_value,
krb5_keyblock *armor_key,
krb5_crypto *armor_crypto)
{
KrbFastArmor *fxarmor = NULL;
krb5_auth_context auth_context = NULL;
krb5_creds cred, *credp = NULL;
krb5_error_code ret;
@@ -1809,21 +1832,13 @@ make_fast_ap_fxarmor(krb5_context context,
krb5_data_zero(&empty);
ALLOC(fxarmor, 1);
if (fxarmor == NULL) {
ret = ENOMEM;
goto out;
}
fxarmor->armor_type = 1;
memset(&cred, 0, sizeof(cred));
ret = krb5_auth_con_init (context, &auth_context);
if (ret)
goto out;
ret = krb5_cc_get_principal(context, state->armor_ccache, &cred.client);
ret = krb5_cc_get_principal(context, armor_ccache, &cred.client);
if (ret)
goto out;
@@ -1837,7 +1852,7 @@ make_fast_ap_fxarmor(krb5_context context,
goto out;
}
ret = krb5_get_credentials(context, 0, state->armor_ccache, &cred, &credp);
ret = krb5_get_credentials(context, 0, armor_ccache, &cred, &credp);
krb5_free_principal(context, cred.server);
krb5_free_principal(context, cred.client);
if (ret)
@@ -1852,32 +1867,120 @@ make_fast_ap_fxarmor(krb5_context context,
AP_OPTS_USE_SUBKEY,
NULL,
credp,
&fxarmor->armor_value);
armor_value);
krb5_free_creds(context, credp);
if (ret)
goto out;
ret = _krb5_fast_armor_key(context,
auth_context->local_subkey,
auth_context->keyblock,
armor_key,
armor_crypto);
if (ret)
goto out;
out:
return ret;
}
static heim_base_once_t armor_service_once = HEIM_BASE_ONCE_INIT;
static heim_ipc armor_service = NULL;
static void
fast_armor_init_ipc(void *ctx)
{
heim_ipc *ipc = ctx;
heim_ipc_init_context("ANY:org.h5l.armor-service", ipc);
}
static krb5_error_code
make_fast_ap_fxarmor(krb5_context context,
struct fast_state *state,
const char *realm,
KrbFastArmor **armor)
{
KrbFastArmor *fxarmor = NULL;
krb5_error_code ret;
if (state->armor_crypto)
krb5_crypto_destroy(context, state->armor_crypto);
krb5_free_keyblock_contents(context, &state->armor_key);
ret = _krb5_fast_armor_key(context,
auth_context->local_subkey,
auth_context->keyblock,
&state->armor_key,
&state->armor_crypto);
if (ret)
ALLOC(fxarmor, 1);
if (fxarmor == NULL) {
ret = ENOMEM;
goto out;
}
if (state->flags & KRB5_FAST_AP_ARMOR_SERVICE) {
KERB_ARMOR_SERVICE_REPLY msg;
krb5_data request, reply;
heim_base_once_f(&armor_service_once, &armor_service, fast_armor_init_ipc);
if (armor_service == NULL) {
krb5_set_error_message(context, ENOENT, "Failed to open fast armor service");
return ENOENT;
}
krb5_data_zero(&reply);
request.data = rk_UNCONST(realm);
request.length = strlen(realm);
ret = heim_ipc_call(armor_service, &request, &reply, NULL);
heim_release(send);
if (ret) {
krb5_set_error_message(context, ret, "Failed to get armor service credential");
return ret;
}
ret = decode_KERB_ARMOR_SERVICE_REPLY(reply.data, reply.length, &msg, NULL);
krb5_data_free(&reply);
if (ret)
goto out;
ret = copy_KrbFastArmor(fxarmor, &msg.armor);
if (ret) {
free_KERB_ARMOR_SERVICE_REPLY(&msg);
goto out;
}
ret = krb5_copy_keyblock_contents(context, &msg.armor_key, &state->armor_key);
free_KERB_ARMOR_SERVICE_REPLY(&msg);
if (ret)
goto out;
ret = krb5_crypto_init(context, &state->armor_key, 0, &state->armor_crypto);
if (ret)
goto out;
} else {
fxarmor->armor_type = 1;
ret = _krb5_make_fast_ap_fxarmor(context,
state->armor_ccache,
&fxarmor->armor_value,
&state->armor_key,
&state->armor_crypto);
if (ret)
goto out;
}
*armor = fxarmor;
fxarmor = NULL;
out:
if (fxarmor)
if (fxarmor) {
free_KrbFastArmor(fxarmor);
free(fxarmor);
}
return ret;
}
static krb5_error_code
fast_wrap_req(krb5_context context, struct fast_state *state, KDC_REQ *req)
{
@@ -1925,6 +2028,8 @@ fast_wrap_req(krb5_context context, struct fast_state *state, KDC_REQ *req)
req->req_body.cname->name_string.len = 2;
req->req_body.cname->name_string.val[0] = strdup(KRB5_WELLKNOWN_NAME);
req->req_body.cname->name_string.val[1] = strdup(KRB5_ANON_NAME);
ALLOC(req->req_body.till, 1);
*req->req_body.till = 0;
if (req->padata) {
ret = copy_METHOD_DATA(req->padata, &fastreq.padata);
@@ -1945,7 +2050,7 @@ fast_wrap_req(krb5_context context, struct fast_state *state, KDC_REQ *req)
size_t len;
void *buf;
ret = make_fast_ap_fxarmor(context, state, &fxreq.u.armored_data.armor);
ret = make_fast_ap_fxarmor(context, state, fastreq.req_body.realm, &fxreq.u.armored_data.armor);
if (ret)
goto out;