841 lines
34 KiB
Diff
841 lines
34 KiB
Diff
|
From 48be25aaa27487fcbbba76044083de37211b30e7 Mon Sep 17 00:00:00 2001
|
||
|
From: Isaac Boukris <iboukris@gmail.com>
|
||
|
Date: Fri, 7 Jan 2022 13:46:24 -0500
|
||
|
Subject: [PATCH] Add PAC ticket signature APIs
|
||
|
|
||
|
Microsoft added a third PAC signature over the ticket to prevent
|
||
|
servers from setting the forwardable flag on evidence tickets. Add
|
||
|
new APIs to generate and verify ticket signatures, as well as defines
|
||
|
for this and other new PAC buffer types. Deprecate the old signing
|
||
|
functions as they cannot generate ticket signatures. Modify several
|
||
|
error returns to better match the protocol errors generated by Active
|
||
|
Directory.
|
||
|
|
||
|
[ghudson@mit.edu: adjusted contracts for KDC requirements; simplified
|
||
|
and commented code changes; wrote commit message. rharwood@redhat.com
|
||
|
also did some work on this commit.]
|
||
|
|
||
|
ticket: 9043 (new)
|
||
|
---
|
||
|
doc/appdev/refs/api/index.rst | 2 +
|
||
|
doc/appdev/refs/macros/index.rst | 6 +
|
||
|
src/include/krb5/krb5.hin | 98 +++++++++++------
|
||
|
src/lib/krb5/krb/deps | 5 +-
|
||
|
src/lib/krb5/krb/int-proto.h | 12 ++
|
||
|
src/lib/krb5/krb/pac.c | 148 ++++++++++++++++++++++++-
|
||
|
src/lib/krb5/krb/pac_sign.c | 121 ++++++++++++++++++++
|
||
|
src/lib/krb5/krb/t_pac.c | 182 +++++++++++++++++++++++++++++++
|
||
|
src/lib/krb5/libkrb5.exports | 2 +
|
||
|
src/lib/krb5_32.def | 3 +
|
||
|
src/plugins/kdb/test/kdb_test.c | 6 +-
|
||
|
11 files changed, 544 insertions(+), 41 deletions(-)
|
||
|
|
||
|
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
|
||
|
index 9e03fd386f..d12be47c3c 100644
|
||
|
--- a/doc/appdev/refs/api/index.rst
|
||
|
+++ b/doc/appdev/refs/api/index.rst
|
||
|
@@ -223,6 +223,8 @@ Rarely used public interfaces
|
||
|
krb5_init_creds_step.rst
|
||
|
krb5_init_keyblock.rst
|
||
|
krb5_is_referral_realm.rst
|
||
|
+ krb5_kdc_sign_ticket.rst
|
||
|
+ krb5_kdc_verify_ticket.rst
|
||
|
krb5_kt_add_entry.rst
|
||
|
krb5_kt_end_seq_get.rst
|
||
|
krb5_kt_get_entry.rst
|
||
|
diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
|
||
|
index 001fb386a7..c6ea088742 100644
|
||
|
--- a/doc/appdev/refs/macros/index.rst
|
||
|
+++ b/doc/appdev/refs/macros/index.rst
|
||
|
@@ -234,12 +234,18 @@ Public
|
||
|
KRB5_NT_UNKNOWN.rst
|
||
|
KRB5_NT_WELLKNOWN.rst
|
||
|
KRB5_NT_X500_PRINCIPAL.rst
|
||
|
+ KRB5_PAC_ATTRIBUTES_INFO.rst
|
||
|
KRB5_PAC_CLIENT_INFO.rst
|
||
|
+ KRB5_PAC_CLIENT_CLAIMS.rst
|
||
|
KRB5_PAC_CREDENTIALS_INFO.rst
|
||
|
KRB5_PAC_DELEGATION_INFO.rst
|
||
|
+ KRB5_PAC_DEVICE_CLAIMS.rst
|
||
|
+ KRB5_PAC_DEVICE_INFO.rst
|
||
|
KRB5_PAC_LOGON_INFO.rst
|
||
|
KRB5_PAC_PRIVSVR_CHECKSUM.rst
|
||
|
+ KRB5_PAC_REQUESTOR.rst
|
||
|
KRB5_PAC_SERVER_CHECKSUM.rst
|
||
|
+ KRB5_PAC_TICKET_CHECKSUM.rst
|
||
|
KRB5_PAC_UPN_DNS_INFO.rst
|
||
|
KRB5_PADATA_AFS3_SALT.rst
|
||
|
KRB5_PADATA_AP_REQ.rst
|
||
|
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||
|
index a7060aa733..8e59628bd9 100644
|
||
|
--- a/src/include/krb5/krb5.hin
|
||
|
+++ b/src/include/krb5/krb5.hin
|
||
|
@@ -1918,7 +1918,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
|
||
|
#define KRB5_AUTHDATA_CAMMAC 96
|
||
|
#define KRB5_AUTHDATA_WIN2K_PAC 128
|
||
|
#define KRB5_AUTHDATA_ETYPE_NEGOTIATION 129 /**< RFC 4537 */
|
||
|
-#define KRB5_AUTHDATA_SIGNTICKET 512 /**< formerly 142 in krb5 1.8 */
|
||
|
+#define KRB5_AUTHDATA_SIGNTICKET 512 /**< @deprecated use PAC */
|
||
|
#define KRB5_AUTHDATA_FX_ARMOR 71
|
||
|
#define KRB5_AUTHDATA_AUTH_INDICATOR 97
|
||
|
#define KRB5_AUTHDATA_AP_OPTIONS 143
|
||
|
@@ -8181,6 +8181,12 @@ krb5_verify_authdata_kdc_issued(krb5_context context,
|
||
|
#define KRB5_PAC_CLIENT_INFO 10 /**< Client name and ticket info */
|
||
|
#define KRB5_PAC_DELEGATION_INFO 11 /**< Constrained delegation info */
|
||
|
#define KRB5_PAC_UPN_DNS_INFO 12 /**< User principal name and DNS info */
|
||
|
+#define KRB5_PAC_CLIENT_CLAIMS 13 /**< Client claims information */
|
||
|
+#define KRB5_PAC_DEVICE_INFO 14 /**< Device information */
|
||
|
+#define KRB5_PAC_DEVICE_CLAIMS 15 /**< Device claims information */
|
||
|
+#define KRB5_PAC_TICKET_CHECKSUM 16 /**< Ticket checksum */
|
||
|
+#define KRB5_PAC_ATTRIBUTES_INFO 17 /**< PAC attributes */
|
||
|
+#define KRB5_PAC_REQUESTOR 18 /**< PAC requestor SID */
|
||
|
|
||
|
struct krb5_pac_data;
|
||
|
/** PAC data structure to convey authorization information */
|
||
|
@@ -8338,56 +8344,84 @@ krb5_pac_verify_ext(krb5_context context, const krb5_pac pac,
|
||
|
krb5_boolean with_realm);
|
||
|
|
||
|
/**
|
||
|
- * Sign a PAC.
|
||
|
+ * Verify a PAC, possibly including ticket signature
|
||
|
*
|
||
|
- * @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 Key for server checksum
|
||
|
- * @param [in] privsvr_key Key for KDC checksum
|
||
|
- * @param [out] data Signed PAC encoding
|
||
|
+ * @param [in] context Library context
|
||
|
+ * @param [in] enc_tkt Ticket enc-part, possibly containing a PAC
|
||
|
+ * @param [in] server_princ Canonicalized name of ticket server
|
||
|
+ * @param [in] server Key to validate server checksum (or NULL)
|
||
|
+ * @param [in] privsvr Key to validate KDC checksum (or NULL)
|
||
|
+ * @param [out] pac_out Verified PAC (NULL if no PAC included)
|
||
|
*
|
||
|
- * This function signs @a pac using the keys @a server_key and @a privsvr_key
|
||
|
- * and returns the signed encoding in @a data. @a pac is modified to include
|
||
|
- * the server and KDC checksum buffers. Use krb5_free_data_contents() to free
|
||
|
- * @a data when it is no longer needed.
|
||
|
+ * If a PAC is present in @a enc_tkt, verify its signatures. If @a privsvr is
|
||
|
+ * not NULL and @a server_princ is not a krbtgt or kadmin/changepw service,
|
||
|
+ * require a ticket signature over @a enc_tkt in addition to the KDC signature.
|
||
|
+ * Place the verified PAC in @a pac_out. If an invalid PAC signature is found,
|
||
|
+ * return an error matching the Windows KDC protocol code for that condition as
|
||
|
+ * closely as possible.
|
||
|
*
|
||
|
- * @version New in 1.10
|
||
|
+ * If no PAC is present in @a enc_tkt, set @a pac_out to NULL and return
|
||
|
+ * successfully.
|
||
|
+ *
|
||
|
+ * @note This function does not validate the PAC_CLIENT_INFO buffer. If a
|
||
|
+ * specific value is expected, the caller can make a separate call to
|
||
|
+ * krb5_pac_verify_ext() with a principal but no keys.
|
||
|
+ *
|
||
|
+ * @retval 0 Success; otherwise - Kerberos error codes
|
||
|
+ *
|
||
|
+ * @version New in 1.20
|
||
|
*/
|
||
|
krb5_error_code KRB5_CALLCONV
|
||
|
+krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||
|
+ krb5_const_principal server_princ,
|
||
|
+ const krb5_keyblock *server,
|
||
|
+ const krb5_keyblock *privsvr, krb5_pac *pac_out);
|
||
|
+
|
||
|
+/** @deprecated Use krb5_kdc_sign_ticket() instead. */
|
||
|
+krb5_error_code KRB5_CALLCONV
|
||
|
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);
|
||
|
|
||
|
+/** @deprecated Use krb5_kdc_sign_ticket() instead. */
|
||
|
+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);
|
||
|
+
|
||
|
/**
|
||
|
- * Sign a PAC, possibly with a specified realm.
|
||
|
+ * Sign a PAC, possibly including a ticket signature
|
||
|
*
|
||
|
* @param [in] context Library context
|
||
|
+ * @param [in] enc_tkt The ticket for the signature
|
||
|
* @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] server_princ Canonical ticket server name
|
||
|
+ * @param [in] client_princ PAC_CLIENT_INFO principal (or NULL)
|
||
|
+ * @param [in] server Key for server checksum
|
||
|
+ * @param [in] privsvr Key for KDC and ticket 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.
|
||
|
+ * Sign @a pac using the keys @a server and @a privsvr. Include a ticket
|
||
|
+ * signature over @a enc_tkt if @a server_princ is not a TGS or kadmin/changepw
|
||
|
+ * principal name. Add the signed PAC's encoding to the authorization data of
|
||
|
+ * @a enc_tkt in the first slot, wrapped in an AD-IF-RELEVANT container. If @a
|
||
|
+ * client_princ is non-null, add a PAC_CLIENT_INFO buffer, including the realm
|
||
|
+ * if @a with_realm is true.
|
||
|
*
|
||
|
- * @version New in 1.17
|
||
|
+ * @retval 0 on success, otherwise - Kerberos error codes
|
||
|
+ *
|
||
|
+ * @version New in 1.20
|
||
|
*/
|
||
|
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_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,
|
||
|
+ const krb5_pac pac, krb5_const_principal server_princ,
|
||
|
+ krb5_const_principal client_princ,
|
||
|
+ const krb5_keyblock *server, const krb5_keyblock *privsvr,
|
||
|
+ krb5_boolean with_realm);
|
||
|
|
||
|
-
|
||
|
-/*
|
||
|
+/**
|
||
|
* Read client information from a PAC.
|
||
|
*
|
||
|
* @param [in] context Library context
|
||
|
diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps
|
||
|
index 439ca02725..cd842b03cd 100644
|
||
|
--- a/src/lib/krb5/krb/deps
|
||
|
+++ b/src/lib/krb5/krb/deps
|
||
|
@@ -709,7 +709,7 @@ pac.so pac.po $(OUTPRE)pac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
||
|
$(top_srcdir)/include/k5-utf8.h $(top_srcdir)/include/krb5.h \
|
||
|
$(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
|
||
|
$(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
|
||
|
- authdata.h pac.c
|
||
|
+ authdata.h int-proto.h pac.c
|
||
|
pac_sign.so pac_sign.po $(OUTPRE)pac_sign.$(OBJEXT): \
|
||
|
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
|
||
|
$(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
|
||
|
@@ -720,7 +720,8 @@ pac_sign.so pac_sign.po $(OUTPRE)pac_sign.$(OBJEXT): \
|
||
|
$(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/k5-utf8.h \
|
||
|
$(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
|
||
|
$(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
|
||
|
- $(top_srcdir)/include/socket-utils.h authdata.h pac_sign.c
|
||
|
+ $(top_srcdir)/include/socket-utils.h authdata.h int-proto.h \
|
||
|
+ pac_sign.c
|
||
|
padata.so padata.po $(OUTPRE)padata.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
|
||
|
$(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
|
||
|
$(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
|
||
|
diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
|
||
|
index fe61bebf5b..453ed60c6c 100644
|
||
|
--- a/src/lib/krb5/krb/int-proto.h
|
||
|
+++ b/src/lib/krb5/krb/int-proto.h
|
||
|
@@ -386,4 +386,16 @@ k5_get_proxy_cred_from_kdc(krb5_context context, krb5_flags options,
|
||
|
krb5_ccache ccache, krb5_creds *in_creds,
|
||
|
krb5_creds **out_creds);
|
||
|
|
||
|
+/* Return true if mprinc will match any hostname in a host-based principal name
|
||
|
+ * (possibly due to ignore_acceptor_hostname) with krb5_sname_match(). */
|
||
|
+krb5_boolean
|
||
|
+k5_sname_wildcard_host(krb5_context context, krb5_const_principal mprinc);
|
||
|
+
|
||
|
+/* Guess the appropriate name-type for a principal based on the name. */
|
||
|
+krb5_int32
|
||
|
+k5_infer_principal_type(krb5_principal princ);
|
||
|
+
|
||
|
+krb5_boolean
|
||
|
+k5_pac_should_have_ticket_signature(krb5_const_principal sprinc);
|
||
|
+
|
||
|
#endif /* KRB5_INT_FUNC_PROTO__ */
|
||
|
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
|
||
|
index 1b9ef12276..6eb23d8090 100644
|
||
|
--- a/src/lib/krb5/krb/pac.c
|
||
|
+++ b/src/lib/krb5/krb/pac.c
|
||
|
@@ -25,6 +25,7 @@
|
||
|
*/
|
||
|
|
||
|
#include "k5-int.h"
|
||
|
+#include "int-proto.h"
|
||
|
#include "authdata.h"
|
||
|
|
||
|
#define MAX_BUFFERS 4096
|
||
|
@@ -552,8 +553,10 @@ k5_pac_verify_server_checksum(krb5_context context,
|
||
|
checksum.checksum_type = load_32_le(p);
|
||
|
checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
|
||
|
checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||
|
+ if (checksum.checksum_type == CKSUMTYPE_SHA1)
|
||
|
+ return KRB5KDC_ERR_SUMTYPE_NOSUPP;
|
||
|
if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||
|
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
|
||
|
+ return KRB5KRB_ERR_GENERIC;
|
||
|
|
||
|
pac_data.length = pac->data.length;
|
||
|
pac_data.data = k5memdup(pac->data.data, pac->data.length, &ret);
|
||
|
@@ -586,7 +589,7 @@ k5_pac_verify_server_checksum(krb5_context context,
|
||
|
}
|
||
|
|
||
|
if (valid == FALSE)
|
||
|
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||
|
+ ret = KRB5KRB_AP_ERR_MODIFIED;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
@@ -623,7 +626,7 @@ k5_pac_verify_kdc_checksum(krb5_context context,
|
||
|
checksum.length = privsvr_checksum.length - PAC_SIGNATURE_DATA_LENGTH;
|
||
|
checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||
|
if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||
|
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
|
||
|
+ return KRB5KRB_ERR_GENERIC;
|
||
|
|
||
|
server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
|
||
|
server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
|
||
|
@@ -635,11 +638,148 @@ k5_pac_verify_kdc_checksum(krb5_context context,
|
||
|
return ret;
|
||
|
|
||
|
if (valid == FALSE)
|
||
|
- ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||
|
+ ret = KRB5KRB_AP_ERR_MODIFIED;
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
+static krb5_error_code
|
||
|
+verify_ticket_checksum(krb5_context context, const krb5_pac pac,
|
||
|
+ const krb5_data *ticket, const krb5_keyblock *privsvr)
|
||
|
+{
|
||
|
+ krb5_error_code ret;
|
||
|
+ krb5_checksum checksum;
|
||
|
+ krb5_data checksum_data;
|
||
|
+ krb5_boolean valid;
|
||
|
+ krb5_octet *p;
|
||
|
+
|
||
|
+ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_TICKET_CHECKSUM,
|
||
|
+ &checksum_data);
|
||
|
+ if (ret != 0)
|
||
|
+ return KRB5KRB_AP_ERR_MODIFIED;
|
||
|
+
|
||
|
+ if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH)
|
||
|
+ return KRB5_BAD_MSIZE;
|
||
|
+
|
||
|
+ p = (krb5_octet *)checksum_data.data;
|
||
|
+ checksum.checksum_type = load_32_le(p);
|
||
|
+ checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
|
||
|
+ checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
|
||
|
+ if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
|
||
|
+ return KRB5KRB_ERR_GENERIC;
|
||
|
+
|
||
|
+ ret = krb5_c_verify_checksum(context, privsvr,
|
||
|
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, ticket,
|
||
|
+ &checksum, &valid);
|
||
|
+ if (ret != 0)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ return valid ? 0 : KRB5KRB_AP_ERR_MODIFIED;
|
||
|
+}
|
||
|
+
|
||
|
+/* Per MS-PAC 2.8.3, tickets encrypted to TGS and password change principals
|
||
|
+ * should not have ticket signatures. */
|
||
|
+krb5_boolean
|
||
|
+k5_pac_should_have_ticket_signature(krb5_const_principal sprinc)
|
||
|
+{
|
||
|
+ if (IS_TGS_PRINC(sprinc))
|
||
|
+ return FALSE;
|
||
|
+ if (sprinc->length == 2 && data_eq_string(sprinc->data[0], "kadmin") &&
|
||
|
+ data_eq_string(sprinc->data[1], "changepw"))
|
||
|
+ return FALSE;
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+krb5_error_code KRB5_CALLCONV
|
||
|
+krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
|
||
|
+ krb5_const_principal server_princ,
|
||
|
+ const krb5_keyblock *server,
|
||
|
+ const krb5_keyblock *privsvr, krb5_pac *pac_out)
|
||
|
+{
|
||
|
+ krb5_error_code ret;
|
||
|
+ krb5_pac pac = NULL;
|
||
|
+ krb5_data *recoded_tkt = NULL;
|
||
|
+ krb5_authdata **authdata, *orig, **ifrel = NULL, **recoded_ifrel = NULL;
|
||
|
+ uint8_t z = 0;
|
||
|
+ krb5_authdata zpac = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC, 1, &z };
|
||
|
+ size_t i, j;
|
||
|
+
|
||
|
+ *pac_out = NULL;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Find the position of the PAC in the ticket authdata. ifrel will be the
|
||
|
+ * decoded AD-IF-RELEVANT container at position i containing a PAC, and j
|
||
|
+ * will be the offset within the container.
|
||
|
+ */
|
||
|
+ authdata = enc_tkt->authorization_data;
|
||
|
+ for (i = 0; authdata != NULL && authdata[i] != NULL; i++) {
|
||
|
+ if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ ret = krb5_decode_authdata_container(context,
|
||
|
+ KRB5_AUTHDATA_IF_RELEVANT,
|
||
|
+ authdata[i], &ifrel);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+
|
||
|
+ for (j = 0; ifrel[j] != NULL; j++) {
|
||
|
+ if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (ifrel[j] != NULL)
|
||
|
+ break;
|
||
|
+
|
||
|
+ krb5_free_authdata(context, ifrel);
|
||
|
+ ifrel = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Stop and return successfully if we didn't find a PAC. */
|
||
|
+ if (ifrel == NULL) {
|
||
|
+ ret = 0;
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = krb5_pac_parse(context, ifrel[j]->contents, ifrel[j]->length, &pac);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+
|
||
|
+ if (privsvr != NULL && k5_pac_should_have_ticket_signature(server_princ)) {
|
||
|
+ /* To check the PAC ticket signatures, re-encode the ticket with the
|
||
|
+ * PAC contents replaced by a single zero. */
|
||
|
+ orig = ifrel[j];
|
||
|
+ ifrel[j] = &zpac;
|
||
|
+ ret = krb5_encode_authdata_container(context,
|
||
|
+ KRB5_AUTHDATA_IF_RELEVANT,
|
||
|
+ ifrel, &recoded_ifrel);
|
||
|
+ ifrel[j] = orig;
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+ orig = authdata[i];
|
||
|
+ authdata[i] = recoded_ifrel[0];
|
||
|
+ ret = encode_krb5_enc_tkt_part(enc_tkt, &recoded_tkt);
|
||
|
+ authdata[i] = orig;
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+
|
||
|
+ ret = verify_ticket_checksum(context, pac, recoded_tkt, privsvr);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = krb5_pac_verify_ext(context, pac, enc_tkt->times.authtime, NULL,
|
||
|
+ server, privsvr, FALSE);
|
||
|
+
|
||
|
+ *pac_out = pac;
|
||
|
+ pac = NULL;
|
||
|
+
|
||
|
+cleanup:
|
||
|
+ krb5_pac_free(context, pac);
|
||
|
+ krb5_free_data(context, recoded_tkt);
|
||
|
+ krb5_free_authdata(context, ifrel);
|
||
|
+ krb5_free_authdata(context, recoded_ifrel);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
krb5_error_code KRB5_CALLCONV
|
||
|
krb5_pac_verify(krb5_context context,
|
||
|
const krb5_pac pac,
|
||
|
diff --git a/src/lib/krb5/krb/pac_sign.c b/src/lib/krb5/krb/pac_sign.c
|
||
|
index 12f0259b4f..0f9581abbb 100644
|
||
|
--- a/src/lib/krb5/krb/pac_sign.c
|
||
|
+++ b/src/lib/krb5/krb/pac_sign.c
|
||
|
@@ -25,6 +25,7 @@
|
||
|
*/
|
||
|
|
||
|
#include "k5-int.h"
|
||
|
+#include "int-proto.h"
|
||
|
#include "authdata.h"
|
||
|
|
||
|
/* draft-brezak-win2k-krb-authz-00 */
|
||
|
@@ -286,3 +287,123 @@ krb5_pac_sign_ext(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
+
|
||
|
+/* Add a signature over der_enc_tkt in privsvr to pac. der_enc_tkt should be
|
||
|
+ * encoded with a dummy PAC authdata element containing a single zero byte. */
|
||
|
+static krb5_error_code
|
||
|
+add_ticket_signature(krb5_context context, const krb5_pac pac,
|
||
|
+ krb5_data *der_enc_tkt, const krb5_keyblock *privsvr)
|
||
|
+{
|
||
|
+ krb5_error_code ret;
|
||
|
+ krb5_data ticket_cksum;
|
||
|
+ krb5_cksumtype ticket_cksumtype;
|
||
|
+ krb5_crypto_iov iov[2];
|
||
|
+
|
||
|
+ /* Create zeroed buffer for checksum. */
|
||
|
+ ret = k5_insert_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM,
|
||
|
+ privsvr, &ticket_cksumtype);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ ret = k5_pac_locate_buffer(context, pac, KRB5_PAC_TICKET_CHECKSUM,
|
||
|
+ &ticket_cksum);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||
|
+ iov[0].data = *der_enc_tkt;
|
||
|
+ iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
|
||
|
+ iov[1].data = make_data(ticket_cksum.data + PAC_SIGNATURE_DATA_LENGTH,
|
||
|
+ ticket_cksum.length - PAC_SIGNATURE_DATA_LENGTH);
|
||
|
+ ret = krb5_c_make_checksum_iov(context, ticket_cksumtype, privsvr,
|
||
|
+ KRB5_KEYUSAGE_APP_DATA_CKSUM, iov, 2);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ store_32_le(ticket_cksumtype, ticket_cksum.data);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/* Set *out to an AD-IF-RELEVANT authdata element containing a PAC authdata
|
||
|
+ * element with contents pac_data. */
|
||
|
+static krb5_error_code
|
||
|
+encode_pac_ad(krb5_context context, krb5_data *pac_data, krb5_authdata **out)
|
||
|
+{
|
||
|
+ krb5_error_code ret;
|
||
|
+ krb5_authdata *container[2], **encoded_container = NULL;
|
||
|
+ krb5_authdata pac_ad = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC };
|
||
|
+ uint8_t z = 0;
|
||
|
+
|
||
|
+ pac_ad.contents = (pac_data != NULL) ? (uint8_t *)pac_data->data : &z;
|
||
|
+ pac_ad.length = (pac_data != NULL) ? pac_data->length : 1;
|
||
|
+ container[0] = &pac_ad;
|
||
|
+ container[1] = NULL;
|
||
|
+
|
||
|
+ ret = krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT,
|
||
|
+ container, &encoded_container);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ *out = encoded_container[0];
|
||
|
+ free(encoded_container);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+krb5_error_code KRB5_CALLCONV
|
||
|
+krb5_kdc_sign_ticket(krb5_context context, krb5_enc_tkt_part *enc_tkt,
|
||
|
+ const krb5_pac pac, krb5_const_principal server_princ,
|
||
|
+ krb5_const_principal client_princ,
|
||
|
+ const krb5_keyblock *server, const krb5_keyblock *privsvr,
|
||
|
+ krb5_boolean with_realm)
|
||
|
+{
|
||
|
+ krb5_error_code ret;
|
||
|
+ krb5_data *der_enc_tkt = NULL, pac_data = empty_data();
|
||
|
+ krb5_authdata **list, *pac_ad;
|
||
|
+ size_t count;
|
||
|
+
|
||
|
+ /* Reallocate space for another authdata element in enc_tkt. */
|
||
|
+ list = enc_tkt->authorization_data;
|
||
|
+ for (count = 0; list != NULL && list[count] != NULL; count++);
|
||
|
+ list = realloc(enc_tkt->authorization_data, (count + 2) * sizeof(*list));
|
||
|
+ if (list == NULL)
|
||
|
+ return ENOMEM;
|
||
|
+ list[count] = NULL;
|
||
|
+ enc_tkt->authorization_data = list;
|
||
|
+
|
||
|
+ /* Create a dummy PAC for ticket signing and make it the first element. */
|
||
|
+ ret = encode_pac_ad(context, NULL, &pac_ad);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+ memmove(list + 1, list, (count + 1) * sizeof(*list));
|
||
|
+ list[0] = pac_ad;
|
||
|
+
|
||
|
+ if (k5_pac_should_have_ticket_signature(server_princ)) {
|
||
|
+ ret = encode_krb5_enc_tkt_part(enc_tkt, &der_enc_tkt);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+
|
||
|
+ assert(privsvr != NULL);
|
||
|
+ ret = add_ticket_signature(context, pac, der_enc_tkt, privsvr);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = krb5_pac_sign_ext(context, pac, enc_tkt->times.authtime,
|
||
|
+ client_princ, server, privsvr, with_realm,
|
||
|
+ &pac_data);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+
|
||
|
+ /* Replace the dummy PAC with the signed real one. */
|
||
|
+ ret = encode_pac_ad(context, &pac_data, &pac_ad);
|
||
|
+ if (ret)
|
||
|
+ goto cleanup;
|
||
|
+ free(list[0]->contents);
|
||
|
+ free(list[0]);
|
||
|
+ list[0] = pac_ad;
|
||
|
+
|
||
|
+cleanup:
|
||
|
+ krb5_free_data(context, der_enc_tkt);
|
||
|
+ krb5_free_data_contents(context, &pac_data);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c
|
||
|
index ccd165380d..173bde7bab 100644
|
||
|
--- a/src/lib/krb5/krb/t_pac.c
|
||
|
+++ b/src/lib/krb5/krb/t_pac.c
|
||
|
@@ -605,6 +605,186 @@ check_pac(krb5_context context, int index, const unsigned char *pdata,
|
||
|
krb5_pac_free(context, pac);
|
||
|
}
|
||
|
|
||
|
+static const krb5_keyblock ticket_sig_krbtgt_key = {
|
||
|
+ 0, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||
|
+ 32, U("\x7a\x58\x98\xd2\xaf\xa6\xaf\xc0\x6a\xce\x06\x04\x4b\xc2\x70\x84"
|
||
|
+ "\x9b\x8e\x0a\x6c\x4c\x07\xdc\x6f\xbb\x48\x43\xe1\xd2\xaa\x97\xf7")
|
||
|
+};
|
||
|
+
|
||
|
+static const krb5_keyblock ticket_sig_server_key = {
|
||
|
+ 0, ENCTYPE_ARCFOUR_HMAC,
|
||
|
+ 16, U("\xed\x23\x11\x20\x7a\x21\x44\x20\xbf\xc0\x8d\x36\xf7\xf6\xb2\x3e")
|
||
|
+};
|
||
|
+
|
||
|
+static const krb5_data ticket_data = {
|
||
|
+ .length = 972, .data =
|
||
|
+ "\x61\x82\x03\xC8\x30\x82\x03\xC4\xA0\x03\x02\x01\x05\xA1\x0A\x1B"
|
||
|
+ "\x08\x43\x44\x4F\x4D\x2E\x43\x4F\x4D\xA2\x0F\x30\x0D\xA0\x03\x02"
|
||
|
+ "\x01\x01\xA1\x06\x30\x04\x1B\x02\x73\x31\xA3\x82\x03\x9E\x30\x82"
|
||
|
+ "\x03\x9A\xA0\x03\x02\x01\x17\xA1\x03\x02\x01\x03\xA2\x82\x03\x8C"
|
||
|
+ "\x04\x82\x03\x88\x44\x31\x61\x20\x17\xC9\xFE\xBC\xAC\x46\xB5\x77"
|
||
|
+ "\xE9\x68\x04\x4C\x9B\x31\x91\x0C\xC1\xD4\xDD\xEF\xC7\x34\x20\x08"
|
||
|
+ "\x90\x91\xE8\x79\xE0\xB5\x03\x26\xA4\x65\xDE\xEC\x47\x03\x2A\x8F"
|
||
|
+ "\x61\xE7\x4D\x38\x5A\x42\x95\x5A\xF9\x2F\x41\x2C\x2A\x6E\x60\xA1"
|
||
|
+ "\xEB\x51\xB3\xBD\x4C\x00\x41\x2A\x44\x76\x08\x37\x1A\x51\xFD\x65"
|
||
|
+ "\x67\x7E\xBF\x3D\x90\x86\xE3\x9A\x54\x6B\x67\xA8\x08\x7A\x73\xCC"
|
||
|
+ "\xC3\xB7\x4B\xD5\x5C\x3A\x14\x6C\xC1\x5F\x54\x4B\x92\x55\xB4\xB7"
|
||
|
+ "\x92\x23\x3F\x53\x89\x47\x8E\x1F\x8B\xB9\xDB\x3B\x93\xE8\x70\xE4"
|
||
|
+ "\x24\xB8\x9D\xF0\x0E\x35\x28\xF8\x7A\x27\x5D\xF7\x25\x97\x9C\xF5"
|
||
|
+ "\x9F\x9F\x64\x04\xF2\xA3\xAB\x11\x15\xB6\xDA\x18\xD6\x46\xD5\xE6"
|
||
|
+ "\xB8\x08\xDE\x0A\x62\xFD\xF8\xAA\x52\x90\xD9\x67\x29\xB2\xCD\x06"
|
||
|
+ "\xB6\xB0\x50\x2B\x3F\x0F\xA3\xA5\xBF\xAA\x6E\x40\x03\xD6\x5F\x02"
|
||
|
+ "\xBC\xD8\x18\x47\x97\x09\xD7\xE4\x96\x3B\xCB\xEB\x92\x2C\x3C\x49"
|
||
|
+ "\xFF\x1F\x71\xE0\x52\x94\x0F\x8B\x9F\xB8\x2A\xBB\x9C\xE2\xA3\xDD"
|
||
|
+ "\x38\x89\xE2\xB1\x0B\x9E\x1F\x7A\xB3\xE3\xD2\xB0\x94\xDC\x87\xBE"
|
||
|
+ "\x37\xA6\xD3\xB3\x29\x35\x9A\x72\xC3\x7A\xF1\xA9\xE6\xC5\xD1\x26"
|
||
|
+ "\x83\x65\x44\x17\xBA\x55\xA8\x5E\x94\x26\xED\xE9\x8A\x93\x11\x5D"
|
||
|
+ "\x7E\x20\x1B\x9C\x15\x9E\x13\x37\x03\x4D\xDD\x99\x51\xD8\x66\x29"
|
||
|
+ "\x6A\xB9\xFB\x49\xFE\x52\x78\xDA\x86\x85\xA9\xA3\xB9\xEF\xEC\xAD"
|
||
|
+ "\x35\xA6\x8D\xAC\x0F\x75\x22\xBB\x0B\x49\x1C\x13\x52\x40\xC9\x52"
|
||
|
+ "\x69\x09\x54\xD1\x0F\x94\x3F\x22\x48\x67\xB0\x96\x28\xAA\xE6\x28"
|
||
|
+ "\xD9\x0C\x08\xEF\x51\xED\x15\x5E\xA2\x53\x59\xA5\x03\xB4\x06\x20"
|
||
|
+ "\x3D\xCC\xB4\xC5\xF8\x8C\x73\x67\xA3\x21\x3D\x19\xCD\xD4\x12\x28"
|
||
|
+ "\xD2\x93\xDE\x0D\xF0\x71\x10\x50\xD6\x33\x35\x04\x11\x64\x43\x39"
|
||
|
+ "\xC3\xDF\x96\xE3\x66\xE3\x85\xCA\xE7\x67\x14\x3A\xF0\x43\xAA\xBB"
|
||
|
+ "\xD4\x1D\xB5\x24\xB5\x74\x90\x25\xA7\x87\x7E\xDB\xD3\x83\x8A\x3A"
|
||
|
+ "\x69\xA8\x2D\xAF\xB7\xB8\xF3\xDC\x13\xAF\x45\x61\x3F\x59\x39\x7E"
|
||
|
+ "\x69\xDE\x0C\x04\xF1\x10\x6B\xB4\x56\xFA\x21\x9F\x72\x2B\x60\x86"
|
||
|
+ "\xE3\x23\x0E\xC4\x51\xF6\xBE\xD8\xE1\x5F\xEE\x73\x4C\x17\x4C\x2C"
|
||
|
+ "\x1B\xFB\x9F\x1F\x7A\x3B\x07\x5B\x8E\xF1\x01\xAC\xD6\x30\x94\x8A"
|
||
|
+ "\x5D\x22\x6F\x08\xCE\xED\x5E\xB6\xDB\x86\x8C\x87\xEB\x8D\x91\xFF"
|
||
|
+ "\x0A\x86\x30\xBD\xC0\xF8\x25\xE7\xAE\x24\x35\xF2\xFC\xE5\xFD\x1B"
|
||
|
+ "\xB0\x05\x4A\xA3\xE5\xEB\x2E\x05\xAD\x99\x67\x49\x87\xE6\xB3\x87"
|
||
|
+ "\x82\xA4\x59\xA7\x6E\xDD\xF2\xB6\x66\xE8\xF7\x70\xF5\xBD\xC9\x0E"
|
||
|
+ "\xFA\x9C\x79\x84\xD4\x9B\x05\x0E\xBB\xF5\xDB\xEF\xFC\xCC\x26\xF2"
|
||
|
+ "\x93\xCF\xD2\x04\x3C\xA9\x2C\x65\x42\x97\x86\xD8\x38\x0A\x1E\xF6"
|
||
|
+ "\xD6\xCA\x30\xB5\x1A\xEC\xFB\xBA\x3B\x84\x57\xB0\xFD\xFB\xE6\xBC"
|
||
|
+ "\xF2\x76\xF6\x4C\xBB\xAB\xB1\x31\xA1\x27\x7C\xE6\xE6\x81\xB6\xCE"
|
||
|
+ "\x84\x86\x40\xB6\x40\x33\xC4\xF8\xB4\x15\xCF\xAA\xA5\x51\x78\xB9"
|
||
|
+ "\x8B\x50\x25\xB2\x88\x86\x96\x72\x8C\x71\x4D\xB5\x3A\x94\x86\x77"
|
||
|
+ "\x0E\x95\x9B\x16\x93\xEF\x3A\x11\x79\xBA\x83\xF7\x74\xD3\x8D\xBA"
|
||
|
+ "\x15\xE1\x2C\x04\x57\xA8\x92\x1E\x9D\x00\x8E\x20\xFD\x30\x70\xE7"
|
||
|
+ "\xF5\x65\x2F\x19\x0C\x94\xBA\x03\x71\x12\x96\xCD\xC8\xB4\x96\xDB"
|
||
|
+ "\xCE\x19\xC2\xDF\x3C\xC2\xF6\x3D\x53\xED\x98\xA5\x41\x72\x2A\x22"
|
||
|
+ "\x7B\xF3\x2B\x17\x6C\xE1\x39\x7D\xAE\x9B\x11\xF9\xC1\xA6\x9E\x9F"
|
||
|
+ "\x89\x3C\x12\xAA\x94\x74\xA7\x4F\x70\xE8\xB9\xDE\x04\xF0\x9D\x39"
|
||
|
+ "\x24\x2D\x92\xE8\x46\x2D\x2E\xF0\x40\x66\x1A\xD9\x27\xF9\x98\xF1"
|
||
|
+ "\x81\x1D\x70\x62\x63\x30\x6D\xCD\x84\x04\x5F\xFA\x83\xD3\xEC\x8D"
|
||
|
+ "\x86\xFB\x40\x61\xC1\x8A\x45\xFF\x7B\xD9\xD4\x18\x61\x7F\x51\xE3"
|
||
|
+ "\xFC\x1E\x18\xF0\xAF\xC6\x18\x2C\xE1\x6D\x5D\xF9\x62\xFC\x20\xA3"
|
||
|
+ "\xB2\x8A\x5F\xE5\xBB\x29\x0F\x99\x63\x07\x88\x38\x3A\x3B\x73\x2A"
|
||
|
+ "\x6D\xDA\x3D\xA8\x0D\x8F\x56\x41\x89\x82\xE5\xB8\x61\x00\x64\x7D"
|
||
|
+ "\x17\x0C\xCE\x03\x55\x8F\xF4\x5B\x0D\x50\xF2\xEB\x05\x67\xBE\xDB"
|
||
|
+ "\x7B\x75\xC5\xEA\xA1\xAB\x1D\xB0\x3C\x6D\x42\x08\x0B\x9A\x45\x20"
|
||
|
+ "\xA8\x8F\xE5\x67\x47\x30\xDE\x93\x5F\x43\x05\xEB\xA8\x2D\x80\xF5"
|
||
|
+ "\x1A\xB8\x4A\x4E\x42\x2D\x0B\x7A\xDC\x46\x20\x2D\x13\x17\xDD\x4B"
|
||
|
+ "\x94\x96\xAA\x1F\x06\x0C\x1F\x62\x07\x9C\x40\xA1"
|
||
|
+};
|
||
|
+
|
||
|
+static void
|
||
|
+test_pac_ticket_signature(krb5_context context)
|
||
|
+{
|
||
|
+ krb5_error_code ret;
|
||
|
+ krb5_ticket *ticket;
|
||
|
+ krb5_principal sprinc;
|
||
|
+ krb5_authdata **authdata1, **authdata2;
|
||
|
+ krb5_pac pac, pac2, pac3;
|
||
|
+ uint32_t *list;
|
||
|
+ size_t len, i;
|
||
|
+ krb5_data data;
|
||
|
+
|
||
|
+ ret = krb5_decode_ticket(&ticket_data, &ticket);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "while decoding ticket");
|
||
|
+
|
||
|
+ ret = krb5_decrypt_tkt_part(context, &ticket_sig_server_key, ticket);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "while decrypting ticket");
|
||
|
+
|
||
|
+ ret = krb5_parse_name(context, "s1@CDOM.COM", &sprinc);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "krb5_parse_name");
|
||
|
+
|
||
|
+ ret = krb5_kdc_verify_ticket(context, ticket->enc_part2, sprinc,
|
||
|
+ &ticket_sig_server_key,
|
||
|
+ &ticket_sig_krbtgt_key, &pac);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "while verifying ticket");
|
||
|
+
|
||
|
+ /* In this test, the server is also the client. */
|
||
|
+ ret = krb5_pac_verify(context, pac, ticket->enc_part2->times.authtime,
|
||
|
+ ticket->server, NULL, NULL);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "while verifying PAC client info");
|
||
|
+
|
||
|
+ /* We know there is only a PAC in this test's ticket. */
|
||
|
+ authdata1 = ticket->enc_part2->authorization_data;
|
||
|
+ ticket->enc_part2->authorization_data = NULL;
|
||
|
+
|
||
|
+ ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac, sprinc,
|
||
|
+ sprinc, &ticket_sig_server_key,
|
||
|
+ &ticket_sig_krbtgt_key, FALSE);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "while signing ticket");
|
||
|
+
|
||
|
+ authdata2 = ticket->enc_part2->authorization_data;
|
||
|
+ assert(authdata2 != NULL);
|
||
|
+ assert(authdata2[1] == NULL);
|
||
|
+
|
||
|
+ assert(authdata1[0]->length == authdata2[0]->length);
|
||
|
+ assert(memcmp(authdata1[0]->contents, authdata2[0]->contents,
|
||
|
+ authdata1[0]->length) == 0);
|
||
|
+
|
||
|
+ /* Test adding signatures to a new PAC. */
|
||
|
+ ret = krb5_pac_init(context, &pac2);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "krb5_pac_init");
|
||
|
+
|
||
|
+ ret = krb5_pac_get_types(context, pac, &len, &list);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "krb5_pac_get_types");
|
||
|
+
|
||
|
+ for (i = 0; i < len; i++) {
|
||
|
+ /* Skip server_cksum, privsvr_cksum, and ticket_cksum. */
|
||
|
+ if (list[i] == 6 || list[i] == 7 || list[i] == 16)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ ret = krb5_pac_get_buffer(context, pac, list[i], &data);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "krb5_pac_get_buffer");
|
||
|
+
|
||
|
+ ret = krb5_pac_add_buffer(context, pac2, list[i], &data);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "krb5_pac_add_buffer");
|
||
|
+
|
||
|
+ krb5_free_data_contents(context, &data);
|
||
|
+ }
|
||
|
+ free(list);
|
||
|
+
|
||
|
+ krb5_free_authdata(context, authdata1);
|
||
|
+ krb5_free_authdata(context, ticket->enc_part2->authorization_data);
|
||
|
+ ticket->enc_part2->authorization_data = NULL;
|
||
|
+
|
||
|
+ ret = krb5_kdc_sign_ticket(context, ticket->enc_part2, pac2, sprinc, NULL,
|
||
|
+ &ticket_sig_server_key, &ticket_sig_krbtgt_key,
|
||
|
+ FALSE);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "while signing ticket");
|
||
|
+
|
||
|
+ /* We can't compare the data since the order of the buffers may differ. */
|
||
|
+ ret = krb5_kdc_verify_ticket(context, ticket->enc_part2, sprinc,
|
||
|
+ &ticket_sig_server_key,
|
||
|
+ &ticket_sig_krbtgt_key, &pac3);
|
||
|
+ if (ret)
|
||
|
+ err(context, ret, "while verifying ticket");
|
||
|
+
|
||
|
+ krb5_pac_free(context, pac);
|
||
|
+ krb5_pac_free(context, pac2);
|
||
|
+ krb5_pac_free(context, pac3);
|
||
|
+ krb5_free_principal(context, sprinc);
|
||
|
+ krb5_free_ticket(context, ticket);
|
||
|
+}
|
||
|
+
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
@@ -618,6 +798,8 @@ main(int argc, char **argv)
|
||
|
if (ret)
|
||
|
err(NULL, 0, "krb5_init_contex");
|
||
|
|
||
|
+ test_pac_ticket_signature(context);
|
||
|
+
|
||
|
ret = krb5_set_default_realm(context, "WIN2K3.THINKER.LOCAL");
|
||
|
if (ret)
|
||
|
err(context, ret, "krb5_set_default_realm");
|
||
|
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
|
||
|
index 48ae46f5c4..28784ec67c 100644
|
||
|
--- a/src/lib/krb5/libkrb5.exports
|
||
|
+++ b/src/lib/krb5/libkrb5.exports
|
||
|
@@ -462,6 +462,8 @@ krb5_is_permitted_enctype
|
||
|
krb5_is_referral_realm
|
||
|
krb5_is_thread_safe
|
||
|
krb5_kdc_rep_decrypt_proc
|
||
|
+krb5_kdc_sign_ticket
|
||
|
+krb5_kdc_verify_ticket
|
||
|
krb5_kt_add_entry
|
||
|
krb5_kt_client_default
|
||
|
krb5_kt_close
|
||
|
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
|
||
|
index 209c6aaef5..8c3469a96c 100644
|
||
|
--- a/src/lib/krb5_32.def
|
||
|
+++ b/src/lib/krb5_32.def
|
||
|
@@ -506,3 +506,6 @@ EXPORTS
|
||
|
; new in 1.20
|
||
|
krb5_marshal_credentials @472
|
||
|
krb5_unmarshal_credentials @473
|
||
|
+ k5_sname_compare @474 ; PRIVATE GSSAPI
|
||
|
+ krb5_kdc_sign_ticket @475 ;
|
||
|
+ krb5_kdc_verify_ticket @476 ;
|
||
|
diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
|
||
|
index 38d371cb86..7d033acae4 100644
|
||
|
--- a/src/plugins/kdb/test/kdb_test.c
|
||
|
+++ b/src/plugins/kdb/test/kdb_test.c
|
||
|
@@ -675,7 +675,7 @@ verify_kdc_signature(krb5_context context, krb5_pac pac,
|
||
|
int tries;
|
||
|
|
||
|
ret = krb5_pac_verify(context, pac, 0, NULL, NULL, tgt_key);
|
||
|
- if (ret != KRB5KRB_AP_ERR_BAD_INTEGRITY)
|
||
|
+ if (ret != KRB5KRB_AP_ERR_MODIFIED)
|
||
|
return ret;
|
||
|
|
||
|
kvno = tgt->key_data[0].key_data_kvno - 1;
|
||
|
@@ -684,7 +684,7 @@ verify_kdc_signature(krb5_context context, krb5_pac pac,
|
||
|
for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) {
|
||
|
ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd);
|
||
|
if (ret)
|
||
|
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||
|
+ return KRB5KRB_AP_ERR_MODIFIED;
|
||
|
ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
@@ -697,7 +697,7 @@ verify_kdc_signature(krb5_context context, krb5_pac pac,
|
||
|
kvno = kd->key_data_kvno - 1;
|
||
|
}
|
||
|
|
||
|
- return KRB5KRB_AP_ERR_BAD_INTEGRITY;
|
||
|
+ return KRB5KRB_AP_ERR_MODIFIED;
|
||
|
}
|
||
|
|
||
|
static krb5_error_code
|
||
|
--
|
||
|
2.39.2
|
||
|
|