aboutsummaryrefslogtreecommitdiff
path: root/src/lib/krb5
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krb5')
-rw-r--r--src/lib/krb5/krb/deps5
-rw-r--r--src/lib/krb5/krb/int-proto.h3
-rw-r--r--src/lib/krb5/krb/pac.c148
-rw-r--r--src/lib/krb5/krb/pac_sign.c121
-rw-r--r--src/lib/krb5/krb/t_pac.c182
-rw-r--r--src/lib/krb5/libkrb5.exports2
6 files changed, 455 insertions, 6 deletions
diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps
index 6197a98..ca6ab25 100644
--- a/src/lib/krb5/krb/deps
+++ b/src/lib/krb5/krb/deps
@@ -710,7 +710,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 \
@@ -721,7 +721,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 15f4adf..b62f904 100644
--- a/src/lib/krb5/krb/int-proto.h
+++ b/src/lib/krb5/krb/int-proto.h
@@ -395,4 +395,7 @@ k5_sname_wildcard_host(krb5_context context, krb5_const_principal mprinc);
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 5118bf7..ab1606d 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"
/* draft-brezak-win2k-krb-authz-00 */
@@ -537,8 +538,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);
@@ -571,7 +574,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;
}
@@ -607,7 +610,7 @@ k5_pac_verify_kdc_checksum(krb5_context context,
p = (krb5_octet *)privsvr_checksum.data;
checksum.checksum_type = load_32_le(p);
if (!krb5_c_is_keyed_cksum(checksum.checksum_type))
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
+ return KRB5KRB_ERR_GENERIC;
/* There may be an RODCIdentifier trailer (see [MS-PAC] 2.8), so look up
* the length of the checksum by its type. */
@@ -629,11 +632,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 12f0259..0f9581a 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 ee47152..0b1b1f0 100644
--- a/src/lib/krb5/krb/t_pac.c
+++ b/src/lib/krb5/krb/t_pac.c
@@ -595,6 +595,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)
{
@@ -608,6 +788,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 0a05521..9a7a16f 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -465,6 +465,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