kdc: remove KRB5SignedPath, to be replaced with PAC
KRB5SignedPath was a Heimdal-specific authorization data element used to protect the authenticity of evidence tickets when used in constrained delegation (without a Windows PAC). Remove this, to be replaced with the Windows PAC which itself now supports signing the entire ticket in the TGS key.
This commit is contained in:

committed by
Luke Howard

parent
544515931b
commit
bb1d8f2a8c
@@ -2511,28 +2511,6 @@ _kdc_as_rep(astgs_request_t r)
|
||||
r->et.starttime, r->et.endtime,
|
||||
r->et.renew_till);
|
||||
|
||||
{
|
||||
krb5_principal client_principal;
|
||||
|
||||
ret = _krb5_principalname2krb5_principal(context, &client_principal,
|
||||
rep.cname, rep.crealm);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* do this as the last thing since this signs the EncTicketPart */
|
||||
ret = _kdc_add_KRB5SignedPath(context,
|
||||
config,
|
||||
r->server,
|
||||
setype,
|
||||
client_principal,
|
||||
NULL,
|
||||
NULL,
|
||||
&r->et);
|
||||
krb5_free_principal(context, client_principal);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
_log_astgs_req(r, setype);
|
||||
|
||||
/*
|
||||
|
301
kdc/krb5tgs.c
301
kdc/krb5tgs.c
@@ -47,231 +47,6 @@ get_krbtgt_realm(const PrincipalName *p)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The KDC might add a signed path to the ticket authorization data
|
||||
* field. This is to avoid server impersonating clients and the
|
||||
* request constrained delegation.
|
||||
*
|
||||
* This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
|
||||
* entry of type KRB5SignedPath.
|
||||
*/
|
||||
|
||||
static krb5_error_code
|
||||
find_KRB5SignedPath(krb5_context context,
|
||||
const AuthorizationData *ad,
|
||||
krb5_data *data)
|
||||
{
|
||||
AuthorizationData child;
|
||||
krb5_error_code ret;
|
||||
int pos;
|
||||
|
||||
if (ad == NULL || ad->len == 0)
|
||||
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
|
||||
|
||||
pos = ad->len - 1;
|
||||
|
||||
if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
|
||||
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
|
||||
|
||||
ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
|
||||
ad->val[pos].ad_data.length,
|
||||
&child,
|
||||
NULL);
|
||||
if (ret) {
|
||||
krb5_set_error_message(context, ret, "Failed to decode "
|
||||
"IF_RELEVANT with %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (child.len != 1) {
|
||||
free_AuthorizationData(&child);
|
||||
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
|
||||
}
|
||||
|
||||
if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
|
||||
free_AuthorizationData(&child);
|
||||
return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
|
||||
}
|
||||
|
||||
if (data)
|
||||
ret = der_copy_octet_string(&child.val[0].ad_data, data);
|
||||
free_AuthorizationData(&child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
krb5_error_code
|
||||
_kdc_add_KRB5SignedPath(krb5_context context,
|
||||
krb5_kdc_configuration *config,
|
||||
hdb_entry_ex *krbtgt,
|
||||
krb5_enctype enctype,
|
||||
krb5_const_principal client,
|
||||
krb5_const_principal server,
|
||||
krb5_principals principals,
|
||||
EncTicketPart *tkt)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
KRB5SignedPath sp;
|
||||
krb5_data data;
|
||||
krb5_crypto crypto = NULL;
|
||||
size_t size = 0;
|
||||
|
||||
if (server && principals) {
|
||||
ret = add_Principals(principals, server);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
{
|
||||
KRB5SignedPathData spd;
|
||||
|
||||
spd.client = rk_UNCONST(client);
|
||||
spd.authtime = tkt->authtime;
|
||||
spd.delegated = principals;
|
||||
spd.method_data = NULL;
|
||||
|
||||
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
|
||||
&spd, &size, ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (data.length != size)
|
||||
krb5_abortx(context, "internal asn.1 encoder error");
|
||||
}
|
||||
|
||||
{
|
||||
Key *key;
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, enctype, &key);
|
||||
if (ret == 0)
|
||||
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
|
||||
if (ret) {
|
||||
free(data.data);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in KRB5SignedPath
|
||||
*/
|
||||
|
||||
sp.etype = enctype;
|
||||
sp.delegated = principals;
|
||||
sp.method_data = NULL;
|
||||
|
||||
ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
|
||||
data.data, data.length, &sp.cksum);
|
||||
krb5_crypto_destroy(context, crypto);
|
||||
free(data.data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
|
||||
free_Checksum(&sp.cksum);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (data.length != size)
|
||||
krb5_abortx(context, "internal asn.1 encoder error");
|
||||
|
||||
|
||||
/*
|
||||
* Add IF-RELEVANT(KRB5SignedPath) to the last slot in
|
||||
* authorization data field.
|
||||
*/
|
||||
|
||||
ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
|
||||
KRB5_AUTHDATA_SIGNTICKET, &data);
|
||||
krb5_data_free(&data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
check_KRB5SignedPath(krb5_context context,
|
||||
krb5_kdc_configuration *config,
|
||||
hdb_entry_ex *krbtgt,
|
||||
krb5_principal cp,
|
||||
EncTicketPart *tkt,
|
||||
krb5_principals *delegated,
|
||||
int *signedpath)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_data data;
|
||||
krb5_crypto crypto = NULL;
|
||||
|
||||
if (delegated)
|
||||
*delegated = NULL;
|
||||
|
||||
ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
|
||||
if (ret == 0) {
|
||||
KRB5SignedPathData spd;
|
||||
KRB5SignedPath sp;
|
||||
size_t size = 0;
|
||||
|
||||
ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
|
||||
krb5_data_free(&data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spd.client = cp;
|
||||
spd.authtime = tkt->authtime;
|
||||
spd.delegated = sp.delegated;
|
||||
spd.method_data = sp.method_data;
|
||||
|
||||
ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
|
||||
&spd, &size, ret);
|
||||
if (ret) {
|
||||
free_KRB5SignedPath(&sp);
|
||||
return ret;
|
||||
}
|
||||
if (data.length != size)
|
||||
krb5_abortx(context, "internal asn.1 encoder error");
|
||||
|
||||
{
|
||||
Key *key;
|
||||
ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use correct kvno! */
|
||||
sp.etype, &key);
|
||||
if (ret == 0)
|
||||
ret = krb5_crypto_init(context, &key->key, 0, &crypto);
|
||||
if (ret) {
|
||||
free(data.data);
|
||||
free_KRB5SignedPath(&sp);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
|
||||
data.data, data.length,
|
||||
&sp.cksum);
|
||||
krb5_crypto_destroy(context, crypto);
|
||||
free(data.data);
|
||||
if (ret) {
|
||||
free_KRB5SignedPath(&sp);
|
||||
kdc_log(context, config, 4,
|
||||
"KRB5SignedPath not signed correctly, not marking as signed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delegated && sp.delegated) {
|
||||
|
||||
*delegated = malloc(sizeof(*sp.delegated));
|
||||
if (*delegated == NULL) {
|
||||
free_KRB5SignedPath(&sp);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
ret = copy_Principals(*delegated, sp.delegated);
|
||||
if (ret) {
|
||||
free_KRB5SignedPath(&sp);
|
||||
free(*delegated);
|
||||
*delegated = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
free_KRB5SignedPath(&sp);
|
||||
|
||||
*signedpath = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
@@ -773,7 +548,6 @@ tgs_make_reply(astgs_request_t r,
|
||||
const char *tgt_realm,
|
||||
hdb_entry_ex *krbtgt,
|
||||
krb5_enctype krbtgt_etype,
|
||||
krb5_principals spp,
|
||||
const krb5_data *rspac,
|
||||
const METHOD_DATA *enc_pa_data)
|
||||
{
|
||||
@@ -955,20 +729,6 @@ tgs_make_reply(astgs_request_t r,
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Filter out type KRB5SignedPath */
|
||||
ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
|
||||
if (ret == 0) {
|
||||
if (et.authorization_data->len == 1) {
|
||||
free_AuthorizationData(et.authorization_data);
|
||||
free(et.authorization_data);
|
||||
et.authorization_data = NULL;
|
||||
} else {
|
||||
AuthorizationData *ad = et.authorization_data;
|
||||
free_AuthorizationDataElement(&ad->val[ad->len - 1]);
|
||||
ad->len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
|
||||
@@ -997,24 +757,6 @@ tgs_make_reply(astgs_request_t r,
|
||||
_kdc_log_timestamp(r, "TGS-REQ", et.authtime, et.starttime,
|
||||
et.endtime, et.renew_till);
|
||||
|
||||
/* Don't sign cross realm tickets, they can't be checked anyway */
|
||||
{
|
||||
char *realm = get_krbtgt_realm(&ek.sname);
|
||||
|
||||
if (realm == NULL || strcmp(realm, ek.srealm) == 0) {
|
||||
ret = _kdc_add_KRB5SignedPath(context,
|
||||
config,
|
||||
krbtgt,
|
||||
krbtgt_etype,
|
||||
client_principal,
|
||||
NULL,
|
||||
spp,
|
||||
&et);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (enc_pa_data->len) {
|
||||
rep.padata = calloc(1, sizeof(*rep.padata));
|
||||
if (rep.padata == NULL) {
|
||||
@@ -1565,7 +1307,6 @@ tgs_build_reply(astgs_request_t priv,
|
||||
HDB *clientdb, *s4u2self_impersonated_clientdb;
|
||||
krb5_realm ref_realm = NULL;
|
||||
EncTicketPart *tgt = &ticket->ticket;
|
||||
krb5_principals spp = NULL;
|
||||
const EncryptionKey *ekey;
|
||||
krb5_keyblock sessionkey;
|
||||
krb5_kvno kvno;
|
||||
@@ -2067,24 +1808,6 @@ server_lookup:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* also check the krbtgt for signature */
|
||||
ret = check_KRB5SignedPath(context,
|
||||
config,
|
||||
krbtgt,
|
||||
cp,
|
||||
tgt,
|
||||
&spp,
|
||||
&signedpath);
|
||||
if (ret) {
|
||||
const char *msg = krb5_get_error_message(context, ret);
|
||||
_kdc_audit_addreason((kdc_request_t)priv, "KRB5SignedPath check failed");
|
||||
kdc_log(context, config, 4,
|
||||
"KRB5SignedPath check failed for %s (%s) from %s with %s",
|
||||
spn, cpn, from, msg);
|
||||
krb5_free_error_message(context, msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process request
|
||||
*/
|
||||
@@ -2417,29 +2140,6 @@ server_lookup:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the KDC issued the user's ticket.
|
||||
*/
|
||||
ret = check_KRB5SignedPath(context,
|
||||
config,
|
||||
krbtgt,
|
||||
cp,
|
||||
&adtkt,
|
||||
NULL,
|
||||
&ad_signedpath);
|
||||
if (ret) {
|
||||
const char *msg = krb5_get_error_message(context, ret);
|
||||
kdc_log(context, config, 4,
|
||||
"KRB5SignedPath check from service %s failed "
|
||||
"for delegation to %s for client %s (%s)"
|
||||
"from %s failed with %s",
|
||||
spn, tpn, dpn, cpn, from, msg);
|
||||
krb5_free_error_message(context, msg);
|
||||
_kdc_audit_addreason((kdc_request_t)priv,
|
||||
"KRB5SignedPath check failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ad_signedpath) {
|
||||
ret = KRB5KDC_ERR_BADOPTION;
|
||||
kdc_log(context, config, 4,
|
||||
@@ -2549,7 +2249,6 @@ server_lookup:
|
||||
tgt_realm,
|
||||
krbtgt_out,
|
||||
tkey_sign->key.keytype,
|
||||
spp,
|
||||
&rspac,
|
||||
&enc_pa_data);
|
||||
|
||||
|
@@ -43,9 +43,6 @@ EXPORTS
|
||||
KRB-PRIV,
|
||||
KRB-SAFE,
|
||||
KRB-SAFE-BODY,
|
||||
KRB5SignedPath,
|
||||
KRB5SignedPathData,
|
||||
KRB5SignedPathPrincipals,
|
||||
KerberosString,
|
||||
KerberosTime,
|
||||
KrbCredInfo,
|
||||
@@ -753,24 +750,6 @@ PA-S4U2Self ::= SEQUENCE {
|
||||
auth[3] GeneralString
|
||||
}
|
||||
|
||||
-- never encoded on the wire, just used to checksum over
|
||||
KRB5SignedPathData ::= SEQUENCE {
|
||||
client[0] Principal OPTIONAL,
|
||||
authtime[1] KerberosTime,
|
||||
delegated[2] Principals OPTIONAL,
|
||||
method_data[3] METHOD-DATA OPTIONAL
|
||||
}
|
||||
|
||||
KRB5SignedPath ::= SEQUENCE {
|
||||
-- DERcoded KRB5SignedPathData
|
||||
-- krbtgt key (etype), KeyUsage = XXX
|
||||
etype[0] ENCTYPE,
|
||||
cksum[1] Checksum,
|
||||
-- srvs delegated though
|
||||
delegated[2] Principals OPTIONAL,
|
||||
method_data[3] METHOD-DATA OPTIONAL
|
||||
}
|
||||
|
||||
AD-LoginAlias ::= SEQUENCE { -- ad-type number TBD --
|
||||
login-alias [0] PrincipalName,
|
||||
checksum [1] Checksum
|
||||
|
@@ -459,8 +459,6 @@ EXPORTS
|
||||
copy_KeyUsage
|
||||
copy_Krb5Int32
|
||||
copy_KRB5PrincipalName
|
||||
copy_KRB5SignedPath
|
||||
copy_KRB5SignedPathData
|
||||
copy_Krb5UInt32
|
||||
copy_KRB_CRED
|
||||
copy_KrbCredInfo
|
||||
@@ -820,8 +818,6 @@ EXPORTS
|
||||
decode_KeyUsage
|
||||
decode_Krb5Int32
|
||||
decode_KRB5PrincipalName
|
||||
decode_KRB5SignedPath
|
||||
decode_KRB5SignedPathData
|
||||
decode_Krb5UInt32
|
||||
decode_KRB_CRED
|
||||
decode_KrbCredInfo
|
||||
@@ -1327,8 +1323,6 @@ EXPORTS
|
||||
encode_KeyUsage
|
||||
encode_Krb5Int32
|
||||
encode_KRB5PrincipalName
|
||||
encode_KRB5SignedPath
|
||||
encode_KRB5SignedPathData
|
||||
encode_Krb5UInt32
|
||||
encode_KRB_CRED
|
||||
encode_KrbCredInfo
|
||||
@@ -1689,8 +1683,6 @@ EXPORTS
|
||||
free_KeyUsage
|
||||
free_Krb5Int32
|
||||
free_KRB5PrincipalName
|
||||
free_KRB5SignedPath
|
||||
free_KRB5SignedPathData
|
||||
free_Krb5UInt32
|
||||
free_KRB_CRED
|
||||
free_KrbCredInfo
|
||||
@@ -2070,8 +2062,6 @@ EXPORTS
|
||||
length_KeyUsage
|
||||
length_Krb5Int32
|
||||
length_KRB5PrincipalName
|
||||
length_KRB5SignedPath
|
||||
length_KRB5SignedPathData
|
||||
length_Krb5UInt32
|
||||
length_KRB_CRED
|
||||
length_KrbCredInfo
|
||||
@@ -2431,8 +2421,6 @@ EXPORTS
|
||||
print_KeyUsage
|
||||
print_Krb5Int32
|
||||
print_KRB5PrincipalName
|
||||
print_KRB5SignedPath
|
||||
print_KRB5SignedPathData
|
||||
print_Krb5UInt32
|
||||
print_KRB_CRED
|
||||
print_KrbCredInfo
|
||||
|
@@ -903,7 +903,7 @@ ${kimpersonate} -s ${ps} -c bar@${R} -t ${aesenctype} || \
|
||||
${kgetcred} --out-cache=${o2cache} --delegation-credential-cache=${ocache} ${server}@${R} > /dev/null 2>/dev/null && \
|
||||
{ ec=1 ; eval "${testfailed}"; }
|
||||
|
||||
echo "test constrained delegation impersonation (missing KRB5SignedPath)"; > messages.log
|
||||
echo "test constrained delegation impersonation (missing PAC)"; > messages.log
|
||||
rm -f ocache.krb5
|
||||
${kimpersonate} -s ${ps} -c bar@${R} -t ${aesenctype} -f forwardable || \
|
||||
{ ec=1 ; eval "${testfailed}"; }
|
||||
|
Reference in New Issue
Block a user