Optional backwards-compatible anon-pkinit behaviour

* Anonymous pkinit responses from the KDC where the name
  type is not well-known (as issued by 7.5 KDCs and earlier)
  are accepted by the client.  There is no need for the client
  to strictly enforce the name type.

* With historical_anon_pkinit = true, the kinit(1) client's
  "--anonymous" option only performs anon pkinit, and does
  not require an '@' prefix for the realm argument.

* With historical_anon_realm = true, the KDC issues anon
  pkinit tickets with the legacy pre-7.0 "real" realm.
This commit is contained in:
Viktor Dukhovni
2019-07-14 23:02:57 -04:00
committed by Viktor Dukhovni
parent f40d393c83
commit fae8df3839
11 changed files with 141 additions and 27 deletions

View File

@@ -59,6 +59,7 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config)
c->check_ticket_addresses = TRUE;
c->allow_null_ticket_addresses = TRUE;
c->allow_anonymous = FALSE;
c->historical_anon_realm = FALSE;
c->strict_nametypes = FALSE;
c->trpolicy = TRPOLICY_ALWAYS_CHECK;
c->enable_pkinit = FALSE;
@@ -162,6 +163,12 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config)
"kdc",
"allow-anonymous", NULL);
c->historical_anon_realm =
krb5_config_get_bool_default(context, NULL,
c->historical_anon_realm,
"kdc",
"historical_anon_realm", NULL);
c->strict_nametypes =
krb5_config_get_bool_default(context, NULL,
c->strict_nametypes,

View File

@@ -141,6 +141,19 @@ Permit tickets with no addresses.
This option is only relevant when check-ticket-addresses is TRUE.
.It Li allow-anonymous = Va boolean
Permit anonymous tickets with no addresses.
.It Li historical_anon_realm = Va boolean
Enables pre-7.0 non-RFC-comformant KDC behavior.
With this option set to
.Li true
the client realm in anonymous pkinit AS replies will be the requested realm,
rather than the RFC-conformant
.Li WELLKNOWN:ANONYMOUS
realm.
This can have a security impact on servers that expect to grant access to
anonymous-but-authenticated to the KDC users of the realm in question:
they would also grant access to unauthenticated anonymous users.
As such, it is not recommend to set this option to
.Li true.
.It Li max-kdc-datagram-reply-length = Va number
Maximum packet size the UDP rely that the KDC will transmit, instead
the KDC sends back a reply telling the client to use TCP instead.

View File

@@ -69,6 +69,7 @@ typedef struct krb5_kdc_configuration {
krb5_boolean check_ticket_addresses;
krb5_boolean allow_null_ticket_addresses;
krb5_boolean allow_anonymous;
krb5_boolean historical_anon_realm;
krb5_boolean strict_nametypes;
enum krb5_kdc_trpolicy trpolicy;

View File

@@ -117,10 +117,10 @@ is_default_salt_p(const krb5_salt *default_salt, const Key *key)
}
static krb5_boolean
is_anon_as_request_p(kdc_request_t r)
krb5_boolean
_kdc_is_anon_request(const KDC_REQ *req)
{
KDC_REQ_BODY *b = &r->req.req_body;
const KDC_REQ_BODY *b = &req->req_body;
/*
* Versions of Heimdal from 0.9rc1 through 1.50 use bit 14 instead
@@ -464,7 +464,7 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa)
heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST");
if (is_anon_as_request_p(r)) {
if (_kdc_is_anon_request(&r->req)) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
kdc_log(r->context, r->config, 0, "ENC-CHALL doesn't support anon");
return ret;
@@ -1795,7 +1795,7 @@ _kdc_as_rep(kdc_request_t r,
*/
if (_kdc_is_anonymous(context, r->client_princ) &&
!is_anon_as_request_p(r)) {
!_kdc_is_anon_request(&r->req)) {
kdc_log(context, config, 0, "Anonymous client w/o anonymous flag");
ret = KRB5KDC_ERR_BADOPTION;
goto out;
@@ -1969,7 +1969,7 @@ _kdc_as_rep(kdc_request_t r,
* send requre preauth is its required or anon is requested,
* anon is today only allowed via preauth mechanisms.
*/
if (require_preauth_p(r) || is_anon_as_request_p(r)) {
if (require_preauth_p(r) || _kdc_is_anon_request(&r->req)) {
ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
_kdc_set_e_text(r, "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ");
goto out;
@@ -2002,7 +2002,7 @@ _kdc_as_rep(kdc_request_t r,
if(ret)
goto out;
if (is_anon_as_request_p(r)) {
if (_kdc_is_anon_request(&r->req)) {
ret = _kdc_check_anon_policy(context, config, r->client, r->server);
if (ret) {
_kdc_set_e_text(r, "Anonymous ticket requests are disabled");
@@ -2036,7 +2036,8 @@ _kdc_as_rep(kdc_request_t r,
rep.pvno = 5;
rep.msg_type = krb_as_rep;
if (_kdc_is_anonymous(context, r->client_princ)) {
if (!config->historical_anon_realm &&
_kdc_is_anonymous(context, r->client_princ)) {
Realm anon_realm = KRB5_ANON_REALM;
ret = copy_Realm(&anon_realm, &rep.crealm);
} else if (f.canonicalize || r->client->entry.flags.force_canonicalize)

View File

@@ -623,7 +623,8 @@ _kdc_pk_rd_padata(krb5_context context,
hx509_certs signer_certs;
int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */
if (_kdc_is_anonymous(context, client->entry.principal))
if (_kdc_is_anonymous(context, client->entry.principal)
|| (config->historical_anon_realm && _kdc_is_anon_request(req)))
flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER;
ret = hx509_cms_verify_signed(context->hx509ctx,
@@ -1676,7 +1677,8 @@ _kdc_pk_check_client(krb5_context context,
size_t i;
if (cp->cert == NULL) {
if (!_kdc_is_anonymous(context, client->entry.principal))
if (!_kdc_is_anonymous(context, client->entry.principal)
&& !config->historical_anon_realm)
return KRB5KDC_ERR_BADOPTION;
*subject_name = strdup("<unauthenticated anonymous client>");