krb5: Add support for AD-KDC-ISSUED

This commit is contained in:
Nicolas Williams
2021-12-29 11:59:59 -06:00
committed by Nico Williams
parent 87f8c0d2b5
commit 1cede09a0b
3 changed files with 65 additions and 19 deletions

View File

@@ -462,8 +462,9 @@ PrincipalNameAttrSrc ::= CHOICE {
enc-ticket-part [1] EncTicketPart -- minus session key enc-ticket-part [1] EncTicketPart -- minus session key
} }
PrincipalNameAttrs ::= SEQUENCE { PrincipalNameAttrs ::= SEQUENCE {
-- True if this name was authenticated via an AP-REQ or a KDC-REP
authenticated [0] BOOLEAN, authenticated [0] BOOLEAN,
-- These are compiled from the Ticket and Authenticator: -- These are compiled from the Ticket, KDC-REP, and/or Authenticator
source [1] PrincipalNameAttrSrc OPTIONAL, source [1] PrincipalNameAttrSrc OPTIONAL,
authenticator-ad [2] AuthorizationData OPTIONAL, authenticator-ad [2] AuthorizationData OPTIONAL,
-- For the server on the client side we should keep track of the -- For the server on the client side we should keep track of the
@@ -472,7 +473,10 @@ PrincipalNameAttrs ::= SEQUENCE {
-- We don't learn much more about the server from the KDC. -- We don't learn much more about the server from the KDC.
peer-realm [3] Realm OPTIONAL, peer-realm [3] Realm OPTIONAL,
transited [4] TransitedEncoding OPTIONAL, transited [4] TransitedEncoding OPTIONAL,
pac-verified [5] BOOLEAN -- True if the PAC was verified
pac-verified [5] BOOLEAN,
-- True if any AD-KDC-ISSUEDs in the Ticket were validated
kdc-issued-verified [6] BOOLEAN
-- TODO: Add requested attributes, for gss_set_name_attribute(), which -- TODO: Add requested attributes, for gss_set_name_attribute(), which
-- should cause corresponding authz-data elements to be added to -- should cause corresponding authz-data elements to be added to
-- any TGS-REQ or to the AP-REQ's Authenticator as appropriate. -- any TGS-REQ or to the AP-REQ's Authenticator as appropriate.

View File

@@ -1037,6 +1037,12 @@ krb5_rd_req_ctx(krb5_context context,
goto out; goto out;
} }
ret = krb5_ticket_get_authorization_data_type(context, o->ticket,
KRB5_AUTHDATA_KDC_ISSUED,
NULL);
if (ret == 0)
o->ticket->client->nameattrs->kdc_issued_verified = 1;
/* If there is a PAC, verify its server signature */ /* If there is a PAC, verify its server signature */
if (inctx == NULL || inctx->check_pac) { if (inctx == NULL || inctx->check_pac) {
krb5_pac pac; krb5_pac pac;

View File

@@ -204,13 +204,38 @@ krb5_ticket_get_flags(krb5_context context,
return TicketFlags2int(ticket->ticket.flags); return TicketFlags2int(ticket->ticket.flags);
} }
/*
* Find an authz-data element in the given `ad'. If `failp', then validate any
* containing AD-KDC-ISSUED's keyed checksum with the `sessionkey' (if given).
*
* All AD-KDC-ISSUED will be validated (if requested) even when `type' is
* `KRB5_AUTHDATA_KDC_ISSUED'.
*
* Only the first matching element will be output (via `data').
*
* Note that all AD-KDC-ISSUEDs found while traversing the authz-data will be
* validated, though only the first one will be returned.
*
* XXX We really need a better interface though. First, forget AD-AND-OR --
* just remove it. Second, probably forget AD-KDC-ISSUED, but still, between
* that, the PAC, and the CAMMAC, we need an interface that can:
*
* a) take the derived keys instead of the service key or the session key,
* b) can indicate whether the element was marked critical,
* c) can indicate whether the element was authenticated to the KDC,
* d) can iterate over all the instances found (if more than one is found).
*
* Also, we need to know here if the authz-data is from a Ticket or from an
* Authenticator -- if the latter then we must refuse to find AD-KDC-ISSUED /
* PAC / CAMMAC or anything of the sort, ever.
*/
static int static int
find_type_in_ad(krb5_context context, find_type_in_ad(krb5_context context,
int type, int type,
krb5_data *data, krb5_data *data, /* optional */
krb5_boolean *found, krb5_boolean *found,
krb5_boolean failp, krb5_boolean failp, /* validate AD-KDC-ISSUED */
krb5_keyblock *sessionkey, krb5_keyblock *sessionkey, /* ticket session key */
const AuthorizationData *ad, const AuthorizationData *ad,
int level) int level)
{ {
@@ -233,14 +258,19 @@ find_type_in_ad(krb5_context context,
*/ */
for (i = 0; i < ad->len; i++) { for (i = 0; i < ad->len; i++) {
if (!*found && ad->val[i].ad_type == type) { if (!*found && ad->val[i].ad_type == type) {
ret = der_copy_octet_string(&ad->val[i].ad_data, data); if (data) {
if (ret) { ret = der_copy_octet_string(&ad->val[i].ad_data, data);
krb5_set_error_message(context, ret, if (ret) {
N_("malloc: out of memory", "")); krb5_set_error_message(context, ret,
goto out; N_("malloc: out of memory", ""));
} goto out;
}
}
*found = TRUE; *found = TRUE;
continue; if (type != KRB5_AUTHDATA_KDC_ISSUED ||
!failp || !sessionkey || !sessionkey->keyvalue.length)
continue;
/* else go on to validate the AD-KDC-ISSUED's keyed checksum */
} }
switch (ad->val[i].ad_type) { switch (ad->val[i].ad_type) {
case KRB5_AUTHDATA_IF_RELEVANT: { case KRB5_AUTHDATA_IF_RELEVANT: {
@@ -263,7 +293,6 @@ find_type_in_ad(krb5_context context,
goto out; goto out;
break; break;
} }
#if 0 /* XXX test */
case KRB5_AUTHDATA_KDC_ISSUED: { case KRB5_AUTHDATA_KDC_ISSUED: {
AD_KDCIssued child; AD_KDCIssued child;
@@ -278,7 +307,7 @@ find_type_in_ad(krb5_context context,
ret); ret);
goto out; goto out;
} }
if (failp) { if (failp && sessionkey && sessionkey->keyvalue.length) {
krb5_boolean valid; krb5_boolean valid;
krb5_data buf; krb5_data buf;
size_t len; size_t len;
@@ -306,7 +335,12 @@ find_type_in_ad(krb5_context context,
free_AD_KDCIssued(&child); free_AD_KDCIssued(&child);
goto out; goto out;
} }
} } else if (failp) {
krb5_clear_error_message(context);
ret = ENOENT;
free_AD_KDCIssued(&child);
goto out;
}
ret = find_type_in_ad(context, type, data, found, failp, sessionkey, ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
&child.elements, level + 1); &child.elements, level + 1);
free_AD_KDCIssued(&child); free_AD_KDCIssued(&child);
@@ -314,7 +348,6 @@ find_type_in_ad(krb5_context context,
goto out; goto out;
break; break;
} }
#endif
case KRB5_AUTHDATA_AND_OR: case KRB5_AUTHDATA_AND_OR:
if (!failp) if (!failp)
break; break;
@@ -338,7 +371,8 @@ find_type_in_ad(krb5_context context,
out: out:
if (ret) { if (ret) {
if (*found) { if (*found) {
krb5_data_free(data); if (data)
krb5_data_free(data);
*found = 0; *found = 0;
} }
} }
@@ -355,7 +389,8 @@ _krb5_get_ad(krb5_context context,
krb5_boolean found = FALSE; krb5_boolean found = FALSE;
krb5_error_code ret; krb5_error_code ret;
krb5_data_zero(data); if (data)
krb5_data_zero(data);
if (ad == NULL) { if (ad == NULL) {
krb5_set_error_message(context, ENOENT, krb5_set_error_message(context, ENOENT,
@@ -399,7 +434,8 @@ krb5_ticket_get_authorization_data_type(krb5_context context,
krb5_error_code ret; krb5_error_code ret;
krb5_boolean found = FALSE; krb5_boolean found = FALSE;
krb5_data_zero(data); if (data)
krb5_data_zero(data);
ad = ticket->ticket.authorization_data; ad = ticket->ticket.authorization_data;
if (ticket->ticket.authorization_data == NULL) { if (ticket->ticket.authorization_data == NULL) {