diff --git a/NEWS b/NEWS index ccc06ffc8..79efe803a 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,17 @@ +Release Notes - Heimdal - Version Heimdal 7.3 + + Security + + - Fix transit path validation. Commit f469fc6 (2010-10-02) inadvertently + caused the previous hop realm to not be added to the transit path + of issued tickets. This may, in some cases, enable bypass of capath + policy in Heimdal versions 1.5 through 7.2. + + Note, this may break sites that rely on the bug. With the bug some + incomplete [capaths] worked, that should not have. These may now break + authentication in some cross-realm configurations. + (CVE-2017-6594) + Release Notes - Heimdal - Version Heimdal 7.2 Bug fixes diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 6048b9c55..98503812f 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -655,8 +655,12 @@ fix_transited_encoding(krb5_context context, "Decoding transited encoding"); return ret; } + + /* + * If the realm of the presented tgt is neither the client nor the server + * realm, it is a transit realm and must be added to transited set. + */ if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) { - /* not us, so add the previous realm to transited set */ if (num_realms + 1 > UINT_MAX/sizeof(*realms)) { ret = ERANGE; goto free_realms; @@ -737,6 +741,7 @@ tgs_make_reply(krb5_context context, const char *server_name, hdb_entry_ex *client, krb5_principal client_principal, + const char *tgt_realm, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, krb5_principals spp, @@ -798,7 +803,7 @@ tgs_make_reply(krb5_context context, &tgt->transited, &et, krb5_principal_get_realm(context, client_principal), krb5_principal_get_realm(context, server->entry.principal), - krb5_principal_get_realm(context, krbtgt->entry.principal)); + tgt_realm); if(ret) goto out; @@ -1519,6 +1524,8 @@ tgs_build_reply(krb5_context context, krb5_keyblock sessionkey; krb5_kvno kvno; krb5_data rspac; + const char *tgt_realm = /* Realm of TGT issuer */ + krb5_principal_get_realm(context, krbtgt->entry.principal); const char *our_realm = /* Realm of this KDC */ krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1); char **capath = NULL; @@ -2324,6 +2331,7 @@ server_lookup: spn, client, cp, + tgt_realm, krbtgt_out, tkey_sign->key.keytype, spp, diff --git a/tests/kdc/check-kdc.in b/tests/kdc/check-kdc.in index 962d5468a..b9174e4db 100644 --- a/tests/kdc/check-kdc.in +++ b/tests/kdc/check-kdc.in @@ -53,6 +53,7 @@ R4=TEST4.H5L.SE R5=SOME-REALM5.FR R6=SOME-REALM6.US R7=SOME-REALM7.UK +R8=SOME-REALM8.UK H1=H1.$R H2=H2.$R @@ -148,6 +149,12 @@ ${kadmin} \ --realm-max-renewable-life=1month \ ${R7} || exit 1 +${kadmin} \ + init \ + --realm-max-ticket-life=1day \ + --realm-max-renewable-life=1month \ + ${R8} || exit 1 + ${kadmin} \ init \ --realm-max-ticket-life=1day \ @@ -191,6 +198,7 @@ ${kadmin} add -p foo --use-defaults foo@${R4} || exit 1 ${kadmin5} add -p foo --use-defaults foo@${R5} || exit 1 ${kadmin} add -p foo --use-defaults foo@${R6} || exit 1 ${kadmin} add -p foo --use-defaults foo@${R7} || exit 1 +${kadmin} add -p foo --use-defaults foo@${R8} || exit 1 ${kadmin} add -p foo --use-defaults foo@${H1} || exit 1 ${kadmin} add -p foo --use-defaults foo/host.${h1}@${H1} || exit 1 ${kadmin} add -p foo --use-defaults foo@${H2} || exit 1 @@ -249,6 +257,9 @@ ${kadmin} add -p cross2 --use-defaults krbtgt/${R5}@${R6} || exit 1 ${kadmin} add -p cross1 --use-defaults krbtgt/${R7}@${R6} || exit 1 ${kadmin} add -p cross2 --use-defaults krbtgt/${R6}@${R7} || exit 1 +${kadmin} add -p cross1 --use-defaults krbtgt/${R8}@${R6} || exit 1 +${kadmin} add -p cross2 --use-defaults krbtgt/${R6}@${R8} || exit 1 + ${kadmin} add -p cross1 --use-defaults krbtgt/${H1}@${R} || exit 1 ${kadmin} add -p cross2 --use-defaults krbtgt/${R}@${H1} || exit 1 @@ -284,6 +295,7 @@ ${kadmin} check ${R4} || exit 1 ${kadmin5} check ${R5} || exit 1 ${kadmin} check ${R6} || exit 1 ${kadmin} check ${R7} || exit 1 +${kadmin} check ${R8} || exit 1 ${kadmin} check ${H1} || exit 1 ${kadmin} check ${H2} || exit 1 ${kadmin} check ${H3} || exit 1 @@ -388,6 +400,8 @@ echo "Getting x-realm tickets with capaths for $R -> $R6" ${kgetcred} foo@${R6} || { ec=1 ; eval "${testfailed}"; } echo "Getting x-realm tickets with capaths for $R -> $R7" ${kgetcred} foo@${R7} || { ec=1 ; eval "${testfailed}"; } +echo "Should not get x-realm tickets with capaths for $R -> $R8" +${kgetcred} foo@${R8} && { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Testing capaths logic (reverse order)" @@ -418,10 +432,13 @@ ${kinit} --password-file=${objdir}/foopassword \ echo "Getting x-realm tickets with hierarchical referrals for $H3 -> $H1" ${kgetcred} --hostbased --canonicalize foo host.${h1} || { ec=1 ; eval "${testfailed}"; } +fgrep "cross-realm ${H3} -> ${H1} via [${H2}, ${R}]" messages.log > /dev/null || { ec=1 ; eval "${testfailed}"; } echo "Getting x-realm tickets with hierarchical referrals for $H3 -> $R" ${kgetcred} --hostbased --canonicalize foo host.${r} || { ec=1 ; eval "${testfailed}"; } +fgrep "cross-realm ${H3} -> ${R} via [${H2}]" messages.log > /dev/null || { ec=1 ; eval "${testfailed}"; } echo "Getting x-realm tickets with hierarchical referrals for $H3 -> $H2" ${kgetcred} --hostbased --canonicalize foo host.${h2} || { ec=1 ; eval "${testfailed}"; } +fgrep "cross-realm ${H3} -> ${H2}" messages.log > /dev/null || { ec=1 ; eval "${testfailed}"; } ${kdestroy} echo "Testing multi-hop [capaths] referral logic" diff --git a/tests/kdc/krb5.conf.in b/tests/kdc/krb5.conf.in index cc2dedb2d..849e773d0 100644 --- a/tests/kdc/krb5.conf.in +++ b/tests/kdc/krb5.conf.in @@ -40,6 +40,9 @@ SOME-REALM7.UK = { kdc = localhost:@port@ } + SOME-REALM8.UK = { + kdc = localhost:@port@ + } TEST-HTTP.H5L.SE = { kdc = http/localhost:@port@ } @@ -147,6 +150,7 @@ SOME-REALM6.US = SOME-REALM5.FR SOME-REALM7.UK = SOME-REALM6.US SOME-REALM7.UK = SOME-REALM5.FR + SOME-REALM8.UK = SOME-REALM6.US } H4.H2.TEST.H5L.SE = { H1.TEST.H5L.SE = H3.H2.TEST.H5L.SE