From 56e179748ba4844ce0c5e505803170b901e2a3c4 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Jun 01 2023 06:20:37 +0000 Subject: ipa-kdb: initial support for passkeys - added passkey detection based on the presence of ipaPassKey attribute in the LDAP entry of the principal - added 'passkey' authentication indicator - added support for enforcing KDC policy based on the 'passkey' indicator Fixes: https://pagure.io/freeipa/issue/9263 Signed-off-by: Alexander Bokovoy Reviewed-By: Alexander Bokovoy --- diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c index 36f127b..f1cd0ed 100644 --- a/daemons/ipa-kdb/ipa_kdb.c +++ b/daemons/ipa-kdb/ipa_kdb.c @@ -200,6 +200,7 @@ static const struct { { "pkinit", IPADB_USER_AUTH_PKINIT }, { "hardened", IPADB_USER_AUTH_HARDENED }, { "idp", IPADB_USER_AUTH_IDP }, + { "passkey", IPADB_USER_AUTH_PASSKEY }, { } }; diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h index 6fd907e..8b7d4c9 100644 --- a/daemons/ipa-kdb/ipa_kdb.h +++ b/daemons/ipa-kdb/ipa_kdb.h @@ -106,6 +106,7 @@ enum ipadb_user_auth { IPADB_USER_AUTH_PKINIT = 1 << 4, IPADB_USER_AUTH_HARDENED = 1 << 5, IPADB_USER_AUTH_IDP = 1 << 6, + IPADB_USER_AUTH_PASSKEY = 1 << 7, }; enum ipadb_user_auth_idx { @@ -114,6 +115,7 @@ enum ipadb_user_auth_idx { IPADB_USER_AUTH_IDX_PKINIT, IPADB_USER_AUTH_IDX_HARDENED, IPADB_USER_AUTH_IDX_IDP, + IPADB_USER_AUTH_IDX_PASSKEY, IPADB_USER_AUTH_IDX_MAX, }; diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c index f2804c9..436ee0e 100644 --- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c +++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c @@ -143,6 +143,15 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata, goto done; } pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_IDP]); + } else if (strcmp(auth_indicator, "passkey") == 0) { + valid_auth_indicators++; + /* Allow hardened even if only password pre-auth is allowed */ + if (!(ua & IPADB_USER_AUTH_PASSKEY)) { + *status = "Passkey pre-authentication not allowed for this user."; + kerr = KRB5KDC_ERR_POLICY; + goto done; + } + pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PASSKEY]); } } diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c index e94e1f8..eb88f65 100644 --- a/daemons/ipa-kdb/ipa_kdb_principals.c +++ b/daemons/ipa-kdb/ipa_kdb_principals.c @@ -78,6 +78,7 @@ static char *std_principal_attrs[] = { IPA_USER_AUTH_TYPE, "ipatokenRadiusConfigLink", "ipaIdpConfigLink", + "ipaPassKey", "krbAuthIndMaxTicketLife", "krbAuthIndMaxRenewableAge", "ipaNTSecurityIdentifier", @@ -396,6 +397,25 @@ static void ipadb_validate_idp(struct ipadb_context *ipactx, ldap_value_free_len(vals); } +static void ipadb_validate_passkey(struct ipadb_context *ipactx, + LDAPMessage *lentry, + enum ipadb_user_auth *ua) +{ + struct berval **vals; + + if (!(*ua & IPADB_USER_AUTH_PASSKEY)) + return; + + /* Ensure that the user has a link to an IdP config. */ + vals = ldap_get_values_len(ipactx->lcontext, lentry, + "ipaPassKey"); + if (vals == NULL || vals[0] == NULL) + *ua &= ~IPADB_USER_AUTH_PASSKEY; + + if (vals != NULL) + ldap_value_free_len(vals); +} + static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx, LDAPMessage *lentry) { @@ -429,6 +449,7 @@ static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx, ipadb_validate_otp(ipactx, lentry, &ua); ipadb_validate_radius(ipactx, lentry, &ua); ipadb_validate_idp(ipactx, lentry, &ua); + ipadb_validate_passkey(ipactx, lentry, &ua); return ua; } @@ -613,6 +634,8 @@ static void ipadb_parse_authind_policies(krb5_context kcontext, IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED}, {"krbAuthIndMaxTicketLife;idp", IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP}, + {"krbAuthIndMaxTicketLife;passkey", + IPADB_USER_AUTH_PASSKEY, IPADB_USER_AUTH_IDX_PASSKEY}, {NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX}, }, age_authind_map[] = { {"krbAuthIndMaxRenewableAge;otp", @@ -625,6 +648,8 @@ static void ipadb_parse_authind_policies(krb5_context kcontext, IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED}, {"krbAuthIndMaxRenewableAge;idp", IPADB_USER_AUTH_IDP, IPADB_USER_AUTH_IDX_IDP}, + {"krbAuthIndMaxRenewableAge;passkey", + IPADB_USER_AUTH_PASSKEY, IPADB_USER_AUTH_IDX_PASSKEY}, {NULL, IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX}, }; @@ -668,6 +693,7 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, const krb5_octet rad_string[] = "otp\0[{\"indicators\": [\"radius\"]}]"; const krb5_octet otp_string[] = "otp\0[{\"indicators\": [\"otp\"]}]"; const krb5_octet idp_string[] = "idp\0[{\"type\":\"oauth2\",\"indicators\": [\"idp\"]}]"; + const krb5_octet passkey_string[] = "passkey\0[{\"indicators\": [\"passkey\"]}]"; struct ipadb_context *ipactx; enum ipadb_user_auth ua; LDAP *lcontext; @@ -1052,6 +1078,11 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext, sizeof(idp_string), idp_string); if (kerr) goto done; + } else if (ua & IPADB_USER_AUTH_PASSKEY) { + kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS, + sizeof(passkey_string), passkey_string); + if (kerr) + goto done; } if (ua & ~IPADB_USER_AUTH_NONE) {