kdc: Verify PAC in TGT provided for user-to-user authentication

Assists Samba to address CVE-2020-25719

It is critical to ensure that the name in the U2U TGT is still associated with
the account was issued to, so we must check the PAC to verify the SID.

Otherwise the SPN check via the S4U2Self hook might be mislead.

Samba BUG: https://bugzilla.samba.org/show_bug.cgi?id=14873

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>

(Similar to Samba commit 49a13f0fc942d1cfb767d5b6bf49d62241d52046)
This commit is contained in:
Joseph Sutton
2021-11-16 13:14:48 +13:00
committed by Luke Howard
parent 3e197ecbee
commit 87348cf27a

View File

@@ -1396,6 +1396,7 @@ tgs_build_reply(astgs_request_t priv,
char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
char *user2user_name = NULL;
hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
hdb_entry_ex *user2user_krbtgt = NULL;
HDB *clientdb, *s4u2self_impersonated_clientdb;
HDB *serverdb = NULL;
krb5_realm ref_realm = NULL;
@@ -1404,6 +1405,7 @@ tgs_build_reply(astgs_request_t priv,
krb5_keyblock sessionkey;
krb5_kvno kvno;
krb5_pac mspac = NULL;
krb5_pac user2user_pac = NULL;
uint16_t rodc_id;
krb5_boolean add_ticket_sig = FALSE;
const char *tgt_realm = /* Realm of TGT issuer */
@@ -1653,13 +1655,13 @@ server_lookup:
if(b->kdc_options.enc_tkt_in_skey) {
Ticket *t;
hdb_entry_ex *uu;
krb5_principal p;
Key *uukey;
krb5uint32 second_kvno = 0;
krb5uint32 *kvno_ptr = NULL;
size_t i;
hdb_entry_ex *user2user_client = NULL;
krb5_boolean user2user_kdc_issued = FALSE;
if(b->additional_tickets == NULL ||
b->additional_tickets->len == 0){
@@ -1692,7 +1694,7 @@ server_lookup:
}
ret = _kdc_db_fetch(context, config, p,
HDB_F_GET_KRBTGT, kvno_ptr,
NULL, &uu);
NULL, &user2user_krbtgt);
krb5_free_principal(context, p);
if(ret){
if (ret == HDB_ERR_NOENTRY)
@@ -1701,17 +1703,15 @@ server_lookup:
"User-to-user service principal (TGS) unknown");
goto out;
}
ret = hdb_enctype2key(context, &uu->entry, NULL,
ret = hdb_enctype2key(context, &user2user_krbtgt->entry, NULL,
t->enc_part.etype, &uukey);
if(ret){
_kdc_free_ent(context, uu);
ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user enctype not supported");
goto out;
}
ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
_kdc_free_ent(context, uu);
if(ret) {
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user TGT decrypt failure");
@@ -1783,7 +1783,27 @@ server_lookup:
goto out;
}
/* Verify the PAC of the TGT. */
ret = _kdc_check_pac(context, config, user2user_princ, NULL,
user2user_client, user2user_krbtgt, user2user_krbtgt, user2user_krbtgt,
&uukey->key, &priv->ticket_key->key, &adtkt, &user2user_kdc_issued, &user2user_pac);
_kdc_free_ent(context, user2user_client);
if (ret) {
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0,
"Verify PAC failed for %s (%s) from %s with %s",
spn, user2user_name, from, msg);
krb5_free_error_message(context, msg);
goto out;
}
if (user2user_pac == NULL || !user2user_kdc_issued) {
ret = KRB5KDC_ERR_BADOPTION;
kdc_log(context, config, 0,
"Ticket not signed with PAC; user-to-user failed (%s).",
user2user_pac ? "Ticket unsigned" : "No PAC");
goto out;
}
ekey = &adtkt.key;
for(i = 0; i < b->etype.len; i++)
@@ -2394,6 +2414,8 @@ out:
_kdc_free_ent(context, client);
if(s4u2self_impersonated_client)
_kdc_free_ent(context, s4u2self_impersonated_client);
if(user2user_krbtgt)
_kdc_free_ent(context, user2user_krbtgt);
krb5_free_principal(context, user2user_princ);
if (tp && tp != cp)
@@ -2408,6 +2430,7 @@ out:
free_EncTicketPart(&adtkt);
krb5_pac_free(context, mspac);
krb5_pac_free(context, user2user_pac);
return ret;
}