kdc: sync KDC FAST with Heimdal-597.121.1
Import KDC FAST from Apple's Heimdal-597.121.1, adding support for: - PA-ENC-CHALLENGE - reply key strengthening - FAST authentication in TGS kuser: Apple sync (squash) krb5_init_creds_store_config/krb5_init_creds_warn_user in kinit
This commit is contained in:
397
kdc/fast.c
397
kdc/fast.c
@@ -46,6 +46,7 @@ get_fastuser_crypto(astgs_request_t r, krb5_enctype enctype,
|
||||
|
||||
*crypto = NULL;
|
||||
|
||||
/* TODO: salt cookie key with client name and realm */
|
||||
ret = krb5_make_principal(r->context, &fast_princ,
|
||||
KRB5_WELLKNOWN_ORG_H5L_REALM,
|
||||
KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL);
|
||||
@@ -116,7 +117,7 @@ fast_parse_cookie(astgs_request_t r, const PA_DATA *pa)
|
||||
goto out;
|
||||
|
||||
if (r->fast.expiration < kdc_time) {
|
||||
kdc_log(r->context, r->config, 2, "fast cookie expired");
|
||||
kdc_log(r->context, r->config, 2, "FAST cookie expired");
|
||||
ret = KRB5KDC_ERR_POLICY;
|
||||
goto out;
|
||||
}
|
||||
@@ -144,11 +145,14 @@ fast_add_cookie(astgs_request_t r, METHOD_DATA *method_data)
|
||||
&r->fast, &size, ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
heim_assert(size == data.length, "internal asn1 encoder error");
|
||||
heim_assert(size == data.length, "internal asn.1 encoder error");
|
||||
|
||||
ret = get_fastuser_crypto(r, KRB5_ENCTYPE_NULL, &crypto);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
kdc_log(r->context, r->config, 0,
|
||||
"Failed to find FAST principal for cookie encryption: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_encrypt_EncryptedData(r->context, crypto,
|
||||
KRB5_KU_H5L_COOKIE,
|
||||
@@ -158,7 +162,7 @@ fast_add_cookie(astgs_request_t r, METHOD_DATA *method_data)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
free(data.data);
|
||||
krb5_data_free(&data);
|
||||
|
||||
shell.version = "H5L1";
|
||||
|
||||
@@ -167,14 +171,16 @@ fast_add_cookie(astgs_request_t r, METHOD_DATA *method_data)
|
||||
free_EncryptedData(&shell.cookie);
|
||||
if (ret)
|
||||
goto out;
|
||||
heim_assert(size == data.length, "internal asn1 encoder error");
|
||||
heim_assert(size == data.length, "internal asn.1 encoder error");
|
||||
|
||||
ret = krb5_padata_add(r->context, method_data,
|
||||
KRB5_PADATA_FX_COOKIE,
|
||||
data.data, data.length);
|
||||
if (ret == 0)
|
||||
krb5_data_zero(&data);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
free(data.data);
|
||||
krb5_data_free(&data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -209,8 +215,7 @@ _kdc_fast_mk_response(krb5_context context,
|
||||
&fastrep, &size, ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (buf.length != size)
|
||||
krb5_abortx(context, "internal asn.1 error");
|
||||
heim_assert(size == buf.length, "internal asn.1 encoder error");
|
||||
|
||||
fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data;
|
||||
|
||||
@@ -230,8 +235,7 @@ _kdc_fast_mk_response(krb5_context context,
|
||||
free_PA_FX_FAST_REPLY(&fxfastrep);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (data->length != size)
|
||||
krb5_abortx(context, "internal asn.1 error");
|
||||
heim_assert(size == data->length, "internal asn.1 encoder error");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -244,9 +248,8 @@ _kdc_fast_mk_error(astgs_request_t r,
|
||||
const KDC_REQ_BODY *req_body,
|
||||
krb5_error_code outer_error,
|
||||
const char *e_text,
|
||||
krb5_principal error_client,
|
||||
krb5_principal error_server,
|
||||
const PrincipalName *error_client_name,
|
||||
const Realm *error_client_realm,
|
||||
time_t *csec, int *cusec,
|
||||
krb5_data *error_msg)
|
||||
{
|
||||
@@ -257,15 +260,16 @@ _kdc_fast_mk_error(astgs_request_t r,
|
||||
|
||||
krb5_data_zero(&e_data);
|
||||
|
||||
if (armor_crypto || (r && r->fast.fast_state.len)) {
|
||||
if (r)
|
||||
ret = fast_add_cookie(r, error_method);
|
||||
else
|
||||
ret = krb5_padata_add(context, error_method,
|
||||
KRB5_PADATA_FX_COOKIE,
|
||||
NULL, 0);
|
||||
heim_assert(r != NULL, "invalid request in _kdc_fast_mk_error");
|
||||
|
||||
/*
|
||||
* FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
|
||||
*/
|
||||
if (armor_crypto || r->fast.fast_state.len) {
|
||||
ret = fast_add_cookie(r, error_method);
|
||||
if (ret) {
|
||||
kdc_log(r->context, r->config, 1, "failed to add fast cookie with: %d", ret);
|
||||
kdc_log(r->context, r->config, 1,
|
||||
"Failed to add FAST cookie: %d", ret);
|
||||
free_METHOD_DATA(error_method);
|
||||
return ret;
|
||||
}
|
||||
@@ -280,16 +284,15 @@ _kdc_fast_mk_error(astgs_request_t r,
|
||||
|
||||
/* first add the KRB-ERROR to the fast errors */
|
||||
|
||||
ret = krb5_mk_error_ext(context,
|
||||
outer_error,
|
||||
e_text,
|
||||
NULL,
|
||||
error_server,
|
||||
error_client_name,
|
||||
error_client_realm,
|
||||
NULL,
|
||||
NULL,
|
||||
&e_data);
|
||||
ret = krb5_mk_error(context,
|
||||
outer_error,
|
||||
e_text,
|
||||
NULL,
|
||||
error_client,
|
||||
error_server,
|
||||
NULL,
|
||||
NULL,
|
||||
&e_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -301,10 +304,14 @@ _kdc_fast_mk_error(astgs_request_t r,
|
||||
return ret;
|
||||
}
|
||||
|
||||
error_client_name = NULL;
|
||||
error_client_realm = NULL;
|
||||
error_server = NULL;
|
||||
e_text = NULL;
|
||||
outer_error = KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED;
|
||||
e_text = NULL;
|
||||
if (r->fast.flags.requested_hidden_names) {
|
||||
error_client = NULL;
|
||||
error_server = NULL;
|
||||
}
|
||||
csec = 0;
|
||||
cusec = 0;
|
||||
|
||||
ret = _kdc_fast_mk_response(context, armor_crypto,
|
||||
error_method, NULL, NULL,
|
||||
@@ -325,27 +332,27 @@ _kdc_fast_mk_error(astgs_request_t r,
|
||||
error_method, &size, ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (e_data.length != size)
|
||||
krb5_abortx(context, "internal asn.1 error");
|
||||
heim_assert(size == e_data.length, "internal asn.1 encoder error");
|
||||
}
|
||||
|
||||
ret = krb5_mk_error_ext(context,
|
||||
outer_error,
|
||||
e_text,
|
||||
(e_data.length ? &e_data : NULL),
|
||||
error_server,
|
||||
error_client_name,
|
||||
error_client_realm,
|
||||
csec,
|
||||
cusec,
|
||||
error_msg);
|
||||
ret = krb5_mk_error(context,
|
||||
outer_error,
|
||||
e_text,
|
||||
(e_data.length ? &e_data : NULL),
|
||||
error_client,
|
||||
error_server,
|
||||
csec,
|
||||
cusec,
|
||||
error_msg);
|
||||
krb5_data_free(&e_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
fast_unwrap_request(astgs_request_t r)
|
||||
fast_unwrap_request(astgs_request_t r,
|
||||
krb5_ticket *tgs_ticket,
|
||||
krb5_auth_context tgs_ac)
|
||||
{
|
||||
krb5_principal armor_server = NULL;
|
||||
hdb_entry_ex *armor_user = NULL;
|
||||
@@ -358,102 +365,121 @@ fast_unwrap_request(astgs_request_t r)
|
||||
krb5_error_code ret;
|
||||
krb5_ap_req ap_req;
|
||||
KrbFastReq fastreq;
|
||||
size_t len, size;
|
||||
krb5_data data;
|
||||
const PA_DATA *pa;
|
||||
krb5_data data;
|
||||
size_t len;
|
||||
int i = 0;
|
||||
|
||||
pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST);
|
||||
if (pa == NULL)
|
||||
if (pa == NULL) {
|
||||
if (tgs_ac && r->fast_asserted) {
|
||||
kdc_log(r->context, r->config, 1,
|
||||
"Client asserted FAST but did not include FX-FAST pa-data");
|
||||
ret = KRB5KRB_AP_ERR_MODIFIED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
kdc_log(r->context, r->config, 10, "Not a FAST request");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data,
|
||||
pa->padata_value.length,
|
||||
&fxreq,
|
||||
&len);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (len != pa->padata_value.length) {
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
if (ret) {
|
||||
kdc_log(r->context, r->config, 4,
|
||||
"Failed to decode PA-FX-FAST-REQUEST: %d", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
"AS-REQ FAST contain unknown type: %d", (int)fxreq.element);
|
||||
kdc_log(r->context, r->config, 4,
|
||||
"PA-FX-FAST-REQUEST contains unknown type: %d",
|
||||
(int)fxreq.element);
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* pull out armor key */
|
||||
if (fxreq.u.armored_data.armor == NULL) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
/*
|
||||
* If check for armor data or it's not a TGS-REQ with implicit
|
||||
* armor.
|
||||
*/
|
||||
if (fxreq.u.armored_data.armor == NULL && tgs_ac == NULL) {
|
||||
kdc_log(r->context, r->config, 4,
|
||||
"AS-REQ armor missing");
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fxreq.u.armored_data.armor->armor_type != 1) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
"AS-REQ armor type not ap-req");
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
*
|
||||
*/
|
||||
if (tgs_ac == NULL) {
|
||||
if (fxreq.u.armored_data.armor->armor_type != 1) {
|
||||
kdc_log(r->context, r->config, 4,
|
||||
"Incorrect AS-REQ armor type");
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_decode_ap_req(r->context,
|
||||
&fxreq.u.armored_data.armor->armor_value,
|
||||
&ap_req);
|
||||
if(ret) {
|
||||
kdc_log(r->context, r->config, 2, "AP-REQ decode failed");
|
||||
goto out;
|
||||
}
|
||||
ret = krb5_decode_ap_req(r->context,
|
||||
&fxreq.u.armored_data.armor->armor_value,
|
||||
&ap_req);
|
||||
if(ret) {
|
||||
kdc_log(r->context, r->config, 4, "Failed to decode AP-REQ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Save that principal that was in the request */
|
||||
ret = _krb5_principalname2krb5_principal(r->context,
|
||||
&armor_server,
|
||||
ap_req.ticket.sname,
|
||||
ap_req.ticket.realm);
|
||||
if (ret) {
|
||||
/* Save that principal that was in the request */
|
||||
ret = _krb5_principalname2krb5_principal(r->context,
|
||||
&armor_server,
|
||||
ap_req.ticket.sname,
|
||||
ap_req.ticket.realm);
|
||||
if (ret) {
|
||||
free_AP_REQ(&ap_req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _kdc_db_fetch(r->context, r->config, armor_server,
|
||||
HDB_F_GET_KRBTGT | HDB_F_DELAY_NEW_KEYS,
|
||||
NULL, NULL, &armor_user);
|
||||
if(ret == HDB_ERR_NOT_FOUND_HERE) {
|
||||
kdc_log(r->context, r->config, 5,
|
||||
"Armor key does not have secrets at this KDC, "
|
||||
"need to proxy");
|
||||
goto out;
|
||||
} else if (ret) {
|
||||
free_AP_REQ(&ap_req);
|
||||
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = hdb_enctype2key(r->context, &armor_user->entry, NULL,
|
||||
ap_req.ticket.enc_part.etype,
|
||||
&armor_key);
|
||||
if (ret) {
|
||||
free_AP_REQ(&ap_req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_verify_ap_req2(r->context, &ac,
|
||||
&ap_req,
|
||||
armor_server,
|
||||
&armor_key->key,
|
||||
0,
|
||||
&ap_req_options,
|
||||
&ticket,
|
||||
KRB5_KU_AP_REQ_AUTH);
|
||||
free_AP_REQ(&ap_req);
|
||||
goto out;
|
||||
if (ret)
|
||||
goto out;
|
||||
} else {
|
||||
heim_assert(tgs_ticket != NULL, "TGS authentication context without ticket");
|
||||
ac = tgs_ac;
|
||||
ticket = tgs_ticket;
|
||||
}
|
||||
|
||||
ret = _kdc_db_fetch(r->context, r->config, armor_server,
|
||||
HDB_F_GET_KRBTGT
|
||||
| HDB_F_DELAY_NEW_KEYS,
|
||||
NULL, NULL, &armor_user);
|
||||
if(ret == HDB_ERR_NOT_FOUND_HERE) {
|
||||
kdc_log(r->context, r->config, 5,
|
||||
"armor key does not have secrets at this KDC, "
|
||||
"need to proxy");
|
||||
free_AP_REQ(&ap_req);
|
||||
goto out;
|
||||
} else if (ret) {
|
||||
free_AP_REQ(&ap_req);
|
||||
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = hdb_enctype2key(r->context, &armor_user->entry, NULL,
|
||||
ap_req.ticket.enc_part.etype,
|
||||
&armor_key);
|
||||
if (ret) {
|
||||
free_AP_REQ(&ap_req);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_verify_ap_req2(r->context, &ac,
|
||||
&ap_req,
|
||||
armor_server,
|
||||
&armor_key->key,
|
||||
0,
|
||||
&ap_req_options,
|
||||
&ticket,
|
||||
KRB5_KU_AP_REQ_AUTH);
|
||||
free_AP_REQ(&ap_req);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (ac->remote_subkey == NULL) {
|
||||
krb5_auth_con_free(r->context, ac);
|
||||
kdc_log(r->context, r->config, 2,
|
||||
@@ -462,29 +488,19 @@ fast_unwrap_request(astgs_request_t r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
r->fast.flags.kdc_verified =
|
||||
!_kdc_is_anonymous_pkinit(r->context, ticket->client);
|
||||
|
||||
ret = _krb5_fast_armor_key(r->context,
|
||||
ac->remote_subkey,
|
||||
&ticket->ticket.key,
|
||||
&armorkey,
|
||||
&r->armor_crypto);
|
||||
krb5_auth_con_free(r->context, ac);
|
||||
krb5_free_ticket(r->context, ticket);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
krb5_free_keyblock_contents(r->context, &armorkey);
|
||||
|
||||
/* verify req-checksum of the outer body */
|
||||
ret = _kdc_verify_checksum(r->context, r->armor_crypto,
|
||||
KRB5_KU_FAST_REQ_CHKSUM,
|
||||
&r->req.req_body._save,
|
||||
&fxreq.u.armored_data.req_checksum);
|
||||
if (ret) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
"FAST request have a bad checksum");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_decrypt_EncryptedData(r->context, r->armor_crypto,
|
||||
KRB5_KU_FAST_ENC,
|
||||
&fxreq.u.armored_data.enc_fast_req,
|
||||
@@ -495,24 +511,57 @@ fast_unwrap_request(astgs_request_t r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = decode_KrbFastReq(data.data, data.length, &fastreq, &size);
|
||||
if (ret) {
|
||||
krb5_data_free(&data);
|
||||
goto out;
|
||||
}
|
||||
if (data.length != size) {
|
||||
krb5_data_free(&data);
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
goto out;
|
||||
}
|
||||
ret = decode_KrbFastReq(data.data, data.length, &fastreq, NULL);
|
||||
krb5_data_free(&data);
|
||||
|
||||
free_KDC_REQ_BODY(&r->req.req_body);
|
||||
ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* check for unsupported mandatory options */
|
||||
/*
|
||||
* verify req-checksum of the outer body
|
||||
*/
|
||||
if (tgs_ac) {
|
||||
/*
|
||||
* -- For TGS, contains the checksum performed over the type
|
||||
* -- AP-REQ in the PA-TGS-REQ padata.
|
||||
*/
|
||||
i = 0;
|
||||
pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_TGS_REQ);
|
||||
if (pa == NULL) {
|
||||
kdc_log(r->context, r->config, 4,
|
||||
"FAST TGS request missing TGS-REQ padata");
|
||||
ret = KRB5KRB_ERR_GENERIC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = _kdc_verify_checksum(r->context, r->armor_crypto,
|
||||
KRB5_KU_FAST_REQ_CHKSUM,
|
||||
&pa->padata_value,
|
||||
&fxreq.u.armored_data.req_checksum);
|
||||
if (ret) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
"Bad checksum in FAST TGS request");
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* -- For AS, contains the checksum performed over the type
|
||||
* -- KDC-REQ-BODY for the req-body field of the KDC-REQ
|
||||
* -- structure;
|
||||
*/
|
||||
ret = _kdc_verify_checksum(r->context, r->armor_crypto,
|
||||
KRB5_KU_FAST_REQ_CHKSUM,
|
||||
&r->req.req_body._save,
|
||||
&fxreq.u.armored_data.req_checksum);
|
||||
if (ret) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
"Bad checksum in FAST AS request");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check for unsupported mandatory options
|
||||
*/
|
||||
if (FastOptions2int(fastreq.fast_options) & 0xfffc) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
"FAST unsupported mandatory option set");
|
||||
@@ -520,6 +569,8 @@ fast_unwrap_request(astgs_request_t r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
r->fast.flags.requested_hidden_names = fastreq.fast_options.hide_client_names;
|
||||
|
||||
/* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */
|
||||
if (r->req.padata)
|
||||
free_METHOD_DATA(r->req.padata);
|
||||
@@ -530,10 +581,22 @@ fast_unwrap_request(astgs_request_t r)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
free_KDC_REQ_BODY(&r->req.req_body);
|
||||
ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
free_KrbFastReq(&fastreq);
|
||||
free_PA_FX_FAST_REQUEST(&fxreq);
|
||||
|
||||
kdc_log(r->context, r->config, 5, "Client selected FAST");
|
||||
|
||||
out:
|
||||
if (ac && ac != tgs_ac)
|
||||
krb5_auth_con_free(r->context, ac);
|
||||
if (ticket && ticket != tgs_ticket)
|
||||
krb5_free_ticket(r->context, ticket);
|
||||
|
||||
if (armor_server)
|
||||
krb5_free_principal(r->context, armor_server);
|
||||
if(armor_user)
|
||||
@@ -542,30 +605,70 @@ fast_unwrap_request(astgs_request_t r)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
krb5_error_code
|
||||
_kdc_fast_unwrap_request(astgs_request_t r)
|
||||
_kdc_fast_unwrap_request(astgs_request_t r,
|
||||
krb5_ticket *tgs_ticket,
|
||||
krb5_auth_context tgs_ac)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
const PA_DATA *pa;
|
||||
int i = 0;
|
||||
|
||||
ret = fast_unwrap_request(r);
|
||||
ret = fast_unwrap_request(r, tgs_ticket, tgs_ac);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Non-FAST mechanisms may use FX-COOKIE to manage state.
|
||||
* FX-COOKIE can be used outside of FAST, e.g. SRP or GSS.
|
||||
*/
|
||||
pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_COOKIE);
|
||||
if (pa) {
|
||||
if (pa)
|
||||
ret = fast_parse_cookie(r, pa);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Strengthen reply key by mixing with a random key that is
|
||||
* protected by FAST.
|
||||
*/
|
||||
krb5_error_code
|
||||
_kdc_fast_strengthen_reply_key(astgs_request_t r)
|
||||
{
|
||||
if (r->armor_crypto) {
|
||||
krb5_keyblock new_reply_key;
|
||||
krb5_error_code ret;
|
||||
|
||||
kdc_log(r->context, r->config, 5,
|
||||
"FAST strengthen reply key with strengthen-key");
|
||||
|
||||
heim_assert(r->reply_key.keytype != KRB5_ENCTYPE_NULL, "NULL reply key enctype");
|
||||
|
||||
ret = krb5_generate_random_keyblock(r->context, r->reply_key.keytype,
|
||||
&r->strengthen_key);
|
||||
if (ret)
|
||||
krb5_abortx(r->context, "random generator fail");
|
||||
|
||||
ret = _krb5_fast_cf2(r->context,
|
||||
&r->strengthen_key, "strengthenkey",
|
||||
&r->reply_key, "replykey",
|
||||
&new_reply_key, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
krb5_free_keyblock_contents(r->context, &r->reply_key);
|
||||
r->reply_key = new_reply_key;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero and free KDCFastState
|
||||
*/
|
||||
void
|
||||
_kdc_free_fast_state(KDCFastState *state)
|
||||
{
|
||||
|
@@ -269,6 +269,8 @@ eval_kinit(heim_dict_t o)
|
||||
ret = krb5_init_creds_set_fast_ccache(kdc_context, ctx, fast_cc);
|
||||
if (ret)
|
||||
krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_fast_ccache");
|
||||
|
||||
fast_cc = NULL;
|
||||
}
|
||||
|
||||
if (password) {
|
||||
|
@@ -93,6 +93,13 @@ struct astgs_request_desc {
|
||||
krb5_timestamp pa_endtime;
|
||||
krb5_timestamp pa_max_life;
|
||||
|
||||
krb5_keyblock strengthen_key;
|
||||
const Key *ticket_key;
|
||||
|
||||
/* only valid for tgs-req */
|
||||
unsigned int rk_is_subkey : 1;
|
||||
unsigned int fast_asserted : 1;
|
||||
|
||||
krb5_crypto armor_crypto;
|
||||
|
||||
KDCFastState fast;
|
||||
|
231
kdc/kerberos5.c
231
kdc/kerberos5.c
@@ -555,62 +555,10 @@ pa_gss_validate(astgs_request_t r, const PA_DATA *pa)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
static krb5_error_code
|
||||
make_pa_enc_challange(astgs_request_t r, krb5_crypto crypto)
|
||||
{
|
||||
krb5_context context = r->context;
|
||||
METHOD_DATA *md = &r->outpadata;
|
||||
PA_ENC_TS_ENC p;
|
||||
unsigned char *buf;
|
||||
size_t buf_size;
|
||||
size_t len;
|
||||
EncryptedData encdata;
|
||||
krb5_error_code ret;
|
||||
int32_t usec;
|
||||
int usec2;
|
||||
|
||||
krb5_us_timeofday (context, &p.patimestamp, &usec);
|
||||
usec2 = usec;
|
||||
p.pausec = &usec2;
|
||||
|
||||
ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
if(buf_size != len)
|
||||
krb5_abortx(context, "internal error in ASN.1 encoder");
|
||||
|
||||
ret = krb5_encrypt_EncryptedData(context,
|
||||
crypto,
|
||||
KRB5_KU_ENC_CHALLENGE_KDC,
|
||||
buf,
|
||||
len,
|
||||
0,
|
||||
&encdata);
|
||||
free(buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
|
||||
free_EncryptedData(&encdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
if(buf_size != len)
|
||||
krb5_abortx(context, "internal error in ASN.1 encoder");
|
||||
|
||||
ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len);
|
||||
if (ret)
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa)
|
||||
{
|
||||
krb5_data pepper1, pepper2, ts_data;
|
||||
krb5_data pepper1, pepper2;
|
||||
int invalidPassword = 0;
|
||||
EncryptedData enc_data;
|
||||
krb5_enctype aenctype;
|
||||
@@ -652,10 +600,11 @@ pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa)
|
||||
|
||||
krb5_crypto_getenctype(r->context, r->armor_crypto, &aenctype);
|
||||
|
||||
kdc_log(r->context, r->config, 5, "FAST armor enctype is: %d", (int)aenctype);
|
||||
|
||||
for (i = 0; i < r->client->entry.keys.len; i++) {
|
||||
krb5_crypto challangecrypto, longtermcrypto;
|
||||
krb5_keyblock challangekey;
|
||||
PA_ENC_TS_ENC p;
|
||||
krb5_crypto challengecrypto, longtermcrypto;
|
||||
krb5_keyblock challengekey;
|
||||
|
||||
k = &r->client->entry.keys.val[i];
|
||||
|
||||
@@ -665,26 +614,32 @@ pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa)
|
||||
|
||||
ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto,
|
||||
&pepper1, &pepper2, aenctype,
|
||||
&challangekey);
|
||||
krb5_crypto_destroy(r->context, longtermcrypto);
|
||||
if (ret)
|
||||
&challengekey);
|
||||
if (ret) {
|
||||
krb5_crypto_destroy(r->context, longtermcrypto);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = krb5_crypto_init(r->context, &challangekey, 0,
|
||||
&challangecrypto);
|
||||
if (ret)
|
||||
ret = krb5_crypto_init(r->context, &challengekey, 0,
|
||||
&challengecrypto);
|
||||
krb5_free_keyblock_contents(r->context, &challengekey);
|
||||
if (ret) {
|
||||
krb5_crypto_destroy(r->context, longtermcrypto);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = krb5_decrypt_EncryptedData(r->context, challangecrypto,
|
||||
KRB5_KU_ENC_CHALLENGE_CLIENT,
|
||||
&enc_data,
|
||||
&ts_data);
|
||||
ret = _krb5_validate_pa_enc_challenge(r->context,
|
||||
challengecrypto,
|
||||
KRB5_KU_ENC_CHALLENGE_CLIENT,
|
||||
&enc_data,
|
||||
r->cname);
|
||||
krb5_crypto_destroy(r->context, challengecrypto);
|
||||
if (ret) {
|
||||
const char *msg = krb5_get_error_message(r->context, ret);
|
||||
krb5_error_code ret2;
|
||||
char *str = NULL;
|
||||
|
||||
invalidPassword = 1;
|
||||
invalidPassword = (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY);
|
||||
|
||||
ret2 = krb5_enctype_to_string(r->context, k->key.keytype, &str);
|
||||
if (ret2)
|
||||
@@ -695,68 +650,66 @@ pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa)
|
||||
krb5_free_error_message(r->context, msg);
|
||||
free(str);
|
||||
|
||||
krb5_crypto_destroy(r->context, longtermcrypto);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = decode_PA_ENC_TS_ENC(ts_data.data,
|
||||
ts_data.length,
|
||||
&p,
|
||||
&size);
|
||||
krb5_data_free(&ts_data);
|
||||
if(ret){
|
||||
krb5_crypto_destroy(r->context, challangecrypto);
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
_kdc_r_log(r, 4, "Failed to decode PA-ENC-TS_ENC -- %s",
|
||||
r->cname);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Found a key that the client used, lets pick that as the reply key
|
||||
*/
|
||||
|
||||
if (labs(kdc_time - p.patimestamp) > r->context->max_skew) {
|
||||
char client_time[100];
|
||||
|
||||
krb5_crypto_destroy(r->context, challangecrypto);
|
||||
|
||||
krb5_format_time(r->context, p.patimestamp,
|
||||
client_time, sizeof(client_time), TRUE);
|
||||
|
||||
ret = KRB5KRB_AP_ERR_SKEW;
|
||||
_kdc_r_log(r, 4, "Too large time skew, "
|
||||
"client time %s is out by %u > %u seconds -- %s",
|
||||
client_time,
|
||||
(unsigned)labs(kdc_time - p.patimestamp),
|
||||
r->context->max_skew,
|
||||
r->cname);
|
||||
|
||||
free_PA_ENC_TS_ENC(&p);
|
||||
krb5_free_keyblock_contents(r->context, &r->reply_key);
|
||||
ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key);
|
||||
if (ret) {
|
||||
krb5_crypto_destroy(r->context, longtermcrypto);
|
||||
goto out;
|
||||
}
|
||||
|
||||
free_PA_ENC_TS_ENC(&p);
|
||||
krb5_free_keyblock_contents(r->context, &challengekey);
|
||||
|
||||
ret = make_pa_enc_challange(r, challangecrypto);
|
||||
krb5_crypto_destroy(r->context, challangecrypto);
|
||||
/*
|
||||
* Provide KDC authentication to the client, uses a different
|
||||
* challenge key (different pepper).
|
||||
*/
|
||||
|
||||
pepper1.data = "kdcchallengearmor";
|
||||
pepper1.length = strlen(pepper1.data);
|
||||
|
||||
ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto,
|
||||
&pepper1, &pepper2, aenctype,
|
||||
&challengekey);
|
||||
krb5_crypto_destroy(r->context, longtermcrypto);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = krb5_crypto_init(r->context, &challengekey, 0, &challengecrypto);
|
||||
krb5_free_keyblock_contents(r->context, &challengekey);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = _krb5_make_pa_enc_challenge(r->context, challengecrypto,
|
||||
KRB5_KU_ENC_CHALLENGE_KDC,
|
||||
&r->outpadata);
|
||||
krb5_crypto_destroy(r->context, challengecrypto);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
set_salt_padata(&r->outpadata, k->salt);
|
||||
krb5_free_keyblock_contents(r->context, &r->reply_key);
|
||||
ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Success
|
||||
*/
|
||||
/*
|
||||
* Success
|
||||
*/
|
||||
if (r->clientdb->hdb_auth_status)
|
||||
r->clientdb->hdb_auth_status(r->context, r->clientdb, r->client,
|
||||
HDB_AUTH_SUCCESS);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
|
||||
if (invalidPassword && r->clientdb->hdb_auth_status) {
|
||||
r->clientdb->hdb_auth_status(r->context, r->clientdb, r->client,
|
||||
HDB_AUTH_WRONG_PASSWORD);
|
||||
ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||
}
|
||||
out:
|
||||
free_EncryptedData(&enc_data);
|
||||
@@ -1016,11 +969,11 @@ log_patypes(astgs_request_t r, METHOD_DATA *padata)
|
||||
krb5_error_code
|
||||
_kdc_encode_reply(krb5_context context,
|
||||
krb5_kdc_configuration *config,
|
||||
krb5_crypto armor_crypto, uint32_t nonce,
|
||||
astgs_request_t r, uint32_t nonce,
|
||||
KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek,
|
||||
krb5_enctype etype,
|
||||
int skvno, const EncryptionKey *skey,
|
||||
int ckvno, const EncryptionKey *reply_key,
|
||||
int ckvno,
|
||||
int rk_is_subkey,
|
||||
const char **e_text,
|
||||
krb5_data *reply)
|
||||
@@ -1066,10 +1019,9 @@ _kdc_encode_reply(krb5_context context,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (armor_crypto) {
|
||||
krb5_data data;
|
||||
krb5_keyblock *strengthen_key = NULL;
|
||||
if (r && r->armor_crypto) {
|
||||
KrbFastFinished finished;
|
||||
krb5_data data;
|
||||
|
||||
kdc_log(context, config, 4, "FAST armor protection");
|
||||
|
||||
@@ -1088,7 +1040,7 @@ _kdc_encode_reply(krb5_context context,
|
||||
if (data.length != len)
|
||||
krb5_abortx(context, "internal asn.1 error");
|
||||
|
||||
ret = krb5_create_checksum(context, armor_crypto,
|
||||
ret = krb5_create_checksum(context, r->armor_crypto,
|
||||
KRB5_KU_FAST_FINISHED, 0,
|
||||
data.data, data.length,
|
||||
&finished.ticket_checksum);
|
||||
@@ -1096,8 +1048,8 @@ _kdc_encode_reply(krb5_context context,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = _kdc_fast_mk_response(context, armor_crypto,
|
||||
rep->padata, strengthen_key, &finished,
|
||||
ret = _kdc_fast_mk_response(context, r->armor_crypto,
|
||||
rep->padata, &r->strengthen_key, &finished,
|
||||
nonce, &data);
|
||||
free_Checksum(&finished.ticket_checksum);
|
||||
if (ret)
|
||||
@@ -1120,9 +1072,9 @@ _kdc_encode_reply(krb5_context context,
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Hide client name of privacy reasons
|
||||
* Hide client name for privacy reasons
|
||||
*/
|
||||
if (1 /* r->fast_options.hide_client_names */) {
|
||||
if (r->fast.flags.requested_hidden_names) {
|
||||
Realm anon_realm = KRB5_ANON_REALM;
|
||||
|
||||
free_Realm(&rep->crealm);
|
||||
@@ -1152,7 +1104,7 @@ _kdc_encode_reply(krb5_context context,
|
||||
*e_text = "KDC internal error";
|
||||
return KRB5KRB_ERR_GENERIC;
|
||||
}
|
||||
ret = krb5_crypto_init(context, reply_key, 0, &crypto);
|
||||
ret = krb5_crypto_init(context, &r->reply_key, 0, &crypto);
|
||||
if (ret) {
|
||||
const char *msg = krb5_get_error_message(context, ret);
|
||||
free(buf);
|
||||
@@ -1988,7 +1940,6 @@ _kdc_as_rep(astgs_request_t r)
|
||||
Key *skey;
|
||||
int found_pa = 0;
|
||||
int i, flags = HDB_F_FOR_AS_REQ;
|
||||
METHOD_DATA error_method;
|
||||
const PA_DATA *pa;
|
||||
krb5_boolean is_tgs;
|
||||
const char *msg;
|
||||
@@ -1996,13 +1947,11 @@ _kdc_as_rep(astgs_request_t r)
|
||||
Key *krbtgt_key;
|
||||
|
||||
memset(&rep, 0, sizeof(rep));
|
||||
error_method.len = 0;
|
||||
error_method.val = NULL;
|
||||
|
||||
/*
|
||||
* Look for FAST armor and unwrap
|
||||
*/
|
||||
ret = _kdc_fast_unwrap_request(r);
|
||||
ret = _kdc_fast_unwrap_request(r, NULL, NULL);
|
||||
if (ret) {
|
||||
_kdc_r_log(r, 1, "FAST unwrap request from %s failed: %d", from, ret);
|
||||
goto out;
|
||||
@@ -2081,10 +2030,10 @@ _kdc_as_rep(astgs_request_t r)
|
||||
r->cname, fixed_client_name);
|
||||
free(fixed_client_name);
|
||||
|
||||
ret = _kdc_fast_mk_error(r, &error_method, r->armor_crypto,
|
||||
ret = _kdc_fast_mk_error(r, &r->outpadata, r->armor_crypto,
|
||||
&req->req_body, KRB5_KDC_ERR_WRONG_REALM,
|
||||
NULL, r->server_princ, NULL,
|
||||
&r->client->entry.principal->realm,
|
||||
NULL,
|
||||
r->client->entry.principal, r->server_princ,
|
||||
NULL, NULL, r->reply);
|
||||
goto out;
|
||||
}
|
||||
@@ -2174,7 +2123,7 @@ _kdc_as_rep(astgs_request_t r)
|
||||
NULL, &ckey, &default_salt);
|
||||
if (ret2 == 0) {
|
||||
ret2 = get_pa_etype_info_both(context, config, &b->etype,
|
||||
&error_method, ckey, !default_salt);
|
||||
&r->outpadata, ckey, !default_salt);
|
||||
if (ret2 != 0)
|
||||
ret = ret2;
|
||||
}
|
||||
@@ -2203,7 +2152,7 @@ _kdc_as_rep(astgs_request_t r)
|
||||
for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) {
|
||||
if ((pat[n].flags & PA_ANNOUNCE) == 0)
|
||||
continue;
|
||||
ret = krb5_padata_add(context, &error_method,
|
||||
ret = krb5_padata_add(context, &r->outpadata,
|
||||
pat[n].type, NULL, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -2217,7 +2166,7 @@ _kdc_as_rep(astgs_request_t r)
|
||||
NULL, &ckey, &default_salt);
|
||||
if (ret == 0) {
|
||||
ret = get_pa_etype_info_both(context, config, &b->etype,
|
||||
&error_method, ckey, !default_salt);
|
||||
&r->outpadata, ckey, !default_salt);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
@@ -2253,7 +2202,7 @@ _kdc_as_rep(astgs_request_t r)
|
||||
* with in a preauth mech.
|
||||
*/
|
||||
|
||||
ret = _kdc_check_access(r, req, &error_method);
|
||||
ret = _kdc_check_access(r, req, &r->outpadata);
|
||||
if(ret)
|
||||
goto out;
|
||||
|
||||
@@ -2577,6 +2526,14 @@ _kdc_as_rep(astgs_request_t r)
|
||||
|
||||
r->et.flags.enc_pa_rep = r->ek.flags.enc_pa_rep = 1;
|
||||
|
||||
/*
|
||||
* update reply-key with strengthen-key
|
||||
*/
|
||||
|
||||
ret = _kdc_fast_strengthen_reply_key(r);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Add REQ_ENC_PA_REP if client supports it
|
||||
*/
|
||||
@@ -2599,11 +2556,11 @@ _kdc_as_rep(astgs_request_t r)
|
||||
*/
|
||||
|
||||
ret = _kdc_encode_reply(context, config,
|
||||
r->armor_crypto, req->req_body.nonce,
|
||||
r, req->req_body.nonce,
|
||||
&rep, &r->et, &r->ek, setype,
|
||||
r->server->entry.kvno, &skey->key,
|
||||
r->client->entry.kvno,
|
||||
&r->reply_key, 0, &r->e_text, r->reply);
|
||||
0, &r->e_text, r->reply);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -2624,16 +2581,12 @@ out:
|
||||
*/
|
||||
if (ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && r->reply->length == 0)
|
||||
ret = _kdc_fast_mk_error(r,
|
||||
(ret == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED)
|
||||
? &r->outpadata : &error_method,
|
||||
&r->outpadata,
|
||||
r->armor_crypto,
|
||||
&req->req_body,
|
||||
ret, r->e_text,
|
||||
r->client_princ,
|
||||
r->server_princ,
|
||||
r->client_princ ?
|
||||
&r->client_princ->name : NULL,
|
||||
r->client_princ ?
|
||||
&r->client_princ->realm : NULL,
|
||||
NULL, NULL,
|
||||
r->reply);
|
||||
|
||||
@@ -2641,8 +2594,6 @@ out:
|
||||
free_EncKDCRepPart(&r->ek);
|
||||
_kdc_free_fast_state(&r->fast);
|
||||
|
||||
if (error_method.len)
|
||||
free_METHOD_DATA(&error_method);
|
||||
if (r->outpadata.len)
|
||||
free_METHOD_DATA(&r->outpadata);
|
||||
if (r->client_princ) {
|
||||
@@ -2665,5 +2616,7 @@ out:
|
||||
}
|
||||
krb5_free_keyblock_contents(r->context, &r->reply_key);
|
||||
krb5_free_keyblock_contents(r->context, &r->session_key);
|
||||
krb5_free_keyblock_contents(r->context, &r->strengthen_key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
160
kdc/krb5tgs.c
160
kdc/krb5tgs.c
@@ -515,8 +515,6 @@ static krb5_error_code
|
||||
tgs_make_reply(astgs_request_t r,
|
||||
krb5_principal tgt_name,
|
||||
const EncTicketPart *tgt,
|
||||
const krb5_keyblock *replykey,
|
||||
int rk_is_subkey,
|
||||
const EncryptionKey *serverkey,
|
||||
const EncryptionKey *krbtgtkey,
|
||||
const krb5_keyblock *sessionkey,
|
||||
@@ -526,14 +524,12 @@ tgs_make_reply(astgs_request_t r,
|
||||
krb5_principal server_principal,
|
||||
hdb_entry_ex *client,
|
||||
krb5_principal client_principal,
|
||||
const char *tgt_realm,
|
||||
const char *tgt_realm,
|
||||
krb5_pac mspac,
|
||||
uint16_t rodc_id,
|
||||
krb5_boolean add_ticket_sig,
|
||||
const METHOD_DATA *enc_pa_data)
|
||||
{
|
||||
krb5_context context = r->context;
|
||||
krb5_kdc_configuration *config = r->config;
|
||||
KDC_REQ_BODY *b = &r->req.req_body;
|
||||
const char **e_text = &r->e_text;
|
||||
krb5_data *reply = r->reply;
|
||||
@@ -570,17 +566,17 @@ tgs_make_reply(astgs_request_t r,
|
||||
*/
|
||||
|
||||
#define GLOBAL_FORCE_TRANSITED_CHECK \
|
||||
(config->trpolicy == TRPOLICY_ALWAYS_CHECK)
|
||||
(r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
|
||||
#define GLOBAL_ALLOW_PER_PRINCIPAL \
|
||||
(config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
|
||||
(r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
|
||||
#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
|
||||
(config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
|
||||
(r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
|
||||
|
||||
/* these will consult the database in future release */
|
||||
#define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
|
||||
#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
|
||||
|
||||
ret = fix_transited_encoding(context, config,
|
||||
ret = fix_transited_encoding(r->context, r->config,
|
||||
!f.disable_transited_check ||
|
||||
GLOBAL_FORCE_TRANSITED_CHECK ||
|
||||
PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
|
||||
@@ -588,8 +584,8 @@ tgs_make_reply(astgs_request_t r,
|
||||
PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
|
||||
GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
|
||||
&tgt->transited, &et,
|
||||
krb5_principal_get_realm(context, client_principal),
|
||||
krb5_principal_get_realm(context, server->entry.principal),
|
||||
krb5_principal_get_realm(r->context, client_principal),
|
||||
krb5_principal_get_realm(r->context, server->entry.principal),
|
||||
tgt_realm);
|
||||
if(ret)
|
||||
goto out;
|
||||
@@ -682,20 +678,20 @@ tgs_make_reply(astgs_request_t r,
|
||||
et.authorization_data = calloc(1, sizeof(*et.authorization_data));
|
||||
if (et.authorization_data == NULL) {
|
||||
ret = ENOMEM;
|
||||
krb5_set_error_message(context, ret, "malloc: out of memory");
|
||||
krb5_set_error_message(r->context, ret, "malloc: out of memory");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < auth_data->len ; i++) {
|
||||
ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret, "malloc: out of memory");
|
||||
krb5_set_error_message(r->context, ret, "malloc: out of memory");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
|
||||
ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et.key);
|
||||
if (ret)
|
||||
goto out;
|
||||
et.crealm = rep.crealm;
|
||||
@@ -732,10 +728,10 @@ tgs_make_reply(astgs_request_t r,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (krb5_enctype_valid(context, serverkey->keytype) != 0
|
||||
if (krb5_enctype_valid(r->context, serverkey->keytype) != 0
|
||||
&& _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
|
||||
{
|
||||
krb5_enctype_enable(context, serverkey->keytype);
|
||||
krb5_enctype_enable(r->context, serverkey->keytype);
|
||||
is_weak = 1;
|
||||
}
|
||||
|
||||
@@ -748,7 +744,7 @@ tgs_make_reply(astgs_request_t r,
|
||||
if (mspac && !et.flags.anonymous) {
|
||||
|
||||
/* The PAC should be the last change to the ticket. */
|
||||
ret = _krb5_kdc_pac_sign_ticket(context, mspac, tgt_name, serverkey,
|
||||
ret = _krb5_kdc_pac_sign_ticket(r->context, mspac, tgt_name, serverkey,
|
||||
krbtgtkey, rodc_id, add_ticket_sig, &et);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -764,15 +760,14 @@ tgs_make_reply(astgs_request_t r,
|
||||
CAST session key. Should the DES3 etype be added to the
|
||||
etype list, even if we don't want a session key with
|
||||
DES3? */
|
||||
ret = _kdc_encode_reply(context, config, NULL, 0,
|
||||
ret = _kdc_encode_reply(r->context, r->config, r, b->nonce,
|
||||
&rep, &et, &ek, serverkey->keytype,
|
||||
kvno,
|
||||
serverkey, 0, replykey, rk_is_subkey,
|
||||
serverkey, 0, r->rk_is_subkey,
|
||||
e_text, reply);
|
||||
if (is_weak)
|
||||
krb5_enctype_disable(context, serverkey->keytype);
|
||||
krb5_enctype_disable(r->context, serverkey->keytype);
|
||||
|
||||
r->reply_key.keytype = replykey->keytype;
|
||||
_log_astgs_req(r, serverkey->keytype);
|
||||
|
||||
out:
|
||||
@@ -887,6 +882,33 @@ need_referral(krb5_context context, krb5_kdc_configuration *config,
|
||||
return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
validate_fast_ad(astgs_request_t r, krb5_authdata *auth_data)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_data data;
|
||||
|
||||
krb5_data_zero(&data);
|
||||
|
||||
ret = _krb5_get_ad(r->context, auth_data, NULL,
|
||||
KRB5_AUTHDATA_FX_FAST_USED, &data);
|
||||
if (ret == 0) {
|
||||
r->fast_asserted = 1;
|
||||
krb5_data_free(&data);
|
||||
}
|
||||
|
||||
ret = _krb5_get_ad(r->context, auth_data, NULL,
|
||||
KRB5_AUTHDATA_FX_FAST_ARMOR, &data);
|
||||
if (ret == 0) {
|
||||
kdc_log(r->context, r->config, 2,
|
||||
"Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
|
||||
krb5_data_free(&data);
|
||||
return KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
tgs_parse_request(astgs_request_t r,
|
||||
const PA_DATA *tgs_req,
|
||||
@@ -898,10 +920,7 @@ tgs_parse_request(astgs_request_t r,
|
||||
const struct sockaddr *from_addr,
|
||||
time_t **csec,
|
||||
int **cusec,
|
||||
AuthorizationData **auth_data,
|
||||
krb5_keyblock **replykey,
|
||||
Key **header_key,
|
||||
int *rk_is_subkey)
|
||||
AuthorizationData **auth_data)
|
||||
{
|
||||
krb5_context context = r->context;
|
||||
krb5_kdc_configuration *config = r->config;
|
||||
@@ -925,7 +944,6 @@ tgs_parse_request(astgs_request_t r,
|
||||
*auth_data = NULL;
|
||||
*csec = NULL;
|
||||
*cusec = NULL;
|
||||
*replykey = NULL;
|
||||
|
||||
memset(&ap_req, 0, sizeof(ap_req));
|
||||
ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
|
||||
@@ -1070,7 +1088,7 @@ next_kvno:
|
||||
goto out;
|
||||
}
|
||||
|
||||
*header_key = tkey;
|
||||
r->ticket_key = tkey;
|
||||
|
||||
{
|
||||
krb5_authenticator auth;
|
||||
@@ -1091,7 +1109,11 @@ next_kvno:
|
||||
goto out;
|
||||
}
|
||||
**cusec = auth->cusec;
|
||||
|
||||
ret = validate_fast_ad(r, auth->authorization_data);
|
||||
krb5_free_authenticator(context, &auth);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1103,7 +1125,7 @@ next_kvno:
|
||||
}
|
||||
|
||||
usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
|
||||
*rk_is_subkey = 1;
|
||||
r->rk_is_subkey = 1;
|
||||
|
||||
ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
|
||||
if(ret){
|
||||
@@ -1115,7 +1137,7 @@ next_kvno:
|
||||
}
|
||||
if(subkey == NULL){
|
||||
usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
|
||||
*rk_is_subkey = 0;
|
||||
r->rk_is_subkey = 0;
|
||||
|
||||
ret = krb5_auth_con_getkey(context, ac, &subkey);
|
||||
if(ret) {
|
||||
@@ -1134,12 +1156,16 @@ next_kvno:
|
||||
goto out;
|
||||
}
|
||||
|
||||
*replykey = subkey;
|
||||
krb5_free_keyblock_contents(r->context, &r->reply_key);
|
||||
ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key);
|
||||
krb5_free_keyblock(r->context, subkey);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (b->enc_authorization_data) {
|
||||
krb5_data ad;
|
||||
|
||||
ret = krb5_crypto_init(context, subkey, 0, &crypto);
|
||||
ret = krb5_crypto_init(context, &r->reply_key, 0, &crypto);
|
||||
if (ret) {
|
||||
const char *msg = krb5_get_error_message(context, ret);
|
||||
krb5_auth_con_free(context, ac);
|
||||
@@ -1175,8 +1201,21 @@ next_kvno:
|
||||
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = validate_fast_ad(r, *auth_data);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for FAST request
|
||||
*/
|
||||
|
||||
ret = _kdc_fast_unwrap_request(r, *ticket, ac);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
krb5_auth_con_free(context, ac);
|
||||
|
||||
out:
|
||||
@@ -1316,9 +1355,6 @@ static krb5_error_code
|
||||
tgs_build_reply(astgs_request_t priv,
|
||||
hdb_entry_ex *krbtgt,
|
||||
krb5_enctype krbtgt_etype,
|
||||
Key *tkey_check,
|
||||
const krb5_keyblock *replykey,
|
||||
int rk_is_subkey,
|
||||
krb5_ticket *ticket,
|
||||
const char **e_text,
|
||||
AuthorizationData **auth_data,
|
||||
@@ -1781,7 +1817,7 @@ server_lookup:
|
||||
priv->client = client;
|
||||
|
||||
ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
|
||||
&tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
|
||||
&priv->ticket_key->key, &priv->ticket_key->key, tgt, &kdc_issued, &mspac);
|
||||
if (ret) {
|
||||
const char *msg = krb5_get_error_message(context, ret);
|
||||
_kdc_audit_addreason((kdc_request_t)priv, "PAC check failed");
|
||||
@@ -2101,7 +2137,7 @@ server_lookup:
|
||||
* a S4U_DELEGATION_INFO blob to the PAC.
|
||||
*/
|
||||
ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
|
||||
&clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
|
||||
&clientkey->key, &priv->ticket_key->key, &adtkt, &ad_kdc_issued, &mspac);
|
||||
if (adclient)
|
||||
_kdc_free_ent(context, adclient);
|
||||
if (ret) {
|
||||
@@ -2230,8 +2266,6 @@ server_lookup:
|
||||
ret = tgs_make_reply(priv,
|
||||
tp,
|
||||
tgt,
|
||||
replykey,
|
||||
rk_is_subkey,
|
||||
ekey,
|
||||
&tkey_sign->key,
|
||||
&sessionkey,
|
||||
@@ -2297,16 +2331,13 @@ _kdc_tgs_rep(astgs_request_t r)
|
||||
AuthorizationData *auth_data = NULL;
|
||||
krb5_error_code ret;
|
||||
int i = 0;
|
||||
const PA_DATA *tgs_req;
|
||||
Key *header_key = NULL;
|
||||
const PA_DATA *tgs_req, *pa;
|
||||
|
||||
hdb_entry_ex *krbtgt = NULL;
|
||||
krb5_ticket *ticket = NULL;
|
||||
const char *e_text = NULL;
|
||||
krb5_enctype krbtgt_etype = ETYPE_NULL;
|
||||
|
||||
krb5_keyblock *replykey = NULL;
|
||||
int rk_is_subkey = 0;
|
||||
time_t *csec = NULL;
|
||||
int *cusec = NULL;
|
||||
|
||||
@@ -2317,8 +2348,16 @@ _kdc_tgs_rep(astgs_request_t r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
|
||||
i = 0;
|
||||
pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR);
|
||||
if (pa) {
|
||||
kdc_log(r->context, r->config, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
|
||||
ret = KRB5KRB_ERR_GENERIC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
|
||||
if(tgs_req == NULL){
|
||||
ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
|
||||
|
||||
@@ -2333,10 +2372,7 @@ _kdc_tgs_rep(astgs_request_t r)
|
||||
&e_text,
|
||||
from, from_addr,
|
||||
&csec, &cusec,
|
||||
&auth_data,
|
||||
&replykey,
|
||||
&header_key,
|
||||
&rk_is_subkey);
|
||||
&auth_data);
|
||||
if (ret == HDB_ERR_NOT_FOUND_HERE) {
|
||||
/* kdc_log() is called in tgs_parse_request() */
|
||||
goto out;
|
||||
@@ -2347,19 +2383,13 @@ _kdc_tgs_rep(astgs_request_t r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
{
|
||||
const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
|
||||
if (pa)
|
||||
kdc_log(context, config, 5, "Got TGS FAST request");
|
||||
}
|
||||
|
||||
ret = _kdc_fast_strengthen_reply_key(r);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = tgs_build_reply(r,
|
||||
krbtgt,
|
||||
krbtgt_etype,
|
||||
header_key,
|
||||
replykey,
|
||||
rk_is_subkey,
|
||||
ticket,
|
||||
&e_text,
|
||||
&auth_data,
|
||||
@@ -2378,21 +2408,15 @@ _kdc_tgs_rep(astgs_request_t r)
|
||||
}
|
||||
|
||||
out:
|
||||
if (replykey)
|
||||
krb5_free_keyblock(context, replykey);
|
||||
|
||||
if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
|
||||
/* XXX add fast wrapping on the error */
|
||||
METHOD_DATA error_method = { 0, NULL };
|
||||
|
||||
|
||||
kdc_log(context, config, 5, "tgs-req: sending error: %d to client", ret);
|
||||
ret = _kdc_fast_mk_error(r,
|
||||
&error_method,
|
||||
NULL,
|
||||
NULL,
|
||||
ret, NULL,
|
||||
NULL,
|
||||
r->armor_crypto,
|
||||
&req->req_body,
|
||||
ret, r->e_text,
|
||||
NULL, NULL,
|
||||
csec, cusec,
|
||||
data);
|
||||
@@ -2400,11 +2424,17 @@ out:
|
||||
}
|
||||
free(csec);
|
||||
free(cusec);
|
||||
|
||||
krb5_free_keyblock_contents(r->context, &r->reply_key);
|
||||
krb5_free_keyblock_contents(r->context, &r->strengthen_key);
|
||||
|
||||
if (ticket)
|
||||
krb5_free_ticket(context, ticket);
|
||||
if(krbtgt)
|
||||
_kdc_free_ent(context, krbtgt);
|
||||
|
||||
_kdc_free_fast_state(&r->fast);
|
||||
|
||||
if (auth_data) {
|
||||
free_AuthorizationData(auth_data);
|
||||
free(auth_data);
|
||||
|
@@ -1077,6 +1077,18 @@ get_new_tickets(krb5_context context,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_init_creds_store_config(context, ctx, tempccache);
|
||||
if (ret) {
|
||||
krb5_warn(context, ret, "krb5_init_creds_store_config");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5_init_creds_warn_user(context, ctx);
|
||||
if (ret) {
|
||||
krb5_warn(context, ret, "krb5_init_creds_warn_user");
|
||||
goto out;
|
||||
}
|
||||
|
||||
krb5_init_creds_free(context, ctx);
|
||||
ctx = NULL;
|
||||
|
||||
|
@@ -862,6 +862,8 @@ EXPORTS
|
||||
krb5_init_creds_set_sitename
|
||||
krb5_init_creds_step
|
||||
krb5_init_creds_store
|
||||
krb5_init_creds_store_config
|
||||
krb5_init_creds_warn_user
|
||||
krb5_process_last_request
|
||||
|
||||
; testing
|
||||
|
@@ -850,7 +850,9 @@ HEIMDAL_KRB5_2.0 {
|
||||
krb5_init_creds_set_sitename;
|
||||
krb5_init_creds_step;
|
||||
krb5_init_creds_store;
|
||||
krb5_init_creds_store_config;
|
||||
krb5_init_creds_free;
|
||||
krb5_init_creds_warn_user;
|
||||
|
||||
# testing
|
||||
krb5_time_abs;
|
||||
|
Reference in New Issue
Block a user