krb5_pac_init.rst
krb5_pac_parse.rst
krb5_pac_sign.rst
+ krb5_pac_sign_ext.rst
krb5_pac_verify.rst
+ krb5_pac_verify_ext.rst
krb5_prepend_error_message.rst
krb5_principal2salt.rst
krb5_rd_cred.rst
krb5_timestamp authtime, krb5_const_principal principal,
const krb5_keyblock *server, const krb5_keyblock *privsvr);
+/**
+ * Verify a PAC, possibly from a specified realm.
+ *
+ * @param [in] context Library context
+ * @param [in] pac PAC handle
+ * @param [in] authtime Expected timestamp
+ * @param [in] principal Expected principal name (or NULL)
+ * @param [in] server Key to validate server checksum (or NULL)
+ * @param [in] privsvr Key to validate KDC checksum (or NULL)
+ * @param [in] with_realm If true, expect the realm of @a principal
+ *
+ * This function is similar to krb5_pac_verify(), but adds a parameter
+ * @a with_realm. If @a with_realm is true, the PAC_CLIENT_INFO field is
+ * expected to include the realm of @a principal as well as the name. This
+ * flag is necessary to verify PACs in cross-realm S4U2Self referral TGTs.
+ *
+ * @version New in 1.17
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_pac_verify_ext(krb5_context context, const krb5_pac pac,
+ krb5_timestamp authtime, krb5_const_principal principal,
+ const krb5_keyblock *server, const krb5_keyblock *privsvr,
+ krb5_boolean with_realm);
+
/**
* Sign a PAC.
*
krb5_const_principal principal, const krb5_keyblock *server_key,
const krb5_keyblock *privsvr_key, krb5_data *data);
+/**
+ * Sign a PAC, possibly with a specified realm.
+ *
+ * @param [in] context Library context
+ * @param [in] pac PAC handle
+ * @param [in] authtime Expected timestamp
+ * @param [in] principal Principal name (or NULL)
+ * @param [in] server_key Key for server checksum
+ * @param [in] privsvr_key Key for KDC checksum
+ * @param [in] with_realm If true, include the realm of @a principal
+ * @param [out] data Signed PAC encoding
+ *
+ * This function is similar to krb5_pac_sign(), but adds a parameter
+ * @a with_realm. If @a with_realm is true, the PAC_CLIENT_INFO field of the
+ * signed PAC will include the realm of @a principal as well as the name. This
+ * flag is necessary to generate PACs for cross-realm S4U2Self referrals.
+ *
+ * @version New in 1.17
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
+ krb5_const_principal principal,
+ const krb5_keyblock *server_key,
+ const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
+ krb5_data *data);
+
/**
* Allow the appplication to override the profile's allow_weak_crypto setting.
*
k5_pac_validate_client(krb5_context context,
const krb5_pac pac,
krb5_timestamp authtime,
- krb5_const_principal principal);
+ krb5_const_principal principal,
+ krb5_boolean with_realm);
krb5_error_code
k5_pac_add_buffer(krb5_context context,
k5_pac_validate_client(krb5_context context,
const krb5_pac pac,
krb5_timestamp authtime,
- krb5_const_principal principal)
+ krb5_const_principal principal,
+ krb5_boolean with_realm)
{
krb5_error_code ret;
krb5_data client_info;
krb5_ui_2 pac_princname_length;
int64_t pac_nt_authtime;
krb5_principal pac_principal;
- int flags;
+ int flags = 0;
ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_CLIENT_INFO,
&client_info);
return ret;
/* Parse the UTF-8 name as an enterprise principal if we are matching
- * against one; otherwise parse it as a regular principal with no realm. */
- flags = KRB5_PRINCIPAL_PARSE_NO_REALM;
+ * against one; otherwise parse it as a regular principal. */
if (principal->type == KRB5_NT_ENTERPRISE_PRINCIPAL)
flags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
+
+ if (with_realm)
+ flags |= KRB5_PRINCIPAL_PARSE_REQUIRE_REALM;
+ else
+ flags |= KRB5_PRINCIPAL_PARSE_NO_REALM;
+
ret = krb5_parse_name_flags(context, pac_princname, flags, &pac_principal);
if (ret != 0) {
free(pac_princname);
!krb5_principal_compare_flags(context,
pac_principal,
principal,
+ with_realm ? 0 :
KRB5_PRINCIPAL_COMPARE_IGNORE_REALM))
ret = KRB5KRB_AP_WRONG_PRINC;
krb5_const_principal principal,
const krb5_keyblock *server,
const krb5_keyblock *privsvr)
+{
+ return krb5_pac_verify_ext(context, pac, authtime, principal, server,
+ privsvr, FALSE);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_verify_ext(krb5_context context,
+ const krb5_pac pac,
+ krb5_timestamp authtime,
+ krb5_const_principal principal,
+ const krb5_keyblock *server,
+ const krb5_keyblock *privsvr,
+ krb5_boolean with_realm)
{
krb5_error_code ret;
}
if (principal != NULL) {
- ret = k5_pac_validate_client(context, pac, authtime, principal);
+ ret = k5_pac_validate_client(context, pac, authtime,
+ principal, with_realm);
if (ret != 0)
return ret;
}
k5_insert_client_info(krb5_context context,
krb5_pac pac,
krb5_timestamp authtime,
- krb5_const_principal principal)
+ krb5_const_principal principal,
+ krb5_boolean with_realm)
{
krb5_error_code ret;
krb5_data client_info;
unsigned char *princ_name_utf16 = NULL, *p;
size_t princ_name_utf16_len = 0;
uint64_t nt_authtime;
+ int flags = 0;
/* If we already have a CLIENT_INFO buffer, then just validate it */
if (k5_pac_locate_buffer(context, pac, KRB5_PAC_CLIENT_INFO,
&client_info) == 0) {
- return k5_pac_validate_client(context, pac, authtime, principal);
+ return k5_pac_validate_client(context, pac, authtime, principal,
+ with_realm);
}
- ret = krb5_unparse_name_flags(context, principal,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM,
- &princ_name_utf8);
+ if (!with_realm) {
+ flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
+ } else if (principal->type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
+ /* Avoid quoting the first @ sign for enterprise name with realm. */
+ flags |= KRB5_PRINCIPAL_UNPARSE_DISPLAY;
+ }
+
+ ret = krb5_unparse_name_flags(context, principal, flags, &princ_name_utf8);
if (ret != 0)
goto cleanup;
krb5_pac_sign(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
krb5_const_principal principal, const krb5_keyblock *server_key,
const krb5_keyblock *privsvr_key, krb5_data *data)
+{
+ return krb5_pac_sign_ext(context, pac, authtime, principal, server_key,
+ privsvr_key, FALSE, data);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
+ krb5_const_principal principal,
+ const krb5_keyblock *server_key,
+ const krb5_keyblock *privsvr_key, krb5_boolean with_realm,
+ krb5_data *data)
{
krb5_error_code ret;
krb5_data server_cksum, privsvr_cksum;
data->data = NULL;
if (principal != NULL) {
- ret = k5_insert_client_info(context, pac, authtime, principal);
+ ret = k5_insert_client_info(context, pac, authtime, principal,
+ with_realm);
if (ret != 0)
return ret;
}
free(list);
}
+ {
+ krb5_principal ep;
+
+ ret = krb5_parse_name_flags(context, user,
+ KRB5_PRINCIPAL_PARSE_ENTERPRISE, &ep);
+ if (ret)
+ err(context, ret, "krb5_parse_name_flags");
+
+ /* Try to verify as enterprise. */
+ ret = krb5_pac_verify(context, pac, authtime, ep, &member_keyblock,
+ &kdc_keyblock);
+ if (!ret)
+ err(context, ret, "krb5_pac_verify should have failed");
+
+ ret = krb5_pac_sign(context, pac, authtime, ep, &member_keyblock,
+ &kdc_keyblock, &data);
+ if (!ret)
+ err(context, ret, "krb5_pac_sign should have failed");
+
+ /* Try to verify with realm. */
+ ret = krb5_pac_verify_ext(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock, TRUE);
+ if (!ret)
+ err(context, ret, "krb5_pac_verify_ext with realm should fail");
+
+ /* Currently we can't re-sign the PAC with realm (although that could
+ * be useful), only sign a new one. */
+ ret = krb5_pac_sign_ext(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock, TRUE, &data);
+ if (!ret)
+ err(context, ret, "krb5_pac_sign_ext with realm should fail");
+
+ krb5_pac_free(context, pac);
+
+ /* Test enterprise. */
+ ret = krb5_pac_init(context, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_init");
+
+ ret = krb5_pac_sign(context, pac, authtime, ep, &member_keyblock,
+ &kdc_keyblock, &data);
+ if (ret)
+ err(context, ret, "krb5_pac_sign enterprise failed");
+
+ krb5_pac_free(context, pac);
+
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ krb5_free_data_contents(context, &data);
+ if (ret)
+ err(context, ret, "krb5_pac_parse failed");
+
+ ret = krb5_pac_verify(context, pac, authtime, ep, &member_keyblock,
+ &kdc_keyblock);
+ if (ret)
+ err(context, ret, "krb5_pac_verify enterprise failed");
+
+ ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock);
+ if (!ret)
+ err(context, ret, "krb5_pac_verify should have failed");
+
+ krb5_pac_free(context, pac);
+
+ /* Test with realm. */
+ ret = krb5_pac_init(context, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_init");
+
+ ret = krb5_pac_sign_ext(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock, TRUE, &data);
+ if (ret)
+ err(context, ret, "krb5_pac_sign_ext with realm failed");
+
+ krb5_pac_free(context, pac);
+
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ krb5_free_data_contents(context, &data);
+ if (ret)
+ err(context, ret, "krb5_pac_parse failed");
+
+ ret = krb5_pac_verify_ext(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock, TRUE);
+ if (ret)
+ err(context, ret, "krb5_pac_verify_ext with realm failed");
+
+ ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock);
+ if (!ret)
+ err(context, ret, "krb5_pac_verify should have failed");
+
+ krb5_pac_free(context, pac);
+
+ /* Test enterprise with realm. */
+ ret = krb5_pac_init(context, &pac);
+ if (ret)
+ err(context, ret, "krb5_pac_init");
+
+ ret = krb5_pac_sign_ext(context, pac, authtime, ep, &member_keyblock,
+ &kdc_keyblock, TRUE, &data);
+ if (ret)
+ err(context, ret, "krb5_pac_sign_ext ent with realm failed");
+
+ krb5_pac_free(context, pac);
+
+ ret = krb5_pac_parse(context, data.data, data.length, &pac);
+ krb5_free_data_contents(context, &data);
+ if (ret)
+ err(context, ret, "krb5_pac_parse failed");
+
+ ret = krb5_pac_verify_ext(context, pac, authtime, ep, &member_keyblock,
+ &kdc_keyblock, TRUE);
+ if (ret)
+ err(context, ret, "krb5_pac_verify_ext ent with realm failed");
+
+ ret = krb5_pac_verify(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock);
+ if (!ret)
+ err(context, ret, "krb5_pac_verify should have failed");
+
+ ret = krb5_pac_verify(context, pac, authtime, ep, &member_keyblock,
+ &kdc_keyblock);
+ if (!ret)
+ err(context, ret, "krb5_pac_verify should have failed");
+
+ ret = krb5_pac_verify_ext(context, pac, authtime, p, &member_keyblock,
+ &kdc_keyblock, TRUE);
+ if (!ret)
+ err(context, ret, "krb5_pac_verify_ext should have failed");
+
+ krb5_free_principal(context, ep);
+ }
+
krb5_pac_free(context, pac);
krb5_free_principal(context, p);
krb5_pac_init
krb5_pac_parse
krb5_pac_sign
+krb5_pac_sign_ext
krb5_pac_verify
+krb5_pac_verify_ext
krb5_parse_name
krb5_parse_name_flags
krb5_prepend_error_message
; new in 1.17
krb5_get_etype_info @447
+ krb5_pac_sign_ext @448
+ krb5_pac_verify_ext @449
; private symbols used by SPAKE client module
profile_get_string @439 ; PRIVATE
profile_release_string @440 ; PRIVATE