From 4112f6fc79c65e68cd8b03ab56567aa9804069df Mon Sep 17 00:00:00 2001 From: Joseph Sutton Date: Tue, 16 Nov 2021 13:04:44 +1300 Subject: [PATCH] kdc: Use sname from request rather than user-to-user TGT client name Assists Samba to address CVE-2020-25719 This may be contary to RFC4120 3.3.3 at https://datatracker.ietf.org/doc/html/rfc4120/#section-3.3.3 (clearer in the GSS mechanism here: https://datatracker.ietf.org/doc/html/draft-swift-win2k-krb-user2user-03 ) as server-name is decribed as optional, however Windows AD and Samba both require that the server-name exist and be a valid SPN matching the provided TGT. The lookup of SPN -> entry ensures that the SPN the client thought it was connecting to was held by the target server. it could be the typical user principal, or a service principal, but needs to be checked for the client not to be fooled into connecting to the wrong service. Samba BUG: https://bugzilla.samba.org/show_bug.cgi?id=14873 Signed-off-by: Joseph Sutton Reviewed-by: Andrew Bartlett (Similar to Samba commit fd50fecbe99ae4fc63843c796d0a516731a1fe6a) --- kdc/krb5tgs.c | 147 +++++++++++++++++++++++++------------------------- 1 file changed, 72 insertions(+), 75 deletions(-) diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index dd556004d..66d6a5fcf 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -1429,81 +1429,7 @@ tgs_build_reply(astgs_request_t priv, if (b->kdc_options.canonicalize) flags |= HDB_F_CANON; - 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; - - if(b->additional_tickets == NULL || - b->additional_tickets->len == 0){ - ret = KRB5KDC_ERR_BADOPTION; /* ? */ - kdc_log(context, config, 4, - "No second ticket present in user-to-user request"); - _kdc_audit_addreason((kdc_request_t)priv, - "No second ticket present in user-to-user request"); - goto out; - } - t = &b->additional_tickets->val[0]; - if(!get_krbtgt_realm(&t->sname)){ - kdc_log(context, config, 4, - "Additional ticket is not a ticket-granting ticket"); - _kdc_audit_addreason((kdc_request_t)priv, - "Additional ticket is not a ticket-granting ticket"); - ret = KRB5KDC_ERR_POLICY; - goto out; - } - ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); - if (ret) - goto out; - - ret = krb5_unparse_name(context, p, &tpn); - if (ret) - goto out; - if(t->enc_part.kvno){ - second_kvno = *t->enc_part.kvno; - kvno_ptr = &second_kvno; - } - ret = _kdc_db_fetch(context, config, p, - HDB_F_GET_KRBTGT, kvno_ptr, - NULL, &uu); - krb5_free_principal(context, p); - if(ret){ - if (ret == HDB_ERR_NOENTRY) - ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; - _kdc_audit_addreason((kdc_request_t)priv, - "User-to-user service principal (TGS) unknown"); - goto out; - } - ret = hdb_enctype2key(context, &uu->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"); - goto out; - } - - ret = _kdc_verify_flags(context, config, &adtkt, tpn); - if (ret) { - _kdc_audit_addreason((kdc_request_t)priv, - "User-to-user TGT expired or invalid"); - goto out; - } - - s = &adtkt.cname; - r = adtkt.crealm; - } else if (s == NULL) { + if (s == NULL) { ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; _kdc_set_e_text(priv, "No server in request"); goto out; @@ -1713,7 +1639,78 @@ server_lookup: krb5_enctype etype; 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; + + if(b->additional_tickets == NULL || + b->additional_tickets->len == 0){ + ret = KRB5KDC_ERR_BADOPTION; /* ? */ + kdc_log(context, config, 4, + "No second ticket present in user-to-user request"); + _kdc_audit_addreason((kdc_request_t)priv, + "No second ticket present in user-to-user request"); + goto out; + } + t = &b->additional_tickets->val[0]; + if(!get_krbtgt_realm(&t->sname)){ + kdc_log(context, config, 4, + "Additional ticket is not a ticket-granting ticket"); + _kdc_audit_addreason((kdc_request_t)priv, + "Additional ticket is not a ticket-granting ticket"); + ret = KRB5KDC_ERR_POLICY; + goto out; + } + ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); + if (ret) + goto out; + + ret = krb5_unparse_name(context, p, &tpn); + if (ret) + goto out; + if(t->enc_part.kvno){ + second_kvno = *t->enc_part.kvno; + kvno_ptr = &second_kvno; + } + ret = _kdc_db_fetch(context, config, p, + HDB_F_GET_KRBTGT, kvno_ptr, + NULL, &uu); + krb5_free_principal(context, p); + if(ret){ + if (ret == HDB_ERR_NOENTRY) + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + _kdc_audit_addreason((kdc_request_t)priv, + "User-to-user service principal (TGS) unknown"); + goto out; + } + ret = hdb_enctype2key(context, &uu->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"); + goto out; + } + + ret = _kdc_verify_flags(context, config, &adtkt, tpn); + if (ret) { + _kdc_audit_addreason((kdc_request_t)priv, + "User-to-user TGT expired or invalid"); + goto out; + } + ekey = &adtkt.key; for(i = 0; i < b->etype.len; i++) if (b->etype.val[i] == adtkt.key.keytype)