diff --git a/third_party/heimdal/kdc/kdc-tester.c b/third_party/heimdal/kdc/kdc-tester.c index beb9e1f4a23..8f8073a44e1 100644 --- a/third_party/heimdal/kdc/kdc-tester.c +++ b/third_party/heimdal/kdc/kdc-tester.c @@ -258,10 +258,6 @@ eval_kinit(heim_dict_t o) krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_opt_set_pkinit"); } - ret = krb5_init_creds_init(kdc_context, client, NULL, NULL, 0, opt, &ctx); - if (ret) - krb5_err(kdc_context, 1, ret, "krb5_init_creds_init"); - fast_armor_cc = heim_dict_get_value(o, HSTR("fast-armor-cc")); if (fast_armor_cc) { @@ -269,13 +265,21 @@ eval_kinit(heim_dict_t o) if (ret) krb5_err(kdc_context, 1, ret, "krb5_cc_resolve"); - ret = krb5_init_creds_set_fast_ccache(kdc_context, ctx, fast_cc); + ret = krb5_get_init_creds_opt_set_fast_ccache(kdc_context, opt, fast_cc); if (ret) - krb5_err(kdc_context, 1, ret, "krb5_init_creds_set_fast_ccache"); + krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_set_fast_ccache"); + + ret = krb5_get_init_creds_opt_set_fast_flags(kdc_context, opt, KRB5_FAST_REQUIRED|KRB5_FAST_KDC_VERIFIED); + if (ret) + krb5_err(kdc_context, 1, ret, "krb5_get_init_creds_set_fast_ccache"); fast_cc = NULL; } + ret = krb5_init_creds_init(kdc_context, client, NULL, NULL, 0, opt, &ctx); + if (ret) + krb5_err(kdc_context, 1, ret, "krb5_init_creds_init"); + if (password) { ret = krb5_init_creds_set_password(kdc_context, ctx, heim_string_get_utf8(password)); diff --git a/third_party/heimdal/kuser/kinit.c b/third_party/heimdal/kuser/kinit.c index d5410df05c2..8df1c1b796f 100644 --- a/third_party/heimdal/kuser/kinit.c +++ b/third_party/heimdal/kuser/kinit.c @@ -742,6 +742,7 @@ get_new_tickets(krb5_context context, gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; gss_OID gss_mech = GSS_C_NO_OID; krb5_principal federated_name = NULL; + krb5_ccache fastid = NULL; #ifndef NO_NTLM struct ntlm_buf ntlmkey; @@ -970,6 +971,33 @@ get_new_tickets(krb5_context context, } } + if (fast_armor_cache_string) { + if (pk_anon_fast_armor > 0) + krb5_errx(context, 1, + N_("cannot specify FAST armor cache with FAST " + "anonymous PKINIT option", "")); + pk_anon_fast_armor = 0; + + ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); + if (ret) { + krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)"); + goto out; + } + + ret = krb5_get_init_creds_opt_set_fast_ccache(context, opt, fastid); + if (ret) { + krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); + goto out; + } + + ret = krb5_get_init_creds_opt_set_fast_flags(context, opt, + KRB5_FAST_REQUIRED); + if (ret) { + krb5_warn(context, ret, "krb5_init_creds_set_fast_flags"); + goto out; + } + } + ret = krb5_init_creds_init(context, principal, prompter, NULL, start_time, opt, &ctx); if (ret) { krb5_warn(context, ret, "krb5_init_creds_init"); @@ -1001,25 +1029,7 @@ get_new_tickets(krb5_context context, } if (fast_armor_cache_string) { - krb5_ccache fastid = NULL; - - if (pk_anon_fast_armor > 0) - krb5_errx(context, 1, - N_("cannot specify FAST armor cache with FAST " - "anonymous PKINIT option", "")); - pk_anon_fast_armor = 0; - - ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); - if (ret) { - krb5_warn(context, ret, "krb5_cc_resolve(FAST cache)"); - goto out; - } - - ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); - if (ret) { - krb5_warn(context, ret, "krb5_init_creds_set_fast_ccache"); - goto out; - } + /* handled above */ } else if (pk_anon_fast_armor == -1) { ret = _krb5_init_creds_set_fast_anon_pkinit_optimistic(context, ctx); if (ret) { @@ -1227,6 +1237,8 @@ out: krb5_cc_destroy(context, tempccache); if (enctype) free(enctype); + if (fastid) + krb5_cc_close(context, fastid); return ret; } diff --git a/third_party/heimdal/lib/krb5/init_creds.c b/third_party/heimdal/lib/krb5/init_creds.c index b2d0d39a3dc..6e77578d125 100644 --- a/third_party/heimdal/lib/krb5/init_creds.c +++ b/third_party/heimdal/lib/krb5/init_creds.c @@ -89,6 +89,7 @@ krb5_get_init_creds_opt_free(krb5_context context, return; if (--opt->opt_private->refcount == 0) { _krb5_get_init_creds_opt_free_pkinit(opt); + free(opt->opt_private->fast_armor_ccache_name); free(opt->opt_private); } memset(opt, 0, sizeof(*opt)); @@ -393,6 +394,51 @@ krb5_get_init_creds_opt_set_process_last_req(krb5_context context, return 0; } +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_fast_ccache(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_ccache fast_ccache) +{ + char *fast_ccache_name; + int ret = krb5_cc_get_full_name(context, + fast_ccache, + &fast_ccache_name); + if (ret) + return ret; + + ret = krb5_get_init_creds_opt_set_fast_ccache_name(context, + opt, + fast_ccache_name); + krb5_xfree(fast_ccache_name); + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_fast_ccache_name(krb5_context context, + krb5_get_init_creds_opt *opt, + const char *fast_ccache_name) +{ + if (opt->opt_private->fast_armor_ccache_name) + free(opt->opt_private->fast_armor_ccache_name); + + opt->opt_private->fast_armor_ccache_name = strdup(fast_ccache_name); + if (opt->opt_private->fast_armor_ccache_name == NULL) + return krb5_enomem(context); + + return 0; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_get_init_creds_opt_set_fast_flags(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_flags flags) +{ + heim_assert((flags & ~KRB5_FAST_PUBLIC_FLAGS) == 0, "invalid flags passed to krb5_get_init_creds_opt_set_fast_flags()"); + opt->opt_private->fast_flags = flags; + return 0; +} + + #ifndef HEIMDAL_SMALLER diff --git a/third_party/heimdal/lib/krb5/init_creds_pw.c b/third_party/heimdal/lib/krb5/init_creds_pw.c index 8b6db0be594..79057d7eeda 100644 --- a/third_party/heimdal/lib/krb5/init_creds_pw.c +++ b/third_party/heimdal/lib/krb5/init_creds_pw.c @@ -579,6 +579,25 @@ get_init_creds_common(krb5_context context, else ctx->runflags.change_password_prompt = ctx->prompter != NULL; + if (options->opt_private->fast_armor_ccache_name) { + /* Open the caller-supplied FAST ccache and set the caller flags */ + ret = krb5_cc_resolve(context, options->opt_private->fast_armor_ccache_name, + &ctx->fast_state.armor_ccache); + if (ret) + goto out; + } + + ctx->fast_state.flags = options->opt_private->fast_flags; + + /* + * If FAST is required with a real credential cache, then the KDC + * will be verified. This allows the + * krb5_get_init_creds_opt_set_fast API to work like MIT without + * exposing KRB5_FAST_KDC_VERIFIED to callers + */ + if (ctx->fast_state.flags & KRB5_FAST_REQUIRED) + ctx->fast_state.flags |= KRB5_FAST_KDC_VERIFIED; + out: if (default_opt) krb5_get_init_creds_opt_free(context, default_opt); diff --git a/third_party/heimdal/lib/krb5/krb5.h b/third_party/heimdal/lib/krb5/krb5.h index 32d4ffcdfc3..c291f3d711c 100644 --- a/third_party/heimdal/lib/krb5/krb5.h +++ b/third_party/heimdal/lib/krb5/krb5.h @@ -804,6 +804,8 @@ typedef struct _krb5_get_init_creds_opt krb5_get_init_creds_opt; #define KRB5_GET_INIT_CREDS_OPT_DISABLE_TRANSITED_CHECK 0x0200 #define KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT 0x0400 +#define KRB5_FAST_REQUIRED 0x0001 /* fast required by action of caller */ + /* krb5_init_creds_step flags argument */ #define KRB5_INIT_CREDS_STEP_FLAG_CONTINUE 0x0001 diff --git a/third_party/heimdal/lib/krb5/krb5_locl.h b/third_party/heimdal/lib/krb5/krb5_locl.h index 1b037cdcba3..57e7819e9c2 100644 --- a/third_party/heimdal/lib/krb5/krb5_locl.h +++ b/third_party/heimdal/lib/krb5/krb5_locl.h @@ -263,6 +263,9 @@ struct _krb5_get_init_creds_opt_private { krb5_gic_process_last_req func; void *ctx; } lr; + + krb5_flags fast_flags; + char *fast_armor_ccache_name; }; typedef uint32_t krb5_enctype_set; @@ -433,22 +436,24 @@ struct krb5_pk_init_ctx_data { struct krb5_fast_state { enum PA_FX_FAST_REQUEST_enum type; unsigned int flags; -#define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 0x0001 -#define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 0x0002 -#define KRB5_FAST_KDC_REPLY_KEY_REPLACED 0x0004 -#define KRB5_FAST_REPLY_REPLY_VERIFIED 0x0008 -#define KRB5_FAST_STRONG 0x0010 -#define KRB5_FAST_EXPECTED 0x0020 /* in exchange with KDC, fast was discovered */ -#define KRB5_FAST_REQUIRED 0x0040 /* fast required by action of caller */ -#define KRB5_FAST_DISABLED 0x0080 +#define KRB5_FAST_PUBLIC_FLAGS 0x0000ff +/* #define KRB5_FAST_REQUIRED 0x000001 - fast required by action of caller defined in krb5.h*/ -#define KRB5_FAST_AP_ARMOR_SERVICE 0x0100 -#define KRB5_FAST_OPTIMISTIC 0x0200 /* Optimistic try, like Anon + PKINIT or service fast bit */ -#define KRB5_FAST_REQUIRE_ENC_PA 0x0400 +#define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 0x000100 +#define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 0x000200 +#define KRB5_FAST_KDC_REPLY_KEY_REPLACED 0x000400 +#define KRB5_FAST_REPLY_REPLY_VERIFIED 0x000800 +#define KRB5_FAST_STRONG 0x001000 +#define KRB5_FAST_EXPECTED 0x002000 /* in exchange with KDC, fast was discovered */ +#define KRB5_FAST_DISABLED 0x008000 -#define KRB5_FAST_AS_REQ 0x1000 -#define KRB5_FAST_ANON_PKINIT_ARMOR 0x2000 -#define KRB5_FAST_KDC_VERIFIED 0x4000 +#define KRB5_FAST_AP_ARMOR_SERVICE 0x010000 +#define KRB5_FAST_OPTIMISTIC 0x020000 /* Optimistic try, like Anon + PKINIT or service fast bit */ +#define KRB5_FAST_REQUIRE_ENC_PA 0x040000 + +#define KRB5_FAST_AS_REQ 0x100000 +#define KRB5_FAST_ANON_PKINIT_ARMOR 0x200000 +#define KRB5_FAST_KDC_VERIFIED 0x400000 krb5_keyblock *reply_key; krb5_ccache armor_ccache; diff --git a/third_party/heimdal/lib/krb5/libkrb5-exports.def.in b/third_party/heimdal/lib/krb5/libkrb5-exports.def.in index 4870de90d1f..6dacb7f592b 100644 --- a/third_party/heimdal/lib/krb5/libkrb5-exports.def.in +++ b/third_party/heimdal/lib/krb5/libkrb5-exports.def.in @@ -374,6 +374,9 @@ EXPORTS krb5_get_init_creds_opt_set_salt krb5_get_init_creds_opt_set_tkt_life krb5_get_init_creds_opt_set_win2k + krb5_get_init_creds_opt_set_fast_ccache + krb5_get_init_creds_opt_set_fast_ccache_name + krb5_get_init_creds_opt_set_fast_flags krb5_get_init_creds_password krb5_get_instance krb5_get_kdc_cred diff --git a/third_party/heimdal/lib/krb5/test_pac.c b/third_party/heimdal/lib/krb5/test_pac.c index 89434ccd09f..d0d940fdca4 100644 --- a/third_party/heimdal/lib/krb5/test_pac.c +++ b/third_party/heimdal/lib/krb5/test_pac.c @@ -872,8 +872,12 @@ check_ticket_signature(krb5_context context, &ticket.sname) == !!signedticket, "ticket-signature"); + /* + * We have to not verify the KDC checksum as the saved PAC has no + * full checksum, and krb5_pac_verify requires this now + */ ret = krb5_pac_verify(context, pac, et.authtime, client, - tkt->key, tkt->kdc_key); + tkt->key, NULL); if (ret) t_err(context, tkt->name, "krb5_pac_verify ticket-sig", ret); @@ -894,9 +898,13 @@ check_ticket_signature(krb5_context context, if (ret) t_err(context, tkt->name, "remove_AuthorizationData", ret); + /* + * While we should do a full PAC signature in the same case as + * signedticket, the saved examples do not have one + */ ret = _krb5_kdc_pac_sign_ticket(context, pac, client, tkt->key, tkt->kdc_key, tkt->rodc_id, - NULL, NULL, signedticket, &et, NULL); + NULL, NULL, signedticket, FALSE, &et, NULL); if (ret) t_err(context, tkt->name, "_krb5_kdc_pac_sign_ticket", ret); @@ -915,9 +923,14 @@ check_ticket_signature(krb5_context context, if (ret) t_err(context, tkt->name, "remove_AuthorizationData 2", ret); + /* + * This time we will not be doing a krb5_data_cmp() so we add the + * full signature so that we can run that check in + * krb5_pac_verify() + */ ret = _krb5_kdc_pac_sign_ticket(context, pac, client, tkt->key, tkt->kdc_key, tkt->rodc_id, - NULL, NULL, signedticket, &et, NULL); + NULL, NULL, signedticket, TRUE, &et, NULL); if (ret) t_err(context, tkt->name, "_krb5_kdcsignedticketsign_ticket 2", ret); @@ -1015,13 +1028,18 @@ main(int argc, char **argv) if (ret) krb5_err(context, 1, ret, "krb5_pac_parse"); + /* + * We have to not verify the KDC checksum as the saved PAC has no + * full checksum, and krb5_pac_verify requires this now + */ ret = krb5_pac_verify(context, pac, authtime, p, - &member_keyblock, &kdc_keyblock); + &member_keyblock, NULL); if (ret) krb5_err(context, 1, ret, "krb5_pac_verify"); ret = _krb5_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, 0, NULL, NULL, + TRUE, NULL, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign"); @@ -1048,14 +1066,14 @@ main(int argc, char **argv) if (ret) krb5_err(context, 1, ret, "krb5_pac_init"); - /* our two user buffer plus the three "system" buffers */ + /* our two user buffer plus the four "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_types"); for (i = 0; i < len; i++) { /* skip server_cksum, privsvr_cksum, and logon_name */ - if (list[i] == 6 || list[i] == 7 || list[i] == 10) + if (list[i] == 6 || list[i] == 7 || list[i] == 10 || list[i] == 19) continue; ret = krb5_pac_get_buffer(context, pac, list[i], &data); @@ -1079,7 +1097,7 @@ main(int argc, char **argv) ret = _krb5_pac_sign(context, pac2, authtime, p, &member_keyblock, &kdc_keyblock, 0, - NULL, NULL, NULL, &data); + NULL, NULL, TRUE, NULL, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign 4"); @@ -1179,7 +1197,7 @@ main(int argc, char **argv) ret = _krb5_pac_sign(context, pac, authtime, p, &member_keyblock, &kdc_keyblock, 0, - NULL, NULL, NULL, &data); + NULL, NULL, TRUE, NULL, &data); if (ret) krb5_err(context, 1, ret, "_krb5_pac_sign"); @@ -1199,11 +1217,11 @@ main(int argc, char **argv) uint32_t *list; size_t len; - /* our two user buffer plus the three "system" buffers */ + /* our two user buffer plus the four "system" buffers */ ret = krb5_pac_get_types(context, pac, &len, &list); if (ret) krb5_err(context, 1, ret, "krb5_pac_get_types"); - if (len != 5) + if (len != 6) krb5_errx(context, 1, "list wrong length"); free(list); } diff --git a/third_party/heimdal/lib/krb5/version-script.map b/third_party/heimdal/lib/krb5/version-script.map index f2cfa3cd3f9..6c1df0c476f 100644 --- a/third_party/heimdal/lib/krb5/version-script.map +++ b/third_party/heimdal/lib/krb5/version-script.map @@ -370,6 +370,9 @@ HEIMDAL_KRB5_2.0 { krb5_get_init_creds_opt_set_salt; krb5_get_init_creds_opt_set_tkt_life; krb5_get_init_creds_opt_set_win2k; + krb5_get_init_creds_opt_set_fast_ccache; + krb5_get_init_creds_opt_set_fast_ccache_name; + krb5_get_init_creds_opt_set_fast_flags; krb5_get_init_creds_password; krb5_get_instance; krb5_get_kdc_cred;