merge support for FAST in as-req codepath

This commit is contained in:
Love Hörnquist Åstrand
2011-10-28 19:25:48 -07:00
31 changed files with 6112 additions and 1212 deletions

View File

@@ -888,7 +888,7 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ
fprintf(headerfile, "heim_octet_string _save;\n");
}
space(level + 1);
fprintf (headerfile, "enum {\n");
fprintf (headerfile, "enum %s_enum {\n", newbasename);
m = have_ellipsis(t);
if (m) {
space(level + 2);

View File

@@ -63,6 +63,8 @@ EXPORTS
PA-ServerReferralData,
PA-SvrReferralData,
PADATA-TYPE,
PA-FX-FAST-REQUEST,
PA-FX-FAST-REPLY,
Principal,
PrincipalName,
Principals,
@@ -72,7 +74,13 @@ EXPORTS
Ticket,
TicketFlags,
TransitedEncoding,
TypedData
TypedData,
KrbFastResponse,
KrbFastFinished,
KrbFastReq,
KrbFastArmor,
KDCFastState,
KDCFastCookie
;
NAME-TYPE ::= INTEGER {
@@ -771,12 +779,12 @@ PA-ServerReferralData ::= SEQUENCE {
FastOptions ::= BIT STRING {
reserved(0),
hide-client-names(1),
kdc-follow--referrals(16)
kdc-follow-referrals(16)
}
KrbFastReq ::= SEQUENCE {
fast-options [0] FastOptions,
padata [1] SEQUENCE OF PA-DATA,
padata [1] METHOD-DATA,
req-body [2] KDC-REQ-BODY,
...
}
@@ -803,15 +811,15 @@ KrbFastFinished ::= SEQUENCE {
usec [1] krb5int32,
crealm [2] Realm,
cname [3] PrincipalName,
checksum [4] Checksum,
ticket-checksum [5] Checksum,
ticket-checksum [4] Checksum,
...
}
KrbFastResponse ::= SEQUENCE {
padata [0] SEQUENCE OF PA-DATA,
rep-key [1] EncryptionKey OPTIONAL,
finished [2] KrbFastFinished OPTIONAL,
padata [0] METHOD-DATA,
strengthen-key [1] EncryptionKey OPTIONAL,
finished [2] KrbFastFinished OPTIONAL,
nonce [3] krb5uint32,
...
}
@@ -825,6 +833,26 @@ PA-FX-FAST-REPLY ::= CHOICE {
...
}
KDCFastFlags ::= BIT STRING {
use_reply_key(0),
reply_key_used(1),
reply_key_replaced(2),
kdc_verfied(3)
}
-- KDCFastState is stored in FX_COOKIE
KDCFastState ::= SEQUENCE {
flags [0] KDCFastFlags,
expiration [1] GeneralizedTime,
fast-state [2] METHOD-DATA,
expected-pa-types [3] SEQUENCE OF PADATA-TYPE OPTIONAL
}
KDCFastCookie ::= SEQUENCE {
version [0] UTF8String,
cookie [1] EncryptedData
}
END
-- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1

View File

@@ -147,6 +147,7 @@ dist_libkrb5_la_SOURCES = \
error_string.c \
expand_hostname.c \
expand_path.c \
fast.c \
fcache.c \
free.c \
free_host_realm.c \

View File

@@ -64,7 +64,7 @@ struct _krb5_checksum_type _krb5_checksum_none = {
"none",
1,
0,
0,
F_DISABLED,
NONE_checksum,
NULL
};

95
lib/krb5/fast.c Normal file
View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2011 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "krb5_locl.h"
krb5_error_code
_krb5_fast_cf2(krb5_context context,
krb5_keyblock *key1,
const char *pepper1,
krb5_keyblock *key2,
const char *pepper2,
krb5_keyblock *armorkey,
krb5_crypto *armor_crypto)
{
krb5_crypto crypto1, crypto2;
krb5_data pa1, pa2;
krb5_error_code ret;
ret = krb5_crypto_init(context, key1, 0, &crypto1);
if (ret)
return ret;
ret = krb5_crypto_init(context, key2, 0, &crypto2);
if (ret) {
krb5_crypto_destroy(context, crypto1);
return ret;
}
pa1.data = rk_UNCONST(pepper1);
pa1.length = strlen(pepper1);
pa2.data = rk_UNCONST(pepper2);
pa2.length = strlen(pepper2);
ret = krb5_crypto_fx_cf2(context, crypto1, crypto2, &pa1, &pa2,
key1->keytype, armorkey);
krb5_crypto_destroy(context, crypto1);
krb5_crypto_destroy(context, crypto2);
if (ret)
return ret;
if (armor_crypto) {
ret = krb5_crypto_init(context, armorkey, 0, armor_crypto);
if (ret)
krb5_free_keyblock_contents(context, armorkey);
}
return ret;
}
krb5_error_code
_krb5_fast_armor_key(krb5_context context,
krb5_keyblock *subkey,
krb5_keyblock *sessionkey,
krb5_keyblock *armorkey,
krb5_crypto *armor_crypto)
{
return _krb5_fast_cf2(context,
subkey,
"subkeyarmor",
sessionkey,
"ticketarmor",
armorkey,
armor_crypto);
}

View File

@@ -544,6 +544,7 @@ get_cred_kdc(krb5_context context,
&krbtgt->addresses,
nonce,
eflags,
NULL,
decrypt_tkt_with_subkey,
subkey);
out2:

View File

@@ -510,6 +510,7 @@ krb5_get_in_cred(krb5_context context,
NULL,
nonce,
flags,
NULL,
decrypt_proc,
decryptarg);
}

View File

@@ -76,7 +76,20 @@ typedef struct krb5_get_init_creds_ctx {
void *prompter_data;
struct pa_info_data *ppaid;
struct fast_state {
enum PA_FX_FAST_REQUEST_enum type;
unsigned int flags;
#define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 1
#define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 2
#define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4
#define KRB5_FAST_REPLY_REPLY_VERIFED 8
#define KRB5_FAST_STRONG 16
#define KRB5_FAST_EXPECTED 32
krb5_keyblock *reply_key;
krb5_ccache armor_ccache;
krb5_crypto armor_crypto;
krb5_keyblock armor_key;
} fast_state;
} krb5_get_init_creds_ctx;
@@ -140,6 +153,15 @@ free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
memset(ctx->password, 0, strlen(ctx->password));
free(ctx->password);
}
/*
* FAST state
*/
if (ctx->fast_state.armor_ccache)
krb5_cc_close(context, ctx->fast_state.armor_ccache);
if (ctx->fast_state.armor_crypto)
krb5_crypto_destroy(context, ctx->fast_state.armor_crypto);
krb5_free_keyblock_contents(context, &ctx->fast_state.armor_key);
krb5_data_free(&ctx->req_buffer);
krb5_free_cred_contents(context, &ctx->cred);
free_METHOD_DATA(&ctx->md);
@@ -251,10 +273,10 @@ report_expiration (krb5_context context,
* @param ctx The krb5_init_creds_context check for expiration.
*/
static krb5_error_code
process_last_request(krb5_context context,
krb5_get_init_creds_opt *options,
krb5_init_creds_context ctx)
krb5_error_code
krb5_process_last_request(krb5_context context,
krb5_get_init_creds_opt *options,
krb5_init_creds_context ctx)
{
krb5_const_realm realm;
LastReq *lr;
@@ -1237,6 +1259,10 @@ process_pa_data_to_md(krb5_context context,
pa_data_add_pac_request(context, ctx, *out_md);
ret = krb5_padata_add(context, *out_md, KRB5_PADATA_REQ_ENC_PA_REP, NULL, 0);
if (ret)
return ret;
if ((*out_md)->len == 0) {
free(*out_md);
*out_md = NULL;
@@ -1618,6 +1644,352 @@ krb5_init_creds_set_keyblock(krb5_context context,
return 0;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_init_creds_set_fast_ccache(krb5_context context,
krb5_init_creds_context ctx,
krb5_ccache fast_ccache)
{
ctx->fast_state.armor_ccache = fast_ccache;
return 0;
}
/*
* FAST
*/
static krb5_error_code
check_fast(krb5_context context, struct fast_state *state)
{
if (state->flags & KRB5_FAST_EXPECTED) {
krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
"Expected FAST, but no FAST "
"was in the response from the KDC");
return KRB5KRB_AP_ERR_MODIFIED;
}
return 0;
}
static krb5_error_code
fast_unwrap_as_rep(krb5_context context, int32_t nonce,
krb5_data *chksumdata,
struct fast_state *state, AS_REP *rep)
{
PA_FX_FAST_REPLY fxfastrep;
KrbFastResponse fastrep;
krb5_error_code ret;
PA_DATA *pa = NULL;
int idx = 0;
if (state->armor_crypto == NULL || rep->padata == NULL)
return check_fast(context, state);
/* find PA_FX_FAST_REPLY */
pa = krb5_find_padata(rep->padata->val, rep->padata->len,
KRB5_PADATA_FX_FAST, &idx);
if (pa == NULL)
return check_fast(context, state);
memset(&fxfastrep, 0, sizeof(fxfastrep));
memset(&fastrep, 0, sizeof(fastrep));
ret = decode_PA_FX_FAST_REPLY(pa->padata_value.data, pa->padata_value.length, &fxfastrep, NULL);
if (ret)
return ret;
if (fxfastrep.element == choice_PA_FX_FAST_REPLY_armored_data) {
krb5_data data;
ret = krb5_decrypt_EncryptedData(context,
state->armor_crypto,
KRB5_KU_FAST_REP,
&fxfastrep.u.armored_data.enc_fast_rep,
&data);
if (ret)
goto out;
ret = decode_KrbFastResponse(data.data, data.length, &fastrep, NULL);
krb5_data_free(&data);
if (ret)
goto out;
} else {
ret = KRB5KDC_ERR_PREAUTH_FAILED;
goto out;
}
free_METHOD_DATA(rep->padata);
ret = copy_METHOD_DATA(&fastrep.padata, rep->padata);
if (ret)
goto out;
if (fastrep.strengthen_key) {
krb5_keyblock result;
ret = _krb5_fast_cf2(context,
fastrep.strengthen_key,
"strengthenkey",
state->reply_key,
"replykey",
&result,
NULL);
if (ret)
goto out;
krb5_free_keyblock_contents(context, state->reply_key);
*state->reply_key = result;
}
if (nonce != fastrep.nonce) {
ret = KRB5KDC_ERR_PREAUTH_FAILED;
goto out;
}
if (fastrep.finished) {
PrincipalName cname;
krb5_realm crealm = NULL;
if (chksumdata == NULL) {
ret = KRB5KDC_ERR_PREAUTH_FAILED;
goto out;
}
ret = krb5_verify_checksum(context, state->armor_crypto,
KRB5_KU_FAST_FINISHED,
chksumdata->data, chksumdata->length,
&fastrep.finished->ticket_checksum);
if (ret)
goto out;
/* update */
ret = copy_Realm(&fastrep.finished->crealm, &crealm);
if (ret)
goto out;
free_Realm(&rep->crealm);
rep->crealm = crealm;
ret = copy_PrincipalName(&fastrep.finished->cname, &cname);
if (ret)
goto out;
free_PrincipalName(&rep->cname);
rep->cname = cname;
#if 0 /* store authenticated checksum as kdc-offset */
fastrep->finished.timestamp;
fastrep->finished.usec = 0;
#endif
} else if (chksumdata) {
/* expected fastrep.finish but didn't get it */
ret = KRB5KDC_ERR_PREAUTH_FAILED;
}
out:
free_PA_FX_FAST_REPLY(&fxfastrep);
return ret;
}
static krb5_error_code
fast_unwrap_error(krb5_context context, struct fast_state *state, KRB_ERROR *error)
{
if (state->armor_crypto == NULL)
return check_fast(context, state);
return 0;
}
static krb5_error_code
make_fast_ap_fxarmor(krb5_context context,
struct fast_state *state,
KrbFastArmor **armor)
{
KrbFastArmor *fxarmor = NULL;
krb5_auth_context auth_context = NULL;
krb5_creds cred, *credp = NULL;
krb5_error_code ret;
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);
if (ret)
goto out;
ret = krb5_make_principal(context, &cred.server,
cred.client->realm,
KRB5_TGS_NAME,
cred.client->realm,
NULL);
if (ret) {
krb5_free_principal(context, cred.client);
goto out;
}
ret = krb5_get_credentials(context, 0, state->armor_ccache, &cred, &credp);
krb5_free_principal(context, cred.server);
krb5_free_principal(context, cred.client);
if (ret)
goto out;
ret = krb5_mk_req_extended(context,
&auth_context,
AP_OPTS_USE_SUBKEY,
NULL,
credp,
&fxarmor->armor_value);
krb5_free_creds(context, credp);
if (ret)
goto out;
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)
goto out;
*armor = fxarmor;
fxarmor = NULL;
out:
if (fxarmor)
free_KrbFastArmor(fxarmor);
return ret;
}
static krb5_error_code
fast_wrap_req(krb5_context context, struct fast_state *state, KDC_REQ *req)
{
KrbFastArmor *fxarmor = NULL;
PA_FX_FAST_REQUEST fxreq;
krb5_error_code ret;
KrbFastReq fastreq;
krb5_data data;
size_t size;
memset(&fxreq, 0, sizeof(fxreq));
memset(&fastreq, 0, sizeof(fastreq));
krb5_data_zero(&data);
if (state->armor_crypto == NULL) {
if (state->armor_ccache) {
/*
* Instead of keeping state in FX_COOKIE in the KDC, we
* rebuild a new armor key for every request, because this
* is what the MIT KDC expect and RFC6113 is vage about
* what the behavior should be.
*/
state->type = choice_PA_FX_FAST_REQUEST_armored_data;
} else {
return check_fast(context, state);
}
}
state->flags |= KRB5_FAST_EXPECTED;
fastreq.fast_options.hide_client_names = 1;
ret = copy_KDC_REQ_BODY(&req->req_body, &fastreq.req_body);
free_KDC_REQ_BODY(&req->req_body);
req->req_body.realm = strdup(KRB5_ANON_REALM);
ALLOC(req->req_body.cname, 1);
req->req_body.cname->name_type = KRB5_NT_PRINCIPAL;
ALLOC(req->req_body.cname->name_string.val, 2);
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);
if (req->padata) {
ret = copy_METHOD_DATA(req->padata, &fastreq.padata);
free_METHOD_DATA(req->padata);
} else {
ALLOC(req->padata, 1);
}
ASN1_MALLOC_ENCODE(KrbFastReq, data.data, data.length, &fastreq, &size, ret);
if (ret)
goto out;
heim_assert(data.length == size, "ASN.1 internal error");
fxreq.element = state->type;
if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) {
size_t len;
void *buf;
ret = make_fast_ap_fxarmor(context, state, &fxreq.u.armored_data.armor);
if (ret)
goto out;
heim_assert(state->armor_crypto != NULL, "FAST armor key missing when FAST started");
ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret);
if (ret)
goto out;
heim_assert(len == size, "ASN.1 internal error");
ret = krb5_create_checksum(context, state->armor_crypto,
KRB5_KU_FAST_REQ_CHKSUM, 0,
buf, len,
&fxreq.u.armored_data.req_checksum);
free(buf);
if (ret)
goto out;
ret = krb5_encrypt_EncryptedData(context, state->armor_crypto,
KRB5_KU_FAST_ENC,
data.data,
data.length,
0,
&fxreq.u.armored_data.enc_fast_req);
krb5_data_free(&data);
} else {
krb5_data_free(&data);
heim_assert(false, "unknown FAST type, internal error");
}
ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST, data.data, data.length, &fxreq, &size, ret);
if (ret)
goto out;
heim_assert(data.length == size, "ASN.1 internal error");
ret = krb5_padata_add(context, req->padata, KRB5_PADATA_FX_FAST, data.data, data.length);
if (ret)
goto out;
krb5_data_zero(&data);
out:
free_PA_FX_FAST_REQUEST(&fxreq);
if (fxarmor) {
free_KrbFastArmor(fxarmor);
free(fxarmor);
}
krb5_data_free(&data);
return ret;
}
/**
* The core loop if krb5_get_init_creds() function family. Create the
* packets and have the caller send them off to the KDC.
@@ -1650,6 +2022,7 @@ krb5_init_creds_step(krb5_context context,
krb5_error_code ret;
size_t len = 0;
size_t size;
AS_REQ req2;
krb5_data_zero(out);
@@ -1684,8 +2057,27 @@ krb5_init_creds_step(krb5_context context,
ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size);
if (ret == 0) {
krb5_keyblock *key = NULL;
unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC;
krb5_data data;
/*
* Unwrap AS-REP
*/
ASN1_MALLOC_ENCODE(Ticket, data.data, data.length,
&rep.kdc_rep.ticket, &size, ret);
if (ret)
goto out;
heim_assert(data.length == size, "ASN.1 internal error");
ret = fast_unwrap_as_rep(context, ctx->nonce, &data,
&ctx->fast_state, &rep.kdc_rep);
krb5_data_free(&data);
if (ret)
goto out;
/*
* Now check and extract the ticket
*/
if (ctx->flags.canonicalize) {
eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
@@ -1695,7 +2087,8 @@ krb5_init_creds_step(krb5_context context,
eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
ret = process_pa_data_to_key(context, ctx, &ctx->cred,
&ctx->as_req, &rep.kdc_rep, hostinfo, &key);
&ctx->as_req, &rep.kdc_rep,
hostinfo, &ctx->fast_state.reply_key);
if (ret) {
free_AS_REP(&rep.kdc_rep);
goto out;
@@ -1706,21 +2099,22 @@ krb5_init_creds_step(krb5_context context,
ret = _krb5_extract_ticket(context,
&rep,
&ctx->cred,
key,
ctx->fast_state.reply_key,
NULL,
KRB5_KU_AS_REP_ENC_PART,
NULL,
ctx->nonce,
eflags,
&ctx->req_buffer,
NULL,
NULL);
krb5_free_keyblock(context, key);
*flags = 0;
if (ret == 0)
ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part);
krb5_free_keyblock(context, ctx->fast_state.reply_key);
ctx->fast_state.reply_key = NULL;
*flags = 0;
free_AS_REP(&rep.kdc_rep);
free_EncASRepPart(&rep.enc_part);
@@ -1741,6 +2135,17 @@ krb5_init_creds_step(krb5_context context,
goto out;
}
/*
* Unwrap KRB-ERROR
*/
ret = fast_unwrap_error(context, &ctx->fast_state, &ctx->error);
if (ret)
goto out;
/*
*
*/
ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred);
_krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d", ret);
@@ -1821,11 +2226,23 @@ krb5_init_creds_step(krb5_context context,
if (ret)
goto out;
/*
* Wrap with FAST
*/
copy_AS_REQ(&ctx->as_req, &req2);
ret = fast_wrap_req(context, &ctx->fast_state, &req2);
if (ret) {
free_AS_REQ(&req2);
goto out;
}
krb5_data_free(&ctx->req_buffer);
ASN1_MALLOC_ENCODE(AS_REQ,
ctx->req_buffer.data, ctx->req_buffer.length,
&ctx->as_req, &len, ret);
&req2, &len, ret);
free_AS_REQ(&req2);
if (ret)
goto out;
if(len != ctx->req_buffer.length)
@@ -1882,6 +2299,43 @@ krb5_init_creds_get_error(krb5_context context,
return ret;
}
/**
*
* @ingroup krb5_credential
*/
krb5_error_code
krb5_init_creds_store(krb5_context context,
krb5_init_creds_context ctx,
krb5_ccache id)
{
krb5_error_code ret;
if (ctx->cred.client == NULL) {
ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
krb5_set_error_message(context, ret, "init creds not completed yet");
return ret;
}
ret = krb5_cc_initialize(context, id, ctx->cred.client);
if (ret)
return ret;
ret = krb5_cc_store_cred(context, id, &ctx->cred);
if (ret)
return ret;
if (ctx->cred.flags.b.enc_pa_rep) {
krb5_data data = { 3, rk_UNCONST("yes") };
ret = krb5_cc_set_config(context, id, ctx->cred.server,
"fast_avail", &data);
if (ret)
return ret;
}
return ret;
}
/**
* Free the krb5_init_creds_context allocated by krb5_init_creds_init().
*
@@ -2016,7 +2470,7 @@ krb5_get_init_creds_password(krb5_context context,
ret = krb5_init_creds_get(context, ctx);
if (ret == 0)
process_last_request(context, options, ctx);
krb5_process_last_request(context, options, ctx);
if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
@@ -2091,7 +2545,7 @@ krb5_get_init_creds_keyblock(krb5_context context,
ret = krb5_init_creds_get(context, ctx);
if (ret == 0)
process_last_request(context, options, ctx);
krb5_process_last_request(context, options, ctx);
out:
if (ret == 0)
@@ -2137,7 +2591,7 @@ krb5_get_init_creds_keytab(krb5_context context,
ret = krb5_init_creds_get(context, ctx);
if (ret == 0)
process_last_request(context, options, ctx);
krb5_process_last_request(context, options, ctx);
out:
if (ret == 0)

View File

@@ -274,14 +274,28 @@ typedef enum krb5_key_usage {
/* Encryption type of the kdc session contribution in pk-init */
KRB5_KU_AS_REQ = 56,
/* Checksum of over the AS-REQ send by the KDC in PA-REQ-ENC-PA-REP */
KRB5_KU_FAST_REQ_CHKSUM = 50,
/* FAST armor checksum */
KRB5_KU_FAST_ENC = 51,
/* FAST armor encryption */
KRB5_KU_FAST_REP = 52,
/* FAST armor reply */
KRB5_KU_FAST_FINISHED = 53,
/* FAST finished checksum */
KRB5_KU_ENC_CHALLENGE_CLIENT = 54,
/* fast challange from client */
KRB5_KU_ENC_CHALLENGE_KDC = 55,
/* fast challange from kdc */
KRB5_KU_DIGEST_ENCRYPT = -18,
/* Encryption key usage used in the digest encryption field */
KRB5_KU_DIGEST_OPAQUE = -19,
/* Checksum key usage used in the digest opaque field */
KRB5_KU_KRB5SIGNEDPATH = -21,
/* Checksum key usage on KRB5SignedPath */
KRB5_KU_CANONICALIZED_NAMES = -23
KRB5_KU_CANONICALIZED_NAMES = -23,
/* Checksum key usage on PA-CANONICALIZED */
KRB5_KU_H5L_COOKIE = -25
/* encrypted foo */
} krb5_key_usage;
typedef krb5_key_usage krb5_keyusage;
@@ -671,6 +685,8 @@ typedef EncAPRepPart krb5_ap_rep_enc_part;
#define KRB5_TGS_NAME ("krbtgt")
#define KRB5_WELLKNOWN_NAME ("WELLKNOWN")
#define KRB5_ANON_NAME ("ANONYMOUS")
#define KRB5_ANON_REALM ("WELLKNOWN:ANONYMOUS")
#define KRB5_WELLKNOWN_ORG_H5L_REALM ("WELLKNOWN:ORG.H5L")
#define KRB5_DIGEST_NAME ("digest")
typedef enum {

View File

@@ -592,7 +592,9 @@ check_client_referral(krb5_context context,
return 0;
noreferral:
if (krb5_principal_compare(context, requested, mapped) == FALSE) {
if (krb5_principal_compare(context, requested, mapped) == FALSE &&
!rep->enc_part.flags.enc_pa_rep)
{
krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
N_("Not same client principal returned "
"as requested", ""));
@@ -656,6 +658,7 @@ _krb5_extract_ticket(krb5_context context,
krb5_addresses *addrs,
unsigned nonce,
unsigned flags,
krb5_data *request,
krb5_decrypt_proc decrypt_proc,
krb5_const_pointer decryptarg)
{
@@ -674,6 +677,48 @@ _krb5_extract_ticket(krb5_context context,
if (ret)
goto out;
if (rep->enc_part.flags.enc_pa_rep && request) {
krb5_crypto crypto = NULL;
Checksum cksum;
PA_DATA *pa = NULL;
int idx = 0;
_krb5_debug(context, 5, "processing enc-ap-rep");
if (rep->enc_part.encrypted_pa_data == NULL ||
(pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val,
rep->enc_part.encrypted_pa_data->len,
KRB5_PADATA_REQ_ENC_PA_REP,
&idx)) == NULL)
{
_krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing");
ret = KRB5KRB_AP_ERR_MODIFIED;
goto out;
}
ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret)
goto out;
ret = decode_Checksum(pa->padata_value.data,
pa->padata_value.length,
&cksum, NULL);
if (ret) {
krb5_crypto_destroy(context, crypto);
goto out;
}
ret = krb5_verify_checksum(context, crypto,
KRB5_KU_AS_REQ,
request->data, request->length,
&cksum);
krb5_crypto_destroy(context, crypto);
free_Checksum(&cksum);
_krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in");
if (ret)
goto out;
}
/* save session key */
creds->session.keyvalue.length = 0;
@@ -688,10 +733,10 @@ _krb5_extract_ticket(krb5_context context,
}
/* compare client and save */
ret = _krb5_principalname2krb5_principal (context,
&tmp_principal,
rep->kdc_rep.cname,
rep->kdc_rep.crealm);
ret = _krb5_principalname2krb5_principal(context,
&tmp_principal,
rep->kdc_rep.cname,
rep->kdc_rep.crealm);
if (ret)
goto out;

View File

@@ -766,11 +766,25 @@ HEIMDAL_KRB5_2.0 {
# kinit helper
krb5_get_init_creds_opt_set_pkinit_user_certs;
krb5_pk_enterprise_cert;
krb5_process_last_request;
krb5_init_creds_init;
krb5_init_creds_set_service;
krb5_init_creds_set_fast_ccache;
krb5_init_creds_set_keytab;
krb5_init_creds_get;
krb5_init_creds_set_password;
krb5_init_creds_store;
krb5_init_creds_free;
# testing
_krb5_aes_cts_encrypt;
_krb5_n_fold;
_krb5_expand_default_cc_name;
# FAST
_krb5_fast_cf2;
_krb5_fast_armor_key;
local:
*;
};